@opsydyn/effect-three 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +12 -0
  3. package/dist/{index-8cf8t6by.js → index-h3vf50fn.js} +2113 -83
  4. package/dist/index-h3vf50fn.js.map +53 -0
  5. package/dist/index-ttwy0znv.js +145 -0
  6. package/dist/index-ttwy0znv.js.map +12 -0
  7. package/dist/index.js +488 -147
  8. package/dist/index.js.map +8 -6
  9. package/dist/kernel/boxSelect.d.ts +22 -0
  10. package/dist/kernel/boxSelect.d.ts.map +1 -0
  11. package/dist/kernel/build.d.ts +142 -6
  12. package/dist/kernel/build.d.ts.map +1 -1
  13. package/dist/kernel/cameraShake.d.ts.map +1 -1
  14. package/dist/kernel/describeScene.d.ts +50 -0
  15. package/dist/kernel/describeScene.d.ts.map +1 -0
  16. package/dist/kernel/description.d.ts +155 -1
  17. package/dist/kernel/description.d.ts.map +1 -1
  18. package/dist/kernel/diff.d.ts +15 -0
  19. package/dist/kernel/diff.d.ts.map +1 -1
  20. package/dist/kernel/equality.d.ts +9 -1
  21. package/dist/kernel/equality.d.ts.map +1 -1
  22. package/dist/kernel/gizmo.d.ts +69 -0
  23. package/dist/kernel/gizmo.d.ts.map +1 -0
  24. package/dist/kernel/history.d.ts +61 -0
  25. package/dist/kernel/history.d.ts.map +1 -0
  26. package/dist/kernel/index.d.ts +13 -2
  27. package/dist/kernel/index.d.ts.map +1 -1
  28. package/dist/kernel/index.js +106 -3
  29. package/dist/kernel/index.js.map +1 -1
  30. package/dist/kernel/inspect.d.ts +85 -0
  31. package/dist/kernel/inspect.d.ts.map +1 -0
  32. package/dist/kernel/lineGeometry.d.ts +25 -0
  33. package/dist/kernel/lineGeometry.d.ts.map +1 -0
  34. package/dist/kernel/lockstep.d.ts +114 -0
  35. package/dist/kernel/lockstep.d.ts.map +1 -0
  36. package/dist/kernel/loop.d.ts.map +1 -1
  37. package/dist/kernel/materials.d.ts.map +1 -1
  38. package/dist/kernel/pivot.d.ts +54 -0
  39. package/dist/kernel/pivot.d.ts.map +1 -0
  40. package/dist/kernel/pointBuffers.d.ts +17 -0
  41. package/dist/kernel/pointBuffers.d.ts.map +1 -0
  42. package/dist/kernel/pointer.d.ts +12 -0
  43. package/dist/kernel/pointer.d.ts.map +1 -1
  44. package/dist/kernel/renderKit.d.ts +21 -1
  45. package/dist/kernel/renderKit.d.ts.map +1 -1
  46. package/dist/kernel/renderer.d.ts +6 -0
  47. package/dist/kernel/renderer.d.ts.map +1 -1
  48. package/dist/kernel/sceneChanges.d.ts +87 -0
  49. package/dist/kernel/sceneChanges.d.ts.map +1 -0
  50. package/dist/kernel/sceneGraph.d.ts +6 -0
  51. package/dist/kernel/sceneGraph.d.ts.map +1 -1
  52. package/dist/kernel/seeded.d.ts +9 -0
  53. package/dist/kernel/seeded.d.ts.map +1 -0
  54. package/dist/kernel/shots.d.ts +26 -0
  55. package/dist/kernel/shots.d.ts.map +1 -0
  56. package/dist/kernel/tape.d.ts +38 -0
  57. package/dist/kernel/tape.d.ts.map +1 -0
  58. package/dist/kernel/trail.d.ts +31 -0
  59. package/dist/kernel/trail.d.ts.map +1 -0
  60. package/dist/kernel/viewportGizmo.d.ts +25 -0
  61. package/dist/kernel/viewportGizmo.d.ts.map +1 -0
  62. package/dist/runtime/Inspector.d.ts +20 -0
  63. package/dist/runtime/Inspector.d.ts.map +1 -0
  64. package/dist/runtime/SceneFile.d.ts +448 -0
  65. package/dist/runtime/SceneFile.d.ts.map +1 -0
  66. package/dist/runtime/SceneSchema.d.ts +318 -0
  67. package/dist/runtime/SceneSchema.d.ts.map +1 -1
  68. package/dist/runtime/errors.d.ts +9 -0
  69. package/dist/runtime/errors.d.ts.map +1 -1
  70. package/dist/runtime/index.d.ts +3 -1
  71. package/dist/runtime/index.d.ts.map +1 -1
  72. package/dist/webgl/index.d.ts.map +1 -1
  73. package/dist/webgl/index.js +228 -3
  74. package/dist/webgl/index.js.map +6 -4
  75. package/dist/webgl/line.d.ts +4 -0
  76. package/dist/webgl/line.d.ts.map +1 -0
  77. package/dist/webgl/points.d.ts +4 -0
  78. package/dist/webgl/points.d.ts.map +1 -0
  79. package/dist/webgpu/index.d.ts.map +1 -1
  80. package/dist/webgpu/index.js +206 -26
  81. package/dist/webgpu/index.js.map +6 -4
  82. package/dist/webgpu/line.d.ts +4 -0
  83. package/dist/webgpu/line.d.ts.map +1 -0
  84. package/dist/webgpu/points.d.ts +4 -0
  85. package/dist/webgpu/points.d.ts.map +1 -0
  86. package/package.json +2 -1
  87. package/src/kernel/boxSelect.ts +73 -0
  88. package/src/kernel/build.ts +332 -0
  89. package/src/kernel/cameraShake.ts +3 -13
  90. package/src/kernel/describeScene.ts +224 -0
  91. package/src/kernel/description.ts +175 -0
  92. package/src/kernel/diff.ts +39 -0
  93. package/src/kernel/equality.ts +101 -0
  94. package/src/kernel/gizmo.ts +478 -0
  95. package/src/kernel/history.ts +118 -0
  96. package/src/kernel/index.ts +97 -0
  97. package/src/kernel/inspect.ts +214 -0
  98. package/src/kernel/lineGeometry.ts +75 -0
  99. package/src/kernel/lockstep.ts +237 -0
  100. package/src/kernel/loop.ts +5 -0
  101. package/src/kernel/materials.ts +3 -0
  102. package/src/kernel/pivot.ts +418 -0
  103. package/src/kernel/pointBuffers.ts +115 -0
  104. package/src/kernel/pointer.ts +55 -12
  105. package/src/kernel/renderKit.ts +23 -1
  106. package/src/kernel/renderer.ts +6 -0
  107. package/src/kernel/sceneChanges.ts +265 -0
  108. package/src/kernel/sceneGraph.ts +319 -8
  109. package/src/kernel/seeded.ts +18 -0
  110. package/src/kernel/shots.ts +167 -0
  111. package/src/kernel/tape.ts +124 -0
  112. package/src/kernel/trail.ts +170 -0
  113. package/src/kernel/viewportGizmo.ts +194 -0
  114. package/src/runtime/Inspector.ts +43 -0
  115. package/src/runtime/SceneFile.ts +46 -0
  116. package/src/runtime/SceneSchema.ts +247 -0
  117. package/src/runtime/errors.ts +6 -0
  118. package/src/runtime/index.ts +3 -1
  119. package/src/webgl/index.ts +4 -0
  120. package/src/webgl/line.ts +66 -0
  121. package/src/webgl/points.ts +205 -0
  122. package/src/webgpu/index.ts +4 -0
  123. package/src/webgpu/line.ts +67 -0
  124. package/src/webgpu/points.ts +193 -0
  125. package/dist/index-8cf8t6by.js.map +0 -41
@@ -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",
@@ -125,6 +182,8 @@ var applyShaded = (material, description, mapChanged = false) => {
125
182
  };
126
183
  var applyBasic = (material, description, textures) => {
127
184
  material.color.setHex(description.color);
185
+ material.depthTest = description.depthTest;
186
+ material.depthWrite = description.depthTest;
128
187
  const mapChanged = applyMap(material, description.map, textures);
129
188
  if (applySurface(material, description) || mapChanged)
130
189
  material.needsUpdate = true;
@@ -489,6 +548,21 @@ var jointsEqual = (a, b) => {
489
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]));
490
549
  var colorRangeEquals = (a, b) => b !== undefined && a.start === b.start && a.color === b.color;
491
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])));
492
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;
493
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);
494
568
  var xrAnchorEquals = (a, b) => b !== undefined && a.id === b.id && vec3Equals2(a.position, b.position) && vec3Equals2(a.rotation, b.rotation);
@@ -658,6 +732,7 @@ var applyTween2 = (object, tween, elapsedSeconds) => {
658
732
  return false;
659
733
  };
660
734
  // src/kernel/build.ts
735
+ import { CatmullRomCurve3, Color as Color2, CubicBezierCurve3, QuadraticBezierCurve3, Vector3 as Vector33 } from "three";
661
736
  var origin = [0, 0, 0];
662
737
  var unitScale = [1, 1, 1];
663
738
  var noRotation = { _tag: "Fixed", euler: origin };
@@ -774,7 +849,8 @@ var basic2 = (options = {}) => ({
774
849
  opacity: options.opacity ?? 1,
775
850
  transparent: options.transparent ?? false,
776
851
  side: options.side ?? "front",
777
- wireframe: options.wireframe ?? false
852
+ wireframe: options.wireframe ?? false,
853
+ depthTest: options.depthTest ?? true
778
854
  });
779
855
  var lambert2 = (options = {}) => ({
780
856
  _tag: "Lambert",
@@ -888,9 +964,105 @@ var group2 = (options) => ({
888
964
  children: options.children ?? [],
889
965
  body: options.body ?? null,
890
966
  follow: options.follow ?? null,
891
- detail: options.detail ?? null
967
+ detail: options.detail ?? null,
968
+ trail: options.trail ?? null
892
969
  });
893
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
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
+ };
894
1066
  var headSpace2 = () => ({ _tag: "Head" });
895
1067
  var jointSpace2 = (hand, joint) => ({
896
1068
  _tag: "Joint",
@@ -925,7 +1097,31 @@ var mesh2 = (options) => ({
925
1097
  interactive: options.interactive ?? false,
926
1098
  castShadow: options.castShadow ?? false,
927
1099
  receiveShadow: options.receiveShadow ?? false,
928
- 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
929
1125
  });
930
1126
  var body2 = (options = {}) => ({
931
1127
  type: options.type ?? "dynamic",
@@ -1291,11 +1487,17 @@ var overlay2 = (options) => ({
1291
1487
  zIndexRange: options.zIndexRange ?? defaultZIndexRange,
1292
1488
  view: options.view ?? null
1293
1489
  });
1490
+ var hud2 = (options) => ({
1491
+ alignment: options.alignment ?? "bottom-right",
1492
+ margin: options.margin ?? [80, 80],
1493
+ children: options.children ?? []
1494
+ });
1294
1495
  var scene2 = (options) => ({
1295
1496
  camera: options.camera ?? perspectiveCamera2(),
1296
1497
  gestures: options.gestures ?? "page",
1297
1498
  views: options.views ?? noViews,
1298
1499
  renderTextures: options.renderTextures ?? noRenderTextures,
1500
+ hud: options.hud ?? null,
1299
1501
  overlays: options.overlays ?? noOverlays,
1300
1502
  environment: options.environment ?? null,
1301
1503
  sky: options.sky ?? null,
@@ -1480,6 +1682,8 @@ var changedFields2 = (prev, next) => {
1480
1682
  fields.push("follow");
1481
1683
  if (!detailEquals(prev.detail, next.detail))
1482
1684
  fields.push("detail");
1685
+ if (!trailEquals(prev.trail, next.trail))
1686
+ fields.push("trail");
1483
1687
  return fields;
1484
1688
  }
1485
1689
  case "Mesh": {
@@ -1507,6 +1711,10 @@ var changedFields2 = (prev, next) => {
1507
1711
  fields.push("receiveShadow");
1508
1712
  if (!bodyEquals2(prev.body, next.body))
1509
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");
1510
1718
  return fields;
1511
1719
  }
1512
1720
  case "Instances": {
@@ -1662,6 +1870,42 @@ var changedFields2 = (prev, next) => {
1662
1870
  fields.push("shadowBias");
1663
1871
  return fields;
1664
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
+ }
1665
1909
  case "ShaderGrid": {
1666
1910
  if (prev._tag !== "ShaderGrid")
1667
1911
  return;
@@ -2352,7 +2596,7 @@ import {
2352
2596
  Plane,
2353
2597
  Ray,
2354
2598
  Spherical,
2355
- Vector3 as Vector33
2599
+ Vector3 as Vector34
2356
2600
  } from "three";
2357
2601
  var defaultOrbit2 = {
2358
2602
  enableRotate: true,
@@ -2379,14 +2623,14 @@ var orbitOptions2 = (options = {}) => ({
2379
2623
  ...options
2380
2624
  });
2381
2625
  var twoPi = 2 * Math.PI;
2382
- var offset = new Vector33;
2626
+ var offset = new Vector34;
2383
2627
  var spherical = new Spherical;
2384
- var target = new Vector33;
2385
- var position2 = new Vector33;
2386
- var axis = new Vector33;
2387
- var panOffset = new Vector33;
2628
+ var target = new Vector34;
2629
+ var position2 = new Vector34;
2630
+ var axis = new Vector34;
2631
+ var panOffset = new Vector34;
2388
2632
  var basis = new Matrix42;
2389
- var worldUp = new Vector33(0, 1, 0);
2633
+ var worldUp = new Vector34(0, 1, 0);
2390
2634
  var toVec3 = (vector) => [vector.x, vector.y, vector.z];
2391
2635
  var clampAzimuth = (theta, options) => {
2392
2636
  let min = options.minAzimuthAngle;
@@ -2464,9 +2708,9 @@ var panCamera2 = (camera, deltaX, deltaY, area, options = defaultOrbit2) => {
2464
2708
  return place(camera, options, zoomOf(camera, options));
2465
2709
  };
2466
2710
  var tiltLimit = Math.cos(70 * MathUtils.DEG2RAD);
2467
- var pointer = new Vector33;
2468
- var before = new Vector33;
2469
- var forward = new Vector33;
2711
+ var pointer = new Vector34;
2712
+ var before = new Vector34;
2713
+ var forward = new Vector34;
2470
2714
  var groundRay = new Ray;
2471
2715
  var ground = new Plane;
2472
2716
  var hostCamera = (camera, cursor, zoom) => {
@@ -2568,7 +2812,7 @@ var orbitKey2 = (camera, key, modifiers, area, options = defaultOrbit2) => {
2568
2812
  return rotating ? turned(-turn, 0) : panCamera2(camera, -step, 0, area, options);
2569
2813
  }
2570
2814
  };
2571
- var corner = new Vector33;
2815
+ var corner = new Vector34;
2572
2816
  var view = new Matrix42;
2573
2817
  var fitDistance = (camera, box, area, margin) => {
2574
2818
  const largest = Math.max(box.max[0] - box.min[0], box.max[1] - box.min[1], box.max[2] - box.min[2]);
@@ -2621,12 +2865,12 @@ import {
2621
2865
  PerspectiveCamera as PerspectiveCamera2,
2622
2866
  Raycaster,
2623
2867
  Vector2 as Vector22,
2624
- Vector3 as Vector34
2868
+ Vector3 as Vector35
2625
2869
  } from "three";
2626
- var point = new Vector34;
2627
- var cameraPosition = new Vector34;
2628
- var direction = new Vector34;
2629
- var toPoint = new Vector34;
2870
+ var point = new Vector35;
2871
+ var cameraPosition = new Vector35;
2872
+ var direction = new Vector35;
2873
+ var toPoint = new Vector35;
2630
2874
  var ndc = new Vector22;
2631
2875
  var raycaster = new Raycaster;
2632
2876
  var lensFor = (graph, overlay) => {
@@ -2701,7 +2945,7 @@ import {
2701
2945
  Euler as Euler3,
2702
2946
  Matrix4 as Matrix43,
2703
2947
  Quaternion as Quaternion3,
2704
- Vector3 as Vector35
2948
+ Vector3 as Vector36
2705
2949
  } from "three";
2706
2950
  var interactionBits2 = (groups) => {
2707
2951
  const mask = (list) => list.reduce((bits, group) => bits | 1 << group, 0);
@@ -2711,7 +2955,7 @@ var interactionBits2 = (groups) => {
2711
2955
  return (mask(groups.memberships) << 16 | filters) >>> 0;
2712
2956
  };
2713
2957
  var toVec32 = (vector) => [vector.x, vector.y, vector.z];
2714
- var size = new Vector35;
2958
+ var size = new Vector36;
2715
2959
  var scaledPositions = (geometry, scale) => {
2716
2960
  const positions = geometry.getAttribute("position");
2717
2961
  const points = new Float32Array(positions.count * 3);
@@ -2730,7 +2974,7 @@ var triangles = (geometry) => {
2730
2974
  };
2731
2975
  var speck = {
2732
2976
  shape: { _tag: "Ball", radius: 0.001 },
2733
- offset: new Vector35
2977
+ offset: new Vector36
2734
2978
  };
2735
2979
  var shapeFor = (geometry, collider, scale) => {
2736
2980
  if (geometry.getAttribute("position") === undefined)
@@ -2744,7 +2988,7 @@ var shapeFor = (geometry, collider, scale) => {
2744
2988
  box.getSize(size).multiply(scale).multiplyScalar(0.5);
2745
2989
  return {
2746
2990
  shape: { _tag: "Cuboid", halfExtents: toVec32(size) },
2747
- offset: box.getCenter(new Vector35).multiply(scale)
2991
+ offset: box.getCenter(new Vector36).multiply(scale)
2748
2992
  };
2749
2993
  }
2750
2994
  case "ball": {
@@ -2761,7 +3005,7 @@ var shapeFor = (geometry, collider, scale) => {
2761
3005
  case "hull":
2762
3006
  return {
2763
3007
  shape: { _tag: "Hull", points: scaledPositions(geometry, scale) },
2764
- offset: new Vector35
3008
+ offset: new Vector36
2765
3009
  };
2766
3010
  case "trimesh":
2767
3011
  return {
@@ -2770,7 +3014,7 @@ var shapeFor = (geometry, collider, scale) => {
2770
3014
  vertices: scaledPositions(geometry, scale),
2771
3015
  indices: triangles(geometry)
2772
3016
  },
2773
- offset: new Vector35
3017
+ offset: new Vector36
2774
3018
  };
2775
3019
  }
2776
3020
  };
@@ -2815,11 +3059,11 @@ function describedCollider(collider, scale) {
2815
3059
  }
2816
3060
  var relative = new Matrix43;
2817
3061
  var bodyInverse = new Matrix43;
2818
- var where = new Vector35;
3062
+ var where = new Vector36;
2819
3063
  var turn = new Quaternion3;
2820
- var relativeScale = new Vector35;
2821
- var worldScale = new Vector35;
2822
- var worldPosition = new Vector35;
3064
+ var relativeScale = new Vector36;
3065
+ var worldScale = new Vector36;
3066
+ var worldPosition = new Vector36;
2823
3067
  var worldTurn = new Quaternion3;
2824
3068
  var isMesh = (object) => ("isMesh" in object) && object.isMesh === true;
2825
3069
  function placedCollider2(child, collider, body) {
@@ -3075,7 +3319,7 @@ var stageBounds2 = (box) => {
3075
3319
  import { Box3, EquirectangularReflectionMapping, UVMapping } from "three";
3076
3320
 
3077
3321
  // src/kernel/pointer.ts
3078
- 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";
3079
3323
  var noModifiers2 = { shift: false, control: false, meta: false, alt: false };
3080
3324
  var pointOnPlane2 = (ray, plane) => {
3081
3325
  const [nx, ny, nz] = plane.normal;
@@ -3116,7 +3360,7 @@ var shown = (object) => {
3116
3360
  var createPicker2 = (graph) => {
3117
3361
  const raycaster = new Raycaster2;
3118
3362
  const ndc = new Vector23;
3119
- const normal = new Vector36;
3363
+ const normal = new Vector37;
3120
3364
  const aim = (x, y) => {
3121
3365
  graph.scene.updateMatrixWorld();
3122
3366
  const views = graph.views();
@@ -3144,26 +3388,26 @@ var createPicker2 = (graph) => {
3144
3388
  }
3145
3389
  return false;
3146
3390
  };
3147
- const rayOrigin = new Vector36;
3148
- const rayDirection = new Vector36;
3149
- const nearestHit = (view) => {
3150
- for (const intersection of raycaster.intersectObjects(graph.interactiveObjects(), true)) {
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)) {
3151
3395
  if (!shown(intersection.object))
3152
3396
  continue;
3153
- const owner = keyedOwner(graph, intersection.object);
3154
- const key = owner === undefined ? undefined : graph.keyOf(owner);
3397
+ const owner = keyedOwner(on, intersection.object);
3398
+ const key = owner === undefined ? undefined : on.keyOf(owner);
3155
3399
  if (owner !== undefined && key !== undefined) {
3156
3400
  normal.set(0, 0, 0);
3157
3401
  if (intersection.face) {
3158
3402
  normal.copy(intersection.face.normal).transformDirection(intersection.object.matrixWorld);
3159
3403
  }
3160
- 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);
3161
3405
  return {
3162
3406
  key,
3163
3407
  ...instance === undefined ? {} : { instance },
3164
3408
  ...partOf(owner, intersection.object),
3165
3409
  ...view === undefined ? {} : { view },
3166
- path: pathOf(graph, owner),
3410
+ path: pathOf(on, owner),
3167
3411
  point: toVec33(intersection.point),
3168
3412
  distance: intersection.distance,
3169
3413
  normal: toVec33(normal),
@@ -3174,6 +3418,16 @@ var createPicker2 = (graph) => {
3174
3418
  }
3175
3419
  return;
3176
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
+ };
3177
3431
  const currentRay = () => ({
3178
3432
  origin: toVec33(raycaster.ray.origin),
3179
3433
  direction: toVec33(raycaster.ray.direction)
@@ -3200,19 +3454,22 @@ var createPicker2 = (graph) => {
3200
3454
  holdCameras: graph.holdCameras,
3201
3455
  turned: graph.turned,
3202
3456
  pick: (x, y) => {
3457
+ const hud = hudHit(x, y);
3458
+ if (hud !== undefined)
3459
+ return hud;
3203
3460
  if (graph.interactiveObjects().length === 0)
3204
3461
  return;
3205
3462
  const view = aim(x, y);
3206
3463
  if (view === false)
3207
3464
  return;
3208
- return nearestHit(view);
3465
+ return nearestHit(graph, view);
3209
3466
  },
3210
3467
  pickRay: (ray) => {
3211
3468
  if (graph.interactiveObjects().length === 0)
3212
3469
  return;
3213
3470
  graph.scene.updateMatrixWorld();
3214
3471
  raycaster.set(rayOrigin.fromArray(ray.origin), rayDirection.fromArray(ray.direction).normalize());
3215
- return nearestHit(undefined);
3472
+ return nearestHit(graph, undefined);
3216
3473
  },
3217
3474
  viewport: graph.viewport
3218
3475
  };
@@ -3225,6 +3482,7 @@ var createPointerTracker2 = (picker) => {
3225
3482
  const pressedPointers = new Map;
3226
3483
  let primary;
3227
3484
  let gesturePress;
3485
+ let gestureMoved = false;
3228
3486
  let hovered;
3229
3487
  let press;
3230
3488
  let pressing = false;
@@ -3289,6 +3547,7 @@ var createPointerTracker2 = (picker) => {
3289
3547
  pressedPointers.clear();
3290
3548
  primary = id;
3291
3549
  pressedPointers.set(id, { x: event.x, y: event.y });
3550
+ gestureMoved = false;
3292
3551
  const region = picker.region(event.x, event.y);
3293
3552
  reportTurned(region, events);
3294
3553
  picker.holdCameras(true);
@@ -3304,6 +3563,7 @@ var createPointerTracker2 = (picker) => {
3304
3563
  if (from === undefined || gesturePress === undefined)
3305
3564
  return;
3306
3565
  pressedPointers.set(id, to);
3566
+ gestureMoved = true;
3307
3567
  const { view, width, height, x, y } = gesturePress;
3308
3568
  const region = { ...view === undefined ? {} : { view }, width, height, x, y };
3309
3569
  const moved = pixels(from, to);
@@ -3342,12 +3602,23 @@ var createPointerTracker2 = (picker) => {
3342
3602
  }
3343
3603
  });
3344
3604
  };
3345
- const endGestures = () => {
3605
+ const endGestures = (events) => {
3346
3606
  if (gesturePress !== undefined)
3347
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
+ }
3348
3618
  pressedPointers.clear();
3349
3619
  primary = undefined;
3350
3620
  gesturePress = undefined;
3621
+ gestureMoved = false;
3351
3622
  };
3352
3623
  const secondary = (event, id) => {
3353
3624
  const events = [];
@@ -3367,7 +3638,7 @@ var createPointerTracker2 = (picker) => {
3367
3638
  return secondary(event, id);
3368
3639
  const events = [];
3369
3640
  if (event._tag === "PointerLeave") {
3370
- endGestures();
3641
+ endGestures(events);
3371
3642
  if (position !== undefined)
3372
3643
  endDrag(captured(), position.x, position.y, events);
3373
3644
  dragged = false;
@@ -3402,7 +3673,7 @@ var createPointerTracker2 = (picker) => {
3402
3673
  case "PointerUp":
3403
3674
  release(hit, event, events);
3404
3675
  endDrag(drag, event.x, event.y, events);
3405
- endGestures();
3676
+ endGestures(events);
3406
3677
  break;
3407
3678
  case "DoubleClick":
3408
3679
  if (hit !== undefined && pressed(hit)) {
@@ -3594,6 +3865,11 @@ var createSceneLoop2 = (options) => {
3594
3865
  renderer.render(graph.scene, graph.camera);
3595
3866
  for (const view of views)
3596
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
+ }
3597
3873
  graph.drawn();
3598
3874
  measure();
3599
3875
  const overlays = graph.overlays();
@@ -3678,21 +3954,21 @@ var recordingRendererFactory2 = () => {
3678
3954
  // src/kernel/sceneGraph.ts
3679
3955
  import {
3680
3956
  AmbientLight,
3681
- Color as Color2,
3957
+ Color as Color4,
3682
3958
  AnimationClip,
3683
3959
  AnimationMixer,
3684
3960
  DirectionalLight,
3685
3961
  Group,
3686
3962
  GridHelper,
3687
3963
  HemisphereLight,
3688
- Mesh,
3964
+ Mesh as Mesh2,
3689
3965
  OrthographicCamera as OrthographicCamera4,
3690
3966
  PerspectiveCamera as PerspectiveCamera3,
3691
3967
  PointLight,
3692
3968
  Quaternion as Quaternion6,
3693
3969
  Scene,
3694
3970
  SpotLight,
3695
- Vector3 as Vector39
3971
+ Vector3 as Vector311
3696
3972
  } from "three";
3697
3973
  import { clone as cloneSkinned } from "three/addons/utils/SkeletonUtils.js";
3698
3974
 
@@ -3700,16 +3976,16 @@ import { clone as cloneSkinned } from "three/addons/utils/SkeletonUtils.js";
3700
3976
  import { Euler as Euler5, Quaternion as Quaternion5 } from "three";
3701
3977
 
3702
3978
  // src/kernel/bodySources.ts
3703
- import { Euler as Euler4, Matrix4 as Matrix44, Quaternion as Quaternion4, Vector3 as Vector37 } from "three";
3979
+ import { Euler as Euler4, Matrix4 as Matrix44, Quaternion as Quaternion4, Vector3 as Vector38 } from "three";
3704
3980
  var bodyId = (key, instance) => instance === null ? key : `${key}\x00${instance}`;
3705
- var position3 = new Vector37;
3981
+ var position3 = new Vector38;
3706
3982
  var quaternion2 = new Quaternion4;
3707
- var scale2 = new Vector37;
3983
+ var scale2 = new Vector38;
3708
3984
  var matrix2 = new Matrix44;
3709
3985
  var local = new Matrix44;
3710
3986
  var inverse = new Matrix44;
3711
3987
  var euler2 = new Euler4;
3712
- var ownScale = new Vector37;
3988
+ var ownScale = new Vector38;
3713
3989
  var toPose = (from) => {
3714
3990
  from.decompose(position3, quaternion2, scale2);
3715
3991
  return {
@@ -4069,10 +4345,10 @@ var createBodyHost = (engine, scene) => {
4069
4345
  };
4070
4346
 
4071
4347
  // src/kernel/cameraMotion.ts
4072
- import { OrthographicCamera as OrthographicCamera3, Spherical as Spherical2, Vector3 as Vector38 } from "three";
4073
- var createPose = () => ({ target: new Vector38, spherical: new Spherical2, zoom: 1 });
4074
- var offset2 = new Vector38;
4075
- 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;
4076
4352
  var readPose = (pose, description) => {
4077
4353
  pose.target.fromArray(description.lookAt);
4078
4354
  offset2.fromArray(description.position).sub(pose.target);
@@ -4113,8 +4389,8 @@ var createCameraMotion = () => {
4113
4389
  const current = createPose();
4114
4390
  const described = createPose();
4115
4391
  const goal = createPose();
4116
- const goalPosition = new Vector38;
4117
- const lookAt = new Vector38;
4392
+ const goalPosition = new Vector39;
4393
+ const lookAt = new Vector39;
4118
4394
  let shown = false;
4119
4395
  let easing = false;
4120
4396
  let damping = 0;
@@ -4204,18 +4480,7 @@ var createCameraMotion = () => {
4204
4480
 
4205
4481
  // src/kernel/cameraShake.ts
4206
4482
  import { SimplexNoise } from "three/addons/math/SimplexNoise.js";
4207
- var seeded = (seed) => {
4208
- let state = seed >>> 0;
4209
- return {
4210
- random: () => {
4211
- state = state + 1831565813 >>> 0;
4212
- let t = state;
4213
- t = Math.imul(t ^ t >>> 15, t | 1);
4214
- t ^= t + Math.imul(t ^ t >>> 7, t | 61);
4215
- return ((t ^ t >>> 14) >>> 0) / 4294967296;
4216
- }
4217
- };
4218
- };
4483
+ var seeded = (seed) => ({ random: seededRandom(seed) });
4219
4484
  var yawNoise = new SimplexNoise(seeded(1));
4220
4485
  var pitchNoise = new SimplexNoise(seeded(2));
4221
4486
  var rollNoise = new SimplexNoise(seeded(3));
@@ -4250,8 +4515,147 @@ var createCameraShaker = () => {
4250
4515
  };
4251
4516
  };
4252
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();
4653
+ }
4654
+ };
4655
+ };
4656
+
4253
4657
  // src/kernel/sceneGraph.ts
4254
- 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";
4255
4659
  var isSurfaced = (entry) => entry._tag === "Mesh" || entry._tag === "Instances";
4256
4660
  var writeVec3 = (target, v) => {
4257
4661
  target.set(v[0], v[1], v[2]);
@@ -4345,6 +4749,7 @@ var createSceneGraph2 = (options = {}) => {
4345
4749
  let views = [];
4346
4750
  const textureGraphs = new Map;
4347
4751
  let textureList = [];
4752
+ let hudHosted;
4348
4753
  let viewDescriptions = [];
4349
4754
  let gestures = emptyScene.gestures;
4350
4755
  let overlayList = emptyScene.overlays;
@@ -4448,9 +4853,32 @@ var createSceneGraph2 = (options = {}) => {
4448
4853
  const facing = new Set;
4449
4854
  const cameraTurn = new Quaternion6;
4450
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;
4451
4879
  const detailing = new Set;
4452
- const cameraPlace = new Vector39;
4453
- const groupPlace = new Vector39;
4880
+ const cameraPlace = new Vector311;
4881
+ const groupPlace = new Vector311;
4454
4882
  const playing = new Set;
4455
4883
  const registry = {
4456
4884
  ...builtinBehaviours2,
@@ -4460,7 +4888,7 @@ var createSceneGraph2 = (options = {}) => {
4460
4888
  const behaving = new Map;
4461
4889
  const moving = new Map;
4462
4890
  const reparented = new Set;
4463
- const worldPosition = new Vector39;
4891
+ const worldPosition = new Vector311;
4464
4892
  const interactive = new Set;
4465
4893
  let interactiveList;
4466
4894
  let index = emptyIndex2;
@@ -4528,6 +4956,69 @@ var createSceneGraph2 = (options = {}) => {
4528
4956
  if (lockZ)
4529
4957
  object.rotation.z = 0;
4530
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
+ };
4531
5022
  const childObject = (node, index) => {
4532
5023
  const child = node.children[index];
4533
5024
  return child === undefined ? undefined : entries.get(child.key)?.object;
@@ -4592,10 +5083,11 @@ var createSceneGraph2 = (options = {}) => {
4592
5083
  if (node.follow !== null)
4593
5084
  entry.object.visible = false;
4594
5085
  trackDetail(entry, node);
5086
+ trackTrail(entry, node);
4595
5087
  return entry;
4596
5088
  }
4597
5089
  case "Mesh": {
4598
- 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));
4599
5091
  const entry = { _tag: "Mesh", node, object };
4600
5092
  writeVec3(object.position, node.position);
4601
5093
  writeVec3(object.scale, node.scale);
@@ -4604,6 +5096,8 @@ var createSceneGraph2 = (options = {}) => {
4604
5096
  trackInteractive(object, node.interactive);
4605
5097
  object.castShadow = node.castShadow;
4606
5098
  object.receiveShadow = node.receiveShadow;
5099
+ trackEdges(entry, node);
5100
+ trackTrail(entry, node);
4607
5101
  return entry;
4608
5102
  }
4609
5103
  case "Instances": {
@@ -4677,6 +5171,30 @@ var createSceneGraph2 = (options = {}) => {
4677
5171
  const hosted = options.kit?.shaderGrid(node);
4678
5172
  return { _tag: "ShaderGrid", node, object: hosted?.object ?? new Group, hosted };
4679
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
+ }
4680
5198
  case "HemisphereLight": {
4681
5199
  const object = new HemisphereLight;
4682
5200
  writeHemisphereLight(object, node);
@@ -4701,9 +5219,9 @@ var createSceneGraph2 = (options = {}) => {
4701
5219
  if (!node.castShadow && !node.receiveShadow)
4702
5220
  return;
4703
5221
  shown.traverse((part) => {
4704
- if (part instanceof Mesh && node.castShadow)
5222
+ if (part instanceof Mesh2 && node.castShadow)
4705
5223
  part.castShadow = true;
4706
- if (part instanceof Mesh && node.receiveShadow)
5224
+ if (part instanceof Mesh2 && node.receiveShadow)
4707
5225
  part.receiveShadow = true;
4708
5226
  });
4709
5227
  };
@@ -4842,6 +5360,17 @@ var createSceneGraph2 = (options = {}) => {
4842
5360
  spinning.delete(entry);
4843
5361
  facing.delete(entry);
4844
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
+ }
4845
5374
  moving.delete(entry);
4846
5375
  reparented.delete(entry);
4847
5376
  trackInteractive(entry.object, false);
@@ -4853,8 +5382,10 @@ var createSceneGraph2 = (options = {}) => {
4853
5382
  entry.object.dispose();
4854
5383
  if (entry._tag === "Grid")
4855
5384
  disposeGridLines(entry.helper);
4856
- if (entry._tag === "ShaderGrid")
5385
+ if (entry._tag === "ShaderGrid" || entry._tag === "Line" || entry._tag === "Points") {
4857
5386
  entry.hosted?.dispose();
5387
+ }
5388
+ sparkling.delete(entry);
4858
5389
  if (entry._tag === "Label") {
4859
5390
  entry.hosted?.dispose();
4860
5391
  if (entry.node.material !== null && entry.material !== undefined) {
@@ -4949,6 +5480,12 @@ var createSceneGraph2 = (options = {}) => {
4949
5480
  retarget(entry, next);
4950
5481
  if (fields.includes("rotation"))
4951
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
+ }
4952
5489
  if (fields.includes("behaviour"))
4953
5490
  trackBehaviour(entry, next);
4954
5491
  if (fields.includes("interactive"))
@@ -5005,6 +5542,8 @@ var createSceneGraph2 = (options = {}) => {
5005
5542
  trackInteractive(entry.object, next.interactive);
5006
5543
  if (fields.includes("detail"))
5007
5544
  trackDetail(entry, next);
5545
+ if (fields.includes("trail"))
5546
+ trackTrail(entry, next);
5008
5547
  if (fields.includes("follow")) {
5009
5548
  entry.object.visible = next.follow === null;
5010
5549
  if (next.follow === null) {
@@ -5040,6 +5579,34 @@ var createSceneGraph2 = (options = {}) => {
5040
5579
  entry.node = next;
5041
5580
  return;
5042
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
+ }
5043
5610
  if (entry._tag === "ShaderGrid" && next._tag === "ShaderGrid") {
5044
5611
  entry.hosted?.update(entry.node, next);
5045
5612
  entry.node = next;
@@ -5169,6 +5736,7 @@ var createSceneGraph2 = (options = {}) => {
5169
5736
  gestures: "page",
5170
5737
  views: [],
5171
5738
  renderTextures: [],
5739
+ hud: null,
5172
5740
  overlays: [],
5173
5741
  environment: null,
5174
5742
  sky: null,
@@ -5180,6 +5748,62 @@ var createSceneGraph2 = (options = {}) => {
5180
5748
  resources: parent.resources,
5181
5749
  children: texture.children
5182
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
+ };
5183
5807
  function hostedTexture(texture) {
5184
5808
  const hosted = textureGraphs.get(texture.id);
5185
5809
  if (hosted === undefined)
@@ -5203,7 +5827,7 @@ var createSceneGraph2 = (options = {}) => {
5203
5827
  const reframed = existing === undefined || existing.description.width !== texture.width || existing.description.height !== texture.height || existing.description.background !== texture.background;
5204
5828
  if (reframed) {
5205
5829
  hosted.graph.resize(texture.width, texture.height);
5206
- 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);
5207
5831
  }
5208
5832
  hosted.description = texture;
5209
5833
  textureGraphs.set(texture.id, hosted);
@@ -5228,6 +5852,11 @@ var createSceneGraph2 = (options = {}) => {
5228
5852
  if (checked._tag === "Invalid")
5229
5853
  return checked;
5230
5854
  }
5855
+ if (next.hud !== null) {
5856
+ const checked = indexScene2(hudScene(next.hud, next), knownBehaviours);
5857
+ if (checked._tag === "Invalid")
5858
+ return checked;
5859
+ }
5231
5860
  const result = diff2(index, next, knownBehaviours);
5232
5861
  if (result._tag === "Invalid")
5233
5862
  return result;
@@ -5262,7 +5891,7 @@ var createSceneGraph2 = (options = {}) => {
5262
5891
  if (next.measure.join("\x00") !== measured.join("\x00"))
5263
5892
  invalidate();
5264
5893
  measured = next.measure;
5265
- const ops = [...result.ops, ...syncTextures(next)];
5894
+ const ops = [...result.ops, ...syncTextures(next), ...syncHud(next)];
5266
5895
  if (ops.length > 0)
5267
5896
  invalidate();
5268
5897
  return { _tag: "Applied", ops };
@@ -5275,6 +5904,7 @@ var createSceneGraph2 = (options = {}) => {
5275
5904
  elapsed = elapsedSeconds;
5276
5905
  for (const texture of textureList)
5277
5906
  texture.graph.tick(elapsedSeconds);
5907
+ hudHosted?.graph.tick(elapsedSeconds);
5278
5908
  for (const entry of spinning) {
5279
5909
  if (isPlaced(entry)) {
5280
5910
  writeRotation2(entry.object.rotation, entry.node.rotation, elapsed);
@@ -5294,6 +5924,13 @@ var createSceneGraph2 = (options = {}) => {
5294
5924
  camera.getWorldQuaternion(cameraTurn);
5295
5925
  facing.forEach(faceCamera);
5296
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
+ }
5297
5934
  if (detailing.size > 0) {
5298
5935
  camera.getWorldPosition(cameraPlace);
5299
5936
  detailing.forEach(showLevel);
@@ -5307,6 +5944,7 @@ var createSceneGraph2 = (options = {}) => {
5307
5944
  invalidate();
5308
5945
  for (const texture of textureList)
5309
5946
  texture.graph.setAnimating(next);
5947
+ hudHosted?.graph.setAnimating(next);
5310
5948
  animating = next;
5311
5949
  if (next)
5312
5950
  return;
@@ -5323,6 +5961,8 @@ var createSceneGraph2 = (options = {}) => {
5323
5961
  texture.graph.dispose();
5324
5962
  textureGraphs.clear();
5325
5963
  textureList = [];
5964
+ hudHosted?.graph.dispose();
5965
+ hudHosted = undefined;
5326
5966
  for (const entry of entries.values()) {
5327
5967
  entry.object.removeFromParent();
5328
5968
  release(entry);
@@ -5355,6 +5995,7 @@ var createSceneGraph2 = (options = {}) => {
5355
5995
  return viewMotions.get(view)?.turned();
5356
5996
  },
5357
5997
  renderTextures: () => textureList,
5998
+ hud: () => hudHosted,
5358
5999
  gestures: () => gestures,
5359
6000
  overlays: () => overlayList,
5360
6001
  environment: () => environmentDescription,
@@ -5383,7 +6024,7 @@ var createSceneGraph2 = (options = {}) => {
5383
6024
  tick,
5384
6025
  elapsedSeconds: () => elapsed,
5385
6026
  renderSettings: () => settings,
5386
- needsFrame: () => dirty || textureList.some((texture) => texture.graph.needsFrame()) || animating && (spinning.size > 0 || moving.size > 0 || behaving.size > 0 || clipsRunning() || cameraMotion.moving() || viewsMoving() || shaking() || 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()),
5387
6028
  drawn: () => {
5388
6029
  dirty = false;
5389
6030
  },
@@ -5410,12 +6051,1401 @@ var createSceneGraph2 = (options = {}) => {
5410
6051
  viewport = { width, height };
5411
6052
  fitCamera(camera, viewport);
5412
6053
  hostViews(viewDescriptions);
6054
+ refitHud();
5413
6055
  invalidate();
5414
6056
  },
5415
6057
  dispose
5416
6058
  };
5417
6059
  };
5418
- 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, 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, cameraShake2, 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 };
5419
7449
 
5420
- //# debugId=DD15A712F87B1C4C64756E2164756E21
5421
- //# sourceMappingURL=index-8cf8t6by.js.map
7450
+ //# debugId=9610D685ADCF1F6764756E2164756E21
7451
+ //# sourceMappingURL=index-h3vf50fn.js.map