@opsydyn/effect-three 0.3.0 → 0.4.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 (125) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +12 -0
  3. package/dist/{index-8cf8t6by.js → index-h3vf50fn.js} +2113 -83
  4. package/dist/index-h3vf50fn.js.map +53 -0
  5. package/dist/index-ttwy0znv.js +145 -0
  6. package/dist/index-ttwy0znv.js.map +12 -0
  7. package/dist/index.js +488 -147
  8. package/dist/index.js.map +8 -6
  9. package/dist/kernel/boxSelect.d.ts +22 -0
  10. package/dist/kernel/boxSelect.d.ts.map +1 -0
  11. package/dist/kernel/build.d.ts +142 -6
  12. package/dist/kernel/build.d.ts.map +1 -1
  13. package/dist/kernel/cameraShake.d.ts.map +1 -1
  14. package/dist/kernel/describeScene.d.ts +50 -0
  15. package/dist/kernel/describeScene.d.ts.map +1 -0
  16. package/dist/kernel/description.d.ts +155 -1
  17. package/dist/kernel/description.d.ts.map +1 -1
  18. package/dist/kernel/diff.d.ts +15 -0
  19. package/dist/kernel/diff.d.ts.map +1 -1
  20. package/dist/kernel/equality.d.ts +9 -1
  21. package/dist/kernel/equality.d.ts.map +1 -1
  22. package/dist/kernel/gizmo.d.ts +69 -0
  23. package/dist/kernel/gizmo.d.ts.map +1 -0
  24. package/dist/kernel/history.d.ts +61 -0
  25. package/dist/kernel/history.d.ts.map +1 -0
  26. package/dist/kernel/index.d.ts +13 -2
  27. package/dist/kernel/index.d.ts.map +1 -1
  28. package/dist/kernel/index.js +106 -3
  29. package/dist/kernel/index.js.map +1 -1
  30. package/dist/kernel/inspect.d.ts +85 -0
  31. package/dist/kernel/inspect.d.ts.map +1 -0
  32. package/dist/kernel/lineGeometry.d.ts +25 -0
  33. package/dist/kernel/lineGeometry.d.ts.map +1 -0
  34. package/dist/kernel/lockstep.d.ts +114 -0
  35. package/dist/kernel/lockstep.d.ts.map +1 -0
  36. package/dist/kernel/loop.d.ts.map +1 -1
  37. package/dist/kernel/materials.d.ts.map +1 -1
  38. package/dist/kernel/pivot.d.ts +54 -0
  39. package/dist/kernel/pivot.d.ts.map +1 -0
  40. package/dist/kernel/pointBuffers.d.ts +17 -0
  41. package/dist/kernel/pointBuffers.d.ts.map +1 -0
  42. package/dist/kernel/pointer.d.ts +12 -0
  43. package/dist/kernel/pointer.d.ts.map +1 -1
  44. package/dist/kernel/renderKit.d.ts +21 -1
  45. package/dist/kernel/renderKit.d.ts.map +1 -1
  46. package/dist/kernel/renderer.d.ts +6 -0
  47. package/dist/kernel/renderer.d.ts.map +1 -1
  48. package/dist/kernel/sceneChanges.d.ts +87 -0
  49. package/dist/kernel/sceneChanges.d.ts.map +1 -0
  50. package/dist/kernel/sceneGraph.d.ts +6 -0
  51. package/dist/kernel/sceneGraph.d.ts.map +1 -1
  52. package/dist/kernel/seeded.d.ts +9 -0
  53. package/dist/kernel/seeded.d.ts.map +1 -0
  54. package/dist/kernel/shots.d.ts +26 -0
  55. package/dist/kernel/shots.d.ts.map +1 -0
  56. package/dist/kernel/tape.d.ts +38 -0
  57. package/dist/kernel/tape.d.ts.map +1 -0
  58. package/dist/kernel/trail.d.ts +31 -0
  59. package/dist/kernel/trail.d.ts.map +1 -0
  60. package/dist/kernel/viewportGizmo.d.ts +25 -0
  61. package/dist/kernel/viewportGizmo.d.ts.map +1 -0
  62. package/dist/runtime/Inspector.d.ts +20 -0
  63. package/dist/runtime/Inspector.d.ts.map +1 -0
  64. package/dist/runtime/SceneFile.d.ts +448 -0
  65. package/dist/runtime/SceneFile.d.ts.map +1 -0
  66. package/dist/runtime/SceneSchema.d.ts +318 -0
  67. package/dist/runtime/SceneSchema.d.ts.map +1 -1
  68. package/dist/runtime/errors.d.ts +9 -0
  69. package/dist/runtime/errors.d.ts.map +1 -1
  70. package/dist/runtime/index.d.ts +3 -1
  71. package/dist/runtime/index.d.ts.map +1 -1
  72. package/dist/webgl/index.d.ts.map +1 -1
  73. package/dist/webgl/index.js +228 -3
  74. package/dist/webgl/index.js.map +6 -4
  75. package/dist/webgl/line.d.ts +4 -0
  76. package/dist/webgl/line.d.ts.map +1 -0
  77. package/dist/webgl/points.d.ts +4 -0
  78. package/dist/webgl/points.d.ts.map +1 -0
  79. package/dist/webgpu/index.d.ts.map +1 -1
  80. package/dist/webgpu/index.js +206 -26
  81. package/dist/webgpu/index.js.map +6 -4
  82. package/dist/webgpu/line.d.ts +4 -0
  83. package/dist/webgpu/line.d.ts.map +1 -0
  84. package/dist/webgpu/points.d.ts +4 -0
  85. package/dist/webgpu/points.d.ts.map +1 -0
  86. package/package.json +2 -1
  87. package/src/kernel/boxSelect.ts +73 -0
  88. package/src/kernel/build.ts +332 -0
  89. package/src/kernel/cameraShake.ts +3 -13
  90. package/src/kernel/describeScene.ts +224 -0
  91. package/src/kernel/description.ts +175 -0
  92. package/src/kernel/diff.ts +39 -0
  93. package/src/kernel/equality.ts +101 -0
  94. package/src/kernel/gizmo.ts +478 -0
  95. package/src/kernel/history.ts +118 -0
  96. package/src/kernel/index.ts +97 -0
  97. package/src/kernel/inspect.ts +214 -0
  98. package/src/kernel/lineGeometry.ts +75 -0
  99. package/src/kernel/lockstep.ts +237 -0
  100. package/src/kernel/loop.ts +5 -0
  101. package/src/kernel/materials.ts +3 -0
  102. package/src/kernel/pivot.ts +418 -0
  103. package/src/kernel/pointBuffers.ts +115 -0
  104. package/src/kernel/pointer.ts +55 -12
  105. package/src/kernel/renderKit.ts +23 -1
  106. package/src/kernel/renderer.ts +6 -0
  107. package/src/kernel/sceneChanges.ts +265 -0
  108. package/src/kernel/sceneGraph.ts +319 -8
  109. package/src/kernel/seeded.ts +18 -0
  110. package/src/kernel/shots.ts +167 -0
  111. package/src/kernel/tape.ts +124 -0
  112. package/src/kernel/trail.ts +170 -0
  113. package/src/kernel/viewportGizmo.ts +194 -0
  114. package/src/runtime/Inspector.ts +43 -0
  115. package/src/runtime/SceneFile.ts +46 -0
  116. package/src/runtime/SceneSchema.ts +247 -0
  117. package/src/runtime/errors.ts +6 -0
  118. package/src/runtime/index.ts +3 -1
  119. package/src/webgl/index.ts +4 -0
  120. package/src/webgl/line.ts +66 -0
  121. package/src/webgl/points.ts +205 -0
  122. package/src/webgpu/index.ts +4 -0
  123. package/src/webgpu/line.ts +67 -0
  124. package/src/webgpu/points.ts +193 -0
  125. package/dist/index-8cf8t6by.js.map +0 -41
@@ -0,0 +1,67 @@
1
+ /**
2
+ * The WebGPU kit's lines: three's fat lines for WebGPU (`Line2`, `LineSegments2` and `Line2NodeMaterial`,
3
+ * the node-material twins of what Drei's `Line` uses), which size themselves to the viewport
4
+ * before each draw.
5
+ *
6
+ * @module
7
+ */
8
+ import { Group } from 'three';
9
+ import { LineGeometry } from 'three/addons/lines/LineGeometry.js';
10
+ import { LineSegmentsGeometry } from 'three/addons/lines/LineSegmentsGeometry.js';
11
+ import { Line2 } from 'three/addons/lines/webgpu/Line2.js';
12
+ import { LineSegments2 } from 'three/addons/lines/webgpu/LineSegments2.js';
13
+ import { Line2NodeMaterial } from 'three/webgpu';
14
+
15
+ import type { LineNode } from '../kernel/description.ts';
16
+ import { drawable, fillLineGeometry } from '../kernel/lineGeometry.ts';
17
+ import type { HostedLine } from '../kernel/renderKit.ts';
18
+
19
+ /** The material's look from the description; vertex colours want white, as Drei sets. */
20
+ const style = (material: Line2NodeMaterial, line: LineNode): void => {
21
+ material.color.setHex(line.vertexColors === null ? line.color : 0xffffff);
22
+ if (material.vertexColors !== (line.vertexColors !== null)) {
23
+ material.vertexColors = line.vertexColors !== null;
24
+ material.needsUpdate = true;
25
+ }
26
+ material.linewidth = line.width;
27
+ material.worldUnits = line.worldUnits;
28
+ material.dashed = line.dashed;
29
+ material.dashSize = line.dashSize;
30
+ material.gapSize = line.gapSize;
31
+ // The node material reads the dash scale as `scale`, as `LineDashedMaterial` names it.
32
+ material.scale = line.dashScale;
33
+ material.dashOffset = line.dashOffset;
34
+ material.opacity = line.opacity;
35
+ material.transparent = line.transparent;
36
+ };
37
+
38
+ const draw = (line: LineNode, material: Line2NodeMaterial): LineSegments2 => {
39
+ const drawn = line.segments
40
+ ? new LineSegments2(fillLineGeometry(new LineSegmentsGeometry(), line), material)
41
+ : new Line2(fillLineGeometry(new LineGeometry(), line), material);
42
+ drawn.computeLineDistances();
43
+ drawn.visible = drawable(line);
44
+ return drawn;
45
+ };
46
+
47
+ export const hostLine = (first: LineNode): HostedLine => {
48
+ const object = new Group();
49
+ const material = new Line2NodeMaterial();
50
+ style(material, first);
51
+ let drawn = draw(first, material);
52
+ object.add(drawn);
53
+ return {
54
+ object,
55
+ update: (next) => {
56
+ style(material, next);
57
+ drawn.removeFromParent();
58
+ drawn.geometry.dispose();
59
+ drawn = draw(next, material);
60
+ object.add(drawn);
61
+ },
62
+ dispose: () => {
63
+ drawn.geometry.dispose();
64
+ material.dispose();
65
+ },
66
+ };
67
+ };
@@ -0,0 +1,193 @@
1
+ /**
2
+ * The WebGPU kit's points. WebGPU draws point primitives one pixel across, so sized
3
+ * points are instanced sprites with three's `PointsNodeMaterial`, as three's WebGPU
4
+ * examples draw them: a quad a point, `sizeNode` pixels across. Dots, sparkles and stars
5
+ * port the WebGL kit's shaders (Drei's, `bf6f4ad`) to TSL, from the same kernel buffers:
6
+ * the sprite's `uv` stands in for `gl_PointCoord`.
7
+ *
8
+ * Sparkles drift in the node's own space here (Drei moves them in world space), which
9
+ * is the same unless the node is rotated or scaled.
10
+ *
11
+ * @module
12
+ */
13
+ import { AdditiveBlending, Group, InstancedBufferAttribute } from 'three';
14
+ import {
15
+ cos,
16
+ distance,
17
+ exp,
18
+ float,
19
+ fwidth,
20
+ instancedBufferAttribute,
21
+ modelWorldMatrix,
22
+ positionView,
23
+ sin,
24
+ smoothstep,
25
+ uniform,
26
+ uv,
27
+ vec2,
28
+ vec3,
29
+ vec4,
30
+ } from 'three/tsl';
31
+ import { PointsNodeMaterial, Sprite } from 'three/webgpu';
32
+
33
+ import type { PointLook, PointsNode } from '../kernel/description.ts';
34
+ import { type PointBuffers, pointBuffers } from '../kernel/pointBuffers.ts';
35
+ import type { HostedPoints } from '../kernel/renderKit.ts';
36
+
37
+ /** Scene time for sparkles and stars, a uniform the host sets each frame. */
38
+ const createTime = () => uniform(0);
39
+ type Time = ReturnType<typeof createTime>;
40
+
41
+ const vec3Attribute = (array: Float32Array) =>
42
+ instancedBufferAttribute<'vec3'>(new InstancedBufferAttribute(array, 3), 'vec3');
43
+ const floatAttribute = (array: Float32Array) =>
44
+ instancedBufferAttribute<'float'>(new InstancedBufferAttribute(array, 1), 'float');
45
+
46
+ type Attributes = {
47
+ readonly position: ReturnType<typeof vec3Attribute>;
48
+ readonly color: ReturnType<typeof vec3Attribute>;
49
+ readonly size: ReturnType<typeof floatAttribute>;
50
+ };
51
+
52
+ const attributes = (buffers: PointBuffers): Attributes => ({
53
+ position: vec3Attribute(buffers.positions),
54
+ color: vec3Attribute(buffers.colors),
55
+ size: floatAttribute(buffers.sizes),
56
+ });
57
+
58
+ /** Where the sprite's fragment is across its point: `gl_PointCoord`. */
59
+ const pointCoord = uv();
60
+
61
+ /** Dots: Drei's `PointMaterial`, round by its mask, a size factor a point. */
62
+ const dotsMaterial = (
63
+ look: Extract<PointLook, { readonly _tag: 'Dots' }>,
64
+ given: Attributes,
65
+ ): PointsNodeMaterial => {
66
+ const material = new PointsNodeMaterial({
67
+ transparent: look.transparent,
68
+ sizeAttenuation: look.sizeAttenuation,
69
+ });
70
+ material.positionNode = given.position;
71
+ material.colorNode = vec4(given.color, 1);
72
+ material.sizeNode = given.size.mul(look.size);
73
+ const cxy = pointCoord.mul(2).sub(1);
74
+ const r = cxy.dot(cxy);
75
+ const delta = fwidth(r);
76
+ const mask = float(1).sub(smoothstep(float(1).sub(delta), delta.add(1), r));
77
+ material.opacityNode = look.round ? mask.mul(look.opacity) : float(look.opacity);
78
+ // Corners left out entirely, opaque or not.
79
+ material.alphaTestNode = float(0.01);
80
+ return material;
81
+ };
82
+
83
+ /** Drei's sparkles: motes swaying about their places, glowing from their middles. */
84
+ const sparklesMaterial = (
85
+ buffers: PointBuffers,
86
+ given: Attributes,
87
+ time: Time,
88
+ ): PointsNodeMaterial => {
89
+ const speed = floatAttribute(buffers.speeds);
90
+ const opacity = floatAttribute(buffers.opacities);
91
+ const noise = vec3Attribute(buffers.noise);
92
+ const material = new PointsNodeMaterial({
93
+ transparent: true,
94
+ depthWrite: false,
95
+ sizeAttenuation: false,
96
+ });
97
+ const worldX = modelWorldMatrix.mul(vec4(given.position, 1)).x;
98
+ const phase = time.mul(speed);
99
+ material.positionNode = given.position.add(
100
+ vec3(
101
+ cos(phase.add(worldX.mul(noise.z).mul(100))).mul(0.2),
102
+ sin(phase.add(worldX.mul(noise.x).mul(100))).mul(0.2),
103
+ cos(phase.add(worldX.mul(noise.y).mul(100))).mul(0.2),
104
+ ),
105
+ );
106
+ material.colorNode = vec4(given.color, 1);
107
+ // Drei's `size * 25 * pixelRatio / -viewZ`; the material multiplies in the pixel ratio.
108
+ material.sizeNode = given.size.mul(25).div(positionView.z.negate());
109
+ const strength = float(0.05)
110
+ .div(distance(pointCoord, vec2(0.5, 0.5)))
111
+ .sub(0.1);
112
+ material.opacityNode = strength.mul(opacity).clamp(0, 1);
113
+ return material;
114
+ };
115
+
116
+ /**
117
+ * Drei's stars. Its shader places them at `vec4(position, 0.5)`: the same direction as
118
+ * twice the position at full weight, half as far in clip space, so here they are drawn at
119
+ * twice their positions, and sized by half the view depth.
120
+ */
121
+ const starsMaterial = (
122
+ look: Extract<PointLook, { readonly _tag: 'Stars' }>,
123
+ given: Attributes,
124
+ time: Time,
125
+ ): PointsNodeMaterial => {
126
+ const material = new PointsNodeMaterial({
127
+ transparent: true,
128
+ depthWrite: false,
129
+ blending: AdditiveBlending,
130
+ sizeAttenuation: false,
131
+ });
132
+ material.positionNode = given.position.mul(2);
133
+ material.colorNode = vec4(given.color, 1);
134
+ material.sizeNode = given.size
135
+ .mul(float(30).div(positionView.z.negate().mul(0.5)))
136
+ .mul(sin(time.add(100)).add(3));
137
+ const d = distance(pointCoord, vec2(0.5, 0.5));
138
+ const soft = float(1).div(exp(d.sub(0.25).mul(16)).add(1));
139
+ material.opacityNode = look.fade ? soft : float(1);
140
+ return material;
141
+ };
142
+
143
+ const materialFor = (
144
+ look: PointLook,
145
+ buffers: PointBuffers,
146
+ given: Attributes,
147
+ time: Time,
148
+ ): PointsNodeMaterial => {
149
+ switch (look._tag) {
150
+ case 'Dots':
151
+ return dotsMaterial(look, given);
152
+ case 'Sparkles':
153
+ return sparklesMaterial(buffers, given, time);
154
+ case 'Stars':
155
+ return starsMaterial(look, given, time);
156
+ }
157
+ };
158
+
159
+ const draw = (look: PointLook, time: Time): Sprite => {
160
+ const buffers = pointBuffers(look);
161
+ const material = materialFor(look, buffers, attributes(buffers), time);
162
+ const sprite = new Sprite(material);
163
+ sprite.count = buffers.count;
164
+ sprite.visible = buffers.count > 0;
165
+ sprite.frustumCulled = false;
166
+ return sprite;
167
+ };
168
+
169
+ export const hostPoints = (first: PointsNode): HostedPoints => {
170
+ const object = new Group();
171
+ const time = createTime();
172
+ let look = first.look;
173
+ let drawn = draw(look, time);
174
+ object.add(drawn);
175
+ // Sprites share three's one quad geometry: only the material is this node's.
176
+ const free = (): void => {
177
+ drawn.material.dispose();
178
+ };
179
+ return {
180
+ object,
181
+ update: (next) => {
182
+ look = next.look;
183
+ drawn.removeFromParent();
184
+ free();
185
+ drawn = draw(look, time);
186
+ object.add(drawn);
187
+ },
188
+ tick: (seconds) => {
189
+ time.value = look._tag === 'Stars' ? seconds * look.speed : seconds;
190
+ },
191
+ dispose: free,
192
+ };
193
+ };