@wave3d/core 0.7.0 → 0.9.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 (75) hide show
  1. package/README.md +3 -1
  2. package/dist/config/model.d.ts +78 -4
  3. package/dist/config/model.js +12 -2
  4. package/dist/config/model.js.map +1 -1
  5. package/dist/index.d.ts +3 -2
  6. package/dist/presets.js +35 -0
  7. package/dist/presets.js.map +1 -1
  8. package/dist/renderer/WaveRenderer.d.ts +146 -12
  9. package/dist/renderer/WaveRenderer.js +218 -56
  10. package/dist/renderer/WaveRenderer.js.map +1 -1
  11. package/dist/renderer/WaveRendererGPU.js +291 -0
  12. package/dist/renderer/WaveRendererGPU.js.map +1 -0
  13. package/dist/renderer/gpu-loader.js +2 -0
  14. package/dist/renderer/index.d.ts +3 -2
  15. package/dist/renderer/interaction.d.ts +29 -0
  16. package/dist/renderer/interaction.js +77 -31
  17. package/dist/renderer/interaction.js.map +1 -1
  18. package/dist/renderer/interactionGates.js +59 -0
  19. package/dist/renderer/interactionGates.js.map +1 -0
  20. package/dist/renderer/particleField.d.ts +1 -28
  21. package/dist/renderer/particleField.js +173 -16
  22. package/dist/renderer/particleField.js.map +1 -1
  23. package/dist/renderer/particleFieldGPU.js +141 -0
  24. package/dist/renderer/particleFieldGPU.js.map +1 -0
  25. package/dist/renderer/shaders.js +178 -86
  26. package/dist/renderer/shaders.js.map +1 -1
  27. package/dist/renderer/tilt.d.ts +17 -0
  28. package/dist/renderer/tilt.js +124 -0
  29. package/dist/renderer/tilt.js.map +1 -0
  30. package/dist/renderer/tsl/color.js +129 -0
  31. package/dist/renderer/tsl/color.js.map +1 -0
  32. package/dist/renderer/tsl/noise.js +83 -0
  33. package/dist/renderer/tsl/noise.js.map +1 -0
  34. package/dist/renderer/tsl/packedArray.js +76 -0
  35. package/dist/renderer/tsl/packedArray.js.map +1 -0
  36. package/dist/renderer/tsl/particleMaterial.js +133 -0
  37. package/dist/renderer/tsl/particleMaterial.js.map +1 -0
  38. package/dist/renderer/tsl/particleUniforms.js +44 -0
  39. package/dist/renderer/tsl/particleUniforms.js.map +1 -0
  40. package/dist/renderer/tsl/pointerField.js +73 -0
  41. package/dist/renderer/tsl/pointerField.js.map +1 -0
  42. package/dist/renderer/tsl/post.js +63 -0
  43. package/dist/renderer/tsl/post.js.map +1 -0
  44. package/dist/renderer/tsl/postChain.js +56 -0
  45. package/dist/renderer/tsl/postChain.js.map +1 -0
  46. package/dist/renderer/tsl/postEffects.js +221 -0
  47. package/dist/renderer/tsl/postEffects.js.map +1 -0
  48. package/dist/renderer/tsl/types.js +28 -0
  49. package/dist/renderer/tsl/types.js.map +1 -0
  50. package/dist/renderer/tsl/uniforms.js +152 -0
  51. package/dist/renderer/tsl/uniforms.js.map +1 -0
  52. package/dist/renderer/tsl/waveMaterial.js +185 -0
  53. package/dist/renderer/tsl/waveMaterial.js.map +1 -0
  54. package/dist/renderer/tsl/waveShape.js +108 -0
  55. package/dist/renderer/tsl/waveShape.js.map +1 -0
  56. package/dist/shell/createWave.d.ts +29 -0
  57. package/dist/shell/createWave.js +39 -11
  58. package/dist/shell/createWave.js.map +1 -1
  59. package/dist/shell/probe.js +18 -1
  60. package/dist/shell/probe.js.map +1 -1
  61. package/dist/standalone/wave3d.standalone.js +2219 -1929
  62. package/dist/standalone/wave3d.standalone.webgpu.js +36647 -0
  63. package/dist/standalone.d.ts +10 -3
  64. package/dist/standalone.js +10 -3
  65. package/dist/standalone.js.map +1 -1
  66. package/dist/studio/StudioWaveRenderer.d.ts +4 -0
  67. package/dist/studio/StudioWaveRenderer.js +9 -0
  68. package/dist/studio/StudioWaveRenderer.js.map +1 -1
  69. package/dist/studio/StudioWaveRendererGPU.js +18 -0
  70. package/dist/studio/StudioWaveRendererGPU.js.map +1 -0
  71. package/dist/studio/index.d.ts +12 -2
  72. package/dist/studio/index.js +14 -1
  73. package/dist/studio/index.js.map +1 -0
  74. package/package.json +12 -3
  75. package/skills/wave3d/SKILL.md +29 -2
@@ -0,0 +1,56 @@
1
+ import { buildBasePost } from "./post.js";
2
+ import { dither, fragCoord, halftone, halftoneCmyk, heatmap, innerLight, paperTexture } from "./postEffects.js";
3
+ import { convertToTexture, renderOutput, screenCoordinate } from "three/tsl";
4
+ import { bloom } from "three/addons/tsl/display/BloomNode.js";
5
+ //#region src/renderer/tsl/postChain.ts
6
+ /**
7
+ * Assembles the post chain in the SAME order the WebGL `EffectComposer` runs it.
8
+ *
9
+ * That order is not arbitrary. `applyPost()` inserts bloom and then innerLight at index 1, so
10
+ * innerLight ends up ahead of bloom; both therefore act on the raw, pre-tone-map scene. The
11
+ * remaining effects are appended AFTER `OutputPass`, so they operate on display-space colour —
12
+ * dithering a linear buffer would crush the steps in the shadows. Reproducing that means placing
13
+ * `renderOutput()` ourselves partway down the chain instead of letting `RenderPipeline` apply it at
14
+ * the end, which is what `outputColorTransform = false` is for.
15
+ *
16
+ * scene → innerLight → +bloom → blur/grain → renderOutput → halftone → heatmap → CMYK → paper → dither
17
+ *
18
+ * Stages that sample an OFFSET coordinate need their input backed by a render target, since a
19
+ * composed node is only defined at the current fragment. `convertToTexture()` materialises those.
20
+ */
21
+ const asStage = (node) => {
22
+ return convertToTexture(node);
23
+ };
24
+ function buildPostChain(scenePass, u, flags) {
25
+ const coord = fragCoord(screenCoordinate.xy);
26
+ let stage = scenePass;
27
+ if (flags.innerLight) {
28
+ const input = asStage(stage);
29
+ stage = innerLight((at) => input.sample(at), u);
30
+ }
31
+ if (flags.bloom) {
32
+ const src = convertToTexture(stage);
33
+ stage = src.add(bloom(src, u.uBloomStrength.mul(3), u.uBloomRadius, u.uBloomThreshold));
34
+ }
35
+ {
36
+ const input = asStage(stage);
37
+ stage = buildBasePost((at) => input.sample(at), u);
38
+ }
39
+ stage = renderOutput(stage);
40
+ if (flags.halftone) {
41
+ const input = asStage(stage);
42
+ stage = halftone((at) => input.sample(at), u, coord);
43
+ }
44
+ if (flags.heatmap) stage = heatmap(stage, u.uHeatmap);
45
+ if (flags.halftoneCmyk) stage = halftoneCmyk(stage, u.uHalftoneCmyk, u.uHalftoneCmykCell, coord);
46
+ if (flags.paperTexture) stage = paperTexture(stage, u.uPaper, u.uPaperScale, coord);
47
+ if (flags.dither) {
48
+ const input = asStage(stage);
49
+ stage = dither((at) => input.sample(at), u, coord);
50
+ }
51
+ return stage;
52
+ }
53
+ //#endregion
54
+ export { buildPostChain };
55
+
56
+ //# sourceMappingURL=postChain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postChain.js","names":[],"sources":["../../../src/renderer/tsl/postChain.ts"],"sourcesContent":["/**\n * Assembles the post chain in the SAME order the WebGL `EffectComposer` runs it.\n *\n * That order is not arbitrary. `applyPost()` inserts bloom and then innerLight at index 1, so\n * innerLight ends up ahead of bloom; both therefore act on the raw, pre-tone-map scene. The\n * remaining effects are appended AFTER `OutputPass`, so they operate on display-space colour —\n * dithering a linear buffer would crush the steps in the shadows. Reproducing that means placing\n * `renderOutput()` ourselves partway down the chain instead of letting `RenderPipeline` apply it at\n * the end, which is what `outputColorTransform = false` is for.\n *\n * scene → innerLight → +bloom → blur/grain → renderOutput → halftone → heatmap → CMYK → paper → dither\n *\n * Stages that sample an OFFSET coordinate need their input backed by a render target, since a\n * composed node is only defined at the current fragment. `convertToTexture()` materialises those.\n */\nimport { bloom } from \"three/addons/tsl/display/BloomNode.js\";\nimport { convertToTexture, renderOutput, screenCoordinate } from \"three/tsl\";\nimport { buildBasePost, type PostUniforms } from \"./post\";\nimport {\n innerLight,\n halftone,\n heatmap,\n halftoneCmyk,\n paperTexture,\n dither,\n fragCoord,\n type InnerLightUniforms,\n type HalftoneUniforms,\n type DitherUniforms,\n} from \"./postEffects\";\nimport type { FloatUniform, Vec2Node, Vec4Node } from \"./types\";\n\n/** Which effects this chain includes. Changing the set rebuilds the graph, as the WebGL path\n * inserts and removes passes. */\nexport interface PostFlags {\n bloom: boolean;\n innerLight: boolean;\n halftone: boolean;\n heatmap: boolean;\n halftoneCmyk: boolean;\n paperTexture: boolean;\n dither: boolean;\n}\n\nexport interface PostChainUniforms\n extends PostUniforms, InnerLightUniforms, HalftoneUniforms, DitherUniforms {\n uBloomStrength: FloatUniform;\n uBloomRadius: FloatUniform;\n uBloomThreshold: FloatUniform;\n uHeatmap: FloatUniform;\n uHalftoneCmyk: FloatUniform;\n uHalftoneCmykCell: FloatUniform;\n uPaper: FloatUniform;\n uPaperScale: FloatUniform;\n}\n\n/** A node that can be sampled at an arbitrary uv. */\ntype TextureStage = { sample: (at: Vec2Node) => Vec4Node };\n\nconst asStage = (node: unknown): TextureStage => {\n const tex = convertToTexture(node as never) as unknown as TextureStage;\n return tex;\n};\n\nexport function buildPostChain(\n scenePass: unknown,\n u: PostChainUniforms,\n flags: PostFlags,\n): Vec4Node {\n // gl_FragCoord's bottom-left origin, which every screen-space effect below was written against.\n const coord = fragCoord(screenCoordinate.xy as unknown as Vec2Node);\n\n // --- scene zone: acts on linear, pre-tone-map colour ---\n let stage: unknown = scenePass;\n\n if (flags.innerLight) {\n // Bind the input BEFORE reassigning `stage`. TSL evaluates an `Fn` body when the shader is\n // built, not when the function is called, so a closure reading `stage` lazily would resolve to\n // the innerLight node itself — a self-referential graph that recurses until the stack blows.\n const input = asStage(stage);\n stage = innerLight((at) => input.sample(at), u);\n }\n if (flags.bloom) {\n // BloomNode returns the bloom CONTRIBUTION, not the composite — UnrealBloomPass adds it to the\n // base image too, so the sum matches. The input is materialised because BloomNode reads it\n // through its own downsample chain.\n const src = convertToTexture(stage as never);\n // x3 on the strength: UnrealBloomPass composites `3.0 * bloomStrength * sum` — its own comment\n // calls the constant \"backwards compatibility with previous alpha-based intensity\" — while\n // three's TSL BloomNode composites `sum * strength` with no such factor. Passing the authored\n // strength straight through therefore renders bloom at a third of the intensity every existing\n // preset was tuned against.\n stage = src.add(\n bloom(\n src,\n u.uBloomStrength.mul(3) as never,\n u.uBloomRadius as never,\n u.uBloomThreshold as never,\n ),\n );\n }\n\n // --- blur + grain (the always-on base pass) ---\n {\n const input = asStage(stage);\n stage = buildBasePost((at) => input.sample(at), u);\n }\n\n // --- OutputPass: tone mapping + sRGB. Everything after this sees display-space colour. ---\n stage = renderOutput(stage as never);\n\n // --- finish zone ---\n if (flags.halftone) {\n const input = asStage(stage);\n stage = halftone((at) => input.sample(at), u, coord);\n }\n if (flags.heatmap) stage = heatmap(stage as never, u.uHeatmap);\n if (flags.halftoneCmyk) {\n stage = halftoneCmyk(stage as never, u.uHalftoneCmyk, u.uHalftoneCmykCell, coord);\n }\n if (flags.paperTexture) {\n stage = paperTexture(stage as never, u.uPaper, u.uPaperScale, coord);\n }\n if (flags.dither) {\n const input = asStage(stage);\n stage = dither((at) => input.sample(at), u, coord);\n }\n\n return stage as Vec4Node;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA2DA,MAAM,WAAW,SAAgC;CAE/C,OADY,iBAAiB,IACpB;AACX;AAEA,SAAgB,eACd,WACA,GACA,OACU;CAEV,MAAM,QAAQ,UAAU,iBAAiB,EAAyB;CAGlE,IAAI,QAAiB;CAErB,IAAI,MAAM,YAAY;EAIpB,MAAM,QAAQ,QAAQ,KAAK;EAC3B,QAAQ,YAAY,OAAO,MAAM,OAAO,EAAE,GAAG,CAAC;CAChD;CACA,IAAI,MAAM,OAAO;EAIf,MAAM,MAAM,iBAAiB,KAAc;EAM3C,QAAQ,IAAI,IACV,MACE,KACA,EAAE,eAAe,IAAI,CAAC,GACtB,EAAE,cACF,EAAE,eACJ,CACF;CACF;CAGA;EACE,MAAM,QAAQ,QAAQ,KAAK;EAC3B,QAAQ,eAAe,OAAO,MAAM,OAAO,EAAE,GAAG,CAAC;CACnD;CAGA,QAAQ,aAAa,KAAc;CAGnC,IAAI,MAAM,UAAU;EAClB,MAAM,QAAQ,QAAQ,KAAK;EAC3B,QAAQ,UAAU,OAAO,MAAM,OAAO,EAAE,GAAG,GAAG,KAAK;CACrD;CACA,IAAI,MAAM,SAAS,QAAQ,QAAQ,OAAgB,EAAE,QAAQ;CAC7D,IAAI,MAAM,cACR,QAAQ,aAAa,OAAgB,EAAE,eAAe,EAAE,mBAAmB,KAAK;CAElF,IAAI,MAAM,cACR,QAAQ,aAAa,OAAgB,EAAE,QAAQ,EAAE,aAAa,KAAK;CAErE,IAAI,MAAM,QAAQ;EAChB,MAAM,QAAQ,QAAQ,KAAK;EAC3B,QAAQ,QAAQ,OAAO,MAAM,OAAO,EAAE,GAAG,GAAG,KAAK;CACnD;CAEA,OAAO;AACT"}
@@ -0,0 +1,221 @@
1
+ import { Fn, Loop, clamp, cos, dot, exp, float, floor, fract, fwidth, int, length, mat2, max, mix, screenSize, sin, smoothstep, sqrt, transpose, uniformArray, uv, vec2, vec3, vec4 } from "three/tsl";
2
+ //#region src/renderer/tsl/postEffects.ts
3
+ /**
4
+ * The optional post effects, in TSL — ports of the layered passes in `../shaders.ts`.
5
+ *
6
+ * On the WebGL path each of these is a `ShaderPass` with its own render target, so it can sample
7
+ * the previous stage at ANY coordinate (`texture2D(tDiffuse, someOtherUv)`). A node graph has no
8
+ * such target by default: a composed node is an expression evaluated at the current fragment, and
9
+ * cannot be sampled elsewhere. Every effect below that reads an offset coordinate — the light
10
+ * march, the halftone cell centre, the dither block centre — therefore takes a TEXTURE node, and
11
+ * the chain in `postChain.ts` materialises the preceding stage with `convertToTexture()`.
12
+ *
13
+ * Effects that only read the current fragment (heatmap, paper texture, CMYK halftone) take a plain
14
+ * colour node and cost nothing extra.
15
+ */
16
+ /** Rec.709 luminance, as the GLSL `luma`. */
17
+ const luma = (c) => dot(c, vec3(.2126, .7152, .0722));
18
+ /**
19
+ * The fragment coordinate in the GLSL convention (origin BOTTOM-left).
20
+ *
21
+ * `screenCoordinate` follows WebGPU's top-left origin and flips Y on WebGL to match, so every
22
+ * effect keyed off `gl_FragCoord` has to flip back or its pattern lands mirrored. Screen-space
23
+ * dot grids and dither matrices are extremely visible when they do.
24
+ */
25
+ function fragCoord(screenCoordinate) {
26
+ return vec2(screenCoordinate.x, screenSize.y.sub(screenCoordinate.y));
27
+ }
28
+ const LIGHT_SAMPLES = 24;
29
+ /**
30
+ * March from each pixel toward the light point, accumulating the wave's own brightness weighted by
31
+ * alpha (so only opaque pixels emit), then add the streaks back. Runs in the scene zone, so it
32
+ * scatters the raw pre-tone-map wave the way bloom does.
33
+ */
34
+ function innerLight(sample, u) {
35
+ return Fn(() => {
36
+ const vUv = uv();
37
+ const src = sample(vUv).toVar("ilSrc");
38
+ const delta = vUv.sub(u.uInnerLightCenter).mul(u.uInnerLightDensity.div(LIGHT_SAMPLES)).toVar("ilDelta");
39
+ const coord = vUv.toVar("ilCoord");
40
+ const decay = float(1).toVar("ilDecay");
41
+ const rays = vec3(0).toVar("ilRays");
42
+ Loop({
43
+ start: 0,
44
+ end: LIGHT_SAMPLES,
45
+ type: "int"
46
+ }, () => {
47
+ coord.subAssign(delta);
48
+ const s = sample(coord).toVar();
49
+ rays.addAssign(s.rgb.mul(s.a).mul(decay));
50
+ decay.mulAssign(u.uInnerLightDecay);
51
+ });
52
+ rays.divAssign(float(LIGHT_SAMPLES));
53
+ return vec4(src.rgb.add(rays.mul(u.uInnerLight)), clamp(max(src.a, luma(rays).mul(u.uInnerLight)), 0, 1));
54
+ })();
55
+ }
56
+ const sigmoid = (x, k) => float(1).div(float(1).add(exp(x.sub(.5).mul(-k))));
57
+ /** paper's classic dot: radius grows as the sampled cell darkens, soft edge via fwidth. */
58
+ const getCircle = (cellUv, lum, baseR) => {
59
+ const r = mix(float(.25 * baseR), 0, lum);
60
+ const d = length(cellUv.sub(.5)).toVar();
61
+ const aa = fwidth(d);
62
+ return float(1).sub(smoothstep(r.sub(aa), r.add(aa), d));
63
+ };
64
+ function halftone(sample, u, coord) {
65
+ return Fn(() => {
66
+ const ca = cos(u.uHalftoneAngle);
67
+ const sa = sin(u.uHalftoneAngle);
68
+ const rot = mat2(ca, sa.negate(), sa, ca).toVar("htRot");
69
+ const cell = max(u.uHalftoneCell, 2).toVar("htCell");
70
+ const gridPx = rot.mul(coord).toVar("htGrid");
71
+ const cellId = floor(gridPx.div(cell));
72
+ const inCell = fract(gridPx.div(cell));
73
+ const tex = sample(transpose(rot).mul(cellId.add(.5).mul(cell)).div(max(screenSize, vec2(1)))).toVar("htTex");
74
+ const c = vec3(sigmoid(tex.r, 2), sigmoid(tex.g, 2), sigmoid(tex.b, 2));
75
+ const lum = mix(float(1), luma(c), tex.a).toVar("htLum");
76
+ const d = getCircle(inCell, lum, 1.3);
77
+ const dots = vec4(tex.rgb, tex.a.mul(d));
78
+ return mix(sample(uv()), dots, clamp(u.uHalftone, 0, 1));
79
+ })();
80
+ }
81
+ const heat = (t) => {
82
+ const s = clamp(t, 0, 1).toVar();
83
+ const c = mix(vec3(0, 0, .4), vec3(0, .6, 1), smoothstep(0, .25, s)).toVar("heatC");
84
+ c.assign(mix(c, vec3(0, 1, .4), smoothstep(.25, .5, s)));
85
+ c.assign(mix(c, vec3(1, 1, 0), smoothstep(.5, .75, s)));
86
+ c.assign(mix(c, vec3(1, .1, 0), smoothstep(.75, 1, s)));
87
+ return c;
88
+ };
89
+ function heatmap(src, uHeatmap) {
90
+ return Fn(() => {
91
+ const s = src.toVar("hmSrc");
92
+ const l = dot(s.rgb, vec3(.299, .587, .114));
93
+ return vec4(mix(s.rgb, heat(l), clamp(uHeatmap, 0, 1)), s.a);
94
+ })();
95
+ }
96
+ const h21 = (p) => fract(sin(dot(p, vec2(127.1, 311.7))).mul(43758.5453));
97
+ function paperTexture(src, uPaper, uPaperScale, coord) {
98
+ return Fn(() => {
99
+ const s = src.toVar("ptSrc");
100
+ const p = coord.div(max(uPaperScale, .5)).toVar("ptP");
101
+ const tex = mix(h21(floor(p)).mul(.5).add(h21(floor(p.mul(vec2(.3, 3)))).mul(.5)), h21(coord), .3);
102
+ const shade = float(1).sub(tex.sub(.5).mul(.35));
103
+ return vec4(s.rgb.mul(mix(float(1), shade, clamp(uPaper, 0, 1))), s.a);
104
+ })();
105
+ }
106
+ /** One rotated halftone dot screen for a channel value. */
107
+ const dotScreen = (coord, value, angle, cell) => {
108
+ const ca = Math.cos(angle);
109
+ const sa = Math.sin(angle);
110
+ const c = fract(mat2(ca, -sa, sa, ca).mul(coord).div(max(cell, 2))).sub(.5).toVar();
111
+ const radius = sqrt(clamp(value, 0, 1)).mul(.5).toVar();
112
+ return smoothstep(radius, radius.sub(.06), length(c));
113
+ };
114
+ function halftoneCmyk(src, uHalftoneCmyk, uCell, coord) {
115
+ return Fn(() => {
116
+ const s = src.toVar("cmykSrc");
117
+ const k = float(1).sub(max(max(s.r, s.g), s.b)).toVar("cmykK");
118
+ const invK = max(float(1).sub(k), .001).toVar();
119
+ const cyan = float(1).sub(s.r).sub(k).div(invK);
120
+ const mag = float(1).sub(s.g).sub(k).div(invK);
121
+ const yel = float(1).sub(s.b).sub(k).div(invK);
122
+ const dc = dotScreen(coord, cyan, 1.309, uCell);
123
+ const dm = dotScreen(coord, mag, .262, uCell);
124
+ const dy = dotScreen(coord, yel, 0, uCell);
125
+ const dk = dotScreen(coord, k, .785, uCell);
126
+ const outc = clamp(vec3(1).sub(vec3(dc, 0, 0)).sub(vec3(0, dm, 0)).sub(vec3(0, 0, dy)).sub(vec3(dk)), vec3(0), vec3(1));
127
+ return vec4(mix(s.rgb, outc, clamp(uHalftoneCmyk, 0, 1)), s.a);
128
+ })();
129
+ }
130
+ const bayerTable = /*@__PURE__*/ uniformArray([
131
+ 0,
132
+ 32,
133
+ 8,
134
+ 40,
135
+ 2,
136
+ 34,
137
+ 10,
138
+ 42,
139
+ 48,
140
+ 16,
141
+ 56,
142
+ 24,
143
+ 50,
144
+ 18,
145
+ 58,
146
+ 26,
147
+ 12,
148
+ 44,
149
+ 4,
150
+ 36,
151
+ 14,
152
+ 46,
153
+ 6,
154
+ 38,
155
+ 60,
156
+ 28,
157
+ 52,
158
+ 20,
159
+ 62,
160
+ 30,
161
+ 54,
162
+ 22,
163
+ 3,
164
+ 35,
165
+ 11,
166
+ 43,
167
+ 1,
168
+ 33,
169
+ 9,
170
+ 41,
171
+ 51,
172
+ 19,
173
+ 59,
174
+ 27,
175
+ 49,
176
+ 17,
177
+ 57,
178
+ 25,
179
+ 15,
180
+ 47,
181
+ 7,
182
+ 39,
183
+ 13,
184
+ 45,
185
+ 5,
186
+ 37,
187
+ 63,
188
+ 31,
189
+ 55,
190
+ 23,
191
+ 61,
192
+ 29,
193
+ 53,
194
+ 21
195
+ ], "float");
196
+ /** `getBayerValue(uv, 8)` from the GLSL: index the 8x8 screen by the wrapped pixel coordinate. */
197
+ const bayer8 = (p) => {
198
+ const cell = fract(p.div(8)).mul(8).toVar("bayerCell");
199
+ const index = int(cell.y).mul(8).add(int(cell.x));
200
+ return float(bayerTable.element(index)).div(64);
201
+ };
202
+ function dither(sample, u, coord) {
203
+ return Fn(() => {
204
+ const pxSize = max(u.uDitherScale, 1).toVar("dPx");
205
+ const pxSizeUV = coord.div(pxSize).toVar("dPxUv");
206
+ const image = sample(floor(coord.div(pxSize)).add(.5).mul(pxSize).div(max(screenSize, vec2(1)))).toVar("dImage");
207
+ const lum = luma(image.rgb).toVar("dLum");
208
+ const colorSteps = max(floor(u.uDitherSteps), 1).toVar("dSteps");
209
+ const dithering = bayer8(pxSizeUV).sub(.5);
210
+ const brightness = clamp(lum.add(dithering.div(colorSteps)), 0, 1).toVar("dBright");
211
+ brightness.assign(mix(float(0), brightness, image.a));
212
+ const quantLum = floor(brightness.mul(colorSteps).add(.5)).div(colorSteps).toVar("dQuant");
213
+ const color = image.rgb.div(max(lum, .001)).mul(quantLum);
214
+ const quantAlpha = floor(image.a.mul(colorSteps).add(.5)).div(colorSteps);
215
+ return mix(image, vec4(color, mix(quantLum, float(1), quantAlpha)), clamp(u.uDitherStrength, 0, 1));
216
+ })();
217
+ }
218
+ //#endregion
219
+ export { dither, fragCoord, halftone, halftoneCmyk, heatmap, innerLight, paperTexture };
220
+
221
+ //# sourceMappingURL=postEffects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postEffects.js","names":[],"sources":["../../../src/renderer/tsl/postEffects.ts"],"sourcesContent":["/**\n * The optional post effects, in TSL — ports of the layered passes in `../shaders.ts`.\n *\n * On the WebGL path each of these is a `ShaderPass` with its own render target, so it can sample\n * the previous stage at ANY coordinate (`texture2D(tDiffuse, someOtherUv)`). A node graph has no\n * such target by default: a composed node is an expression evaluated at the current fragment, and\n * cannot be sampled elsewhere. Every effect below that reads an offset coordinate — the light\n * march, the halftone cell centre, the dither block centre — therefore takes a TEXTURE node, and\n * the chain in `postChain.ts` materialises the preceding stage with `convertToTexture()`.\n *\n * Effects that only read the current fragment (heatmap, paper texture, CMYK halftone) take a plain\n * colour node and cost nothing extra.\n */\nimport {\n Fn,\n Loop,\n float,\n int,\n vec2,\n vec3,\n vec4,\n mat2,\n cos,\n sin,\n exp,\n max,\n mix,\n clamp,\n floor,\n fract,\n sqrt,\n dot,\n length,\n smoothstep,\n fwidth,\n uv,\n uniformArray,\n screenSize,\n transpose,\n} from \"three/tsl\";\nimport type { FloatNode, FloatUniform, Vec2Node, Vec2Uniform, Vec3Node, Vec4Node } from \"./types\";\n\n/** A stage that can be sampled at an arbitrary uv (i.e. backed by a render target). */\nexport type Sampler = (at: Vec2Node) => Vec4Node;\n\n/** Rec.709 luminance, as the GLSL `luma`. */\nconst luma = (c: Vec3Node): FloatNode => dot(c, vec3(0.2126, 0.7152, 0.0722));\n\n/**\n * The fragment coordinate in the GLSL convention (origin BOTTOM-left).\n *\n * `screenCoordinate` follows WebGPU's top-left origin and flips Y on WebGL to match, so every\n * effect keyed off `gl_FragCoord` has to flip back or its pattern lands mirrored. Screen-space\n * dot grids and dither matrices are extremely visible when they do.\n */\nexport function fragCoord(screenCoordinate: Vec2Node): Vec2Node {\n return vec2(screenCoordinate.x, screenSize.y.sub(screenCoordinate.y));\n}\n\n// ---- innerLight: radial light scattering (GPU Gems 3 style) ---------------------------------\n\nconst LIGHT_SAMPLES = 24;\n\nexport interface InnerLightUniforms {\n uInnerLight: FloatUniform;\n uInnerLightDensity: FloatUniform;\n uInnerLightDecay: FloatUniform;\n uInnerLightCenter: Vec2Uniform;\n}\n\n/**\n * March from each pixel toward the light point, accumulating the wave's own brightness weighted by\n * alpha (so only opaque pixels emit), then add the streaks back. Runs in the scene zone, so it\n * scatters the raw pre-tone-map wave the way bloom does.\n */\nexport function innerLight(sample: Sampler, u: InnerLightUniforms): Vec4Node {\n return Fn(() => {\n const vUv = uv();\n const src = sample(vUv).toVar(\"ilSrc\");\n const delta = vUv\n .sub(u.uInnerLightCenter)\n .mul(u.uInnerLightDensity.div(LIGHT_SAMPLES))\n .toVar(\"ilDelta\");\n const coord = vUv.toVar(\"ilCoord\");\n const decay = float(1).toVar(\"ilDecay\");\n const rays = vec3(0).toVar(\"ilRays\");\n Loop({ start: 0, end: LIGHT_SAMPLES, type: \"int\" }, () => {\n coord.subAssign(delta);\n const s = sample(coord).toVar();\n rays.addAssign(s.rgb.mul(s.a).mul(decay)); // only opaque (wave) pixels emit light\n decay.mulAssign(u.uInnerLightDecay);\n });\n rays.divAssign(float(LIGHT_SAMPLES));\n const outc = src.rgb.add(rays.mul(u.uInnerLight));\n // Shafts stay visible over a transparent background.\n const outA = max(src.a, luma(rays).mul(u.uInnerLight));\n return vec4(outc, clamp(outA, 0, 1));\n })();\n}\n\n// ---- halftone: rotated dot screen -------------------------------------------------------------\n\nexport interface HalftoneUniforms {\n uHalftone: FloatUniform;\n uHalftoneCell: FloatUniform;\n uHalftoneAngle: FloatUniform;\n}\n\nconst sigmoid = (x: FloatNode, k: number): FloatNode =>\n float(1).div(float(1).add(exp(x.sub(0.5).mul(-k))));\n\n/** paper's classic dot: radius grows as the sampled cell darkens, soft edge via fwidth. */\nconst getCircle = (cellUv: Vec2Node, lum: FloatNode, baseR: number): FloatNode => {\n const r = mix(float(0.25 * baseR), 0.0, lum);\n const d = length(cellUv.sub(0.5)).toVar();\n const aa = fwidth(d);\n return float(1).sub(smoothstep(r.sub(aa), r.add(aa), d));\n};\n\nexport function halftone(sample: Sampler, u: HalftoneUniforms, coord: Vec2Node): Vec4Node {\n return Fn(() => {\n const ca = cos(u.uHalftoneAngle);\n const sa = sin(u.uHalftoneAngle);\n const rot = mat2(ca, sa.negate(), sa, ca).toVar(\"htRot\");\n const cell = max(u.uHalftoneCell, 2.0).toVar(\"htCell\");\n const gridPx = rot.mul(coord).toVar(\"htGrid\"); // rotate the screen into the dot grid\n const cellId = floor(gridPx.div(cell));\n const inCell = fract(gridPx.div(cell)); // position within the cell (0..1)\n const centrePx = transpose(rot).mul(cellId.add(0.5).mul(cell)); // cell centre, back in px\n const tex = sample(centrePx.div(max(screenSize, vec2(1)))).toVar(\"htTex\");\n\n const c = vec3(sigmoid(tex.r, 2), sigmoid(tex.g, 2), sigmoid(tex.b, 2)); // paper default k=2\n const lum = mix(float(1), luma(c), tex.a).toVar(\"htLum\");\n const d = getCircle(inCell, lum, 1.3); // baseR 1.3 ~ paper's original-colours default\n const dots = vec4(tex.rgb, tex.a.mul(d)); // wave-coloured dots, transparent between\n return mix(sample(uv()), dots, clamp(u.uHalftone, 0, 1));\n })();\n}\n\n// ---- heatmap: luminance to a thermal palette ---------------------------------------------------\n\nconst heat = (t: FloatNode): Vec3Node => {\n const s = clamp(t, 0, 1).toVar();\n const c = mix(vec3(0.0, 0.0, 0.4), vec3(0.0, 0.6, 1.0), smoothstep(0.0, 0.25, s)).toVar(\"heatC\");\n c.assign(mix(c, vec3(0.0, 1.0, 0.4), smoothstep(0.25, 0.5, s)));\n c.assign(mix(c, vec3(1.0, 1.0, 0.0), smoothstep(0.5, 0.75, s)));\n c.assign(mix(c, vec3(1.0, 0.1, 0.0), smoothstep(0.75, 1.0, s)));\n return c;\n};\n\nexport function heatmap(src: Vec4Node, uHeatmap: FloatUniform): Vec4Node {\n return Fn(() => {\n const s = src.toVar(\"hmSrc\");\n const l = dot(s.rgb, vec3(0.299, 0.587, 0.114));\n return vec4(mix(s.rgb, heat(l), clamp(uHeatmap, 0, 1)), s.a);\n })();\n}\n\n// ---- paper texture: fibrous substrate shading --------------------------------------------------\n\nconst h21 = (p: Vec2Node): FloatNode => fract(sin(dot(p, vec2(127.1, 311.7))).mul(43758.5453));\n\nexport function paperTexture(\n src: Vec4Node,\n uPaper: FloatUniform,\n uPaperScale: FloatUniform,\n coord: Vec2Node,\n): Vec4Node {\n return Fn(() => {\n const s = src.toVar(\"ptSrc\");\n const p = coord.div(max(uPaperScale, 0.5)).toVar(\"ptP\");\n const fiber = h21(floor(p))\n .mul(0.5)\n .add(h21(floor(p.mul(vec2(0.3, 3.0)))).mul(0.5));\n const tex = mix(fiber, h21(coord), 0.3); // + fine speckle\n const shade = float(1).sub(tex.sub(0.5).mul(0.35));\n return vec4(s.rgb.mul(mix(float(1), shade, clamp(uPaper, 0, 1))), s.a);\n })();\n}\n\n// ---- CMYK halftone: four rotated dot screens ---------------------------------------------------\n\n/** One rotated halftone dot screen for a channel value. */\nconst dotScreen = (\n coord: Vec2Node,\n value: FloatNode,\n angle: number,\n cell: FloatUniform,\n): FloatNode => {\n const ca = Math.cos(angle);\n const sa = Math.sin(angle);\n const r = mat2(ca, -sa, sa, ca).mul(coord);\n const c = fract(r.div(max(cell, 2.0)))\n .sub(0.5)\n .toVar();\n const radius = sqrt(clamp(value, 0, 1))\n .mul(0.5)\n .toVar();\n return smoothstep(radius, radius.sub(0.06), length(c));\n};\n\nexport function halftoneCmyk(\n src: Vec4Node,\n uHalftoneCmyk: FloatUniform,\n uCell: FloatUniform,\n coord: Vec2Node,\n): Vec4Node {\n return Fn(() => {\n const s = src.toVar(\"cmykSrc\");\n const k = float(1)\n .sub(max(max(s.r, s.g), s.b))\n .toVar(\"cmykK\"); // RGB -> CMYK\n const invK = max(float(1).sub(k), 1e-3).toVar();\n const cyan = float(1).sub(s.r).sub(k).div(invK);\n const mag = float(1).sub(s.g).sub(k).div(invK);\n const yel = float(1).sub(s.b).sub(k).div(invK);\n const dc = dotScreen(coord, cyan, 1.309, uCell); // 75 degrees\n const dm = dotScreen(coord, mag, 0.262, uCell); // 15\n const dy = dotScreen(coord, yel, 0.0, uCell); // 0\n const dk = dotScreen(coord, k, 0.785, uCell); // 45\n // Subtractive: cyan absorbs red, magenta green, yellow blue, black all.\n const outc = clamp(\n vec3(1)\n .sub(vec3(dc, 0, 0))\n .sub(vec3(0, dm, 0))\n .sub(vec3(0, 0, dy))\n .sub(vec3(dk)),\n vec3(0),\n vec3(1),\n );\n return vec4(mix(s.rgb, outc, clamp(uHalftoneCmyk, 0, 1)), s.a);\n })();\n}\n\n// ---- dither: ordered (Bayer) ------------------------------------------------------------------\n\nexport interface DitherUniforms {\n uDitherStrength: FloatUniform;\n uDitherScale: FloatUniform;\n uDitherSteps: FloatUniform;\n}\n\n/**\n * paper's default 8x8 ordered screen — the same 64 values the GLSL declares as a `const int[64]`.\n *\n * Kept as the literal table rather than a closed form. The recursive \"magic square\" identities that\n * look like they should reproduce it do not: three plausible bit-interleave formulations were\n * checked against these entries and disagreed on 48 to 56 of the 64, which would have shifted the\n * dither pattern in a way that is easy to mistake for a rendering difference. A uniform array of\n * 64 floats costs one buffer in the post stage, which has room to spare.\n */\nconst BAYER_8X8 = [\n 0, 32, 8, 40, 2, 34, 10, 42, 48, 16, 56, 24, 50, 18, 58, 26, 12, 44, 4, 36, 14, 46, 6, 38, 60, 28,\n 52, 20, 62, 30, 54, 22, 3, 35, 11, 43, 1, 33, 9, 41, 51, 19, 59, 27, 49, 17, 57, 25, 15, 47, 7,\n 39, 13, 45, 5, 37, 63, 31, 55, 23, 61, 29, 53, 21,\n];\n\nconst bayerTable = /*@__PURE__*/ uniformArray(BAYER_8X8, \"float\");\n\n/** `getBayerValue(uv, 8)` from the GLSL: index the 8x8 screen by the wrapped pixel coordinate. */\nconst bayer8 = (p: Vec2Node): FloatNode => {\n const cell = fract(p.div(8)).mul(8).toVar(\"bayerCell\");\n const index = int(cell.y).mul(8).add(int(cell.x));\n return float(bayerTable.element(index as never) as never).div(64.0);\n};\n\nexport function dither(sample: Sampler, u: DitherUniforms, coord: Vec2Node): Vec4Node {\n return Fn(() => {\n const pxSize = max(u.uDitherScale, 1.0).toVar(\"dPx\");\n const pxSizeUV = coord.div(pxSize).toVar(\"dPxUv\");\n const sampleUV = floor(coord.div(pxSize))\n .add(0.5)\n .mul(pxSize)\n .div(max(screenSize, vec2(1)));\n const image = sample(sampleUV).toVar(\"dImage\");\n\n const lum = luma(image.rgb).toVar(\"dLum\");\n const colorSteps = max(floor(u.uDitherSteps), 1.0).toVar(\"dSteps\");\n\n const dithering = bayer8(pxSizeUV).sub(0.5);\n const brightness = clamp(lum.add(dithering.div(colorSteps)), 0, 1).toVar(\"dBright\");\n brightness.assign(mix(float(0), brightness, image.a));\n const quantLum = floor(brightness.mul(colorSteps).add(0.5)).div(colorSteps).toVar(\"dQuant\");\n\n // paper's \"original colours\" path: keep the source hue, quantize luminance.\n const color = image.rgb.div(max(lum, 0.001)).mul(quantLum);\n const quantAlpha = floor(image.a.mul(colorSteps).add(0.5)).div(colorSteps);\n const opacity = mix(quantLum, float(1), quantAlpha);\n\n return mix(image, vec4(color, opacity), clamp(u.uDitherStrength, 0, 1));\n })();\n}\n"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { Vector2 } from "three";
2
+ import { uniform } from "three/tsl";
3
+ //#region src/renderer/tsl/types.ts
4
+ /**
5
+ * Node type aliases for the TSL shader graphs.
6
+ *
7
+ * `three/webgpu` is imported for TYPES ONLY here. That import is erased at build time, so this
8
+ * module stays out of the runtime graph — which matters: a single *value* import of `three/webgpu`
9
+ * or `three/tsl` anywhere reachable from the package entry pulls the whole ~200 KB (gzipped) node
10
+ * system into the eager bundle instead of the lazy backend chunk. `src/index.ts` keeps three out
11
+ * the same way.
12
+ */
13
+ /**
14
+ * `floatBitsToUint` / `uintBitsToFloat` are typed as a bare `BitcastNode` in @types/three 0.185,
15
+ * which declares none of the node operators (`.x`, `.sub`, `.toVar`, …) the runtime proxy actually
16
+ * carries. These shims restore the real node type. Delete them once the upstream types catch up —
17
+ * the runtime behaviour is already correct, this is purely a typings gap.
18
+ */
19
+ const asUVec2 = (n) => n;
20
+ const asFloat = (n) => n;
21
+ /** {@link FloatUniform} constructor. */
22
+ const floatUniform = (v) => uniform(v);
23
+ /** {@link Vec2Uniform} constructor. */
24
+ const vec2Uniform = (x, y) => uniform(new Vector2(x, y));
25
+ //#endregion
26
+ export { asFloat, asUVec2, floatUniform, vec2Uniform };
27
+
28
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../src/renderer/tsl/types.ts"],"sourcesContent":["/**\n * Node type aliases for the TSL shader graphs.\n *\n * `three/webgpu` is imported for TYPES ONLY here. That import is erased at build time, so this\n * module stays out of the runtime graph — which matters: a single *value* import of `three/webgpu`\n * or `three/tsl` anywhere reachable from the package entry pulls the whole ~200 KB (gzipped) node\n * system into the eager bundle instead of the lazy backend chunk. `src/index.ts` keeps three out\n * the same way.\n */\nimport { Vector2 } from \"three\";\nimport { uniform } from \"three/tsl\";\nimport type { Node } from \"three/webgpu\";\n\nexport type FloatNode = Node<\"float\">;\nexport type Vec2Node = Node<\"vec2\">;\nexport type Vec3Node = Node<\"vec3\">;\nexport type Vec4Node = Node<\"vec4\">;\nexport type Mat4Node = Node<\"mat4\">;\n\nexport type UVec2Node = Node<\"uvec2\">;\n\n/**\n * `floatBitsToUint` / `uintBitsToFloat` are typed as a bare `BitcastNode` in @types/three 0.185,\n * which declares none of the node operators (`.x`, `.sub`, `.toVar`, …) the runtime proxy actually\n * carries. These shims restore the real node type. Delete them once the upstream types catch up —\n * the runtime behaviour is already correct, this is purely a typings gap.\n */\nexport const asUVec2 = (n: unknown): UVec2Node => n as UVec2Node;\nexport const asFloat = (n: unknown): FloatNode => n as FloatNode;\n\n/**\n * A float uniform with a live `.value`.\n *\n * `uniform()` is declared as `UniformNode<unknown, unknown>`, which carries neither the node\n * operators nor a typed `value`. This narrows both, so call sites read as ordinary node maths and\n * `.value = x` stays type-checked.\n */\nexport type FloatUniform = FloatNode & { value: number };\n\n/** {@link FloatUniform} constructor. */\nexport const floatUniform = (v: number): FloatUniform => uniform(v) as unknown as FloatUniform;\n\n/** A vec2 uniform with a live, mutable `.value`. */\nexport type Vec2Uniform = Vec2Node & { value: Vector2 };\n\n/** {@link Vec2Uniform} constructor. */\nexport const vec2Uniform = (x: number, y: number): Vec2Uniform =>\n uniform(new Vector2(x, y)) as unknown as Vec2Uniform;\n"],"mappings":";;;;;;;;;;;;;;;;;;AA2BA,MAAa,WAAW,MAA0B;AAClD,MAAa,WAAW,MAA0B;;AAYlD,MAAa,gBAAgB,MAA4B,QAAQ,CAAC;;AAMlE,MAAa,eAAe,GAAW,MACrC,QAAQ,IAAI,QAAQ,GAAG,CAAC,CAAC"}
@@ -0,0 +1,152 @@
1
+ import "../../config/model.js";
2
+ import { PackedArrays } from "./packedArray.js";
3
+ import { DataTexture, RGBAFormat, UnsignedByteType, Vector2, Vector3, Vector4 } from "three";
4
+ import { texture, uniform } from "three/tsl";
5
+ //#region src/renderer/tsl/uniforms.ts
6
+ /**
7
+ * The TSL mirror of `WaveRenderer.makeUniforms()`.
8
+ *
9
+ * Every entry keeps the SAME key and the same `.value` write semantics as the GLSL registry, so the
10
+ * ~116 config-sync writes in `refresh()` (`u.uHueShift.value = …`, `u.uColors.value[i].set(…)`) work
11
+ * against either backend without a second code path. That is the whole reason this port is tractable:
12
+ * only the shader graph changes, not the config plumbing around it.
13
+ *
14
+ * Two shapes exist behind that uniform surface:
15
+ * - scalars and vectors ARE the TSL uniform node — it already exposes a live `.value`.
16
+ * - arrays are a `{ value, node }` wrapper, because `UniformArrayNode` keeps the source array on
17
+ * `.array` and uses `.value` for its own padded buffer. The node re-packs from `.array` on every
18
+ * render (`updateType = RENDER`), so mutating the shared elements in place propagates with no
19
+ * explicit invalidation — matching how the GLSL path already mutates its Vector3s.
20
+ */
21
+ /**
22
+ * A 1x1 opaque-white stand-in for the palette texture.
23
+ *
24
+ * The GLSL picks between the palette sample and the procedural gradient with a ternary, which still
25
+ * compiles both sides; the node graph likewise builds the sample unconditionally, so this uniform
26
+ * can never hold `null` the way the GLSL registry's `uPalette` does. `uUsePalette` still decides
27
+ * which result is used — this only guarantees there is something valid to sample.
28
+ */
29
+ function makeFallbackPalette() {
30
+ const tex = new DataTexture(new Uint8Array([
31
+ 255,
32
+ 255,
33
+ 255,
34
+ 255
35
+ ]), 1, 1, RGBAFormat, UnsignedByteType);
36
+ tex.needsUpdate = true;
37
+ return tex;
38
+ }
39
+ /** Build one wave's uniform registry. Defaults mirror `makeUniforms()` exactly. */
40
+ function makeTslUniforms(drawingBufferSize) {
41
+ const packed = new PackedArrays();
42
+ const colorSlots = packed.reserve(8);
43
+ const meshPosSlots = packed.reserve(8);
44
+ const meshColorSlots = packed.reserve(8);
45
+ const lightPosSlots = packed.reserve(8);
46
+ const lightColorSlots = packed.reserve(8);
47
+ const bandBoundsSlots = packed.reserve(4);
48
+ const bandParamsSlots = packed.reserve(4);
49
+ const bandParaSlots = packed.reserve(4);
50
+ const rippleSlots = packed.reserve(4);
51
+ return {
52
+ /** Folds every array view into the shared buffer. Called once per frame before drawing. */
53
+ packed,
54
+ uTime: uniform(0),
55
+ uSpeed: uniform(.05),
56
+ uSeed: uniform(0),
57
+ uDispFreqX: uniform(.003234),
58
+ uDispFreqZ: uniform(.00799),
59
+ uDispAmount: uniform(6.051),
60
+ uDetailFreq: uniform(.04),
61
+ uDetailAmount: uniform(0),
62
+ uTwFreqX: uniform(-.055),
63
+ uTwFreqY: uniform(.077),
64
+ uTwFreqZ: uniform(-.518),
65
+ uTwPowX: uniform(3.95),
66
+ uTwPowY: uniform(5.85),
67
+ uTwPowZ: uniform(6.33),
68
+ uLoopSeconds: uniform(0),
69
+ uColors: packed.vec3(colorSlots, 8, () => new Vector3(1, 1, 1)),
70
+ uColorPos: packed.scalar(colorSlots, 8, (i) => i / 7, "w"),
71
+ uColorCount: uniform(2, "int"),
72
+ uGradType: uniform(0, "int"),
73
+ uGradAngle: uniform(0),
74
+ uGradShift: uniform(.15),
75
+ uMeshPointPos: packed.vec2(meshPosSlots, 8, () => new Vector2(.5, .5)),
76
+ uMeshPointColor: packed.vec3(meshColorSlots, 8, () => new Vector3(1, 1, 1)),
77
+ uMeshPointInfluence: packed.scalar(meshPosSlots, 8, () => .65, "w"),
78
+ uMeshPointCount: uniform(0, "int"),
79
+ uMeshSoftness: uniform(.62),
80
+ uPalette: texture(makeFallbackPalette()),
81
+ uUsePalette: uniform(1),
82
+ uPaletteRaw: uniform(1),
83
+ uPaletteScale: uniform(new Vector2(1, 1)),
84
+ uPaletteOffset: uniform(new Vector2(0, 0)),
85
+ uPaletteRotation: uniform(0),
86
+ uDebug: uniform(0),
87
+ uSheen: uniform(1),
88
+ uRoundness: uniform(.35),
89
+ uIridescence: uniform(0),
90
+ uDepthTint: uniform(0),
91
+ uDepthTintColor: uniform(new Vector3()),
92
+ uHueShift: uniform(0),
93
+ uContrast: uniform(1),
94
+ uSaturation: uniform(1),
95
+ uFiberCount: uniform(90),
96
+ uFiberStrength: uniform(.25),
97
+ uTexture: uniform(0),
98
+ uCreaseLight: uniform(.15),
99
+ uCreaseSharpness: uniform(2),
100
+ uCreaseSoftness: uniform(1),
101
+ uEdgeFade: uniform(.06),
102
+ uEdgeFeather: uniform(.1),
103
+ uOpacity: uniform(1),
104
+ uSquared: uniform(1),
105
+ uResolution: uniform(drawingBufferSize.clone()),
106
+ uAmbient: uniform(.45),
107
+ uNumLights: uniform(1, "int"),
108
+ uLightPos: packed.vec3(lightPosSlots, 8, () => new Vector3()),
109
+ uLightColor: packed.vec3(lightColorSlots, 8, () => new Vector3(1, 1, 1)),
110
+ uLightIntensity: packed.scalar(lightPosSlots, 8, () => 0, "w"),
111
+ uNumNoiseBands: uniform(0, "int"),
112
+ uNoiseBandBounds: packed.vec4(bandBoundsSlots, 4, () => new Vector4()),
113
+ uNoiseBandParams: packed.vec4(bandParamsSlots, 4, () => new Vector4()),
114
+ uNoiseBandParaPow: packed.scalar(bandParaSlots, 4, () => 0, "x"),
115
+ uLineAmount: uniform(425),
116
+ uLineThickness: uniform(1),
117
+ uLineDerivativePower: uniform(.95),
118
+ uMaxWidth: uniform(1232),
119
+ uClearColor: uniform(new Vector3(1, 1, 1)),
120
+ uHelixTurns: uniform(0),
121
+ uHelixRadius: uniform(0),
122
+ uHelixRoll: uniform(0),
123
+ uHelixPhase: uniform(0),
124
+ uRadialAmount: uniform(0),
125
+ uRadialArc: uniform(160),
126
+ uRadialSpread: uniform(1),
127
+ uRadialRadius: uniform(40),
128
+ uRadialCenter: uniform(0),
129
+ uRungAmount: uniform(0),
130
+ uRungThickness: uniform(1),
131
+ uPointer: uniform(new Vector2(0, 0)),
132
+ uPointerActive: uniform(0),
133
+ uPointerRadius: uniform(.6),
134
+ uPointerAspect: uniform(1),
135
+ uPointerAgitate: uniform(0),
136
+ uPointerPush: uniform(0),
137
+ uPointerWake: uniform(0),
138
+ uPointerVel: uniform(new Vector2(0, 0)),
139
+ uShapeFlow: uniform(0),
140
+ uPointerThin: uniform(0),
141
+ uPointerHue: uniform(0),
142
+ uPointerLighten: uniform(0),
143
+ uPointerRipple: uniform(0),
144
+ uRippleOrigin: packed.vec2(rippleSlots, 4, () => new Vector2()),
145
+ uRippleAge: packed.scalar(rippleSlots, 4, () => 0, "z"),
146
+ uRippleAmp: packed.scalar(rippleSlots, 4, () => 0, "w")
147
+ };
148
+ }
149
+ //#endregion
150
+ export { makeTslUniforms };
151
+
152
+ //# sourceMappingURL=uniforms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uniforms.js","names":[],"sources":["../../../src/renderer/tsl/uniforms.ts"],"sourcesContent":["/**\n * The TSL mirror of `WaveRenderer.makeUniforms()`.\n *\n * Every entry keeps the SAME key and the same `.value` write semantics as the GLSL registry, so the\n * ~116 config-sync writes in `refresh()` (`u.uHueShift.value = …`, `u.uColors.value[i].set(…)`) work\n * against either backend without a second code path. That is the whole reason this port is tractable:\n * only the shader graph changes, not the config plumbing around it.\n *\n * Two shapes exist behind that uniform surface:\n * - scalars and vectors ARE the TSL uniform node — it already exposes a live `.value`.\n * - arrays are a `{ value, node }` wrapper, because `UniformArrayNode` keeps the source array on\n * `.array` and uses `.value` for its own padded buffer. The node re-packs from `.array` on every\n * render (`updateType = RENDER`), so mutating the shared elements in place propagates with no\n * explicit invalidation — matching how the GLSL path already mutates its Vector3s.\n */\nimport { DataTexture, RGBAFormat, UnsignedByteType, Vector2, Vector3, Vector4 } from \"three\";\nimport { uniform, texture } from \"three/tsl\";\nimport { PackedArrays } from \"./packedArray\";\nimport { MAX_COLORS, MAX_LIGHTS, MAX_MESH_POINTS, MAX_NOISE_BANDS } from \"../../config/model\";\nimport { RIPPLE_SLOTS } from \"../interactionGates\";\n\n/**\n * A 1x1 opaque-white stand-in for the palette texture.\n *\n * The GLSL picks between the palette sample and the procedural gradient with a ternary, which still\n * compiles both sides; the node graph likewise builds the sample unconditionally, so this uniform\n * can never hold `null` the way the GLSL registry's `uPalette` does. `uUsePalette` still decides\n * which result is used — this only guarantees there is something valid to sample.\n */\nfunction makeFallbackPalette(): DataTexture {\n const tex = new DataTexture(\n new Uint8Array([255, 255, 255, 255]),\n 1,\n 1,\n RGBAFormat,\n UnsignedByteType,\n );\n tex.needsUpdate = true;\n return tex;\n}\n\n/** Build one wave's uniform registry. Defaults mirror `makeUniforms()` exactly. */\nexport function makeTslUniforms(drawingBufferSize: Vector2) {\n // Every array-valued uniform shares ONE buffer — see PackedArrays for why (WebGPU allows only 12\n // uniform buffers per shader stage, and TSL gives each uniformArray its own).\n const packed = new PackedArrays();\n const colorSlots = packed.reserve(MAX_COLORS);\n const meshPosSlots = packed.reserve(MAX_MESH_POINTS);\n const meshColorSlots = packed.reserve(MAX_MESH_POINTS);\n const lightPosSlots = packed.reserve(MAX_LIGHTS);\n const lightColorSlots = packed.reserve(MAX_LIGHTS);\n const bandBoundsSlots = packed.reserve(MAX_NOISE_BANDS);\n const bandParamsSlots = packed.reserve(MAX_NOISE_BANDS);\n const bandParaSlots = packed.reserve(MAX_NOISE_BANDS);\n const rippleSlots = packed.reserve(RIPPLE_SLOTS);\n\n return {\n /** Folds every array view into the shared buffer. Called once per frame before drawing. */\n packed,\n // ---- Deformation (vertex) ----\n uTime: uniform(0),\n uSpeed: uniform(0.05),\n uSeed: uniform(0),\n uDispFreqX: uniform(0.003234),\n uDispFreqZ: uniform(0.00799),\n uDispAmount: uniform(6.051),\n uDetailFreq: uniform(0.04),\n uDetailAmount: uniform(0),\n uTwFreqX: uniform(-0.055),\n uTwFreqY: uniform(0.077),\n uTwFreqZ: uniform(-0.518),\n uTwPowX: uniform(3.95),\n uTwPowY: uniform(5.85),\n uTwPowZ: uniform(6.33),\n uLoopSeconds: uniform(0),\n\n // ---- Colour + light (fragment) ----\n uColors: packed.vec3(colorSlots, MAX_COLORS, () => new Vector3(1, 1, 1)),\n uColorPos: packed.scalar(\n colorSlots,\n MAX_COLORS,\n (i) => (MAX_COLORS > 1 ? i / (MAX_COLORS - 1) : 0),\n \"w\",\n ),\n uColorCount: uniform(2, \"int\"),\n uGradType: uniform(0, \"int\"),\n uGradAngle: uniform(0),\n uGradShift: uniform(0.15),\n uMeshPointPos: packed.vec2(meshPosSlots, MAX_MESH_POINTS, () => new Vector2(0.5, 0.5)),\n uMeshPointColor: packed.vec3(meshColorSlots, MAX_MESH_POINTS, () => new Vector3(1, 1, 1)),\n uMeshPointInfluence: packed.scalar(meshPosSlots, MAX_MESH_POINTS, () => 0.65, \"w\"),\n uMeshPointCount: uniform(0, \"int\"),\n uMeshSoftness: uniform(0.62),\n uPalette: texture(makeFallbackPalette()),\n uUsePalette: uniform(1),\n uPaletteRaw: uniform(1),\n uPaletteScale: uniform(new Vector2(1, 1)),\n uPaletteOffset: uniform(new Vector2(0, 0)),\n uPaletteRotation: uniform(0),\n uDebug: uniform(0),\n uSheen: uniform(1),\n uRoundness: uniform(0.35),\n uIridescence: uniform(0),\n uDepthTint: uniform(0),\n uDepthTintColor: uniform(new Vector3()),\n uHueShift: uniform(0),\n uContrast: uniform(1),\n uSaturation: uniform(1),\n uFiberCount: uniform(90),\n uFiberStrength: uniform(0.25),\n uTexture: uniform(0),\n uCreaseLight: uniform(0.15),\n uCreaseSharpness: uniform(2.0),\n uCreaseSoftness: uniform(1.0),\n uEdgeFade: uniform(0.06),\n uEdgeFeather: uniform(0.1),\n uOpacity: uniform(1),\n uSquared: uniform(1),\n // Seeded from the CURRENT drawing buffer, not (1,1) — see the note in makeUniforms(): the\n // edgeFade vignette divides gl_FragCoord by this, so a stale (1,1) renders the wave invisible.\n uResolution: uniform(drawingBufferSize.clone()),\n uAmbient: uniform(0.45),\n uNumLights: uniform(1, \"int\"),\n uLightPos: packed.vec3(lightPosSlots, MAX_LIGHTS, () => new Vector3()),\n uLightColor: packed.vec3(lightColorSlots, MAX_LIGHTS, () => new Vector3(1, 1, 1)),\n uLightIntensity: packed.scalar(lightPosSlots, MAX_LIGHTS, () => 0, \"w\"),\n uNumNoiseBands: uniform(0, \"int\"),\n uNoiseBandBounds: packed.vec4(bandBoundsSlots, MAX_NOISE_BANDS, () => new Vector4()),\n uNoiseBandParams: packed.vec4(bandParamsSlots, MAX_NOISE_BANDS, () => new Vector4()),\n uNoiseBandParaPow: packed.scalar(bandParaSlots, MAX_NOISE_BANDS, () => 0, \"x\"),\n\n // ---- Wireframe thin-line theme ----\n uLineAmount: uniform(425),\n uLineThickness: uniform(1),\n uLineDerivativePower: uniform(0.95),\n uMaxWidth: uniform(1232),\n uClearColor: uniform(new Vector3(1, 1, 1)),\n\n // ---- Helix / radial / rungs ----\n uHelixTurns: uniform(0),\n uHelixRadius: uniform(0),\n uHelixRoll: uniform(0),\n uHelixPhase: uniform(0),\n uRadialAmount: uniform(0),\n uRadialArc: uniform(160),\n uRadialSpread: uniform(1),\n uRadialRadius: uniform(40),\n uRadialCenter: uniform(0),\n uRungAmount: uniform(0),\n uRungThickness: uniform(1),\n\n // ---- Interaction / pointer field ----\n uPointer: uniform(new Vector2(0, 0)),\n uPointerActive: uniform(0),\n uPointerRadius: uniform(0.6),\n uPointerAspect: uniform(1),\n uPointerAgitate: uniform(0),\n uPointerPush: uniform(0),\n uPointerWake: uniform(0),\n uPointerVel: uniform(new Vector2(0, 0)),\n uShapeFlow: uniform(0),\n uPointerThin: uniform(0),\n uPointerHue: uniform(0),\n uPointerLighten: uniform(0),\n uPointerRipple: uniform(0),\n uRippleOrigin: packed.vec2(rippleSlots, RIPPLE_SLOTS, () => new Vector2()),\n uRippleAge: packed.scalar(rippleSlots, RIPPLE_SLOTS, () => 0, \"z\"),\n uRippleAmp: packed.scalar(rippleSlots, RIPPLE_SLOTS, () => 0, \"w\"),\n };\n}\n\nexport type WaveTslUniforms = ReturnType<typeof makeTslUniforms>;\n"],"mappings":"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"}