@es3d/es3d 0.0.0-stage → 1.0.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 (82) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +86 -3
  3. package/docs/REFERENCE.md +581 -0
  4. package/docs/SPEC.md +417 -0
  5. package/package.json +50 -4
  6. package/scripts/es3d-cli.mjs +377 -0
  7. package/src/cache/geometry-store.js +392 -0
  8. package/src/cache/mesh-bundle.js +123 -0
  9. package/src/cache/sha256.js +73 -0
  10. package/src/format/ast.js +238 -0
  11. package/src/format/colors.js +93 -0
  12. package/src/format/compact-parser.js +171 -0
  13. package/src/format/compact-tokenizer.js +165 -0
  14. package/src/format/errors.js +247 -0
  15. package/src/format/json.js +55 -0
  16. package/src/format/limits.js +14 -0
  17. package/src/format/parse.js +92 -0
  18. package/src/format/schema.js +617 -0
  19. package/src/format/serializer.js +333 -0
  20. package/src/format/validator.js +330 -0
  21. package/src/format/value-error.js +12 -0
  22. package/src/format/value-format.js +314 -0
  23. package/src/format/values.js +459 -0
  24. package/src/format/xml-parser.js +136 -0
  25. package/src/format/xml-tokenizer.js +237 -0
  26. package/src/geometry/contour.js +86 -0
  27. package/src/geometry/extrude.js +175 -0
  28. package/src/geometry/gear.js +85 -0
  29. package/src/geometry/geometry-cache.js +159 -0
  30. package/src/geometry/lod-error.js +178 -0
  31. package/src/geometry/mesh.js +458 -0
  32. package/src/geometry/primitives.js +299 -0
  33. package/src/geometry/registry.js +645 -0
  34. package/src/geometry/revolve.js +136 -0
  35. package/src/geometry/sweep.js +441 -0
  36. package/src/index.js +47 -0
  37. package/src/io/compression.js +67 -0
  38. package/src/io/convert.js +236 -0
  39. package/src/io/download.js +13 -0
  40. package/src/io/external-scene.js +127 -0
  41. package/src/io/file-loader.js +28 -0
  42. package/src/io/gltf.js +630 -0
  43. package/src/io/mesh-import.js +104 -0
  44. package/src/io/obj.js +352 -0
  45. package/src/io/step-brep.js +439 -0
  46. package/src/io/step-exact.js +1149 -0
  47. package/src/io/step.js +1418 -0
  48. package/src/io/stl.js +193 -0
  49. package/src/io/svg-import.js +787 -0
  50. package/src/material/materials.js +154 -0
  51. package/src/math/mat4.js +475 -0
  52. package/src/math/random.js +30 -0
  53. package/src/math/trig.js +65 -0
  54. package/src/math/vec3.js +81 -0
  55. package/src/optimize/optimizer.js +579 -0
  56. package/src/path/path-flatten.js +322 -0
  57. package/src/path/path-parser.js +332 -0
  58. package/src/path/shapes.js +129 -0
  59. package/src/path/triangulate.js +517 -0
  60. package/src/pipeline.js +74 -0
  61. package/src/render/camera.js +168 -0
  62. package/src/render/frame-builder.js +362 -0
  63. package/src/render/geometry-pool.js +149 -0
  64. package/src/render/lighting.js +149 -0
  65. package/src/render/orbit-controls.js +237 -0
  66. package/src/render/renderer.js +249 -0
  67. package/src/render/scroll-timeline.js +104 -0
  68. package/src/render/shaders/glsl.js +285 -0
  69. package/src/render/shaders/wgsl.js +252 -0
  70. package/src/render/stage.js +352 -0
  71. package/src/render/texture-cache.js +40 -0
  72. package/src/render/textures.js +223 -0
  73. package/src/render/webgl2/webgl2-backend.js +532 -0
  74. package/src/render/webgpu/webgpu-backend.js +480 -0
  75. package/src/scene/animation.js +171 -0
  76. package/src/scene/camera-constraints.js +117 -0
  77. package/src/scene/flatten.js +754 -0
  78. package/src/scene/picking.js +161 -0
  79. package/src/scene/scene-graph.js +320 -0
  80. package/src/transform/transform.js +211 -0
  81. package/src/wasm/kernels-binary.js +3 -0
  82. package/src/wasm/kernels.js +385 -0
@@ -0,0 +1,581 @@
1
+ # ES3D element reference
2
+
3
+ <!-- Generated by `npm run docs:reference` from src/format/schema.js. Do not edit by hand. -->
4
+
5
+ Every element and attribute of ES3D version 1 as implemented by the reference reader. Semantics are described in [SPEC.md](SPEC.md).
6
+ Unknown attributes and elements are errors (with a "did you mean" suggestion); elements whose name starts with `x-` are vendor extensions and are skipped with a warning.
7
+
8
+ ## Common attributes
9
+
10
+ Scene nodes (shapes, containers, `<use>`, `<scene>`) accept these placement and style attributes in addition to their own. The local transform is `transform · T(position) · R(rotation) · S(scale)`.
11
+
12
+ | Attribute | Alias | Type | Default | Range | Description |
13
+ |---|---|---|---|---|---|
14
+ | `id` | | id | | | Unique identifier, referenced by &lt;use ref&gt;, material="…" and path="…". |
15
+ | `name` | | string | | | Human readable label shown in tools. |
16
+ | `transform` | `t` | transform | | | SVG-style transform list; applied outside position/rotation/scale. |
17
+ | `position` | `p` | vec3 | `0,0,0` | | Translation x,y,z. |
18
+ | `rotation` | `rot` | vec3 | `0,0,0` | | Euler angles in degrees, applied about X, then Y, then Z. |
19
+ | `scale` | `sc` | scale3 | `1,1,1` | | Uniform scale or x,y,z. |
20
+ | `visible` | | bool | `true` | | When false the element and its children are not rendered. |
21
+ | `material` | `m` | ref → material | | | Material id. Inherited by descendants, like SVG fill. |
22
+ | `color` | `c` | color | | | Base colour override. Inherited by descendants. |
23
+
24
+ ## Document structure
25
+
26
+ ### `<es3d>`
27
+
28
+ Root element of an ES3D document.
29
+
30
+ Children: `<title>`, `<desc>`, `<defs>`, `<scene>`, `<environment>`, `<controls>`, `<box>`, `<sphere>`, `<cylinder>`, `<cone>`, `<capsule>`, `<plane>`, `<torus>`, `<line>`, `<polyline>`, `<polygon>`, `<path>`, `<extrude>`, `<revolve>`, `<sweep>`, `<gear>`, `<mesh>`, `<group>`, `<repeat>`, `<scatter>`, `<lod>`, `<use>`, `<light>`, `<camera>`, `<material>`.
31
+
32
+ Attributes:
33
+
34
+ | Attribute | Alias | Type | Default | Range | Description |
35
+ |---|---|---|---|---|---|
36
+ | `version` **(required)** | | string | | | Format version; this implementation reads version 1. |
37
+ | `unit` | | `m` \| `cm` \| `mm` \| `km` \| `in` \| `ft` | `m` | | Length unit (informative). |
38
+ | `xmlns` | | string | | | Optional. Ignored if present. A namespace is not required. |
39
+ | `name` | | string | | | Human readable label shown in tools. |
40
+
41
+ ### `<title>`
42
+
43
+ Document title.
44
+
45
+ Children: text content.
46
+
47
+ No attributes.
48
+
49
+ ### `<desc>`
50
+
51
+ Free text description.
52
+
53
+ Children: text content.
54
+
55
+ No attributes.
56
+
57
+ ### `<defs>`
58
+
59
+ Definitions that are not rendered directly; referenced with &lt;use ref&gt;.
60
+
61
+ Children: `<box>`, `<sphere>`, `<cylinder>`, `<cone>`, `<capsule>`, `<plane>`, `<torus>`, `<line>`, `<polyline>`, `<polygon>`, `<path>`, `<extrude>`, `<revolve>`, `<sweep>`, `<gear>`, `<mesh>`, `<group>`, `<repeat>`, `<scatter>`, `<lod>`, `<use>`, `<light>`, `<camera>`, `<material>`.
62
+
63
+ No attributes.
64
+
65
+ ### `<scene>`
66
+
67
+ Optional wrapper for scene content; behaves like a group.
68
+
69
+ Children: `<box>`, `<sphere>`, `<cylinder>`, `<cone>`, `<capsule>`, `<plane>`, `<torus>`, `<line>`, `<polyline>`, `<polygon>`, `<path>`, `<extrude>`, `<revolve>`, `<sweep>`, `<gear>`, `<mesh>`, `<group>`, `<repeat>`, `<scatter>`, `<lod>`, `<use>`, `<light>`, `<camera>`, `<material>`, `<environment>`, `<controls>`.
70
+
71
+ Accepts the common attributes, plus:
72
+
73
+ | Attribute | Alias | Type | Default | Range | Description |
74
+ |---|---|---|---|---|---|
75
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
76
+
77
+ ### `<environment>`
78
+
79
+ Background and ambient (hemisphere) lighting.
80
+
81
+ Children: none.
82
+
83
+ Attributes:
84
+
85
+ | Attribute | Alias | Type | Default | Range | Description |
86
+ |---|---|---|---|---|---|
87
+ | `background` | | color | `#171a1f` | | Clear colour. |
88
+ | `sky` | | color | `#ccdbf2` | | Ambient light colour from above. |
89
+ | `ground` | | color | `#403833` | | Ambient light colour from below. |
90
+ | `intensity` | | number | `0.5` | ≥ 0 | Ambient / environment intensity. |
91
+ | `exposure` | | number | `1` | > 0 | Tone mapping exposure. |
92
+
93
+ ## Materials
94
+
95
+ ### `<material>`
96
+
97
+ Minimal physically based material (metallic/roughness).
98
+
99
+ Children: none.
100
+
101
+ Attributes:
102
+
103
+ | Attribute | Alias | Type | Default | Range | Description |
104
+ |---|---|---|---|---|---|
105
+ | `id` | | id | | | Unique identifier, referenced by &lt;use ref&gt;, material="…" and path="…". |
106
+ | `name` | | string | | | Human readable label shown in tools. |
107
+ | `color` | `c` | color | `#ccc` | | Base colour (sRGB). |
108
+ | `metallic` | | number | `0` | ≥ 0, ≤ 1 | 0 = dielectric, 1 = metal. |
109
+ | `roughness` | | number | `0.5` | ≥ 0, ≤ 1 | 0 = mirror, 1 = fully rough. |
110
+ | `opacity` | | number | `1` | ≥ 0, ≤ 1 | Alpha; values below 1 are blended. |
111
+ | `emissive` | | color | `#000` | | Emitted colour. |
112
+ | `emissiveIntensity` | | number | `1` | ≥ 0 | Multiplier for emissive. |
113
+ | `map` | | texture | | | Base colour texture: image URL or checker(), grid(), stripes(), noise(), bricks(). |
114
+ | `normalMap` | | normalTexture | | | Normal map: image URL or bumps(), tiles(), noise(), waves(), bricks(). |
115
+ | `normalScale` | | number | `1` | | Normal map strength. |
116
+ | `uvScale` | | vec2 | `1,1` | | Texture repeat in u and v. |
117
+ | `doubleSided` | | bool | `false` | | Render back faces too. |
118
+ | `unlit` | | bool | `false` | | Ignore lighting; output the base colour. |
119
+ | `occlusionMap` | | texture | | | Occlusion texture. The red channel darkens indirect light. Image URL or a procedural texture. |
120
+ | `occlusionStrength` | | number | `1` | ≥ 0, ≤ 1 | Strength of occlusionMap. 0 disables it, 1 uses the texture as stored. |
121
+ | `metallicRoughnessMap` | | texture | | | Packed texture: green multiplies roughness, blue multiplies metallic. |
122
+ | `emissiveMap` | | texture | | | sRGB texture multiplied with emissive. |
123
+ | `alphaMode` | | `auto` \| `opaque` \| `mask` \| `blend` | `auto` | | auto blends when opacity is below 1 and is opaque otherwise. mask discards fragments below alphaCutoff. blend uses opacity as coverage. opaque ignores alpha. |
124
+ | `alphaCutoff` | | number | `0.5` | ≥ 0, ≤ 1 | Mask threshold. |
125
+
126
+ ## Containers and instancing
127
+
128
+ ### `<group>`
129
+
130
+ Groups children under a common transform and style.
131
+
132
+ Children: `<box>`, `<sphere>`, `<cylinder>`, `<cone>`, `<capsule>`, `<plane>`, `<torus>`, `<line>`, `<polyline>`, `<polygon>`, `<path>`, `<extrude>`, `<revolve>`, `<sweep>`, `<gear>`, `<mesh>`, `<group>`, `<repeat>`, `<scatter>`, `<lod>`, `<use>`, `<light>`, `<camera>`, `<material>`, `<animate>`.
133
+
134
+ Accepts the common attributes, plus:
135
+
136
+ | Attribute | Alias | Type | Default | Range | Description |
137
+ |---|---|---|---|---|---|
138
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
139
+
140
+ ### `<repeat>`
141
+
142
+ Repeats its children count times; copy i is transformed by step applied i times.
143
+
144
+ Children: `<box>`, `<sphere>`, `<cylinder>`, `<cone>`, `<capsule>`, `<plane>`, `<torus>`, `<line>`, `<polyline>`, `<polygon>`, `<path>`, `<extrude>`, `<revolve>`, `<sweep>`, `<gear>`, `<mesh>`, `<group>`, `<repeat>`, `<scatter>`, `<lod>`, `<use>`, `<light>`, `<camera>`, `<material>`, `<animate>`.
145
+
146
+ Accepts the common attributes, plus:
147
+
148
+ | Attribute | Alias | Type | Default | Range | Description |
149
+ |---|---|---|---|---|---|
150
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
151
+ | `count` **(required)** | `n` | int | | ≥ 0, ≤ 1000000 | Number of copies. |
152
+ | `step` **(required)** | | transform | | | Transform applied cumulatively between copies. |
153
+
154
+ ### `<scatter>`
155
+
156
+ Deterministic pseudo-random or grid placement of its children (seeded mulberry32).
157
+
158
+ Children: `<box>`, `<sphere>`, `<cylinder>`, `<cone>`, `<capsule>`, `<plane>`, `<torus>`, `<line>`, `<polyline>`, `<polygon>`, `<path>`, `<extrude>`, `<revolve>`, `<sweep>`, `<gear>`, `<mesh>`, `<group>`, `<repeat>`, `<scatter>`, `<lod>`, `<use>`, `<light>`, `<camera>`, `<material>`, `<animate>`.
159
+
160
+ Accepts the common attributes, plus:
161
+
162
+ | Attribute | Alias | Type | Default | Range | Description |
163
+ |---|---|---|---|---|---|
164
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
165
+ | `count` | `n` | int | | ≥ 0, ≤ 1000000 | Number of random copies (random layout). |
166
+ | `grid` | | count2 | | | Grid layout nx,nz (instead of count). |
167
+ | `spacing` | | vec2 | `1,1` | | Grid cell size x,z. |
168
+ | `area` | | size2 | | | Random layout: rectangle width,depth centred at the origin (XZ plane). |
169
+ | `radius` | | number | | > 0 | Random layout: disc radius (XZ plane). |
170
+ | `seed` | | int | `1` | ≥ 0 | Random seed. |
171
+ | `jitter` | | number | `0` | ≥ 0, ≤ 1 | Grid layout: random offset as a fraction of the cell. |
172
+ | `randomScale` | | range3 | | | Per-copy scale: a range (uniform, e.g. 0.8..1.2) or x,y,z ranges. |
173
+ | `randomRotation` | | range3 | | | Per-copy Euler ranges in degrees, e.g. 0,0..360,0. |
174
+ | `randomMaterial` | | ids → material | | | Per-copy material chosen from this list of ids. |
175
+
176
+ ### `<lod>`
177
+
178
+ Level of detail switch: child i is shown while the camera distance is below distances[i].
179
+
180
+ Children: `<box>`, `<sphere>`, `<cylinder>`, `<cone>`, `<capsule>`, `<plane>`, `<torus>`, `<line>`, `<polyline>`, `<polygon>`, `<path>`, `<extrude>`, `<revolve>`, `<sweep>`, `<gear>`, `<mesh>`, `<group>`, `<repeat>`, `<scatter>`, `<lod>`, `<use>`, `<light>`, `<camera>`, `<material>`, `<animate>`.
181
+
182
+ Accepts the common attributes, plus:
183
+
184
+ | Attribute | Alias | Type | Default | Range | Description |
185
+ |---|---|---|---|---|---|
186
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
187
+ | `distances` **(required)** | | numbers | | | Increasing switch distances; one fewer than the number of children. |
188
+
189
+ ### `<use>`
190
+
191
+ Instantiates the element with the given id (like SVG &lt;use&gt;).
192
+
193
+ Children: `<animate>`.
194
+
195
+ Accepts the common attributes, plus:
196
+
197
+ | Attribute | Alias | Type | Default | Range | Description |
198
+ |---|---|---|---|---|---|
199
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
200
+ | `ref` **(required)** | `href` | ref → node | | | Id of the element to instantiate. |
201
+
202
+ ## Shapes
203
+
204
+ ### `<box>`
205
+
206
+ Axis aligned box centred at the origin, optionally with rounded edges.
207
+
208
+ Children: `<animate>`.
209
+
210
+ Accepts the common attributes, plus:
211
+
212
+ | Attribute | Alias | Type | Default | Range | Description |
213
+ |---|---|---|---|---|---|
214
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
215
+ | `size` | `s` | size3 | `1,1,1` | | Edge lengths (one value for a cube). |
216
+ | `radius` | `r` | number | `0` | ≥ 0 | Edge rounding radius. |
217
+ | `segments` | | int | | ≥ 1, ≤ 32 | Rounding segments (automatic when omitted). |
218
+
219
+ ### `<sphere>`
220
+
221
+ Sphere centred at the origin.
222
+
223
+ Children: `<animate>`.
224
+
225
+ Accepts the common attributes, plus:
226
+
227
+ | Attribute | Alias | Type | Default | Range | Description |
228
+ |---|---|---|---|---|---|
229
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
230
+ | `radius` | `r` | number | `0.5` | > 0 | Radius. |
231
+ | `segments` | | int | | ≥ 3, ≤ 512 | Fixed tessellation (automatic level of detail when omitted). |
232
+
233
+ ### `<cylinder>`
234
+
235
+ Cylinder (or truncated cone) along Y, centred at the origin.
236
+
237
+ Children: `<animate>`.
238
+
239
+ Accepts the common attributes, plus:
240
+
241
+ | Attribute | Alias | Type | Default | Range | Description |
242
+ |---|---|---|---|---|---|
243
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
244
+ | `radius` | `r` | number | `0.5` | > 0 | Bottom radius (and top radius unless radiusTop is set). |
245
+ | `radiusTop` | | number | | ≥ 0 | Top radius. |
246
+ | `height` | `h` | number | `1` | > 0 | Height. |
247
+ | `segments` | | int | | ≥ 3, ≤ 512 | Fixed number of sides, e.g. 6 for a hexagonal prism. |
248
+ | `caps` | | bool | `true` | | Close the ends. |
249
+
250
+ ### `<cone>`
251
+
252
+ Cone along Y with its base at -height/2 and apex at +height/2.
253
+
254
+ Children: `<animate>`.
255
+
256
+ Accepts the common attributes, plus:
257
+
258
+ | Attribute | Alias | Type | Default | Range | Description |
259
+ |---|---|---|---|---|---|
260
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
261
+ | `radius` | `r` | number | `0.5` | > 0 | Base radius. |
262
+ | `height` | `h` | number | `1` | > 0 | Height. |
263
+ | `segments` | | int | | ≥ 3, ≤ 512 | Fixed number of sides. |
264
+ | `caps` | | bool | `true` | | Close the base. |
265
+
266
+ ### `<capsule>`
267
+
268
+ Capsule along Y; height is the total height including both caps.
269
+
270
+ Children: `<animate>`.
271
+
272
+ Accepts the common attributes, plus:
273
+
274
+ | Attribute | Alias | Type | Default | Range | Description |
275
+ |---|---|---|---|---|---|
276
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
277
+ | `radius` | `r` | number | `0.25` | > 0 | Radius. |
278
+ | `height` | `h` | number | `1` | > 0 | Total height (at least 2 × radius). |
279
+ | `segments` | | int | | ≥ 3, ≤ 512 | Fixed tessellation. |
280
+
281
+ ### `<plane>`
282
+
283
+ Flat rectangle in the XZ plane facing +Y (rendered double sided).
284
+
285
+ Children: `<animate>`.
286
+
287
+ Accepts the common attributes, plus:
288
+
289
+ | Attribute | Alias | Type | Default | Range | Description |
290
+ |---|---|---|---|---|---|
291
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
292
+ | `size` | `s` | size2 | `1,1` | | Width (x) and depth (z). |
293
+
294
+ ### `<torus>`
295
+
296
+ Torus around the Y axis.
297
+
298
+ Children: `<animate>`.
299
+
300
+ Accepts the common attributes, plus:
301
+
302
+ | Attribute | Alias | Type | Default | Range | Description |
303
+ |---|---|---|---|---|---|
304
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
305
+ | `radius` | `r` | number | `0.35` | > 0 | Distance from the centre to the tube centre. |
306
+ | `tube` | | number | `0.15` | > 0 | Tube radius. |
307
+ | `arc` | | angle | `360` | > 0, ≤ 360 | Swept angle in degrees (partial torus / pipe elbow). |
308
+ | `segments` | | int | | ≥ 3, ≤ 1024 | Fixed segments around the ring. |
309
+ | `tubeSegments` | | int | | ≥ 3, ≤ 512 | Fixed segments around the tube. |
310
+
311
+ ### `<line>`
312
+
313
+ Straight line segment; rendered as a tube when radius &gt; 0.
314
+
315
+ Children: `<animate>`.
316
+
317
+ Accepts the common attributes, plus:
318
+
319
+ | Attribute | Alias | Type | Default | Range | Description |
320
+ |---|---|---|---|---|---|
321
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
322
+ | `from` **(required)** | | vec3 | | | Start point. |
323
+ | `to` **(required)** | | vec3 | | | End point. |
324
+ | `radius` | `r` | number | `0` | ≥ 0 | Tube radius (0 = hairline). |
325
+ | `segments` | | int | | ≥ 3, ≤ 256 | Tube sides. |
326
+
327
+ ### `<polyline>`
328
+
329
+ 3D polyline or 2D path outline; rendered as a tube when radius &gt; 0.
330
+
331
+ Children: `<animate>`.
332
+
333
+ Accepts the common attributes, plus:
334
+
335
+ | Attribute | Alias | Type | Default | Range | Description |
336
+ |---|---|---|---|---|---|
337
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
338
+ | `points` | | points3 | | | x,y,z x,y,z … |
339
+ | `d` | | path2d | | | Outline of 2D path data in the XY plane (alternative to points). |
340
+ | `closed` | | bool | `false` | | Connect the last point to the first. |
341
+ | `smooth` | | bool | `false` | | Interpolate the points with a Catmull-Rom spline. |
342
+ | `radius` | `r` | number | `0` | ≥ 0 | Tube radius (0 = hairline). |
343
+ | `segments` | | int | | ≥ 3, ≤ 256 | Tube sides. |
344
+
345
+ ### `<polygon>`
346
+
347
+ Filled flat polygon in the XY plane (rendered double sided).
348
+
349
+ Children: `<animate>`.
350
+
351
+ Accepts the common attributes, plus:
352
+
353
+ | Attribute | Alias | Type | Default | Range | Description |
354
+ |---|---|---|---|---|---|
355
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
356
+ | `points` **(required)** | | points2 | | | x,y x,y … (at least 3 points). |
357
+
358
+ ### `<path>`
359
+
360
+ Filled flat 2D path in the XY plane (rendered double sided). In &lt;defs&gt; it is a reusable outline.
361
+
362
+ Children: `<animate>`.
363
+
364
+ Accepts the common attributes, plus:
365
+
366
+ | Attribute | Alias | Type | Default | Range | Description |
367
+ |---|---|---|---|---|---|
368
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
369
+ | `d` | | path2d | | | SVG path data in the local XY plane (y up): M L H V C S Q T A Z. |
370
+ | `path` | | ref → path | | | Id of a &lt;path&gt; element whose d is used. |
371
+ | `fillRule` | | `nonzero` \| `evenodd` | `nonzero` | | How nested contours become holes (SVG fill-rule). |
372
+
373
+ ### `<extrude>`
374
+
375
+ Extrudes a 2D path along +Z, optionally with a rounded bevel.
376
+
377
+ Children: `<animate>`.
378
+
379
+ Accepts the common attributes, plus:
380
+
381
+ | Attribute | Alias | Type | Default | Range | Description |
382
+ |---|---|---|---|---|---|
383
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
384
+ | `d` | | path2d | | | SVG path data in the local XY plane (y up): M L H V C S Q T A Z. |
385
+ | `path` | | ref → path | | | Id of a &lt;path&gt; element whose d is used. |
386
+ | `fillRule` | | `nonzero` \| `evenodd` | `nonzero` | | How nested contours become holes (SVG fill-rule). |
387
+ | `depth` | | number | `1` | > 0 | Extrusion depth along Z. |
388
+ | `bevel` | | number | `0` | ≥ 0 | Bevel radius on the front and back edges. |
389
+ | `bevelSegments` | | int | `3` | ≥ 1, ≤ 16 | Segments per bevel. |
390
+ | `center` | | bool | `false` | | Centre the extrusion on z = 0. |
391
+
392
+ ### `<revolve>`
393
+
394
+ Revolves (lathes) a 2D profile around the Y axis; x is the distance from the axis.
395
+
396
+ Children: `<animate>`.
397
+
398
+ Accepts the common attributes, plus:
399
+
400
+ | Attribute | Alias | Type | Default | Range | Description |
401
+ |---|---|---|---|---|---|
402
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
403
+ | `d` | | path2d | | | SVG path data in the local XY plane (y up): M L H V C S Q T A Z. |
404
+ | `path` | | ref → path | | | Id of a &lt;path&gt; element whose d is used. |
405
+ | `fillRule` | | `nonzero` \| `evenodd` | `nonzero` | | How nested contours become holes (SVG fill-rule). |
406
+ | `angle` | | angle | `360` | > 0, ≤ 360 | Revolution angle in degrees. |
407
+ | `segments` | | int | | ≥ 3, ≤ 1024 | Fixed number of radial segments. |
408
+
409
+ ### `<sweep>`
410
+
411
+ Sweeps a profile (circle or 2D path) along a 3D spine with rotation minimising frames.
412
+
413
+ Children: `<animate>`.
414
+
415
+ Accepts the common attributes, plus:
416
+
417
+ | Attribute | Alias | Type | Default | Range | Description |
418
+ |---|---|---|---|---|---|
419
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
420
+ | `d` | | path2d | | | SVG path data in the local XY plane (y up): M L H V C S Q T A Z. |
421
+ | `path` | | ref → path | | | Id of a &lt;path&gt; element whose d is used. |
422
+ | `fillRule` | | `nonzero` \| `evenodd` | `nonzero` | | How nested contours become holes (SVG fill-rule). |
423
+ | `radius` | `r` | number | | > 0 | Circular profile radius (alternative to d/path). |
424
+ | `along` **(required)** | | spine | | | Spine: x,y,z points, 3D path data (M L C S Q T Z) or helix(r,pitch,turns). |
425
+ | `smooth` | | bool | `false` | | Interpolate spine points with a Catmull-Rom spline. |
426
+ | `twist` | | angle | `0` | | Profile rotation in degrees from start to end. |
427
+ | `taper` | | number | `1` | ≥ 0 | Profile scale at the end (1 = constant). |
428
+ | `caps` | | bool | `true` | | Close open ends. |
429
+ | `segments` | | int | | ≥ 3, ≤ 256 | Circle profile sides. |
430
+
431
+ ### `<gear>`
432
+
433
+ Involute spur gear in the XY plane, extruded along Z.
434
+
435
+ Children: `<animate>`.
436
+
437
+ Accepts the common attributes, plus:
438
+
439
+ | Attribute | Alias | Type | Default | Range | Description |
440
+ |---|---|---|---|---|---|
441
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
442
+ | `teeth` | | int | `24` | ≥ 5, ≤ 400 | Number of teeth. |
443
+ | `module` | | number | `0.04` | > 0 | Module: pitch diameter / teeth. |
444
+ | `pressureAngle` | | angle | `20` | ≥ 10, ≤ 35 | Pressure angle in degrees. |
445
+ | `depth` | | number | `0.2` | > 0 | Face width (extrusion depth). |
446
+ | `bore` | | number | `0` | ≥ 0 | Radius of the centre hole. |
447
+ | `bevel` | | number | `0` | ≥ 0 | Edge bevel radius. |
448
+ | `center` | | bool | `true` | | Centre the gear on z = 0. |
449
+
450
+ ### `<mesh>`
451
+
452
+ Explicit indexed triangle mesh (escape hatch for data that is not procedural).
453
+
454
+ Children: `<animate>`.
455
+
456
+ Accepts the common attributes, plus:
457
+
458
+ | Attribute | Alias | Type | Default | Range | Description |
459
+ |---|---|---|---|---|---|
460
+ | `collide` | | bool | `true` | | When false the camera may pass through the element and its children (see &lt;controls collide&gt;). |
461
+ | `positions` **(required)** | | floats | | | x y z for every vertex. |
462
+ | `indices` | | indices | | | Triangle vertex indices (3 per triangle); omitted = non-indexed triangles. |
463
+ | `normals` | | floats | | | Optional x y z normal per vertex (computed when omitted). |
464
+ | `uvs` | | floats | | | Optional u v per vertex. |
465
+ | `smooth` | | angle | `30` | ≥ 0, ≤ 180 | Crease angle for computed normals (0 = flat). |
466
+
467
+ ## Lights and cameras
468
+
469
+ ### `<light>`
470
+
471
+ Directional, point, spot, ambient or hemisphere light.
472
+
473
+ Children: `<animate>`.
474
+
475
+ Attributes:
476
+
477
+ | Attribute | Alias | Type | Default | Range | Description |
478
+ |---|---|---|---|---|---|
479
+ | `id` | | id | | | Unique identifier, referenced by &lt;use ref&gt;, material="…" and path="…". |
480
+ | `name` | | string | | | Human readable label shown in tools. |
481
+ | `transform` | `t` | transform | | | SVG-style transform list; applied outside position/rotation/scale. |
482
+ | `position` | `p` | vec3 | `0,0,0` | | Light position (point/spot). |
483
+ | `rotation` | `rot` | vec3 | `0,0,0` | | Euler angles in degrees, applied about X, then Y, then Z. |
484
+ | `visible` | | bool | `true` | | When false the element and its children are not rendered. |
485
+ | `type` **(required)** | | `directional` \| `point` \| `spot` \| `ambient` \| `hemisphere` | | | Light kind. |
486
+ | `color` | `c` | color | `#fff` | | Light colour. |
487
+ | `intensity` | | number | `1` | ≥ 0 | Intensity multiplier. |
488
+ | `direction` | `dir` | vec3 | | | Direction the light travels (directional/spot). |
489
+ | `target` | | vec3 | | | Point the light aims at (alternative to direction). |
490
+ | `range` | | number | `0` | ≥ 0 | Point/spot cut-off distance (0 = unlimited). |
491
+ | `angle` | | angle | `45` | ≥ 1, ≤ 179 | Spot cone angle in degrees. |
492
+ | `penumbra` | | number | `0.2` | ≥ 0, ≤ 1 | Spot edge softness. |
493
+ | `groundColor` | | color | `#403833` | | Hemisphere light colour from below. |
494
+
495
+ ### `<camera>`
496
+
497
+ Perspective or orthographic camera. The first camera is the initial view.
498
+
499
+ Children: `<animate>`.
500
+
501
+ Attributes:
502
+
503
+ | Attribute | Alias | Type | Default | Range | Description |
504
+ |---|---|---|---|---|---|
505
+ | `id` | | id | | | Unique identifier, referenced by &lt;use ref&gt;, material="…" and path="…". |
506
+ | `name` | | string | | | Human readable label shown in tools. |
507
+ | `transform` | `t` | transform | | | SVG-style transform list; applied outside position/rotation/scale. |
508
+ | `position` | `p` | vec3 | `0,0,10` | | Eye position. |
509
+ | `rotation` | `rot` | vec3 | | | Euler orientation (used when no target is given; the camera looks down -Z). |
510
+ | `target` | | vec3 | | | Point the camera looks at. |
511
+ | `up` | | vec3 | `0,1,0` | | Up vector. |
512
+ | `type` | | `perspective` \| `orthographic` | `perspective` | | Projection. |
513
+ | `fov` | | angle | `45` | ≥ 1, ≤ 179 | Vertical field of view in degrees (perspective). |
514
+ | `height` | | number | `10` | > 0 | Visible height (orthographic). |
515
+ | `near` | | number | | > 0 | Near clip distance (automatic when omitted). |
516
+ | `far` | | number | | > 0 | Far clip distance (automatic when omitted). |
517
+ | `aspect` | | number | `1` | > 0 | Width / height of the view the author framed (e.g. 1.778 for 16:9). fov is the vertical angle at this aspect ratio. |
518
+ | `fit` | | `contain` \| `cover` \| `width` \| `height` | `contain` | | How the framed view adapts to other screens: contain keeps all of it visible, cover fills the screen, width and height keep that extent fixed. |
519
+
520
+ ## Animation
521
+
522
+ ### `<animate>`
523
+
524
+ Animates a transform of its parent (position, rotation, scale; target and fov of a camera) over time or over page scroll.
525
+
526
+ Children: none.
527
+
528
+ Attributes:
529
+
530
+ | Attribute | Alias | Type | Default | Range | Description |
531
+ |---|---|---|---|---|---|
532
+ | `attr` **(required)** | | `position` \| `rotation` \| `scale` \| `target` \| `fov` | | | Animated attribute. target and fov apply to &lt;camera&gt; only. |
533
+ | `from` | | animValue | | | Start value (defaults to the parent value). |
534
+ | `to` | | animValue | | | End value. |
535
+ | `values` | | keyframes | | | Key values separated by semicolons, e.g. 0,1,0; 2,1,0; 2,3,0 (instead of from/to). |
536
+ | `keyTimes` | | numbers | | | Progress (0 to 1) at which each of values is reached; evenly spaced when omitted. |
537
+ | `along` | | spine | | | Path to move along at constant speed (position and target): x,y,z points, 3D path data or helix(). |
538
+ | `smooth` | | bool | `false` | | Pass through values or along points on a smooth (centripetal Catmull-Rom) curve. |
539
+ | `dur` | | duration | | | Duration of one cycle, e.g. 4s or 500ms (required unless timeline="scroll"). |
540
+ | `begin` | | duration | `0` | ≥ 0 | Delay before the animation starts. |
541
+ | `repeat` | | repeatCount | `indefinite` | | Number of cycles or 'indefinite'. |
542
+ | `alternate` | | bool | `false` | | Play every second cycle backwards. |
543
+ | `easing` | | `linear` \| `ease-in` \| `ease-out` \| `ease-in-out` | `linear` | | Timing function. |
544
+ | `timeline` | | `time` \| `scroll` | `time` | | time: plays by the clock. scroll: progress follows page scroll from 0 to 1 (dur, begin, repeat and alternate are not used). |
545
+
546
+ ## Value types
547
+
548
+ | Type | Syntax |
549
+ |---|---|
550
+ | angle | Number of degrees. |
551
+ | animValue | Three numbers (one or three for scale, one for fov). |
552
+ | bool | `true` or `false`. |
553
+ | color | `#rgb`, `#rrggbb`, `#rrggbbaa`, `rgb(r,g,b)`, `rgba(r,g,b,a)` or a CSS colour name; sRGB. |
554
+ | count2 | Two positive whole numbers `nx,nz`. |
555
+ | duration | Time: `4`, `4s` or `250ms`. |
556
+ | enum | One of the listed keywords. |
557
+ | floats | Whitespace separated numbers (mesh data, stored as float32). |
558
+ | id | Identifier: a letter or `_` followed by letters, digits, `_ . : -`. |
559
+ | idlist | Comma or space separated ids. |
560
+ | indices | Whitespace separated non-negative whole numbers. |
561
+ | int | Whole number. |
562
+ | keyframes | Key values separated by semicolons, each with as many numbers as `from`/`to`: `0,1,0; 2,1,0; 2,3,0`. |
563
+ | normalTexture | Image URL, or a procedural normal map: `bumps(count,strength)`, `tiles(count,strength,gap)`, `noise(scale,strength,seed)`, `waves(count,strength)`, `bricks(count,strength)`. |
564
+ | number | Decimal number, e.g. `1`, `-0.25`, `.5`, `2e-3`. |
565
+ | numbers | List of numbers. |
566
+ | path2d | SVG path data: `M L H V C S Q T A Z` (absolute and relative), in the local XY plane with y up. |
567
+ | points2 | Point list `x,y x,y …`. |
568
+ | points3 | Point list `x,y,z x,y,z …`. |
569
+ | range3 | A range `lo..hi` used for x, y and z, or three comma separated ranges/numbers `x,y,z`. |
570
+ | ref | Id of another element of the indicated kind. |
571
+ | repeatCount | Number of repetitions or `indefinite`. |
572
+ | scale3 | One number (uniform) or three numbers. |
573
+ | size2 | One number (both dimensions) or two numbers. |
574
+ | size3 | One number (all three dimensions) or three numbers. |
575
+ | spine | 3D spine: `x,y,z x,y,z …`, 3D path data (`M L C S Q T Z` with 3 numbers per point) or `helix(radius,pitch,turns[,segmentsPerTurn])`. |
576
+ | string | Free text. |
577
+ | texture | Image URL, or a procedural texture: `checker(count,color1,color2)`, `grid(count,width,line,background)`, `stripes(count,color1,color2)`, `noise(scale,color1,color2,seed)`, `bricks(count,brick,mortar)`; trailing arguments may be omitted. |
578
+ | transform | SVG-style list: `translate(x[,y[,z]])`, `rotate(x,y,z)`, `rotate(a,ax,ay,az)`, `rotateX(a)`, `rotateY(a)`, `rotateZ(a)`, `scale(s)`, `scale(x,y,z)`, `quat(x,y,z,w)`, `matrix(16 numbers, column-major)`; composed left to right. |
579
+ | vec2 | Two numbers `x,y` (comma and/or space separated). |
580
+ | vec3 | Three numbers `x,y,z`. |
581
+