@typegpu/react 0.10.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +42 -0
- package/index.d.mts +92 -0
- package/index.mjs +269 -0
- package/package.json +25 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Software Mansion <swmansion.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# @typegpu/react
|
|
4
|
+
|
|
5
|
+
🚧 **Under Construction** 🚧
|
|
6
|
+
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
# Basic usage
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { d, common } from 'typegpu';
|
|
13
|
+
import { hsvToRgb } from '@typegpu/color';
|
|
14
|
+
import { useFrame, useRoot, useUniformValue, useMirroredUniform, useConfigureContext } from '@typegpu/react';
|
|
15
|
+
|
|
16
|
+
const App = (props: Props) => {
|
|
17
|
+
const time = useUniformValue(d.f32, 0);
|
|
18
|
+
const color = useMirroredUniform(d.vec3f, props.color);
|
|
19
|
+
|
|
20
|
+
const root = useRoot();
|
|
21
|
+
const renderPipeline = useMemo(() => root.createRenderPipeline({
|
|
22
|
+
vertex: common.fullScreenTriangle,
|
|
23
|
+
// Runs each frame on the GPU 🌈
|
|
24
|
+
fragment: ({ uv }) => {
|
|
25
|
+
'use gpu';
|
|
26
|
+
return hsvToRgb(time.$, uv.x, uv.y) * color.$;
|
|
27
|
+
},
|
|
28
|
+
}), [root, time, color]);
|
|
29
|
+
|
|
30
|
+
const { canvasRefCallback, ctxRef } = useConfigureContext();
|
|
31
|
+
|
|
32
|
+
// Runs each frame on the CPU 🤖
|
|
33
|
+
useFrame(({ elapsedSeconds }) => {
|
|
34
|
+
if (!ctxRef.current) return;
|
|
35
|
+
|
|
36
|
+
time.value = elapsedSeconds;
|
|
37
|
+
renderPipeline.withColorAttachment({ view: ctxRef.current }).draw(3);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return <canvas ref={canvasRefCallback} />;
|
|
41
|
+
};
|
|
42
|
+
```
|
package/index.d.mts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { LayoutEntryToInput, TgpuBindGroup, TgpuBindGroupLayout, TgpuBuffer, TgpuMutable, TgpuRoot, ValidateBufferSchema, ValidateStorageSchema, ValidateUniformSchema, d } from "typegpu";
|
|
2
|
+
import * as d$1 from "typegpu/data";
|
|
3
|
+
|
|
4
|
+
//#region src/root-context.d.ts
|
|
5
|
+
declare function useRoot(): TgpuRoot;
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/use-frame.d.ts
|
|
8
|
+
interface FrameCtx {
|
|
9
|
+
/**
|
|
10
|
+
* Time elapsed since the last frame
|
|
11
|
+
*/
|
|
12
|
+
readonly deltaSeconds: number;
|
|
13
|
+
/**
|
|
14
|
+
* Time elapsed since the mounting of this hook
|
|
15
|
+
*/
|
|
16
|
+
readonly elapsedSeconds: number;
|
|
17
|
+
}
|
|
18
|
+
declare function useFrame(cb: (ctx: FrameCtx) => void): void;
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/use-mutable.d.ts
|
|
21
|
+
declare function useMutable<TSchema extends d.AnyWgslData>(schema: ValidateStorageSchema<TSchema>, initialValue?: d.Infer<TSchema>): TgpuMutable<TSchema>;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/symbols.d.ts
|
|
24
|
+
declare const $buffer: unique symbol;
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/use-uniform-value.d.ts
|
|
27
|
+
interface UniformValue<TSchema extends d$1.BaseData, TValue extends d$1.Infer<TSchema>> {
|
|
28
|
+
schema: TSchema;
|
|
29
|
+
value: TValue;
|
|
30
|
+
readonly $: d$1.InferGPU<TSchema>;
|
|
31
|
+
readonly [$buffer]: TgpuBuffer<TSchema>;
|
|
32
|
+
}
|
|
33
|
+
declare function useUniformValue<TSchema extends d$1.AnyWgslData, TValue extends d$1.Infer<TSchema>>(schema: ValidateUniformSchema<TSchema>, initialValue?: TValue): UniformValue<TSchema, TValue>;
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/use-buffer.d.ts
|
|
36
|
+
interface UseBufferOptions<TSchema extends d$1.AnyData> {
|
|
37
|
+
initial?: (() => d$1.Infer<NoInfer<TSchema>>) | d$1.Infer<NoInfer<TSchema>>;
|
|
38
|
+
onInit?: (buffer: TgpuBuffer<TSchema>) => void;
|
|
39
|
+
}
|
|
40
|
+
declare function useBuffer<TSchema extends d$1.AnyData>(schema: ValidateBufferSchema<TSchema>, options?: UseBufferOptions<TSchema>): TgpuBuffer<TSchema>;
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/use-configure-context.d.ts
|
|
43
|
+
interface UseConfigureContextOptions {
|
|
44
|
+
/**
|
|
45
|
+
* @default true
|
|
46
|
+
*/
|
|
47
|
+
autoResize?: boolean;
|
|
48
|
+
}
|
|
49
|
+
interface UseConfigureContextResult {
|
|
50
|
+
canvasRefCallback: React.RefCallback<HTMLCanvasElement>;
|
|
51
|
+
canvasRef: Readonly<React.Ref<HTMLCanvasElement | null>>;
|
|
52
|
+
ctxRef: React.RefObject<GPUCanvasContext | null>;
|
|
53
|
+
}
|
|
54
|
+
declare function useConfigureContext(options?: UseConfigureContextOptions): UseConfigureContextResult;
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/use-bind-group.d.ts
|
|
57
|
+
type ExtractInputFromEntries<T extends TgpuBindGroupLayout['entries']> = { [Key in keyof T]: T[Key] extends {
|
|
58
|
+
uniform: d.BaseData;
|
|
59
|
+
} ? LayoutEntryToInput<T[Key]> | UniformValue<T[Key]['uniform'], d.Infer<T[Key]['uniform']>> : LayoutEntryToInput<T[Key]> };
|
|
60
|
+
/**
|
|
61
|
+
* Creates a group of resources that can be bound to a shader based on a specified layout.
|
|
62
|
+
*
|
|
63
|
+
* @remarks
|
|
64
|
+
* Typed wrapper around a GPUBindGroup.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const fooLayout = tgpu.bindGroupLayout({
|
|
69
|
+
* foo: { uniform: d.vec3f },
|
|
70
|
+
* bar: { texture: 'float' },
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* function App() {
|
|
74
|
+
* const fooBuffer = useBuffer(...);
|
|
75
|
+
* const barTexture = useTexture(...);
|
|
76
|
+
*
|
|
77
|
+
* const fooBindGroup = useBindGroup(fooLayout, {
|
|
78
|
+
* foo: fooBuffer,
|
|
79
|
+
* bar: barTexture,
|
|
80
|
+
* });
|
|
81
|
+
*
|
|
82
|
+
* // ...
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @param layout Layout describing the bind group to be created.
|
|
87
|
+
* @param entries A record with values being the resources populating the bind group
|
|
88
|
+
* and keys being their associated names, matching the layout keys.
|
|
89
|
+
*/
|
|
90
|
+
declare function useBindGroup<TLayout extends TgpuBindGroupLayout>(layout: TLayout, entries: ExtractInputFromEntries<TLayout['entries']>): TgpuBindGroup<TLayout['entries']>;
|
|
91
|
+
//#endregion
|
|
92
|
+
export { type UniformValue, useBindGroup, useBuffer, useConfigureContext, useFrame, useMutable, useRoot, useUniformValue };
|
package/index.mjs
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import React, { createContext, use, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import tgpu from "typegpu";
|
|
3
|
+
import "react/jsx-runtime";
|
|
4
|
+
|
|
5
|
+
//#region src/root-context.tsx
|
|
6
|
+
var RootContext = class {
|
|
7
|
+
#root;
|
|
8
|
+
#rootPromise;
|
|
9
|
+
initOrGetRoot() {
|
|
10
|
+
if (this.#root) return this.#root;
|
|
11
|
+
if (!this.#rootPromise) this.#rootPromise = tgpu.init().then((root) => {
|
|
12
|
+
this.#root = root;
|
|
13
|
+
return root;
|
|
14
|
+
});
|
|
15
|
+
return this.#rootPromise;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Used in case no provider is mounted
|
|
20
|
+
*/
|
|
21
|
+
const globalRootContextValue = new RootContext();
|
|
22
|
+
const rootContext = createContext(null);
|
|
23
|
+
function useRoot() {
|
|
24
|
+
const maybeRoot = (useContext(rootContext) ?? globalRootContextValue).initOrGetRoot();
|
|
25
|
+
return maybeRoot instanceof Promise ? use(maybeRoot) : maybeRoot;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/use-frame.ts
|
|
30
|
+
function useFrame(cb) {
|
|
31
|
+
const latestCb = useRef(cb);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
latestCb.current = cb;
|
|
34
|
+
}, [cb]);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
let frameId;
|
|
37
|
+
let startTime;
|
|
38
|
+
let lastTime;
|
|
39
|
+
const loop = () => {
|
|
40
|
+
frameId = requestAnimationFrame(loop);
|
|
41
|
+
const now = performance.now();
|
|
42
|
+
if (lastTime === void 0 || startTime === void 0) {
|
|
43
|
+
startTime = now;
|
|
44
|
+
lastTime = now;
|
|
45
|
+
}
|
|
46
|
+
latestCb.current({
|
|
47
|
+
deltaSeconds: (now - lastTime) / 1e3,
|
|
48
|
+
elapsedSeconds: (now - startTime) / 1e3
|
|
49
|
+
});
|
|
50
|
+
lastTime = now;
|
|
51
|
+
};
|
|
52
|
+
loop();
|
|
53
|
+
return () => {
|
|
54
|
+
if (frameId !== void 0) cancelAnimationFrame(frameId);
|
|
55
|
+
};
|
|
56
|
+
}, []);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/use-mutable.ts
|
|
61
|
+
function useMutable(schema, initialValue) {
|
|
62
|
+
const root = useRoot();
|
|
63
|
+
const [mutable] = useState(() => {
|
|
64
|
+
return root.createMutable(schema, initialValue);
|
|
65
|
+
});
|
|
66
|
+
const cleanupRef = useRef(null);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (cleanupRef.current) clearTimeout(cleanupRef.current);
|
|
69
|
+
return () => {
|
|
70
|
+
cleanupRef.current = setTimeout(() => {
|
|
71
|
+
mutable.buffer.destroy();
|
|
72
|
+
}, 200);
|
|
73
|
+
};
|
|
74
|
+
}, [mutable]);
|
|
75
|
+
return mutable;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region package.json
|
|
80
|
+
var version = "0.10.0-alpha.1";
|
|
81
|
+
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/symbols.ts
|
|
84
|
+
const $buffer = Symbol(`@typegpu/react:${version}:$buffer`);
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/use-uniform-value.ts
|
|
88
|
+
function initialValueFromSchema(schema) {
|
|
89
|
+
if (typeof schema !== "function") throw new Error("Cannot use a non-callable schema with `useUniformValue`");
|
|
90
|
+
return schema();
|
|
91
|
+
}
|
|
92
|
+
function useUniformValue(schema, initialValue) {
|
|
93
|
+
const root = useRoot();
|
|
94
|
+
const [uniformBuffer] = useState(() => {
|
|
95
|
+
return root.createUniform(schema, initialValue);
|
|
96
|
+
});
|
|
97
|
+
const cleanupRef = useRef(null);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (cleanupRef.current) clearTimeout(cleanupRef.current);
|
|
100
|
+
return () => {
|
|
101
|
+
cleanupRef.current = setTimeout(() => {
|
|
102
|
+
uniformBuffer.buffer.destroy();
|
|
103
|
+
}, 200);
|
|
104
|
+
};
|
|
105
|
+
}, [uniformBuffer]);
|
|
106
|
+
return useMemo(() => {
|
|
107
|
+
let currentValue = initialValue ?? initialValueFromSchema(schema);
|
|
108
|
+
return {
|
|
109
|
+
schema,
|
|
110
|
+
[$buffer]: uniformBuffer.buffer,
|
|
111
|
+
get value() {
|
|
112
|
+
return currentValue;
|
|
113
|
+
},
|
|
114
|
+
set value(newValue) {
|
|
115
|
+
currentValue = newValue;
|
|
116
|
+
uniformBuffer.write(newValue);
|
|
117
|
+
},
|
|
118
|
+
get $() {
|
|
119
|
+
return uniformBuffer.$;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}, []);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/use-buffer.ts
|
|
127
|
+
function useBuffer(schema, options) {
|
|
128
|
+
const { initial, onInit } = options ?? {};
|
|
129
|
+
const root = useRoot();
|
|
130
|
+
const [buffer] = useState(() => {
|
|
131
|
+
const buffer = root.createBuffer(schema, typeof initial === "function" ? initial() : initial);
|
|
132
|
+
onInit?.(buffer);
|
|
133
|
+
return buffer;
|
|
134
|
+
});
|
|
135
|
+
const cleanupRef = useRef(null);
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
if (cleanupRef.current) clearTimeout(cleanupRef.current);
|
|
138
|
+
return () => {
|
|
139
|
+
cleanupRef.current = setTimeout(() => {
|
|
140
|
+
buffer.buffer.destroy();
|
|
141
|
+
}, 200);
|
|
142
|
+
};
|
|
143
|
+
}, [buffer]);
|
|
144
|
+
return buffer;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region src/use-effect-event.ts
|
|
149
|
+
/**
|
|
150
|
+
* Polyfill for the `useEffectEvent` React hook.
|
|
151
|
+
* WARNING: Do not use in the render phase, nor in `useLayoutEffect` calls.
|
|
152
|
+
* @param handler
|
|
153
|
+
* @returns A stable reference of the passed in function.
|
|
154
|
+
*/
|
|
155
|
+
function useEffectEvent(handler) {
|
|
156
|
+
const handlerRef = useRef(handler);
|
|
157
|
+
useLayoutEffect(() => {
|
|
158
|
+
handlerRef.current = handler;
|
|
159
|
+
});
|
|
160
|
+
return useCallback((...args) => {
|
|
161
|
+
const fn = handlerRef.current;
|
|
162
|
+
return fn(...args);
|
|
163
|
+
}, []);
|
|
164
|
+
}
|
|
165
|
+
var use_effect_event_default = React.useEffectEvent ?? useEffectEvent;
|
|
166
|
+
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/use-configure-context.ts
|
|
169
|
+
function useConfigureContext(options) {
|
|
170
|
+
const { autoResize = true } = options ?? {};
|
|
171
|
+
const root = useRoot();
|
|
172
|
+
const canvasRef = useRef(null);
|
|
173
|
+
const resizeEffect = use_effect_event_default((entries) => {
|
|
174
|
+
const entry = entries[0];
|
|
175
|
+
if (!canvasRef.current || !entry) return;
|
|
176
|
+
const el = canvasRef.current;
|
|
177
|
+
const dpcb = entry.devicePixelContentBoxSize?.[0];
|
|
178
|
+
const dpr = dpcb ? 1 : window.devicePixelRatio || 1;
|
|
179
|
+
const box = dpcb ?? (Array.isArray(entry.contentBoxSize) ? entry.contentBoxSize[0] : entry.contentBoxSize);
|
|
180
|
+
if (!box) return;
|
|
181
|
+
el.width = Math.round(box.inlineSize * dpr);
|
|
182
|
+
el.height = Math.round(box.blockSize * dpr);
|
|
183
|
+
});
|
|
184
|
+
const ctxRef = useRef(null);
|
|
185
|
+
const resizeObserverRef = useRef(null);
|
|
186
|
+
const canvasRefCallback = useCallback((el) => {
|
|
187
|
+
if (el) {
|
|
188
|
+
canvasRef.current = el;
|
|
189
|
+
ctxRef.current = root.configureContext({
|
|
190
|
+
canvas: el,
|
|
191
|
+
alphaMode: "premultiplied"
|
|
192
|
+
});
|
|
193
|
+
if (autoResize) {
|
|
194
|
+
if (resizeObserverRef.current) resizeObserverRef.current.disconnect();
|
|
195
|
+
resizeObserverRef.current = new ResizeObserver(resizeEffect);
|
|
196
|
+
resizeObserverRef.current.observe(el);
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
canvasRef.current = null;
|
|
200
|
+
ctxRef.current = null;
|
|
201
|
+
}
|
|
202
|
+
return () => {
|
|
203
|
+
canvasRef.current = null;
|
|
204
|
+
ctxRef.current = null;
|
|
205
|
+
resizeObserverRef.current?.disconnect();
|
|
206
|
+
resizeObserverRef.current = null;
|
|
207
|
+
};
|
|
208
|
+
}, [root]);
|
|
209
|
+
useEffect(() => {
|
|
210
|
+
const el = canvasRef.current;
|
|
211
|
+
if (!el) return;
|
|
212
|
+
if (resizeObserverRef.current) resizeObserverRef.current.disconnect();
|
|
213
|
+
if (autoResize) {
|
|
214
|
+
resizeObserverRef.current = new ResizeObserver(resizeEffect);
|
|
215
|
+
resizeObserverRef.current.observe(el);
|
|
216
|
+
}
|
|
217
|
+
return () => {
|
|
218
|
+
resizeObserverRef.current?.disconnect();
|
|
219
|
+
resizeObserverRef.current = null;
|
|
220
|
+
};
|
|
221
|
+
}, [resizeEffect]);
|
|
222
|
+
return {
|
|
223
|
+
canvasRefCallback,
|
|
224
|
+
canvasRef,
|
|
225
|
+
ctxRef
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
//#endregion
|
|
230
|
+
//#region src/use-bind-group.ts
|
|
231
|
+
/**
|
|
232
|
+
* Creates a group of resources that can be bound to a shader based on a specified layout.
|
|
233
|
+
*
|
|
234
|
+
* @remarks
|
|
235
|
+
* Typed wrapper around a GPUBindGroup.
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```ts
|
|
239
|
+
* const fooLayout = tgpu.bindGroupLayout({
|
|
240
|
+
* foo: { uniform: d.vec3f },
|
|
241
|
+
* bar: { texture: 'float' },
|
|
242
|
+
* });
|
|
243
|
+
*
|
|
244
|
+
* function App() {
|
|
245
|
+
* const fooBuffer = useBuffer(...);
|
|
246
|
+
* const barTexture = useTexture(...);
|
|
247
|
+
*
|
|
248
|
+
* const fooBindGroup = useBindGroup(fooLayout, {
|
|
249
|
+
* foo: fooBuffer,
|
|
250
|
+
* bar: barTexture,
|
|
251
|
+
* });
|
|
252
|
+
*
|
|
253
|
+
* // ...
|
|
254
|
+
* }
|
|
255
|
+
* ```
|
|
256
|
+
*
|
|
257
|
+
* @param layout Layout describing the bind group to be created.
|
|
258
|
+
* @param entries A record with values being the resources populating the bind group
|
|
259
|
+
* and keys being their associated names, matching the layout keys.
|
|
260
|
+
*/
|
|
261
|
+
function useBindGroup(layout, entries) {
|
|
262
|
+
return useRoot().createBindGroup(layout, Object.fromEntries(Object.entries(entries).map(([key, value]) => {
|
|
263
|
+
if (value[$buffer]) return [key, value[$buffer]];
|
|
264
|
+
return [key, value];
|
|
265
|
+
})));
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
//#endregion
|
|
269
|
+
export { useBindGroup, useBuffer, useConfigureContext, useFrame, useMutable, useRoot, useUniformValue };
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@typegpu/react",
|
|
3
|
+
"version": "0.10.0-alpha.1",
|
|
4
|
+
"description": "The best way to integrate TypeGPU into your React app.",
|
|
5
|
+
"keywords": [],
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"types": "./index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
"./package.json": "./package.json",
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./index.d.mts",
|
|
14
|
+
"default": "./index.mjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"react": "^19.0.0",
|
|
19
|
+
"typegpu": "^0.10.2"
|
|
20
|
+
},
|
|
21
|
+
"main": "./index.js",
|
|
22
|
+
"private": false,
|
|
23
|
+
"dependencies": {},
|
|
24
|
+
"scripts": {}
|
|
25
|
+
}
|