@opsydyn/effect-three 0.4.0 → 0.6.4

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 (53) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +4 -2
  3. package/dist/{index-h3vf50fn.js → index-re3rrfwd.js} +880 -79
  4. package/dist/index-re3rrfwd.js.map +56 -0
  5. package/dist/index.js +71 -2
  6. package/dist/index.js.map +3 -3
  7. package/dist/kernel/bodies.d.ts +20 -1
  8. package/dist/kernel/bodies.d.ts.map +1 -1
  9. package/dist/kernel/build.d.ts +24 -2
  10. package/dist/kernel/build.d.ts.map +1 -1
  11. package/dist/kernel/description.d.ts +68 -0
  12. package/dist/kernel/description.d.ts.map +1 -1
  13. package/dist/kernel/equality.d.ts +3 -1
  14. package/dist/kernel/equality.d.ts.map +1 -1
  15. package/dist/kernel/index.d.ts +7 -5
  16. package/dist/kernel/index.d.ts.map +1 -1
  17. package/dist/kernel/index.js +20 -2
  18. package/dist/kernel/index.js.map +1 -1
  19. package/dist/kernel/loop.d.ts.map +1 -1
  20. package/dist/kernel/paintOrder.d.ts +53 -0
  21. package/dist/kernel/paintOrder.d.ts.map +1 -0
  22. package/dist/kernel/physics.d.ts +39 -0
  23. package/dist/kernel/physics.d.ts.map +1 -1
  24. package/dist/kernel/pointer.d.ts +19 -1
  25. package/dist/kernel/pointer.d.ts.map +1 -1
  26. package/dist/kernel/preview.d.ts +32 -0
  27. package/dist/kernel/preview.d.ts.map +1 -0
  28. package/dist/kernel/sceneGraph.d.ts +3 -1
  29. package/dist/kernel/sceneGraph.d.ts.map +1 -1
  30. package/dist/kernel/sceneIndex.d.ts +5 -0
  31. package/dist/kernel/sceneIndex.d.ts.map +1 -1
  32. package/dist/kernel/timeline.d.ts +60 -0
  33. package/dist/kernel/timeline.d.ts.map +1 -0
  34. package/dist/runtime/SceneFile.d.ts +14 -0
  35. package/dist/runtime/SceneFile.d.ts.map +1 -1
  36. package/dist/runtime/SceneSchema.d.ts +86 -0
  37. package/dist/runtime/SceneSchema.d.ts.map +1 -1
  38. package/package.json +3 -2
  39. package/src/kernel/bodies.ts +299 -17
  40. package/src/kernel/build.ts +42 -1
  41. package/src/kernel/description.ts +68 -0
  42. package/src/kernel/equality.ts +22 -0
  43. package/src/kernel/index.ts +13 -1
  44. package/src/kernel/loop.ts +2 -0
  45. package/src/kernel/paintOrder.ts +274 -0
  46. package/src/kernel/physics.ts +86 -1
  47. package/src/kernel/pointer.ts +43 -5
  48. package/src/kernel/preview.ts +467 -0
  49. package/src/kernel/sceneGraph.ts +35 -3
  50. package/src/kernel/sceneIndex.ts +8 -0
  51. package/src/kernel/timeline.ts +93 -0
  52. package/src/runtime/SceneSchema.ts +72 -0
  53. package/dist/index-h3vf50fn.js.map +0 -53
@@ -55,6 +55,18 @@ __export(exports_lockstep, {
55
55
  welcomeDue: () => welcomeDue
56
56
  });
57
57
 
58
+ // src/kernel/timeline.ts
59
+ var exports_timeline = {};
60
+ __export(exports_timeline, {
61
+ due: () => due,
62
+ extend: () => extend,
63
+ make: () => make3,
64
+ reach: () => reach,
65
+ restart: () => restart,
66
+ schedule: () => schedule,
67
+ until: () => until
68
+ });
69
+
58
70
  // src/kernel/description.ts
59
71
  var handJoints2 = [
60
72
  "wrist",
@@ -564,7 +576,9 @@ var trailEquals = (a, b) => a === b || a !== null && b !== null && Object.is(a.w
564
576
  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
577
  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])));
566
578
  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;
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);
579
+ var assetEquals = (a, b) => b !== undefined && a.kind === b.kind && a.id === b.id && a.url === b.url && a.levels.length === b.levels.length && a.levels.every((level, i) => level === b.levels[i]);
580
+ var assetsEqual2 = (a, b) => a === b || a.length === b.length && a.every((asset, i) => assetEquals(asset, b[i]));
581
+ 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.until === b.until && a.run === b.run && a.snapshotAt === b.snapshotAt && a.keep === b.keep && (a.from === b.from || a.from !== null && b.from !== null && a.from.step === b.from.step && a.from.snapshot === b.from.snapshot) && a.debug === b.debug && jointsEqual(a.joints, b.joints);
568
582
  var xrAnchorEquals = (a, b) => b !== undefined && a.id === b.id && vec3Equals2(a.position, b.position) && vec3Equals2(a.rotation, b.rotation);
569
583
  var xrEquals2 = (a, b) => a === b || a !== null && b !== null && vec3Equals2(a.origin, b.origin) && Object.is(a.heading, b.heading) && a.referenceSpace === b.referenceSpace && Object.is(a.framebufferScale, b.framebufferScale) && a.hitTest === b.hitTest && a.showInputs === b.showInputs && (a.glide === b.glide || a.glide !== null && b.glide !== null && Object.is(a.glide.speed, b.glide.speed) && a.glide.turn === b.glide.turn && Object.is(a.glide.turnSpeed, b.glide.turnSpeed) && Object.is(a.glide.snapDegrees, b.glide.snapDegrees)) && a.planes === b.planes && a.meshes === b.meshes && a.domOverlay === b.domOverlay && a.anchors.length === b.anchors.length && a.anchors.every((anchor, i) => xrAnchorEquals(anchor, b.anchors[i]));
570
584
  var xrSpaceEquals = (a, b) => {
@@ -1175,6 +1189,11 @@ var physics2 = (options = {}) => ({
1175
1189
  paused: options.paused ?? false,
1176
1190
  timeStep: options.timeStep ?? 1 / 60,
1177
1191
  interpolate: options.interpolate ?? true,
1192
+ until: options.until ?? null,
1193
+ run: options.run ?? 0,
1194
+ snapshotAt: options.snapshotAt ?? null,
1195
+ from: options.from ?? null,
1196
+ keep: options.keep ?? 0,
1178
1197
  debug: options.debug ?? false,
1179
1198
  joints: options.joints ?? noJoints
1180
1199
  });
@@ -1476,6 +1495,13 @@ var contactShadows2 = (options = {}) => {
1476
1495
  };
1477
1496
  var noOverlays = [];
1478
1497
  var noMeasures = [];
1498
+ var noAssets = [];
1499
+ var noLevels = [];
1500
+ var assetOf = (kind) => ({ id, url, levels }) => ({ kind, id, url, levels: levels ?? noLevels });
1501
+ var modelAsset2 = assetOf("model");
1502
+ var textureAsset2 = assetOf("texture");
1503
+ var environmentAsset2 = assetOf("environment");
1504
+ var fontAsset2 = assetOf("font");
1479
1505
  var defaultZIndexRange = [16777271, 0];
1480
1506
  var overlay2 = (options) => ({
1481
1507
  key: options.key,
@@ -1505,6 +1531,7 @@ var scene2 = (options) => ({
1505
1531
  physics: options.physics ?? null,
1506
1532
  xr: options.xr ?? null,
1507
1533
  measure: options.measure ?? noMeasures,
1534
+ assets: options.assets ?? noAssets,
1508
1535
  render: options.render ?? defaultRenderSettings,
1509
1536
  resources: {
1510
1537
  geometries: options.resources?.geometries ?? noResources.geometries,
@@ -1549,6 +1576,10 @@ var indexScene2 = (description, behaviours = new Set) => {
1549
1576
  if (duplicateView !== undefined) {
1550
1577
  return { _tag: "Invalid", error: { _tag: "DuplicateViewKey", key: duplicateView } };
1551
1578
  }
1579
+ const duplicateAsset = firstDuplicateInstance(description.assets.map((asset) => ({ key: asset.id })));
1580
+ if (duplicateAsset !== undefined) {
1581
+ return { _tag: "Invalid", error: { _tag: "DuplicateAssetId", id: duplicateAsset } };
1582
+ }
1552
1583
  const duplicateOverlay = firstDuplicateInstance(description.overlays);
1553
1584
  if (duplicateOverlay !== undefined) {
1554
1585
  return { _tag: "Invalid", error: { _tag: "DuplicateOverlayKey", key: duplicateOverlay } };
@@ -2954,6 +2985,38 @@ var interactionBits2 = (groups) => {
2954
2985
  const filters = groups.filters === null ? 65535 : mask(groups.filters);
2955
2986
  return (mask(groups.memberships) << 16 | filters) >>> 0;
2956
2987
  };
2988
+ var run = (first, count) => Array.from({ length: count }, (_, i) => String.fromCharCode(first.charCodeAt(0) + i));
2989
+ var digits = [...run("A", 26), ...run("a", 26), ...run("0", 10), "+", "/"];
2990
+ var digitValues = new Map(digits.map((char, i) => [char, i]));
2991
+ var digit = (value) => digits[value] ?? "";
2992
+ var snapshotText2 = (bytes) => {
2993
+ const out = [];
2994
+ for (let at = 0;at < bytes.length; at += 3) {
2995
+ const a = bytes[at] ?? 0;
2996
+ const b = bytes[at + 1] ?? 0;
2997
+ const c = bytes[at + 2] ?? 0;
2998
+ const left = bytes.length - at;
2999
+ out.push(digit(a >> 2), digit((a & 3) << 4 | b >> 4), left > 1 ? digit((b & 15) << 2 | c >> 6) : "=", left > 2 ? digit(c & 63) : "=");
3000
+ }
3001
+ return out.join("");
3002
+ };
3003
+ var snapshotBytes2 = (text) => {
3004
+ const digits = text.replace(/=+$/, "");
3005
+ const bytes = new Uint8Array(Math.floor(digits.length * 3 / 4));
3006
+ let bits = 0;
3007
+ let held = 0;
3008
+ let at = 0;
3009
+ for (const char of digits) {
3010
+ bits = bits << 6 | (digitValues.get(char) ?? 0);
3011
+ held += 6;
3012
+ if (held >= 8) {
3013
+ held -= 8;
3014
+ bytes[at] = bits >> held & 255;
3015
+ at += 1;
3016
+ }
3017
+ }
3018
+ return bytes;
3019
+ };
2957
3020
  var toVec32 = (vector) => [vector.x, vector.y, vector.z];
2958
3021
  var size = new Vector36;
2959
3022
  var scaledPositions = (geometry, scale) => {
@@ -3475,7 +3538,7 @@ var createPicker2 = (graph) => {
3475
3538
  };
3476
3539
  };
3477
3540
  var none2 = [];
3478
- var missTolerance = 2;
3541
+ var missTolerances = { mouse: 2, pen: 2, touch: 10 };
3479
3542
  var pointerOf = (input) => ("pointer" in input) && input.pointer !== undefined ? input.pointer : 0;
3480
3543
  var createPointerTracker2 = (picker) => {
3481
3544
  let position;
@@ -3512,7 +3575,7 @@ var createPointerTracker2 = (picker) => {
3512
3575
  }
3513
3576
  return;
3514
3577
  }
3515
- if (from?.button === event.button && travel(from, event.x, event.y) <= missTolerance) {
3578
+ if (from?.button === event.button && travel(from, event.x, event.y) <= missTolerances[from.device]) {
3516
3579
  events.push({ _tag: "PointerMissed", button: event.button });
3517
3580
  }
3518
3581
  };
@@ -3663,7 +3726,13 @@ var createPointerTracker2 = (picker) => {
3663
3726
  moveGesture(id, event, events);
3664
3727
  break;
3665
3728
  case "PointerDown":
3666
- press = { key: hit?.key, button: event.button, x: event.x, y: event.y };
3729
+ press = {
3730
+ key: hit?.key,
3731
+ button: event.button,
3732
+ x: event.x,
3733
+ y: event.y,
3734
+ device: event.device ?? "mouse"
3735
+ };
3667
3736
  pressing = true;
3668
3737
  dragged = false;
3669
3738
  if (hit !== undefined)
@@ -3852,6 +3921,8 @@ var createSceneLoop2 = (options) => {
3852
3921
  emit({ _tag: "Collision", ...collision });
3853
3922
  for (const force of graph.contactForces())
3854
3923
  emit({ _tag: "ContactForce", ...force });
3924
+ for (const reached of graph.physicsReached())
3925
+ emit({ _tag: "PhysicsReached", ...reached });
3855
3926
  const settings = graph.renderSettings();
3856
3927
  if (settings !== configured) {
3857
3928
  renderer.configure(settings);
@@ -4143,6 +4214,36 @@ var between = (a, b, alpha) => {
4143
4214
  quaternion: [from.x, from.y, from.z, from.w]
4144
4215
  };
4145
4216
  };
4217
+ var catchUpAfter = 0.25;
4218
+ var mostPerFrame = 1;
4219
+ var checksumBytes = new DataView(new ArrayBuffer(8));
4220
+ var mixByte = (hash, byte) => Math.imul(hash ^ byte, 16777619) >>> 0;
4221
+ var mixNumber = (hash, value) => {
4222
+ checksumBytes.setFloat64(0, value);
4223
+ let mixed = hash;
4224
+ for (let i = 0;i < 8; i++)
4225
+ mixed = mixByte(mixed, checksumBytes.getUint8(i));
4226
+ return mixed;
4227
+ };
4228
+ var mixText = (hash, text) => {
4229
+ let mixed = hash;
4230
+ for (let i = 0;i < text.length; i++) {
4231
+ const code = text.charCodeAt(i);
4232
+ mixed = mixByte(mixByte(mixed, code & 255), code >>> 8);
4233
+ }
4234
+ return mixed;
4235
+ };
4236
+ var checksumOf = (poses) => {
4237
+ let hash = 2166136261;
4238
+ for (const [id, { position, quaternion }] of poses.toSorted(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) {
4239
+ hash = mixText(hash, id);
4240
+ for (const value of position)
4241
+ hash = mixNumber(hash, value);
4242
+ for (const value of quaternion)
4243
+ hash = mixNumber(hash, value);
4244
+ }
4245
+ return hash.toString(16).padStart(8, "0");
4246
+ };
4146
4247
  var remade = (hosted, source, signature) => hosted.source.holder !== source.holder || hosted.source.body.collider !== source.body.collider || !collidersEqual(hosted.source.body.colliders, source.body.colliders) || hosted.signature !== signature;
4147
4248
  var resettled = (a, b) => !bodyEquals2({ ...a, impulse: null }, { ...b, impulse: null });
4148
4249
  var named = (a, b, ids) => {
@@ -4168,6 +4269,13 @@ var createBodyHost = (engine, scene) => {
4168
4269
  const debug = createPhysicsDebug(scene);
4169
4270
  let last;
4170
4271
  let accumulator = 0;
4272
+ let steps = 0;
4273
+ let reported;
4274
+ let snapped;
4275
+ let reached = [];
4276
+ const kept = new Map;
4277
+ let rushing = false;
4278
+ let restored;
4171
4279
  const drawDebug = () => {
4172
4280
  if (world !== undefined && settings?.debug === true)
4173
4281
  debug.show(world.debugLines());
@@ -4183,9 +4291,37 @@ var createBodyHost = (engine, scene) => {
4183
4291
  joined.clear();
4184
4292
  accumulator = 0;
4185
4293
  last = undefined;
4294
+ steps = 0;
4295
+ reported = undefined;
4296
+ snapped = undefined;
4297
+ reached = [];
4298
+ };
4299
+ const make = (active, physics) => {
4300
+ const { from } = physics;
4301
+ const bytes = from === null ? undefined : from.snapshot === null ? kept.get(from.step) : snapshotBytes2(from.snapshot);
4302
+ if (from === null || bytes === undefined || active.restoreWorld === undefined) {
4303
+ kept.clear();
4304
+ return active.createWorld(physics);
4305
+ }
4306
+ for (const step of kept.keys())
4307
+ if (step > from.step || from.snapshot !== null)
4308
+ kept.delete(step);
4309
+ const made = active.restoreWorld(physics, bytes);
4310
+ steps = from.step;
4311
+ rushing = true;
4312
+ restored = { bodies: new Set(made.bodies), joints: new Set(made.joints) };
4313
+ return made.world;
4314
+ };
4315
+ const adopt = (active, source, signature) => {
4316
+ const pose = active.pose(source.id) ?? source.described();
4317
+ source.place(pose);
4318
+ hosted.set(source.id, { source, signature, previous: pose, current: pose, shown: pose });
4186
4319
  };
4320
+ let restarting = false;
4187
4321
  const add = (active, source, signature) => {
4188
- const pose = source.pose();
4322
+ const pose = restarting ? source.described() : source.pose();
4323
+ if (restarting)
4324
+ source.place(pose);
4189
4325
  active.add(source.id, source.body, source.colliders(), pose);
4190
4326
  if (source.body.impulse !== null)
4191
4327
  active.applyImpulse(source.id, source.body.impulse.impulse);
@@ -4195,6 +4331,10 @@ var createBodyHost = (engine, scene) => {
4195
4331
  const syncBody = (active, source) => {
4196
4332
  const existing = hosted.get(source.id);
4197
4333
  const signature = source.signature();
4334
+ if (existing === undefined && restored?.bodies.has(source.id) === true) {
4335
+ adopt(active, source, signature);
4336
+ return;
4337
+ }
4198
4338
  if (existing === undefined || remade(existing, source, signature)) {
4199
4339
  if (existing !== undefined)
4200
4340
  active.remove(source.id);
@@ -4250,11 +4390,22 @@ var createBodyHost = (engine, scene) => {
4250
4390
  const sync = (physics, sources) => {
4251
4391
  if (physics === null || engine === undefined) {
4252
4392
  dispose();
4393
+ kept.clear();
4253
4394
  return;
4254
4395
  }
4396
+ restarting = settings !== null && settings.run !== physics.run;
4397
+ if (restarting)
4398
+ dispose();
4255
4399
  if (world === undefined)
4256
- world = engine.createWorld(physics);
4257
- else if (!physicsEquals2(settings && { ...settings, joints: physics.joints }, physics)) {
4400
+ world = make(engine, physics);
4401
+ else if (!physicsEquals2(settings && {
4402
+ ...settings,
4403
+ joints: physics.joints,
4404
+ until: physics.until,
4405
+ snapshotAt: physics.snapshotAt,
4406
+ from: physics.from,
4407
+ keep: physics.keep
4408
+ }, physics)) {
4258
4409
  world.configure(physics);
4259
4410
  }
4260
4411
  settings = physics;
@@ -4271,7 +4422,22 @@ var createBodyHost = (engine, scene) => {
4271
4422
  world.remove(id);
4272
4423
  hosted.delete(id);
4273
4424
  }
4425
+ if (restored !== undefined) {
4426
+ for (const id of restored.bodies)
4427
+ if (!seen.has(id))
4428
+ world.remove(id);
4429
+ for (const joint of physics.joints) {
4430
+ if (restored.joints.has(joint.key))
4431
+ joined.set(joint.key, joint);
4432
+ }
4433
+ for (const id of restored.joints) {
4434
+ if (!joined.has(id))
4435
+ world.removeJoint(id);
4436
+ }
4437
+ restored = undefined;
4438
+ }
4274
4439
  syncJoints(world, physics.joints);
4440
+ restarting = false;
4275
4441
  drawDebug();
4276
4442
  };
4277
4443
  const kinematicTargets = (active) => {
@@ -4280,11 +4446,8 @@ var createBodyHost = (engine, scene) => {
4280
4446
  active.moveKinematic(id, source.pose());
4281
4447
  }
4282
4448
  };
4283
- const step = (active, seconds) => {
4284
- for (const body of hosted.values())
4285
- body.previous = body.current;
4286
- kinematicTargets(active);
4287
- for (const collision of active.step(seconds)) {
4449
+ const heard = (arrived, active) => {
4450
+ for (const collision of arrived) {
4288
4451
  collisions.push({
4289
4452
  ...named(hosted.get(collision.a)?.source, hosted.get(collision.b)?.source, collision),
4290
4453
  started: collision.started
@@ -4297,22 +4460,99 @@ var createBodyHost = (engine, scene) => {
4297
4460
  ...payload
4298
4461
  });
4299
4462
  }
4463
+ };
4464
+ const step = (active, seconds) => {
4465
+ for (const body of hosted.values())
4466
+ body.previous = body.current;
4467
+ kinematicTargets(active);
4468
+ heard(active.step(seconds), active);
4300
4469
  for (const [id, body] of hosted)
4301
4470
  body.current = active.pose(id) ?? body.current;
4471
+ steps += 1;
4472
+ };
4473
+ const collect = (active) => {
4474
+ if (active.received === undefined)
4475
+ return false;
4476
+ const { collisions: arrived, pending } = active.received();
4477
+ heard(arrived, active);
4478
+ for (const [id, body] of hosted)
4479
+ body.current = active.pose(id) ?? body.current;
4480
+ return pending;
4481
+ };
4482
+ const free = (active, timeStep, delta) => {
4483
+ accumulator += delta;
4484
+ while (accumulator >= timeStep) {
4485
+ step(active, timeStep);
4486
+ accumulator -= timeStep;
4487
+ }
4488
+ collect(active);
4489
+ return accumulator / timeStep;
4490
+ };
4491
+ const snapshotOwed = (physics, until) => physics.snapshotAt !== null && snapped !== physics.snapshotAt && steps <= physics.snapshotAt && physics.snapshotAt <= until;
4492
+ const report = (active, physics, snapshot) => {
4493
+ const wanted = snapshot || physics.keep > 0;
4494
+ const bytes = wanted ? active.snapshot?.() : undefined;
4495
+ if (wanted && active.snapshot !== undefined && bytes === undefined)
4496
+ return false;
4497
+ if (physics.keep > 0 && bytes !== undefined) {
4498
+ kept.delete(steps);
4499
+ kept.set(steps, bytes);
4500
+ for (const step of kept.keys())
4501
+ if (kept.size > physics.keep)
4502
+ kept.delete(step);
4503
+ }
4504
+ const { run } = physics;
4505
+ reached.push({
4506
+ run,
4507
+ step: steps,
4508
+ checksum: checksumOf([...hosted.keys()].flatMap((id) => posed(active, id))),
4509
+ ...snapshot && bytes !== undefined ? { snapshot: snapshotText2(bytes) } : {}
4510
+ });
4511
+ return true;
4512
+ };
4513
+ const driven = (active, physics, until, delta) => {
4514
+ const { timeStep } = physics;
4515
+ const snapping = snapshotOwed(physics, until);
4516
+ const stop = snapping && physics.snapshotAt !== null ? physics.snapshotAt : until;
4517
+ accumulator += delta;
4518
+ const owed = Math.max(0, stop - steps);
4519
+ const paced = Math.floor(accumulator / timeStep);
4520
+ const behind = rushing || owed > Math.ceil(catchUpAfter / timeStep);
4521
+ rushing = false;
4522
+ const count = Math.min(owed, behind ? owed : paced, Math.ceil(mostPerFrame / timeStep));
4523
+ for (let i = 0;i < count; i++)
4524
+ step(active, timeStep);
4525
+ accumulator = Math.max(0, accumulator - count * timeStep);
4526
+ const pending = collect(active);
4527
+ if (steps < stop)
4528
+ return Math.min(1, accumulator / timeStep);
4529
+ if (stop < until) {
4530
+ if (!pending && report(active, physics, true))
4531
+ snapped = stop;
4532
+ return Math.min(1, accumulator / timeStep);
4533
+ }
4534
+ accumulator = 0;
4535
+ if (steps === until && (reported !== until || snapping) && !pending && report(active, physics, snapping)) {
4536
+ reported = until;
4537
+ if (snapping)
4538
+ snapped = until;
4539
+ }
4540
+ return 1;
4541
+ };
4542
+ const posed = (active, id) => {
4543
+ const pose = active.pose(id);
4544
+ return pose === undefined ? [] : [[id, pose]];
4302
4545
  };
4303
4546
  const tick = (elapsed, animating) => {
4304
4547
  const delta = last === undefined ? 0 : Math.min(0.5, Math.max(0, elapsed - last));
4305
4548
  last = elapsed;
4306
- if (world === undefined || settings === null || settings.paused || !animating)
4549
+ if (world === undefined || settings === null || settings.paused)
4550
+ return;
4551
+ if (settings.until === null && !animating)
4307
4552
  return;
4308
- const timeStep = settings.timeStep;
4309
- accumulator += delta;
4310
4553
  scene.updateMatrixWorld();
4311
- while (accumulator >= timeStep) {
4312
- step(world, timeStep);
4313
- accumulator -= timeStep;
4314
- }
4315
- const alpha = settings.interpolate ? accumulator / timeStep : 1;
4554
+ const progress = settings.until === null ? free(world, settings.timeStep, delta) : driven(world, settings, settings.until, delta);
4555
+ const alpha = settings.interpolate ? progress : 1;
4316
4556
  for (const body of hosted.values()) {
4317
4557
  if (body.source.body.type === "dynamic") {
4318
4558
  body.shown = between(body.previous, body.current, alpha);
@@ -4340,6 +4580,14 @@ var createBodyHost = (engine, scene) => {
4340
4580
  contactForces = [];
4341
4581
  return drained;
4342
4582
  },
4583
+ drainReached: () => {
4584
+ if (reached.length === 0)
4585
+ return reached;
4586
+ const drained = reached;
4587
+ reached = [];
4588
+ return drained;
4589
+ },
4590
+ owesSteps: () => world !== undefined && settings !== null && !settings.paused && settings.until !== null && (steps < settings.until || reported !== settings.until || snapshotOwed(settings, settings.until)),
4343
4591
  dispose
4344
4592
  };
4345
4593
  };
@@ -4851,6 +5099,7 @@ var createSceneGraph2 = (options = {}) => {
4851
5099
  const keys = new WeakMap;
4852
5100
  const spinning = new Set;
4853
5101
  const facing = new Set;
5102
+ const facingOrder = [];
4854
5103
  const cameraTurn = new Quaternion6;
4855
5104
  const parentTurn = new Quaternion6;
4856
5105
  const sparkling = new Set;
@@ -4956,6 +5205,18 @@ var createSceneGraph2 = (options = {}) => {
4956
5205
  if (lockZ)
4957
5206
  object.rotation.z = 0;
4958
5207
  };
5208
+ const depthOf = (object) => {
5209
+ let depth = 0;
5210
+ for (let parent = object.parent;parent !== null; parent = parent.parent)
5211
+ depth += 1;
5212
+ return depth;
5213
+ };
5214
+ const faceCameras = () => {
5215
+ facingOrder.length = 0;
5216
+ facing.forEach((entry) => facingOrder.push(entry));
5217
+ facingOrder.sort((a, b) => depthOf(a.object) - depthOf(b.object));
5218
+ facingOrder.forEach(faceCamera);
5219
+ };
4959
5220
  const trailTarget = (object, local) => local ? trailPlace.copy(object.position) : object.getWorldPosition(trailPlace);
4960
5221
  const trackTrail = (entry, node) => {
4961
5222
  const current = trailing.get(entry);
@@ -5744,6 +6005,7 @@ var createSceneGraph2 = (options = {}) => {
5744
6005
  physics: null,
5745
6006
  xr: null,
5746
6007
  measure: [],
6008
+ assets: [],
5747
6009
  render: parent.render,
5748
6010
  resources: parent.resources,
5749
6011
  children: texture.children
@@ -5887,6 +6149,8 @@ var createSceneGraph2 = (options = {}) => {
5887
6149
  invalidate();
5888
6150
  physicsDescription = next.physics;
5889
6151
  bodyHost.sync(next.physics, bodySources());
6152
+ if (bodyHost.owesSteps())
6153
+ invalidate();
5890
6154
  xrDescription = next.xr;
5891
6155
  if (next.measure.join("\x00") !== measured.join("\x00"))
5892
6156
  invalidate();
@@ -5922,7 +6186,7 @@ var createSceneGraph2 = (options = {}) => {
5922
6186
  bodyHost.tick(elapsed, animating);
5923
6187
  if (facing.size > 0) {
5924
6188
  camera.getWorldQuaternion(cameraTurn);
5925
- facing.forEach(faceCamera);
6189
+ faceCameras();
5926
6190
  }
5927
6191
  edged.forEach(refreshEdges);
5928
6192
  if (animating)
@@ -6002,6 +6266,7 @@ var createSceneGraph2 = (options = {}) => {
6002
6266
  contactShadows: () => contactDescription,
6003
6267
  collisions: bodyHost.drainCollisions,
6004
6268
  contactForces: bodyHost.drainContactForces,
6269
+ physicsReached: bodyHost.drainReached,
6005
6270
  xr: () => xrDescription,
6006
6271
  measured: () => measured,
6007
6272
  labelLayout: (key) => {
@@ -6024,7 +6289,7 @@ var createSceneGraph2 = (options = {}) => {
6024
6289
  tick,
6025
6290
  elapsedSeconds: () => elapsed,
6026
6291
  renderSettings: () => settings,
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()),
6292
+ 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()) || bodyHost.owesSteps(),
6028
6293
  drawn: () => {
6029
6294
  dirty = false;
6030
6295
  },
@@ -6057,8 +6322,507 @@ var createSceneGraph2 = (options = {}) => {
6057
6322
  dispose
6058
6323
  };
6059
6324
  };
6325
+ // src/kernel/preview.ts
6326
+ import {
6327
+ Box2,
6328
+ Color as Color5,
6329
+ DirectionalLight as DirectionalLight2,
6330
+ HemisphereLight as HemisphereLight2,
6331
+ InstancedMesh as InstancedMesh2,
6332
+ LinearSRGBColorSpace,
6333
+ LineBasicMaterial as LineBasicMaterial2,
6334
+ LineDashedMaterial,
6335
+ Matrix3,
6336
+ Matrix4 as Matrix45,
6337
+ Mesh as Mesh3,
6338
+ MeshBasicMaterial as MeshBasicMaterial3,
6339
+ MeshLambertMaterial as MeshLambertMaterial2,
6340
+ MeshNormalMaterial as MeshNormalMaterial2,
6341
+ MeshPhongMaterial as MeshPhongMaterial2,
6342
+ MeshStandardMaterial as MeshStandardMaterial2,
6343
+ MeshToonMaterial,
6344
+ Light,
6345
+ Line,
6346
+ PointLight as PointLight2,
6347
+ Points,
6348
+ Scene as Scene2,
6349
+ Sprite,
6350
+ PointsMaterial,
6351
+ SpotLight as SpotLight2,
6352
+ SpriteMaterial,
6353
+ SRGBColorSpace,
6354
+ Vector2 as Vector24,
6355
+ Vector3 as Vector313,
6356
+ AmbientLight as AmbientLight2
6357
+ } from "three";
6358
+ import {
6359
+ Projector,
6360
+ RenderableFace,
6361
+ RenderableLine,
6362
+ RenderableSprite
6363
+ } from "three/addons/renderers/Projector.js";
6364
+
6365
+ // src/kernel/paintOrder.ts
6366
+ import { Sphere, Vector3 as Vector312 } from "three";
6367
+ var onPlane = 0.000001;
6368
+ var candidates = 8;
6369
+ var splitCost = 8;
6370
+ var planeOf = (points) => {
6371
+ const [a, b, c] = points;
6372
+ if (a === undefined || b === undefined || c === undefined)
6373
+ return;
6374
+ const normal = new Vector312().subVectors(b, a).cross(new Vector312().subVectors(c, a));
6375
+ if (normal.lengthSq() === 0)
6376
+ return;
6377
+ normal.normalize();
6378
+ return { normal, constant: normal.dot(a) };
6379
+ };
6380
+ var side = (plane, point) => plane.normal.dot(point) - plane.constant;
6381
+ var toleranceAt = (points) => onPlane * Math.max(1, ...points.map((point) => point.length()));
6382
+ var split = (plane, facet) => {
6383
+ const sides = facet.points.map((point) => side(plane, point));
6384
+ const tolerance = toleranceAt(facet.points);
6385
+ if (sides.every((s) => Math.abs(s) <= tolerance))
6386
+ return { on: facet };
6387
+ if (sides.every((s) => s >= -tolerance))
6388
+ return { front: facet };
6389
+ if (sides.every((s) => s <= tolerance))
6390
+ return { back: facet };
6391
+ const front = [];
6392
+ const back = [];
6393
+ facet.points.forEach((point, i) => {
6394
+ const next = facet.points[(i + 1) % facet.points.length] ?? point;
6395
+ const here = sides[i] ?? 0;
6396
+ const there = sides[(i + 1) % sides.length] ?? 0;
6397
+ if (here >= -tolerance)
6398
+ front.push(point);
6399
+ if (here <= tolerance)
6400
+ back.push(point);
6401
+ if (here > tolerance && there < -tolerance || here < -tolerance && there > tolerance) {
6402
+ const crossing = point.clone().lerp(next, here / (here - there));
6403
+ front.push(crossing);
6404
+ back.push(crossing.clone());
6405
+ }
6406
+ });
6407
+ return {
6408
+ ...front.length >= 3 ? { front: { ...facet, points: front } } : {},
6409
+ ...back.length >= 3 ? { back: { ...facet, points: back } } : {}
6410
+ };
6411
+ };
6412
+ function hidesNone(facet, facets, eye) {
6413
+ const plane = planeOf(facet.points);
6414
+ if (plane === undefined)
6415
+ return true;
6416
+ const tolerance = toleranceAt(facet.points);
6417
+ return side(plane, eye) > tolerance && facets.every((other) => other === facet || other.points.every((point) => side(plane, point) <= tolerance));
6418
+ }
6419
+ var unitOf = (facets, marks, eye) => {
6420
+ const points = [...facets.flatMap((facet) => facet.points), ...marks.map((mark) => mark.at)];
6421
+ const bounds = new Sphere().setFromPoints(points);
6422
+ const selfOrdered = facets.every((facet) => hidesNone(facet, facets, eye));
6423
+ return { facets, marks, bounds, selfOrdered };
6424
+ };
6425
+ var sizeOf = (unit) => unit.facets.length + unit.marks.length;
6426
+ var sideOf = (plane, unit) => {
6427
+ const distance = side(plane, unit.bounds.center);
6428
+ const reach = unit.bounds.radius * (1 + onPlane) + onPlane;
6429
+ return distance > reach ? 1 : distance < -reach ? -1 : 0;
6430
+ };
6431
+ var weigh = (plane, units) => {
6432
+ let cut = 0;
6433
+ let front = 0;
6434
+ let back = 0;
6435
+ for (const unit of units) {
6436
+ const whole = sideOf(plane, unit);
6437
+ if (whole > 0)
6438
+ front += sizeOf(unit);
6439
+ else if (whole < 0)
6440
+ back += sizeOf(unit);
6441
+ else {
6442
+ const parts = unit.facets.map((facet) => split(plane, facet));
6443
+ const ahead = parts.filter((part) => part.front !== undefined).length;
6444
+ const behind = parts.filter((part) => part.back !== undefined).length;
6445
+ if (ahead > 0 && behind > 0)
6446
+ cut++;
6447
+ front += ahead;
6448
+ back += behind;
6449
+ }
6450
+ }
6451
+ return splitCost * cut + Math.abs(front - back);
6452
+ };
6453
+ var partition = (plane, units) => {
6454
+ const front = [];
6455
+ const back = [];
6456
+ const on = [];
6457
+ for (const unit of units) {
6458
+ const whole = sideOf(plane, unit);
6459
+ if (whole > 0)
6460
+ front.push(unit);
6461
+ else if (whole < 0)
6462
+ back.push(unit);
6463
+ else {
6464
+ const ahead = [];
6465
+ const behind = [];
6466
+ for (const facet of unit.facets) {
6467
+ const parts = split(plane, facet);
6468
+ if (parts.front !== undefined)
6469
+ ahead.push(parts.front);
6470
+ if (parts.back !== undefined)
6471
+ behind.push(parts.back);
6472
+ if (parts.on !== undefined)
6473
+ on.push(parts.on);
6474
+ }
6475
+ const marksAhead = unit.marks.filter((mark) => side(plane, mark.at) >= 0);
6476
+ const marksBehind = unit.marks.filter((mark) => side(plane, mark.at) < 0);
6477
+ if (ahead.length + marksAhead.length > 0)
6478
+ front.push({ ...unit, facets: ahead, marks: marksAhead });
6479
+ if (behind.length + marksBehind.length > 0)
6480
+ back.push({ ...unit, facets: behind, marks: marksBehind });
6481
+ }
6482
+ }
6483
+ return { front, back, on };
6484
+ };
6485
+ var planeFor = (units) => {
6486
+ const withFacets = units.filter((unit) => unit.facets.length > 0);
6487
+ const count = Math.min(candidates, withFacets.length);
6488
+ let best;
6489
+ let lightest = Number.POSITIVE_INFINITY;
6490
+ for (let i = 0;i < count; i++) {
6491
+ const unit = withFacets[Math.floor(i * withFacets.length / count)];
6492
+ const facet = unit?.facets[Math.floor(i * (unit?.facets.length ?? 0) / count)];
6493
+ const plane = facet === undefined ? undefined : planeOf(facet.points);
6494
+ if (plane === undefined)
6495
+ continue;
6496
+ const weight = weigh(plane, units);
6497
+ if (weight < lightest) {
6498
+ lightest = weight;
6499
+ best = plane;
6500
+ }
6501
+ }
6502
+ if (best !== undefined)
6503
+ return best;
6504
+ for (const unit of withFacets) {
6505
+ for (const facet of unit.facets) {
6506
+ const plane = planeOf(facet.points);
6507
+ if (plane !== undefined)
6508
+ return plane;
6509
+ }
6510
+ }
6511
+ return;
6512
+ };
6513
+ var distanceFrom = (eye) => (mark) => mark.at.distanceToSquared(eye);
6514
+ var apart = (unit) => [
6515
+ ...unit.facets.map((facet) => ({
6516
+ facets: [facet],
6517
+ marks: [],
6518
+ bounds: new Sphere().setFromPoints([...facet.points]),
6519
+ selfOrdered: true
6520
+ })),
6521
+ ...unit.marks.map((mark) => ({
6522
+ facets: [],
6523
+ marks: [mark],
6524
+ bounds: new Sphere(mark.at.clone(), 0),
6525
+ selfOrdered: true
6526
+ }))
6527
+ ];
6528
+ var paint = (units, eye, into) => {
6529
+ const [only] = units;
6530
+ if (only !== undefined && units.length === 1) {
6531
+ if (only.selfOrdered && only.marks.length === 0) {
6532
+ into.push(...only.facets);
6533
+ return;
6534
+ }
6535
+ if (only.facets.length === 0) {
6536
+ into.push(...only.marks.toSorted((a, b) => distanceFrom(eye)(b) - distanceFrom(eye)(a)));
6537
+ return;
6538
+ }
6539
+ paint(apart(only), eye, into);
6540
+ return;
6541
+ }
6542
+ const plane = planeFor(units);
6543
+ if (plane === undefined) {
6544
+ const marks = units.flatMap((unit) => unit.marks);
6545
+ into.push(...marks.toSorted((a, b) => distanceFrom(eye)(b) - distanceFrom(eye)(a)));
6546
+ return;
6547
+ }
6548
+ const { front, back, on } = partition(plane, units);
6549
+ const facing = side(plane, eye) >= 0;
6550
+ paint(facing ? back : front, eye, into);
6551
+ into.push(...on);
6552
+ paint(facing ? front : back, eye, into);
6553
+ };
6554
+ var paintOrder = (units, eye) => {
6555
+ const into = [];
6556
+ paint(units, eye, into);
6557
+ return into;
6558
+ };
6559
+
6560
+ // src/kernel/preview.ts
6561
+ var overdraw = 0.5;
6562
+ var black = new Color5(0, 0, 0);
6563
+ var irradianceAt = (lights, position, normal, into) => {
6564
+ into.copy(black);
6565
+ const lightPosition = new Vector313;
6566
+ const toLight = new Vector313;
6567
+ const direction = new Vector313;
6568
+ for (const light of lights) {
6569
+ const color = light.color.clone().multiplyScalar(light.intensity);
6570
+ if (light instanceof AmbientLight2) {
6571
+ into.add(color);
6572
+ } else if (light instanceof HemisphereLight2) {
6573
+ lightPosition.setFromMatrixPosition(light.matrixWorld).normalize();
6574
+ const weight = 0.5 * normal.dot(lightPosition) + 0.5;
6575
+ into.add(light.groundColor.clone().lerp(light.color, weight).multiplyScalar(light.intensity));
6576
+ } else if (light instanceof DirectionalLight2) {
6577
+ lightPosition.setFromMatrixPosition(light.matrixWorld);
6578
+ direction.setFromMatrixPosition(light.target.matrixWorld);
6579
+ toLight.subVectors(lightPosition, direction).normalize();
6580
+ into.add(color.multiplyScalar(Math.max(normal.dot(toLight), 0)));
6581
+ } else if (light instanceof PointLight2 || light instanceof SpotLight2) {
6582
+ lightPosition.setFromMatrixPosition(light.matrixWorld);
6583
+ toLight.subVectors(lightPosition, position);
6584
+ const distance = toLight.length();
6585
+ toLight.normalize();
6586
+ const cone = light instanceof SpotLight2 ? spotAttenuation(light, toLight) : 1;
6587
+ const falloff = distanceAttenuation(distance, light.distance, light.decay);
6588
+ into.add(color.multiplyScalar(Math.max(normal.dot(toLight), 0) * cone * falloff));
6589
+ }
6590
+ }
6591
+ return into;
6592
+ };
6593
+ var distanceAttenuation = (distance, cutoff, decay) => {
6594
+ const falloff = 1 / Math.max(distance ** decay, 0.01);
6595
+ return cutoff > 0 ? falloff * Math.min(Math.max(1 - (distance / cutoff) ** 4, 0), 1) ** 2 : falloff;
6596
+ };
6597
+ var smoothstep = (low, high, x) => {
6598
+ const t = Math.min(Math.max((x - low) / (high - low), 0), 1);
6599
+ return t * t * (3 - 2 * t);
6600
+ };
6601
+ var spotAttenuation = (light, toLight) => {
6602
+ const direction = new Vector313().setFromMatrixPosition(light.matrixWorld).sub(new Vector313().setFromMatrixPosition(light.target.matrixWorld)).normalize();
6603
+ return smoothstep(Math.cos(light.angle), Math.cos(light.angle * (1 - light.penumbra)), direction.dot(toLight));
6604
+ };
6605
+ var faceColor = (painter, face, material, centre) => {
6606
+ if (material instanceof MeshBasicMaterial3) {
6607
+ const color = material.color.clone();
6608
+ return material.vertexColors ? color.multiply(face.color) : color;
6609
+ }
6610
+ if (material instanceof MeshNormalMaterial2) {
6611
+ const normal = face.normalModel.clone().applyMatrix3(painter.normalView).normalize();
6612
+ return new Color5(normal.x, normal.y, normal.z).multiplyScalar(0.5).addScalar(0.5);
6613
+ }
6614
+ if (material instanceof MeshLambertMaterial2 || material instanceof MeshPhongMaterial2 || material instanceof MeshStandardMaterial2 || material instanceof MeshToonMaterial) {
6615
+ const diffuse = material.color.clone();
6616
+ if (material.vertexColors)
6617
+ diffuse.multiply(face.color);
6618
+ return irradianceAt(painter.lights, centre, face.normalModel, new Color5).multiply(diffuse).multiplyScalar(1 / Math.PI).add(material.emissive.clone().multiplyScalar(material.emissiveIntensity));
6619
+ }
6620
+ return;
6621
+ };
6622
+ var styleOf = (color, colorSpace) => {
6623
+ const shown = new Color5(Math.min(Math.max(color.r, 0), 1), Math.min(Math.max(color.g, 0), 1), Math.min(Math.max(color.b, 0), 1));
6624
+ return `#${shown.getHexString(colorSpace)}`;
6625
+ };
6626
+ var opacityOf = (material) => material.transparent ? material.opacity : 1;
6627
+ var standInsFor = (object) => {
6628
+ if (!(object instanceof InstancedMesh2)) {
6629
+ const standIn = object.clone(false);
6630
+ standIn.matrix.copy(object.matrixWorld);
6631
+ return [{ standIn }];
6632
+ }
6633
+ const material = Array.isArray(object.material) ? object.material[0] : object.material;
6634
+ if (material === undefined)
6635
+ return [];
6636
+ const matrix = new Matrix45;
6637
+ const standIns = [];
6638
+ for (let i = 0;i < object.count; i++) {
6639
+ object.getMatrixAt(i, matrix);
6640
+ const tinted = object.instanceColor === null ? undefined : material.clone();
6641
+ if (tinted !== undefined && "color" in tinted && tinted.color instanceof Color5) {
6642
+ tinted.color.multiply(object.getColorAt(i, new Color5));
6643
+ }
6644
+ const standIn = new Mesh3(object.geometry, tinted ?? material);
6645
+ standIn.matrix.multiplyMatrices(object.matrixWorld, matrix);
6646
+ standIn.renderOrder = object.renderOrder;
6647
+ standIns.push(tinted === undefined ? { standIn } : { standIn, tinted });
6648
+ }
6649
+ return standIns;
6650
+ };
6651
+ var number = (precision) => (value) => String(Number(value.toFixed(precision)));
6652
+ var widened = (points) => {
6653
+ const out = points.map((point) => point.clone());
6654
+ for (const [i, from] of out.entries()) {
6655
+ const to = out[(i + 1) % out.length];
6656
+ const length = to === undefined ? 0 : from.distanceTo(to);
6657
+ if (to === undefined || length === 0)
6658
+ continue;
6659
+ const step = new Vector24().subVectors(to, from).multiplyScalar(overdraw / length);
6660
+ to.add(step);
6661
+ from.sub(step);
6662
+ }
6663
+ return out;
6664
+ };
6665
+ var facetPaint = (fill, opacity) => opacity < 1 ? `fill="${fill}" fill-opacity="${String(Number(opacity.toFixed(2)))}"` : `fill="${fill}" stroke="${fill}"`;
6666
+ var centreOf2 = (object) => {
6667
+ if (!(object instanceof Mesh3))
6668
+ return new Vector313().setFromMatrixPosition(object.matrixWorld);
6669
+ const geometry = object.geometry;
6670
+ if (geometry.boundingSphere === null)
6671
+ geometry.computeBoundingSphere();
6672
+ return (geometry.boundingSphere?.center.clone() ?? new Vector313).applyMatrix4(object.matrixWorld);
6673
+ };
6674
+ var isDrawn = (object) => object instanceof Mesh3 || object instanceof Line || object instanceof Points || object instanceof Sprite;
6675
+ var previewSvg2 = (description, options) => {
6676
+ const { width, height } = options;
6677
+ const graph = createSceneGraph2({
6678
+ ...options.store === undefined ? {} : { store: options.store },
6679
+ ...options.behaviours === undefined ? {} : { behaviours: options.behaviours }
6680
+ });
6681
+ const applied = graph.reconcile(description);
6682
+ if (applied._tag === "Invalid") {
6683
+ graph.dispose();
6684
+ return applied;
6685
+ }
6686
+ graph.resize(width, height);
6687
+ graph.tick(options.at ?? 0);
6688
+ const { scene, camera } = graph;
6689
+ scene.updateMatrixWorld();
6690
+ camera.updateMatrixWorld();
6691
+ const lights = [];
6692
+ const drawn = [];
6693
+ scene.traverseVisible((object) => {
6694
+ if (object instanceof Light)
6695
+ lights.push(object);
6696
+ else if (isDrawn(object))
6697
+ drawn.push(object);
6698
+ });
6699
+ const colorSpace = graph.renderSettings().colorSpace === "linear" ? LinearSRGBColorSpace : SRGBColorSpace;
6700
+ const painter = {
6701
+ lights,
6702
+ normalView: new Matrix3().getNormalMatrix(camera.matrixWorldInverse),
6703
+ colorSpace
6704
+ };
6705
+ const halfWidth = width / 2;
6706
+ const halfHeight = height / 2;
6707
+ const at = number(options.precision ?? 1);
6708
+ const eye = new Vector313().setFromMatrixPosition(camera.matrixWorld);
6709
+ const ahead = camera.getWorldDirection(new Vector313);
6710
+ const near = { normal: ahead, constant: ahead.dot(eye) + camera.near };
6711
+ const xy = (x, y) => `${at(x * halfWidth)},${at(-y * halfHeight)}`;
6712
+ function facetOf(face, material, centre, opacity) {
6713
+ const color = faceColor(painter, face, material, centre);
6714
+ if (color === undefined)
6715
+ return;
6716
+ const points = [face.v1, face.v2, face.v3].map((vertex) => vertex.positionWorld.clone());
6717
+ const paint = facetPaint(styleOf(color, colorSpace), opacity);
6718
+ return split(near, { _tag: "Facet", points, item: { paint, d: "" } }).front;
6719
+ }
6720
+ const projector = new Projector;
6721
+ const holder = new Scene2;
6722
+ const units = [];
6723
+ const over = [];
6724
+ const tinted = [];
6725
+ for (const object of drawn) {
6726
+ for (const { standIn, tinted: copy } of standInsFor(object)) {
6727
+ if (copy !== undefined)
6728
+ tinted.push(copy);
6729
+ standIn.matrixAutoUpdate = false;
6730
+ holder.add(standIn);
6731
+ const projected = projector.projectScene(holder, camera, false, true);
6732
+ holder.remove(standIn);
6733
+ const centre = centreOf2(standIn);
6734
+ const facets = [];
6735
+ const marks = [];
6736
+ const keep = (material, item) => {
6737
+ if (!material.depthTest)
6738
+ over.push({ renderOrder: standIn.renderOrder, item });
6739
+ else if (item._tag === "Facet")
6740
+ facets.push(item);
6741
+ else
6742
+ marks.push(item);
6743
+ };
6744
+ for (const element of projected.elements) {
6745
+ const material = element.material;
6746
+ if (material === null || material.opacity === 0)
6747
+ continue;
6748
+ const opacity = opacityOf(material);
6749
+ const faded = opacity < 1 ? ` fill-opacity="${at(opacity)}"` : "";
6750
+ if (element instanceof RenderableFace) {
6751
+ const seen = facetOf(element, material, centre, opacity);
6752
+ if (seen === undefined)
6753
+ continue;
6754
+ keep(material, seen);
6755
+ } else if (element instanceof RenderableLine && material instanceof LineBasicMaterial2) {
6756
+ const a = element.v1.positionScreen;
6757
+ const b = element.v2.positionScreen;
6758
+ const dashes = material instanceof LineDashedMaterial ? ` stroke-dasharray="${at(material.dashSize)},${at(material.gapSize)}"` : "";
6759
+ const stroked = opacity < 1 ? ` stroke-opacity="${at(opacity)}"` : "";
6760
+ keep(material, {
6761
+ _tag: "Mark",
6762
+ at: element.v1.positionWorld.clone().lerp(element.v2.positionWorld, 0.5),
6763
+ item: {
6764
+ paint: `fill="none" stroke="${styleOf(material.color, colorSpace)}"${stroked} stroke-width="${at(material.linewidth)}" stroke-linecap="${material.linecap}"${dashes}`,
6765
+ d: `M${xy(a.x, a.y)}L${xy(b.x, b.y)}`
6766
+ }
6767
+ });
6768
+ } else if (element instanceof RenderableSprite && (material instanceof SpriteMaterial || material instanceof PointsMaterial)) {
6769
+ const size = material instanceof PointsMaterial ? material.size : 1;
6770
+ const w = element.scale.x * halfWidth * size;
6771
+ const h = element.scale.y * halfHeight * size;
6772
+ const x = element.x * halfWidth;
6773
+ const y = -element.y * halfHeight;
6774
+ keep(material, {
6775
+ _tag: "Mark",
6776
+ at: new Vector313(element.x, element.y, element.z).unproject(camera),
6777
+ item: {
6778
+ paint: `fill="${styleOf(material.color, colorSpace)}"${faded}`,
6779
+ d: `M${at(x - w / 2)},${at(y - h / 2)}h${at(w)}v${at(h)}h${at(-w)}z`
6780
+ }
6781
+ });
6782
+ }
6783
+ }
6784
+ if (facets.length + marks.length > 0)
6785
+ units.push(unitOf(facets, marks, eye));
6786
+ }
6787
+ }
6788
+ for (const material of tinted)
6789
+ material.dispose();
6790
+ graph.dispose();
6791
+ const ordered = [
6792
+ ...paintOrder(units, eye),
6793
+ ...over.toSorted((a, b) => a.renderOrder - b.renderOrder).map(({ item }) => item)
6794
+ ];
6795
+ const clip = new Box2(new Vector24(-halfWidth, -halfHeight), new Vector24(halfWidth, halfHeight));
6796
+ const toPicture = (point) => {
6797
+ const projectedPoint = point.clone().project(camera);
6798
+ return new Vector24(projectedPoint.x * halfWidth, -projectedPoint.y * halfHeight);
6799
+ };
6800
+ function outlineOf(shape) {
6801
+ if (shape._tag === "Mark")
6802
+ return shape.item.d;
6803
+ const corners = widened(shape.points.map(toPicture));
6804
+ return new Box2().setFromPoints([...corners]).intersectsBox(clip) ? `M${corners.map((corner) => `${at(corner.x)},${at(corner.y)}`).join("L")}z` : undefined;
6805
+ }
6806
+ const groups = [];
6807
+ for (const shape of ordered) {
6808
+ const outline = outlineOf(shape);
6809
+ const last = groups.at(-1);
6810
+ if (outline === undefined)
6811
+ continue;
6812
+ if (last?.paint === shape.item.paint)
6813
+ last.outlines.push(outline);
6814
+ else
6815
+ groups.push({ paint: shape.item.paint, outlines: [outline] });
6816
+ }
6817
+ const paths = groups.map(({ paint, outlines }) => `<path ${paint} d="${outlines.join("")}"/>`);
6818
+ const background = options.background === undefined || options.background === null ? "" : `<rect x="${at(-halfWidth)}" y="${at(-halfHeight)}" width="${at(width)}" height="${at(height)}" fill="${styleOf(new Color5(options.background), colorSpace)}"/>`;
6819
+ return {
6820
+ _tag: "Preview",
6821
+ svg: `<svg xmlns="http://www.w3.org/2000/svg" width="${at(width)}" height="${at(height)}" viewBox="${at(-halfWidth)} ${at(-halfHeight)} ${at(width)} ${at(height)}">${background}<g stroke-width="0.6" stroke-linejoin="round">${paths.join("")}</g></svg>`
6822
+ };
6823
+ };
6060
6824
  // src/kernel/gizmo.ts
6061
- import { Euler as Euler6, Quaternion as Quaternion7, Vector3 as Vector312 } from "three";
6825
+ import { Euler as Euler6, Quaternion as Quaternion7, Vector3 as Vector314 } from "three";
6062
6826
  var gizmo2 = (options = {}) => ({
6063
6827
  mode: options.mode ?? "translate",
6064
6828
  space: options.space ?? "world",
@@ -6073,9 +6837,9 @@ var gizmo2 = (options = {}) => ({
6073
6837
  grab: null
6074
6838
  });
6075
6839
  var axes = {
6076
- x: new Vector312(1, 0, 0),
6077
- y: new Vector312(0, 1, 0),
6078
- z: new Vector312(0, 0, 1)
6840
+ x: new Vector314(1, 0, 0),
6841
+ y: new Vector314(0, 1, 0),
6842
+ z: new Vector314(0, 0, 1)
6079
6843
  };
6080
6844
  var turnOf = (rotation) => new Quaternion7().setFromEuler(new Euler6(rotation[0], rotation[1], rotation[2]));
6081
6845
  var spaceOf = (state, handle) => {
@@ -6104,30 +6868,30 @@ var dragPlane = (state, handle, start, eye, facingCamera) => {
6104
6868
  if (normal.lengthSq() < 0.000000000001)
6105
6869
  normal.copy(eye);
6106
6870
  normal.normalize();
6107
- const center = new Vector312(...start.position);
6871
+ const center = new Vector314(...start.position);
6108
6872
  return { normal: toVec34(normal), constant: -normal.dot(center) };
6109
6873
  };
6110
- var onPlane = (grab, ray) => {
6874
+ var onPlane2 = (grab, ray) => {
6111
6875
  const point = pointOnPlane2(ray, grab.plane);
6112
6876
  if (point === undefined)
6113
6877
  return;
6114
- return new Vector312(...point).sub(new Vector312(...grab.start.position));
6878
+ return new Vector314(...point).sub(new Vector314(...grab.start.position));
6115
6879
  };
6116
6880
  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);
6881
+ const back = new Vector314(...camera.position).sub(new Vector314(...camera.lookAt));
6882
+ return back.lengthSq() > 0.000000000001 ? back.normalize() : new Vector314(0, 0, 1);
6119
6883
  };
6120
6884
  var pressGizmo2 = (state, placement, handle, ray, camera) => {
6121
- const center = new Vector312(...placement.position);
6885
+ const center = new Vector314(...placement.position);
6122
6886
  const facingCamera = backwards(camera);
6123
- const towardsEye = new Vector312(...camera.position).sub(center);
6887
+ const towardsEye = new Vector314(...camera.position).sub(center);
6124
6888
  const distance = towardsEye.length();
6125
6889
  const eye = camera._tag === "Orthographic" || distance < 0.000000001 ? facingCamera.clone() : towardsEye.normalize();
6126
6890
  const plane = dragPlane(state, handle, placement, eye, facingCamera);
6127
6891
  const point = pointOnPlane2(ray, plane);
6128
6892
  if (point === undefined)
6129
6893
  return state;
6130
- const from = toVec34(new Vector312(...point).sub(center));
6894
+ const from = toVec34(new Vector314(...point).sub(center));
6131
6895
  return { ...state, grab: { handle, start: placement, from, plane, eye: toVec34(eye), distance } };
6132
6896
  };
6133
6897
  var releaseGizmo2 = (state) => ({ ...state, grab: null });
@@ -6136,7 +6900,7 @@ var snapped = (value, step) => step === null ? value : Math.round(value / step)
6136
6900
  var includes = (handle, axis) => handle.includes(axis);
6137
6901
  var translated = (state, grab, end) => {
6138
6902
  const space = spaceOf(state, grab.handle);
6139
- const offset = end.clone().sub(new Vector312(...grab.from));
6903
+ const offset = end.clone().sub(new Vector314(...grab.from));
6140
6904
  const turn = turnOf(grab.start.rotation);
6141
6905
  if (space === "local")
6142
6906
  offset.applyQuaternion(turn.clone().invert());
@@ -6147,7 +6911,7 @@ var translated = (state, grab, end) => {
6147
6911
  if (!includes(grab.handle, "z"))
6148
6912
  offset.z = 0;
6149
6913
  if (space === "local") {
6150
- const local = offset.add(new Vector312(...grab.start.position).applyQuaternion(turn.clone().invert()));
6914
+ const local = offset.add(new Vector314(...grab.start.position).applyQuaternion(turn.clone().invert()));
6151
6915
  if (includes(grab.handle, "x"))
6152
6916
  local.x = snapped(local.x, state.translationSnap);
6153
6917
  if (includes(grab.handle, "y"))
@@ -6156,7 +6920,7 @@ var translated = (state, grab, end) => {
6156
6920
  local.z = snapped(local.z, state.translationSnap);
6157
6921
  return { ...grab.start, position: toVec34(local.applyQuaternion(turn)) };
6158
6922
  }
6159
- const position = offset.add(new Vector312(...grab.start.position));
6923
+ const position = offset.add(new Vector314(...grab.start.position));
6160
6924
  if (includes(grab.handle, "x"))
6161
6925
  position.x = snapped(position.x, state.translationSnap);
6162
6926
  if (includes(grab.handle, "y"))
@@ -6166,8 +6930,8 @@ var translated = (state, grab, end) => {
6166
6930
  return { ...grab.start, position: toVec34(position) };
6167
6931
  };
6168
6932
  var scaled2 = (state, grab, end) => {
6169
- const from = new Vector312(...grab.from);
6170
- const factor = new Vector312(1, 1, 1);
6933
+ const from = new Vector314(...grab.from);
6934
+ const factor = new Vector314(1, 1, 1);
6171
6935
  if (grab.handle === "xyz") {
6172
6936
  const ratio = end.length() / Math.max(from.length(), 0.000000001) * (end.dot(from) < 0 ? -1 : 1);
6173
6937
  factor.setScalar(ratio);
@@ -6190,10 +6954,10 @@ var rotated = (state, grab, end) => {
6190
6954
  if (grab.handle !== "x" && grab.handle !== "y" && grab.handle !== "z")
6191
6955
  return grab.start;
6192
6956
  const space = spaceOf(state, grab.handle);
6193
- const offset = end.clone().sub(new Vector312(...grab.from));
6957
+ const offset = end.clone().sub(new Vector314(...grab.from));
6194
6958
  const speed = 20 / Math.max(grab.distance, 0.000000001);
6195
6959
  const axis = axisIn(grab.handle, space, grab.start.rotation);
6196
- const across = axis.clone().cross(new Vector312(...grab.eye));
6960
+ const across = axis.clone().cross(new Vector314(...grab.eye));
6197
6961
  const angle = snapped(across.lengthSq() < 0.000000000001 ? 0 : offset.dot(across.normalize()) * speed, state.rotationSnap);
6198
6962
  const start = turnOf(grab.start.rotation);
6199
6963
  const turn = space === "local" ? start.clone().multiply(new Quaternion7().setFromAxisAngle(axes[grab.handle], angle)) : new Quaternion7().setFromAxisAngle(axes[grab.handle], angle).multiply(start);
@@ -6204,7 +6968,7 @@ var dragGizmo2 = (state, ray) => {
6204
6968
  const grab = state.grab;
6205
6969
  if (grab === null)
6206
6970
  return;
6207
- const end = onPlane(grab, ray);
6971
+ const end = onPlane2(grab, ray);
6208
6972
  if (end === undefined)
6209
6973
  return grab.start;
6210
6974
  if (state.mode === "translate")
@@ -6237,7 +7001,7 @@ var hideThreshold = 0.99;
6237
7001
  var screenScale = (state, at, camera) => {
6238
7002
  if (camera._tag === "Orthographic")
6239
7003
  return 480 / camera.zoom * state.size / 4;
6240
- const distance = new Vector312(...camera.position).distanceTo(new Vector312(...at));
7004
+ const distance = new Vector314(...camera.position).distanceTo(new Vector314(...at));
6241
7005
  const spread = Math.min(1.9 * Math.tan(Math.PI * camera.fov / 360), 7);
6242
7006
  return distance * spread * state.size / 4;
6243
7007
  };
@@ -6326,7 +7090,7 @@ var planeHandles = (key, state) => {
6326
7090
  var gizmoNodes2 = (key, state, placement, camera) => {
6327
7091
  const space = spaceOf(state, state.grab?.handle ?? null);
6328
7092
  const scale = screenScale(state, placement.position, camera);
6329
- const eye = new Vector312(...camera.position).sub(new Vector312(...placement.position)).normalize();
7093
+ const eye = new Vector314(...camera.position).sub(new Vector314(...placement.position)).normalize();
6330
7094
  const shown = { x: state.showX, y: state.showY, z: state.showZ };
6331
7095
  const visible = (axis) => shown[axis] && (state.mode === "rotate" || state.grab?.handle === axis || Math.abs(axisIn(axis, space, placement.rotation).dot(eye)) <= hideThreshold);
6332
7096
  return group2({
@@ -6349,7 +7113,7 @@ var gizmoNodes2 = (key, state, placement, camera) => {
6349
7113
  });
6350
7114
  };
6351
7115
  // src/kernel/boxSelect.ts
6352
- import { OrthographicCamera as OrthographicCamera5, PerspectiveCamera as PerspectiveCamera4, Vector3 as Vector313 } from "three";
7116
+ import { OrthographicCamera as OrthographicCamera5, PerspectiveCamera as PerspectiveCamera4, Vector3 as Vector315 } from "three";
6353
7117
  var hostCamera2 = (camera, size) => {
6354
7118
  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
7119
  if (host instanceof OrthographicCamera5 && camera._tag === "Orthographic") {
@@ -6365,7 +7129,7 @@ var between2 = (value, a, b) => value >= Math.min(a, b) && value <= Math.max(a,
6365
7129
  var boxSelect2 = (camera, size, from, to, candidates) => {
6366
7130
  const host = hostCamera2(camera, size);
6367
7131
  const inside = (candidate) => {
6368
- const seen = new Vector313(...candidate.at).project(host);
7132
+ const seen = new Vector315(...candidate.at).project(host);
6369
7133
  return between2(seen.x, from.x, to.x) && between2(seen.y, from.y, to.y) && between2(seen.z, -1, 1);
6370
7134
  };
6371
7135
  return candidates.filter(inside).map((candidate) => candidate.key);
@@ -6505,6 +7269,43 @@ var remove = (state, peer, until) => ({
6505
7269
  members: state.members.map((member) => member.peer === peer && (member.until === null || until < member.until) ? { ...member, until } : member),
6506
7270
  received: state.received.filter((packet) => packet.peer !== peer || packet.turn < until)
6507
7271
  });
7272
+ // src/kernel/timeline.ts
7273
+ var make3 = (frontier = 0) => ({
7274
+ inputs: [],
7275
+ applied: 0,
7276
+ reached: null,
7277
+ frontier
7278
+ });
7279
+ var schedule = (timeline, step, input) => {
7280
+ const at = timeline.inputs.findIndex((scheduled) => scheduled.step > step);
7281
+ const index = at < 0 ? timeline.inputs.length : at;
7282
+ return {
7283
+ ...timeline,
7284
+ inputs: [...timeline.inputs.slice(0, index), { step, input }, ...timeline.inputs.slice(index)]
7285
+ };
7286
+ };
7287
+ var extend = (timeline, frontier) => frontier <= timeline.frontier ? timeline : { ...timeline, frontier };
7288
+ var reach = (timeline, step) => timeline.reached === step ? timeline : { ...timeline, reached: step };
7289
+ var due = (timeline) => {
7290
+ const { reached } = timeline;
7291
+ if (reached === null)
7292
+ return { timeline, inputs: [] };
7293
+ let applied = timeline.applied;
7294
+ while ((timeline.inputs[applied]?.step ?? Infinity) <= reached)
7295
+ applied += 1;
7296
+ if (applied === timeline.applied)
7297
+ return { timeline, inputs: [] };
7298
+ return {
7299
+ timeline: { ...timeline, applied },
7300
+ inputs: timeline.inputs.slice(timeline.applied, applied).map((scheduled) => scheduled.input)
7301
+ };
7302
+ };
7303
+ var until = (timeline) => Math.min(timeline.inputs[timeline.applied]?.step ?? Infinity, timeline.frontier);
7304
+ var restart = (timeline) => ({
7305
+ ...timeline,
7306
+ applied: 0,
7307
+ reached: null
7308
+ });
6508
7309
  // src/kernel/describeScene.ts
6509
7310
  var extentOf = (geometry) => {
6510
7311
  switch (geometry._tag) {
@@ -6547,7 +7348,7 @@ var shapeOf = (geometry, description) => {
6547
7348
  return geometry;
6548
7349
  return description.resources.geometries.find((entry) => entry.id === geometry.id)?.geometry;
6549
7350
  };
6550
- var sizeOf = (node, description) => {
7351
+ var sizeOf2 = (node, description) => {
6551
7352
  if (node._tag !== "Mesh")
6552
7353
  return null;
6553
7354
  const shape = shapeOf(node.geometry, description);
@@ -6576,7 +7377,7 @@ var thingsIn = (nodes, parent, description) => nodes.flatMap((node) => [
6576
7377
  key: node.key,
6577
7378
  kind: kindOf(node),
6578
7379
  position: "position" in node ? node.position : [0, 0, 0],
6579
- size: sizeOf(node, description),
7380
+ size: sizeOf2(node, description),
6580
7381
  colour: colourOf(node),
6581
7382
  parent
6582
7383
  }
@@ -6618,17 +7419,17 @@ var describeScene2 = (description) => {
6618
7419
  staging: stagingOf(description)
6619
7420
  };
6620
7421
  };
6621
- var number = (value) => String(Math.round(value * 100) / 100);
6622
- var point2 = (at) => `(${at.map(number).join(", ")})`;
7422
+ var number2 = (value) => String(Math.round(value * 100) / 100);
7423
+ var point2 = (at) => `(${at.map(number2).join(", ")})`;
6623
7424
  var hex = (colour) => `#${colour.toString(16).padStart(6, "0")}`;
6624
7425
  var thingLine = (thing) => [
6625
7426
  `- ${thing.key}: ${thing.kind}`,
6626
- thing.size === null ? "" : `, ${thing.size.map(number).join(" × ")}`,
7427
+ thing.size === null ? "" : `, ${thing.size.map(number2).join(" × ")}`,
6627
7428
  thing.colour === null ? "" : `, ${hex(thing.colour)}`,
6628
7429
  `, at ${point2(thing.position)}`,
6629
7430
  thing.parent === null ? "" : ` in ${thing.parent}`
6630
7431
  ].join("");
6631
- var lightLine = (light) => `- ${light.key}: ${light.kind}, ${hex(light.colour)} × ${number(light.intensity)}${light.position === null ? "" : ` at ${point2(light.position)}`}`;
7432
+ var lightLine = (light) => `- ${light.key}: ${light.kind}, ${hex(light.colour)} × ${number2(light.intensity)}${light.position === null ? "" : ` at ${point2(light.position)}`}`;
6632
7433
  var formatSummary2 = (summary) => [
6633
7434
  `Camera: ${summary.camera.kind.toLowerCase()} at ${point2(summary.camera.position)}, looking at ${point2(summary.camera.lookAt)}`,
6634
7435
  `Things (${summary.things.length})${summary.bounds === null ? "" : `, within ${point2(summary.bounds.min)} to ${point2(summary.bounds.max)}`}:`,
@@ -6639,7 +7440,7 @@ var formatSummary2 = (summary) => [
6639
7440
  ].join(`
6640
7441
  `);
6641
7442
  // src/kernel/shots.ts
6642
- import { Vector3 as Vector314 } from "three";
7443
+ import { Vector3 as Vector316 } from "three";
6643
7444
  var shotAngles2 = [
6644
7445
  "front",
6645
7446
  "back",
@@ -6659,8 +7460,8 @@ var directionOf = {
6659
7460
  low: [0.35, -0.02, 1]
6660
7461
  };
6661
7462
  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);
7463
+ const centre = new Vector316(...subject.min).add(new Vector316(...subject.max)).multiplyScalar(0.5);
7464
+ const from = new Vector316(...directionOf[angle]).normalize().add(centre);
6664
7465
  const aimed = {
6665
7466
  ...camera,
6666
7467
  position: [from.x, from.y, from.z],
@@ -7071,7 +7872,7 @@ var tapeNodes2 = (key, state, look = {}) => {
7071
7872
  return group2({ key, children: [...span, ...ends] });
7072
7873
  };
7073
7874
  // src/kernel/pivot.ts
7074
- import { Euler as Euler7, Quaternion as Quaternion8, Vector3 as Vector315 } from "three";
7875
+ import { Euler as Euler7, Quaternion as Quaternion8, Vector3 as Vector317 } from "three";
7075
7876
  var pivot2 = (options = {}) => ({
7076
7877
  scale: options.scale ?? 1,
7077
7878
  depthTest: options.depthTest ?? true,
@@ -7083,11 +7884,11 @@ var pivot2 = (options = {}) => ({
7083
7884
  grab: null
7084
7885
  });
7085
7886
  var unit = {
7086
- x: new Vector315(1, 0, 0),
7087
- y: new Vector315(0, 1, 0),
7088
- z: new Vector315(0, 0, 1)
7887
+ x: new Vector317(1, 0, 0),
7888
+ y: new Vector317(0, 1, 0),
7889
+ z: new Vector317(0, 0, 1)
7089
7890
  };
7090
- var planeOf = {
7891
+ var planeOf2 = {
7091
7892
  z: ["x", "y"],
7092
7893
  y: ["z", "x"],
7093
7894
  x: ["y", "z"]
@@ -7099,7 +7900,7 @@ var axisOf = (handle) => handle.split("-")[1];
7099
7900
  var frameOf = (handle, placement) => {
7100
7901
  const turn = turnOf2(placement.rotation);
7101
7902
  const axis = axisOf(handle);
7102
- const [first, second] = planeOf[axis];
7903
+ const [first, second] = planeOf2[axis];
7103
7904
  const kind = kindOf2(handle);
7104
7905
  const flat = kind === "slider" || kind === "rotator";
7105
7906
  const e1 = (flat ? unit[first] : unit[axis]).clone().applyQuaternion(turn);
@@ -7123,8 +7924,8 @@ var pressPivot2 = (state, placement, handle, point) => {
7123
7924
  var releasePivot2 = (state) => ({ ...state, grab: null });
7124
7925
  var hoverPivot2 = (state, handle) => state.hovered === handle ? state : { ...state, hovered: handle };
7125
7926
  var offsetAlong = (point, direction, ray) => {
7126
- const origin = new Vector315(...ray.origin);
7127
- const toward = new Vector315(...ray.direction);
7927
+ const origin = new Vector317(...ray.origin);
7928
+ const toward = new Vector317(...ray.direction);
7128
7929
  const e1 = direction.dot(direction);
7129
7930
  const e2 = direction.dot(point) - direction.dot(origin);
7130
7931
  const e3 = direction.dot(toward);
@@ -7135,8 +7936,8 @@ var offsetAlong = (point, direction, ray) => {
7135
7936
  return -v1.dot(v2) / v1.dot(v1);
7136
7937
  };
7137
7938
  var meetPlane = (ray, at, normal) => {
7138
- const origin = new Vector315(...ray.origin);
7139
- const toward = new Vector315(...ray.direction);
7939
+ const origin = new Vector317(...ray.origin);
7940
+ const toward = new Vector317(...ray.direction);
7140
7941
  const facing = normal.dot(toward);
7141
7942
  if (facing === 0)
7142
7943
  return;
@@ -7148,15 +7949,15 @@ var angleBetween = (from, to, at, e1, e2) => {
7148
7949
  return Math.atan2(b.dot(e2), b.dot(e1)) - Math.atan2(a.dot(e2), a.dot(e1));
7149
7950
  };
7150
7951
  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)
7952
+ point: new Vector317(...grab.point),
7953
+ e1: new Vector317(...grab.e1),
7954
+ e2: new Vector317(...grab.e2),
7955
+ normal: new Vector317(...grab.normal),
7956
+ at: new Vector317(...grab.start.position)
7156
7957
  });
7157
7958
  var moved2 = (start, by) => ({
7158
7959
  ...start,
7159
- position: toVec35(new Vector315(...start.position).add(by))
7960
+ position: toVec35(new Vector317(...start.position).add(by))
7160
7961
  });
7161
7962
  var arrowDrag = (grab, ray) => {
7162
7963
  const { point, e1 } = vectorsOf(grab);
@@ -7335,7 +8136,7 @@ var pivotNodes2 = (key, state, placement) => group2({
7335
8136
  ]
7336
8137
  });
7337
8138
  // src/kernel/viewportGizmo.ts
7338
- import { Euler as Euler8, Matrix4 as Matrix45, Quaternion as Quaternion9, Vector3 as Vector316 } from "three";
8139
+ import { Euler as Euler8, Matrix4 as Matrix46, Quaternion as Quaternion9, Vector3 as Vector318 } from "three";
7339
8140
  var colours3 = { x: 16719968, y: 2154368, z: 2130175 };
7340
8141
  var ink = 0;
7341
8142
  var directions = {
@@ -7347,7 +8148,7 @@ var directions = {
7347
8148
  "-z": [0, 0, -1]
7348
8149
  };
7349
8150
  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)));
8151
+ var cameraTurn = (camera) => new Quaternion9().setFromRotationMatrix(new Matrix46().lookAt(new Vector318(...camera.position), new Vector318(...camera.lookAt), new Vector318(0, 1, 0)));
7351
8152
  var gizmoTurn = (camera) => {
7352
8153
  const turn = new Euler8().setFromQuaternion(cameraTurn(camera).invert());
7353
8154
  return [turn.x, turn.y, turn.z];
@@ -7437,15 +8238,15 @@ var viewportAxisOf2 = (key, hit) => {
7437
8238
  return axes2.find((candidate) => candidate === axis);
7438
8239
  };
7439
8240
  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]);
8241
+ const target = new Vector318(...camera.lookAt);
8242
+ const distance = new Vector318(...camera.position).distanceTo(target);
8243
+ const direction = new Vector318(...directions[axis]);
7443
8244
  if (axis === "y" || axis === "-y")
7444
8245
  direction.z = 0.000001;
7445
8246
  const position = direction.normalize().multiplyScalar(distance).add(target);
7446
8247
  return { ...camera, position: [position.x, position.y, position.z] };
7447
8248
  };
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 };
8249
+ 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, assetsEqual2, 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, modelAsset2, textureAsset2, environmentAsset2, fontAsset2, 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, snapshotText2, snapshotBytes2, colliderFor2, describedColliders2, collidersFor2, colliderSignature2, locomote2, teleport2, glided2, createXrTracker2, environmentPresets2, environmentPresetUrl2, stagePresets2, stage2, centerOffset2, stageBounds2, noModifiers2, pointOnPlane2, createPicker2, createPointerTracker2, createSceneLoop2, recordingRendererFactory2, createSceneGraph2, previewSvg2, gizmo2, pressGizmo2, releaseGizmo2, hoverGizmo2, dragGizmo2, movedAlike2, gizmoHandleOf2, gizmoNodes2, boxSelect2, exports_history, exports_lockstep, exports_timeline, 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 };
7449
8250
 
7450
- //# debugId=9610D685ADCF1F6764756E2164756E21
7451
- //# sourceMappingURL=index-h3vf50fn.js.map
8251
+ //# debugId=0311CB843C4BF34064756E2164756E21
8252
+ //# sourceMappingURL=index-re3rrfwd.js.map