p5 2.2.3 → 2.3.0-rc.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.
Files changed (137) hide show
  1. package/dist/accessibility/color_namer.js +9 -11
  2. package/dist/accessibility/describe.js +0 -1
  3. package/dist/accessibility/gridOutput.js +0 -1
  4. package/dist/accessibility/index.js +9 -10
  5. package/dist/accessibility/outputs.js +0 -1
  6. package/dist/accessibility/textOutput.js +0 -1
  7. package/dist/app.js +11 -10
  8. package/dist/app.node.js +122 -0
  9. package/dist/color/color_conversion.js +9 -11
  10. package/dist/color/creating_reading.js +1 -1
  11. package/dist/color/index.js +2 -2
  12. package/dist/color/p5.Color.js +1 -1
  13. package/dist/color/setting.js +25 -12
  14. package/dist/{constants-BdTiYOQI.js → constants-CYF6mp5_.js} +2 -2
  15. package/dist/core/States.js +1 -1
  16. package/dist/core/constants.js +1 -1
  17. package/dist/core/environment.js +28 -29
  18. package/dist/core/filterShaders.js +1 -1
  19. package/dist/core/friendly_errors/fes_core.js +9 -8
  20. package/dist/core/friendly_errors/file_errors.js +1 -2
  21. package/dist/core/friendly_errors/index.js +1 -1
  22. package/dist/core/friendly_errors/param_validator.js +737 -640
  23. package/dist/core/friendly_errors/sketch_verifier.js +1 -1
  24. package/dist/core/friendly_errors/stacktrace.js +0 -1
  25. package/dist/core/helpers.js +3 -4
  26. package/dist/core/init.js +24 -21
  27. package/dist/core/internationalization.js +1 -1
  28. package/dist/core/legacy.js +9 -11
  29. package/dist/core/main.js +9 -10
  30. package/dist/core/p5.Graphics.js +5 -5
  31. package/dist/core/p5.Renderer.js +3 -3
  32. package/dist/core/p5.Renderer2D.js +9 -10
  33. package/dist/core/p5.Renderer3D.js +5 -5
  34. package/dist/core/rendering.js +5 -5
  35. package/dist/core/structure.js +0 -1
  36. package/dist/core/transform.js +7 -16
  37. package/dist/{creating_reading-C7hu6sg1.js → creating_reading-DLkHH80h.js} +11 -8
  38. package/dist/data/local_storage.js +0 -1
  39. package/dist/dom/dom.js +2 -3
  40. package/dist/dom/index.js +2 -2
  41. package/dist/dom/p5.Element.js +2 -2
  42. package/dist/dom/p5.MediaElement.js +2 -2
  43. package/dist/events/acceleration.js +5 -3
  44. package/dist/events/keyboard.js +0 -1
  45. package/dist/events/pointer.js +0 -2
  46. package/dist/image/const.js +1 -1
  47. package/dist/image/filterRenderer2D.js +19 -12
  48. package/dist/image/image.js +5 -5
  49. package/dist/image/index.js +5 -5
  50. package/dist/image/loading_displaying.js +5 -5
  51. package/dist/image/p5.Image.js +3 -3
  52. package/dist/image/pixels.js +0 -1
  53. package/dist/io/files.js +5 -5
  54. package/dist/io/index.js +5 -5
  55. package/dist/io/p5.Table.js +0 -1
  56. package/dist/io/p5.TableRow.js +0 -1
  57. package/dist/io/p5.XML.js +0 -1
  58. package/dist/{ir_builders-Cd6rU9Vm.js → ir_builders-C2ebb6Lu.js} +234 -1
  59. package/dist/{main-H_nu4eDs.js → main-D2MtO721.js} +107 -136
  60. package/dist/math/Matrices/Matrix.js +1 -1
  61. package/dist/math/Matrices/MatrixNumjs.js +1 -1
  62. package/dist/math/calculation.js +0 -1
  63. package/dist/math/index.js +3 -1
  64. package/dist/math/math.js +3 -17
  65. package/dist/math/noise.js +0 -1
  66. package/dist/math/p5.Matrix.js +1 -2
  67. package/dist/math/p5.Vector.js +233 -279
  68. package/dist/math/patch-vector.js +75 -0
  69. package/dist/math/random.js +0 -1
  70. package/dist/math/trigonometry.js +3 -4
  71. package/dist/{p5.Renderer-BmD2P6Wv.js → p5.Renderer-C0Kzy71d.js} +31 -24
  72. package/dist/{rendering-CC8JNTwG.js → rendering-CvNr0bB8.js} +732 -44
  73. package/dist/shape/2d_primitives.js +1 -4
  74. package/dist/shape/attributes.js +43 -8
  75. package/dist/shape/curves.js +0 -1
  76. package/dist/shape/custom_shapes.js +260 -5
  77. package/dist/shape/index.js +2 -2
  78. package/dist/shape/vertex.js +0 -2
  79. package/dist/strands/ir_builders.js +1 -1
  80. package/dist/strands/ir_types.js +5 -1
  81. package/dist/strands/p5.strands.js +286 -31
  82. package/dist/strands/strands_api.js +179 -8
  83. package/dist/strands/strands_codegen.js +26 -8
  84. package/dist/strands/strands_conditionals.js +1 -1
  85. package/dist/strands/strands_for.js +1 -1
  86. package/dist/strands/strands_node.js +1 -1
  87. package/dist/strands/strands_ternary.js +56 -0
  88. package/dist/strands/strands_transpiler.js +416 -251
  89. package/dist/strands_glslBackend-i-ReKgZo.js +423 -0
  90. package/dist/type/index.js +3 -3
  91. package/dist/type/lib/Typr.js +1 -1
  92. package/dist/type/p5.Font.js +3 -3
  93. package/dist/type/textCore.js +31 -24
  94. package/dist/utilities/conversion.js +0 -1
  95. package/dist/utilities/time_date.js +0 -1
  96. package/dist/utilities/utility_functions.js +0 -1
  97. package/dist/webgl/3d_primitives.js +5 -5
  98. package/dist/webgl/GeometryBuilder.js +1 -1
  99. package/dist/webgl/ShapeBuilder.js +26 -1
  100. package/dist/webgl/enums.js +1 -1
  101. package/dist/webgl/index.js +8 -9
  102. package/dist/webgl/interaction.js +8 -4
  103. package/dist/webgl/light.js +5 -5
  104. package/dist/webgl/loading.js +60 -21
  105. package/dist/webgl/material.js +5 -5
  106. package/dist/webgl/p5.Camera.js +5 -5
  107. package/dist/webgl/p5.Framebuffer.js +5 -5
  108. package/dist/webgl/p5.Geometry.js +3 -5
  109. package/dist/webgl/p5.Quat.js +1 -1
  110. package/dist/webgl/p5.RendererGL.js +17 -21
  111. package/dist/webgl/p5.Shader.js +129 -36
  112. package/dist/webgl/p5.Texture.js +5 -5
  113. package/dist/webgl/strands_glslBackend.js +5 -386
  114. package/dist/webgl/text.js +5 -5
  115. package/dist/webgl/utils.js +5 -5
  116. package/dist/webgl2Compatibility-DA7DLMuq.js +7 -0
  117. package/dist/webgpu/index.js +7 -3
  118. package/dist/webgpu/p5.RendererWebGPU.js +1036 -180
  119. package/dist/webgpu/shaders/color.js +1 -1
  120. package/dist/webgpu/shaders/compute.js +32 -0
  121. package/dist/webgpu/shaders/functions/randomComputeWGSL.js +31 -0
  122. package/dist/webgpu/shaders/functions/randomVertWGSL.js +30 -0
  123. package/dist/webgpu/shaders/functions/randomWGSL.js +30 -0
  124. package/dist/webgpu/shaders/line.js +1 -1
  125. package/dist/webgpu/shaders/material.js +3 -3
  126. package/dist/webgpu/strands_wgslBackend.js +137 -15
  127. package/lib/p5.esm.js +4088 -1950
  128. package/lib/p5.esm.min.js +1 -1
  129. package/lib/p5.js +4088 -1950
  130. package/lib/p5.min.js +1 -1
  131. package/lib/p5.webgpu.esm.js +1638 -306
  132. package/lib/p5.webgpu.js +1637 -305
  133. package/lib/p5.webgpu.min.js +1 -1
  134. package/package.json +6 -1
  135. package/types/global.d.ts +4137 -2396
  136. package/types/p5.d.ts +2702 -1658
  137. package/dist/noise3DGLSL-Bwrdi4gi.js +0 -9
@@ -1,4 +1,4 @@
1
- import { ae as THRESHOLD, af as POSTERIZE, ab as BLUR } from '../constants-BdTiYOQI.js';
1
+ import { af as THRESHOLD, ag as POSTERIZE, ac as BLUR } from '../constants-CYF6mp5_.js';
2
2
 
3
3
  const filterParamDefaults = {
4
4
  [BLUR]: 3,
@@ -1,15 +1,16 @@
1
1
  import { Shader } from '../webgl/p5.Shader.js';
2
- import { s as setWebGLUniformValue, e as setWebGLTextureParams, g as getWebGLUniformMetadata, h as getWebGLShaderAttributes, j as populateGLSLHooks, T as Texture } from '../rendering-CC8JNTwG.js';
3
- import { I as Image } from '../p5.Renderer-BmD2P6Wv.js';
4
- import { C as CLAMP, aa as WEBGL2, p as CORNER, B as BLEND, ab as BLUR, ac as WEBGL } from '../constants-BdTiYOQI.js';
2
+ import { s as setWebGLUniformValue, e as setWebGLTextureParams, g as getWebGLUniformMetadata, h as getWebGLShaderAttributes, j as populateGLSLHooks, T as Texture } from '../rendering-CvNr0bB8.js';
3
+ import { I as Image } from '../p5.Renderer-C0Kzy71d.js';
4
+ import { C as CLAMP, ab as WEBGL2, n as CORNER, B as BLEND, ac as BLUR, ad as WEBGL } from '../constants-CYF6mp5_.js';
5
5
  import { filterParamDefaults } from './const.js';
6
- import { w as webgl2CompatibilityShader, f as filterBaseVert, a as filterBaseFrag, n as noiseGLSL } from '../noise3DGLSL-Bwrdi4gi.js';
7
- import { glslBackend } from '../webgl/strands_glslBackend.js';
6
+ import { w as webgl2CompatibilityShader, f as filterBaseVert, a as filterBaseFrag } from '../webgl2Compatibility-DA7DLMuq.js';
7
+ import { g as glslBackend, r as randomGLSL, a as randomVertGLSL } from '../strands_glslBackend-i-ReKgZo.js';
8
8
  import { getShaderHookTypes } from '../webgl/shaderHookUtils.js';
9
9
  import { makeFilterShader } from '../core/filterShaders.js';
10
- import '../creating_reading-C7hu6sg1.js';
10
+ import '../creating_reading-DLkHH80h.js';
11
11
  import 'colorjs.io/fn';
12
12
  import '../color/color_spaces/hsb.js';
13
+ import '../strands/ir_types.js';
13
14
  import '../dom/p5.Element.js';
14
15
  import '../dom/p5.File.js';
15
16
  import '../io/p5.XML.js';
@@ -23,7 +24,6 @@ import '../color/setting.js';
23
24
  import 'omggif';
24
25
  import '../io/csv.js';
25
26
  import '../io/utilities.js';
26
- import 'gifenc';
27
27
  import './pixels.js';
28
28
  import './filters.js';
29
29
  import '../core/transform.js';
@@ -44,10 +44,9 @@ import '../type/textCore.js';
44
44
  import '../core/States.js';
45
45
  import '../webgl/enums.js';
46
46
  import '../math/trigonometry.js';
47
- import '../strands/ir_types.js';
48
47
  import '../strands/ir_dag.js';
49
48
  import '../strands/strands_FES.js';
50
- import '../ir_builders-Cd6rU9Vm.js';
49
+ import '../ir_builders-C2ebb6Lu.js';
51
50
  import '../strands/ir_cfg.js';
52
51
  import '../strands/strands_builtins.js';
53
52
 
@@ -330,15 +329,23 @@ class FilterRenderer2D {
330
329
  'vec4 getColor': `(FilterInputs inputs, in sampler2D canvasContent) {
331
330
  return getTexture(canvasContent, inputs.texCoord);
332
331
  }`
333
- }
332
+ },
333
+ hookAliases: {
334
+ 'getColor': ['filterColor'],
335
+ },
334
336
  }
335
337
  );
336
338
  }
337
339
  return this._baseFilterShader;
338
340
  }
339
341
 
340
- getNoiseShaderSnippet() {
341
- return noiseGLSL;
342
+
343
+ getRandomFragmentShaderSnippet() {
344
+ return randomGLSL;
345
+ }
346
+
347
+ getRandomVertexShaderSnippet() {
348
+ return randomVertGLSL;
342
349
  }
343
350
 
344
351
  /**
@@ -1,13 +1,14 @@
1
1
  import 'omggif';
2
2
  import '../dom/p5.Element.js';
3
- export { i as default } from '../rendering-CC8JNTwG.js';
3
+ export { i as default } from '../rendering-CvNr0bB8.js';
4
4
  import '../dom/p5.File.js';
5
5
  import '../io/p5.XML.js';
6
- import '../creating_reading-C7hu6sg1.js';
6
+ import '../creating_reading-DLkHH80h.js';
7
7
  import 'colorjs.io/fn';
8
8
  import '../color/color_spaces/hsb.js';
9
- import '../constants-BdTiYOQI.js';
10
- import '../p5.Renderer-BmD2P6Wv.js';
9
+ import '../constants-CYF6mp5_.js';
10
+ import '../strands/ir_types.js';
11
+ import '../p5.Renderer-C0Kzy71d.js';
11
12
  import './filters.js';
12
13
  import '../math/p5.Vector.js';
13
14
  import '../shape/custom_shapes.js';
@@ -21,7 +22,6 @@ import '../shape/curves.js';
21
22
  import '../shape/vertex.js';
22
23
  import '../color/setting.js';
23
24
  import '../io/csv.js';
24
- import 'gifenc';
25
25
  import './pixels.js';
26
26
  import '../core/transform.js';
27
27
  import '../webgl/GeometryBuilder.js';
@@ -1,11 +1,12 @@
1
- import { i as image$1, b as loadingDisplaying, t as texture } from '../rendering-CC8JNTwG.js';
2
- import { i as image$2 } from '../p5.Renderer-BmD2P6Wv.js';
1
+ import { i as image$1, l as loadingDisplaying, t as texture } from '../rendering-CvNr0bB8.js';
2
+ import { i as image$2 } from '../p5.Renderer-C0Kzy71d.js';
3
3
  import pixels from './pixels.js';
4
4
  import shader from '../webgl/p5.Shader.js';
5
- import '../constants-BdTiYOQI.js';
6
- import '../creating_reading-C7hu6sg1.js';
5
+ import '../constants-CYF6mp5_.js';
6
+ import '../creating_reading-DLkHH80h.js';
7
7
  import 'colorjs.io/fn';
8
8
  import '../color/color_spaces/hsb.js';
9
+ import '../strands/ir_types.js';
9
10
  import '../dom/p5.Element.js';
10
11
  import '../dom/p5.File.js';
11
12
  import '../io/p5.XML.js';
@@ -19,7 +20,6 @@ import '../color/setting.js';
19
20
  import 'omggif';
20
21
  import '../io/csv.js';
21
22
  import '../io/utilities.js';
22
- import 'gifenc';
23
23
  import '../core/transform.js';
24
24
  import '../webgl/GeometryBuilder.js';
25
25
  import '../math/p5.Matrix.js';
@@ -1,15 +1,15 @@
1
1
  import '../core/helpers.js';
2
- import '../constants-BdTiYOQI.js';
3
- export { b as default } from '../rendering-CC8JNTwG.js';
2
+ import '../constants-CYF6mp5_.js';
3
+ export { l as default } from '../rendering-CvNr0bB8.js';
4
4
  import 'omggif';
5
- import 'gifenc';
6
- import '../creating_reading-C7hu6sg1.js';
5
+ import '../creating_reading-DLkHH80h.js';
7
6
  import 'colorjs.io/fn';
8
7
  import '../color/color_spaces/hsb.js';
8
+ import '../strands/ir_types.js';
9
9
  import '../dom/p5.Element.js';
10
10
  import '../dom/p5.File.js';
11
11
  import '../io/p5.XML.js';
12
- import '../p5.Renderer-BmD2P6Wv.js';
12
+ import '../p5.Renderer-C0Kzy71d.js';
13
13
  import './filters.js';
14
14
  import '../math/p5.Vector.js';
15
15
  import '../shape/custom_shapes.js';
@@ -1,10 +1,10 @@
1
1
  import './filters.js';
2
- export { I as Image, i as default } from '../p5.Renderer-BmD2P6Wv.js';
2
+ export { I as Image, i as default } from '../p5.Renderer-C0Kzy71d.js';
3
3
  import '../io/utilities.js';
4
- import '../creating_reading-C7hu6sg1.js';
4
+ import '../creating_reading-DLkHH80h.js';
5
5
  import 'colorjs.io/fn';
6
6
  import '../color/color_spaces/hsb.js';
7
- import '../constants-BdTiYOQI.js';
7
+ import '../constants-CYF6mp5_.js';
8
8
  import '../math/p5.Vector.js';
9
9
  import '../shape/custom_shapes.js';
10
10
  import '../core/States.js';
@@ -4,7 +4,6 @@ import Filters from './filters.js';
4
4
  * @module Image
5
5
  * @submodule Pixels
6
6
  * @for p5
7
- * @requires core
8
7
  */
9
8
 
10
9
 
package/dist/io/files.js CHANGED
@@ -1,15 +1,16 @@
1
- import '../p5.Renderer-BmD2P6Wv.js';
2
- export { d as default, a as request } from '../rendering-CC8JNTwG.js';
1
+ import '../p5.Renderer-C0Kzy71d.js';
2
+ export { f as default, d as request } from '../rendering-CvNr0bB8.js';
3
3
  import './csv.js';
4
4
  import './utilities.js';
5
- import '../creating_reading-C7hu6sg1.js';
5
+ import '../creating_reading-DLkHH80h.js';
6
6
  import 'colorjs.io/fn';
7
7
  import '../color/color_spaces/hsb.js';
8
- import '../constants-BdTiYOQI.js';
8
+ import '../constants-CYF6mp5_.js';
9
9
  import '../image/filters.js';
10
10
  import '../math/p5.Vector.js';
11
11
  import '../shape/custom_shapes.js';
12
12
  import '../core/States.js';
13
+ import '../strands/ir_types.js';
13
14
  import '../dom/p5.Element.js';
14
15
  import '../dom/p5.File.js';
15
16
  import './p5.XML.js';
@@ -21,7 +22,6 @@ import '../shape/curves.js';
21
22
  import '../shape/vertex.js';
22
23
  import '../color/setting.js';
23
24
  import 'omggif';
24
- import 'gifenc';
25
25
  import '../image/pixels.js';
26
26
  import '../core/transform.js';
27
27
  import '../webgl/GeometryBuilder.js';
package/dist/io/index.js CHANGED
@@ -1,14 +1,15 @@
1
- import { d as files } from '../rendering-CC8JNTwG.js';
1
+ import { f as files } from '../rendering-CvNr0bB8.js';
2
2
  import table from './p5.Table.js';
3
3
  import tableRow from './p5.TableRow.js';
4
4
  import xml from './p5.XML.js';
5
- import '../constants-BdTiYOQI.js';
6
- import '../creating_reading-C7hu6sg1.js';
5
+ import '../constants-CYF6mp5_.js';
6
+ import '../creating_reading-DLkHH80h.js';
7
7
  import 'colorjs.io/fn';
8
8
  import '../color/color_spaces/hsb.js';
9
+ import '../strands/ir_types.js';
9
10
  import '../dom/p5.Element.js';
10
11
  import '../dom/p5.File.js';
11
- import '../p5.Renderer-BmD2P6Wv.js';
12
+ import '../p5.Renderer-C0Kzy71d.js';
12
13
  import '../image/filters.js';
13
14
  import '../math/p5.Vector.js';
14
15
  import '../shape/custom_shapes.js';
@@ -23,7 +24,6 @@ import '../shape/vertex.js';
23
24
  import '../color/setting.js';
24
25
  import 'omggif';
25
26
  import './csv.js';
26
- import 'gifenc';
27
27
  import '../image/pixels.js';
28
28
  import '../core/transform.js';
29
29
  import '../webgl/GeometryBuilder.js';
@@ -3,7 +3,6 @@ import { stringify } from './csv.js';
3
3
  /**
4
4
  * @module IO
5
5
  * @submodule Table
6
- * @requires core
7
6
  */
8
7
 
9
8
 
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * @module IO
3
3
  * @submodule Table
4
- * @requires core
5
4
  */
6
5
 
7
6
  class TableRow {
package/dist/io/p5.XML.js CHANGED
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * @module IO
3
3
  * @submodule Input
4
- * @requires core
5
4
  */
6
5
 
7
6
  class XML {
@@ -10,6 +10,9 @@ class StrandsNode {
10
10
  this.strandsContext = strandsContext;
11
11
  this.dimension = dimension;
12
12
  this.structProperties = null;
13
+ // Schema for struct storage buffers (set by uniformStorage when buffer has a struct layout).
14
+ // When set, buf.get(idx) returns a field proxy instead of a scalar StrandsNode.
15
+ this._schema = null;
13
16
  this.isStrandsNode = true;
14
17
 
15
18
  // Store original identifier for varying variables
@@ -163,6 +166,56 @@ class StrandsNode {
163
166
 
164
167
  return this;
165
168
  }
169
+
170
+ get(index) {
171
+ // Validate baseType is 'storage'
172
+ const nodeData = getNodeDataFromID(this.strandsContext.dag, this.id);
173
+ if (nodeData.baseType !== 'storage') {
174
+ throw new Error('get() can only be used on storage buffers');
175
+ }
176
+
177
+ // For struct storage, return a proxy with per-field getters/setters
178
+ if (this._schema) {
179
+ return createStructArrayElementProxy(this.strandsContext, this, index, this._schema);
180
+ }
181
+
182
+ // Create array access node: buffer.get(index) -> buffer[index]
183
+ const { id, dimension } = arrayAccessNode(
184
+ this.strandsContext,
185
+ this,
186
+ index);
187
+ return createStrandsNode(id, dimension, this.strandsContext);
188
+ }
189
+
190
+ set(index, value) {
191
+ // Validate baseType is 'storage' and has _originalIdentifier
192
+ const nodeData = getNodeDataFromID(this.strandsContext.dag, this.id);
193
+ if (nodeData.baseType !== 'storage') {
194
+ throw new Error('set() can only be used on storage buffers');
195
+ }
196
+ if (!this._originalIdentifier) {
197
+ throw new Error('set() can only be used on storage buffers with an identifier');
198
+ }
199
+
200
+ // If value is a plain object (struct literal), expand to per-field assignments
201
+ // e.g. buf[idx] = { position: pos, velocity: vel }
202
+ // becomes buf[idx].position = pos; buf[idx].velocity = vel;
203
+ if (value !== null && typeof value === 'object' && !value.isStrandsNode && this._schema) {
204
+ const proxy = createStructArrayElementProxy(this.strandsContext, this, index, this._schema);
205
+ for (const [fieldName, fieldValue] of Object.entries(value)) {
206
+ proxy[fieldName] = fieldValue;
207
+ }
208
+ return this;
209
+ }
210
+
211
+ // Create array assignment node: buffer.set(index, value) -> buffer[index] = value
212
+ // This creates an ASSIGNMENT node and records it in the CFG basic block
213
+ // CFG preserves sequential order, preventing reordering of assignments
214
+ arrayAssignmentNode(this.strandsContext, this, index, value);
215
+
216
+ // Return this for chaining
217
+ return this;
218
+ }
166
219
  }
167
220
  function createStrandsNode(id, dimension, strandsContext, onRebind) {
168
221
  return new Proxy(
@@ -788,4 +841,184 @@ function swizzleTrap(id, dimension, strandsContext, onRebind) {
788
841
  return trap;
789
842
  }
790
843
 
791
- export { StrandsNode as S, structInstanceNode as a, binaryOpNode as b, createStrandsNode as c, structConstructorNode as d, scalarLiteralNode as e, functionCallNode as f, constructTypeFromIDs as g, castToFloat as h, swizzleNode as i, swizzleTrap as j, memberAccessNode as m, primitiveConstructorNode as p, statementNode as s, unaryOpNode as u, variableNode as v };
844
+ function arrayAccessNode(strandsContext, bufferNode, indexNode, accessMode) {
845
+ const { dag, cfg } = strandsContext;
846
+
847
+ // Ensure index is a StrandsNode
848
+ let index;
849
+ if (indexNode instanceof StrandsNode) {
850
+ index = indexNode;
851
+ } else {
852
+ const { id, dimension } = primitiveConstructorNode(
853
+ strandsContext,
854
+ { baseType: BaseType.INT, dimension: 1 },
855
+ indexNode
856
+ );
857
+ index = createStrandsNode(id, dimension, strandsContext);
858
+ }
859
+
860
+ // Array access returns a single float
861
+ const nodeData = createNodeData({
862
+ nodeType: NodeType.OPERATION,
863
+ opCode: OpCode.Binary.ARRAY_ACCESS,
864
+ dependsOn: [bufferNode.id, index.id],
865
+ dimension: 1,
866
+ baseType: BaseType.FLOAT});
867
+
868
+ const id = getOrCreateNode(dag, nodeData);
869
+ recordInBasicBlock(cfg, cfg.currentBlock, id);
870
+
871
+ return { id, dimension: 1 };
872
+ }
873
+
874
+ function createStructArrayElementProxy(strandsContext, bufferNode, indexNode, schema) {
875
+ const { dag, cfg } = strandsContext;
876
+
877
+ // Ensure index is a StrandsNode
878
+ let index;
879
+ if (indexNode instanceof StrandsNode) {
880
+ index = indexNode;
881
+ } else {
882
+ const { id, dimension } = primitiveConstructorNode(
883
+ strandsContext,
884
+ { baseType: BaseType.INT, dimension: 1 },
885
+ indexNode
886
+ );
887
+ index = createStrandsNode(id, dimension, strandsContext);
888
+ }
889
+
890
+ // Create a plain object with getters/setters for each struct field.
891
+ // When read, a field creates an ARRAY_ACCESS IR node with the field name encoded
892
+ // in the identifier slot. When written, an ASSIGNMENT IR node is recorded in the CFG.
893
+ const proxy = {};
894
+
895
+ for (const field of schema.fields) {
896
+ Object.defineProperty(proxy, field.name, {
897
+ get() {
898
+ // Encode field name in identifier so WGSL backend can emit buf[idx].field
899
+ const nodeData = createNodeData({
900
+ nodeType: NodeType.OPERATION,
901
+ opCode: OpCode.Binary.ARRAY_ACCESS,
902
+ dependsOn: [bufferNode.id, index.id],
903
+ dimension: field.dim,
904
+ baseType: BaseType.FLOAT,
905
+ identifier: field.name,
906
+ });
907
+ const id = getOrCreateNode(dag, nodeData);
908
+ recordInBasicBlock(cfg, cfg.currentBlock, id);
909
+ // When a swizzle assignment fires (e.g. buf[i].vel.y *= -1), onRebind
910
+ // receives the new vector ID and writes it back to the buffer field,
911
+ // equivalent to buf[i].vel = newVec.
912
+ const onRebind = (newFieldID) => {
913
+ const accessData = createNodeData({
914
+ nodeType: NodeType.OPERATION,
915
+ opCode: OpCode.Binary.ARRAY_ACCESS,
916
+ dependsOn: [bufferNode.id, index.id],
917
+ dimension: field.dim,
918
+ baseType: BaseType.FLOAT,
919
+ identifier: field.name,
920
+ });
921
+ const accessID = getOrCreateNode(dag, accessData);
922
+ const assignData = createNodeData({
923
+ nodeType: NodeType.ASSIGNMENT,
924
+ dependsOn: [accessID, newFieldID],
925
+ phiBlocks: [],
926
+ });
927
+ const assignID = getOrCreateNode(dag, assignData);
928
+ recordInBasicBlock(cfg, cfg.currentBlock, assignID);
929
+ };
930
+ return createStrandsNode(id, field.dim, strandsContext, onRebind);
931
+ },
932
+ set(val) {
933
+ // Create access node as assignment target (field name in identifier)
934
+ const accessData = createNodeData({
935
+ nodeType: NodeType.OPERATION,
936
+ opCode: OpCode.Binary.ARRAY_ACCESS,
937
+ dependsOn: [bufferNode.id, index.id],
938
+ dimension: field.dim,
939
+ baseType: BaseType.FLOAT,
940
+ identifier: field.name,
941
+ });
942
+ const accessID = getOrCreateNode(dag, accessData);
943
+
944
+ let valueID;
945
+ if (val?.isStrandsNode) {
946
+ valueID = val.id;
947
+ } else {
948
+ const { id } = primitiveConstructorNode(
949
+ strandsContext,
950
+ { baseType: BaseType.FLOAT, dimension: field.dim },
951
+ val
952
+ );
953
+ valueID = id;
954
+ }
955
+
956
+ const assignData = createNodeData({
957
+ nodeType: NodeType.ASSIGNMENT,
958
+ dependsOn: [accessID, valueID],
959
+ phiBlocks: [],
960
+ });
961
+ const assignID = getOrCreateNode(dag, assignData);
962
+ recordInBasicBlock(cfg, cfg.currentBlock, assignID);
963
+ },
964
+ configurable: true,
965
+ });
966
+ }
967
+
968
+ return proxy;
969
+ }
970
+
971
+ function arrayAssignmentNode(strandsContext, bufferNode, indexNode, valueNode) {
972
+ const { dag, cfg } = strandsContext;
973
+
974
+ // Ensure index is a StrandsNode
975
+ let index;
976
+ if (indexNode instanceof StrandsNode) {
977
+ index = indexNode;
978
+ } else {
979
+ const { id, dimension } = primitiveConstructorNode(
980
+ strandsContext,
981
+ { baseType: BaseType.INT, dimension: 1 },
982
+ indexNode
983
+ );
984
+ index = createStrandsNode(id, dimension, strandsContext);
985
+ }
986
+
987
+ // Ensure value is a StrandsNode
988
+ let value;
989
+ if (valueNode instanceof StrandsNode) {
990
+ value = valueNode;
991
+ } else {
992
+ const { id, dimension } = primitiveConstructorNode(
993
+ strandsContext,
994
+ { baseType: BaseType.FLOAT, dimension: 1 },
995
+ valueNode
996
+ );
997
+ value = createStrandsNode(id, dimension, strandsContext);
998
+ }
999
+
1000
+ // Create array access node as the assignment target
1001
+ const arrayAccessData = createNodeData({
1002
+ nodeType: NodeType.OPERATION,
1003
+ opCode: OpCode.Binary.ARRAY_ACCESS,
1004
+ dependsOn: [bufferNode.id, index.id],
1005
+ dimension: 1,
1006
+ baseType: BaseType.FLOAT
1007
+ });
1008
+ const arrayAccessID = getOrCreateNode(dag, arrayAccessData);
1009
+
1010
+ // Create assignment node: buffer[index] = value
1011
+ const assignmentData = createNodeData({
1012
+ nodeType: NodeType.ASSIGNMENT,
1013
+ dependsOn: [arrayAccessID, value.id],
1014
+ phiBlocks: []
1015
+ });
1016
+ const assignmentID = getOrCreateNode(dag, assignmentData);
1017
+
1018
+ // CRITICAL: Record in CFG to preserve sequential ordering
1019
+ recordInBasicBlock(cfg, cfg.currentBlock, assignmentID);
1020
+
1021
+ return { id: assignmentID };
1022
+ }
1023
+
1024
+ export { StrandsNode as S, statementNode as a, binaryOpNode as b, createStrandsNode as c, structInstanceNode as d, structConstructorNode as e, functionCallNode as f, constructTypeFromIDs as g, castToFloat as h, swizzleNode as i, swizzleTrap as j, arrayAccessNode as k, createStructArrayElementProxy as l, memberAccessNode as m, arrayAssignmentNode as n, primitiveConstructorNode as p, scalarLiteralNode as s, unaryOpNode as u, variableNode as v };