sparcoon 0.9.1 → 0.9.3

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 (36) hide show
  1. package/README.md +176 -76
  2. package/dist/artifact/FXArtifact.d.ts +51 -3
  3. package/dist/behaviorTransformFeedbackLayout.d.ts +24 -0
  4. package/dist/behaviorTransformFeedbackLayout.js +24 -0
  5. package/dist/coreLayout.d.ts +9 -5
  6. package/dist/coreLayout.js +17 -4
  7. package/dist/editor/index.d.ts +1 -0
  8. package/dist/editor/index.js +1 -1
  9. package/dist/effect/FXEffect.d.ts +4 -0
  10. package/dist/effect/FXEffect.js +47 -14
  11. package/dist/effect/FXEffectSpec.d.ts +21 -4
  12. package/dist/emitter/FXApplyRenderArtifactOptions.d.ts +15 -0
  13. package/dist/emitter/FXApplyRenderArtifactOptions.js +1 -0
  14. package/dist/emitter/FXEmitter.d.ts +44 -14
  15. package/dist/emitter/FXEmitter.js +132 -156
  16. package/dist/emitter/FXEmitterDriver.Internal.d.ts +26 -0
  17. package/dist/emitter/FXEmitterDriver.Internal.js +70 -0
  18. package/dist/emitter/FXFromArtifactsOptions.d.ts +12 -1
  19. package/dist/emitter/FXGPUEmitterDriver.Internal.d.ts +1 -0
  20. package/dist/emitter/FXGPUEmitterDriver.Internal.js +137 -0
  21. package/dist/emitter/FXJSEmitterDriver.Internal.d.ts +1 -0
  22. package/dist/emitter/FXJSEmitterDriver.Internal.js +133 -0
  23. package/dist/emitter/FXSimulationHolder.js +7 -5
  24. package/dist/emitter/FXTransformFeedbackSimulationHolder.d.ts +1 -0
  25. package/dist/emitter/FXTransformFeedbackSimulationHolder.js +249 -0
  26. package/dist/index.d.ts +4 -3
  27. package/dist/index.js +3 -2
  28. package/dist/instancedParticle/FXInstancedParticle.js +28 -1
  29. package/dist/instancedParticle/FXTransformFeedbackParticle.d.ts +1 -0
  30. package/dist/instancedParticle/FXTransformFeedbackParticle.js +169 -0
  31. package/dist/miscellaneous/fxMath.d.ts +18 -11
  32. package/dist/miscellaneous/fxMath.js +89 -209
  33. package/dist/render/FXArtifactMaterial.Internal.js +66 -40
  34. package/dist/render/FXArtifactMaterial.js +1 -1
  35. package/dist/render/FXMesh.js +2 -4
  36. package/package.json +11 -3
@@ -48,11 +48,23 @@ function transformPreamble(outputs, withNormal) {
48
48
  return lines.join("\n");
49
49
  }
50
50
  // `#include <project_vertex>` replacement: projects `fxModelPos`, records camera distance, feeds alpha-hash.
51
+ // World -> view via `viewMatrix` only, deliberately skipping `modelMatrix`: particle simulation
52
+ // authors `fxModelPos` directly in world space (reference space == world by convention), so the
53
+ // emitter's own scene transform must never re-enter here - see fxWorldMatrix for the explicit
54
+ // opt-in a graph uses when it wants particles attached to the emitter instead.
51
55
  function projectFromModelPos() {
52
56
  return [
53
- "vec4 mvPosition = modelViewMatrix * vec4(fxModelPos, 1.0);",
57
+ "vec4 mvPosition = viewMatrix * vec4(fxModelPos, 1.0);",
54
58
  "p_cameraDistance = length(mvPosition.xyz);",
55
59
  "gl_Position = projectionMatrix * mvPosition;",
60
+ // A dead particle (age >= lifetime, coreLayout.ts's convention) is pushed outside the clip
61
+ // volume on every axis so the GPU's trivial-reject clip test drops the whole primitive before
62
+ // rasterization - a fragment discard would defeat opaque mode's early-Z instead (see
63
+ // alphaDiscardLines, which already skips discard for that reason). A JS-driven emitter never
64
+ // draws a dead particle at all (removeDeadParticles keeps it out of the instance range), so
65
+ // this is a no-op there; a GPU-driven emitter always draws its full fixed capacity with no
66
+ // such compaction (FXTransformFeedbackParticle), which is what this actually guards.
67
+ "if (PARTICLE_AGE >= PARTICLE_LIFETIME) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); }",
56
68
  "#ifdef USE_ALPHAHASH",
57
69
  " vPosition = fxModelPos;",
58
70
  "#endif",
@@ -161,7 +173,7 @@ export function buildUnlitArtifactMaterial(render, varyings, timeUniform, deltaU
161
173
  "uniform vec3 objectVelocity;",
162
174
  "uniform vec3 objectAngularVelocity;",
163
175
  "varying float p_cameraDistance;",
164
- // World-space surface frame + position (NORMAL_SPACE_PLAN): the canonical author space for
176
+ // World-space surface frame + position: the canonical author space for
165
177
  // normals. Written in the vertex stage, read as the geometryNormal/geometryTangent/worldPosition
166
178
  // builtins in the fragment stage.
167
179
  "varying vec3 vWorldNormal;",
@@ -185,12 +197,13 @@ export function buildUnlitArtifactMaterial(render, varyings, timeUniform, deltaU
185
197
  "vec3 objectNormal = fxNormalXform * normal;",
186
198
  "#include <defaultnormal_vertex>",
187
199
  "#include <normal_vertex>",
188
- // World-space surface frame + position (NORMAL_SPACE_PLAN): mat3(modelMatrix) is exact for a
189
- // plane's frame under uniform scale; the tangent is the plane's local +X (the u axis), so billboard
190
- // roll/orientation is baked in here ONCE for every consumer (normal maps, spherical normal, fresnel).
191
- "vWorldNormal = normalize( mat3( modelMatrix ) * objectNormal );",
192
- "vWorldTangent = normalize( mat3( modelMatrix ) * ( fxNormalXform * vec3( 1.0, 0.0, 0.0 ) ) );",
193
- "vWorldPos = ( modelMatrix * vec4( fxModelPos, 1.0 ) ).xyz;",
200
+ // World-space surface frame + position: fxModelPos/objectNormal are already world space (no
201
+ // modelMatrix step - see fxWorldMatrix for the explicit emitter-attach opt-in). The tangent is
202
+ // the plane's local +X (the u axis), so billboard roll/orientation is baked in here ONCE for
203
+ // every consumer (normal maps, spherical normal, fresnel).
204
+ "vWorldNormal = normalize( objectNormal );",
205
+ "vWorldTangent = normalize( fxNormalXform * vec3( 1.0, 0.0, 0.0 ) );",
206
+ "vWorldPos = fxModelPos;",
194
207
  projectFromModelPos(),
195
208
  "#include <fog_vertex>",
196
209
  "}",
@@ -205,7 +218,7 @@ export function buildUnlitArtifactMaterial(render, varyings, timeUniform, deltaU
205
218
  "uniform vec3 objectVelocity;",
206
219
  "uniform vec3 objectAngularVelocity;",
207
220
  "varying float p_cameraDistance;",
208
- // World-space surface frame + position (NORMAL_SPACE_PLAN): the canonical author space for
221
+ // World-space surface frame + position: the canonical author space for
209
222
  // normals. Written in the vertex stage, read as the geometryNormal/geometryTangent/worldPosition
210
223
  // builtins in the fragment stage.
211
224
  "varying vec3 vWorldNormal;",
@@ -223,7 +236,7 @@ export function buildUnlitArtifactMaterial(render, varyings, timeUniform, deltaU
223
236
  "void main() {",
224
237
  // Front-facing sign for the surface frame below (a back-facing fragment flips the normal).
225
238
  "float fxFaceDirection = gl_FrontFacing ? 1.0 : - 1.0;",
226
- // World-space surface frame + position - the canonical author space (NORMAL_SPACE_PLAN). The
239
+ // World-space surface frame + position - the canonical author space. The
227
240
  // lighting intrinsics convert world->view at their own boundary; geometryTangent/worldPosition feed
228
241
  // normal maps and camera-correct fresnel. Declared before the node body so any reader resolves.
229
242
  "vec3 geometryNormal = normalize( vWorldNormal ) * fxFaceDirection;",
@@ -258,13 +271,18 @@ export function buildUnlitArtifactMaterial(render, varyings, timeUniform, deltaU
258
271
  forceSinglePass: true,
259
272
  premultipliedAlpha: true,
260
273
  });
274
+ // `alphaHash` pulls in Three's own alphahash_pars_fragment chunk, which calls dFdx/dFdy - under
275
+ // a real WebGL1 context those need an explicit extension request or the shader fails to
276
+ // compile ("extension is disabled"); under WebGL2 this is a no-op (dFdx/dFdy are core there,
277
+ // and three skips extension generation entirely for a WebGL2 context either way).
278
+ material.extensions.derivatives = materialFlags(renderMode).alphaHash;
261
279
  material.customProgramCacheKey = () => `fx-unlit_${cacheKey}`;
262
280
  return material;
263
281
  }
264
282
  // The lighting-node intrinsics the graph calls by name (`fn.raw(... "fxLambertShade" ...)`) but never
265
283
  // defines - the frozen `fx_` cross-repo ABI. Each wraps the exact stock Lambert light sequence in a
266
- // function of (color, WORLD-space normal) -> shaded color: the graph authors normals in world space
267
- // (NORMAL_SPACE_PLAN), and each intrinsic converts world->view on its first line before Three's
284
+ // function of (color, WORLD-space normal) -> shaded color: the graph authors normals in world
285
+ // space, and each intrinsic converts world->view on its first line before Three's
268
286
  // view-space light chain runs, so view space stays a private detail behind this ABI. A node emits a
269
287
  // plain expression that can sit anywhere in the graph (mid-graph mix included). Placed AFTER the pars chunks (which supply the
270
288
  // `ReflectedLight`/`LambertMaterial` types, the `RE_*` macros, `vViewPosition`, the light uniforms) and
@@ -330,7 +348,7 @@ function buildLitArtifactMaterial(render, varyings, timeUniform, deltaUniform, v
330
348
  "uniform vec3 objectVelocity;",
331
349
  "uniform vec3 objectAngularVelocity;",
332
350
  "varying float p_cameraDistance;",
333
- // World-space surface frame + position (NORMAL_SPACE_PLAN): the canonical author space for
351
+ // World-space surface frame + position: the canonical author space for
334
352
  // normals. Written in the vertex stage, read as the geometryNormal/geometryTangent/worldPosition
335
353
  // builtins in the fragment stage.
336
354
  "varying vec3 vWorldNormal;",
@@ -353,17 +371,18 @@ function buildLitArtifactMaterial(render, varyings, timeUniform, deltaUniform, v
353
371
  "vec3 objectNormal = fxNormalXform * normal;",
354
372
  "#include <defaultnormal_vertex>",
355
373
  "#include <normal_vertex>",
356
- // World-space surface frame + position (NORMAL_SPACE_PLAN): mat3(modelMatrix) is exact for a
357
- // plane's frame under uniform scale; the tangent is the plane's local +X (the u axis), so billboard
358
- // roll/orientation is baked in here ONCE for every consumer (normal maps, spherical normal, fresnel).
359
- "vWorldNormal = normalize( mat3( modelMatrix ) * objectNormal );",
360
- "vWorldTangent = normalize( mat3( modelMatrix ) * ( fxNormalXform * vec3( 1.0, 0.0, 0.0 ) ) );",
361
- "vWorldPos = ( modelMatrix * vec4( fxModelPos, 1.0 ) ).xyz;",
374
+ // World-space surface frame + position: fxModelPos/objectNormal are already world space (no
375
+ // modelMatrix step - see fxWorldMatrix for the explicit emitter-attach opt-in). The tangent is
376
+ // the plane's local +X (the u axis), so billboard roll/orientation is baked in here ONCE for
377
+ // every consumer (normal maps, spherical normal, fresnel).
378
+ "vWorldNormal = normalize( objectNormal );",
379
+ "vWorldTangent = normalize( fxNormalXform * vec3( 1.0, 0.0, 0.0 ) );",
380
+ "vWorldPos = fxModelPos;",
362
381
  "vec3 transformed = position;",
363
382
  projectFromModelPos(),
364
383
  "vViewPosition = - mvPosition.xyz;",
365
384
  "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined( USE_SHADOWMAP ) || defined( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0",
366
- " vec4 worldPosition = modelMatrix * vec4(particleCenter, 1.0);",
385
+ " vec4 worldPosition = vec4(particleCenter, 1.0);",
367
386
  "#endif",
368
387
  "#include <shadowmap_vertex>",
369
388
  "#include <fog_vertex>",
@@ -378,7 +397,7 @@ function buildLitArtifactMaterial(render, varyings, timeUniform, deltaUniform, v
378
397
  "uniform vec3 objectVelocity;",
379
398
  "uniform vec3 objectAngularVelocity;",
380
399
  "varying float p_cameraDistance;",
381
- // World-space surface frame + position (NORMAL_SPACE_PLAN): the canonical author space for
400
+ // World-space surface frame + position: the canonical author space for
382
401
  // normals. Written in the vertex stage, read as the geometryNormal/geometryTangent/worldPosition
383
402
  // builtins in the fragment stage.
384
403
  "varying vec3 vWorldNormal;",
@@ -402,7 +421,7 @@ function buildLitArtifactMaterial(render, varyings, timeUniform, deltaUniform, v
402
421
  // Front-facing sign (matching `normal_fragment_begin` under DOUBLE_SIDED): a back-facing fragment
403
422
  // flips the surface frame below.
404
423
  "float fxFaceDirection = gl_FrontFacing ? 1.0 : - 1.0;",
405
- // World-space surface frame + position - the canonical author space (NORMAL_SPACE_PLAN). The
424
+ // World-space surface frame + position - the canonical author space. The
406
425
  // lighting intrinsics convert world->view at their own boundary; geometryTangent/worldPosition feed
407
426
  // normal maps and camera-correct fresnel. Declared before the node body so any reader resolves.
408
427
  "vec3 geometryNormal = normalize( vWorldNormal ) * fxFaceDirection;",
@@ -439,6 +458,8 @@ function buildLitArtifactMaterial(render, varyings, timeUniform, deltaUniform, v
439
458
  forceSinglePass: true,
440
459
  premultipliedAlpha: true,
441
460
  });
461
+ // See buildUnlitArtifactMaterial's identical line for why this is needed.
462
+ material.extensions.derivatives = materialFlags(renderMode).alphaHash;
442
463
  material.customProgramCacheKey = () => `fx-lit-nodes_${cacheKey}`;
443
464
  return material;
444
465
  }
@@ -471,11 +492,12 @@ function meshTransformPreamble(outputs, withNormal) {
471
492
  }
472
493
  return lines.join("\n");
473
494
  }
474
- // Mesh `#include <project_vertex>` replacement: plain object-space projection. No `p_cameraDistance`
475
- // (a mesh has no per-particle camera-distance builtin); still feeds alpha-hash `vPosition`.
495
+ // Mesh `#include <project_vertex>` replacement: plain world-space projection (`viewMatrix` only,
496
+ // no `modelMatrix` - see {@link projectFromModelPos}). No `p_cameraDistance` (a mesh has no
497
+ // per-particle camera-distance builtin); still feeds alpha-hash `vPosition`.
476
498
  function meshProjectFromModelPos() {
477
499
  return [
478
- "vec4 mvPosition = modelViewMatrix * vec4(fxModelPos, 1.0);",
500
+ "vec4 mvPosition = viewMatrix * vec4(fxModelPos, 1.0);",
479
501
  "gl_Position = projectionMatrix * mvPosition;",
480
502
  "#ifdef USE_ALPHAHASH",
481
503
  " vPosition = fxModelPos;",
@@ -516,9 +538,9 @@ function buildMeshUnlitArtifactMaterial(render, timeUniform, deltaUniform, veloc
516
538
  "vec3 objectNormal = fxNormalXform * normal;",
517
539
  "#include <defaultnormal_vertex>",
518
540
  "#include <normal_vertex>",
519
- "vWorldNormal = normalize( mat3( modelMatrix ) * objectNormal );",
520
- "vWorldTangent = normalize( mat3( modelMatrix ) * ( fxNormalXform * vec3( 1.0, 0.0, 0.0 ) ) );",
521
- "vWorldPos = ( modelMatrix * vec4( fxModelPos, 1.0 ) ).xyz;",
541
+ "vWorldNormal = normalize( objectNormal );",
542
+ "vWorldTangent = normalize( fxNormalXform * vec3( 1.0, 0.0, 0.0 ) );",
543
+ "vWorldPos = fxModelPos;",
522
544
  meshProjectFromModelPos(),
523
545
  "#include <fog_vertex>",
524
546
  "}",
@@ -571,6 +593,8 @@ function buildMeshUnlitArtifactMaterial(render, timeUniform, deltaUniform, veloc
571
593
  forceSinglePass: true,
572
594
  premultipliedAlpha: true,
573
595
  });
596
+ // See buildUnlitArtifactMaterial's identical line for why this is needed.
597
+ material.extensions.derivatives = materialFlags(renderMode).alphaHash;
574
598
  material.customProgramCacheKey = () => `fx-mesh-unlit_${cacheKey}`;
575
599
  return material;
576
600
  }
@@ -611,14 +635,14 @@ function buildMeshLitArtifactMaterial(render, timeUniform, deltaUniform, velocit
611
635
  "vec3 objectNormal = fxNormalXform * normal;",
612
636
  "#include <defaultnormal_vertex>",
613
637
  "#include <normal_vertex>",
614
- "vWorldNormal = normalize( mat3( modelMatrix ) * objectNormal );",
615
- "vWorldTangent = normalize( mat3( modelMatrix ) * ( fxNormalXform * vec3( 1.0, 0.0, 0.0 ) ) );",
616
- "vWorldPos = ( modelMatrix * vec4( fxModelPos, 1.0 ) ).xyz;",
638
+ "vWorldNormal = normalize( objectNormal );",
639
+ "vWorldTangent = normalize( fxNormalXform * vec3( 1.0, 0.0, 0.0 ) );",
640
+ "vWorldPos = fxModelPos;",
617
641
  "vec3 transformed = position;",
618
642
  meshProjectFromModelPos(),
619
643
  "vViewPosition = - mvPosition.xyz;",
620
644
  "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined( USE_SHADOWMAP ) || defined( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0",
621
- " vec4 worldPosition = modelMatrix * vec4(fxModelPos, 1.0);",
645
+ " vec4 worldPosition = vec4(fxModelPos, 1.0);",
622
646
  "#endif",
623
647
  "#include <shadowmap_vertex>",
624
648
  "#include <fog_vertex>",
@@ -683,6 +707,8 @@ function buildMeshLitArtifactMaterial(render, timeUniform, deltaUniform, velocit
683
707
  forceSinglePass: true,
684
708
  premultipliedAlpha: true,
685
709
  });
710
+ // See buildUnlitArtifactMaterial's identical line for why this is needed.
711
+ material.extensions.derivatives = materialFlags(renderMode).alphaHash;
686
712
  material.customProgramCacheKey = () => `fx-mesh-lit-nodes_${cacheKey}`;
687
713
  return material;
688
714
  }
@@ -753,16 +779,16 @@ export function buildArtifactDepthMaterial(render, varyings, timeUniform, deltaU
753
779
  "vec3 objectNormal = fxNormalXform * normal;",
754
780
  "#include <defaultnormal_vertex>",
755
781
  "#include <normal_vertex>",
756
- "vWorldNormal = normalize( mat3( modelMatrix ) * objectNormal );",
757
- "vWorldTangent = normalize( mat3( modelMatrix ) * ( fxNormalXform * vec3( 1.0, 0.0, 0.0 ) ) );",
758
- "vWorldPos = ( modelMatrix * vec4( fxModelPos, 1.0 ) ).xyz;",
782
+ "vWorldNormal = normalize( objectNormal );",
783
+ "vWorldTangent = normalize( fxNormalXform * vec3( 1.0, 0.0, 0.0 ) );",
784
+ "vWorldPos = fxModelPos;",
759
785
  ...(lit ? ["vec3 transformed = position;"] : []),
760
786
  projectFromModelPos(),
761
787
  ...(lit
762
788
  ? [
763
789
  "vViewPosition = - mvPosition.xyz;",
764
790
  "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined( USE_SHADOWMAP ) || defined( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0",
765
- " vec4 worldPosition = modelMatrix * vec4(particleCenter, 1.0);",
791
+ " vec4 worldPosition = vec4(particleCenter, 1.0);",
766
792
  "#endif",
767
793
  "#include <shadowmap_vertex>",
768
794
  ]
@@ -870,16 +896,16 @@ export function buildMeshArtifactDepthMaterial(render, timeUniform, deltaUniform
870
896
  "vec3 objectNormal = fxNormalXform * normal;",
871
897
  "#include <defaultnormal_vertex>",
872
898
  "#include <normal_vertex>",
873
- "vWorldNormal = normalize( mat3( modelMatrix ) * objectNormal );",
874
- "vWorldTangent = normalize( mat3( modelMatrix ) * ( fxNormalXform * vec3( 1.0, 0.0, 0.0 ) ) );",
875
- "vWorldPos = ( modelMatrix * vec4( fxModelPos, 1.0 ) ).xyz;",
899
+ "vWorldNormal = normalize( objectNormal );",
900
+ "vWorldTangent = normalize( fxNormalXform * vec3( 1.0, 0.0, 0.0 ) );",
901
+ "vWorldPos = fxModelPos;",
876
902
  ...(lit ? ["vec3 transformed = position;"] : []),
877
903
  meshProjectFromModelPos(),
878
904
  ...(lit
879
905
  ? [
880
906
  "vViewPosition = - mvPosition.xyz;",
881
907
  "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined( USE_SHADOWMAP ) || defined( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0",
882
- " vec4 worldPosition = modelMatrix * vec4(fxModelPos, 1.0);",
908
+ " vec4 worldPosition = vec4(fxModelPos, 1.0);",
883
909
  "#endif",
884
910
  "#include <shadowmap_vertex>",
885
911
  ]
@@ -1,4 +1,4 @@
1
- import { buildArtifactDepthMaterial, buildArtifactMaterial } from "./FXArtifactMaterial.Internal.js";
1
+ import { buildArtifactDepthMaterial, buildArtifactMaterial, } from "./FXArtifactMaterial.Internal.js";
2
2
  /**
3
3
  * @internal Runtime material driver: wraps a precompiled {@link FXRenderArtifact} and builds the
4
4
  * concrete self-contained `ShaderMaterial` via {@link buildArtifactMaterial}, which picks the flat or
@@ -1,4 +1,4 @@
1
- import { Mesh, Quaternion, Vector3, } from "three";
1
+ import { Mesh, Quaternion, Vector3 } from "three";
2
2
  import { FXObjectMotionTracker } from "../emitter/FXObjectMotion.Internal.js";
3
3
  import { resolveGeometrySource } from "../instancedParticle/primitiveGeometry.js";
4
4
  import { FXWorld } from "../world/FXWorld.js";
@@ -39,9 +39,7 @@ export class FXMesh extends Mesh {
39
39
  const driver = new FXMeshMaterial(render, options.textures);
40
40
  const geometry = resolveGeometrySource(render.geometry, options.geometries ?? {});
41
41
  const ownsGeometry = render.geometry === undefined || render.geometry.type === "primitive";
42
- const depthMaterial = (options.castShadow ?? false)
43
- ? driver.buildThreeDepthMaterial()
44
- : undefined;
42
+ const depthMaterial = (options.castShadow ?? false) ? driver.buildThreeDepthMaterial() : undefined;
45
43
  const mesh = new FXMesh(geometry, driver, driver.buildThreeMaterial(), depthMaterial, ownsGeometry, world);
46
44
  if (options.receiveShadow ?? false) {
47
45
  mesh.receiveShadow = true;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sparcoon",
3
- "version": "0.9.1",
4
- "description": "Runtime for VFX artifacts authored in the Sparcoon Editor.",
3
+ "version": "0.9.3",
4
+ "description": "Three.js runtime for visual effects authored in the Sparcoon Editor - precompiled artifacts, one draw call per emitter, no eval.",
5
5
  "keywords": [
6
6
  "three",
7
7
  "threejs",
@@ -14,13 +14,18 @@
14
14
  "instanced",
15
15
  "instancing",
16
16
  "billboard",
17
+ "transform-feedback",
17
18
  "webgl",
19
+ "webgl2",
20
+ "glsl",
18
21
  "3d",
19
22
  "animation",
23
+ "playable-ads",
24
+ "esm",
20
25
  "typescript",
21
26
  "sparcoon"
22
27
  ],
23
- "homepage": "https://github.com/jango-git/sparcoon#readme",
28
+ "homepage": "https://jango-git.github.io/sparcoon-editor/",
24
29
  "bugs": {
25
30
  "url": "https://github.com/jango-git/sparcoon/issues"
26
31
  },
@@ -50,6 +55,9 @@
50
55
  "LICENSE"
51
56
  ],
52
57
  "sideEffects": false,
58
+ "publishConfig": {
59
+ "tag": "experimental"
60
+ },
53
61
  "engines": {
54
62
  "node": ">=18.18.0"
55
63
  },