@scenoco-three/editor 0.4.0 → 0.5.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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -17
  3. package/app/cameraRig.ts +73 -12
  4. package/app/commands.ts +5 -1
  5. package/app/desktopControls.ts +13 -10
  6. package/app/document.ts +474 -427
  7. package/app/editLog.ts +127 -0
  8. package/app/editor.css +51 -0
  9. package/app/gizmo.ts +100 -6
  10. package/app/index.html +6 -122
  11. package/app/main.ts +488 -304
  12. package/app/meta.ts +24 -0
  13. package/app/picking.ts +47 -0
  14. package/app/session.ts +476 -311
  15. package/app/touchControls.ts +85 -62
  16. package/app/ui-react/AddMemberPopup.tsx +114 -0
  17. package/app/ui-react/BottomLauncher.tsx +15 -0
  18. package/app/ui-react/EditorUI.tsx +22 -0
  19. package/app/ui-react/FilePicker.tsx +80 -0
  20. package/app/ui-react/HeadBtn.tsx +21 -0
  21. package/app/ui-react/InspectorSheet.tsx +475 -0
  22. package/app/ui-react/NodeListSheet.tsx +56 -0
  23. package/app/ui-react/TopBar.tsx +137 -0
  24. package/app/ui-react/Tree.tsx +106 -0
  25. package/app/ui-react/cx.ts +4 -0
  26. package/app/ui-react/fields.tsx +407 -0
  27. package/app/ui-react/format.ts +30 -0
  28. package/app/ui-react/mount.tsx +31 -0
  29. package/app/ui-react/store.ts +80 -0
  30. package/app/ui-react/types.ts +88 -0
  31. package/app/ui-react/ui.module.css +250 -0
  32. package/app/ui-react/useSize.ts +20 -0
  33. package/app/values.ts +137 -0
  34. package/dist/cli/index.js +93 -70
  35. package/dist/index.d.ts +10 -3
  36. package/dist/index.js +9 -5
  37. package/dist/mcp.d.ts +28 -12
  38. package/dist/mcp.js +172 -131
  39. package/dist/protocol.d.ts +74 -65
  40. package/dist/protocol.js +17 -4
  41. package/dist/server.d.ts +106 -39
  42. package/dist/server.js +386 -361
  43. package/package.json +25 -10
  44. package/app/filePicker.ts +0 -64
  45. package/app/panels.ts +0 -553
  46. package/app/toolbar.ts +0 -131
  47. package/app/wsClient.ts +0 -92
  48. package/dist/args.d.ts +0 -8
  49. package/dist/args.js +0 -28
package/app/meta.ts ADDED
@@ -0,0 +1,24 @@
1
+ import type { Object3D } from 'three';
2
+
3
+ /**
4
+ * The few things the chrome needs to say about a live object.
5
+ *
6
+ * v1 read these off `Object3D` itself — the runtime carried `sceneTag` and `sceneId` because the
7
+ * bundle put them there. Nothing does now: the *document* knows which element built a node, so
8
+ * the editor asks it, and a node with no element is one nothing authored.
9
+ */
10
+
11
+ /**
12
+ * Gizmo handles and helpers, which belong to the editor rather than to the scene.
13
+ *
14
+ * Asks about this object alone — the chrome lists roots. Picking asks the same question of every
15
+ * ancestor, because a ray lands deep inside a helper; that one is in `picking.ts`.
16
+ */
17
+ export function isEditorOnly(object: Object3D): boolean {
18
+ return object.userData.scenocoEditorOnly === true;
19
+ }
20
+
21
+ export const round = (n: number): number => Math.round(n * 1000) / 1000;
22
+
23
+ /** Radians on a live `Euler` → the degrees a document is written in. */
24
+ export const toDeg = (radians: number): number => round((radians * 180) / Math.PI);
package/app/picking.ts ADDED
@@ -0,0 +1,47 @@
1
+ import { Raycaster, Vector2, type Camera, type Object3D, type Scene } from 'three';
2
+ import { findProvenance } from '@scenoco-three/core';
3
+
4
+ const raycaster = new Raycaster();
5
+ const pointer = new Vector2();
6
+
7
+ /**
8
+ * What a click at these coordinates selects: the nearest node a **document** authored.
9
+ *
10
+ * A ray hits some deeply nested mesh inside a model nobody wrote by hand, so the hit itself is
11
+ * rarely the answer — the thing worth selecting is the element that put it there, which is what
12
+ * the compiler's provenance stamp says.
13
+ *
14
+ * Returns null for a click on nothing, and for a click on something the editor drew for itself.
15
+ */
16
+ export function pickAt(
17
+ event: { clientX: number; clientY: number },
18
+ canvas: HTMLCanvasElement,
19
+ scene: Scene,
20
+ camera: Camera,
21
+ ): Object3D | null {
22
+ const rect = canvas.getBoundingClientRect();
23
+ pointer.set(
24
+ ((event.clientX - rect.left) / rect.width) * 2 - 1,
25
+ -((event.clientY - rect.top) / rect.height) * 2 + 1,
26
+ );
27
+ raycaster.setFromCamera(pointer, camera);
28
+ const hit = raycaster.intersectObjects(scene.children, true).find((i) => !belongsToEditor(i.object));
29
+ return hit ? (findProvenance(hit.object)?.object ?? null) : null;
30
+ }
31
+
32
+ /**
33
+ * Is this object, **or anything above it**, something the editor drew for itself?
34
+ *
35
+ * Not the same question as `meta.ts`'s `isEditorOnly`, which asks only about the object itself —
36
+ * that one answers for a node the chrome is about to list, where the object *is* the helper's
37
+ * root. Here a ray has hit one of the small meshes deep inside a helper, so the flag is on an
38
+ * ancestor. Testing only the hit object let a click on a gizmo handle select the gizmo — which
39
+ * attached the transform control to its own helper and put `updateMatrixWorld` into infinite
40
+ * recursion, killing the page.
41
+ */
42
+ function belongsToEditor(object: Object3D): boolean {
43
+ for (let o: Object3D | null = object; o; o = o.parent) {
44
+ if (o.userData.scenocoEditorOnly) return true;
45
+ }
46
+ return false;
47
+ }