@fjandin/react-shader 0.0.18 → 0.0.20

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.js CHANGED
@@ -220,30 +220,15 @@ function isVec3(value) {
220
220
  function isVec4(value) {
221
221
  return Array.isArray(value) && value.length === 4 && typeof value[0] === "number";
222
222
  }
223
- function isVec4Array(value) {
224
- return Array.isArray(value) && value.length > 0 && Array.isArray(value[0]) && value[0].length === 4;
225
- }
226
223
  function inferWgslType(value) {
227
- if (typeof value === "number") {
228
- return { wgslType: "f32", baseType: "f32", isArray: false, arrayLength: 0 };
229
- }
230
- if (isVec4Array(value)) {
231
- return {
232
- wgslType: `array<vec4f, 100>`,
233
- baseType: "vec4f",
234
- isArray: true,
235
- arrayLength: 100
236
- };
237
- }
238
- if (isVec4(value)) {
239
- return { wgslType: "vec4f", baseType: "vec4f", isArray: false, arrayLength: 0 };
240
- }
241
- if (isVec3(value)) {
242
- return { wgslType: "vec3f", baseType: "vec3f", isArray: false, arrayLength: 0 };
243
- }
244
- if (isVec2(value)) {
245
- return { wgslType: "vec2f", baseType: "vec2f", isArray: false, arrayLength: 0 };
246
- }
224
+ if (typeof value === "number")
225
+ return "f32";
226
+ if (isVec4(value))
227
+ return "vec4f";
228
+ if (isVec3(value))
229
+ return "vec3f";
230
+ if (isVec2(value))
231
+ return "vec2f";
247
232
  throw new Error(`Unsupported uniform value type: ${typeof value}`);
248
233
  }
249
234
  function getTypeAlignment(type) {
@@ -269,7 +254,6 @@ function getTypeSize(type) {
269
254
  return 16;
270
255
  }
271
256
  }
272
- var UNIFORM_ARRAY_STRIDE = 16;
273
257
  var DEFAULT_UNIFORMS = [
274
258
  { name: "iTime", baseType: "f32" },
275
259
  { name: "iMouseLeftDown", baseType: "f32" },
@@ -284,49 +268,20 @@ function calculateUniformLayout(customUniforms) {
284
268
  const alignment = getTypeAlignment(baseType);
285
269
  const size = getTypeSize(baseType);
286
270
  offset = Math.ceil(offset / alignment) * alignment;
287
- fields.push({ name, type: baseType, offset, size, isArray: false });
271
+ fields.push({ name, type: baseType, offset, size });
288
272
  offset += size;
289
273
  };
290
- const addArrayField = (name, baseType, arrayLength) => {
291
- offset = Math.ceil(offset / 16) * 16;
292
- const totalSize = arrayLength * UNIFORM_ARRAY_STRIDE;
293
- fields.push({
294
- name,
295
- type: `array<${baseType}, ${arrayLength}>`,
296
- offset,
297
- size: totalSize,
298
- isArray: true,
299
- arrayLength,
300
- elementStride: UNIFORM_ARRAY_STRIDE
301
- });
302
- offset += totalSize;
303
- };
304
274
  for (const u of DEFAULT_UNIFORMS) {
305
275
  addField(u.name, u.baseType);
306
276
  }
307
277
  if (customUniforms) {
308
- const scalarEntries = [];
309
- const arrayEntries = [];
310
- for (const [name, value] of Object.entries(customUniforms)) {
311
- const inferred = inferWgslType(value);
312
- if (inferred.isArray) {
313
- arrayEntries.push({ name, inferred });
314
- } else {
315
- scalarEntries.push({ name, inferred });
316
- }
317
- }
318
- for (const { name } of arrayEntries) {
319
- scalarEntries.push({
320
- name: `${name}_count`,
321
- inferred: { wgslType: "f32", baseType: "f32", isArray: false, arrayLength: 0 }
322
- });
323
- }
324
- scalarEntries.sort((a, b) => getTypeAlignment(b.inferred.baseType) - getTypeAlignment(a.inferred.baseType));
325
- for (const { name, inferred } of scalarEntries) {
326
- addField(name, inferred.baseType);
327
- }
328
- for (const { name, inferred } of arrayEntries) {
329
- addArrayField(name, inferred.baseType, inferred.arrayLength);
278
+ const entries = Object.entries(customUniforms).map(([name, value]) => ({
279
+ name,
280
+ baseType: inferWgslType(value)
281
+ }));
282
+ entries.sort((a, b) => getTypeAlignment(b.baseType) - getTypeAlignment(a.baseType));
283
+ for (const { name, baseType } of entries) {
284
+ addField(name, baseType);
330
285
  }
331
286
  }
332
287
  const bufferSize = Math.ceil(offset / 16) * 16;
@@ -341,21 +296,9 @@ ${members}
341
296
  }
342
297
  function packUniformValue(field, value, floatData) {
343
298
  const floatOffset = field.offset / 4;
344
- if (field.isArray && field.elementStride && field.arrayLength) {
345
- const stride = field.elementStride / 4;
346
- const maxLen = field.arrayLength;
347
- if (isVec4Array(value)) {
348
- for (let i = 0;i < value.length && i < maxLen; i++) {
349
- const elemOffset = floatOffset + i * stride;
350
- floatData[elemOffset] = value[i][0];
351
- floatData[elemOffset + 1] = value[i][1];
352
- floatData[elemOffset + 2] = value[i][2];
353
- floatData[elemOffset + 3] = value[i][3];
354
- }
355
- }
356
- } else if (typeof value === "number") {
299
+ if (typeof value === "number") {
357
300
  floatData[floatOffset] = value;
358
- } else if (Array.isArray(value) && typeof value[0] === "number") {
301
+ } else if (Array.isArray(value)) {
359
302
  for (let i = 0;i < value.length; i++) {
360
303
  floatData[floatOffset + i] = value[i];
361
304
  }
@@ -383,11 +326,60 @@ fn main(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
383
326
  return output;
384
327
  }
385
328
  `;
386
- function createFragmentShader(userCode, layout) {
329
+ function getStorageBufferNames(defs) {
330
+ if (!defs)
331
+ return [];
332
+ return Object.keys(defs).sort();
333
+ }
334
+ function createStorageBuffer(device, name, binding, data) {
335
+ const length = Math.max(data.length, 1);
336
+ const byteSize = length * 16;
337
+ const buffer = device.createBuffer({
338
+ label: `storage: ${name}`,
339
+ size: byteSize,
340
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
341
+ });
342
+ const packingArray = new Float32Array(length * 4);
343
+ for (let i = 0;i < data.length; i++) {
344
+ const off = i * 4;
345
+ packingArray[off] = data[i][0];
346
+ packingArray[off + 1] = data[i][1];
347
+ packingArray[off + 2] = data[i][2];
348
+ packingArray[off + 3] = data[i][3];
349
+ }
350
+ device.queue.writeBuffer(buffer, 0, packingArray);
351
+ return { name, binding, buffer, currentLength: length, dataLength: data.length, packingArray };
352
+ }
353
+ function packAndUploadStorageBuffer(device, entry, data) {
354
+ const arr = entry.packingArray;
355
+ for (let i = 0;i < data.length; i++) {
356
+ const off = i * 4;
357
+ arr[off] = data[i][0];
358
+ arr[off + 1] = data[i][1];
359
+ arr[off + 2] = data[i][2];
360
+ arr[off + 3] = data[i][3];
361
+ }
362
+ const uploadLength = Math.max(entry.dataLength, 1);
363
+ device.queue.writeBuffer(entry.buffer, 0, arr, 0, uploadLength * 4);
364
+ }
365
+ function rebuildBindGroup(state) {
366
+ const entries = [{ binding: 0, resource: { buffer: state.uniformBuffer } }];
367
+ for (const sb of state.storageBuffers) {
368
+ entries.push({ binding: sb.binding, resource: { buffer: sb.buffer } });
369
+ }
370
+ return state.device.createBindGroup({
371
+ layout: state.bindGroupLayout,
372
+ entries
373
+ });
374
+ }
375
+ function createFragmentShader(userCode, layout, storageBufferNames) {
376
+ const storageDeclarations = storageBufferNames.map((name, i) => `@group(0) @binding(${i + 1}) var<storage, read> ${name}: array<vec4f>;`).join(`
377
+ `);
387
378
  return `
388
379
  ${generateUniformStruct(layout)}
389
380
 
390
381
  @group(0) @binding(0) var<uniform> uniforms: Uniforms;
382
+ ${storageDeclarations}
391
383
 
392
384
  ${userCode}
393
385
 
@@ -400,7 +392,7 @@ fn main(@location(0) uv: vec2f) -> @location(0) vec4f {
400
392
  }
401
393
  `;
402
394
  }
403
- async function initializeWebGPU(canvas, fragmentSource, customUniforms) {
395
+ async function initializeWebGPU(canvas, fragmentSource, customUniforms, storageBufferDefs) {
404
396
  if (!navigator.gpu) {
405
397
  throw new Error("WebGPU not supported in this browser");
406
398
  }
@@ -409,6 +401,9 @@ async function initializeWebGPU(canvas, fragmentSource, customUniforms) {
409
401
  throw new Error("Failed to get WebGPU adapter");
410
402
  }
411
403
  const device = await adapter.requestDevice();
404
+ device.lost.then((info) => {
405
+ console.error(`WebGPU device lost: ${info.message}`);
406
+ });
412
407
  const context = canvas.getContext("webgpu");
413
408
  if (!context) {
414
409
  throw new Error("Failed to get WebGPU context");
@@ -420,36 +415,43 @@ async function initializeWebGPU(canvas, fragmentSource, customUniforms) {
420
415
  alphaMode: "premultiplied"
421
416
  });
422
417
  const uniformLayout = calculateUniformLayout(customUniforms);
418
+ const storageBufferNames = getStorageBufferNames(storageBufferDefs);
423
419
  const vertexModule = device.createShaderModule({
424
420
  label: "vertex shader",
425
421
  code: VERTEX_SHADER
426
422
  });
427
423
  const fragmentModule = device.createShaderModule({
428
424
  label: "fragment shader",
429
- code: createFragmentShader(fragmentSource, uniformLayout)
425
+ code: createFragmentShader(fragmentSource, uniformLayout, storageBufferNames)
430
426
  });
431
427
  const uniformBuffer = device.createBuffer({
432
428
  label: "uniforms",
433
429
  size: uniformLayout.bufferSize,
434
430
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
435
431
  });
436
- const bindGroupLayout = device.createBindGroupLayout({
437
- entries: [
438
- {
439
- binding: 0,
440
- visibility: GPUShaderStage.FRAGMENT,
441
- buffer: { type: "uniform" }
442
- }
443
- ]
444
- });
432
+ const storageBuffers = storageBufferNames.map((name, i) => createStorageBuffer(device, name, i + 1, storageBufferDefs?.[name] ?? []));
433
+ const layoutEntries = [
434
+ {
435
+ binding: 0,
436
+ visibility: GPUShaderStage.FRAGMENT,
437
+ buffer: { type: "uniform" }
438
+ }
439
+ ];
440
+ for (const sb of storageBuffers) {
441
+ layoutEntries.push({
442
+ binding: sb.binding,
443
+ visibility: GPUShaderStage.FRAGMENT,
444
+ buffer: { type: "read-only-storage" }
445
+ });
446
+ }
447
+ const bindGroupLayout = device.createBindGroupLayout({ entries: layoutEntries });
448
+ const bindGroupEntries = [{ binding: 0, resource: { buffer: uniformBuffer } }];
449
+ for (const sb of storageBuffers) {
450
+ bindGroupEntries.push({ binding: sb.binding, resource: { buffer: sb.buffer } });
451
+ }
445
452
  const uniformBindGroup = device.createBindGroup({
446
453
  layout: bindGroupLayout,
447
- entries: [
448
- {
449
- binding: 0,
450
- resource: { buffer: uniformBuffer }
451
- }
452
- ]
454
+ entries: bindGroupEntries
453
455
  });
454
456
  const pipelineLayout = device.createPipelineLayout({
455
457
  bindGroupLayouts: [bindGroupLayout]
@@ -473,10 +475,26 @@ async function initializeWebGPU(canvas, fragmentSource, customUniforms) {
473
475
  pipeline,
474
476
  uniformBuffer,
475
477
  uniformBindGroup,
476
- uniformLayout
478
+ uniformLayout,
479
+ bindGroupLayout,
480
+ storageBuffers,
481
+ renderPassDescriptor: {
482
+ colorAttachments: [
483
+ {
484
+ view: undefined,
485
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
486
+ loadOp: "clear",
487
+ storeOp: "store"
488
+ }
489
+ ]
490
+ },
491
+ submitArray: [null]
477
492
  };
478
493
  }
479
494
  function cleanupWebGPU(state) {
495
+ for (const sb of state.storageBuffers) {
496
+ sb.buffer.destroy();
497
+ }
480
498
  state.uniformBuffer.destroy();
481
499
  state.device.destroy();
482
500
  }
@@ -488,6 +506,7 @@ function useWebGPU(options) {
488
506
  const lastFrameTimeRef = useRef2(0);
489
507
  const mouseRef = useRef2([0, 0]);
490
508
  const mouseNormalizedRef = useRef2([0, 0]);
509
+ const resolutionRef = useRef2([0, 0]);
491
510
  const mouseLeftDownRef = useRef2(false);
492
511
  const canvasRectRef = useRef2(null);
493
512
  const onErrorRef = useRef2(options.onError);
@@ -500,7 +519,18 @@ function useWebGPU(options) {
500
519
  const timeScaleRef = useRef2(options.timeScale ?? 1);
501
520
  const fragmentRef = useRef2(options.fragment);
502
521
  const uniformsRef = useRef2(options.uniforms);
522
+ const storageBuffersRef = useRef2(options.storageBuffers);
503
523
  const dprRef = useRef2(window.devicePixelRatio || 1);
524
+ const uniformDataRef = useRef2(null);
525
+ const allValuesRef = useRef2({});
526
+ const frameInfoRef = useRef2({
527
+ deltaTime: 0,
528
+ time: 0,
529
+ resolution: [0, 0],
530
+ mouse: [0, 0],
531
+ mouseNormalized: [0, 0],
532
+ mouseLeftDown: false
533
+ });
504
534
  onErrorRef.current = options.onError;
505
535
  onFrameRef.current = options.onFrame;
506
536
  onClickRef.current = options.onClick;
@@ -511,17 +541,7 @@ function useWebGPU(options) {
511
541
  timeScaleRef.current = options.timeScale ?? 1;
512
542
  fragmentRef.current = options.fragment;
513
543
  uniformsRef.current = options.uniforms;
514
- const buildFrameInfo = useCallback2((deltaTime) => {
515
- const canvas = canvasRef.current;
516
- return {
517
- deltaTime,
518
- time: elapsedTimeRef.current,
519
- resolution: [canvas?.width ?? 0, canvas?.height ?? 0],
520
- mouse: mouseRef.current,
521
- mouseNormalized: mouseNormalizedRef.current,
522
- mouseLeftDown: mouseLeftDownRef.current
523
- };
524
- }, []);
544
+ storageBuffersRef.current = options.storageBuffers;
525
545
  const render = useCallback2((time) => {
526
546
  const state = stateRef.current;
527
547
  const canvas = canvasRef.current;
@@ -531,10 +551,18 @@ function useWebGPU(options) {
531
551
  const deltaTime = lastFrameTimeRef.current === 0 ? 0 : (time - lastFrameTimeRef.current) / 1000;
532
552
  lastFrameTimeRef.current = time;
533
553
  elapsedTimeRef.current += deltaTime * timeScaleRef.current;
554
+ const info = frameInfoRef.current;
555
+ info.deltaTime = deltaTime;
556
+ info.time = elapsedTimeRef.current;
557
+ info.resolution[0] = canvas.width;
558
+ info.resolution[1] = canvas.height;
559
+ info.mouse = mouseRef.current;
560
+ info.mouseNormalized = mouseNormalizedRef.current;
561
+ info.mouseLeftDown = mouseLeftDownRef.current;
534
562
  if (onFrameRef.current) {
535
- onFrameRef.current(buildFrameInfo(deltaTime));
563
+ onFrameRef.current(frameInfoRef.current);
536
564
  }
537
- const { device, context, pipeline, uniformBuffer, uniformBindGroup, uniformLayout } = state;
565
+ const { device, context, pipeline, uniformBuffer, uniformLayout } = state;
538
566
  const dpr = dprRef.current;
539
567
  const displayWidth = canvas.clientWidth;
540
568
  const displayHeight = canvas.clientHeight;
@@ -548,22 +576,21 @@ function useWebGPU(options) {
548
576
  canvas.width = bufferWidth;
549
577
  canvas.height = bufferHeight;
550
578
  }
551
- const defaultValues = {
552
- iTime: elapsedTimeRef.current,
553
- iMouseLeftDown: mouseLeftDownRef.current ? 1 : 0,
554
- iResolution: [canvas.width, canvas.height],
555
- iMouse: mouseRef.current,
556
- iMouseNormalized: mouseNormalizedRef.current
557
- };
558
- const allValues = { ...defaultValues, ...uniformsRef.current };
559
- if (uniformsRef.current) {
560
- for (const [name, value] of Object.entries(uniformsRef.current)) {
561
- if (isVec4Array(value)) {
562
- allValues[`${name}_count`] = value.length;
563
- }
579
+ const allValues = allValuesRef.current;
580
+ allValues.iTime = elapsedTimeRef.current;
581
+ allValues.iMouseLeftDown = mouseLeftDownRef.current ? 1 : 0;
582
+ resolutionRef.current[0] = canvas.width;
583
+ resolutionRef.current[1] = canvas.height;
584
+ allValues.iResolution = resolutionRef.current;
585
+ allValues.iMouse = mouseRef.current;
586
+ allValues.iMouseNormalized = mouseNormalizedRef.current;
587
+ const customs = uniformsRef.current;
588
+ if (customs) {
589
+ for (const name in customs) {
590
+ allValues[name] = customs[name];
564
591
  }
565
592
  }
566
- const uniformData = new Float32Array(uniformLayout.bufferSize / 4);
593
+ const uniformData = uniformDataRef.current;
567
594
  for (const field of uniformLayout.fields) {
568
595
  const value = allValues[field.name];
569
596
  if (value === undefined) {
@@ -572,25 +599,43 @@ function useWebGPU(options) {
572
599
  packUniformValue(field, value, uniformData);
573
600
  }
574
601
  device.queue.writeBuffer(uniformBuffer, 0, uniformData);
602
+ let needsBindGroupRebuild = false;
603
+ for (const entry of state.storageBuffers) {
604
+ const data = storageBuffersRef.current?.[entry.name];
605
+ if (!data)
606
+ continue;
607
+ const requiredLength = Math.max(data.length, 1);
608
+ if (requiredLength > entry.currentLength || requiredLength < entry.currentLength / 2) {
609
+ const allocLength = Math.max(Math.ceil(requiredLength * 1.5), 1);
610
+ entry.buffer.destroy();
611
+ const byteSize = allocLength * 16;
612
+ entry.buffer = device.createBuffer({
613
+ label: `storage: ${entry.name}`,
614
+ size: byteSize,
615
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
616
+ });
617
+ entry.packingArray = new Float32Array(allocLength * 4);
618
+ entry.currentLength = allocLength;
619
+ needsBindGroupRebuild = true;
620
+ }
621
+ entry.dataLength = data.length;
622
+ packAndUploadStorageBuffer(device, entry, data);
623
+ }
624
+ if (needsBindGroupRebuild) {
625
+ state.uniformBindGroup = rebuildBindGroup(state);
626
+ }
575
627
  const commandEncoder = device.createCommandEncoder();
576
628
  const textureView = context.getCurrentTexture().createView();
577
- const renderPass = commandEncoder.beginRenderPass({
578
- colorAttachments: [
579
- {
580
- view: textureView,
581
- clearValue: { r: 0, g: 0, b: 0, a: 1 },
582
- loadOp: "clear",
583
- storeOp: "store"
584
- }
585
- ]
586
- });
629
+ state.renderPassDescriptor.colorAttachments[0].view = textureView;
630
+ const renderPass = commandEncoder.beginRenderPass(state.renderPassDescriptor);
587
631
  renderPass.setPipeline(pipeline);
588
- renderPass.setBindGroup(0, uniformBindGroup);
632
+ renderPass.setBindGroup(0, state.uniformBindGroup);
589
633
  renderPass.draw(3);
590
634
  renderPass.end();
591
- device.queue.submit([commandEncoder.finish()]);
635
+ state.submitArray[0] = commandEncoder.finish();
636
+ device.queue.submit(state.submitArray);
592
637
  animationFrameRef.current = requestAnimationFrame(render);
593
- }, [buildFrameInfo]);
638
+ }, []);
594
639
  useEffect(() => {
595
640
  const canvas = canvasRef.current;
596
641
  if (!canvas)
@@ -598,12 +643,13 @@ function useWebGPU(options) {
598
643
  let mounted = true;
599
644
  const initialize = async () => {
600
645
  try {
601
- const state = await initializeWebGPU(canvas, fragmentRef.current, uniformsRef.current);
646
+ const state = await initializeWebGPU(canvas, fragmentRef.current, uniformsRef.current, storageBuffersRef.current);
602
647
  if (!mounted) {
603
648
  cleanupWebGPU(state);
604
649
  return;
605
650
  }
606
651
  stateRef.current = state;
652
+ uniformDataRef.current = new Float32Array(state.uniformLayout.bufferSize / 4);
607
653
  elapsedTimeRef.current = 0;
608
654
  lastFrameTimeRef.current = 0;
609
655
  animationFrameRef.current = requestAnimationFrame(render);
@@ -658,25 +704,25 @@ function useWebGPU(options) {
658
704
  (mouseRef.current[0] - canvas.width / 2) / minDimension,
659
705
  (mouseRef.current[1] - canvas.height / 2) / minDimension
660
706
  ];
661
- onMouseMoveRef.current?.(buildFrameInfo(0));
707
+ onMouseMoveRef.current?.(frameInfoRef.current);
662
708
  };
663
709
  const handleMouseDown = (event) => {
664
710
  if (event.button === 0) {
665
711
  mouseLeftDownRef.current = true;
666
712
  }
667
- onMouseDownRef.current?.(buildFrameInfo(0));
713
+ onMouseDownRef.current?.(frameInfoRef.current);
668
714
  };
669
715
  const handleMouseUp = (event) => {
670
716
  if (event.button === 0) {
671
717
  mouseLeftDownRef.current = false;
672
718
  }
673
- onMouseUpRef.current?.(buildFrameInfo(0));
719
+ onMouseUpRef.current?.(frameInfoRef.current);
674
720
  };
675
721
  const handleClick = () => {
676
- onClickRef.current?.(buildFrameInfo(0));
722
+ onClickRef.current?.(frameInfoRef.current);
677
723
  };
678
724
  const handleMouseWheel = (event) => {
679
- onMouseWheelRef.current?.(buildFrameInfo(0), event.deltaY);
725
+ onMouseWheelRef.current?.(frameInfoRef.current, event.deltaY);
680
726
  };
681
727
  window.addEventListener("mousemove", handleMouseMove);
682
728
  window.addEventListener("mousedown", handleMouseDown);
@@ -692,7 +738,7 @@ function useWebGPU(options) {
692
738
  canvas.removeEventListener("click", handleClick);
693
739
  window.removeEventListener("wheel", handleMouseWheel);
694
740
  };
695
- }, [buildFrameInfo]);
741
+ }, []);
696
742
  return { canvasRef, mouseRef };
697
743
  }
698
744
 
@@ -720,6 +766,7 @@ function ReactGpuShader({
720
766
  className,
721
767
  fragment,
722
768
  uniforms,
769
+ storageBuffers,
723
770
  fullscreen = false,
724
771
  timeScale,
725
772
  onFrame,
@@ -740,6 +787,7 @@ function ReactGpuShader({
740
787
  const { canvasRef } = useWebGPU({
741
788
  fragment,
742
789
  uniforms,
790
+ storageBuffers,
743
791
  onError: handleError,
744
792
  timeScale,
745
793
  onFrame,
@@ -991,11 +1039,11 @@ function isVec2Array(value) {
991
1039
  function isVec3Array(value) {
992
1040
  return Array.isArray(value) && value.length > 0 && Array.isArray(value[0]) && value[0].length === 3;
993
1041
  }
994
- function isVec4Array2(value) {
1042
+ function isVec4Array(value) {
995
1043
  return Array.isArray(value) && value.length > 0 && Array.isArray(value[0]) && value[0].length === 4;
996
1044
  }
997
1045
  function isArrayUniform(value) {
998
- return isFloatArray(value) || isVec2Array(value) || isVec3Array(value) || isVec4Array2(value);
1046
+ return isFloatArray(value) || isVec2Array(value) || isVec3Array(value) || isVec4Array(value);
999
1047
  }
1000
1048
  function setUniform(gl, location, value) {
1001
1049
  if (location === null) {
@@ -1003,7 +1051,7 @@ function setUniform(gl, location, value) {
1003
1051
  }
1004
1052
  if (typeof value === "number") {
1005
1053
  gl.uniform1f(location, value);
1006
- } else if (isVec4Array2(value)) {
1054
+ } else if (isVec4Array(value)) {
1007
1055
  gl.uniform4fv(location, value.flat());
1008
1056
  } else if (isVec3Array(value)) {
1009
1057
  gl.uniform3fv(location, value.flat());
@@ -1059,7 +1107,7 @@ function getUniformType(value) {
1059
1107
  if (typeof value === "number") {
1060
1108
  return "float";
1061
1109
  }
1062
- if (isVec4Array2(value)) {
1110
+ if (isVec4Array(value)) {
1063
1111
  return `vec4[${MAX_ARRAY_LENGTH}]`;
1064
1112
  }
1065
1113
  if (isVec3Array(value)) {
package/dist/types.d.ts CHANGED
@@ -5,6 +5,8 @@ export type FloatArray = number[];
5
5
  export type Vec2Array = Vec2[];
6
6
  export type Vec3Array = Vec3[];
7
7
  export type Vec4Array = Vec4[];
8
+ export type GpuUniformValue = number | Vec2 | Vec3 | Vec4;
9
+ export type GpuStorageBuffers = Record<string, Vec4Array>;
8
10
  export type TextureSource = HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | ImageBitmap | ImageData | OffscreenCanvas;
9
11
  export type TextureWrap = "repeat" | "clamp" | "mirror";
10
12
  export type TextureMinFilter = "nearest" | "linear" | "mipmap";
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AACnC,MAAM,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAC3C,MAAM,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAEnD,MAAM,MAAM,UAAU,GAAG,MAAM,EAAE,CAAA;AACjC,MAAM,MAAM,SAAS,GAAG,IAAI,EAAE,CAAA;AAC9B,MAAM,MAAM,SAAS,GAAG,IAAI,EAAE,CAAA;AAC9B,MAAM,MAAM,SAAS,GAAG,IAAI,EAAE,CAAA;AAG9B,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAGzD,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;AAEzD,MAAM,MAAM,aAAa,GACrB,gBAAgB,GAChB,iBAAiB,GACjB,gBAAgB,GAChB,WAAW,GACX,SAAS,GACT,eAAe,CAAA;AAEnB,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAA;AACvD,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAC9D,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,QAAQ,CAAA;AAEnD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,aAAa,CAAA;IACrB,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,SAAS,CAAC,EAAE,gBAAgB,CAAA;IAC5B,SAAS,CAAC,EAAE,gBAAgB,CAAA;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,UAAU,GACV,SAAS,GACT,SAAS,GACT,SAAS,GACT,aAAa,GACb,cAAc,CAAA;AAElB,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5B,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvB,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,aAAa,EAAE,OAAO,CAAA;CACvB;AACD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IACvC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACnC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACnC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACvC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACvC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACrC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7D;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,IAAI,CAAA;IACZ,gBAAgB,EAAE,IAAI,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,IAAI,CAAA;CAClB;AAGD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,CAAA;AAClE,MAAM,MAAM,oBAAoB,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,CAAA;AAExF,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,eAAe,CAAA;IACxB,YAAY,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,GAAG,IAAI,CAAA;IACzD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;QACvB,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACrB,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QACrB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KACvB,CAAC,CAAA;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,CAAA;IACnB,aAAa,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,IAAI,CAAA;IAC7C,KAAK,EAAE,oBAAoB,CAAA;IAC3B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;CACnB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjandin/react-shader",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "description": "React component for rendering WebGL shaders",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",