Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div id='example-app'></div>
<div id="example-app"></div>
22 changes: 14 additions & 8 deletions apps/typegpu-docs/src/content/examples/react/triangle/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import { vec4f } from 'typegpu/data';
import { useRender } from '@typegpu/react';
import * as d from 'typegpu/data';
import { useFrame, useRender, useUniformValue } from '@typegpu/react';
import { hsvToRgb } from '@typegpu/color';

function App() {
const time = useUniformValue(d.f32, 0);

useFrame(() => {
time.value = performance.now() / 1000;
});

const { ref } = useRender({
fragment: ({ uv }) => {
fragment: () => {
'kernel';
return vec4f(uv.x, uv.y, 1, 1);
const t = time.$;
const rgb = hsvToRgb(d.vec3f(t * 0.5, 1, 1));
return d.vec4f(rgb, 1);
},
});

// TODO: Provide a time variable to the shader with useUniformValue
// TODO: Make the gradient shift colors over time using hsvToRgb from @typegpu/color

return (
<main>
<canvas ref={ref} width='256' height='256' />
Expand All @@ -28,7 +34,7 @@ const reactRoot = createRoot(
reactRoot.render(<App />);

export function onCleanup() {
reactRoot.unmount();
setTimeout(() => reactRoot.unmount(), 0);
}

// #endregion
4 changes: 2 additions & 2 deletions apps/typegpu-docs/vitest.config.mts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createJiti } from 'jiti';
import { defineConfig } from 'vitest/config';
import { defineConfig, type Plugin } from 'vitest/config';
import { imagetools } from 'vite-imagetools';
import type TypeGPUPlugin from 'unplugin-typegpu/vite';

Expand All @@ -13,7 +13,7 @@ export default defineConfig({
plugins: [
typegpu({ include: [/\.m?[jt]sx?/] }),
/** @type {any} */ imagetools(),
],
] as Plugin[],
server: {
proxy: {
'/TypeGPU': {
Expand Down
57 changes: 53 additions & 4 deletions packages/typegpu-react/src/use-uniform-value.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,62 @@
import type * as d from 'typegpu/data';
import { useRoot } from './root-context.tsx';
import { useEffect, useMemo, useRef, useState } from 'react';
import type { ValidateUniformSchema } from 'typegpu';

interface UniformValue<TSchema, TValue extends d.Infer<TSchema>> {
schema: TSchema;
value: TValue;
value: TValue | undefined;
readonly $: d.InferGPU<TSchema>;
}

export function useUniformValue<TSchema, TValue extends d.Infer<TSchema>>(
schema: d.AnyWgslData,
export function useUniformValue<
TSchema extends d.AnyWgslData,
TValue extends d.Infer<TSchema>,
>(
schema: ValidateUniformSchema<TSchema>,
initialValue?: TValue | undefined,
): UniformValue<TSchema, TValue> {
// TODO: Implement
const root = useRoot();

const [uniformBuffer] = useState(() => {
return root.createUniform(
schema,
initialValue,
);
});

const cleanupRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
if (cleanupRef.current) {
clearTimeout(cleanupRef.current);
}

return () => {
cleanupRef.current = setTimeout(() => {
uniformBuffer.buffer.destroy();
}, 200);
};
}, [uniformBuffer]);

// biome-ignore lint/correctness/useExhaustiveDependencies: This value needs to be stable
const uniformValue = useMemo(() => {
let currentValue = initialValue;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Schemas should generally be callable, in which case they return an initial value that matches that schema.

Suggested change
let currentValue = initialValue;
let currentValue = initialValue ?? schema();

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing that out! However, with current implementation:

export function useUniformValue<
  TSchema extends d.AnyWgslData,
  TValue extends d.Infer<TSchema>,
>(
  schema: ValidateUniformSchema<TSchema>,
  initialValue?: TValue | undefined,
): UniformValue<TSchema, TValue> {

schema is not callable:

This expression is not callable.
  Not all constituents of type 'AnyWgslData | `(Error) ${string}`' are callable.
    Type 'U16' has no call signatures.ts(2349)

I'm wondering how can I alter this to simplify the logic.

return {
schema,
get value() {
return currentValue;
},
set value(newValue: TValue | undefined) {
currentValue = newValue;
if (newValue !== undefined) {
uniformBuffer.write(newValue);
}
},
Comment on lines +46 to +54
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of the previous comment, we don't have to worry about undefined.

Suggested change
get value() {
return currentValue;
},
set value(newValue: TValue | undefined) {
currentValue = newValue;
if (newValue !== undefined) {
uniformBuffer.write(newValue);
}
},
get value() {
return currentValue;
},
set value(newValue: TValue) {
currentValue = newValue;
uniformBuffer.write(newValue);
},

get $() {
return uniformBuffer.$;
},
};
}, []);

return uniformValue as UniformValue<TSchema, TValue>;
}
2 changes: 2 additions & 0 deletions packages/typegpu/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ export type {
Configurable,
TgpuRoot,
ValidateBufferSchema,
ValidateStorageSchema,
ValidateUniformSchema,
WithBinding,
WithCompute,
WithFragment,
Expand Down