@opsydyn/effect-three 0.2.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 (134) hide show
  1. package/CHANGELOG.md +21 -1
  2. package/README.md +14 -1
  3. package/dist/{index-01kwfekm.js → index-h3vf50fn.js} +2418 -85
  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 +543 -149
  8. package/dist/index.js.map +8 -6
  9. package/dist/kernel/behaviours.d.ts.map +1 -1
  10. package/dist/kernel/boxSelect.d.ts +22 -0
  11. package/dist/kernel/boxSelect.d.ts.map +1 -0
  12. package/dist/kernel/build.d.ts +197 -6
  13. package/dist/kernel/build.d.ts.map +1 -1
  14. package/dist/kernel/cameraMotion.d.ts +3 -1
  15. package/dist/kernel/cameraMotion.d.ts.map +1 -1
  16. package/dist/kernel/cameraShake.d.ts +33 -0
  17. package/dist/kernel/cameraShake.d.ts.map +1 -0
  18. package/dist/kernel/describeScene.d.ts +50 -0
  19. package/dist/kernel/describeScene.d.ts.map +1 -0
  20. package/dist/kernel/description.d.ts +240 -2
  21. package/dist/kernel/description.d.ts.map +1 -1
  22. package/dist/kernel/diff.d.ts +18 -1
  23. package/dist/kernel/diff.d.ts.map +1 -1
  24. package/dist/kernel/equality.d.ts +13 -1
  25. package/dist/kernel/equality.d.ts.map +1 -1
  26. package/dist/kernel/gizmo.d.ts +69 -0
  27. package/dist/kernel/gizmo.d.ts.map +1 -0
  28. package/dist/kernel/history.d.ts +61 -0
  29. package/dist/kernel/history.d.ts.map +1 -0
  30. package/dist/kernel/index.d.ts +13 -2
  31. package/dist/kernel/index.d.ts.map +1 -1
  32. package/dist/kernel/index.js +116 -3
  33. package/dist/kernel/index.js.map +1 -1
  34. package/dist/kernel/inspect.d.ts +85 -0
  35. package/dist/kernel/inspect.d.ts.map +1 -0
  36. package/dist/kernel/lineGeometry.d.ts +25 -0
  37. package/dist/kernel/lineGeometry.d.ts.map +1 -0
  38. package/dist/kernel/lockstep.d.ts +114 -0
  39. package/dist/kernel/lockstep.d.ts.map +1 -0
  40. package/dist/kernel/loop.d.ts.map +1 -1
  41. package/dist/kernel/materials.d.ts.map +1 -1
  42. package/dist/kernel/pivot.d.ts +54 -0
  43. package/dist/kernel/pivot.d.ts.map +1 -0
  44. package/dist/kernel/pointBuffers.d.ts +17 -0
  45. package/dist/kernel/pointBuffers.d.ts.map +1 -0
  46. package/dist/kernel/pointer.d.ts +12 -0
  47. package/dist/kernel/pointer.d.ts.map +1 -1
  48. package/dist/kernel/renderKit.d.ts +21 -1
  49. package/dist/kernel/renderKit.d.ts.map +1 -1
  50. package/dist/kernel/renderer.d.ts +6 -0
  51. package/dist/kernel/renderer.d.ts.map +1 -1
  52. package/dist/kernel/resources.d.ts.map +1 -1
  53. package/dist/kernel/sceneChanges.d.ts +87 -0
  54. package/dist/kernel/sceneChanges.d.ts.map +1 -0
  55. package/dist/kernel/sceneGraph.d.ts +6 -1
  56. package/dist/kernel/sceneGraph.d.ts.map +1 -1
  57. package/dist/kernel/seeded.d.ts +9 -0
  58. package/dist/kernel/seeded.d.ts.map +1 -0
  59. package/dist/kernel/shots.d.ts +26 -0
  60. package/dist/kernel/shots.d.ts.map +1 -0
  61. package/dist/kernel/tape.d.ts +38 -0
  62. package/dist/kernel/tape.d.ts.map +1 -0
  63. package/dist/kernel/trail.d.ts +31 -0
  64. package/dist/kernel/trail.d.ts.map +1 -0
  65. package/dist/kernel/viewportGizmo.d.ts +25 -0
  66. package/dist/kernel/viewportGizmo.d.ts.map +1 -0
  67. package/dist/runtime/Inspector.d.ts +20 -0
  68. package/dist/runtime/Inspector.d.ts.map +1 -0
  69. package/dist/runtime/SceneFile.d.ts +448 -0
  70. package/dist/runtime/SceneFile.d.ts.map +1 -0
  71. package/dist/runtime/SceneSchema.d.ts +614 -5
  72. package/dist/runtime/SceneSchema.d.ts.map +1 -1
  73. package/dist/runtime/errors.d.ts +9 -0
  74. package/dist/runtime/errors.d.ts.map +1 -1
  75. package/dist/runtime/index.d.ts +3 -1
  76. package/dist/runtime/index.d.ts.map +1 -1
  77. package/dist/webgl/index.d.ts.map +1 -1
  78. package/dist/webgl/index.js +228 -3
  79. package/dist/webgl/index.js.map +6 -4
  80. package/dist/webgl/line.d.ts +4 -0
  81. package/dist/webgl/line.d.ts.map +1 -0
  82. package/dist/webgl/points.d.ts +4 -0
  83. package/dist/webgl/points.d.ts.map +1 -0
  84. package/dist/webgpu/index.d.ts.map +1 -1
  85. package/dist/webgpu/index.js +206 -26
  86. package/dist/webgpu/index.js.map +6 -4
  87. package/dist/webgpu/line.d.ts +4 -0
  88. package/dist/webgpu/line.d.ts.map +1 -0
  89. package/dist/webgpu/points.d.ts +4 -0
  90. package/dist/webgpu/points.d.ts.map +1 -0
  91. package/package.json +2 -1
  92. package/src/kernel/behaviours.ts +5 -0
  93. package/src/kernel/bodySources.ts +1 -1
  94. package/src/kernel/boxSelect.ts +73 -0
  95. package/src/kernel/build.ts +430 -0
  96. package/src/kernel/cameraMotion.ts +3 -0
  97. package/src/kernel/cameraShake.ts +87 -0
  98. package/src/kernel/describeScene.ts +224 -0
  99. package/src/kernel/description.ts +266 -1
  100. package/src/kernel/diff.ts +46 -1
  101. package/src/kernel/equality.ts +148 -0
  102. package/src/kernel/gizmo.ts +478 -0
  103. package/src/kernel/history.ts +118 -0
  104. package/src/kernel/index.ts +102 -0
  105. package/src/kernel/inspect.ts +214 -0
  106. package/src/kernel/lineGeometry.ts +75 -0
  107. package/src/kernel/lockstep.ts +237 -0
  108. package/src/kernel/loop.ts +5 -0
  109. package/src/kernel/materials.ts +3 -0
  110. package/src/kernel/pivot.ts +418 -0
  111. package/src/kernel/pointBuffers.ts +115 -0
  112. package/src/kernel/pointer.ts +63 -12
  113. package/src/kernel/renderKit.ts +23 -1
  114. package/src/kernel/renderer.ts +6 -0
  115. package/src/kernel/resources.ts +69 -0
  116. package/src/kernel/sceneChanges.ts +265 -0
  117. package/src/kernel/sceneGraph.ts +461 -9
  118. package/src/kernel/seeded.ts +18 -0
  119. package/src/kernel/shots.ts +167 -0
  120. package/src/kernel/tape.ts +124 -0
  121. package/src/kernel/trail.ts +170 -0
  122. package/src/kernel/viewportGizmo.ts +194 -0
  123. package/src/runtime/Inspector.ts +43 -0
  124. package/src/runtime/SceneFile.ts +46 -0
  125. package/src/runtime/SceneSchema.ts +305 -4
  126. package/src/runtime/errors.ts +6 -0
  127. package/src/runtime/index.ts +3 -1
  128. package/src/webgl/index.ts +4 -0
  129. package/src/webgl/line.ts +66 -0
  130. package/src/webgl/points.ts +205 -0
  131. package/src/webgpu/index.ts +4 -0
  132. package/src/webgpu/line.ts +67 -0
  133. package/src/webgpu/points.ts +193 -0
  134. package/dist/index-01kwfekm.js.map +0 -40
@@ -1,3 +1,60 @@
1
+ import {
2
+ seededRandom,
3
+ edgePoints,
4
+ edgeLine,
5
+ animatedLook
6
+ } from "./index-ttwy0znv.js";
7
+ var __defProp = Object.defineProperty;
8
+ var __returnValue = (v) => v;
9
+ function __exportSetter(name, newValue) {
10
+ this[name] = __returnValue.bind(null, newValue);
11
+ }
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, {
15
+ get: all[name],
16
+ enumerable: true,
17
+ configurable: true,
18
+ set: __exportSetter.bind(all, name)
19
+ });
20
+ };
21
+
22
+ // src/kernel/history.ts
23
+ var exports_history = {};
24
+ __export(exports_history, {
25
+ branches: () => branches,
26
+ canRedo: () => canRedo,
27
+ canUndo: () => canUndo,
28
+ chooseBranch: () => chooseBranch,
29
+ depth: () => depth,
30
+ jumpTo: () => jumpTo,
31
+ make: () => make,
32
+ pathTo: () => pathTo,
33
+ present: () => present,
34
+ presentEntry: () => presentEntry,
35
+ record: () => record,
36
+ redo: () => redo,
37
+ undo: () => undo
38
+ });
39
+
40
+ // src/kernel/lockstep.ts
41
+ var exports_lockstep = {};
42
+ __export(exports_lockstep, {
43
+ admit: () => admit,
44
+ advance: () => advance,
45
+ join: () => join,
46
+ leaderAt: () => leaderAt,
47
+ leave: () => leave,
48
+ make: () => make2,
49
+ membersAt: () => membersAt,
50
+ receive: () => receive,
51
+ remove: () => remove,
52
+ send: () => send,
53
+ submit: () => submit,
54
+ waitingOn: () => waitingOn,
55
+ welcomeDue: () => welcomeDue
56
+ });
57
+
1
58
  // src/kernel/description.ts
2
59
  var handJoints2 = [
3
60
  "wrist",
@@ -67,6 +124,10 @@ var writeRotation2 = (target, rotation, elapsedSeconds) => {
67
124
  target.set(rotation.euler[0], rotation.euler[1], rotation.euler[2]);
68
125
  return;
69
126
  }
127
+ if (rotation._tag === "Billboard") {
128
+ target.set(0, 0, 0);
129
+ return;
130
+ }
70
131
  const angle = spinAngle2(rotation, elapsedSeconds);
71
132
  switch (rotation.axis) {
72
133
  case "x":
@@ -121,6 +182,8 @@ var applyShaded = (material, description, mapChanged = false) => {
121
182
  };
122
183
  var applyBasic = (material, description, textures) => {
123
184
  material.color.setHex(description.color);
185
+ material.depthTest = description.depthTest;
186
+ material.depthWrite = description.depthTest;
124
187
  const mapChanged = applyMap(material, description.map, textures);
125
188
  if (applySurface(material, description) || mapChanged)
126
189
  material.needsUpdate = true;
@@ -251,6 +314,13 @@ import {
251
314
 
252
315
  // src/kernel/equality.ts
253
316
  var vec3Equals2 = (a, b) => a === b || Object.is(a[0], b[0]) && Object.is(a[1], b[1]) && Object.is(a[2], b[2]);
317
+ var detailEquals = (a, b) => {
318
+ if (a === b)
319
+ return true;
320
+ if (a === null || b === null)
321
+ return false;
322
+ return Object.is(a.hysteresis, b.hysteresis) && a.distances.length === b.distances.length && a.distances.every((distance, index) => Object.is(distance, b.distances[index]));
323
+ };
254
324
  var rotationEquals2 = (a, b) => {
255
325
  if (a === b)
256
326
  return true;
@@ -259,6 +329,9 @@ var rotationEquals2 = (a, b) => {
259
329
  if (a._tag === "Spin" && b._tag === "Spin") {
260
330
  return a.axis === b.axis && Object.is(a.radiansPerSecond, b.radiansPerSecond) && Object.is(a.phase, b.phase);
261
331
  }
332
+ if (a._tag === "Billboard" && b._tag === "Billboard") {
333
+ return a.lockX === b.lockX && a.lockY === b.lockY && a.lockZ === b.lockZ;
334
+ }
262
335
  return false;
263
336
  };
264
337
  var shapeEquals2 = (a, b) => {
@@ -283,6 +356,10 @@ var shapeEquals2 = (a, b) => {
283
356
  return b._tag === "Ring" && Object.is(a.innerRadius, b.innerRadius) && Object.is(a.outerRadius, b.outerRadius) && a.thetaSegments === b.thetaSegments;
284
357
  case "Circle":
285
358
  return b._tag === "Circle" && Object.is(a.radius, b.radius) && a.segments === b.segments;
359
+ case "RoundedBox":
360
+ return b._tag === "RoundedBox" && Object.is(a.width, b.width) && Object.is(a.height, b.height) && Object.is(a.depth, b.depth) && Object.is(a.radius, b.radius) && a.smoothness === b.smoothness && a.bevelSegments === b.bevelSegments && a.steps === b.steps && Object.is(a.creaseAngle, b.creaseAngle);
361
+ case "Backdrop":
362
+ return b._tag === "Backdrop" && Object.is(a.floor, b.floor) && a.segments === b.segments;
286
363
  case "Text":
287
364
  return b._tag === "Text" && a.text === b.text && a.font === b.font && Object.is(a.size, b.size) && Object.is(a.depth, b.depth) && a.curveSegments === b.curveSegments && a.center === b.center && Object.is(a.letterSpacing, b.letterSpacing) && Object.is(a.lineHeight, b.lineHeight) && a.align === b.align && bevelEquals(a.bevel, b.bevel);
288
365
  }
@@ -340,11 +417,12 @@ var materialRefEquals2 = (a, b) => {
340
417
  }
341
418
  return sameFlatRecord(a, b);
342
419
  };
420
+ var cameraShakeEquals = (a, b) => a === b || a !== null && b !== null && Object.is(a.intensity, b.intensity) && a.decay === b.decay && Object.is(a.decayRate, b.decayRate) && Object.is(a.maxYaw, b.maxYaw) && Object.is(a.maxPitch, b.maxPitch) && Object.is(a.maxRoll, b.maxRoll) && Object.is(a.yawFrequency, b.yawFrequency) && Object.is(a.pitchFrequency, b.pitchFrequency) && Object.is(a.rollFrequency, b.rollFrequency) && Object.is(a.trigger, b.trigger);
343
421
  var cameraEquals2 = (a, b) => {
344
422
  if (a === b)
345
423
  return true;
346
424
  const sameLens = a._tag === "Perspective" && b._tag === "Perspective" && Object.is(a.fov, b.fov) || a._tag === "Orthographic" && b._tag === "Orthographic" && Object.is(a.zoom, b.zoom);
347
- return sameLens && Object.is(a.near, b.near) && Object.is(a.far, b.far) && Object.is(a.damping, b.damping) && Object.is(a.autoRotate, b.autoRotate) && vec3Equals2(a.position, b.position) && vec3Equals2(a.lookAt, b.lookAt);
425
+ return sameLens && Object.is(a.near, b.near) && Object.is(a.far, b.far) && Object.is(a.damping, b.damping) && Object.is(a.autoRotate, b.autoRotate) && cameraShakeEquals(a.shake, b.shake) && vec3Equals2(a.position, b.position) && vec3Equals2(a.lookAt, b.lookAt);
348
426
  };
349
427
  var renderSettingsEquals2 = (a, b) => a === b || a.frames === b.frames && Object.is(a.resolution, b.resolution) && a.shadows === b.shadows && a.toneMapping === b.toneMapping && Object.is(a.exposure, b.exposure) && a.colorSpace === b.colorSpace && effectsEqual2(a.effects, b.effects);
350
428
  var effectsEqual2 = (a, b) => {
@@ -470,6 +548,21 @@ var jointsEqual = (a, b) => {
470
548
  var labelTypeEquals = (a, b) => a.text === b.text && a.font === b.font && Object.is(a.fontSize, b.fontSize) && a.color === b.color && Object.is(a.fillOpacity, b.fillOpacity) && Object.is(a.anchorX, b.anchorX) && Object.is(a.anchorY, b.anchorY) && Object.is(a.maxWidth, b.maxWidth) && Object.is(a.lineHeight, b.lineHeight) && Object.is(a.letterSpacing, b.letterSpacing) && a.textAlign === b.textAlign && Object.is(a.outlineWidth, b.outlineWidth) && a.outlineColor === b.outlineColor && Object.is(a.outlineOpacity, b.outlineOpacity) && Object.is(a.outlineBlur, b.outlineBlur) && Object.is(a.curveRadius, b.curveRadius) && a.colorRanges.length === b.colorRanges.length && a.colorRanges.every((range, i) => colorRangeEquals(range, b.colorRanges[i]));
471
549
  var colorRangeEquals = (a, b) => b !== undefined && a.start === b.start && a.color === b.color;
472
550
  var labelMaterialEquals = (a, b) => a === b || a !== null && b !== null && materialRefEquals2(a, b);
551
+ var pointLookEquals = (a, b) => {
552
+ if (a === b)
553
+ return true;
554
+ switch (a._tag) {
555
+ case "Dots":
556
+ return b._tag === "Dots" && a.positions.length === b.positions.length && a.positions.every((point, index) => vec3Equals2(point, b.positions[index] ?? point)) && numbersEqual(a.colors, b.colors) && numbersEqual(a.sizes, b.sizes) && Object.is(a.color, b.color) && Object.is(a.size, b.size) && a.sizeAttenuation === b.sizeAttenuation && a.round === b.round && Object.is(a.opacity, b.opacity) && a.transparent === b.transparent;
557
+ case "Sparkles":
558
+ return b._tag === "Sparkles" && a.count === b.count && Object.is(a.speed, b.speed) && Object.is(a.opacity, b.opacity) && vec3Equals2(a.scale, b.scale) && Object.is(a.size, b.size) && Object.is(a.color, b.color) && vec3Equals2(a.noise, b.noise) && Object.is(a.seed, b.seed);
559
+ case "Stars":
560
+ return b._tag === "Stars" && Object.is(a.radius, b.radius) && Object.is(a.depth, b.depth) && a.count === b.count && Object.is(a.factor, b.factor) && Object.is(a.saturation, b.saturation) && a.fade === b.fade && Object.is(a.speed, b.speed) && Object.is(a.seed, b.seed);
561
+ }
562
+ };
563
+ var trailEquals = (a, b) => a === b || a !== null && b !== null && Object.is(a.width, b.width) && Object.is(a.length, b.length) && Object.is(a.decay, b.decay) && a.local === b.local && Object.is(a.stride, b.stride) && Object.is(a.interval, b.interval) && Object.is(a.color, b.color) && a.taper === b.taper && a.fade === b.fade;
564
+ var edgesEquals = (a, b) => a === b || a !== null && b !== null && Object.is(a.threshold, b.threshold) && Object.is(a.color, b.color) && Object.is(a.width, b.width) && a.worldUnits === b.worldUnits && a.dashed === b.dashed && Object.is(a.dashSize, b.dashSize) && Object.is(a.gapSize, b.gapSize) && Object.is(a.opacity, b.opacity) && a.transparent === b.transparent;
565
+ var lineLookEquals = (a, b) => a.segments === b.segments && Object.is(a.color, b.color) && Object.is(a.width, b.width) && a.worldUnits === b.worldUnits && a.dashed === b.dashed && Object.is(a.dashSize, b.dashSize) && Object.is(a.gapSize, b.gapSize) && Object.is(a.dashScale, b.dashScale) && Object.is(a.dashOffset, b.dashOffset) && Object.is(a.opacity, b.opacity) && a.transparent === b.transparent && (a.points === b.points || a.points.length === b.points.length && a.points.every((point, index) => vec3Equals2(point, b.points[index] ?? point))) && (a.vertexColors === b.vertexColors || a.vertexColors !== null && b.vertexColors !== null && a.vertexColors.length === b.vertexColors.length && a.vertexColors.every((color, index) => Object.is(color, b.vertexColors?.[index])));
473
566
  var shaderGridLookEquals = (a, b) => Object.is(a.size[0], b.size[0]) && Object.is(a.size[1], b.size[1]) && Object.is(a.cellSize, b.cellSize) && Object.is(a.cellThickness, b.cellThickness) && a.cellColor === b.cellColor && Object.is(a.sectionSize, b.sectionSize) && Object.is(a.sectionThickness, b.sectionThickness) && a.sectionColor === b.sectionColor && a.infinite === b.infinite && a.followCamera === b.followCamera && Object.is(a.fadeDistance, b.fadeDistance) && Object.is(a.fadeStrength, b.fadeStrength) && Object.is(a.fadeFrom, b.fadeFrom) && a.side === b.side;
474
567
  var physicsEquals2 = (a, b) => a === b || a !== null && b !== null && vec3Equals2(a.gravity, b.gravity) && a.paused === b.paused && Object.is(a.timeStep, b.timeStep) && a.interpolate === b.interpolate && a.debug === b.debug && jointsEqual(a.joints, b.joints);
475
568
  var xrAnchorEquals = (a, b) => b !== undefined && a.id === b.id && vec3Equals2(a.position, b.position) && vec3Equals2(a.rotation, b.rotation);
@@ -639,6 +732,7 @@ var applyTween2 = (object, tween, elapsedSeconds) => {
639
732
  return false;
640
733
  };
641
734
  // src/kernel/build.ts
735
+ import { CatmullRomCurve3, Color as Color2, CubicBezierCurve3, QuadraticBezierCurve3, Vector3 as Vector33 } from "three";
642
736
  var origin = [0, 0, 0];
643
737
  var unitScale = [1, 1, 1];
644
738
  var noRotation = { _tag: "Fixed", euler: origin };
@@ -651,6 +745,12 @@ var spin2 = (options) => ({
651
745
  radiansPerSecond: options.radiansPerSecond,
652
746
  phase: options.phase ?? 0
653
747
  });
748
+ var billboard2 = (options = {}) => ({
749
+ _tag: "Billboard",
750
+ lockX: options.lockX ?? false,
751
+ lockY: options.lockY ?? false,
752
+ lockZ: options.lockZ ?? false
753
+ });
654
754
  var box2 = (size = {}) => ({
655
755
  _tag: "Box",
656
756
  width: size.width ?? 1,
@@ -691,6 +791,22 @@ var capsule2 = (options = {}) => ({
691
791
  capSegments: options.capSegments ?? 4,
692
792
  radialSegments: options.radialSegments ?? 8
693
793
  });
794
+ var roundedBox2 = (options = {}) => ({
795
+ _tag: "RoundedBox",
796
+ width: options.width ?? 1,
797
+ height: options.height ?? 1,
798
+ depth: options.depth ?? 1,
799
+ radius: options.radius ?? 0.05,
800
+ smoothness: options.smoothness ?? 4,
801
+ bevelSegments: options.bevelSegments ?? 4,
802
+ steps: options.steps ?? 1,
803
+ creaseAngle: options.creaseAngle ?? 0.4
804
+ });
805
+ var backdrop2 = (options = {}) => ({
806
+ _tag: "Backdrop",
807
+ floor: options.floor ?? 0.25,
808
+ segments: options.segments ?? 20
809
+ });
694
810
  var ring2 = (options = {}) => ({
695
811
  _tag: "Ring",
696
812
  innerRadius: options.innerRadius ?? 0.5,
@@ -733,7 +849,8 @@ var basic2 = (options = {}) => ({
733
849
  opacity: options.opacity ?? 1,
734
850
  transparent: options.transparent ?? false,
735
851
  side: options.side ?? "front",
736
- wireframe: options.wireframe ?? false
852
+ wireframe: options.wireframe ?? false,
853
+ depthTest: options.depthTest ?? true
737
854
  });
738
855
  var lambert2 = (options = {}) => ({
739
856
  _tag: "Lambert",
@@ -846,8 +963,106 @@ var group2 = (options) => ({
846
963
  interactive: options.interactive ?? false,
847
964
  children: options.children ?? [],
848
965
  body: options.body ?? null,
849
- follow: options.follow ?? null
966
+ follow: options.follow ?? null,
967
+ detail: options.detail ?? null,
968
+ trail: options.trail ?? null
969
+ });
970
+ var detailed2 = (options) => ({ distances: options.distances, hysteresis: options.hysteresis ?? 0 });
971
+ var line2 = (options) => ({
972
+ _tag: "Line",
973
+ key: options.key,
974
+ position: options.position ?? origin,
975
+ rotation: options.rotation ?? noRotation,
976
+ scale: options.scale ?? unitScale,
977
+ transition: options.transition ?? instantTransition,
978
+ behaviour: options.behaviour ?? null,
979
+ interactive: options.interactive ?? false,
980
+ points: options.points,
981
+ segments: options.segments ?? false,
982
+ color: options.color ?? 16777215,
983
+ vertexColors: options.vertexColors ?? null,
984
+ width: options.width ?? 1,
985
+ worldUnits: options.worldUnits ?? false,
986
+ dashed: options.dashed ?? false,
987
+ dashSize: options.dashSize ?? 1,
988
+ gapSize: options.gapSize ?? 1,
989
+ dashScale: options.dashScale ?? 1,
990
+ dashOffset: options.dashOffset ?? 0,
991
+ opacity: options.opacity ?? 1,
992
+ transparent: options.transparent ?? false
993
+ });
994
+ var asVector = (point) => new Vector33(point[0], point[1], point[2]);
995
+ var asVec3 = (point) => [point.x, point.y, point.z];
996
+ var placed = (options, look) => ({
997
+ _tag: "Points",
998
+ key: options.key,
999
+ position: options.position ?? origin,
1000
+ rotation: options.rotation ?? noRotation,
1001
+ scale: options.scale ?? unitScale,
1002
+ transition: options.transition ?? instantTransition,
1003
+ behaviour: options.behaviour ?? null,
1004
+ look
1005
+ });
1006
+ var points2 = (options) => placed(options, {
1007
+ _tag: "Dots",
1008
+ positions: options.positions,
1009
+ colors: options.colors ?? null,
1010
+ sizes: options.sizes ?? null,
1011
+ color: options.color ?? 16777215,
1012
+ size: options.size ?? 1,
1013
+ sizeAttenuation: options.sizeAttenuation ?? true,
1014
+ round: options.round ?? true,
1015
+ opacity: options.opacity ?? 1,
1016
+ transparent: options.transparent ?? false
1017
+ });
1018
+ var sparkles2 = (options) => {
1019
+ const spread = options.spread ?? 1;
1020
+ const noise = options.noise ?? 1;
1021
+ return placed(options, {
1022
+ _tag: "Sparkles",
1023
+ count: options.count ?? 100,
1024
+ speed: options.speed ?? 1,
1025
+ opacity: options.opacity ?? 1,
1026
+ scale: typeof spread === "number" ? [spread, spread, spread] : spread,
1027
+ size: options.size ?? null,
1028
+ color: options.color ?? 16777215,
1029
+ noise: typeof noise === "number" ? [noise, noise, noise] : noise,
1030
+ seed: options.seed ?? 1
1031
+ });
1032
+ };
1033
+ var stars2 = (options) => placed(options, {
1034
+ _tag: "Stars",
1035
+ radius: options.radius ?? 100,
1036
+ depth: options.depth ?? 50,
1037
+ count: options.count ?? 5000,
1038
+ factor: options.factor ?? 4,
1039
+ saturation: options.saturation ?? 0,
1040
+ fade: options.fade ?? false,
1041
+ speed: options.speed ?? 1,
1042
+ seed: options.seed ?? 1
850
1043
  });
1044
+ var catmullRomPoints2 = (points, options = {}) => new CatmullRomCurve3(points.map(asVector), options.closed ?? false, options.curveType ?? "centripetal", options.tension ?? 0.5).getPoints(options.segments ?? 20).map(asVec3);
1045
+ var catmullRomPointAt2 = (points, t, options = {}) => asVec3(new CatmullRomCurve3(points.map(asVector), options.closed ?? false, options.curveType ?? "centripetal", options.tension ?? 0.5).getPoint(Math.min(1, Math.max(0, t))));
1046
+ var catmullRomColors2 = (colors, options = {}) => {
1047
+ const segments = options.segments ?? 20;
1048
+ if (colors.length < 2 || colors.length === segments + 1)
1049
+ return colors;
1050
+ const stops = colors.map((color) => new Color2(color));
1051
+ const first = stops[0];
1052
+ if (options.closed === true && first !== undefined)
1053
+ stops.push(first.clone());
1054
+ const divisions = segments / (stops.length - 1);
1055
+ const at = (index) => (stops[Math.floor(index / divisions)] ?? new Color2).clone().lerp(stops[Math.floor(index / divisions) + 1] ?? new Color2, index % divisions / divisions).getHex();
1056
+ const blended = Array.from({ length: segments - 1 }, (_, step) => at(step + 1));
1057
+ return [colors[0] ?? 0, ...blended, stops.at(-1)?.getHex() ?? 0];
1058
+ };
1059
+ var cubicBezierPoints2 = (options) => new CubicBezierCurve3(asVector(options.start), asVector(options.midA), asVector(options.midB), asVector(options.end)).getPoints(options.segments ?? 20).map(asVec3);
1060
+ var quadraticBezierPoints2 = (options) => {
1061
+ const [, startY] = options.start;
1062
+ const [endX, , endZ] = options.end;
1063
+ const mid = options.mid ?? [endX, startY, endZ];
1064
+ return new QuadraticBezierCurve3(asVector(options.start), asVector(mid), asVector(options.end)).getPoints(options.segments ?? 20).map(asVec3);
1065
+ };
851
1066
  var headSpace2 = () => ({ _tag: "Head" });
852
1067
  var jointSpace2 = (hand, joint) => ({
853
1068
  _tag: "Joint",
@@ -882,7 +1097,31 @@ var mesh2 = (options) => ({
882
1097
  interactive: options.interactive ?? false,
883
1098
  castShadow: options.castShadow ?? false,
884
1099
  receiveShadow: options.receiveShadow ?? false,
885
- body: options.body ?? null
1100
+ body: options.body ?? null,
1101
+ edges: options.edges ?? null,
1102
+ trail: options.trail ?? null
1103
+ });
1104
+ var trail2 = (options = {}) => ({
1105
+ width: options.width ?? 0.2,
1106
+ length: options.length ?? 1,
1107
+ decay: options.decay ?? 1,
1108
+ local: options.local ?? false,
1109
+ stride: options.stride ?? 0,
1110
+ interval: options.interval ?? 1,
1111
+ color: options.color ?? 16738740,
1112
+ taper: options.taper ?? "none",
1113
+ fade: options.fade ?? false
1114
+ });
1115
+ var edges2 = (options = {}) => ({
1116
+ threshold: options.threshold ?? 15,
1117
+ color: options.color ?? 16777215,
1118
+ width: options.width ?? 1,
1119
+ worldUnits: options.worldUnits ?? false,
1120
+ dashed: options.dashed ?? false,
1121
+ dashSize: options.dashSize ?? 1,
1122
+ gapSize: options.gapSize ?? 1,
1123
+ opacity: options.opacity ?? 1,
1124
+ transparent: options.transparent ?? false
886
1125
  });
887
1126
  var body2 = (options = {}) => ({
888
1127
  type: options.type ?? "dynamic",
@@ -1032,7 +1271,9 @@ var borrowed2 = (options) => ({
1032
1271
  transition: options.transition ?? instantTransition,
1033
1272
  behaviour: options.behaviour ?? null,
1034
1273
  interactive: options.interactive ?? false,
1035
- body: options.body ?? null
1274
+ body: options.body ?? null,
1275
+ castShadow: options.castShadow ?? false,
1276
+ receiveShadow: options.receiveShadow ?? false
1036
1277
  });
1037
1278
  var noColorRanges = [];
1038
1279
  var label2 = (options) => ({
@@ -1124,7 +1365,8 @@ var perspectiveCamera2 = (options = {}) => ({
1124
1365
  position: options.position ?? [0, 0, 5],
1125
1366
  lookAt: options.lookAt ?? origin,
1126
1367
  damping: options.damping ?? 0,
1127
- autoRotate: options.autoRotate ?? 0
1368
+ autoRotate: options.autoRotate ?? 0,
1369
+ shake: options.shake ?? null
1128
1370
  });
1129
1371
  var orthographicCamera2 = (options = {}) => ({
1130
1372
  _tag: "Orthographic",
@@ -1134,7 +1376,20 @@ var orthographicCamera2 = (options = {}) => ({
1134
1376
  position: options.position ?? [0, 0, 5],
1135
1377
  lookAt: options.lookAt ?? origin,
1136
1378
  damping: options.damping ?? 0,
1137
- autoRotate: options.autoRotate ?? 0
1379
+ autoRotate: options.autoRotate ?? 0,
1380
+ shake: options.shake ?? null
1381
+ });
1382
+ var cameraShake2 = (options = {}) => ({
1383
+ intensity: options.intensity ?? 1,
1384
+ decay: options.decay ?? false,
1385
+ decayRate: options.decayRate ?? 0.65,
1386
+ maxYaw: options.maxYaw ?? 0.1,
1387
+ maxPitch: options.maxPitch ?? 0.1,
1388
+ maxRoll: options.maxRoll ?? 0.1,
1389
+ yawFrequency: options.yawFrequency ?? 0.1,
1390
+ pitchFrequency: options.pitchFrequency ?? 0.1,
1391
+ rollFrequency: options.rollFrequency ?? 0.1,
1392
+ trigger: options.trigger ?? 0
1138
1393
  });
1139
1394
  var noEffects = [];
1140
1395
  var bloom2 = (options = {}) => ({
@@ -1232,11 +1487,17 @@ var overlay2 = (options) => ({
1232
1487
  zIndexRange: options.zIndexRange ?? defaultZIndexRange,
1233
1488
  view: options.view ?? null
1234
1489
  });
1490
+ var hud2 = (options) => ({
1491
+ alignment: options.alignment ?? "bottom-right",
1492
+ margin: options.margin ?? [80, 80],
1493
+ children: options.children ?? []
1494
+ });
1235
1495
  var scene2 = (options) => ({
1236
1496
  camera: options.camera ?? perspectiveCamera2(),
1237
1497
  gestures: options.gestures ?? "page",
1238
1498
  views: options.views ?? noViews,
1239
1499
  renderTextures: options.renderTextures ?? noRenderTextures,
1500
+ hud: options.hud ?? null,
1240
1501
  overlays: options.overlays ?? noOverlays,
1241
1502
  environment: options.environment ?? null,
1242
1503
  sky: options.sky ?? null,
@@ -1419,6 +1680,10 @@ var changedFields2 = (prev, next) => {
1419
1680
  fields.push("body");
1420
1681
  if (!xrSpaceEquals(prev.follow, next.follow))
1421
1682
  fields.push("follow");
1683
+ if (!detailEquals(prev.detail, next.detail))
1684
+ fields.push("detail");
1685
+ if (!trailEquals(prev.trail, next.trail))
1686
+ fields.push("trail");
1422
1687
  return fields;
1423
1688
  }
1424
1689
  case "Mesh": {
@@ -1446,6 +1711,10 @@ var changedFields2 = (prev, next) => {
1446
1711
  fields.push("receiveShadow");
1447
1712
  if (!bodyEquals2(prev.body, next.body))
1448
1713
  fields.push("body");
1714
+ if (!edgesEquals(prev.edges, next.edges))
1715
+ fields.push("edges");
1716
+ if (!trailEquals(prev.trail, next.trail))
1717
+ fields.push("trail");
1449
1718
  return fields;
1450
1719
  }
1451
1720
  case "Instances": {
@@ -1498,6 +1767,10 @@ var changedFields2 = (prev, next) => {
1498
1767
  fields.push("interactive");
1499
1768
  if (!bodyEquals2(prev.body, next.body))
1500
1769
  fields.push("body");
1770
+ if (prev.castShadow !== next.castShadow)
1771
+ fields.push("castShadow");
1772
+ if (prev.receiveShadow !== next.receiveShadow)
1773
+ fields.push("receiveShadow");
1501
1774
  return fields;
1502
1775
  }
1503
1776
  case "Label": {
@@ -1597,6 +1870,42 @@ var changedFields2 = (prev, next) => {
1597
1870
  fields.push("shadowBias");
1598
1871
  return fields;
1599
1872
  }
1873
+ case "Points": {
1874
+ if (prev._tag !== "Points")
1875
+ return;
1876
+ if (!behaviourEquals2(prev.behaviour, next.behaviour))
1877
+ fields.push("behaviour");
1878
+ if (!vec3Equals2(prev.position, next.position))
1879
+ fields.push("position");
1880
+ if (!rotationEquals2(prev.rotation, next.rotation))
1881
+ fields.push("rotation");
1882
+ if (!vec3Equals2(prev.scale, next.scale))
1883
+ fields.push("scale");
1884
+ if (!transitionEquals2(prev.transition, next.transition))
1885
+ fields.push("transition");
1886
+ if (!pointLookEquals(prev.look, next.look))
1887
+ fields.push("look");
1888
+ return fields;
1889
+ }
1890
+ case "Line": {
1891
+ if (prev._tag !== "Line")
1892
+ return;
1893
+ if (!behaviourEquals2(prev.behaviour, next.behaviour))
1894
+ fields.push("behaviour");
1895
+ if (!vec3Equals2(prev.position, next.position))
1896
+ fields.push("position");
1897
+ if (!rotationEquals2(prev.rotation, next.rotation))
1898
+ fields.push("rotation");
1899
+ if (!vec3Equals2(prev.scale, next.scale))
1900
+ fields.push("scale");
1901
+ if (!transitionEquals2(prev.transition, next.transition))
1902
+ fields.push("transition");
1903
+ if (prev.interactive !== next.interactive)
1904
+ fields.push("interactive");
1905
+ if (!lineLookEquals(prev, next))
1906
+ fields.push("line");
1907
+ return fields;
1908
+ }
1600
1909
  case "ShaderGrid": {
1601
1910
  if (prev._tag !== "ShaderGrid")
1602
1911
  return;
@@ -1744,14 +2053,18 @@ import {
1744
2053
  CircleGeometry,
1745
2054
  ConeGeometry,
1746
2055
  CylinderGeometry,
2056
+ Euler as Euler2,
1747
2057
  ExtrudeGeometry,
1748
2058
  Material,
1749
2059
  PlaneGeometry,
2060
+ Quaternion as Quaternion2,
1750
2061
  RingGeometry,
2062
+ Shape,
1751
2063
  ShapeGeometry as ShapeGeometry3,
1752
2064
  SphereGeometry,
1753
2065
  TorusGeometry
1754
2066
  } from "three";
2067
+ import { toCreasedNormals } from "three/addons/utils/BufferGeometryUtils.js";
1755
2068
 
1756
2069
  // src/kernel/textLayout.ts
1757
2070
  import { Vector2 } from "three";
@@ -1846,6 +2159,45 @@ var buildText = (shape, font) => {
1846
2159
  geometry.center();
1847
2160
  return geometry;
1848
2161
  };
2162
+ var roundedEpsilon = 0.00001;
2163
+ var buildRoundedBox = (shape) => {
2164
+ const { width, height, depth, radius } = shape;
2165
+ const outline = new Shape;
2166
+ const inset = radius - roundedEpsilon;
2167
+ const e = roundedEpsilon;
2168
+ outline.absarc(e, e, e, -Math.PI / 2, -Math.PI, true);
2169
+ outline.absarc(e, height - inset * 2, e, Math.PI, Math.PI / 2, true);
2170
+ outline.absarc(width - inset * 2, height - inset * 2, e, Math.PI / 2, 0, true);
2171
+ outline.absarc(width - inset * 2, e, e, 0, -Math.PI / 2, true);
2172
+ const geometry = new ExtrudeGeometry(outline, {
2173
+ depth: depth - radius * 2,
2174
+ bevelEnabled: true,
2175
+ bevelSegments: shape.bevelSegments * 2,
2176
+ steps: shape.steps,
2177
+ bevelSize: radius - roundedEpsilon,
2178
+ bevelThickness: radius,
2179
+ curveSegments: shape.smoothness
2180
+ });
2181
+ geometry.center();
2182
+ return toCreasedNormals(geometry, shape.creaseAngle);
2183
+ };
2184
+ var backdropTurn = new Quaternion2().setFromEuler(new Euler2(-Math.PI / 2, 0, Math.PI / 2));
2185
+ var easeInExpo = (x) => x === 0 ? 0 : 2 ** (10 * x - 10);
2186
+ var buildBackdrop = (shape) => {
2187
+ const { segments, floor } = shape;
2188
+ const geometry = new PlaneGeometry(1, 1, segments, segments);
2189
+ const position = geometry.getAttribute("position");
2190
+ const offset = 0.5;
2191
+ let vertex = 0;
2192
+ for (let x = 0;x < segments + 1; x++) {
2193
+ for (let y = 0;y < segments + 1; y++) {
2194
+ position.setXYZ(vertex++, x / segments - offset + (x === 0 ? -floor : 0), y / segments - offset, easeInExpo(x / segments));
2195
+ }
2196
+ }
2197
+ position.needsUpdate = true;
2198
+ geometry.computeVertexNormals();
2199
+ return geometry.applyQuaternion(backdropTurn);
2200
+ };
1849
2201
  var buildShape = (shape, fontOf) => {
1850
2202
  switch (shape._tag) {
1851
2203
  case "Text":
@@ -1868,6 +2220,10 @@ var buildShape = (shape, fontOf) => {
1868
2220
  return new RingGeometry(shape.innerRadius, shape.outerRadius, shape.thetaSegments);
1869
2221
  case "Circle":
1870
2222
  return new CircleGeometry(shape.radius, shape.segments);
2223
+ case "RoundedBox":
2224
+ return buildRoundedBox(shape);
2225
+ case "Backdrop":
2226
+ return buildBackdrop(shape);
1871
2227
  }
1872
2228
  };
1873
2229
  var notLent = new BufferGeometry;
@@ -2240,7 +2596,7 @@ import {
2240
2596
  Plane,
2241
2597
  Ray,
2242
2598
  Spherical,
2243
- Vector3 as Vector33
2599
+ Vector3 as Vector34
2244
2600
  } from "three";
2245
2601
  var defaultOrbit2 = {
2246
2602
  enableRotate: true,
@@ -2267,14 +2623,14 @@ var orbitOptions2 = (options = {}) => ({
2267
2623
  ...options
2268
2624
  });
2269
2625
  var twoPi = 2 * Math.PI;
2270
- var offset = new Vector33;
2626
+ var offset = new Vector34;
2271
2627
  var spherical = new Spherical;
2272
- var target = new Vector33;
2273
- var position2 = new Vector33;
2274
- var axis = new Vector33;
2275
- var panOffset = new Vector33;
2628
+ var target = new Vector34;
2629
+ var position2 = new Vector34;
2630
+ var axis = new Vector34;
2631
+ var panOffset = new Vector34;
2276
2632
  var basis = new Matrix42;
2277
- var worldUp = new Vector33(0, 1, 0);
2633
+ var worldUp = new Vector34(0, 1, 0);
2278
2634
  var toVec3 = (vector) => [vector.x, vector.y, vector.z];
2279
2635
  var clampAzimuth = (theta, options) => {
2280
2636
  let min = options.minAzimuthAngle;
@@ -2352,9 +2708,9 @@ var panCamera2 = (camera, deltaX, deltaY, area, options = defaultOrbit2) => {
2352
2708
  return place(camera, options, zoomOf(camera, options));
2353
2709
  };
2354
2710
  var tiltLimit = Math.cos(70 * MathUtils.DEG2RAD);
2355
- var pointer = new Vector33;
2356
- var before = new Vector33;
2357
- var forward = new Vector33;
2711
+ var pointer = new Vector34;
2712
+ var before = new Vector34;
2713
+ var forward = new Vector34;
2358
2714
  var groundRay = new Ray;
2359
2715
  var ground = new Plane;
2360
2716
  var hostCamera = (camera, cursor, zoom) => {
@@ -2456,7 +2812,7 @@ var orbitKey2 = (camera, key, modifiers, area, options = defaultOrbit2) => {
2456
2812
  return rotating ? turned(-turn, 0) : panCamera2(camera, -step, 0, area, options);
2457
2813
  }
2458
2814
  };
2459
- var corner = new Vector33;
2815
+ var corner = new Vector34;
2460
2816
  var view = new Matrix42;
2461
2817
  var fitDistance = (camera, box, area, margin) => {
2462
2818
  const largest = Math.max(box.max[0] - box.min[0], box.max[1] - box.min[1], box.max[2] - box.min[2]);
@@ -2509,12 +2865,12 @@ import {
2509
2865
  PerspectiveCamera as PerspectiveCamera2,
2510
2866
  Raycaster,
2511
2867
  Vector2 as Vector22,
2512
- Vector3 as Vector34
2868
+ Vector3 as Vector35
2513
2869
  } from "three";
2514
- var point = new Vector34;
2515
- var cameraPosition = new Vector34;
2516
- var direction = new Vector34;
2517
- var toPoint = new Vector34;
2870
+ var point = new Vector35;
2871
+ var cameraPosition = new Vector35;
2872
+ var direction = new Vector35;
2873
+ var toPoint = new Vector35;
2518
2874
  var ndc = new Vector22;
2519
2875
  var raycaster = new Raycaster;
2520
2876
  var lensFor = (graph, overlay) => {
@@ -2586,10 +2942,10 @@ var placeOverlays2 = (graph) => {
2586
2942
  };
2587
2943
  // src/kernel/physics.ts
2588
2944
  import {
2589
- Euler as Euler2,
2945
+ Euler as Euler3,
2590
2946
  Matrix4 as Matrix43,
2591
- Quaternion as Quaternion2,
2592
- Vector3 as Vector35
2947
+ Quaternion as Quaternion3,
2948
+ Vector3 as Vector36
2593
2949
  } from "three";
2594
2950
  var interactionBits2 = (groups) => {
2595
2951
  const mask = (list) => list.reduce((bits, group) => bits | 1 << group, 0);
@@ -2599,7 +2955,7 @@ var interactionBits2 = (groups) => {
2599
2955
  return (mask(groups.memberships) << 16 | filters) >>> 0;
2600
2956
  };
2601
2957
  var toVec32 = (vector) => [vector.x, vector.y, vector.z];
2602
- var size = new Vector35;
2958
+ var size = new Vector36;
2603
2959
  var scaledPositions = (geometry, scale) => {
2604
2960
  const positions = geometry.getAttribute("position");
2605
2961
  const points = new Float32Array(positions.count * 3);
@@ -2618,7 +2974,7 @@ var triangles = (geometry) => {
2618
2974
  };
2619
2975
  var speck = {
2620
2976
  shape: { _tag: "Ball", radius: 0.001 },
2621
- offset: new Vector35
2977
+ offset: new Vector36
2622
2978
  };
2623
2979
  var shapeFor = (geometry, collider, scale) => {
2624
2980
  if (geometry.getAttribute("position") === undefined)
@@ -2632,7 +2988,7 @@ var shapeFor = (geometry, collider, scale) => {
2632
2988
  box.getSize(size).multiply(scale).multiplyScalar(0.5);
2633
2989
  return {
2634
2990
  shape: { _tag: "Cuboid", halfExtents: toVec32(size) },
2635
- offset: box.getCenter(new Vector35).multiply(scale)
2991
+ offset: box.getCenter(new Vector36).multiply(scale)
2636
2992
  };
2637
2993
  }
2638
2994
  case "ball": {
@@ -2649,7 +3005,7 @@ var shapeFor = (geometry, collider, scale) => {
2649
3005
  case "hull":
2650
3006
  return {
2651
3007
  shape: { _tag: "Hull", points: scaledPositions(geometry, scale) },
2652
- offset: new Vector35
3008
+ offset: new Vector36
2653
3009
  };
2654
3010
  case "trimesh":
2655
3011
  return {
@@ -2658,7 +3014,7 @@ var shapeFor = (geometry, collider, scale) => {
2658
3014
  vertices: scaledPositions(geometry, scale),
2659
3015
  indices: triangles(geometry)
2660
3016
  },
2661
- offset: new Vector35
3017
+ offset: new Vector36
2662
3018
  };
2663
3019
  }
2664
3020
  };
@@ -2666,8 +3022,8 @@ var colliderFor2 = (geometry, collider, scale) => {
2666
3022
  const { shape, offset } = shapeFor(geometry, collider, scale);
2667
3023
  return { shape, translation: toVec32(offset), rotation: [0, 0, 0, 1] };
2668
3024
  };
2669
- var turn3 = new Quaternion2;
2670
- var turnEuler = new Euler2;
3025
+ var turn3 = new Quaternion3;
3026
+ var turnEuler = new Euler3;
2671
3027
  var largest = (a, b) => Math.max(Math.abs(a), Math.abs(b));
2672
3028
  var scaledShape = (shape, scale) => {
2673
3029
  switch (shape._tag) {
@@ -2703,12 +3059,12 @@ function describedCollider(collider, scale) {
2703
3059
  }
2704
3060
  var relative = new Matrix43;
2705
3061
  var bodyInverse = new Matrix43;
2706
- var where = new Vector35;
2707
- var turn = new Quaternion2;
2708
- var relativeScale = new Vector35;
2709
- var worldScale = new Vector35;
2710
- var worldPosition = new Vector35;
2711
- var worldTurn = new Quaternion2;
3062
+ var where = new Vector36;
3063
+ var turn = new Quaternion3;
3064
+ var relativeScale = new Vector36;
3065
+ var worldScale = new Vector36;
3066
+ var worldPosition = new Vector36;
3067
+ var worldTurn = new Quaternion3;
2712
3068
  var isMesh = (object) => ("isMesh" in object) && object.isMesh === true;
2713
3069
  function placedCollider2(child, collider, body) {
2714
3070
  child.matrixWorld.decompose(worldPosition, worldTurn, worldScale);
@@ -2963,7 +3319,7 @@ var stageBounds2 = (box) => {
2963
3319
  import { Box3, EquirectangularReflectionMapping, UVMapping } from "three";
2964
3320
 
2965
3321
  // src/kernel/pointer.ts
2966
- import { Raycaster as Raycaster2, Vector2 as Vector23, Vector3 as Vector36 } from "three";
3322
+ import { Raycaster as Raycaster2, Vector2 as Vector23, Vector3 as Vector37 } from "three";
2967
3323
  var noModifiers2 = { shift: false, control: false, meta: false, alt: false };
2968
3324
  var pointOnPlane2 = (ray, plane) => {
2969
3325
  const [nx, ny, nz] = plane.normal;
@@ -2995,10 +3351,16 @@ var pathOf = (graph, object) => {
2995
3351
  }
2996
3352
  return path;
2997
3353
  };
3354
+ var shown = (object) => {
3355
+ for (let at = object;at !== null; at = at.parent)
3356
+ if (!at.visible)
3357
+ return false;
3358
+ return true;
3359
+ };
2998
3360
  var createPicker2 = (graph) => {
2999
3361
  const raycaster = new Raycaster2;
3000
3362
  const ndc = new Vector23;
3001
- const normal = new Vector36;
3363
+ const normal = new Vector37;
3002
3364
  const aim = (x, y) => {
3003
3365
  graph.scene.updateMatrixWorld();
3004
3366
  const views = graph.views();
@@ -3026,24 +3388,26 @@ var createPicker2 = (graph) => {
3026
3388
  }
3027
3389
  return false;
3028
3390
  };
3029
- const rayOrigin = new Vector36;
3030
- const rayDirection = new Vector36;
3031
- const nearestHit = (view) => {
3032
- for (const intersection of raycaster.intersectObjects(graph.interactiveObjects(), true)) {
3033
- const owner = keyedOwner(graph, intersection.object);
3034
- const key = owner === undefined ? undefined : graph.keyOf(owner);
3391
+ const rayOrigin = new Vector37;
3392
+ const rayDirection = new Vector37;
3393
+ const nearestHit = (on, view) => {
3394
+ for (const intersection of raycaster.intersectObjects(on.interactiveObjects(), true)) {
3395
+ if (!shown(intersection.object))
3396
+ continue;
3397
+ const owner = keyedOwner(on, intersection.object);
3398
+ const key = owner === undefined ? undefined : on.keyOf(owner);
3035
3399
  if (owner !== undefined && key !== undefined) {
3036
3400
  normal.set(0, 0, 0);
3037
3401
  if (intersection.face) {
3038
3402
  normal.copy(intersection.face.normal).transformDirection(intersection.object.matrixWorld);
3039
3403
  }
3040
- const instance = intersection.instanceId === undefined ? undefined : graph.instanceKeyOf(intersection.object, intersection.instanceId);
3404
+ const instance = intersection.instanceId === undefined ? undefined : on.instanceKeyOf(intersection.object, intersection.instanceId);
3041
3405
  return {
3042
3406
  key,
3043
3407
  ...instance === undefined ? {} : { instance },
3044
3408
  ...partOf(owner, intersection.object),
3045
3409
  ...view === undefined ? {} : { view },
3046
- path: pathOf(graph, owner),
3410
+ path: pathOf(on, owner),
3047
3411
  point: toVec33(intersection.point),
3048
3412
  distance: intersection.distance,
3049
3413
  normal: toVec33(normal),
@@ -3054,6 +3418,16 @@ var createPicker2 = (graph) => {
3054
3418
  }
3055
3419
  return;
3056
3420
  };
3421
+ const hudHit = (x, y) => {
3422
+ const hud = graph.hud();
3423
+ if (hud === undefined || hud.graph.interactiveObjects().length === 0)
3424
+ return;
3425
+ hud.graph.scene.updateMatrixWorld();
3426
+ hud.graph.camera.updateMatrixWorld();
3427
+ ndc.set(x, y);
3428
+ raycaster.setFromCamera(ndc, hud.graph.camera);
3429
+ return nearestHit(hud.graph, undefined);
3430
+ };
3057
3431
  const currentRay = () => ({
3058
3432
  origin: toVec33(raycaster.ray.origin),
3059
3433
  direction: toVec33(raycaster.ray.direction)
@@ -3080,19 +3454,22 @@ var createPicker2 = (graph) => {
3080
3454
  holdCameras: graph.holdCameras,
3081
3455
  turned: graph.turned,
3082
3456
  pick: (x, y) => {
3457
+ const hud = hudHit(x, y);
3458
+ if (hud !== undefined)
3459
+ return hud;
3083
3460
  if (graph.interactiveObjects().length === 0)
3084
3461
  return;
3085
3462
  const view = aim(x, y);
3086
3463
  if (view === false)
3087
3464
  return;
3088
- return nearestHit(view);
3465
+ return nearestHit(graph, view);
3089
3466
  },
3090
3467
  pickRay: (ray) => {
3091
3468
  if (graph.interactiveObjects().length === 0)
3092
3469
  return;
3093
3470
  graph.scene.updateMatrixWorld();
3094
3471
  raycaster.set(rayOrigin.fromArray(ray.origin), rayDirection.fromArray(ray.direction).normalize());
3095
- return nearestHit(undefined);
3472
+ return nearestHit(graph, undefined);
3096
3473
  },
3097
3474
  viewport: graph.viewport
3098
3475
  };
@@ -3105,6 +3482,7 @@ var createPointerTracker2 = (picker) => {
3105
3482
  const pressedPointers = new Map;
3106
3483
  let primary;
3107
3484
  let gesturePress;
3485
+ let gestureMoved = false;
3108
3486
  let hovered;
3109
3487
  let press;
3110
3488
  let pressing = false;
@@ -3169,6 +3547,7 @@ var createPointerTracker2 = (picker) => {
3169
3547
  pressedPointers.clear();
3170
3548
  primary = id;
3171
3549
  pressedPointers.set(id, { x: event.x, y: event.y });
3550
+ gestureMoved = false;
3172
3551
  const region = picker.region(event.x, event.y);
3173
3552
  reportTurned(region, events);
3174
3553
  picker.holdCameras(true);
@@ -3184,6 +3563,7 @@ var createPointerTracker2 = (picker) => {
3184
3563
  if (from === undefined || gesturePress === undefined)
3185
3564
  return;
3186
3565
  pressedPointers.set(id, to);
3566
+ gestureMoved = true;
3187
3567
  const { view, width, height, x, y } = gesturePress;
3188
3568
  const region = { ...view === undefined ? {} : { view }, width, height, x, y };
3189
3569
  const moved = pixels(from, to);
@@ -3222,12 +3602,23 @@ var createPointerTracker2 = (picker) => {
3222
3602
  }
3223
3603
  });
3224
3604
  };
3225
- const endGestures = () => {
3605
+ const endGestures = (events) => {
3226
3606
  if (gesturePress !== undefined)
3227
3607
  picker.holdCameras(false);
3608
+ if (gesturePress !== undefined && gestureMoved) {
3609
+ const { button, modifiers, key, view } = gesturePress;
3610
+ events.push({
3611
+ _tag: "GestureEnd",
3612
+ button,
3613
+ modifiers,
3614
+ ...key === undefined ? {} : { key },
3615
+ ...view === undefined ? {} : { view }
3616
+ });
3617
+ }
3228
3618
  pressedPointers.clear();
3229
3619
  primary = undefined;
3230
3620
  gesturePress = undefined;
3621
+ gestureMoved = false;
3231
3622
  };
3232
3623
  const secondary = (event, id) => {
3233
3624
  const events = [];
@@ -3247,7 +3638,7 @@ var createPointerTracker2 = (picker) => {
3247
3638
  return secondary(event, id);
3248
3639
  const events = [];
3249
3640
  if (event._tag === "PointerLeave") {
3250
- endGestures();
3641
+ endGestures(events);
3251
3642
  if (position !== undefined)
3252
3643
  endDrag(captured(), position.x, position.y, events);
3253
3644
  dragged = false;
@@ -3282,7 +3673,7 @@ var createPointerTracker2 = (picker) => {
3282
3673
  case "PointerUp":
3283
3674
  release(hit, event, events);
3284
3675
  endDrag(drag, event.x, event.y, events);
3285
- endGestures();
3676
+ endGestures(events);
3286
3677
  break;
3287
3678
  case "DoubleClick":
3288
3679
  if (hit !== undefined && pressed(hit)) {
@@ -3474,6 +3865,11 @@ var createSceneLoop2 = (options) => {
3474
3865
  renderer.render(graph.scene, graph.camera);
3475
3866
  for (const view of views)
3476
3867
  renderer.render(graph.scene, view.camera, view.area);
3868
+ const hud = graph.hud();
3869
+ if (hud !== undefined && renderer.renderOver !== undefined) {
3870
+ renderer.renderOver(hud.graph.scene, hud.graph.camera);
3871
+ hud.graph.drawn();
3872
+ }
3477
3873
  graph.drawn();
3478
3874
  measure();
3479
3875
  const overlays = graph.overlays();
@@ -3558,36 +3954,38 @@ var recordingRendererFactory2 = () => {
3558
3954
  // src/kernel/sceneGraph.ts
3559
3955
  import {
3560
3956
  AmbientLight,
3561
- Color as Color2,
3957
+ Color as Color4,
3562
3958
  AnimationClip,
3563
3959
  AnimationMixer,
3564
3960
  DirectionalLight,
3565
3961
  Group,
3566
3962
  GridHelper,
3567
3963
  HemisphereLight,
3568
- Mesh,
3964
+ Mesh as Mesh2,
3569
3965
  OrthographicCamera as OrthographicCamera4,
3570
3966
  PerspectiveCamera as PerspectiveCamera3,
3571
3967
  PointLight,
3968
+ Quaternion as Quaternion6,
3572
3969
  Scene,
3573
3970
  SpotLight,
3574
- Vector3 as Vector39
3971
+ Vector3 as Vector311
3575
3972
  } from "three";
3973
+ import { clone as cloneSkinned } from "three/addons/utils/SkeletonUtils.js";
3576
3974
 
3577
3975
  // src/kernel/bodies.ts
3578
- import { Euler as Euler4, Quaternion as Quaternion4 } from "three";
3976
+ import { Euler as Euler5, Quaternion as Quaternion5 } from "three";
3579
3977
 
3580
3978
  // src/kernel/bodySources.ts
3581
- import { Euler as Euler3, Matrix4 as Matrix44, Quaternion as Quaternion3, Vector3 as Vector37 } from "three";
3979
+ import { Euler as Euler4, Matrix4 as Matrix44, Quaternion as Quaternion4, Vector3 as Vector38 } from "three";
3582
3980
  var bodyId = (key, instance) => instance === null ? key : `${key}\x00${instance}`;
3583
- var position3 = new Vector37;
3584
- var quaternion2 = new Quaternion3;
3585
- var scale2 = new Vector37;
3981
+ var position3 = new Vector38;
3982
+ var quaternion2 = new Quaternion4;
3983
+ var scale2 = new Vector38;
3586
3984
  var matrix2 = new Matrix44;
3587
3985
  var local = new Matrix44;
3588
3986
  var inverse = new Matrix44;
3589
- var euler2 = new Euler3;
3590
- var ownScale = new Vector37;
3987
+ var euler2 = new Euler4;
3988
+ var ownScale = new Vector38;
3591
3989
  var toPose = (from) => {
3592
3990
  from.decompose(position3, quaternion2, scale2);
3593
3991
  return {
@@ -3600,7 +3998,7 @@ var worldScale2 = (from) => {
3600
3998
  return ownScale;
3601
3999
  };
3602
4000
  var scaleText = (from) => worldScale2(from).toArray().map((value) => (Math.round(value * 1e5) / 1e5 || 0).toString()).join(",");
3603
- var rotationText = (rotation) => rotation._tag === "Fixed" ? rotation.euler.join(",") : "spin";
4001
+ var rotationText = (rotation) => rotation._tag === "Fixed" ? rotation.euler.join(",") : rotation._tag;
3604
4002
  var placeObject = (object, pose) => {
3605
4003
  object.matrixWorld.decompose(position3, quaternion2, scale2);
3606
4004
  matrix2.compose(position3.fromArray(pose.position), quaternion2.fromArray(pose.quaternion), scale2);
@@ -3717,9 +4115,9 @@ var createPhysicsDebug = (scene) => {
3717
4115
  };
3718
4116
 
3719
4117
  // src/kernel/bodies.ts
3720
- var from = new Quaternion4;
3721
- var to = new Quaternion4;
3722
- var euler3 = new Euler4;
4118
+ var from = new Quaternion5;
4119
+ var to = new Quaternion5;
4120
+ var euler3 = new Euler5;
3723
4121
  var quatOf = (angles) => {
3724
4122
  from.setFromEuler(euler3.fromArray([...angles]));
3725
4123
  return [from.x, from.y, from.z, from.w];
@@ -3947,10 +4345,10 @@ var createBodyHost = (engine, scene) => {
3947
4345
  };
3948
4346
 
3949
4347
  // src/kernel/cameraMotion.ts
3950
- import { OrthographicCamera as OrthographicCamera3, Spherical as Spherical2, Vector3 as Vector38 } from "three";
3951
- var createPose = () => ({ target: new Vector38, spherical: new Spherical2, zoom: 1 });
3952
- var offset2 = new Vector38;
3953
- var position4 = new Vector38;
4348
+ import { OrthographicCamera as OrthographicCamera3, Spherical as Spherical2, Vector3 as Vector39 } from "three";
4349
+ var createPose = () => ({ target: new Vector39, spherical: new Spherical2, zoom: 1 });
4350
+ var offset2 = new Vector39;
4351
+ var position4 = new Vector39;
3954
4352
  var readPose = (pose, description) => {
3955
4353
  pose.target.fromArray(description.lookAt);
3956
4354
  offset2.fromArray(description.position).sub(pose.target);
@@ -3991,8 +4389,8 @@ var createCameraMotion = () => {
3991
4389
  const current = createPose();
3992
4390
  const described = createPose();
3993
4391
  const goal = createPose();
3994
- const goalPosition = new Vector38;
3995
- const lookAt = new Vector38;
4392
+ const goalPosition = new Vector39;
4393
+ const lookAt = new Vector39;
3996
4394
  let shown = false;
3997
4395
  let easing = false;
3998
4396
  let damping = 0;
@@ -4075,12 +4473,189 @@ var createCameraMotion = () => {
4075
4473
  return;
4076
4474
  position4.setFromSpherical(goal.spherical).add(goal.target);
4077
4475
  return [position4.x, position4.y, position4.z];
4476
+ },
4477
+ target: () => current.target
4478
+ };
4479
+ };
4480
+
4481
+ // src/kernel/cameraShake.ts
4482
+ import { SimplexNoise } from "three/addons/math/SimplexNoise.js";
4483
+ var seeded = (seed) => ({ random: seededRandom(seed) });
4484
+ var yawNoise = new SimplexNoise(seeded(1));
4485
+ var pitchNoise = new SimplexNoise(seeded(2));
4486
+ var rollNoise = new SimplexNoise(seeded(3));
4487
+ var shakeIntensity = (shake, seconds) => {
4488
+ const decayed = shake.decay ? shake.intensity - shake.decayRate * seconds : shake.intensity;
4489
+ return Math.min(1, Math.max(0, decayed));
4490
+ };
4491
+ var createCameraShaker = () => {
4492
+ let current = null;
4493
+ let since = 0;
4494
+ let offset = false;
4495
+ return {
4496
+ describe: (shake, now) => {
4497
+ if (shake !== null && (current === null || !cameraShakeEquals(current, shake)))
4498
+ since = now;
4499
+ current = shake;
4500
+ },
4501
+ apply: (camera, target, now, animating) => {
4502
+ const shake = current;
4503
+ const strength = shake === null || !animating ? 0 : shakeIntensity(shake, Math.max(0, now - since)) ** 2;
4504
+ if (shake === null || strength === 0) {
4505
+ if (offset)
4506
+ camera.lookAt(target);
4507
+ offset = false;
4508
+ return;
4509
+ }
4510
+ camera.lookAt(target);
4511
+ camera.rotation.set(camera.rotation.x + shake.maxPitch * strength * pitchNoise.noise(now * shake.pitchFrequency, 1), camera.rotation.y + shake.maxYaw * strength * yawNoise.noise(now * shake.yawFrequency, 1), camera.rotation.z + shake.maxRoll * strength * rollNoise.noise(now * shake.rollFrequency, 1));
4512
+ offset = true;
4513
+ },
4514
+ shaking: (now) => offset || current !== null && shakeIntensity(current, Math.max(0, now - since)) > 0
4515
+ };
4516
+ };
4517
+
4518
+ // src/kernel/trail.ts
4519
+ import {
4520
+ BufferAttribute as BufferAttribute2,
4521
+ BufferGeometry as BufferGeometry3,
4522
+ Color as Color3,
4523
+ DoubleSide as DoubleSide2,
4524
+ Mesh,
4525
+ MeshBasicMaterial as MeshBasicMaterial2,
4526
+ Vector3 as Vector310
4527
+ } from "three";
4528
+ var stepsPerSecond = 60;
4529
+ var widthAt = (trail, along) => {
4530
+ const full = trail.width * 0.1;
4531
+ if (trail.taper === "linear")
4532
+ return full * along;
4533
+ if (trail.taper === "quadratic")
4534
+ return full * along * along;
4535
+ return full;
4536
+ };
4537
+ var createTrailRibbon = (first, start, now) => {
4538
+ let trail = first;
4539
+ let count = 0;
4540
+ let points = new Float32Array(0);
4541
+ const geometry = new BufferGeometry3;
4542
+ const material = new MeshBasicMaterial2({
4543
+ vertexColors: true,
4544
+ transparent: true,
4545
+ side: DoubleSide2,
4546
+ depthWrite: false
4547
+ });
4548
+ const object = new Mesh(geometry, material);
4549
+ object.frustumCulled = false;
4550
+ object.raycast = () => {
4551
+ return;
4552
+ };
4553
+ object.name = "effect-three:trail";
4554
+ const last = new Vector310;
4555
+ const here = new Vector310;
4556
+ const ahead = new Vector310;
4557
+ const behind = new Vector310;
4558
+ const side = new Vector310;
4559
+ const toEye = new Vector310;
4560
+ const tint = new Color3;
4561
+ let clock = now;
4562
+ let phase = 0;
4563
+ const reset = (at, time) => {
4564
+ count = Math.max(2, Math.round(trail.length * 10));
4565
+ points = new Float32Array(count * 3);
4566
+ for (let point = 0;point < count; point++)
4567
+ at.toArray(points, point * 3);
4568
+ const index = [];
4569
+ for (let point = 0;point < count - 1; point++) {
4570
+ const a = point * 2;
4571
+ index.push(a, a + 1, a + 2, a + 1, a + 3, a + 2);
4572
+ }
4573
+ geometry.setIndex(index);
4574
+ geometry.setAttribute("position", new BufferAttribute2(new Float32Array(count * 6), 3));
4575
+ geometry.setAttribute("color", new BufferAttribute2(new Float32Array(count * 8), 4));
4576
+ paint();
4577
+ last.copy(at);
4578
+ clock = time;
4579
+ phase = 0;
4580
+ };
4581
+ const paint = () => {
4582
+ const colors = geometry.getAttribute("color");
4583
+ tint.setHex(trail.color);
4584
+ for (let point = 0;point < count; point++) {
4585
+ const alpha = trail.fade ? point / (count - 1) : 1;
4586
+ colors.setXYZW(point * 2, tint.r, tint.g, tint.b, alpha);
4587
+ colors.setXYZW(point * 2 + 1, tint.r, tint.g, tint.b, alpha);
4588
+ }
4589
+ colors.needsUpdate = true;
4590
+ };
4591
+ const push = (at) => {
4592
+ points.copyWithin(0, 3);
4593
+ at.toArray(points, (count - 1) * 3);
4594
+ };
4595
+ reset(start, now);
4596
+ return {
4597
+ object,
4598
+ record: (position, time) => {
4599
+ const due = Math.min(count, Math.floor((time - clock) * stepsPerSecond));
4600
+ if (due <= 0)
4601
+ return;
4602
+ clock += due / stepsPerSecond;
4603
+ for (let step = 0;step < due; step++) {
4604
+ if (phase === 0) {
4605
+ for (let shift = 0;shift < trail.decay; shift++) {
4606
+ if (position.distanceTo(last) < trail.stride)
4607
+ continue;
4608
+ push(position);
4609
+ }
4610
+ last.copy(position);
4611
+ }
4612
+ phase = (phase + 1) % Math.max(1, Math.round(trail.interval));
4613
+ }
4614
+ },
4615
+ face: (eye) => {
4616
+ const position = geometry.getAttribute("position");
4617
+ for (let point = 0;point < count; point++) {
4618
+ here.fromArray(points, point * 3);
4619
+ ahead.fromArray(points, Math.min(point + 1, count - 1) * 3);
4620
+ behind.fromArray(points, Math.max(point - 1, 0) * 3);
4621
+ side.subVectors(ahead, behind).cross(toEye.subVectors(eye, here));
4622
+ const length = side.length();
4623
+ if (length > 0.000000001)
4624
+ side.multiplyScalar(widthAt(trail, point / (count - 1)) / 2 / length);
4625
+ else
4626
+ side.set(0, 0, 0);
4627
+ position.setXYZ(point * 2, here.x + side.x, here.y + side.y, here.z + side.z);
4628
+ position.setXYZ(point * 2 + 1, here.x - side.x, here.y - side.y, here.z - side.z);
4629
+ }
4630
+ position.needsUpdate = true;
4631
+ },
4632
+ settled: () => {
4633
+ const end = (count - 1) * 3;
4634
+ for (let point = 0;point < end; point += 3) {
4635
+ if (points[point] !== points[end] || points[point + 1] !== points[end + 1])
4636
+ return false;
4637
+ if (points[point + 2] !== points[end + 2])
4638
+ return false;
4639
+ }
4640
+ return true;
4641
+ },
4642
+ restyle: (next, position, time) => {
4643
+ const resized = Math.round(next.length * 10) !== Math.round(trail.length * 10);
4644
+ trail = next;
4645
+ if (resized)
4646
+ reset(position, time);
4647
+ else
4648
+ paint();
4649
+ },
4650
+ dispose: () => {
4651
+ geometry.dispose();
4652
+ material.dispose();
4078
4653
  }
4079
4654
  };
4080
4655
  };
4081
4656
 
4082
4657
  // src/kernel/sceneGraph.ts
4083
- var isPlaced = (entry) => entry._tag === "Group" || entry._tag === "Mesh" || entry._tag === "Instances" || entry._tag === "Borrowed" || entry._tag === "Label";
4658
+ var isPlaced = (entry) => entry._tag === "Group" || entry._tag === "Mesh" || entry._tag === "Instances" || entry._tag === "Borrowed" || entry._tag === "Label" || entry._tag === "Line" || entry._tag === "Points";
4084
4659
  var isSurfaced = (entry) => entry._tag === "Mesh" || entry._tag === "Instances";
4085
4660
  var writeVec3 = (target, v) => {
4086
4661
  target.set(v[0], v[1], v[2]);
@@ -4165,6 +4740,7 @@ var applyLens = (camera, description) => {
4165
4740
  };
4166
4741
  var noInstances = [];
4167
4742
  var emptyScene = scene2({});
4743
+ var cloneLoan = (lent) => lent.getObjectByProperty("isSkinnedMesh", true) === undefined ? lent.clone() : cloneSkinned(lent);
4168
4744
  var createSceneGraph2 = (options = {}) => {
4169
4745
  const store = options.store ?? createResourceStore2();
4170
4746
  const ownsStore = options.store === undefined;
@@ -4173,6 +4749,7 @@ var createSceneGraph2 = (options = {}) => {
4173
4749
  let views = [];
4174
4750
  const textureGraphs = new Map;
4175
4751
  let textureList = [];
4752
+ let hudHosted;
4176
4753
  let viewDescriptions = [];
4177
4754
  let gestures = emptyScene.gestures;
4178
4755
  let overlayList = emptyScene.overlays;
@@ -4202,7 +4779,23 @@ var createSceneGraph2 = (options = {}) => {
4202
4779
  hostedSky = undefined;
4203
4780
  }
4204
4781
  const cameraMotion = createCameraMotion();
4782
+ const cameraShaker = createCameraShaker();
4205
4783
  const viewMotions = new Map;
4784
+ const viewShakers = new Map;
4785
+ const shaking = () => {
4786
+ if (cameraShaker.shaking(elapsed))
4787
+ return true;
4788
+ for (const shaker of viewShakers.values())
4789
+ if (shaker.shaking(elapsed))
4790
+ return true;
4791
+ return false;
4792
+ };
4793
+ const shakeView = (view) => {
4794
+ const motion = viewMotions.get(view.key);
4795
+ if (motion === undefined)
4796
+ return;
4797
+ viewShakers.get(view.key)?.apply(view.camera, motion.target(), elapsed, animating);
4798
+ };
4206
4799
  const viewsMoving = () => {
4207
4800
  for (const motion of viewMotions.values())
4208
4801
  if (motion.moving())
@@ -4233,6 +4826,9 @@ var createSceneGraph2 = (options = {}) => {
4233
4826
  applyLens(hostedCamera, description.camera);
4234
4827
  const motion = viewMotions.get(description.key) ?? createCameraMotion();
4235
4828
  viewMotions.set(description.key, motion);
4829
+ const shaker = viewShakers.get(description.key) ?? createCameraShaker();
4830
+ viewShakers.set(description.key, shaker);
4831
+ shaker.describe(description.camera.shake, elapsed);
4236
4832
  motion.aim(hostedCamera, description.camera, elapsed, hostedCamera !== previous || !animating);
4237
4833
  const area = areaOf(description.rect);
4238
4834
  fitCamera(hostedCamera, area);
@@ -4246,10 +4842,43 @@ var createSceneGraph2 = (options = {}) => {
4246
4842
  if (!described.some((description) => description.key === key))
4247
4843
  viewMotions.delete(key);
4248
4844
  }
4845
+ for (const key of viewShakers.keys()) {
4846
+ if (!described.some((description) => description.key === key))
4847
+ viewShakers.delete(key);
4848
+ }
4249
4849
  };
4250
4850
  const entries = new Map;
4251
4851
  const keys = new WeakMap;
4252
4852
  const spinning = new Set;
4853
+ const facing = new Set;
4854
+ const cameraTurn = new Quaternion6;
4855
+ const parentTurn = new Quaternion6;
4856
+ const sparkling = new Set;
4857
+ const trackSparkle = (entry, node) => {
4858
+ if (animatedLook(node.look))
4859
+ sparkling.add(entry);
4860
+ else
4861
+ sparkling.delete(entry);
4862
+ if (entry._tag === "Points")
4863
+ entry.hosted?.tick(animating ? elapsed : 0);
4864
+ };
4865
+ const sparkle = (entry) => {
4866
+ if (entry._tag === "Points")
4867
+ entry.hosted?.tick(elapsed);
4868
+ };
4869
+ const trailing = new Map;
4870
+ const trailPlace = new Vector311;
4871
+ const eye = new Vector311;
4872
+ const trailsMoving = () => {
4873
+ for (const ribbon of trailing.values())
4874
+ if (!ribbon.settled())
4875
+ return true;
4876
+ return false;
4877
+ };
4878
+ const edged = new Map;
4879
+ const detailing = new Set;
4880
+ const cameraPlace = new Vector311;
4881
+ const groupPlace = new Vector311;
4253
4882
  const playing = new Set;
4254
4883
  const registry = {
4255
4884
  ...builtinBehaviours2,
@@ -4259,7 +4888,7 @@ var createSceneGraph2 = (options = {}) => {
4259
4888
  const behaving = new Map;
4260
4889
  const moving = new Map;
4261
4890
  const reparented = new Set;
4262
- const worldPosition = new Vector39;
4891
+ const worldPosition = new Vector311;
4263
4892
  const interactive = new Set;
4264
4893
  let interactiveList;
4265
4894
  let index = emptyIndex2;
@@ -4307,6 +4936,140 @@ var createSceneGraph2 = (options = {}) => {
4307
4936
  spinning.add(entry);
4308
4937
  else
4309
4938
  spinning.delete(entry);
4939
+ if (node.rotation._tag === "Billboard")
4940
+ facing.add(entry);
4941
+ else
4942
+ facing.delete(entry);
4943
+ };
4944
+ const faceCamera = (entry) => {
4945
+ if (!isPlaced(entry) || entry.node.rotation._tag !== "Billboard")
4946
+ return;
4947
+ const { lockX, lockY, lockZ } = entry.node.rotation;
4948
+ const object = entry.object;
4949
+ parentTurn.identity();
4950
+ object.parent?.getWorldQuaternion(parentTurn);
4951
+ object.quaternion.copy(cameraTurn).premultiply(parentTurn.invert());
4952
+ if (lockX)
4953
+ object.rotation.x = 0;
4954
+ if (lockY)
4955
+ object.rotation.y = 0;
4956
+ if (lockZ)
4957
+ object.rotation.z = 0;
4958
+ };
4959
+ const trailTarget = (object, local) => local ? trailPlace.copy(object.position) : object.getWorldPosition(trailPlace);
4960
+ const trackTrail = (entry, node) => {
4961
+ const current = trailing.get(entry);
4962
+ if (node.trail === null) {
4963
+ if (current === undefined)
4964
+ return;
4965
+ current.object.removeFromParent();
4966
+ current.dispose();
4967
+ trailing.delete(entry);
4968
+ return;
4969
+ }
4970
+ const start = trailTarget(entry.object, node.trail.local);
4971
+ if (current !== undefined) {
4972
+ current.restyle(node.trail, start, elapsed);
4973
+ return;
4974
+ }
4975
+ const ribbon = createTrailRibbon(node.trail, start, elapsed);
4976
+ scene.add(ribbon.object);
4977
+ trailing.set(entry, ribbon);
4978
+ };
4979
+ const followTrail = (ribbon, entry) => {
4980
+ if (entry._tag !== "Group" && entry._tag !== "Mesh")
4981
+ return;
4982
+ if (entry.node.trail === null)
4983
+ return;
4984
+ ribbon.record(trailTarget(entry.object, entry.node.trail.local), elapsed);
4985
+ ribbon.face(eye);
4986
+ };
4987
+ const unpickable = (part) => {
4988
+ part.raycast = () => {
4989
+ return;
4990
+ };
4991
+ };
4992
+ const trackEdges = (entry, node) => {
4993
+ const current = edged.get(entry);
4994
+ const draw = options.kit?.line;
4995
+ if (node.edges === null || draw === undefined) {
4996
+ if (current === undefined)
4997
+ return;
4998
+ current.hosted.object.removeFromParent();
4999
+ current.hosted.dispose();
5000
+ edged.delete(entry);
5001
+ return;
5002
+ }
5003
+ if (current !== undefined)
5004
+ return;
5005
+ const hosted = draw(edgeLine(node.key, node.edges, []));
5006
+ entry.object.add(hosted.object);
5007
+ edged.set(entry, { hosted, geometry: undefined, edges: undefined });
5008
+ };
5009
+ const refreshEdges = (lines, entry) => {
5010
+ if (entry._tag !== "Mesh" || entry.node.edges === null)
5011
+ return;
5012
+ const { geometry } = entry.object;
5013
+ const look = entry.node.edges;
5014
+ if (geometry === lines.geometry && lines.edges !== undefined && edgesEquals(look, lines.edges)) {
5015
+ return;
5016
+ }
5017
+ lines.hosted.update(edgeLine(entry.node.key, look, edgePoints(geometry, look.threshold)));
5018
+ lines.hosted.object.traverse(unpickable);
5019
+ lines.geometry = geometry;
5020
+ lines.edges = look;
5021
+ };
5022
+ const childObject = (node, index) => {
5023
+ const child = node.children[index];
5024
+ return child === undefined ? undefined : entries.get(child.key)?.object;
5025
+ };
5026
+ const showLevel = (entry) => {
5027
+ if (entry._tag !== "Group")
5028
+ return;
5029
+ const { node } = entry;
5030
+ const { detail } = node;
5031
+ if (detail === null)
5032
+ return;
5033
+ const { distances, hysteresis } = detail;
5034
+ const count = node.children.length;
5035
+ if (count < 2)
5036
+ return;
5037
+ entry.object.getWorldPosition(groupPlace);
5038
+ const distance = cameraPlace.distanceTo(groupPlace) / camera.zoom;
5039
+ const first = childObject(node, 0);
5040
+ if (first !== undefined)
5041
+ first.visible = true;
5042
+ let level = 1;
5043
+ for (;level < count; level++) {
5044
+ const object = childObject(node, level);
5045
+ const from = distances[level] ?? Number.NaN;
5046
+ const reach = object?.visible === true ? from - from * hysteresis : from;
5047
+ if (!(distance >= reach))
5048
+ break;
5049
+ const previous = childObject(node, level - 1);
5050
+ if (previous !== undefined)
5051
+ previous.visible = false;
5052
+ if (object !== undefined)
5053
+ object.visible = true;
5054
+ }
5055
+ for (;level < count; level++) {
5056
+ const object = childObject(node, level);
5057
+ if (object !== undefined)
5058
+ object.visible = false;
5059
+ }
5060
+ };
5061
+ const trackDetail = (entry, node) => {
5062
+ if (node.detail !== null) {
5063
+ detailing.add(entry);
5064
+ return;
5065
+ }
5066
+ if (detailing.delete(entry)) {
5067
+ for (let index = 0;index < node.children.length; index++) {
5068
+ const object = childObject(node, index);
5069
+ if (object !== undefined)
5070
+ object.visible = true;
5071
+ }
5072
+ }
4310
5073
  };
4311
5074
  const build = (node) => {
4312
5075
  switch (node._tag) {
@@ -4319,10 +5082,12 @@ var createSceneGraph2 = (options = {}) => {
4319
5082
  trackInteractive(entry.object, node.interactive);
4320
5083
  if (node.follow !== null)
4321
5084
  entry.object.visible = false;
5085
+ trackDetail(entry, node);
5086
+ trackTrail(entry, node);
4322
5087
  return entry;
4323
5088
  }
4324
5089
  case "Mesh": {
4325
- const object = new Mesh(store.acquireGeometry(node.geometry), store.acquireMaterial(node.material));
5090
+ const object = new Mesh2(store.acquireGeometry(node.geometry), store.acquireMaterial(node.material));
4326
5091
  const entry = { _tag: "Mesh", node, object };
4327
5092
  writeVec3(object.position, node.position);
4328
5093
  writeVec3(object.scale, node.scale);
@@ -4331,6 +5096,8 @@ var createSceneGraph2 = (options = {}) => {
4331
5096
  trackInteractive(object, node.interactive);
4332
5097
  object.castShadow = node.castShadow;
4333
5098
  object.receiveShadow = node.receiveShadow;
5099
+ trackEdges(entry, node);
5100
+ trackTrail(entry, node);
4334
5101
  return entry;
4335
5102
  }
4336
5103
  case "Instances": {
@@ -4404,6 +5171,30 @@ var createSceneGraph2 = (options = {}) => {
4404
5171
  const hosted = options.kit?.shaderGrid(node);
4405
5172
  return { _tag: "ShaderGrid", node, object: hosted?.object ?? new Group, hosted };
4406
5173
  }
5174
+ case "Points": {
5175
+ const hosted = options.kit?.points?.(node);
5176
+ const entry = { _tag: "Points", node, object: new Group, hosted };
5177
+ if (hosted !== undefined)
5178
+ entry.object.add(hosted.object);
5179
+ writeVec3(entry.object.position, node.position);
5180
+ writeVec3(entry.object.scale, node.scale);
5181
+ trackRotation(entry, node);
5182
+ trackBehaviour(entry, node);
5183
+ trackSparkle(entry, node);
5184
+ return entry;
5185
+ }
5186
+ case "Line": {
5187
+ const hosted = options.kit?.line?.(node);
5188
+ const entry = { _tag: "Line", node, object: new Group, hosted };
5189
+ if (hosted !== undefined)
5190
+ entry.object.add(hosted.object);
5191
+ writeVec3(entry.object.position, node.position);
5192
+ writeVec3(entry.object.scale, node.scale);
5193
+ trackRotation(entry, node);
5194
+ trackBehaviour(entry, node);
5195
+ trackInteractive(entry.object, node.interactive);
5196
+ return entry;
5197
+ }
4407
5198
  case "HemisphereLight": {
4408
5199
  const object = new HemisphereLight;
4409
5200
  writeHemisphereLight(object, node);
@@ -4418,11 +5209,22 @@ var createSceneGraph2 = (options = {}) => {
4418
5209
  const lent = store.lent(entry.node.id);
4419
5210
  if (lent === undefined)
4420
5211
  return;
4421
- const shown = lent.parent === null ? lent : lent.clone();
5212
+ const shown = lent.parent === null ? lent : cloneLoan(lent);
4422
5213
  entry.object.add(shown);
4423
5214
  entry.shown = shown;
5215
+ castShadows(shown, entry.node);
4424
5216
  startPlayer(entry);
4425
5217
  };
5218
+ const castShadows = (shown, node) => {
5219
+ if (!node.castShadow && !node.receiveShadow)
5220
+ return;
5221
+ shown.traverse((part) => {
5222
+ if (part instanceof Mesh2 && node.castShadow)
5223
+ part.castShadow = true;
5224
+ if (part instanceof Mesh2 && node.receiveShadow)
5225
+ part.receiveShadow = true;
5226
+ });
5227
+ };
4426
5228
  const stopPlayer = (entry) => {
4427
5229
  if (entry.player === undefined)
4428
5230
  return;
@@ -4556,6 +5358,19 @@ var createSceneGraph2 = (options = {}) => {
4556
5358
  if (isPlaced(entry))
4557
5359
  behaving.delete(entry);
4558
5360
  spinning.delete(entry);
5361
+ facing.delete(entry);
5362
+ detailing.delete(entry);
5363
+ const lines = edged.get(entry);
5364
+ if (lines !== undefined) {
5365
+ lines.hosted.dispose();
5366
+ edged.delete(entry);
5367
+ }
5368
+ const ribbon = trailing.get(entry);
5369
+ if (ribbon !== undefined) {
5370
+ ribbon.object.removeFromParent();
5371
+ ribbon.dispose();
5372
+ trailing.delete(entry);
5373
+ }
4559
5374
  moving.delete(entry);
4560
5375
  reparented.delete(entry);
4561
5376
  trackInteractive(entry.object, false);
@@ -4567,8 +5382,10 @@ var createSceneGraph2 = (options = {}) => {
4567
5382
  entry.object.dispose();
4568
5383
  if (entry._tag === "Grid")
4569
5384
  disposeGridLines(entry.helper);
4570
- if (entry._tag === "ShaderGrid")
5385
+ if (entry._tag === "ShaderGrid" || entry._tag === "Line" || entry._tag === "Points") {
4571
5386
  entry.hosted?.dispose();
5387
+ }
5388
+ sparkling.delete(entry);
4572
5389
  if (entry._tag === "Label") {
4573
5390
  entry.hosted?.dispose();
4574
5391
  if (entry.node.material !== null && entry.material !== undefined) {
@@ -4663,6 +5480,12 @@ var createSceneGraph2 = (options = {}) => {
4663
5480
  retarget(entry, next);
4664
5481
  if (fields.includes("rotation"))
4665
5482
  trackRotation(entry, next);
5483
+ if (entry._tag === "Mesh" && next._tag === "Mesh" && fields.includes("edges")) {
5484
+ trackEdges(entry, next);
5485
+ }
5486
+ if (entry._tag === "Mesh" && next._tag === "Mesh" && fields.includes("trail")) {
5487
+ trackTrail(entry, next);
5488
+ }
4666
5489
  if (fields.includes("behaviour"))
4667
5490
  trackBehaviour(entry, next);
4668
5491
  if (fields.includes("interactive"))
@@ -4685,6 +5508,10 @@ var createSceneGraph2 = (options = {}) => {
4685
5508
  showLoan(entry);
4686
5509
  else if (fields.includes("animation"))
4687
5510
  startPlayer(entry);
5511
+ if (fields.includes("castShadow") || fields.includes("receiveShadow")) {
5512
+ if (entry.shown !== undefined)
5513
+ castShadows(entry.shown, next);
5514
+ }
4688
5515
  return;
4689
5516
  }
4690
5517
  if (entry._tag === "Label" && next._tag === "Label") {
@@ -4713,6 +5540,10 @@ var createSceneGraph2 = (options = {}) => {
4713
5540
  trackBehaviour(entry, next);
4714
5541
  if (fields.includes("interactive"))
4715
5542
  trackInteractive(entry.object, next.interactive);
5543
+ if (fields.includes("detail"))
5544
+ trackDetail(entry, next);
5545
+ if (fields.includes("trail"))
5546
+ trackTrail(entry, next);
4716
5547
  if (fields.includes("follow")) {
4717
5548
  entry.object.visible = next.follow === null;
4718
5549
  if (next.follow === null) {
@@ -4748,6 +5579,34 @@ var createSceneGraph2 = (options = {}) => {
4748
5579
  entry.node = next;
4749
5580
  return;
4750
5581
  }
5582
+ if (entry._tag === "Points" && next._tag === "Points") {
5583
+ entry.node = next;
5584
+ if (movesTransform(entry, fields))
5585
+ retarget(entry, next);
5586
+ if (fields.includes("rotation"))
5587
+ trackRotation(entry, next);
5588
+ if (fields.includes("behaviour"))
5589
+ trackBehaviour(entry, next);
5590
+ if (fields.includes("look")) {
5591
+ entry.hosted?.update(next);
5592
+ trackSparkle(entry, next);
5593
+ }
5594
+ return;
5595
+ }
5596
+ if (entry._tag === "Line" && next._tag === "Line") {
5597
+ entry.node = next;
5598
+ if (movesTransform(entry, fields))
5599
+ retarget(entry, next);
5600
+ if (fields.includes("rotation"))
5601
+ trackRotation(entry, next);
5602
+ if (fields.includes("behaviour"))
5603
+ trackBehaviour(entry, next);
5604
+ if (fields.includes("interactive"))
5605
+ trackInteractive(entry.object, next.interactive);
5606
+ if (fields.includes("line"))
5607
+ entry.hosted?.update(next);
5608
+ return;
5609
+ }
4751
5610
  if (entry._tag === "ShaderGrid" && next._tag === "ShaderGrid") {
4752
5611
  entry.hosted?.update(entry.node, next);
4753
5612
  entry.node = next;
@@ -4785,6 +5644,7 @@ var createSceneGraph2 = (options = {}) => {
4785
5644
  camera = cameraFor(camera, op.camera);
4786
5645
  applyLens(camera, op.camera);
4787
5646
  cameraMotion.aim(camera, op.camera, elapsed, camera !== previous || !animating);
5647
+ cameraShaker.describe(op.camera.shake, elapsed);
4788
5648
  fitCamera(camera, viewport);
4789
5649
  return;
4790
5650
  }
@@ -4876,6 +5736,7 @@ var createSceneGraph2 = (options = {}) => {
4876
5736
  gestures: "page",
4877
5737
  views: [],
4878
5738
  renderTextures: [],
5739
+ hud: null,
4879
5740
  overlays: [],
4880
5741
  environment: null,
4881
5742
  sky: null,
@@ -4887,6 +5748,62 @@ var createSceneGraph2 = (options = {}) => {
4887
5748
  resources: parent.resources,
4888
5749
  children: texture.children
4889
5750
  });
5751
+ const hudCamera = (hud) => {
5752
+ const [marginX, marginY] = hud.margin;
5753
+ const [vertical, horizontal] = hud.alignment.split("-");
5754
+ const across = { left: -viewport.width / 2 + marginX, right: viewport.width / 2 - marginX };
5755
+ const up = { top: viewport.height / 2 - marginY, bottom: -viewport.height / 2 + marginY };
5756
+ const x = across[horizontal] ?? 0;
5757
+ const y = up[vertical] ?? 0;
5758
+ return orthographicCamera2({
5759
+ zoom: 1,
5760
+ near: 0.1,
5761
+ far: 2000,
5762
+ position: [-x, -y, 200],
5763
+ lookAt: [-x, -y, 0]
5764
+ });
5765
+ };
5766
+ const hudScene = (hud, parent) => textureScene({
5767
+ id: "hud",
5768
+ width: viewport.width,
5769
+ height: viewport.height,
5770
+ camera: hudCamera(hud),
5771
+ background: null,
5772
+ children: hud.children
5773
+ }, parent);
5774
+ const syncHud = (next) => {
5775
+ if (next.hud === null) {
5776
+ if (hudHosted === undefined)
5777
+ return [];
5778
+ hudHosted.graph.dispose();
5779
+ hudHosted = undefined;
5780
+ return [{ _tag: "RemoveHud" }];
5781
+ }
5782
+ const created = hudHosted === undefined;
5783
+ const hosted = hudHosted ?? {
5784
+ graph: createSceneGraph2({
5785
+ store,
5786
+ ...options.behaviours === undefined ? {} : { behaviours: options.behaviours },
5787
+ ...options.kit === undefined ? {} : { kit: options.kit }
5788
+ }),
5789
+ description: next.hud,
5790
+ parent: next
5791
+ };
5792
+ if (created)
5793
+ hosted.graph.resize(viewport.width, viewport.height);
5794
+ const result = hosted.graph.reconcile(hudScene(next.hud, next));
5795
+ hosted.description = next.hud;
5796
+ hosted.parent = next;
5797
+ hudHosted = hosted;
5798
+ const ops = result._tag === "Applied" ? result.ops : [];
5799
+ return created || ops.length > 0 ? [{ _tag: "UpdateHud", ops }] : [];
5800
+ };
5801
+ const refitHud = () => {
5802
+ if (hudHosted === undefined)
5803
+ return;
5804
+ hudHosted.graph.resize(viewport.width, viewport.height);
5805
+ hudHosted.graph.reconcile(hudScene(hudHosted.description, hudHosted.parent));
5806
+ };
4890
5807
  function hostedTexture(texture) {
4891
5808
  const hosted = textureGraphs.get(texture.id);
4892
5809
  if (hosted === undefined)
@@ -4910,7 +5827,7 @@ var createSceneGraph2 = (options = {}) => {
4910
5827
  const reframed = existing === undefined || existing.description.width !== texture.width || existing.description.height !== texture.height || existing.description.background !== texture.background;
4911
5828
  if (reframed) {
4912
5829
  hosted.graph.resize(texture.width, texture.height);
4913
- hosted.graph.scene.background = texture.background === null ? null : new Color2(texture.background);
5830
+ hosted.graph.scene.background = texture.background === null ? null : new Color4(texture.background);
4914
5831
  }
4915
5832
  hosted.description = texture;
4916
5833
  textureGraphs.set(texture.id, hosted);
@@ -4935,6 +5852,11 @@ var createSceneGraph2 = (options = {}) => {
4935
5852
  if (checked._tag === "Invalid")
4936
5853
  return checked;
4937
5854
  }
5855
+ if (next.hud !== null) {
5856
+ const checked = indexScene2(hudScene(next.hud, next), knownBehaviours);
5857
+ if (checked._tag === "Invalid")
5858
+ return checked;
5859
+ }
4938
5860
  const result = diff2(index, next, knownBehaviours);
4939
5861
  if (result._tag === "Invalid")
4940
5862
  return result;
@@ -4969,7 +5891,7 @@ var createSceneGraph2 = (options = {}) => {
4969
5891
  if (next.measure.join("\x00") !== measured.join("\x00"))
4970
5892
  invalidate();
4971
5893
  measured = next.measure;
4972
- const ops = [...result.ops, ...syncTextures(next)];
5894
+ const ops = [...result.ops, ...syncTextures(next), ...syncHud(next)];
4973
5895
  if (ops.length > 0)
4974
5896
  invalidate();
4975
5897
  return { _tag: "Applied", ops };
@@ -4982,6 +5904,7 @@ var createSceneGraph2 = (options = {}) => {
4982
5904
  elapsed = elapsedSeconds;
4983
5905
  for (const texture of textureList)
4984
5906
  texture.graph.tick(elapsedSeconds);
5907
+ hudHosted?.graph.tick(elapsedSeconds);
4985
5908
  for (const entry of spinning) {
4986
5909
  if (isPlaced(entry)) {
4987
5910
  writeRotation2(entry.object.rotation, entry.node.rotation, elapsed);
@@ -4994,7 +5917,24 @@ var createSceneGraph2 = (options = {}) => {
4994
5917
  cameraMotion.step(camera, elapsed);
4995
5918
  for (const view of views)
4996
5919
  viewMotions.get(view.key)?.step(view.camera, elapsed);
5920
+ cameraShaker.apply(camera, cameraMotion.target(), elapsed, animating);
5921
+ views.forEach(shakeView);
4997
5922
  bodyHost.tick(elapsed, animating);
5923
+ if (facing.size > 0) {
5924
+ camera.getWorldQuaternion(cameraTurn);
5925
+ facing.forEach(faceCamera);
5926
+ }
5927
+ edged.forEach(refreshEdges);
5928
+ if (animating)
5929
+ sparkling.forEach(sparkle);
5930
+ if (trailing.size > 0) {
5931
+ camera.getWorldPosition(eye);
5932
+ trailing.forEach(followTrail);
5933
+ }
5934
+ if (detailing.size > 0) {
5935
+ camera.getWorldPosition(cameraPlace);
5936
+ detailing.forEach(showLevel);
5937
+ }
4998
5938
  };
4999
5939
  const finishTween = (tween, entry) => {
5000
5940
  applyTween2(entry.object, tween, Number.POSITIVE_INFINITY);
@@ -5004,6 +5944,7 @@ var createSceneGraph2 = (options = {}) => {
5004
5944
  invalidate();
5005
5945
  for (const texture of textureList)
5006
5946
  texture.graph.setAnimating(next);
5947
+ hudHosted?.graph.setAnimating(next);
5007
5948
  animating = next;
5008
5949
  if (next)
5009
5950
  return;
@@ -5020,6 +5961,8 @@ var createSceneGraph2 = (options = {}) => {
5020
5961
  texture.graph.dispose();
5021
5962
  textureGraphs.clear();
5022
5963
  textureList = [];
5964
+ hudHosted?.graph.dispose();
5965
+ hudHosted = undefined;
5023
5966
  for (const entry of entries.values()) {
5024
5967
  entry.object.removeFromParent();
5025
5968
  release(entry);
@@ -5052,6 +5995,7 @@ var createSceneGraph2 = (options = {}) => {
5052
5995
  return viewMotions.get(view)?.turned();
5053
5996
  },
5054
5997
  renderTextures: () => textureList,
5998
+ hud: () => hudHosted,
5055
5999
  gestures: () => gestures,
5056
6000
  overlays: () => overlayList,
5057
6001
  environment: () => environmentDescription,
@@ -5080,7 +6024,7 @@ var createSceneGraph2 = (options = {}) => {
5080
6024
  tick,
5081
6025
  elapsedSeconds: () => elapsed,
5082
6026
  renderSettings: () => settings,
5083
- needsFrame: () => dirty || textureList.some((texture) => texture.graph.needsFrame()) || animating && (spinning.size > 0 || moving.size > 0 || behaving.size > 0 || clipsRunning() || cameraMotion.moving() || viewsMoving() || bodyHost.needsFrame()),
6027
+ needsFrame: () => dirty || trailsMoving() || textureList.some((texture) => texture.graph.needsFrame()) || (hudHosted?.graph.needsFrame() ?? false) || animating && (spinning.size > 0 || moving.size > 0 || behaving.size > 0 || clipsRunning() || cameraMotion.moving() || viewsMoving() || shaking() || sparkling.size > 0 || bodyHost.needsFrame()),
5084
6028
  drawn: () => {
5085
6029
  dirty = false;
5086
6030
  },
@@ -5107,12 +6051,1401 @@ var createSceneGraph2 = (options = {}) => {
5107
6051
  viewport = { width, height };
5108
6052
  fitCamera(camera, viewport);
5109
6053
  hostViews(viewDescriptions);
6054
+ refitHud();
5110
6055
  invalidate();
5111
6056
  },
5112
6057
  dispose
5113
6058
  };
5114
6059
  };
5115
- export { handJoints2, clipTime2, clipRunning2, createPose2, resetPose2, float2, builtinBehaviours2, spinAngle2, writeRotation2, buildMaterial2, updateMaterial2, vec3Equals2, rotationEquals2, shapeEquals2, geometryRefEquals2, instanceEquals2, instancesEqual2, behaviourEquals2, animationEquals2, transitionEquals2, materialRefEquals2, cameraEquals2, renderSettingsEquals2, effectsEqual2, viewsEqual2, resourcesEqual2, overlaysEqual2, environmentEquals2, skyEquals2, contactShadowsEquals2, bodyEquals2, physicsEquals2, xrEquals2, capacityFor2, createPerformanceMonitor2, easeProgress2, startTween2, applyTween2, fixed2, spin2, box2, sphere2, plane2, cylinder2, torus2, cone2, capsule2, ring2, circle2, text2, instant2, ease2, basic2, lambert2, phong2, standard2, physical2, normalMaterial2, shadowMaterial2, grid2, shaderGrid2, sharedGeometry2, lentGeometry2, sharedMaterial2, group2, headSpace2, jointSpace2, controllerSpace2, anchorSpace2, planeSpace2, meshSpace2, xrMeshGeometryId2, xrMesh2, xrAnchor2, mesh2, body2, interactionGroups2, cuboidCollider2, ballCollider2, capsuleCollider2, cylinderCollider2, coneCollider2, velocityMotor2, positionMotor2, physics2, bodyRef2, joint2, fixedJoint2, sphericalJoint2, revoluteJoint2, prismaticJoint2, ropeJoint2, springJoint2, glide2, xr2, instance2, instances2, behave2, play2, borrowed2, label2, colorRange2, ambientLight2, directionalLight2, pointLight2, spotLight2, hemisphereLight2, perspectiveCamera2, orthographicCamera2, bloom2, vignette2, film2, renderSettings2, view2, renderTexture2, environment2, sunPositionFromAngles2, sky2, contactShadows2, overlay2, scene2, emptyIndex2, indexScene2, changedFields2, diff2, createResourceStore2, createSceneClock2, createManualFrames2, createGatedFrames2, createFramePacer2, defaultOrbit2, orbitOptions2, rotateCamera2, dollyCamera2, panCamera2, dollyCameraToward2, orbit2, orbitKey2, autoRotated2, fitCamera2, clipCamera2, placeOverlays2, interactionBits2, colliderFor2, describedColliders2, collidersFor2, colliderSignature2, locomote2, teleport2, glided2, createXrTracker2, environmentPresets2, environmentPresetUrl2, stagePresets2, stage2, centerOffset2, stageBounds2, noModifiers2, pointOnPlane2, createPicker2, createPointerTracker2, createSceneLoop2, recordingRendererFactory2, createSceneGraph2 };
6060
+ // src/kernel/gizmo.ts
6061
+ import { Euler as Euler6, Quaternion as Quaternion7, Vector3 as Vector312 } from "three";
6062
+ var gizmo2 = (options = {}) => ({
6063
+ mode: options.mode ?? "translate",
6064
+ space: options.space ?? "world",
6065
+ size: options.size ?? 1,
6066
+ translationSnap: options.translationSnap ?? null,
6067
+ rotationSnap: options.rotationSnap ?? null,
6068
+ scaleSnap: options.scaleSnap ?? null,
6069
+ showX: options.showX ?? true,
6070
+ showY: options.showY ?? true,
6071
+ showZ: options.showZ ?? true,
6072
+ hovered: null,
6073
+ grab: null
6074
+ });
6075
+ var axes = {
6076
+ x: new Vector312(1, 0, 0),
6077
+ y: new Vector312(0, 1, 0),
6078
+ z: new Vector312(0, 0, 1)
6079
+ };
6080
+ var turnOf = (rotation) => new Quaternion7().setFromEuler(new Euler6(rotation[0], rotation[1], rotation[2]));
6081
+ var spaceOf = (state, handle) => {
6082
+ if (state.mode === "scale")
6083
+ return "local";
6084
+ if (handle === "xyz")
6085
+ return "world";
6086
+ return state.space;
6087
+ };
6088
+ var axisIn = (name, space, rotation) => space === "local" ? axes[name].clone().applyQuaternion(turnOf(rotation)) : axes[name].clone();
6089
+ var toVec34 = (vector) => [vector.x, vector.y, vector.z];
6090
+ var dragPlane = (state, handle, start, eye, facingCamera) => {
6091
+ const space = spaceOf(state, handle);
6092
+ const along = (name) => axisIn(name, space, start.rotation);
6093
+ const facing = (axis) => axis.clone().cross(eye.clone().cross(axis));
6094
+ const normals = {
6095
+ x: () => facing(along("x")),
6096
+ y: () => facing(along("y")),
6097
+ z: () => facing(along("z")),
6098
+ xy: () => along("z"),
6099
+ yz: () => along("x"),
6100
+ xz: () => along("y"),
6101
+ xyz: () => facingCamera.clone()
6102
+ };
6103
+ const normal = state.mode === "rotate" ? facingCamera.clone() : normals[handle]();
6104
+ if (normal.lengthSq() < 0.000000000001)
6105
+ normal.copy(eye);
6106
+ normal.normalize();
6107
+ const center = new Vector312(...start.position);
6108
+ return { normal: toVec34(normal), constant: -normal.dot(center) };
6109
+ };
6110
+ var onPlane = (grab, ray) => {
6111
+ const point = pointOnPlane2(ray, grab.plane);
6112
+ if (point === undefined)
6113
+ return;
6114
+ return new Vector312(...point).sub(new Vector312(...grab.start.position));
6115
+ };
6116
+ var backwards = (camera) => {
6117
+ const back = new Vector312(...camera.position).sub(new Vector312(...camera.lookAt));
6118
+ return back.lengthSq() > 0.000000000001 ? back.normalize() : new Vector312(0, 0, 1);
6119
+ };
6120
+ var pressGizmo2 = (state, placement, handle, ray, camera) => {
6121
+ const center = new Vector312(...placement.position);
6122
+ const facingCamera = backwards(camera);
6123
+ const towardsEye = new Vector312(...camera.position).sub(center);
6124
+ const distance = towardsEye.length();
6125
+ const eye = camera._tag === "Orthographic" || distance < 0.000000001 ? facingCamera.clone() : towardsEye.normalize();
6126
+ const plane = dragPlane(state, handle, placement, eye, facingCamera);
6127
+ const point = pointOnPlane2(ray, plane);
6128
+ if (point === undefined)
6129
+ return state;
6130
+ const from = toVec34(new Vector312(...point).sub(center));
6131
+ return { ...state, grab: { handle, start: placement, from, plane, eye: toVec34(eye), distance } };
6132
+ };
6133
+ var releaseGizmo2 = (state) => ({ ...state, grab: null });
6134
+ var hoverGizmo2 = (state, handle) => state.hovered === handle ? state : { ...state, hovered: handle };
6135
+ var snapped = (value, step) => step === null ? value : Math.round(value / step) * step;
6136
+ var includes = (handle, axis) => handle.includes(axis);
6137
+ var translated = (state, grab, end) => {
6138
+ const space = spaceOf(state, grab.handle);
6139
+ const offset = end.clone().sub(new Vector312(...grab.from));
6140
+ const turn = turnOf(grab.start.rotation);
6141
+ if (space === "local")
6142
+ offset.applyQuaternion(turn.clone().invert());
6143
+ if (!includes(grab.handle, "x"))
6144
+ offset.x = 0;
6145
+ if (!includes(grab.handle, "y"))
6146
+ offset.y = 0;
6147
+ if (!includes(grab.handle, "z"))
6148
+ offset.z = 0;
6149
+ if (space === "local") {
6150
+ const local = offset.add(new Vector312(...grab.start.position).applyQuaternion(turn.clone().invert()));
6151
+ if (includes(grab.handle, "x"))
6152
+ local.x = snapped(local.x, state.translationSnap);
6153
+ if (includes(grab.handle, "y"))
6154
+ local.y = snapped(local.y, state.translationSnap);
6155
+ if (includes(grab.handle, "z"))
6156
+ local.z = snapped(local.z, state.translationSnap);
6157
+ return { ...grab.start, position: toVec34(local.applyQuaternion(turn)) };
6158
+ }
6159
+ const position = offset.add(new Vector312(...grab.start.position));
6160
+ if (includes(grab.handle, "x"))
6161
+ position.x = snapped(position.x, state.translationSnap);
6162
+ if (includes(grab.handle, "y"))
6163
+ position.y = snapped(position.y, state.translationSnap);
6164
+ if (includes(grab.handle, "z"))
6165
+ position.z = snapped(position.z, state.translationSnap);
6166
+ return { ...grab.start, position: toVec34(position) };
6167
+ };
6168
+ var scaled2 = (state, grab, end) => {
6169
+ const from = new Vector312(...grab.from);
6170
+ const factor = new Vector312(1, 1, 1);
6171
+ if (grab.handle === "xyz") {
6172
+ const ratio = end.length() / Math.max(from.length(), 0.000000001) * (end.dot(from) < 0 ? -1 : 1);
6173
+ factor.setScalar(ratio);
6174
+ } else {
6175
+ const inverse = turnOf(grab.start.rotation).invert();
6176
+ const a = from.clone().applyQuaternion(inverse);
6177
+ const b = end.clone().applyQuaternion(inverse);
6178
+ factor.set(includes(grab.handle, "x") ? b.x / a.x : 1, includes(grab.handle, "y") ? b.y / a.y : 1, includes(grab.handle, "z") ? b.z / a.z : 1);
6179
+ }
6180
+ const step = state.scaleSnap;
6181
+ const each = (index, axis) => {
6182
+ const value = grab.start.scale[index] * factor.getComponent(index);
6183
+ if (step === null || !includes(grab.handle, axis))
6184
+ return value;
6185
+ return snapped(value, step) || step;
6186
+ };
6187
+ return { ...grab.start, scale: [each(0, "x"), each(1, "y"), each(2, "z")] };
6188
+ };
6189
+ var rotated = (state, grab, end) => {
6190
+ if (grab.handle !== "x" && grab.handle !== "y" && grab.handle !== "z")
6191
+ return grab.start;
6192
+ const space = spaceOf(state, grab.handle);
6193
+ const offset = end.clone().sub(new Vector312(...grab.from));
6194
+ const speed = 20 / Math.max(grab.distance, 0.000000001);
6195
+ const axis = axisIn(grab.handle, space, grab.start.rotation);
6196
+ const across = axis.clone().cross(new Vector312(...grab.eye));
6197
+ const angle = snapped(across.lengthSq() < 0.000000000001 ? 0 : offset.dot(across.normalize()) * speed, state.rotationSnap);
6198
+ const start = turnOf(grab.start.rotation);
6199
+ const turn = space === "local" ? start.clone().multiply(new Quaternion7().setFromAxisAngle(axes[grab.handle], angle)) : new Quaternion7().setFromAxisAngle(axes[grab.handle], angle).multiply(start);
6200
+ const euler = new Euler6().setFromQuaternion(turn.normalize());
6201
+ return { ...grab.start, rotation: [euler.x, euler.y, euler.z] };
6202
+ };
6203
+ var dragGizmo2 = (state, ray) => {
6204
+ const grab = state.grab;
6205
+ if (grab === null)
6206
+ return;
6207
+ const end = onPlane(grab, ray);
6208
+ if (end === undefined)
6209
+ return grab.start;
6210
+ if (state.mode === "translate")
6211
+ return translated(state, grab, end);
6212
+ if (state.mode === "scale")
6213
+ return scaled2(state, grab, end);
6214
+ return rotated(state, grab, end);
6215
+ };
6216
+ var movedAlike2 = (from, to, other) => {
6217
+ const turn = turnOf(to.rotation).multiply(turnOf(from.rotation).invert());
6218
+ const turned = new Euler6().setFromQuaternion(turn.multiply(turnOf(other.rotation)).normalize());
6219
+ const ratio = (axis) => from.scale[axis] === 0 ? 1 : to.scale[axis] / from.scale[axis];
6220
+ const shifted = (axis) => other.position[axis] + to.position[axis] - from.position[axis];
6221
+ return {
6222
+ position: [shifted(0), shifted(1), shifted(2)],
6223
+ rotation: [turned.x, turned.y, turned.z],
6224
+ scale: [other.scale[0] * ratio(0), other.scale[1] * ratio(1), other.scale[2] * ratio(2)]
6225
+ };
6226
+ };
6227
+ var colours = {
6228
+ x: 16725587,
6229
+ y: 9100032,
6230
+ z: 2920447,
6231
+ xy: 2920447,
6232
+ yz: 16725587,
6233
+ xz: 9100032
6234
+ };
6235
+ var highlight = 16776960;
6236
+ var hideThreshold = 0.99;
6237
+ var screenScale = (state, at, camera) => {
6238
+ if (camera._tag === "Orthographic")
6239
+ return 480 / camera.zoom * state.size / 4;
6240
+ const distance = new Vector312(...camera.position).distanceTo(new Vector312(...at));
6241
+ const spread = Math.min(1.9 * Math.tan(Math.PI * camera.fov / 360), 7);
6242
+ return distance * spread * state.size / 4;
6243
+ };
6244
+ var gizmoHandleOf2 = (key, hit) => {
6245
+ const prefix = `${key}:`;
6246
+ if (!hit.startsWith(prefix))
6247
+ return;
6248
+ const name = hit.slice(prefix.length).split(":")[0];
6249
+ const handles = ["x", "y", "z", "xy", "yz", "xz", "xyz"];
6250
+ return handles.find((handle) => handle === name);
6251
+ };
6252
+ var look = (state, handle, colour) => basic2({
6253
+ color: state.grab?.handle === handle || state.hovered === handle ? highlight : colour,
6254
+ transparent: true,
6255
+ opacity: state.grab !== null && state.grab.handle !== handle ? 0.25 : 0.9,
6256
+ depthTest: false
6257
+ });
6258
+ var pointAlong = { x: [0, 0, -Math.PI / 2], y: [0, 0, 0], z: [Math.PI / 2, 0, 0] };
6259
+ var tips = { x: [0.5, 0, 0], y: [0, 0.5, 0], z: [0, 0, 0.5] };
6260
+ var ringRound = { x: [0, Math.PI / 2, 0], y: [Math.PI / 2, 0, 0], z: [0, 0, 0] };
6261
+ var ring = (key, state, axis) => [
6262
+ mesh2({
6263
+ key: `${key}:${axis}`,
6264
+ rotation: fixed2([...ringRound[axis]]),
6265
+ geometry: torus2({ radius: 0.5, tube: 0.02, radialSegments: 6, tubularSegments: 48 }),
6266
+ material: look(state, axis, colours[axis]),
6267
+ interactive: true
6268
+ })
6269
+ ];
6270
+ var arrow = (key, state, axis) => {
6271
+ const along = pointAlong[axis];
6272
+ const tipAt = tips[axis];
6273
+ const material = look(state, axis, colours[axis]);
6274
+ return [
6275
+ mesh2({
6276
+ key: `${key}:${axis}:stem`,
6277
+ position: [tipAt[0] / 2, tipAt[1] / 2, tipAt[2] / 2],
6278
+ rotation: fixed2([...along]),
6279
+ geometry: cylinder2({ radiusTop: 0.012, radiusBottom: 0.012, height: 0.5 }),
6280
+ material,
6281
+ interactive: true
6282
+ }),
6283
+ mesh2({
6284
+ key: `${key}:${axis}:tip`,
6285
+ position: tipAt,
6286
+ rotation: fixed2([...along]),
6287
+ geometry: state.mode === "scale" ? box2({ width: 0.08, height: 0.08, depth: 0.08 }) : cone2({ radius: 0.04, height: 0.12, radialSegments: 12 }),
6288
+ material,
6289
+ interactive: true
6290
+ })
6291
+ ];
6292
+ };
6293
+ var axisHandles = (key, state, visible) => ["x", "y", "z"].filter(visible).flatMap((axis) => state.mode === "rotate" ? ring(key, state, axis) : arrow(key, state, axis));
6294
+ var planeHandles = (key, state) => {
6295
+ if (state.mode === "rotate")
6296
+ return [];
6297
+ const squares = [
6298
+ {
6299
+ handle: "xy",
6300
+ at: [0.15, 0.15, 0],
6301
+ turn: [0, 0, 0],
6302
+ shown: state.showX && state.showY
6303
+ },
6304
+ {
6305
+ handle: "yz",
6306
+ at: [0, 0.15, 0.15],
6307
+ turn: [0, Math.PI / 2, 0],
6308
+ shown: state.showY && state.showZ
6309
+ },
6310
+ {
6311
+ handle: "xz",
6312
+ at: [0.15, 0, 0.15],
6313
+ turn: [-Math.PI / 2, 0, 0],
6314
+ shown: state.showX && state.showZ
6315
+ }
6316
+ ];
6317
+ return squares.filter((square) => square.shown).map((square) => mesh2({
6318
+ key: `${key}:${square.handle}`,
6319
+ position: square.at,
6320
+ rotation: fixed2([...square.turn]),
6321
+ geometry: plane2({ width: 0.12, height: 0.12 }),
6322
+ material: { ...look(state, square.handle, colours[square.handle]), side: "double" },
6323
+ interactive: true
6324
+ }));
6325
+ };
6326
+ var gizmoNodes2 = (key, state, placement, camera) => {
6327
+ const space = spaceOf(state, state.grab?.handle ?? null);
6328
+ const scale = screenScale(state, placement.position, camera);
6329
+ const eye = new Vector312(...camera.position).sub(new Vector312(...placement.position)).normalize();
6330
+ const shown = { x: state.showX, y: state.showY, z: state.showZ };
6331
+ const visible = (axis) => shown[axis] && (state.mode === "rotate" || state.grab?.handle === axis || Math.abs(axisIn(axis, space, placement.rotation).dot(eye)) <= hideThreshold);
6332
+ return group2({
6333
+ key,
6334
+ position: placement.position,
6335
+ rotation: fixed2(space === "local" ? placement.rotation : [0, 0, 0]),
6336
+ scale: [scale, scale, scale],
6337
+ children: [
6338
+ ...axisHandles(key, state, visible),
6339
+ ...planeHandles(key, state),
6340
+ ...state.mode === "rotate" ? [] : [
6341
+ mesh2({
6342
+ key: `${key}:xyz`,
6343
+ geometry: state.mode === "scale" ? box2({ width: 0.1, height: 0.1, depth: 0.1 }) : sphere2({ radius: 0.06, widthSegments: 12, heightSegments: 8 }),
6344
+ material: look(state, "xyz", 16777215),
6345
+ interactive: true
6346
+ })
6347
+ ]
6348
+ ]
6349
+ });
6350
+ };
6351
+ // src/kernel/boxSelect.ts
6352
+ import { OrthographicCamera as OrthographicCamera5, PerspectiveCamera as PerspectiveCamera4, Vector3 as Vector313 } from "three";
6353
+ var hostCamera2 = (camera, size) => {
6354
+ const host = camera._tag === "Perspective" ? new PerspectiveCamera4(camera.fov, size.width / size.height, camera.near, camera.far) : new OrthographicCamera5(size.width / -2, size.width / 2, size.height / 2, size.height / -2, camera.near, camera.far);
6355
+ if (host instanceof OrthographicCamera5 && camera._tag === "Orthographic") {
6356
+ host.zoom = camera.zoom;
6357
+ }
6358
+ host.position.set(...camera.position);
6359
+ host.lookAt(...camera.lookAt);
6360
+ host.updateMatrixWorld();
6361
+ host.updateProjectionMatrix();
6362
+ return host;
6363
+ };
6364
+ var between2 = (value, a, b) => value >= Math.min(a, b) && value <= Math.max(a, b);
6365
+ var boxSelect2 = (camera, size, from, to, candidates) => {
6366
+ const host = hostCamera2(camera, size);
6367
+ const inside = (candidate) => {
6368
+ const seen = new Vector313(...candidate.at).project(host);
6369
+ return between2(seen.x, from.x, to.x) && between2(seen.y, from.y, to.y) && between2(seen.z, -1, 1);
6370
+ };
6371
+ return candidates.filter(inside).map((candidate) => candidate.key);
6372
+ };
6373
+ // src/kernel/history.ts
6374
+ var make = (value, label = "Start") => ({
6375
+ entries: [{ id: 0, parent: null, label, value, next: null }],
6376
+ current: 0
6377
+ });
6378
+ var entryOf = (state, id) => {
6379
+ const entry = state.entries[id];
6380
+ if (entry === undefined)
6381
+ throw new RangeError(`No history entry ${id}`);
6382
+ return entry;
6383
+ };
6384
+ var presentEntry = (state) => entryOf(state, state.current);
6385
+ var present = (state) => presentEntry(state).value;
6386
+ var withNext = (state, id, next) => ({
6387
+ ...state,
6388
+ entries: state.entries.map((entry) => entry.id === id ? { ...entry, next } : entry)
6389
+ });
6390
+ var record = (state, value, label) => {
6391
+ const id = state.entries.length;
6392
+ const grown = {
6393
+ entries: [...state.entries, { id, parent: state.current, label, value, next: null }],
6394
+ current: id
6395
+ };
6396
+ return withNext(grown, state.current, id);
6397
+ };
6398
+ var canUndo = (state) => presentEntry(state).parent !== null;
6399
+ var canRedo = (state) => presentEntry(state).next !== null;
6400
+ var undo = (state) => {
6401
+ const parent = presentEntry(state).parent;
6402
+ return parent === null ? state : { ...state, current: parent };
6403
+ };
6404
+ var redo = (state) => {
6405
+ const next = presentEntry(state).next;
6406
+ return next === null ? state : { ...state, current: next };
6407
+ };
6408
+ var branches = (state) => state.entries.filter((entry) => entry.parent === state.current);
6409
+ var chooseBranch = (state, id) => branches(state).some((entry) => entry.id === id) ? withNext(state, state.current, id) : state;
6410
+ var pathTo = (state, id) => {
6411
+ const path = [];
6412
+ for (let at = id;at !== null; at = entryOf(state, at).parent) {
6413
+ path.unshift(entryOf(state, at));
6414
+ }
6415
+ return path;
6416
+ };
6417
+ var jumpTo = (state, id) => {
6418
+ const path = pathTo(state, id);
6419
+ const chosen = path.slice(1).reduce((at, entry) => withNext(at, entry.parent ?? 0, entry.id), state);
6420
+ return { ...chosen, current: id };
6421
+ };
6422
+ var depth = (state) => pathTo(state, state.current).length - 1;
6423
+ // src/kernel/lockstep.ts
6424
+ var sortedPeers = (members) => members.toSorted((a, b) => a.peer < b.peer ? -1 : a.peer > b.peer ? 1 : 0);
6425
+ var memberAt = (member, turn) => member.from <= turn && (member.until === null || turn < member.until);
6426
+ var membersAt = (state, turn) => sortedPeers(state.members.filter((member) => memberAt(member, turn))).map((member) => member.peer);
6427
+ var leaderAt = (state, turn) => membersAt(state, turn)[0];
6428
+ var make2 = (self, lead = 2) => ({
6429
+ self,
6430
+ members: [{ peer: self, from: 0, until: null }],
6431
+ turn: 0,
6432
+ sent: 0,
6433
+ lead,
6434
+ pending: [],
6435
+ received: []
6436
+ });
6437
+ var join = (self, welcome, heard = []) => ({
6438
+ self,
6439
+ members: welcome.members,
6440
+ turn: welcome.turn,
6441
+ sent: welcome.turn,
6442
+ lead: welcome.lead,
6443
+ pending: [],
6444
+ received: heard.filter((packet) => packet.turn >= welcome.turn)
6445
+ });
6446
+ var submit = (state, input) => ({
6447
+ ...state,
6448
+ pending: [...state.pending, { _tag: "Input", input }]
6449
+ });
6450
+ var known = (state, peer) => state.members.some((member) => member.peer === peer && member.until === null) || state.pending.some((entry) => entry._tag === "Admit" && entry.peer === peer);
6451
+ var admit = (state, peer) => leaderAt(state, state.sent) !== state.self || known(state, peer) ? state : { ...state, pending: [...state.pending, { _tag: "Admit", peer }] };
6452
+ var hasPacket = (state, peer, turn) => state.received.some((packet) => packet.peer === peer && packet.turn === turn);
6453
+ var receive = (state, packet) => {
6454
+ if (packet.turn < state.turn || hasPacket(state, packet.peer, packet.turn))
6455
+ return state;
6456
+ const member = state.members.find((each) => each.peer === packet.peer);
6457
+ if (member !== undefined && !memberAt(member, packet.turn))
6458
+ return state;
6459
+ return { ...state, received: [...state.received, packet] };
6460
+ };
6461
+ var send = (state) => {
6462
+ const member = state.members.find((each) => each.peer === state.self);
6463
+ const ahead = state.sent >= state.turn + state.lead;
6464
+ if (member === undefined || !memberAt(member, state.sent) || ahead) {
6465
+ return { state, packet: undefined };
6466
+ }
6467
+ const packet = { peer: state.self, turn: state.sent, entries: state.pending };
6468
+ return {
6469
+ state: { ...state, sent: state.sent + 1, pending: [], received: [...state.received, packet] },
6470
+ packet
6471
+ };
6472
+ };
6473
+ var waitingOn = (state) => membersAt(state, state.turn).filter((peer) => !hasPacket(state, peer, state.turn));
6474
+ var packetsOf = (state, peer, turn) => state.received.filter((packet) => packet.peer === peer && packet.turn === turn);
6475
+ var applyTurn = (state) => {
6476
+ const turn = state.turn;
6477
+ const packets = membersAt(state, turn).flatMap((peer) => packetsOf(state, peer, turn));
6478
+ const entries = packets.flatMap((packet) => packet.entries.map((entry) => ({ peer: packet.peer, entry })));
6479
+ const admitted = entries.flatMap(({ entry }) => entry._tag === "Admit" && !state.members.some((member) => member.peer === entry.peer) ? [{ peer: entry.peer, from: turn + state.lead + 1, until: null }] : []);
6480
+ const applied = entries.flatMap(({ peer, entry }) => entry._tag === "Input" ? [{ turn, peer, input: entry.input }] : []);
6481
+ return {
6482
+ state: {
6483
+ ...state,
6484
+ turn: turn + 1,
6485
+ members: [...state.members, ...admitted],
6486
+ received: state.received.filter((packet) => packet.turn > turn)
6487
+ },
6488
+ applied
6489
+ };
6490
+ };
6491
+ var advance = (state) => {
6492
+ let current = state;
6493
+ const applied = [];
6494
+ while (membersAt(current, current.turn).length > 0 && waitingOn(current).length === 0) {
6495
+ const next = applyTurn(current);
6496
+ current = next.state;
6497
+ applied.push(...next.applied);
6498
+ }
6499
+ return { state: current, applied };
6500
+ };
6501
+ var welcomeDue = (before, state) => state.members.filter((member) => member.from > before && member.from <= state.turn).filter((member) => leaderAt(state, member.from - 1) === state.self).map((member) => member.peer);
6502
+ var leave = (state) => state.sent - 1;
6503
+ var remove = (state, peer, until) => ({
6504
+ ...state,
6505
+ members: state.members.map((member) => member.peer === peer && (member.until === null || until < member.until) ? { ...member, until } : member),
6506
+ received: state.received.filter((packet) => packet.peer !== peer || packet.turn < until)
6507
+ });
6508
+ // src/kernel/describeScene.ts
6509
+ var extentOf = (geometry) => {
6510
+ switch (geometry._tag) {
6511
+ case "Box":
6512
+ case "RoundedBox":
6513
+ return [geometry.width, geometry.height, geometry.depth];
6514
+ case "Sphere":
6515
+ return [geometry.radius * 2, geometry.radius * 2, geometry.radius * 2];
6516
+ case "Cone":
6517
+ return [geometry.radius * 2, geometry.height, geometry.radius * 2];
6518
+ case "Cylinder": {
6519
+ const across = Math.max(geometry.radiusTop, geometry.radiusBottom) * 2;
6520
+ return [across, geometry.height, across];
6521
+ }
6522
+ case "Capsule":
6523
+ return [geometry.radius * 2, geometry.height + geometry.radius * 2, geometry.radius * 2];
6524
+ case "Torus": {
6525
+ const across = (geometry.radius + geometry.tube) * 2;
6526
+ return [across, across, geometry.tube * 2];
6527
+ }
6528
+ case "Plane":
6529
+ return [geometry.width, geometry.height, 0];
6530
+ case "Circle":
6531
+ return [geometry.radius * 2, geometry.radius * 2, 0];
6532
+ case "Ring":
6533
+ return [geometry.outerRadius * 2, geometry.outerRadius * 2, 0];
6534
+ default:
6535
+ return;
6536
+ }
6537
+ };
6538
+ var scaled3 = (extent, scale) => [
6539
+ extent[0] * Math.abs(scale[0]),
6540
+ extent[1] * Math.abs(scale[1]),
6541
+ extent[2] * Math.abs(scale[2])
6542
+ ];
6543
+ var shapeOf = (geometry, description) => {
6544
+ if (geometry._tag === "LentGeometry")
6545
+ return;
6546
+ if (geometry._tag !== "SharedGeometry")
6547
+ return geometry;
6548
+ return description.resources.geometries.find((entry) => entry.id === geometry.id)?.geometry;
6549
+ };
6550
+ var sizeOf = (node, description) => {
6551
+ if (node._tag !== "Mesh")
6552
+ return null;
6553
+ const shape = shapeOf(node.geometry, description);
6554
+ const extent = shape === undefined ? undefined : extentOf(shape);
6555
+ return extent === undefined ? null : scaled3(extent, node.scale);
6556
+ };
6557
+ var colourOf = (node) => node._tag === "Mesh" && ("color" in node.material) ? node.material.color : null;
6558
+ var kindOf = (node) => node._tag === "Mesh" ? `Mesh (${node.geometry._tag})` : node._tag;
6559
+ var isLight = (node) => node._tag.endsWith("Light");
6560
+ var lightOf = (node) => {
6561
+ if (!isLight(node) || !("color" in node) || !("intensity" in node))
6562
+ return [];
6563
+ return [
6564
+ {
6565
+ key: node.key,
6566
+ kind: node._tag,
6567
+ colour: node.color,
6568
+ intensity: node.intensity,
6569
+ position: "position" in node ? node.position : null
6570
+ }
6571
+ ];
6572
+ };
6573
+ var thingsIn = (nodes, parent, description) => nodes.flatMap((node) => [
6574
+ ...isLight(node) ? [] : [
6575
+ {
6576
+ key: node.key,
6577
+ kind: kindOf(node),
6578
+ position: "position" in node ? node.position : [0, 0, 0],
6579
+ size: sizeOf(node, description),
6580
+ colour: colourOf(node),
6581
+ parent
6582
+ }
6583
+ ],
6584
+ ...node._tag === "Group" ? thingsIn(node.children, node.key, description) : []
6585
+ ]);
6586
+ var lightsIn = (nodes) => nodes.flatMap((node) => [
6587
+ ...lightOf(node),
6588
+ ...node._tag === "Group" ? lightsIn(node.children) : []
6589
+ ]);
6590
+ var thingsBounds2 = (things) => {
6591
+ const sized = things.filter((thing) => thing.parent === null && thing.size !== null);
6592
+ if (sized.length === 0)
6593
+ return null;
6594
+ const edge = (axis, sign) => sized.map((thing) => thing.position[axis] + sign * ((thing.size?.[axis] ?? 0) / 2));
6595
+ const low = (axis) => Math.min(...edge(axis, -1));
6596
+ const high = (axis) => Math.max(...edge(axis, 1));
6597
+ return { min: [low(0), low(1), low(2)], max: [high(0), high(1), high(2)] };
6598
+ };
6599
+ var stagingOf = (description) => [
6600
+ ...description.environment === null ? [] : ["environment lighting"],
6601
+ ...description.sky === null ? [] : ["sky"],
6602
+ ...description.render.shadows === "off" ? [] : [`${description.render.shadows} shadows`],
6603
+ ...description.contactShadows === null ? [] : ["contact shadows"],
6604
+ ...description.render.effects.map((effect) => effect._tag.toLowerCase()),
6605
+ ...description.physics === null ? [] : ["physics"]
6606
+ ];
6607
+ var describeScene2 = (description) => {
6608
+ const things = thingsIn(description.children, null, description);
6609
+ return {
6610
+ camera: {
6611
+ kind: description.camera._tag,
6612
+ position: description.camera.position,
6613
+ lookAt: description.camera.lookAt
6614
+ },
6615
+ things,
6616
+ lights: lightsIn(description.children),
6617
+ bounds: thingsBounds2(things),
6618
+ staging: stagingOf(description)
6619
+ };
6620
+ };
6621
+ var number = (value) => String(Math.round(value * 100) / 100);
6622
+ var point2 = (at) => `(${at.map(number).join(", ")})`;
6623
+ var hex = (colour) => `#${colour.toString(16).padStart(6, "0")}`;
6624
+ var thingLine = (thing) => [
6625
+ `- ${thing.key}: ${thing.kind}`,
6626
+ thing.size === null ? "" : `, ${thing.size.map(number).join(" × ")}`,
6627
+ thing.colour === null ? "" : `, ${hex(thing.colour)}`,
6628
+ `, at ${point2(thing.position)}`,
6629
+ thing.parent === null ? "" : ` in ${thing.parent}`
6630
+ ].join("");
6631
+ var lightLine = (light) => `- ${light.key}: ${light.kind}, ${hex(light.colour)} × ${number(light.intensity)}${light.position === null ? "" : ` at ${point2(light.position)}`}`;
6632
+ var formatSummary2 = (summary) => [
6633
+ `Camera: ${summary.camera.kind.toLowerCase()} at ${point2(summary.camera.position)}, looking at ${point2(summary.camera.lookAt)}`,
6634
+ `Things (${summary.things.length})${summary.bounds === null ? "" : `, within ${point2(summary.bounds.min)} to ${point2(summary.bounds.max)}`}:`,
6635
+ ...summary.things.map(thingLine),
6636
+ `Lights (${summary.lights.length}):`,
6637
+ ...summary.lights.map(lightLine),
6638
+ `Staging: ${summary.staging.length === 0 ? "none" : summary.staging.join(", ")}`
6639
+ ].join(`
6640
+ `);
6641
+ // src/kernel/shots.ts
6642
+ import { Vector3 as Vector314 } from "three";
6643
+ var shotAngles2 = [
6644
+ "front",
6645
+ "back",
6646
+ "left",
6647
+ "right",
6648
+ "top",
6649
+ "three-quarter",
6650
+ "low"
6651
+ ];
6652
+ var directionOf = {
6653
+ front: [0, 0.15, 1],
6654
+ back: [0, 0.15, -1],
6655
+ left: [-1, 0.15, 0],
6656
+ right: [1, 0.15, 0],
6657
+ top: [0, 1, 0.0001],
6658
+ "three-quarter": [1, 0.7, 1],
6659
+ low: [0.35, -0.02, 1]
6660
+ };
6661
+ var shotCamera2 = (camera, subject, angle, area = { width: 16, height: 10 }, margin = 1.3) => {
6662
+ const centre = new Vector314(...subject.min).add(new Vector314(...subject.max)).multiplyScalar(0.5);
6663
+ const from = new Vector314(...directionOf[angle]).normalize().add(centre);
6664
+ const aimed = {
6665
+ ...camera,
6666
+ position: [from.x, from.y, from.z],
6667
+ lookAt: [centre.x, centre.y, centre.z]
6668
+ };
6669
+ return fitCamera2(aimed, subject, area, margin);
6670
+ };
6671
+ var moods2 = ["studio", "daylight", "sunset", "night"];
6672
+ var moodStaging2 = (mood, prefix = "mood") => {
6673
+ switch (mood) {
6674
+ case "studio":
6675
+ return {
6676
+ lights: [
6677
+ hemisphereLight2({
6678
+ key: `${prefix}:fill`,
6679
+ color: 16777215,
6680
+ groundColor: 7301730,
6681
+ intensity: 0.8
6682
+ }),
6683
+ directionalLight2({
6684
+ key: `${prefix}:key`,
6685
+ position: [4, 7, 3],
6686
+ intensity: 2,
6687
+ castShadow: true
6688
+ })
6689
+ ],
6690
+ environment: environment2({ environmentIntensity: 0.35 }),
6691
+ sky: null
6692
+ };
6693
+ case "daylight":
6694
+ return {
6695
+ lights: [
6696
+ hemisphereLight2({
6697
+ key: `${prefix}:sky`,
6698
+ color: 13625087,
6699
+ groundColor: 9075296,
6700
+ intensity: 1
6701
+ }),
6702
+ directionalLight2({
6703
+ key: `${prefix}:sun`,
6704
+ position: [6, 9, 4],
6705
+ intensity: 3,
6706
+ castShadow: true
6707
+ })
6708
+ ],
6709
+ environment: environment2({ environmentIntensity: 0.25 }),
6710
+ sky: sky2({ sunPosition: sunPositionFromAngles2(0.85, 0.35) })
6711
+ };
6712
+ case "sunset":
6713
+ return {
6714
+ lights: [
6715
+ hemisphereLight2({
6716
+ key: `${prefix}:sky`,
6717
+ color: 16757370,
6718
+ groundColor: 3811904,
6719
+ intensity: 0.6
6720
+ }),
6721
+ directionalLight2({
6722
+ key: `${prefix}:sun`,
6723
+ color: 16751194,
6724
+ position: [-8, 2.5, 3],
6725
+ intensity: 2.5,
6726
+ castShadow: true
6727
+ })
6728
+ ],
6729
+ environment: null,
6730
+ sky: sky2({ sunPosition: sunPositionFromAngles2(0.52, 0.25), turbidity: 8, rayleigh: 3 })
6731
+ };
6732
+ case "night":
6733
+ return {
6734
+ lights: [
6735
+ hemisphereLight2({
6736
+ key: `${prefix}:sky`,
6737
+ color: 3820160,
6738
+ groundColor: 1052696,
6739
+ intensity: 0.35
6740
+ }),
6741
+ directionalLight2({
6742
+ key: `${prefix}:moon`,
6743
+ color: 11190271,
6744
+ position: [-3, 8, -4],
6745
+ intensity: 0.8,
6746
+ castShadow: true
6747
+ })
6748
+ ],
6749
+ environment: null,
6750
+ sky: null
6751
+ };
6752
+ }
6753
+ };
6754
+ // src/kernel/inspect.ts
6755
+ var resolve = (ast) => ast._tag === "Suspend" && ("thunk" in ast) ? resolve(ast.thunk()) : ast;
6756
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
6757
+ var labelOf = (path) => String(path.at(-1) ?? "value");
6758
+ var literalOf = (ast) => ("literal" in ast) ? ast.literal : undefined;
6759
+ var tagOf = (ast) => {
6760
+ const member = resolve(ast);
6761
+ if (!("propertySignatures" in member))
6762
+ return;
6763
+ const tag = member.propertySignatures.find((property) => property.name === "_tag");
6764
+ return tag === undefined ? undefined : literalOf(resolve(tag.type));
6765
+ };
6766
+ var memberFor = (types, value) => {
6767
+ if (isRecord(value) && "_tag" in value) {
6768
+ const tagged = types.find((member) => tagOf(member) === value["_tag"]);
6769
+ if (tagged !== undefined)
6770
+ return tagged;
6771
+ }
6772
+ if (value === null)
6773
+ return types.find((member) => resolve(member)._tag === "Null");
6774
+ return types.find((member) => resolve(member)._tag !== "Null") ?? types[0];
6775
+ };
6776
+ var fixed = (path, text) => ({
6777
+ _tag: "Fixed",
6778
+ path,
6779
+ label: labelOf(path),
6780
+ text
6781
+ });
6782
+ var isVector = (value) => Array.isArray(value) && value.length === 3 && value.every((n) => typeof n === "number");
6783
+ var walk = (given, value, path, hints) => {
6784
+ const ast = resolve(given);
6785
+ const label = labelOf(path);
6786
+ if (hints.colours.includes(ast) && typeof value === "number") {
6787
+ return [{ _tag: "Colour", path, label, value }];
6788
+ }
6789
+ if (hints.vectors.includes(ast) && isVector(value)) {
6790
+ return [{ _tag: "Vector", path, label, value }];
6791
+ }
6792
+ switch (ast._tag) {
6793
+ case "Number":
6794
+ return typeof value === "number" ? [{ _tag: "Number", path, label, value }] : [];
6795
+ case "String":
6796
+ return typeof value === "string" ? [{ _tag: "Text", path, label, value }] : [];
6797
+ case "Boolean":
6798
+ return typeof value === "boolean" ? [{ _tag: "Toggle", path, label, value }] : [];
6799
+ case "Literal":
6800
+ case "Null":
6801
+ return [fixed(path, String(value))];
6802
+ case "Union":
6803
+ return "types" in ast ? unionFields(ast.types, value, path, hints) : [];
6804
+ case "Objects":
6805
+ return "propertySignatures" in ast ? objectFields(ast, value, path, hints) : [];
6806
+ case "Arrays":
6807
+ return "elements" in ast ? arrayFields(ast, value, path, hints) : [];
6808
+ default:
6809
+ return [fixed(path, String(value))];
6810
+ }
6811
+ };
6812
+ var unionFields = (types, value, path, hints) => {
6813
+ const literals = types.map((member) => literalOf(resolve(member)));
6814
+ if (typeof value === "string" && literals.every((literal) => typeof literal === "string")) {
6815
+ return [{ _tag: "Choice", path, label: labelOf(path), value, options: literals.map(String) }];
6816
+ }
6817
+ const member = memberFor(types, value);
6818
+ return member === undefined ? [fixed(path, String(value))] : walk(member, value, path, hints);
6819
+ };
6820
+ var objectFields = (ast, value, path, hints) => {
6821
+ if (!isRecord(value))
6822
+ return [fixed(path, String(value))];
6823
+ return ast.propertySignatures.flatMap((property) => propertyFields(String(property.name), property.type, value, path, hints));
6824
+ };
6825
+ function propertyFields(name, type, value, path, hints) {
6826
+ if (!(name in value))
6827
+ return [];
6828
+ if (name === "_tag")
6829
+ return [fixed([...path, name], String(value[name]))];
6830
+ return walk(type, value[name], [...path, name], hints);
6831
+ }
6832
+ var arrayFields = (ast, value, path, hints) => {
6833
+ if (!Array.isArray(value))
6834
+ return [fixed(path, String(value))];
6835
+ if (ast.rest.length > 0) {
6836
+ return [fixed(path, `${value.length} ${value.length === 1 ? "item" : "items"}`)];
6837
+ }
6838
+ return ast.elements.flatMap((element, index) => walk(element, value[index], [...path, index], hints));
6839
+ };
6840
+ var inspectFields2 = (ast, value, hints = { colours: [], vectors: [] }) => walk(ast, value, [], hints);
6841
+ var setAt2 = (value, path, next) => {
6842
+ const [head, ...rest] = path;
6843
+ if (head === undefined)
6844
+ return next;
6845
+ if (Array.isArray(value) && typeof head === "number") {
6846
+ return value.map((item, index) => index === head ? setAt2(item, rest, next) : item);
6847
+ }
6848
+ if (isRecord(value) && typeof head === "string") {
6849
+ return { ...value, [head]: setAt2(value[head], rest, next) };
6850
+ }
6851
+ return value;
6852
+ };
6853
+ // src/kernel/sceneChanges.ts
6854
+ var settingOf = {
6855
+ SetCamera: "camera",
6856
+ SetViews: "views",
6857
+ SetRenderSettings: "render",
6858
+ DefineResources: "resources"
6859
+ };
6860
+ var comparedSettings = [
6861
+ "gestures",
6862
+ "overlays",
6863
+ "environment",
6864
+ "sky",
6865
+ "contactShadows",
6866
+ "physics",
6867
+ "xr",
6868
+ "measure"
6869
+ ];
6870
+ var entriesOf = (value) => Object.entries(value);
6871
+ var same = (a, b) => {
6872
+ if (a === b)
6873
+ return true;
6874
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null)
6875
+ return false;
6876
+ if (Array.isArray(a) !== Array.isArray(b))
6877
+ return false;
6878
+ const fieldsA = entriesOf(a);
6879
+ const fieldsB = new Map(entriesOf(b));
6880
+ return fieldsA.length === fieldsB.size && fieldsA.every(([key, value]) => fieldsB.has(key) && same(value, fieldsB.get(key)));
6881
+ };
6882
+ var nodeChange = (op, place) => {
6883
+ switch (op._tag) {
6884
+ case "Create":
6885
+ return [{ place, _tag: "Added", key: op.node.key, kind: op.node._tag, parent: op.parent }];
6886
+ case "Remove":
6887
+ return [{ place, _tag: "Removed", key: op.key }];
6888
+ case "Replace":
6889
+ return [{ place, _tag: "Replaced", key: op.node.key, kind: op.node._tag }];
6890
+ case "Update":
6891
+ return [{ place, _tag: "Changed", key: op.node.key, fields: op.fields }];
6892
+ case "Move":
6893
+ return [{ place, _tag: "Moved", key: op.key, parent: op.parent }];
6894
+ case "Order":
6895
+ return [{ place, _tag: "Reordered", parent: op.parent, keys: op.keys }];
6896
+ default:
6897
+ return [];
6898
+ }
6899
+ };
6900
+ var behavioursIn = (description) => {
6901
+ const names = new Set;
6902
+ const visit = (node) => {
6903
+ if ("behaviour" in node && node.behaviour !== null)
6904
+ names.add(node.behaviour.name);
6905
+ if (node._tag === "Group")
6906
+ node.children.forEach(visit);
6907
+ };
6908
+ description.children.forEach(visit);
6909
+ return names;
6910
+ };
6911
+ var startOf = (before) => {
6912
+ const indexed = indexScene2(before, behavioursIn(before));
6913
+ return indexed._tag === "Indexed" ? indexed.index : emptyIndex2;
6914
+ };
6915
+ var isSetting = (setting) => setting !== undefined;
6916
+ var settingsOf = (before, after, ops) => [
6917
+ ...ops.map((op) => settingOf[op._tag]).filter(isSetting),
6918
+ ...comparedSettings.filter((setting) => !same(before[setting], after[setting]))
6919
+ ];
6920
+ var changesIn = (before, after, place) => {
6921
+ const result = diff2(startOf(before), after, behavioursIn(after));
6922
+ if (result._tag === "Invalid")
6923
+ return result;
6924
+ const settings = settingsOf(before, after, result.ops);
6925
+ const settingsChange = settings.length === 0 ? [] : [{ place, _tag: "Settings", settings }];
6926
+ return {
6927
+ _tag: "Changes",
6928
+ changes: [...settingsChange, ...result.ops.flatMap((op) => nodeChange(op, place))]
6929
+ };
6930
+ };
6931
+ var nestedScene = (parent, children) => ({ ...parent, hud: null, renderTextures: [], children });
6932
+ var hudChanges = (before, after) => {
6933
+ if (before.hud === null && after.hud === null)
6934
+ return { _tag: "Changes", changes: [] };
6935
+ if (after.hud === null)
6936
+ return { _tag: "Changes", changes: [{ place: "hud", _tag: "HudRemoved" }] };
6937
+ const added = before.hud === null ? [{ place: "hud", _tag: "HudAdded" }] : [];
6938
+ const inside = changesIn(nestedScene(before, before.hud?.children ?? []), nestedScene(before, after.hud.children), "hud");
6939
+ return inside._tag === "Invalid" ? inside : { _tag: "Changes", changes: [...added, ...inside.changes] };
6940
+ };
6941
+ var textureChanges = (before, after) => {
6942
+ const changes = [];
6943
+ for (const texture of after.renderTextures) {
6944
+ const was = before.renderTextures.find((candidate) => candidate.id === texture.id);
6945
+ const place = { texture: texture.id };
6946
+ if (was === undefined)
6947
+ changes.push({ place, _tag: "TextureAdded", id: texture.id });
6948
+ const inside = changesIn(nestedScene(before, was?.children ?? []), nestedScene(before, texture.children), place);
6949
+ if (inside._tag === "Invalid")
6950
+ return inside;
6951
+ changes.push(...inside.changes);
6952
+ }
6953
+ for (const texture of before.renderTextures) {
6954
+ if (!after.renderTextures.some((candidate) => candidate.id === texture.id)) {
6955
+ changes.push({ place: { texture: texture.id }, _tag: "TextureRemoved", id: texture.id });
6956
+ }
6957
+ }
6958
+ return { _tag: "Changes", changes };
6959
+ };
6960
+ var sceneChanges2 = (before, after) => {
6961
+ const parts = [
6962
+ changesIn(before, after, "scene"),
6963
+ hudChanges(before, after),
6964
+ textureChanges(before, after)
6965
+ ];
6966
+ const invalid = parts.find((part) => part._tag === "Invalid");
6967
+ if (invalid !== undefined)
6968
+ return invalid;
6969
+ return {
6970
+ _tag: "Changes",
6971
+ changes: parts.flatMap((part) => part._tag === "Changes" ? part.changes : [])
6972
+ };
6973
+ };
6974
+ var placeLabel = (place) => {
6975
+ if (place === "scene")
6976
+ return "";
6977
+ return place === "hud" ? "hud " : `texture ${place.texture} `;
6978
+ };
6979
+ var parentLabel = (parent) => parent === null ? "the root" : parent;
6980
+ var lineOf2 = (change) => {
6981
+ const where = placeLabel(change.place);
6982
+ switch (change._tag) {
6983
+ case "Added":
6984
+ return `${where}+ ${change.kind} ${change.key}${change.parent === null ? "" : ` in ${change.parent}`}`;
6985
+ case "Removed":
6986
+ return `${where}- ${change.key}`;
6987
+ case "Replaced":
6988
+ return `${where}± ${change.key}, now a ${change.kind}`;
6989
+ case "Changed":
6990
+ return `${where}~ ${change.key}: ${change.fields.join(", ")}`;
6991
+ case "Moved":
6992
+ return `${where}> ${change.key} to ${parentLabel(change.parent)}`;
6993
+ case "Reordered":
6994
+ return `${where}= order of ${parentLabel(change.parent)}: ${change.keys.join(", ")}`;
6995
+ case "Settings":
6996
+ return `${where}⋯ scene: ${change.settings.join(", ")}`;
6997
+ case "HudAdded":
6998
+ return "+ hud";
6999
+ case "HudRemoved":
7000
+ return "- hud";
7001
+ case "TextureAdded":
7002
+ return `+ texture ${change.id}`;
7003
+ case "TextureRemoved":
7004
+ return `- texture ${change.id}`;
7005
+ }
7006
+ };
7007
+ var formatChanges2 = (changes) => changes.length === 0 ? "No changes." : changes.map(lineOf2).join(`
7008
+ `);
7009
+ // src/kernel/tape.ts
7010
+ var tape2 = (options = {}) => ({
7011
+ from: null,
7012
+ to: null,
7013
+ pointer: null,
7014
+ snap: options.snap ?? null
7015
+ });
7016
+ var snapped2 = (state, point) => {
7017
+ const step = state.snap;
7018
+ if (step === null)
7019
+ return point;
7020
+ return [
7021
+ Math.round(point[0] / step) * step,
7022
+ Math.round(point[1] / step) * step,
7023
+ Math.round(point[2] / step) * step
7024
+ ];
7025
+ };
7026
+ var placeTapeEnd2 = (state, point) => {
7027
+ const at = snapped2(state, point);
7028
+ if (state.from !== null && state.to === null)
7029
+ return { ...state, to: at, pointer: null };
7030
+ return { ...state, from: at, to: null, pointer: null };
7031
+ };
7032
+ var pointTape2 = (state, point) => state.from !== null && state.to === null ? { ...state, pointer: point === null ? null : snapped2(state, point) } : state;
7033
+ var clearTape2 = (state) => ({ ...tape2({ snap: state.snap }) });
7034
+ var farEnd = (state) => state.to ?? state.pointer;
7035
+ var distance = (a, b) => Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
7036
+ var tapeLength2 = (state) => {
7037
+ const end = farEnd(state);
7038
+ return state.from === null || end === null ? undefined : distance(state.from, end);
7039
+ };
7040
+ var tapeMiddle2 = (state) => {
7041
+ const end = farEnd(state);
7042
+ if (state.from === null || end === null)
7043
+ return;
7044
+ return [(state.from[0] + end[0]) / 2, (state.from[1] + end[1]) / 2, (state.from[2] + end[2]) / 2];
7045
+ };
7046
+ var endBall = (key, at, look) => mesh2({
7047
+ key,
7048
+ position: at,
7049
+ geometry: sphere2({ radius: look.endRadius, widthSegments: 16, heightSegments: 8 }),
7050
+ material: basic2({ color: look.color })
7051
+ });
7052
+ var tapeNodes2 = (key, state, look = {}) => {
7053
+ const shown = {
7054
+ color: look.color ?? 16763955,
7055
+ width: look.width ?? 3,
7056
+ endRadius: look.endRadius ?? 0.03
7057
+ };
7058
+ const end = farEnd(state);
7059
+ const ends = [state.from, state.to].flatMap((at, index) => at === null ? [] : [endBall(`${key}:end:${index}`, at, shown)]);
7060
+ const span = state.from === null || end === null ? [] : [
7061
+ line2({
7062
+ key: `${key}:line`,
7063
+ points: [state.from, end],
7064
+ color: shown.color,
7065
+ width: shown.width,
7066
+ dashed: state.to === null,
7067
+ dashSize: 0.08,
7068
+ gapSize: 0.05
7069
+ })
7070
+ ];
7071
+ return group2({ key, children: [...span, ...ends] });
7072
+ };
7073
+ // src/kernel/pivot.ts
7074
+ import { Euler as Euler7, Quaternion as Quaternion8, Vector3 as Vector315 } from "three";
7075
+ var pivot2 = (options = {}) => ({
7076
+ scale: options.scale ?? 1,
7077
+ depthTest: options.depthTest ?? true,
7078
+ disableAxes: options.disableAxes ?? false,
7079
+ disableSliders: options.disableSliders ?? false,
7080
+ disableRotations: options.disableRotations ?? false,
7081
+ disableScaling: options.disableScaling ?? false,
7082
+ hovered: null,
7083
+ grab: null
7084
+ });
7085
+ var unit = {
7086
+ x: new Vector315(1, 0, 0),
7087
+ y: new Vector315(0, 1, 0),
7088
+ z: new Vector315(0, 0, 1)
7089
+ };
7090
+ var planeOf = {
7091
+ z: ["x", "y"],
7092
+ y: ["z", "x"],
7093
+ x: ["y", "z"]
7094
+ };
7095
+ var turnOf2 = (rotation) => new Quaternion8().setFromEuler(new Euler7(rotation[0], rotation[1], rotation[2]));
7096
+ var toVec35 = (vector) => [vector.x, vector.y, vector.z];
7097
+ var kindOf2 = (handle) => handle.split("-")[0];
7098
+ var axisOf = (handle) => handle.split("-")[1];
7099
+ var frameOf = (handle, placement) => {
7100
+ const turn = turnOf2(placement.rotation);
7101
+ const axis = axisOf(handle);
7102
+ const [first, second] = planeOf[axis];
7103
+ const kind = kindOf2(handle);
7104
+ const flat = kind === "slider" || kind === "rotator";
7105
+ const e1 = (flat ? unit[first] : unit[axis]).clone().applyQuaternion(turn);
7106
+ const e2 = (flat ? unit[second] : unit[axis]).clone().applyQuaternion(turn);
7107
+ return { e1, e2, normal: e1.clone().cross(e2).normalize() };
7108
+ };
7109
+ var pressPivot2 = (state, placement, handle, point) => {
7110
+ const { e1, e2, normal } = frameOf(handle, placement);
7111
+ return {
7112
+ ...state,
7113
+ grab: {
7114
+ handle,
7115
+ start: placement,
7116
+ point,
7117
+ e1: toVec35(e1),
7118
+ e2: toVec35(e2),
7119
+ normal: toVec35(kindOf2(handle) === "arrow" || kindOf2(handle) === "sphere" ? e1 : normal)
7120
+ }
7121
+ };
7122
+ };
7123
+ var releasePivot2 = (state) => ({ ...state, grab: null });
7124
+ var hoverPivot2 = (state, handle) => state.hovered === handle ? state : { ...state, hovered: handle };
7125
+ var offsetAlong = (point, direction, ray) => {
7126
+ const origin = new Vector315(...ray.origin);
7127
+ const toward = new Vector315(...ray.direction);
7128
+ const e1 = direction.dot(direction);
7129
+ const e2 = direction.dot(point) - direction.dot(origin);
7130
+ const e3 = direction.dot(toward);
7131
+ if (e3 === 0)
7132
+ return -e2 / e1;
7133
+ const v1 = toward.clone().multiplyScalar(e1 / e3).sub(direction);
7134
+ const v2 = toward.clone().multiplyScalar(e2 / e3).add(origin).sub(point);
7135
+ return -v1.dot(v2) / v1.dot(v1);
7136
+ };
7137
+ var meetPlane = (ray, at, normal) => {
7138
+ const origin = new Vector315(...ray.origin);
7139
+ const toward = new Vector315(...ray.direction);
7140
+ const facing = normal.dot(toward);
7141
+ if (facing === 0)
7142
+ return;
7143
+ return origin.addScaledVector(toward, normal.dot(at.clone().sub(origin)) / facing);
7144
+ };
7145
+ var angleBetween = (from, to, at, e1, e2) => {
7146
+ const a = from.clone().sub(at);
7147
+ const b = to.clone().sub(at);
7148
+ return Math.atan2(b.dot(e2), b.dot(e1)) - Math.atan2(a.dot(e2), a.dot(e1));
7149
+ };
7150
+ var vectorsOf = (grab) => ({
7151
+ point: new Vector315(...grab.point),
7152
+ e1: new Vector315(...grab.e1),
7153
+ e2: new Vector315(...grab.e2),
7154
+ normal: new Vector315(...grab.normal),
7155
+ at: new Vector315(...grab.start.position)
7156
+ });
7157
+ var moved2 = (start, by) => ({
7158
+ ...start,
7159
+ position: toVec35(new Vector315(...start.position).add(by))
7160
+ });
7161
+ var arrowDrag = (grab, ray) => {
7162
+ const { point, e1 } = vectorsOf(grab);
7163
+ return moved2(grab.start, e1.clone().multiplyScalar(offsetAlong(point, e1, ray)));
7164
+ };
7165
+ var sliderDrag = (grab, ray) => {
7166
+ const { point, e1, e2, normal, at } = vectorsOf(grab);
7167
+ const meet = meetPlane(ray, at, normal);
7168
+ if (meet === undefined)
7169
+ return grab.start;
7170
+ const offset = meet.sub(point);
7171
+ return moved2(grab.start, e1.multiplyScalar(offset.dot(e1)).add(e2.multiplyScalar(offset.dot(e2))));
7172
+ };
7173
+ var tenDegrees = Math.PI / 18;
7174
+ var rotatorDrag = (grab, ray, snap) => {
7175
+ const { point, e1, e2, normal, at } = vectorsOf(grab);
7176
+ const meet = meetPlane(ray, at, normal);
7177
+ if (meet === undefined)
7178
+ return grab.start;
7179
+ const turned = angleBetween(point, meet, at, e1, e2);
7180
+ const angle = snap ? Math.round(turned / tenDegrees) * tenDegrees : turned;
7181
+ const turn = new Quaternion8().setFromAxisAngle(normal, angle).multiply(turnOf2(grab.start.rotation));
7182
+ const euler = new Euler7().setFromQuaternion(turn.normalize());
7183
+ return { ...grab.start, rotation: [euler.x, euler.y, euler.z] };
7184
+ };
7185
+ var sphereDrag = (state, grab, ray, snap) => {
7186
+ const { point, e1 } = vectorsOf(grab);
7187
+ const grown = 2 ** (offsetAlong(point, e1, ray) / state.scale * 0.2);
7188
+ const factor = Math.max(snap ? Math.round(grown * 10) / 10 : grown, 0.00001);
7189
+ const index = { x: 0, y: 1, z: 2 }[axisOf(grab.handle)];
7190
+ const scale = [
7191
+ grab.start.scale[0] * (index === 0 ? factor : 1),
7192
+ grab.start.scale[1] * (index === 1 ? factor : 1),
7193
+ grab.start.scale[2] * (index === 2 ? factor : 1)
7194
+ ];
7195
+ return { ...grab.start, scale };
7196
+ };
7197
+ var dragPivot2 = (state, ray, options = {}) => {
7198
+ const grab = state.grab;
7199
+ if (grab === null)
7200
+ return;
7201
+ const snap = options.snap ?? false;
7202
+ const kind = kindOf2(grab.handle);
7203
+ if (kind === "arrow")
7204
+ return arrowDrag(grab, ray);
7205
+ if (kind === "slider")
7206
+ return sliderDrag(grab, ray);
7207
+ if (kind === "rotator")
7208
+ return rotatorDrag(grab, ray, snap);
7209
+ return sphereDrag(state, grab, ray, snap);
7210
+ };
7211
+ var colours2 = { x: 16719968, y: 2154368, z: 2130175 };
7212
+ var hoveredColour = 16777024;
7213
+ var handles = ["arrow", "slider", "rotator", "sphere"];
7214
+ var pivotHandleOf2 = (key, hit) => {
7215
+ const [owner, name] = hit.split(":");
7216
+ if (owner !== key)
7217
+ return;
7218
+ return handles.flatMap((kind) => ["x", "y", "z"].map((axis) => `${kind}-${axis}`)).find((handle) => handle === name);
7219
+ };
7220
+ var lookOf = (state, handle) => basic2({
7221
+ color: state.grab?.handle === handle || state.hovered === handle ? hoveredColour : colours2[axisOf(handle)],
7222
+ depthTest: state.depthTest,
7223
+ side: "double"
7224
+ });
7225
+ var unseen = basic2({ opacity: 0, transparent: true, depthTest: false });
7226
+ var pointAlong2 = {
7227
+ x: [0, 0, -Math.PI / 2],
7228
+ y: [0, 0, 0],
7229
+ z: [Math.PI / 2, 0, 0]
7230
+ };
7231
+ var along = (axis, distance) => {
7232
+ const { x, y, z } = unit[axis];
7233
+ return [x * distance, y * distance, z * distance];
7234
+ };
7235
+ var arrowNodes = (key, state, axis) => {
7236
+ const handle = `arrow-${axis}`;
7237
+ const size = state.scale;
7238
+ const coneLength = size / 5;
7239
+ const stem = size - coneLength;
7240
+ const material = lookOf(state, handle);
7241
+ return [
7242
+ mesh2({
7243
+ key: `${key}:${handle}:stem`,
7244
+ position: along(axis, stem / 2),
7245
+ rotation: fixed2(pointAlong2[axis]),
7246
+ geometry: cylinder2({ radiusTop: size / 80, radiusBottom: size / 80, height: stem }),
7247
+ material
7248
+ }),
7249
+ mesh2({
7250
+ key: `${key}:${handle}:hit`,
7251
+ position: along(axis, size / 2),
7252
+ rotation: fixed2(pointAlong2[axis]),
7253
+ geometry: cylinder2({ radiusTop: size * 0.07, radiusBottom: size * 0.07, height: size }),
7254
+ material: unseen,
7255
+ interactive: true
7256
+ }),
7257
+ mesh2({
7258
+ key: `${key}:${handle}:cone`,
7259
+ position: along(axis, stem + coneLength / 2),
7260
+ rotation: fixed2(pointAlong2[axis]),
7261
+ geometry: cone2({ radius: size / 20, height: coneLength, radialSegments: 24 }),
7262
+ material,
7263
+ interactive: true
7264
+ })
7265
+ ];
7266
+ };
7267
+ var ontoPlane = {
7268
+ z: [0, 0, 0],
7269
+ y: [-Math.PI / 2, 0, -Math.PI / 2],
7270
+ x: [Math.PI / 2, Math.PI / 2, 0]
7271
+ };
7272
+ var sliderNode = (key, state, axis) => {
7273
+ const handle = `slider-${axis}`;
7274
+ const out = state.scale / 7 * 1.7;
7275
+ const side = state.scale * 0.225;
7276
+ return group2({
7277
+ key: `${key}:${handle}`,
7278
+ rotation: fixed2(ontoPlane[axis]),
7279
+ children: [
7280
+ mesh2({
7281
+ key: `${key}:${handle}:square`,
7282
+ position: [out, out, 0],
7283
+ geometry: plane2({ width: side, height: side }),
7284
+ material: lookOf(state, handle),
7285
+ interactive: true
7286
+ })
7287
+ ]
7288
+ });
7289
+ };
7290
+ var arcSegments = 8;
7291
+ var rotatorNode = (key, state, axis) => {
7292
+ const handle = `rotator-${axis}`;
7293
+ const radius = state.scale * 0.65;
7294
+ const step = Math.PI / 2 / arcSegments;
7295
+ const chord = 2 * radius * Math.sin(step / 2);
7296
+ const segment = (index, part) => {
7297
+ const middle = step * (index + 0.5);
7298
+ const thickness = part === "line" ? radius / 50 : state.scale * 0.03;
7299
+ return mesh2({
7300
+ key: `${key}:${handle}:${part}:${index}`,
7301
+ position: [Math.cos(middle) * radius, Math.sin(middle) * radius, 0],
7302
+ rotation: fixed2([0, 0, middle]),
7303
+ geometry: cylinder2({ radiusTop: thickness, radiusBottom: thickness, height: chord }),
7304
+ material: part === "line" ? lookOf(state, handle) : unseen,
7305
+ interactive: part === "hit"
7306
+ });
7307
+ };
7308
+ const indices = Array.from({ length: arcSegments }, (_, index) => index);
7309
+ return group2({
7310
+ key: `${key}:${handle}`,
7311
+ rotation: fixed2(ontoPlane[axis]),
7312
+ children: [
7313
+ ...indices.map((index) => segment(index, "line")),
7314
+ ...indices.map((index) => segment(index, "hit"))
7315
+ ]
7316
+ });
7317
+ };
7318
+ var sphereNode = (key, state, axis) => mesh2({
7319
+ key: `${key}:sphere-${axis}`,
7320
+ position: along(axis, state.scale * 1.2),
7321
+ geometry: sphere2({ radius: state.scale / 22.5, widthSegments: 12, heightSegments: 12 }),
7322
+ material: lookOf(state, `sphere-${axis}`),
7323
+ interactive: true
7324
+ });
7325
+ var axesOf = ["x", "y", "z"];
7326
+ var pivotNodes2 = (key, state, placement) => group2({
7327
+ key,
7328
+ position: placement.position,
7329
+ rotation: fixed2(placement.rotation),
7330
+ children: [
7331
+ ...state.disableAxes ? [] : axesOf.flatMap((axis) => arrowNodes(key, state, axis)),
7332
+ ...state.disableSliders ? [] : axesOf.map((axis) => sliderNode(key, state, axis)),
7333
+ ...state.disableRotations ? [] : axesOf.map((axis) => rotatorNode(key, state, axis)),
7334
+ ...state.disableScaling ? [] : axesOf.map((axis) => sphereNode(key, state, axis))
7335
+ ]
7336
+ });
7337
+ // src/kernel/viewportGizmo.ts
7338
+ import { Euler as Euler8, Matrix4 as Matrix45, Quaternion as Quaternion9, Vector3 as Vector316 } from "three";
7339
+ var colours3 = { x: 16719968, y: 2154368, z: 2130175 };
7340
+ var ink = 0;
7341
+ var directions = {
7342
+ x: [1, 0, 0],
7343
+ y: [0, 1, 0],
7344
+ z: [0, 0, 1],
7345
+ "-x": [-1, 0, 0],
7346
+ "-y": [0, -1, 0],
7347
+ "-z": [0, 0, -1]
7348
+ };
7349
+ var axes2 = ["x", "y", "z", "-x", "-y", "-z"];
7350
+ var cameraTurn = (camera) => new Quaternion9().setFromRotationMatrix(new Matrix45().lookAt(new Vector316(...camera.position), new Vector316(...camera.lookAt), new Vector316(0, 1, 0)));
7351
+ var gizmoTurn = (camera) => {
7352
+ const turn = new Euler8().setFromQuaternion(cameraTurn(camera).invert());
7353
+ return [turn.x, turn.y, turn.z];
7354
+ };
7355
+ var stroke = (key, length, angle, at) => mesh2({
7356
+ key,
7357
+ position: [at[0], at[1], 0.01],
7358
+ rotation: fixed2([0, 0, angle]),
7359
+ geometry: box2({ width: length, height: 0.07, depth: 0.001 }),
7360
+ material: basic2({ color: ink })
7361
+ });
7362
+ var letters = {
7363
+ x: [
7364
+ [0.34, Math.PI / 4, [0, 0]],
7365
+ [0.34, -Math.PI / 4, [0, 0]]
7366
+ ],
7367
+ y: [
7368
+ [0.14, Math.PI / 2, [0, -0.07]],
7369
+ [0.17, Math.PI / 3, [0.04, 0.06]],
7370
+ [0.17, -Math.PI / 3, [-0.04, 0.06]]
7371
+ ],
7372
+ z: [
7373
+ [0.22, 0, [0, 0.11]],
7374
+ [0.22, 0, [0, -0.11]],
7375
+ [0.3, Math.PI / 4, [0, 0]]
7376
+ ]
7377
+ };
7378
+ var isPositive = (axis) => axis.length === 1;
7379
+ var colourOf2 = (axis) => colours3[isPositive(axis) ? axis : axis.slice(1)];
7380
+ var headScale = (axis, hovered) => (isPositive(axis) ? 1 : 0.75) * (axis === hovered ? 1.2 : 1);
7381
+ var labelOf2 = (key, axis) => isPositive(axis) ? letters[axis].map(([length, angle, at], index) => stroke(`${key}:${axis}:letter:${index}`, length, angle, at)) : [];
7382
+ var head = (key, axis, hovered) => {
7383
+ const scale = headScale(axis, hovered);
7384
+ return group2({
7385
+ key: `${key}:${axis}`,
7386
+ position: directions[axis],
7387
+ rotation: billboard2(),
7388
+ scale: [scale, scale, scale],
7389
+ interactive: true,
7390
+ children: [
7391
+ mesh2({
7392
+ key: `${key}:${axis}:disc`,
7393
+ geometry: circle2({ radius: 0.25, segments: 32 }),
7394
+ material: basic2({
7395
+ color: colourOf2(axis),
7396
+ opacity: isPositive(axis) ? 1 : 0.75,
7397
+ transparent: !isPositive(axis)
7398
+ })
7399
+ }),
7400
+ ...labelOf2(key, axis)
7401
+ ]
7402
+ });
7403
+ };
7404
+ var bar = (key, axis) => {
7405
+ const [x, y, z] = directions[axis];
7406
+ return mesh2({
7407
+ key: `${key}:${axis}:bar`,
7408
+ position: [x * 0.4, y * 0.4, z * 0.4],
7409
+ geometry: box2({
7410
+ width: axis === "x" ? 0.8 : 0.05,
7411
+ height: axis === "y" ? 0.8 : 0.05,
7412
+ depth: axis === "z" ? 0.8 : 0.05
7413
+ }),
7414
+ material: basic2({ color: colours3[axis] })
7415
+ });
7416
+ };
7417
+ var viewportGizmoNodes2 = (key, camera, options = {}) => {
7418
+ const size = options.size ?? 40;
7419
+ const hovered = options.hovered ?? null;
7420
+ const shown = options.hideNegativeAxes === true ? axes2.filter(isPositive) : axes2;
7421
+ return group2({
7422
+ key,
7423
+ rotation: fixed2(gizmoTurn(camera)),
7424
+ scale: [size, size, size],
7425
+ children: [
7426
+ bar(key, "x"),
7427
+ bar(key, "y"),
7428
+ bar(key, "z"),
7429
+ ...shown.map((axis) => head(key, axis, hovered))
7430
+ ]
7431
+ });
7432
+ };
7433
+ var viewportAxisOf2 = (key, hit) => {
7434
+ const [owner, axis] = hit.split(":");
7435
+ if (owner !== key)
7436
+ return;
7437
+ return axes2.find((candidate) => candidate === axis);
7438
+ };
7439
+ var cameraAlong2 = (camera, axis) => {
7440
+ const target = new Vector316(...camera.lookAt);
7441
+ const distance = new Vector316(...camera.position).distanceTo(target);
7442
+ const direction = new Vector316(...directions[axis]);
7443
+ if (axis === "y" || axis === "-y")
7444
+ direction.z = 0.000001;
7445
+ const position = direction.normalize().multiplyScalar(distance).add(target);
7446
+ return { ...camera, position: [position.x, position.y, position.z] };
7447
+ };
7448
+ export { __export, handJoints2, clipTime2, clipRunning2, createPose2, resetPose2, float2, builtinBehaviours2, spinAngle2, writeRotation2, buildMaterial2, updateMaterial2, vec3Equals2, rotationEquals2, shapeEquals2, geometryRefEquals2, instanceEquals2, instancesEqual2, behaviourEquals2, animationEquals2, transitionEquals2, materialRefEquals2, cameraEquals2, renderSettingsEquals2, effectsEqual2, viewsEqual2, resourcesEqual2, overlaysEqual2, environmentEquals2, skyEquals2, contactShadowsEquals2, bodyEquals2, physicsEquals2, xrEquals2, capacityFor2, createPerformanceMonitor2, easeProgress2, startTween2, applyTween2, fixed2, spin2, billboard2, box2, sphere2, plane2, cylinder2, torus2, cone2, capsule2, roundedBox2, backdrop2, ring2, circle2, text2, instant2, ease2, basic2, lambert2, phong2, standard2, physical2, normalMaterial2, shadowMaterial2, grid2, shaderGrid2, sharedGeometry2, lentGeometry2, sharedMaterial2, group2, detailed2, line2, points2, sparkles2, stars2, catmullRomPoints2, catmullRomPointAt2, catmullRomColors2, cubicBezierPoints2, quadraticBezierPoints2, headSpace2, jointSpace2, controllerSpace2, anchorSpace2, planeSpace2, meshSpace2, xrMeshGeometryId2, xrMesh2, xrAnchor2, mesh2, trail2, edges2, body2, interactionGroups2, cuboidCollider2, ballCollider2, capsuleCollider2, cylinderCollider2, coneCollider2, velocityMotor2, positionMotor2, physics2, bodyRef2, joint2, fixedJoint2, sphericalJoint2, revoluteJoint2, prismaticJoint2, ropeJoint2, springJoint2, glide2, xr2, instance2, instances2, behave2, play2, borrowed2, label2, colorRange2, ambientLight2, directionalLight2, pointLight2, spotLight2, hemisphereLight2, perspectiveCamera2, orthographicCamera2, cameraShake2, bloom2, vignette2, film2, renderSettings2, view2, renderTexture2, environment2, sunPositionFromAngles2, sky2, contactShadows2, overlay2, hud2, scene2, emptyIndex2, indexScene2, changedFields2, diff2, createResourceStore2, createSceneClock2, createManualFrames2, createGatedFrames2, createFramePacer2, defaultOrbit2, orbitOptions2, rotateCamera2, dollyCamera2, panCamera2, dollyCameraToward2, orbit2, orbitKey2, autoRotated2, fitCamera2, clipCamera2, placeOverlays2, interactionBits2, colliderFor2, describedColliders2, collidersFor2, colliderSignature2, locomote2, teleport2, glided2, createXrTracker2, environmentPresets2, environmentPresetUrl2, stagePresets2, stage2, centerOffset2, stageBounds2, noModifiers2, pointOnPlane2, createPicker2, createPointerTracker2, createSceneLoop2, recordingRendererFactory2, createSceneGraph2, gizmo2, pressGizmo2, releaseGizmo2, hoverGizmo2, dragGizmo2, movedAlike2, gizmoHandleOf2, gizmoNodes2, boxSelect2, exports_history, exports_lockstep, thingsBounds2, describeScene2, formatSummary2, shotAngles2, shotCamera2, moods2, moodStaging2, inspectFields2, setAt2, sceneChanges2, formatChanges2, tape2, placeTapeEnd2, pointTape2, clearTape2, tapeLength2, tapeMiddle2, tapeNodes2, pivot2, pressPivot2, releasePivot2, hoverPivot2, dragPivot2, pivotHandleOf2, pivotNodes2, viewportGizmoNodes2, viewportAxisOf2, cameraAlong2 };
5116
7449
 
5117
- //# debugId=C47554518AE363C364756E2164756E21
5118
- //# sourceMappingURL=index-01kwfekm.js.map
7450
+ //# debugId=9610D685ADCF1F6764756E2164756E21
7451
+ //# sourceMappingURL=index-h3vf50fn.js.map