react-shadertoy 0.1.0 → 0.2.0
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/dist/index.d.mts +15 -3
- package/dist/index.d.ts +15 -3
- package/dist/index.js +180 -29
- package/dist/index.mjs +140 -14
- package/package.json +1 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { CSSProperties, RefObject } from 'react';
|
|
3
3
|
|
|
4
|
+
/** Texture source: URL string for image loading */
|
|
5
|
+
type TextureSource = string;
|
|
6
|
+
/** Texture inputs mapped to Shadertoy channels */
|
|
7
|
+
type TextureInputs = {
|
|
8
|
+
iChannel0?: TextureSource;
|
|
9
|
+
iChannel1?: TextureSource;
|
|
10
|
+
iChannel2?: TextureSource;
|
|
11
|
+
iChannel3?: TextureSource;
|
|
12
|
+
};
|
|
4
13
|
interface ShadertoyProps {
|
|
5
14
|
/** Shadertoy-compatible GLSL fragment shader (must contain mainImage) */
|
|
6
15
|
fragmentShader: string;
|
|
16
|
+
/** Texture inputs for iChannel0-3 */
|
|
17
|
+
textures?: TextureInputs;
|
|
7
18
|
/** Container style */
|
|
8
19
|
style?: CSSProperties;
|
|
9
20
|
/** Container className */
|
|
@@ -23,6 +34,7 @@ interface ShadertoyProps {
|
|
|
23
34
|
}
|
|
24
35
|
interface UseShadertoyOptions {
|
|
25
36
|
fragmentShader: string;
|
|
37
|
+
textures?: TextureInputs;
|
|
26
38
|
paused?: boolean;
|
|
27
39
|
speed?: number;
|
|
28
40
|
pixelRatio?: number;
|
|
@@ -38,8 +50,8 @@ interface UseShadertoyReturn {
|
|
|
38
50
|
resume: () => void;
|
|
39
51
|
}
|
|
40
52
|
|
|
41
|
-
declare function Shadertoy({ fragmentShader, style, className, paused, speed, pixelRatio, mouse, onError, onLoad, }: ShadertoyProps): react_jsx_runtime.JSX.Element;
|
|
53
|
+
declare function Shadertoy({ fragmentShader, textures, style, className, paused, speed, pixelRatio, mouse, onError, onLoad, }: ShadertoyProps): react_jsx_runtime.JSX.Element;
|
|
42
54
|
|
|
43
|
-
declare function useShadertoy({ fragmentShader, paused, speed, pixelRatio, mouse: mouseEnabled, onError, onLoad, }: UseShadertoyOptions): UseShadertoyReturn;
|
|
55
|
+
declare function useShadertoy({ fragmentShader, textures: texturesProp, paused, speed, pixelRatio, mouse: mouseEnabled, onError, onLoad, }: UseShadertoyOptions): UseShadertoyReturn;
|
|
44
56
|
|
|
45
|
-
export { Shadertoy, type ShadertoyProps, type UseShadertoyOptions, type UseShadertoyReturn, useShadertoy };
|
|
57
|
+
export { Shadertoy, type ShadertoyProps, type TextureInputs, type UseShadertoyOptions, type UseShadertoyReturn, useShadertoy };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { CSSProperties, RefObject } from 'react';
|
|
3
3
|
|
|
4
|
+
/** Texture source: URL string for image loading */
|
|
5
|
+
type TextureSource = string;
|
|
6
|
+
/** Texture inputs mapped to Shadertoy channels */
|
|
7
|
+
type TextureInputs = {
|
|
8
|
+
iChannel0?: TextureSource;
|
|
9
|
+
iChannel1?: TextureSource;
|
|
10
|
+
iChannel2?: TextureSource;
|
|
11
|
+
iChannel3?: TextureSource;
|
|
12
|
+
};
|
|
4
13
|
interface ShadertoyProps {
|
|
5
14
|
/** Shadertoy-compatible GLSL fragment shader (must contain mainImage) */
|
|
6
15
|
fragmentShader: string;
|
|
16
|
+
/** Texture inputs for iChannel0-3 */
|
|
17
|
+
textures?: TextureInputs;
|
|
7
18
|
/** Container style */
|
|
8
19
|
style?: CSSProperties;
|
|
9
20
|
/** Container className */
|
|
@@ -23,6 +34,7 @@ interface ShadertoyProps {
|
|
|
23
34
|
}
|
|
24
35
|
interface UseShadertoyOptions {
|
|
25
36
|
fragmentShader: string;
|
|
37
|
+
textures?: TextureInputs;
|
|
26
38
|
paused?: boolean;
|
|
27
39
|
speed?: number;
|
|
28
40
|
pixelRatio?: number;
|
|
@@ -38,8 +50,8 @@ interface UseShadertoyReturn {
|
|
|
38
50
|
resume: () => void;
|
|
39
51
|
}
|
|
40
52
|
|
|
41
|
-
declare function Shadertoy({ fragmentShader, style, className, paused, speed, pixelRatio, mouse, onError, onLoad, }: ShadertoyProps): react_jsx_runtime.JSX.Element;
|
|
53
|
+
declare function Shadertoy({ fragmentShader, textures, style, className, paused, speed, pixelRatio, mouse, onError, onLoad, }: ShadertoyProps): react_jsx_runtime.JSX.Element;
|
|
42
54
|
|
|
43
|
-
declare function useShadertoy({ fragmentShader, paused, speed, pixelRatio, mouse: mouseEnabled, onError, onLoad, }: UseShadertoyOptions): UseShadertoyReturn;
|
|
55
|
+
declare function useShadertoy({ fragmentShader, textures: texturesProp, paused, speed, pixelRatio, mouse: mouseEnabled, onError, onLoad, }: UseShadertoyOptions): UseShadertoyReturn;
|
|
44
56
|
|
|
45
|
-
export { Shadertoy, type ShadertoyProps, type UseShadertoyOptions, type UseShadertoyReturn, useShadertoy };
|
|
57
|
+
export { Shadertoy, type ShadertoyProps, type TextureInputs, type UseShadertoyOptions, type UseShadertoyReturn, useShadertoy };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
2
19
|
|
|
3
|
-
|
|
4
|
-
var
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Shadertoy: () => Shadertoy,
|
|
24
|
+
useShadertoy: () => useShadertoy
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
5
27
|
|
|
6
28
|
// src/useShadertoy.ts
|
|
29
|
+
var import_react = require("react");
|
|
7
30
|
|
|
8
31
|
// src/renderer.ts
|
|
9
32
|
var QUAD_VERTICES = new Float32Array([
|
|
@@ -35,6 +58,14 @@ uniform float iTimeDelta;
|
|
|
35
58
|
uniform int iFrame;
|
|
36
59
|
uniform vec4 iMouse;
|
|
37
60
|
uniform vec4 iDate;
|
|
61
|
+
uniform sampler2D iChannel0;
|
|
62
|
+
uniform sampler2D iChannel1;
|
|
63
|
+
uniform sampler2D iChannel2;
|
|
64
|
+
uniform sampler2D iChannel3;
|
|
65
|
+
uniform vec3 iChannelResolution[4];
|
|
66
|
+
|
|
67
|
+
// Shadertoy compatibility: texture() is GLSL 300 es, WebGL1 uses texture2D()
|
|
68
|
+
#define texture texture2D
|
|
38
69
|
|
|
39
70
|
${shader}
|
|
40
71
|
|
|
@@ -90,13 +121,21 @@ function createRenderer(canvas, fragmentShader) {
|
|
|
90
121
|
iTimeDelta: gl.getUniformLocation(program, "iTimeDelta"),
|
|
91
122
|
iFrame: gl.getUniformLocation(program, "iFrame"),
|
|
92
123
|
iMouse: gl.getUniformLocation(program, "iMouse"),
|
|
93
|
-
iDate: gl.getUniformLocation(program, "iDate")
|
|
124
|
+
iDate: gl.getUniformLocation(program, "iDate"),
|
|
125
|
+
iChannel: [
|
|
126
|
+
gl.getUniformLocation(program, "iChannel0"),
|
|
127
|
+
gl.getUniformLocation(program, "iChannel1"),
|
|
128
|
+
gl.getUniformLocation(program, "iChannel2"),
|
|
129
|
+
gl.getUniformLocation(program, "iChannel3")
|
|
130
|
+
],
|
|
131
|
+
iChannelResolution: gl.getUniformLocation(program, "iChannelResolution")
|
|
94
132
|
};
|
|
95
133
|
gl.useProgram(program);
|
|
96
134
|
return {
|
|
97
135
|
gl,
|
|
98
136
|
program,
|
|
99
137
|
locations,
|
|
138
|
+
textures: [null, null, null, null],
|
|
100
139
|
time: 0,
|
|
101
140
|
frame: 0,
|
|
102
141
|
lastTime: 0
|
|
@@ -113,6 +152,72 @@ function dispose(state) {
|
|
|
113
152
|
gl.getExtension("WEBGL_lose_context")?.loseContext();
|
|
114
153
|
}
|
|
115
154
|
|
|
155
|
+
// src/textures.ts
|
|
156
|
+
function loadImageTexture(gl, url, unit) {
|
|
157
|
+
const texture = gl.createTexture();
|
|
158
|
+
gl.activeTexture(gl.TEXTURE0 + unit);
|
|
159
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
160
|
+
gl.texImage2D(
|
|
161
|
+
gl.TEXTURE_2D,
|
|
162
|
+
0,
|
|
163
|
+
gl.RGBA,
|
|
164
|
+
1,
|
|
165
|
+
1,
|
|
166
|
+
0,
|
|
167
|
+
gl.RGBA,
|
|
168
|
+
gl.UNSIGNED_BYTE,
|
|
169
|
+
new Uint8Array([255, 0, 255, 255])
|
|
170
|
+
);
|
|
171
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
172
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
173
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
174
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
175
|
+
const state = { texture, width: 1, height: 1, unit, loaded: false };
|
|
176
|
+
const promise = new Promise((resolve, reject) => {
|
|
177
|
+
const img = new Image();
|
|
178
|
+
img.crossOrigin = "anonymous";
|
|
179
|
+
img.onload = () => {
|
|
180
|
+
if (gl.isContextLost()) {
|
|
181
|
+
resolve();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
gl.activeTexture(gl.TEXTURE0 + unit);
|
|
185
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
186
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
|
|
187
|
+
if (isPOT(img.width) && isPOT(img.height)) {
|
|
188
|
+
gl.generateMipmap(gl.TEXTURE_2D);
|
|
189
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
|
|
190
|
+
}
|
|
191
|
+
state.width = img.width;
|
|
192
|
+
state.height = img.height;
|
|
193
|
+
state.loaded = true;
|
|
194
|
+
resolve();
|
|
195
|
+
};
|
|
196
|
+
img.onerror = () => reject(new Error(`Failed to load texture: ${url}`));
|
|
197
|
+
img.src = url;
|
|
198
|
+
});
|
|
199
|
+
return { state, promise };
|
|
200
|
+
}
|
|
201
|
+
function bindTextures(gl, locations, textures) {
|
|
202
|
+
for (let i = 0; i < 4; i++) {
|
|
203
|
+
const tex = textures[i];
|
|
204
|
+
if (!tex) continue;
|
|
205
|
+
gl.activeTexture(gl.TEXTURE0 + tex.unit);
|
|
206
|
+
gl.bindTexture(gl.TEXTURE_2D, tex.texture);
|
|
207
|
+
if (locations[i]) {
|
|
208
|
+
gl.uniform1i(locations[i], tex.unit);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function disposeTextures(gl, textures) {
|
|
213
|
+
for (const tex of textures) {
|
|
214
|
+
if (tex) gl.deleteTexture(tex.texture);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function isPOT(v) {
|
|
218
|
+
return (v & v - 1) === 0 && v > 0;
|
|
219
|
+
}
|
|
220
|
+
|
|
116
221
|
// src/uniforms.ts
|
|
117
222
|
function updateUniforms(state, delta, speed, mouse) {
|
|
118
223
|
const { gl, locations } = state;
|
|
@@ -140,6 +245,18 @@ function updateUniforms(state, delta, speed, mouse) {
|
|
|
140
245
|
const mw = mouse.pressed ? mouse.clickY : -Math.abs(mouse.clickY);
|
|
141
246
|
gl.uniform4f(locations.iMouse, mouse.x, mouse.y, mz, mw);
|
|
142
247
|
}
|
|
248
|
+
if (locations.iChannelResolution) {
|
|
249
|
+
const res = new Float32Array(12);
|
|
250
|
+
for (let i = 0; i < 4; i++) {
|
|
251
|
+
const tex = state.textures[i];
|
|
252
|
+
if (tex) {
|
|
253
|
+
res[i * 3] = tex.width;
|
|
254
|
+
res[i * 3 + 1] = tex.height;
|
|
255
|
+
res[i * 3 + 2] = 1;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
gl.uniform3fv(locations.iChannelResolution, res);
|
|
259
|
+
}
|
|
143
260
|
if (locations.iDate) {
|
|
144
261
|
const now = /* @__PURE__ */ new Date();
|
|
145
262
|
const seconds = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds() + now.getMilliseconds() / 1e3;
|
|
@@ -155,8 +272,10 @@ function updateUniforms(state, delta, speed, mouse) {
|
|
|
155
272
|
}
|
|
156
273
|
|
|
157
274
|
// src/useShadertoy.ts
|
|
275
|
+
var CHANNEL_KEYS = ["iChannel0", "iChannel1", "iChannel2", "iChannel3"];
|
|
158
276
|
function useShadertoy({
|
|
159
277
|
fragmentShader,
|
|
278
|
+
textures: texturesProp,
|
|
160
279
|
paused = false,
|
|
161
280
|
speed = 1,
|
|
162
281
|
pixelRatio,
|
|
@@ -164,14 +283,14 @@ function useShadertoy({
|
|
|
164
283
|
onError,
|
|
165
284
|
onLoad
|
|
166
285
|
}) {
|
|
167
|
-
const canvasRef =
|
|
168
|
-
const rendererRef =
|
|
169
|
-
const rafRef =
|
|
170
|
-
const pausedRef =
|
|
171
|
-
const speedRef =
|
|
172
|
-
const [isReady, setIsReady] =
|
|
173
|
-
const [error, setError] =
|
|
174
|
-
const mouseState =
|
|
286
|
+
const canvasRef = (0, import_react.useRef)(null);
|
|
287
|
+
const rendererRef = (0, import_react.useRef)(null);
|
|
288
|
+
const rafRef = (0, import_react.useRef)(0);
|
|
289
|
+
const pausedRef = (0, import_react.useRef)(paused);
|
|
290
|
+
const speedRef = (0, import_react.useRef)(speed);
|
|
291
|
+
const [isReady, setIsReady] = (0, import_react.useState)(false);
|
|
292
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
293
|
+
const mouseState = (0, import_react.useRef)({
|
|
175
294
|
x: 0,
|
|
176
295
|
y: 0,
|
|
177
296
|
clickX: 0,
|
|
@@ -180,7 +299,7 @@ function useShadertoy({
|
|
|
180
299
|
});
|
|
181
300
|
pausedRef.current = paused;
|
|
182
301
|
speedRef.current = speed;
|
|
183
|
-
|
|
302
|
+
(0, import_react.useEffect)(() => {
|
|
184
303
|
const canvas = canvasRef.current;
|
|
185
304
|
if (!canvas) return;
|
|
186
305
|
const result = createRenderer(canvas, fragmentShader);
|
|
@@ -190,16 +309,42 @@ function useShadertoy({
|
|
|
190
309
|
return;
|
|
191
310
|
}
|
|
192
311
|
rendererRef.current = result;
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
312
|
+
const texturePromises = [];
|
|
313
|
+
if (texturesProp) {
|
|
314
|
+
for (let i = 0; i < 4; i++) {
|
|
315
|
+
const src = texturesProp[CHANNEL_KEYS[i]];
|
|
316
|
+
if (typeof src === "string") {
|
|
317
|
+
const { state, promise } = loadImageTexture(result.gl, src, i);
|
|
318
|
+
result.textures[i] = state;
|
|
319
|
+
texturePromises.push(promise);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const markReady = () => {
|
|
324
|
+
setIsReady(true);
|
|
325
|
+
setError(null);
|
|
326
|
+
onLoad?.();
|
|
327
|
+
};
|
|
328
|
+
if (texturePromises.length > 0) {
|
|
329
|
+
Promise.all(texturePromises).then(() => {
|
|
330
|
+
if (rendererRef.current) markReady();
|
|
331
|
+
}).catch((err) => {
|
|
332
|
+
const msg = err instanceof Error ? err.message : "Texture load failed";
|
|
333
|
+
setError(msg);
|
|
334
|
+
onError?.(msg);
|
|
335
|
+
});
|
|
336
|
+
} else {
|
|
337
|
+
markReady();
|
|
338
|
+
}
|
|
196
339
|
let lastTimestamp = 0;
|
|
197
340
|
const loop = (timestamp) => {
|
|
198
341
|
const delta = lastTimestamp ? (timestamp - lastTimestamp) / 1e3 : 0;
|
|
199
342
|
lastTimestamp = timestamp;
|
|
200
343
|
if (!pausedRef.current && rendererRef.current) {
|
|
201
|
-
|
|
202
|
-
|
|
344
|
+
const r = rendererRef.current;
|
|
345
|
+
bindTextures(r.gl, r.locations.iChannel, r.textures);
|
|
346
|
+
updateUniforms(r, delta, speedRef.current, mouseState.current);
|
|
347
|
+
render(r);
|
|
203
348
|
}
|
|
204
349
|
rafRef.current = requestAnimationFrame(loop);
|
|
205
350
|
};
|
|
@@ -207,13 +352,14 @@ function useShadertoy({
|
|
|
207
352
|
return () => {
|
|
208
353
|
cancelAnimationFrame(rafRef.current);
|
|
209
354
|
if (rendererRef.current) {
|
|
355
|
+
disposeTextures(rendererRef.current.gl, rendererRef.current.textures);
|
|
210
356
|
dispose(rendererRef.current);
|
|
211
357
|
rendererRef.current = null;
|
|
212
358
|
}
|
|
213
359
|
setIsReady(false);
|
|
214
360
|
};
|
|
215
|
-
}, [fragmentShader, onError, onLoad]);
|
|
216
|
-
|
|
361
|
+
}, [fragmentShader, texturesProp, onError, onLoad]);
|
|
362
|
+
(0, import_react.useEffect)(() => {
|
|
217
363
|
const canvas = canvasRef.current;
|
|
218
364
|
if (!canvas) return;
|
|
219
365
|
const dpr = pixelRatio ?? (typeof window !== "undefined" ? window.devicePixelRatio : 1);
|
|
@@ -227,7 +373,7 @@ function useShadertoy({
|
|
|
227
373
|
observer.observe(canvas);
|
|
228
374
|
return () => observer.disconnect();
|
|
229
375
|
}, [pixelRatio]);
|
|
230
|
-
|
|
376
|
+
(0, import_react.useEffect)(() => {
|
|
231
377
|
if (!mouseEnabled) return;
|
|
232
378
|
const canvas = canvasRef.current;
|
|
233
379
|
if (!canvas) return;
|
|
@@ -282,16 +428,20 @@ function useShadertoy({
|
|
|
282
428
|
window.removeEventListener("touchend", te);
|
|
283
429
|
};
|
|
284
430
|
}, [mouseEnabled, pixelRatio]);
|
|
285
|
-
const pause =
|
|
431
|
+
const pause = (0, import_react.useCallback)(() => {
|
|
286
432
|
pausedRef.current = true;
|
|
287
433
|
}, []);
|
|
288
|
-
const resume =
|
|
434
|
+
const resume = (0, import_react.useCallback)(() => {
|
|
289
435
|
pausedRef.current = false;
|
|
290
436
|
}, []);
|
|
291
437
|
return { canvasRef, isReady, error, pause, resume };
|
|
292
438
|
}
|
|
439
|
+
|
|
440
|
+
// src/Shadertoy.tsx
|
|
441
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
293
442
|
function Shadertoy({
|
|
294
443
|
fragmentShader,
|
|
444
|
+
textures,
|
|
295
445
|
style,
|
|
296
446
|
className,
|
|
297
447
|
paused,
|
|
@@ -303,6 +453,7 @@ function Shadertoy({
|
|
|
303
453
|
}) {
|
|
304
454
|
const { canvasRef } = useShadertoy({
|
|
305
455
|
fragmentShader,
|
|
456
|
+
textures,
|
|
306
457
|
paused,
|
|
307
458
|
speed,
|
|
308
459
|
pixelRatio,
|
|
@@ -310,7 +461,7 @@ function Shadertoy({
|
|
|
310
461
|
onError,
|
|
311
462
|
onLoad
|
|
312
463
|
});
|
|
313
|
-
return /* @__PURE__ */
|
|
464
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
314
465
|
"canvas",
|
|
315
466
|
{
|
|
316
467
|
ref: canvasRef,
|
|
@@ -319,8 +470,8 @@ function Shadertoy({
|
|
|
319
470
|
}
|
|
320
471
|
);
|
|
321
472
|
}
|
|
322
|
-
|
|
323
|
-
exports
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
473
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
474
|
+
0 && (module.exports = {
|
|
475
|
+
Shadertoy,
|
|
476
|
+
useShadertoy
|
|
477
|
+
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { useRef, useState, useEffect, useCallback } from 'react';
|
|
2
|
-
import { jsx } from 'react/jsx-runtime';
|
|
3
|
-
|
|
4
1
|
// src/useShadertoy.ts
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
5
3
|
|
|
6
4
|
// src/renderer.ts
|
|
7
5
|
var QUAD_VERTICES = new Float32Array([
|
|
@@ -33,6 +31,14 @@ uniform float iTimeDelta;
|
|
|
33
31
|
uniform int iFrame;
|
|
34
32
|
uniform vec4 iMouse;
|
|
35
33
|
uniform vec4 iDate;
|
|
34
|
+
uniform sampler2D iChannel0;
|
|
35
|
+
uniform sampler2D iChannel1;
|
|
36
|
+
uniform sampler2D iChannel2;
|
|
37
|
+
uniform sampler2D iChannel3;
|
|
38
|
+
uniform vec3 iChannelResolution[4];
|
|
39
|
+
|
|
40
|
+
// Shadertoy compatibility: texture() is GLSL 300 es, WebGL1 uses texture2D()
|
|
41
|
+
#define texture texture2D
|
|
36
42
|
|
|
37
43
|
${shader}
|
|
38
44
|
|
|
@@ -88,13 +94,21 @@ function createRenderer(canvas, fragmentShader) {
|
|
|
88
94
|
iTimeDelta: gl.getUniformLocation(program, "iTimeDelta"),
|
|
89
95
|
iFrame: gl.getUniformLocation(program, "iFrame"),
|
|
90
96
|
iMouse: gl.getUniformLocation(program, "iMouse"),
|
|
91
|
-
iDate: gl.getUniformLocation(program, "iDate")
|
|
97
|
+
iDate: gl.getUniformLocation(program, "iDate"),
|
|
98
|
+
iChannel: [
|
|
99
|
+
gl.getUniformLocation(program, "iChannel0"),
|
|
100
|
+
gl.getUniformLocation(program, "iChannel1"),
|
|
101
|
+
gl.getUniformLocation(program, "iChannel2"),
|
|
102
|
+
gl.getUniformLocation(program, "iChannel3")
|
|
103
|
+
],
|
|
104
|
+
iChannelResolution: gl.getUniformLocation(program, "iChannelResolution")
|
|
92
105
|
};
|
|
93
106
|
gl.useProgram(program);
|
|
94
107
|
return {
|
|
95
108
|
gl,
|
|
96
109
|
program,
|
|
97
110
|
locations,
|
|
111
|
+
textures: [null, null, null, null],
|
|
98
112
|
time: 0,
|
|
99
113
|
frame: 0,
|
|
100
114
|
lastTime: 0
|
|
@@ -111,6 +125,72 @@ function dispose(state) {
|
|
|
111
125
|
gl.getExtension("WEBGL_lose_context")?.loseContext();
|
|
112
126
|
}
|
|
113
127
|
|
|
128
|
+
// src/textures.ts
|
|
129
|
+
function loadImageTexture(gl, url, unit) {
|
|
130
|
+
const texture = gl.createTexture();
|
|
131
|
+
gl.activeTexture(gl.TEXTURE0 + unit);
|
|
132
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
133
|
+
gl.texImage2D(
|
|
134
|
+
gl.TEXTURE_2D,
|
|
135
|
+
0,
|
|
136
|
+
gl.RGBA,
|
|
137
|
+
1,
|
|
138
|
+
1,
|
|
139
|
+
0,
|
|
140
|
+
gl.RGBA,
|
|
141
|
+
gl.UNSIGNED_BYTE,
|
|
142
|
+
new Uint8Array([255, 0, 255, 255])
|
|
143
|
+
);
|
|
144
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
145
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
146
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
147
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
148
|
+
const state = { texture, width: 1, height: 1, unit, loaded: false };
|
|
149
|
+
const promise = new Promise((resolve, reject) => {
|
|
150
|
+
const img = new Image();
|
|
151
|
+
img.crossOrigin = "anonymous";
|
|
152
|
+
img.onload = () => {
|
|
153
|
+
if (gl.isContextLost()) {
|
|
154
|
+
resolve();
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
gl.activeTexture(gl.TEXTURE0 + unit);
|
|
158
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
159
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
|
|
160
|
+
if (isPOT(img.width) && isPOT(img.height)) {
|
|
161
|
+
gl.generateMipmap(gl.TEXTURE_2D);
|
|
162
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
|
|
163
|
+
}
|
|
164
|
+
state.width = img.width;
|
|
165
|
+
state.height = img.height;
|
|
166
|
+
state.loaded = true;
|
|
167
|
+
resolve();
|
|
168
|
+
};
|
|
169
|
+
img.onerror = () => reject(new Error(`Failed to load texture: ${url}`));
|
|
170
|
+
img.src = url;
|
|
171
|
+
});
|
|
172
|
+
return { state, promise };
|
|
173
|
+
}
|
|
174
|
+
function bindTextures(gl, locations, textures) {
|
|
175
|
+
for (let i = 0; i < 4; i++) {
|
|
176
|
+
const tex = textures[i];
|
|
177
|
+
if (!tex) continue;
|
|
178
|
+
gl.activeTexture(gl.TEXTURE0 + tex.unit);
|
|
179
|
+
gl.bindTexture(gl.TEXTURE_2D, tex.texture);
|
|
180
|
+
if (locations[i]) {
|
|
181
|
+
gl.uniform1i(locations[i], tex.unit);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function disposeTextures(gl, textures) {
|
|
186
|
+
for (const tex of textures) {
|
|
187
|
+
if (tex) gl.deleteTexture(tex.texture);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function isPOT(v) {
|
|
191
|
+
return (v & v - 1) === 0 && v > 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
114
194
|
// src/uniforms.ts
|
|
115
195
|
function updateUniforms(state, delta, speed, mouse) {
|
|
116
196
|
const { gl, locations } = state;
|
|
@@ -138,6 +218,18 @@ function updateUniforms(state, delta, speed, mouse) {
|
|
|
138
218
|
const mw = mouse.pressed ? mouse.clickY : -Math.abs(mouse.clickY);
|
|
139
219
|
gl.uniform4f(locations.iMouse, mouse.x, mouse.y, mz, mw);
|
|
140
220
|
}
|
|
221
|
+
if (locations.iChannelResolution) {
|
|
222
|
+
const res = new Float32Array(12);
|
|
223
|
+
for (let i = 0; i < 4; i++) {
|
|
224
|
+
const tex = state.textures[i];
|
|
225
|
+
if (tex) {
|
|
226
|
+
res[i * 3] = tex.width;
|
|
227
|
+
res[i * 3 + 1] = tex.height;
|
|
228
|
+
res[i * 3 + 2] = 1;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
gl.uniform3fv(locations.iChannelResolution, res);
|
|
232
|
+
}
|
|
141
233
|
if (locations.iDate) {
|
|
142
234
|
const now = /* @__PURE__ */ new Date();
|
|
143
235
|
const seconds = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds() + now.getMilliseconds() / 1e3;
|
|
@@ -153,8 +245,10 @@ function updateUniforms(state, delta, speed, mouse) {
|
|
|
153
245
|
}
|
|
154
246
|
|
|
155
247
|
// src/useShadertoy.ts
|
|
248
|
+
var CHANNEL_KEYS = ["iChannel0", "iChannel1", "iChannel2", "iChannel3"];
|
|
156
249
|
function useShadertoy({
|
|
157
250
|
fragmentShader,
|
|
251
|
+
textures: texturesProp,
|
|
158
252
|
paused = false,
|
|
159
253
|
speed = 1,
|
|
160
254
|
pixelRatio,
|
|
@@ -188,16 +282,42 @@ function useShadertoy({
|
|
|
188
282
|
return;
|
|
189
283
|
}
|
|
190
284
|
rendererRef.current = result;
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
285
|
+
const texturePromises = [];
|
|
286
|
+
if (texturesProp) {
|
|
287
|
+
for (let i = 0; i < 4; i++) {
|
|
288
|
+
const src = texturesProp[CHANNEL_KEYS[i]];
|
|
289
|
+
if (typeof src === "string") {
|
|
290
|
+
const { state, promise } = loadImageTexture(result.gl, src, i);
|
|
291
|
+
result.textures[i] = state;
|
|
292
|
+
texturePromises.push(promise);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
const markReady = () => {
|
|
297
|
+
setIsReady(true);
|
|
298
|
+
setError(null);
|
|
299
|
+
onLoad?.();
|
|
300
|
+
};
|
|
301
|
+
if (texturePromises.length > 0) {
|
|
302
|
+
Promise.all(texturePromises).then(() => {
|
|
303
|
+
if (rendererRef.current) markReady();
|
|
304
|
+
}).catch((err) => {
|
|
305
|
+
const msg = err instanceof Error ? err.message : "Texture load failed";
|
|
306
|
+
setError(msg);
|
|
307
|
+
onError?.(msg);
|
|
308
|
+
});
|
|
309
|
+
} else {
|
|
310
|
+
markReady();
|
|
311
|
+
}
|
|
194
312
|
let lastTimestamp = 0;
|
|
195
313
|
const loop = (timestamp) => {
|
|
196
314
|
const delta = lastTimestamp ? (timestamp - lastTimestamp) / 1e3 : 0;
|
|
197
315
|
lastTimestamp = timestamp;
|
|
198
316
|
if (!pausedRef.current && rendererRef.current) {
|
|
199
|
-
|
|
200
|
-
|
|
317
|
+
const r = rendererRef.current;
|
|
318
|
+
bindTextures(r.gl, r.locations.iChannel, r.textures);
|
|
319
|
+
updateUniforms(r, delta, speedRef.current, mouseState.current);
|
|
320
|
+
render(r);
|
|
201
321
|
}
|
|
202
322
|
rafRef.current = requestAnimationFrame(loop);
|
|
203
323
|
};
|
|
@@ -205,12 +325,13 @@ function useShadertoy({
|
|
|
205
325
|
return () => {
|
|
206
326
|
cancelAnimationFrame(rafRef.current);
|
|
207
327
|
if (rendererRef.current) {
|
|
328
|
+
disposeTextures(rendererRef.current.gl, rendererRef.current.textures);
|
|
208
329
|
dispose(rendererRef.current);
|
|
209
330
|
rendererRef.current = null;
|
|
210
331
|
}
|
|
211
332
|
setIsReady(false);
|
|
212
333
|
};
|
|
213
|
-
}, [fragmentShader, onError, onLoad]);
|
|
334
|
+
}, [fragmentShader, texturesProp, onError, onLoad]);
|
|
214
335
|
useEffect(() => {
|
|
215
336
|
const canvas = canvasRef.current;
|
|
216
337
|
if (!canvas) return;
|
|
@@ -288,8 +409,12 @@ function useShadertoy({
|
|
|
288
409
|
}, []);
|
|
289
410
|
return { canvasRef, isReady, error, pause, resume };
|
|
290
411
|
}
|
|
412
|
+
|
|
413
|
+
// src/Shadertoy.tsx
|
|
414
|
+
import { jsx } from "react/jsx-runtime";
|
|
291
415
|
function Shadertoy({
|
|
292
416
|
fragmentShader,
|
|
417
|
+
textures,
|
|
293
418
|
style,
|
|
294
419
|
className,
|
|
295
420
|
paused,
|
|
@@ -301,6 +426,7 @@ function Shadertoy({
|
|
|
301
426
|
}) {
|
|
302
427
|
const { canvasRef } = useShadertoy({
|
|
303
428
|
fragmentShader,
|
|
429
|
+
textures,
|
|
304
430
|
paused,
|
|
305
431
|
speed,
|
|
306
432
|
pixelRatio,
|
|
@@ -317,7 +443,7 @@ function Shadertoy({
|
|
|
317
443
|
}
|
|
318
444
|
);
|
|
319
445
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
446
|
+
export {
|
|
447
|
+
Shadertoy,
|
|
448
|
+
useShadertoy
|
|
449
|
+
};
|
package/package.json
CHANGED
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/renderer.ts","../src/uniforms.ts","../src/useShadertoy.ts","../src/Shadertoy.tsx"],"names":["useRef","useState","useEffect","useCallback","jsx"],"mappings":"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","file":"index.js","sourcesContent":["import type { RendererState, UniformLocations } from './types'\n\n// Full-screen quad: two triangles covering clip space\nconst QUAD_VERTICES = new Float32Array([\n -1, -1,\n 1, -1,\n -1, 1,\n -1, 1,\n 1, -1,\n 1, 1,\n])\n\nconst VERTEX_SHADER = `\nattribute vec2 position;\nvoid main() {\n gl_Position = vec4(position, 0.0, 1.0);\n}\n`\n\n/**\n * Wrap Shadertoy GLSL: prepend uniform declarations + main() bridge.\n */\nfunction wrapFragmentShader(shader: string): string {\n return `precision highp float;\n\nuniform vec3 iResolution;\nuniform float iTime;\nuniform float iTimeDelta;\nuniform int iFrame;\nuniform vec4 iMouse;\nuniform vec4 iDate;\n\n${shader}\n\nvoid main() {\n mainImage(gl_FragColor, gl_FragCoord.xy);\n}\n`\n}\n\nfunction compileShader(\n gl: WebGLRenderingContext,\n type: number,\n source: string,\n): WebGLShader | string {\n const shader = gl.createShader(type)\n if (!shader) return 'Failed to create shader'\n\n gl.shaderSource(shader, source)\n gl.compileShader(shader)\n\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const log = gl.getShaderInfoLog(shader) || 'Unknown compile error'\n gl.deleteShader(shader)\n return log\n }\n\n return shader\n}\n\n/**\n * Initialize WebGL: compile shaders, link program, setup quad.\n * Returns RendererState on success or error string on failure.\n */\nexport function createRenderer(\n canvas: HTMLCanvasElement,\n fragmentShader: string,\n): RendererState | string {\n const gl = canvas.getContext('webgl', {\n antialias: false,\n alpha: true,\n premultipliedAlpha: false,\n })\n if (!gl) return 'WebGL not supported'\n\n // Compile vertex shader\n const vert = compileShader(gl, gl.VERTEX_SHADER, VERTEX_SHADER)\n if (typeof vert === 'string') return vert\n\n // Compile fragment shader (wrapped)\n const frag = compileShader(gl, gl.FRAGMENT_SHADER, wrapFragmentShader(fragmentShader))\n if (typeof frag === 'string') return frag\n\n // Link program\n const program = gl.createProgram()\n if (!program) return 'Failed to create program'\n\n gl.attachShader(program, vert)\n gl.attachShader(program, frag)\n gl.linkProgram(program)\n\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n const log = gl.getProgramInfoLog(program) || 'Unknown link error'\n gl.deleteProgram(program)\n return log\n }\n\n // Clean up individual shaders (attached to program)\n gl.deleteShader(vert)\n gl.deleteShader(frag)\n\n // Setup quad geometry\n const buffer = gl.createBuffer()\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n gl.bufferData(gl.ARRAY_BUFFER, QUAD_VERTICES, gl.STATIC_DRAW)\n\n const positionLoc = gl.getAttribLocation(program, 'position')\n gl.enableVertexAttribArray(positionLoc)\n gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0)\n\n // Get uniform locations\n const locations: UniformLocations = {\n iResolution: gl.getUniformLocation(program, 'iResolution'),\n iTime: gl.getUniformLocation(program, 'iTime'),\n iTimeDelta: gl.getUniformLocation(program, 'iTimeDelta'),\n iFrame: gl.getUniformLocation(program, 'iFrame'),\n iMouse: gl.getUniformLocation(program, 'iMouse'),\n iDate: gl.getUniformLocation(program, 'iDate'),\n }\n\n gl.useProgram(program)\n\n return {\n gl,\n program,\n locations,\n time: 0,\n frame: 0,\n lastTime: 0,\n }\n}\n\n/**\n * Render one frame.\n */\nexport function render(state: RendererState): void {\n const { gl } = state\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight)\n gl.drawArrays(gl.TRIANGLES, 0, 6)\n}\n\n/**\n * Clean up WebGL resources.\n */\nexport function dispose(state: RendererState): void {\n const { gl, program } = state\n gl.deleteProgram(program)\n gl.getExtension('WEBGL_lose_context')?.loseContext()\n}\n","import type { MouseState, RendererState } from './types'\n\n/**\n * Update all Shadertoy standard uniforms for one frame.\n */\nexport function updateUniforms(\n state: RendererState,\n delta: number,\n speed: number,\n mouse: MouseState,\n): void {\n const { gl, locations } = state\n\n // iTime\n state.time += delta * speed\n if (locations.iTime) {\n gl.uniform1f(locations.iTime, state.time)\n }\n\n // iTimeDelta\n if (locations.iTimeDelta) {\n gl.uniform1f(locations.iTimeDelta, delta)\n }\n\n // iFrame\n state.frame++\n if (locations.iFrame) {\n gl.uniform1i(locations.iFrame, state.frame)\n }\n\n // iResolution\n if (locations.iResolution) {\n gl.uniform3f(\n locations.iResolution,\n gl.drawingBufferWidth,\n gl.drawingBufferHeight,\n 1.0,\n )\n }\n\n // iMouse — Shadertoy convention:\n // xy: current position (if pressed)\n // zw: click position (positive when pressed, negative when released)\n if (locations.iMouse) {\n const mz = mouse.pressed ? mouse.clickX : -Math.abs(mouse.clickX)\n const mw = mouse.pressed ? mouse.clickY : -Math.abs(mouse.clickY)\n gl.uniform4f(locations.iMouse, mouse.x, mouse.y, mz, mw)\n }\n\n // iDate — vec4(year, month, day, seconds_since_midnight)\n if (locations.iDate) {\n const now = new Date()\n const seconds =\n now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds() + now.getMilliseconds() / 1000\n gl.uniform4f(\n locations.iDate,\n now.getFullYear(),\n now.getMonth(), // 0-based, matches Shadertoy\n now.getDate(),\n seconds,\n )\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport { createRenderer, dispose, render } from './renderer'\nimport type { MouseState, RendererState, UseShadertoyOptions, UseShadertoyReturn } from './types'\nimport { updateUniforms } from './uniforms'\n\nexport function useShadertoy({\n fragmentShader,\n paused = false,\n speed = 1.0,\n pixelRatio,\n mouse: mouseEnabled = true,\n onError,\n onLoad,\n}: UseShadertoyOptions): UseShadertoyReturn {\n const canvasRef = useRef<HTMLCanvasElement | null>(null)\n const rendererRef = useRef<RendererState | null>(null)\n const rafRef = useRef<number>(0)\n const pausedRef = useRef(paused)\n const speedRef = useRef(speed)\n\n const [isReady, setIsReady] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const mouseState = useRef<MouseState>({\n x: 0, y: 0,\n clickX: 0, clickY: 0,\n pressed: false,\n })\n\n // Keep refs in sync\n pausedRef.current = paused\n speedRef.current = speed\n\n // Initialize WebGL\n useEffect(() => {\n const canvas = canvasRef.current\n if (!canvas) return\n\n const result = createRenderer(canvas, fragmentShader)\n if (typeof result === 'string') {\n setError(result)\n onError?.(result)\n return\n }\n\n rendererRef.current = result\n setIsReady(true)\n setError(null)\n onLoad?.()\n\n // Render loop\n let lastTimestamp = 0\n\n const loop = (timestamp: number) => {\n const delta = lastTimestamp ? (timestamp - lastTimestamp) / 1000 : 0\n lastTimestamp = timestamp\n\n if (!pausedRef.current && rendererRef.current) {\n updateUniforms(rendererRef.current, delta, speedRef.current, mouseState.current)\n render(rendererRef.current)\n }\n\n rafRef.current = requestAnimationFrame(loop)\n }\n\n rafRef.current = requestAnimationFrame(loop)\n\n return () => {\n cancelAnimationFrame(rafRef.current)\n if (rendererRef.current) {\n dispose(rendererRef.current)\n rendererRef.current = null\n }\n setIsReady(false)\n }\n }, [fragmentShader, onError, onLoad])\n\n // Canvas resize\n useEffect(() => {\n const canvas = canvasRef.current\n if (!canvas) return\n\n const dpr = pixelRatio ?? (typeof window !== 'undefined' ? window.devicePixelRatio : 1)\n\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect\n canvas.width = Math.round(width * dpr)\n canvas.height = Math.round(height * dpr)\n }\n })\n\n observer.observe(canvas)\n return () => observer.disconnect()\n }, [pixelRatio])\n\n // Mouse / touch events\n useEffect(() => {\n if (!mouseEnabled) return\n const canvas = canvasRef.current\n if (!canvas) return\n\n const toPixel = (cx: number, cy: number) => {\n const r = canvas.getBoundingClientRect()\n const dpr = pixelRatio ?? window.devicePixelRatio\n return {\n x: (cx - r.left) * dpr,\n y: (r.height - (cy - r.top)) * dpr, // flip Y\n }\n }\n\n const onMove = (cx: number, cy: number) => {\n if (!mouseState.current.pressed) return\n const { x, y } = toPixel(cx, cy)\n mouseState.current.x = x\n mouseState.current.y = y\n }\n\n const onDown = (cx: number, cy: number) => {\n const { x, y } = toPixel(cx, cy)\n mouseState.current.x = x\n mouseState.current.y = y\n mouseState.current.clickX = x\n mouseState.current.clickY = y\n mouseState.current.pressed = true\n }\n\n const onUp = () => {\n mouseState.current.pressed = false\n }\n\n const mm = (e: MouseEvent) => onMove(e.clientX, e.clientY)\n const md = (e: MouseEvent) => onDown(e.clientX, e.clientY)\n const mu = () => onUp()\n const tm = (e: TouchEvent) => {\n if (e.touches[0]) onMove(e.touches[0].clientX, e.touches[0].clientY)\n }\n const ts = (e: TouchEvent) => {\n if (e.touches[0]) onDown(e.touches[0].clientX, e.touches[0].clientY)\n }\n const te = () => onUp()\n\n window.addEventListener('mousemove', mm)\n canvas.addEventListener('mousedown', md)\n window.addEventListener('mouseup', mu)\n window.addEventListener('touchmove', tm, { passive: true })\n canvas.addEventListener('touchstart', ts, { passive: true })\n window.addEventListener('touchend', te)\n\n return () => {\n window.removeEventListener('mousemove', mm)\n canvas.removeEventListener('mousedown', md)\n window.removeEventListener('mouseup', mu)\n window.removeEventListener('touchmove', tm)\n canvas.removeEventListener('touchstart', ts)\n window.removeEventListener('touchend', te)\n }\n }, [mouseEnabled, pixelRatio])\n\n const pause = useCallback(() => { pausedRef.current = true }, [])\n const resume = useCallback(() => { pausedRef.current = false }, [])\n\n return { canvasRef, isReady, error, pause, resume }\n}\n","import type { ShadertoyProps } from './types'\nimport { useShadertoy } from './useShadertoy'\n\nexport function Shadertoy({\n fragmentShader,\n style,\n className,\n paused,\n speed,\n pixelRatio,\n mouse,\n onError,\n onLoad,\n}: ShadertoyProps) {\n const { canvasRef } = useShadertoy({\n fragmentShader,\n paused,\n speed,\n pixelRatio,\n mouse,\n onError,\n onLoad,\n })\n\n return (\n <canvas\n ref={canvasRef}\n className={className}\n style={{ width: '100%', height: '100%', display: 'block', ...style }}\n />\n )\n}\n"]}
|
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/renderer.ts","../src/uniforms.ts","../src/useShadertoy.ts","../src/Shadertoy.tsx"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { RendererState, UniformLocations } from './types'\n\n// Full-screen quad: two triangles covering clip space\nconst QUAD_VERTICES = new Float32Array([\n -1, -1,\n 1, -1,\n -1, 1,\n -1, 1,\n 1, -1,\n 1, 1,\n])\n\nconst VERTEX_SHADER = `\nattribute vec2 position;\nvoid main() {\n gl_Position = vec4(position, 0.0, 1.0);\n}\n`\n\n/**\n * Wrap Shadertoy GLSL: prepend uniform declarations + main() bridge.\n */\nfunction wrapFragmentShader(shader: string): string {\n return `precision highp float;\n\nuniform vec3 iResolution;\nuniform float iTime;\nuniform float iTimeDelta;\nuniform int iFrame;\nuniform vec4 iMouse;\nuniform vec4 iDate;\n\n${shader}\n\nvoid main() {\n mainImage(gl_FragColor, gl_FragCoord.xy);\n}\n`\n}\n\nfunction compileShader(\n gl: WebGLRenderingContext,\n type: number,\n source: string,\n): WebGLShader | string {\n const shader = gl.createShader(type)\n if (!shader) return 'Failed to create shader'\n\n gl.shaderSource(shader, source)\n gl.compileShader(shader)\n\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const log = gl.getShaderInfoLog(shader) || 'Unknown compile error'\n gl.deleteShader(shader)\n return log\n }\n\n return shader\n}\n\n/**\n * Initialize WebGL: compile shaders, link program, setup quad.\n * Returns RendererState on success or error string on failure.\n */\nexport function createRenderer(\n canvas: HTMLCanvasElement,\n fragmentShader: string,\n): RendererState | string {\n const gl = canvas.getContext('webgl', {\n antialias: false,\n alpha: true,\n premultipliedAlpha: false,\n })\n if (!gl) return 'WebGL not supported'\n\n // Compile vertex shader\n const vert = compileShader(gl, gl.VERTEX_SHADER, VERTEX_SHADER)\n if (typeof vert === 'string') return vert\n\n // Compile fragment shader (wrapped)\n const frag = compileShader(gl, gl.FRAGMENT_SHADER, wrapFragmentShader(fragmentShader))\n if (typeof frag === 'string') return frag\n\n // Link program\n const program = gl.createProgram()\n if (!program) return 'Failed to create program'\n\n gl.attachShader(program, vert)\n gl.attachShader(program, frag)\n gl.linkProgram(program)\n\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n const log = gl.getProgramInfoLog(program) || 'Unknown link error'\n gl.deleteProgram(program)\n return log\n }\n\n // Clean up individual shaders (attached to program)\n gl.deleteShader(vert)\n gl.deleteShader(frag)\n\n // Setup quad geometry\n const buffer = gl.createBuffer()\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n gl.bufferData(gl.ARRAY_BUFFER, QUAD_VERTICES, gl.STATIC_DRAW)\n\n const positionLoc = gl.getAttribLocation(program, 'position')\n gl.enableVertexAttribArray(positionLoc)\n gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0)\n\n // Get uniform locations\n const locations: UniformLocations = {\n iResolution: gl.getUniformLocation(program, 'iResolution'),\n iTime: gl.getUniformLocation(program, 'iTime'),\n iTimeDelta: gl.getUniformLocation(program, 'iTimeDelta'),\n iFrame: gl.getUniformLocation(program, 'iFrame'),\n iMouse: gl.getUniformLocation(program, 'iMouse'),\n iDate: gl.getUniformLocation(program, 'iDate'),\n }\n\n gl.useProgram(program)\n\n return {\n gl,\n program,\n locations,\n time: 0,\n frame: 0,\n lastTime: 0,\n }\n}\n\n/**\n * Render one frame.\n */\nexport function render(state: RendererState): void {\n const { gl } = state\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight)\n gl.drawArrays(gl.TRIANGLES, 0, 6)\n}\n\n/**\n * Clean up WebGL resources.\n */\nexport function dispose(state: RendererState): void {\n const { gl, program } = state\n gl.deleteProgram(program)\n gl.getExtension('WEBGL_lose_context')?.loseContext()\n}\n","import type { MouseState, RendererState } from './types'\n\n/**\n * Update all Shadertoy standard uniforms for one frame.\n */\nexport function updateUniforms(\n state: RendererState,\n delta: number,\n speed: number,\n mouse: MouseState,\n): void {\n const { gl, locations } = state\n\n // iTime\n state.time += delta * speed\n if (locations.iTime) {\n gl.uniform1f(locations.iTime, state.time)\n }\n\n // iTimeDelta\n if (locations.iTimeDelta) {\n gl.uniform1f(locations.iTimeDelta, delta)\n }\n\n // iFrame\n state.frame++\n if (locations.iFrame) {\n gl.uniform1i(locations.iFrame, state.frame)\n }\n\n // iResolution\n if (locations.iResolution) {\n gl.uniform3f(\n locations.iResolution,\n gl.drawingBufferWidth,\n gl.drawingBufferHeight,\n 1.0,\n )\n }\n\n // iMouse — Shadertoy convention:\n // xy: current position (if pressed)\n // zw: click position (positive when pressed, negative when released)\n if (locations.iMouse) {\n const mz = mouse.pressed ? mouse.clickX : -Math.abs(mouse.clickX)\n const mw = mouse.pressed ? mouse.clickY : -Math.abs(mouse.clickY)\n gl.uniform4f(locations.iMouse, mouse.x, mouse.y, mz, mw)\n }\n\n // iDate — vec4(year, month, day, seconds_since_midnight)\n if (locations.iDate) {\n const now = new Date()\n const seconds =\n now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds() + now.getMilliseconds() / 1000\n gl.uniform4f(\n locations.iDate,\n now.getFullYear(),\n now.getMonth(), // 0-based, matches Shadertoy\n now.getDate(),\n seconds,\n )\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport { createRenderer, dispose, render } from './renderer'\nimport type { MouseState, RendererState, UseShadertoyOptions, UseShadertoyReturn } from './types'\nimport { updateUniforms } from './uniforms'\n\nexport function useShadertoy({\n fragmentShader,\n paused = false,\n speed = 1.0,\n pixelRatio,\n mouse: mouseEnabled = true,\n onError,\n onLoad,\n}: UseShadertoyOptions): UseShadertoyReturn {\n const canvasRef = useRef<HTMLCanvasElement | null>(null)\n const rendererRef = useRef<RendererState | null>(null)\n const rafRef = useRef<number>(0)\n const pausedRef = useRef(paused)\n const speedRef = useRef(speed)\n\n const [isReady, setIsReady] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const mouseState = useRef<MouseState>({\n x: 0, y: 0,\n clickX: 0, clickY: 0,\n pressed: false,\n })\n\n // Keep refs in sync\n pausedRef.current = paused\n speedRef.current = speed\n\n // Initialize WebGL\n useEffect(() => {\n const canvas = canvasRef.current\n if (!canvas) return\n\n const result = createRenderer(canvas, fragmentShader)\n if (typeof result === 'string') {\n setError(result)\n onError?.(result)\n return\n }\n\n rendererRef.current = result\n setIsReady(true)\n setError(null)\n onLoad?.()\n\n // Render loop\n let lastTimestamp = 0\n\n const loop = (timestamp: number) => {\n const delta = lastTimestamp ? (timestamp - lastTimestamp) / 1000 : 0\n lastTimestamp = timestamp\n\n if (!pausedRef.current && rendererRef.current) {\n updateUniforms(rendererRef.current, delta, speedRef.current, mouseState.current)\n render(rendererRef.current)\n }\n\n rafRef.current = requestAnimationFrame(loop)\n }\n\n rafRef.current = requestAnimationFrame(loop)\n\n return () => {\n cancelAnimationFrame(rafRef.current)\n if (rendererRef.current) {\n dispose(rendererRef.current)\n rendererRef.current = null\n }\n setIsReady(false)\n }\n }, [fragmentShader, onError, onLoad])\n\n // Canvas resize\n useEffect(() => {\n const canvas = canvasRef.current\n if (!canvas) return\n\n const dpr = pixelRatio ?? (typeof window !== 'undefined' ? window.devicePixelRatio : 1)\n\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect\n canvas.width = Math.round(width * dpr)\n canvas.height = Math.round(height * dpr)\n }\n })\n\n observer.observe(canvas)\n return () => observer.disconnect()\n }, [pixelRatio])\n\n // Mouse / touch events\n useEffect(() => {\n if (!mouseEnabled) return\n const canvas = canvasRef.current\n if (!canvas) return\n\n const toPixel = (cx: number, cy: number) => {\n const r = canvas.getBoundingClientRect()\n const dpr = pixelRatio ?? window.devicePixelRatio\n return {\n x: (cx - r.left) * dpr,\n y: (r.height - (cy - r.top)) * dpr, // flip Y\n }\n }\n\n const onMove = (cx: number, cy: number) => {\n if (!mouseState.current.pressed) return\n const { x, y } = toPixel(cx, cy)\n mouseState.current.x = x\n mouseState.current.y = y\n }\n\n const onDown = (cx: number, cy: number) => {\n const { x, y } = toPixel(cx, cy)\n mouseState.current.x = x\n mouseState.current.y = y\n mouseState.current.clickX = x\n mouseState.current.clickY = y\n mouseState.current.pressed = true\n }\n\n const onUp = () => {\n mouseState.current.pressed = false\n }\n\n const mm = (e: MouseEvent) => onMove(e.clientX, e.clientY)\n const md = (e: MouseEvent) => onDown(e.clientX, e.clientY)\n const mu = () => onUp()\n const tm = (e: TouchEvent) => {\n if (e.touches[0]) onMove(e.touches[0].clientX, e.touches[0].clientY)\n }\n const ts = (e: TouchEvent) => {\n if (e.touches[0]) onDown(e.touches[0].clientX, e.touches[0].clientY)\n }\n const te = () => onUp()\n\n window.addEventListener('mousemove', mm)\n canvas.addEventListener('mousedown', md)\n window.addEventListener('mouseup', mu)\n window.addEventListener('touchmove', tm, { passive: true })\n canvas.addEventListener('touchstart', ts, { passive: true })\n window.addEventListener('touchend', te)\n\n return () => {\n window.removeEventListener('mousemove', mm)\n canvas.removeEventListener('mousedown', md)\n window.removeEventListener('mouseup', mu)\n window.removeEventListener('touchmove', tm)\n canvas.removeEventListener('touchstart', ts)\n window.removeEventListener('touchend', te)\n }\n }, [mouseEnabled, pixelRatio])\n\n const pause = useCallback(() => { pausedRef.current = true }, [])\n const resume = useCallback(() => { pausedRef.current = false }, [])\n\n return { canvasRef, isReady, error, pause, resume }\n}\n","import type { ShadertoyProps } from './types'\nimport { useShadertoy } from './useShadertoy'\n\nexport function Shadertoy({\n fragmentShader,\n style,\n className,\n paused,\n speed,\n pixelRatio,\n mouse,\n onError,\n onLoad,\n}: ShadertoyProps) {\n const { canvasRef } = useShadertoy({\n fragmentShader,\n paused,\n speed,\n pixelRatio,\n mouse,\n onError,\n onLoad,\n })\n\n return (\n <canvas\n ref={canvasRef}\n className={className}\n style={{ width: '100%', height: '100%', display: 'block', ...style }}\n />\n )\n}\n"]}
|