reze-engine 0.54.8 → 0.54.10

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.
@@ -1 +1 @@
1
- {"version":3,"file":"lights.d.ts","sourceRoot":"","sources":["../../src/shaders/lights.ts"],"names":[],"mappings":"AAiCA;yEACyE;AACzE,eAAO,MAAM,YAAY,IAAI,CAAA;AAC7B,+CAA+C;AAC/C,eAAO,MAAM,YAAY,IAAI,CAAA;AAC7B;;;;;GAKG;AACH,eAAO,MAAM,UAAU,KAAK,CAAA;AAC5B,kCAAkC;AAClC,eAAO,MAAM,aAAa,QAA2C,CAAA;AAErE;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,qJAQhC,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,idAa9B,CAAA;AAED,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAC3B,MAAM,CA+ER;AAED,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAkEhE"}
1
+ {"version":3,"file":"lights.d.ts","sourceRoot":"","sources":["../../src/shaders/lights.ts"],"names":[],"mappings":"AAkCA;yEACyE;AACzE,eAAO,MAAM,YAAY,IAAI,CAAA;AAC7B,+CAA+C;AAC/C,eAAO,MAAM,YAAY,IAAI,CAAA;AAC7B;;;;;GAKG;AACH,eAAO,MAAM,UAAU,KAAK,CAAA;AAC5B,kCAAkC;AAClC,eAAO,MAAM,aAAa,QAA2C,CAAA;AAErE;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,qJAQhC,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,idAa9B,CAAA;AAED,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAC3B,MAAM,CA+ER;AAED,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAkEhE"}
@@ -24,6 +24,7 @@
24
24
  // that can disagree. `type` is reserved — every light is a point light today
25
25
  // and the loop does not branch on it, so it is honest padding rather than a
26
26
  // switch with one case.
27
+ import { castDistanceStub } from "./passes/cast-distance";
27
28
  import { audioApi } from "./audio-api";
28
29
  import { midiApi } from "./midi-api";
29
30
  import { lyricsApi } from "./lyrics-api";
@@ -150,7 +151,7 @@ ${viewportApi("viewU[6].w")}
150
151
  ${trailSlotsApi(cast.trailCount)}
151
152
  // The id accessors, stubbed: this module cannot read an attachment the
152
153
  // scene pass writes. See id-api.ts — the author's whole file compiles here.
153
- ${idApi(false, 0, 0)}
154
+ ${idApi(false, 0, 0) + castDistanceStub()}
154
155
  ${wgsl}
155
156
 
156
157
  @compute @workgroup_size(64)
@@ -49,4 +49,19 @@ export declare function buildCastResolveShader(): string;
49
49
  * accessors before it: an author should never have to guard a name.
50
50
  */
51
51
  export declare function castDistanceApi(group: number, tex: number, samp: number, scale: number): string;
52
+ /**
53
+ * The accessor as a STUB, for every module that is not a field.
54
+ *
55
+ * An effect's whole source is spliced into each module its entry points reach —
56
+ * declare lightEmit and the light module compiles your foreground() along with
57
+ * it. So a name that exists only in the field module is a compile error the
58
+ * moment one effect uses both, which is exactly what a silhouette glow that
59
+ * also lights the cast wants to do.
60
+ *
61
+ * Answers "unreachably far", the same shape of answer idApi gives when the id
62
+ * buffer is off: the arithmetic still runs and produces nothing, rather than the
63
+ * shader failing to build. Nothing outside a field mount has a screen position
64
+ * to ask about anyway.
65
+ */
66
+ export declare function castDistanceStub(): string;
52
67
  //# sourceMappingURL=cast-distance.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cast-distance.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/cast-distance.ts"],"names":[],"mappings":"AA0CA;4EAC4E;AAC5E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;kEAEkE;AAClE,eAAO,MAAM,gBAAgB,EAAE,gBAA8B,CAAA;AAC7D;;8DAE8D;AAC9D,eAAO,MAAM,gBAAgB,EAAE,gBAA6B,CAAA;AAE5D;uDACuD;AACvD,eAAO,MAAM,oBAAoB,EAAE,gBAA4B,CAAA;AAE/D,iFAAiF;AACjF,eAAO,MAAM,cAAc,IAAI,CAAA;AAgB/B;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAyE3D;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CA4B5C;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CA4B/C;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAmC/F"}
1
+ {"version":3,"file":"cast-distance.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/cast-distance.ts"],"names":[],"mappings":"AA0CA;4EAC4E;AAC5E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;kEAEkE;AAClE,eAAO,MAAM,gBAAgB,EAAE,gBAA8B,CAAA;AAC7D;;8DAE8D;AAC9D,eAAO,MAAM,gBAAgB,EAAE,gBAA6B,CAAA;AAE5D;uDACuD;AACvD,eAAO,MAAM,oBAAoB,EAAE,gBAA4B,CAAA;AAE/D,iFAAiF;AACjF,eAAO,MAAM,cAAc,IAAI,CAAA;AAgB/B;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAyE3D;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CA4B5C;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CA4B/C;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAmC/F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAIzC"}
@@ -267,3 +267,22 @@ fn rzCastDistance(uv: vec2f) -> f32 {
267
267
  }
268
268
  `;
269
269
  }
270
+ /**
271
+ * The accessor as a STUB, for every module that is not a field.
272
+ *
273
+ * An effect's whole source is spliced into each module its entry points reach —
274
+ * declare lightEmit and the light module compiles your foreground() along with
275
+ * it. So a name that exists only in the field module is a compile error the
276
+ * moment one effect uses both, which is exactly what a silhouette glow that
277
+ * also lights the cast wants to do.
278
+ *
279
+ * Answers "unreachably far", the same shape of answer idApi gives when the id
280
+ * buffer is off: the arithmetic still runs and produces nothing, rather than the
281
+ * shader failing to build. Nothing outside a field mount has a screen position
282
+ * to ask about anyway.
283
+ */
284
+ export function castDistanceStub() {
285
+ return /* wgsl */ `
286
+ fn rzCastDistance(uv: vec2f) -> f32 { return 1.0e30; }
287
+ `;
288
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/grid.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAkC7C,eAAO,MAAM,QAAQ,OAAO,CAAA;AAC5B,uEAAuE;AACvE,eAAO,MAAM,UAAU,EAAE,gBAAgC,CAAA;AAEzD,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CA6B1F;AAWD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAgEnF"}
1
+ {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/grid.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAkC7C,eAAO,MAAM,QAAQ,OAAO,CAAA;AAC5B,uEAAuE;AACvE,eAAO,MAAM,UAAU,EAAE,gBAAgC,CAAA;AAEzD,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CA6B1F;AAWD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CA6EnF"}
@@ -146,6 +146,19 @@ fn rzGrid(uv: vec2f) -> vec4f { return rzGridPrev(uv); }
146
146
  // Stubbed: this module cannot read an attachment the scene pass writes — see
147
147
  // id-api.ts. The author's whole file compiles here, so the names must exist.
148
148
  idApi(false, 0, 0) +
149
+ // Inlined rather than imported from cast-distance, and NOT for tidiness.
150
+ //
151
+ // This module and composite.ts import each other — grid takes
152
+ // EFFECT_SCENE_API from it, composite takes gridReadApi from here — and that
153
+ // cycle has always been benign because both only touch the other inside
154
+ // functions. Adding an import here put a third module ahead of composite in
155
+ // grid's own evaluation order, which is enough to change where a bundler
156
+ // enters the cycle: Node's loader tolerated it and a browser one threw
157
+ // "Cannot access 'grid' before initialization" at load.
158
+ //
159
+ // One line of WGSL is not worth an import into a module that is already in a
160
+ // cycle. The other mounts import it normally — none of them is.
161
+ "fn rzCastDistance(uv: vec2f) -> f32 { return 1.0e30; }\n" +
149
162
  "\n// ── user effect (setEffect) ──\n" +
150
163
  wgsl +
151
164
  /* wgsl */ `
@@ -1 +1 @@
1
- {"version":3,"file":"particles.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/particles.ts"],"names":[],"mappings":"AA0BA,sEAAsE;AACtE,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAA;IACb;;mFAE+E;IAC/E,UAAU,EAAE,MAAM,CAAA;IAClB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB,CAAA;AAiCD,qDAAqD;AACrD,KAAK,aAAa,GAAG,OAAO,GAAG,UAAU,CAAA;AAEzC,KAAK,cAAc,GAAG;IACpB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,aAAa,CAAA;IACpB,qEAAqE;IACrE,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED,oEAAoE;AACpE,eAAO,MAAM,eAAe,KAAK,CAAA;AAuDjC,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAMlG;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CA6CxF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CA4HvF"}
1
+ {"version":3,"file":"particles.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/particles.ts"],"names":[],"mappings":"AA2BA,sEAAsE;AACtE,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAA;IACb;;mFAE+E;IAC/E,UAAU,EAAE,MAAM,CAAA;IAClB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB,CAAA;AAiCD,qDAAqD;AACrD,KAAK,aAAa,GAAG,OAAO,GAAG,UAAU,CAAA;AAEzC,KAAK,cAAc,GAAG;IACpB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,aAAa,CAAA;IACpB,qEAAqE;IACrE,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED,oEAAoE;AACpE,eAAO,MAAM,eAAe,KAAK,CAAA;AAuDjC,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAMlG;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CA6CxF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CA4HvF"}
@@ -1,3 +1,4 @@
1
+ import { castDistanceStub } from "./cast-distance";
1
2
  import { RZ_LIGHT_STRUCT_WGSL } from "../lights";
2
3
  import { audioApi } from "../audio-api";
3
4
  import { lyricsApi } from "../lyrics-api";
@@ -121,7 +122,7 @@ export function buildParticleComputeShader(src, cast) {
121
122
  PRELUDE +
122
123
  // Stubbed: this module cannot read an attachment the scene pass writes — see
123
124
  // id-api.ts. The author's whole file compiles here, so the names must exist.
124
- idApi(false, 0, 0) +
125
+ idApi(false, 0, 0) + castDistanceStub() +
125
126
  "\n// ── user effect ──\n" +
126
127
  src.wgsl +
127
128
  /* wgsl */ `
@@ -180,7 +181,7 @@ override ADDITIVE: bool = ${src.blend === "additive" ? "true" : "false"};\n` +
180
181
  PRELUDE +
181
182
  // Stubbed: this module cannot read an attachment the scene pass writes — see
182
183
  // id-api.ts. The author's whole file compiles here, so the names must exist.
183
- idApi(false, 0, 0) +
184
+ idApi(false, 0, 0) + castDistanceStub() +
184
185
  "\n// ── user effect ──\n" +
185
186
  src.wgsl +
186
187
  /* wgsl */ `
@@ -1 +1 @@
1
- {"version":3,"file":"trails.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/trails.ts"],"names":[],"mappings":"AA0BA,KAAK,WAAW,GAAG;IACjB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAA;IACb;oEACgE;IAChE,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,8DAA8D;IAC9D,KAAK,EAAE,OAAO,GAAG,UAAU,CAAA;IAC3B,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAA;AAEnC,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAKjF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE;IACJ,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,EAAE,CAAA;IACf;;;;kFAI8E;IAC9E,SAAS,EAAE,OAAO,CAAA;CACnB,GACA,MAAM,CAgVR"}
1
+ {"version":3,"file":"trails.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/trails.ts"],"names":[],"mappings":"AA2BA,KAAK,WAAW,GAAG;IACjB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAA;IACb;oEACgE;IAChE,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,8DAA8D;IAC9D,KAAK,EAAE,OAAO,GAAG,UAAU,CAAA;IAC3B,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAA;AAEnC,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAKjF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE;IACJ,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,EAAE,CAAA;IACf;;;;kFAI8E;IAC9E,SAAS,EAAE,OAAO,CAAA;CACnB,GACA,MAAM,CAgVR"}
@@ -1,3 +1,4 @@
1
+ import { castDistanceStub } from "./cast-distance";
1
2
  import { RZ_LIGHT_STRUCT_WGSL } from "../lights";
2
3
  import { audioApi } from "../audio-api";
3
4
  import { lyricsApi } from "../lyrics-api";
@@ -186,7 +187,7 @@ fn rzTurnRadius(a: vec3f, b: vec3f, c: vec3f) -> f32 {
186
187
  lyricsApi(0, 6) +
187
188
  // Stubbed: this module cannot read an attachment the scene pass writes — see
188
189
  // id-api.ts. The author's whole file compiles here, so the names must exist.
189
- idApi(false, 0, 0) +
190
+ idApi(false, 0, 0) + castDistanceStub() +
190
191
  "\n// ── user effect ──\n" +
191
192
  src.wgsl +
192
193
  /* wgsl */ `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reze-engine",
3
- "version": "0.54.8",
3
+ "version": "0.54.10",
4
4
  "description": "A lightweight WebGPU engine for real-time 3D MMD/PMX model rendering",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -25,6 +25,7 @@
25
25
  // and the loop does not branch on it, so it is honest padding rather than a
26
26
  // switch with one case.
27
27
 
28
+ import { castDistanceStub } from "./passes/cast-distance"
28
29
  import { audioApi } from "./audio-api"
29
30
  import { midiApi } from "./midi-api"
30
31
  import { lyricsApi } from "./lyrics-api"
@@ -160,7 +161,7 @@ ${viewportApi("viewU[6].w")}
160
161
  ${trailSlotsApi(cast.trailCount)}
161
162
  // The id accessors, stubbed: this module cannot read an attachment the
162
163
  // scene pass writes. See id-api.ts — the author's whole file compiles here.
163
- ${idApi(false, 0, 0)}
164
+ ${idApi(false, 0, 0) + castDistanceStub()}
164
165
  ${wgsl}
165
166
 
166
167
  @compute @workgroup_size(64)
@@ -278,3 +278,23 @@ fn rzCastDistance(uv: vec2f) -> f32 {
278
278
  }
279
279
  `
280
280
  }
281
+
282
+ /**
283
+ * The accessor as a STUB, for every module that is not a field.
284
+ *
285
+ * An effect's whole source is spliced into each module its entry points reach —
286
+ * declare lightEmit and the light module compiles your foreground() along with
287
+ * it. So a name that exists only in the field module is a compile error the
288
+ * moment one effect uses both, which is exactly what a silhouette glow that
289
+ * also lights the cast wants to do.
290
+ *
291
+ * Answers "unreachably far", the same shape of answer idApi gives when the id
292
+ * buffer is off: the arithmetic still runs and produces nothing, rather than the
293
+ * shader failing to build. Nothing outside a field mount has a screen position
294
+ * to ask about anyway.
295
+ */
296
+ export function castDistanceStub(): string {
297
+ return /* wgsl */ `
298
+ fn rzCastDistance(uv: vec2f) -> f32 { return 1.0e30; }
299
+ `
300
+ }
@@ -154,6 +154,19 @@ fn rzGrid(uv: vec2f) -> vec4f { return rzGridPrev(uv); }
154
154
  // Stubbed: this module cannot read an attachment the scene pass writes — see
155
155
  // id-api.ts. The author's whole file compiles here, so the names must exist.
156
156
  idApi(false, 0, 0) +
157
+ // Inlined rather than imported from cast-distance, and NOT for tidiness.
158
+ //
159
+ // This module and composite.ts import each other — grid takes
160
+ // EFFECT_SCENE_API from it, composite takes gridReadApi from here — and that
161
+ // cycle has always been benign because both only touch the other inside
162
+ // functions. Adding an import here put a third module ahead of composite in
163
+ // grid's own evaluation order, which is enough to change where a bundler
164
+ // enters the cycle: Node's loader tolerated it and a browser one threw
165
+ // "Cannot access 'grid' before initialization" at load.
166
+ //
167
+ // One line of WGSL is not worth an import into a module that is already in a
168
+ // cycle. The other mounts import it normally — none of them is.
169
+ "fn rzCastDistance(uv: vec2f) -> f32 { return 1.0e30; }\n" +
157
170
  "\n// ── user effect (setEffect) ──\n" +
158
171
  wgsl +
159
172
  /* wgsl */ `
@@ -1,3 +1,4 @@
1
+ import { castDistanceStub } from "./cast-distance"
1
2
  import { RZ_LIGHT_STRUCT_WGSL } from "../lights"
2
3
  import { audioApi } from "../audio-api"
3
4
  import { lyricsApi } from "../lyrics-api"
@@ -176,7 +177,7 @@ export function buildParticleComputeShader(src: ParticleSource, cast: CastLayout
176
177
  PRELUDE +
177
178
  // Stubbed: this module cannot read an attachment the scene pass writes — see
178
179
  // id-api.ts. The author's whole file compiles here, so the names must exist.
179
- idApi(false, 0, 0) +
180
+ idApi(false, 0, 0) + castDistanceStub() +
180
181
  "\n// ── user effect ──\n" +
181
182
  src.wgsl +
182
183
  /* wgsl */ `
@@ -238,7 +239,7 @@ override ADDITIVE: bool = ${src.blend === "additive" ? "true" : "false"};\n` +
238
239
  PRELUDE +
239
240
  // Stubbed: this module cannot read an attachment the scene pass writes — see
240
241
  // id-api.ts. The author's whole file compiles here, so the names must exist.
241
- idApi(false, 0, 0) +
242
+ idApi(false, 0, 0) + castDistanceStub() +
242
243
  "\n// ── user effect ──\n" +
243
244
  src.wgsl +
244
245
  /* wgsl */ `
@@ -1,3 +1,4 @@
1
+ import { castDistanceStub } from "./cast-distance"
1
2
  import { RZ_LIGHT_STRUCT_WGSL } from "../lights"
2
3
  import { audioApi } from "../audio-api"
3
4
  import { lyricsApi } from "../lyrics-api"
@@ -235,7 +236,7 @@ fn rzTurnRadius(a: vec3f, b: vec3f, c: vec3f) -> f32 {
235
236
  lyricsApi(0, 6) +
236
237
  // Stubbed: this module cannot read an attachment the scene pass writes — see
237
238
  // id-api.ts. The author's whole file compiles here, so the names must exist.
238
- idApi(false, 0, 0) +
239
+ idApi(false, 0, 0) + castDistanceStub() +
239
240
  "\n// ── user effect ──\n" +
240
241
  src.wgsl +
241
242
  /* wgsl */ `