@scenoco-three/editor 0.5.4 → 0.7.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.
- package/README.md +31 -106
- package/bin/serve.js +37 -0
- package/dist/editor.js +12521 -0
- package/package.json +29 -41
- package/app/cameraRig.ts +0 -118
- package/app/commands.ts +0 -78
- package/app/desktopControls.ts +0 -47
- package/app/document.ts +0 -547
- package/app/editLog.ts +0 -127
- package/app/editor.css +0 -51
- package/app/gizmo.ts +0 -169
- package/app/globals.d.ts +0 -9
- package/app/index.html +0 -14
- package/app/main.ts +0 -546
- package/app/meta.ts +0 -24
- package/app/picking.ts +0 -47
- package/app/session.ts +0 -612
- package/app/touchControls.ts +0 -127
- package/app/ui-react/AddMemberPopup.tsx +0 -114
- package/app/ui-react/BottomLauncher.tsx +0 -15
- package/app/ui-react/EditorUI.tsx +0 -22
- package/app/ui-react/FilePicker.tsx +0 -80
- package/app/ui-react/HeadBtn.tsx +0 -21
- package/app/ui-react/InspectorSheet.tsx +0 -475
- package/app/ui-react/NodeListSheet.tsx +0 -56
- package/app/ui-react/TopBar.tsx +0 -137
- package/app/ui-react/Tree.tsx +0 -106
- package/app/ui-react/cx.ts +0 -4
- package/app/ui-react/fields.tsx +0 -407
- package/app/ui-react/format.ts +0 -30
- package/app/ui-react/mount.tsx +0 -31
- package/app/ui-react/store.ts +0 -80
- package/app/ui-react/types.ts +0 -88
- package/app/ui-react/ui.module.css +0 -250
- package/app/ui-react/useSize.ts +0 -20
- package/app/values.ts +0 -137
- package/app/vite-env.d.ts +0 -7
- package/dist/cli/index.d.ts +0 -2
- package/dist/cli/index.js +0 -122
- package/dist/index.d.ts +0 -10
- package/dist/index.js +0 -10
- package/dist/mcp.d.ts +0 -32
- package/dist/mcp.js +0 -191
- package/dist/protocol.d.ts +0 -170
- package/dist/protocol.js +0 -22
- package/dist/server.d.ts +0 -124
- package/dist/server.js +0 -440
package/app/editor.css
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* The page shell and the theme.
|
|
3
|
-
*
|
|
4
|
-
* `ui.module.css` styles the chrome and reads these three variables for every panel — so they
|
|
5
|
-
* have to be defined here, on `:root`, not inside the module: a CSS Module hashes class names but
|
|
6
|
-
* a custom property still resolves through the cascade, and an undefined `var(--line)` is not an
|
|
7
|
-
* error. It silently paints nothing, which is exactly how every panel border went missing.
|
|
8
|
-
*/
|
|
9
|
-
:root {
|
|
10
|
-
color-scheme: dark;
|
|
11
|
-
/* Translucent, because a panel floats over the viewport and the scene behind it is context. */
|
|
12
|
-
--panel: rgba(20, 24, 32, 0.92);
|
|
13
|
-
--line: #2a3344;
|
|
14
|
-
/* A panel floats over the scene, so its outline has to hold against whatever is behind it —
|
|
15
|
-
brighter than `--line`, which divides rows *inside* a panel and should stay quiet. */
|
|
16
|
-
--edge: #3d4b64;
|
|
17
|
-
--accent: #4af0e0;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
* { box-sizing: border-box; }
|
|
21
|
-
|
|
22
|
-
html,
|
|
23
|
-
body {
|
|
24
|
-
margin: 0;
|
|
25
|
-
height: 100%;
|
|
26
|
-
overflow: hidden;
|
|
27
|
-
background: #15181f;
|
|
28
|
-
color: #d6e2f0;
|
|
29
|
-
font: 13px/1.5 ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
#viewport {
|
|
33
|
-
position: fixed;
|
|
34
|
-
inset: 0;
|
|
35
|
-
width: 100%;
|
|
36
|
-
height: 100%;
|
|
37
|
-
display: block;
|
|
38
|
-
touch-action: none;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/*
|
|
42
|
-
* The chrome overlays the viewport but lets pointer events fall through to the canvas; each
|
|
43
|
-
* panel re-enables them on its own surface. Otherwise an invisible full-screen div would eat
|
|
44
|
-
* every click meant for the scene.
|
|
45
|
-
*/
|
|
46
|
-
#sc-ui {
|
|
47
|
-
position: fixed;
|
|
48
|
-
inset: 0;
|
|
49
|
-
z-index: 5;
|
|
50
|
-
pointer-events: none;
|
|
51
|
-
}
|
package/app/gizmo.ts
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { Quaternion, Vector3, type Camera, type Object3D, type Scene } from 'three';
|
|
2
|
-
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
|
|
3
|
-
|
|
4
|
-
export type GizmoMode = 'translate' | 'rotate' | 'scale';
|
|
5
|
-
|
|
6
|
-
/** Which axes the handles follow: the world's, or the object's own. */
|
|
7
|
-
export type GizmoSpace = 'world' | 'local';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* How far the pointer must travel before a press on a handle counts as a drag.
|
|
11
|
-
*
|
|
12
|
-
* No click is perfectly still — a real mouse moves a pixel or two between down and up — and
|
|
13
|
-
* `TransformControls` applies every one of those pixels. Without a threshold, clicking an object
|
|
14
|
-
* in scale mode quietly resizes it by a fraction of a percent, which is invisible on screen and
|
|
15
|
-
* permanent in the document: the file gains a `scale` attribute nobody asked for.
|
|
16
|
-
*/
|
|
17
|
-
const DRAG_THRESHOLD = 3;
|
|
18
|
-
|
|
19
|
-
export interface GizmoOptions {
|
|
20
|
-
/** Live refresh while dragging (e.g. update the inspector numbers). */
|
|
21
|
-
onObjectChange?: () => void;
|
|
22
|
-
/** Drag finished — commit the object's new transform as one undoable edit. */
|
|
23
|
-
onCommit?: (object: Object3D) => void;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Thin wrapper over three's `TransformControls` (translate/rotate/scale handles).
|
|
28
|
-
* The control mutates the attached `Object3D` directly during a drag; on drag end
|
|
29
|
-
* we hand the object to `onCommit`, which records a single undoable edit (the
|
|
30
|
-
* compiled scene was untouched during the drag, so it still holds the pre-drag
|
|
31
|
-
* value — exactly the right "before" for undo).
|
|
32
|
-
*
|
|
33
|
-
* Camera controls read `dragging` to stand down while a handle is being dragged,
|
|
34
|
-
* so the fly camera and the gizmo never fight over the same pointer/touch.
|
|
35
|
-
*/
|
|
36
|
-
export class Gizmo {
|
|
37
|
-
private readonly controls: TransformControls;
|
|
38
|
-
private readonly helper: Object3D;
|
|
39
|
-
|
|
40
|
-
private readonly scene: Scene;
|
|
41
|
-
|
|
42
|
-
/** Where the press started, while one is in progress. */
|
|
43
|
-
private pressedAt: { x: number; y: number } | null = null;
|
|
44
|
-
/** True once a press has travelled far enough to be a drag. */
|
|
45
|
-
private travelled = false;
|
|
46
|
-
/** The attached object's transform at the moment of the press, to put back after a click. */
|
|
47
|
-
private readonly grabbed = {
|
|
48
|
-
position: new Vector3(),
|
|
49
|
-
quaternion: new Quaternion(),
|
|
50
|
-
scale: new Vector3(),
|
|
51
|
-
/** Kept alongside the quaternion because it is the form the document writes. */
|
|
52
|
-
eulerAngles: new Vector3(),
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
constructor(
|
|
56
|
-
camera: Camera,
|
|
57
|
-
domElement: HTMLElement,
|
|
58
|
-
scene: Scene,
|
|
59
|
-
touch: boolean,
|
|
60
|
-
opts: GizmoOptions = {},
|
|
61
|
-
) {
|
|
62
|
-
this.scene = scene;
|
|
63
|
-
this.controls = new TransformControls(camera, domElement);
|
|
64
|
-
this.controls.setSize(touch ? 1.4 : 1); // fat-finger handles on touch
|
|
65
|
-
this.helper = this.controls.getHelper();
|
|
66
|
-
this.helper.userData.scenocoEditorOnly = true; // keep it out of the Hierarchy + picking
|
|
67
|
-
scene.add(this.helper);
|
|
68
|
-
|
|
69
|
-
domElement.addEventListener('pointerdown', (event) => {
|
|
70
|
-
this.pressedAt = { x: event.clientX, y: event.clientY };
|
|
71
|
-
this.travelled = false;
|
|
72
|
-
});
|
|
73
|
-
domElement.addEventListener('pointermove', (event) => {
|
|
74
|
-
if (!this.pressedAt || this.travelled) return;
|
|
75
|
-
this.travelled = Math.hypot(event.clientX - this.pressedAt.x, event.clientY - this.pressedAt.y) > DRAG_THRESHOLD;
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// A press that never travelled changed nothing the user meant to change, so the object goes
|
|
79
|
-
// back to where it was grabbed and the document never hears about it.
|
|
80
|
-
this.controls.addEventListener('objectChange', () => {
|
|
81
|
-
if (this.travelled) opts.onObjectChange?.();
|
|
82
|
-
});
|
|
83
|
-
this.controls.addEventListener('dragging-changed', (e) => {
|
|
84
|
-
// Fired true at drag start, false at drag end.
|
|
85
|
-
const object = this.controls.object;
|
|
86
|
-
if (!object) return;
|
|
87
|
-
if (e.value) {
|
|
88
|
-
this.grabbed.position.copy(object.position);
|
|
89
|
-
this.grabbed.quaternion.copy(object.quaternion);
|
|
90
|
-
this.grabbed.scale.copy(object.scale);
|
|
91
|
-
this.grabbed.eulerAngles.copy(object.eulerAngles);
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
this.pressedAt = null;
|
|
95
|
-
if (this.travelled) opts.onCommit?.(object);
|
|
96
|
-
else {
|
|
97
|
-
object.position.copy(this.grabbed.position);
|
|
98
|
-
object.quaternion.copy(this.grabbed.quaternion);
|
|
99
|
-
object.scale.copy(this.grabbed.scale);
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* The attached object's value for one channel as it was when the drag began.
|
|
106
|
-
*
|
|
107
|
-
* Undo needs this and cannot work it out later. By the time the first edit is recorded the
|
|
108
|
-
* object has already moved — the write happens *because* it moved — so a "before" captured
|
|
109
|
-
* there is a frame late. For a channel the document writes, undo restores the text and the
|
|
110
|
-
* error never shows; for one it does not write (a rotation left at zero, a scale left at one,
|
|
111
|
-
* which is most of them) there is nothing to restore from, and the object is left wherever
|
|
112
|
-
* that first frame put it.
|
|
113
|
-
*/
|
|
114
|
-
grabbedValue(channel: 'position' | 'eulerAngles' | 'scale'): Vector3 {
|
|
115
|
-
return this.grabbed[channel];
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/** True while a handle is being dragged — camera controls check this to yield. */
|
|
119
|
-
get dragging(): boolean {
|
|
120
|
-
return this.controls.dragging;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
setMode(mode: GizmoMode): void {
|
|
124
|
-
this.controls.setMode(mode);
|
|
125
|
-
}
|
|
126
|
-
get mode(): GizmoMode {
|
|
127
|
-
return this.controls.mode as GizmoMode;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Whether the handles line up with the world's axes or the object's own — Unity's
|
|
132
|
-
* Global/Local button.
|
|
133
|
-
*
|
|
134
|
-
* It changes what a drag means, not just how it looks: dragging the green arrow moves a node
|
|
135
|
-
* along world Y in one space and along its own up in the other, and for anything rotated the
|
|
136
|
-
* two are different edits.
|
|
137
|
-
*/
|
|
138
|
-
setSpace(space: GizmoSpace): void {
|
|
139
|
-
this.controls.setSpace(space);
|
|
140
|
-
}
|
|
141
|
-
get space(): GizmoSpace {
|
|
142
|
-
return this.controls.space as GizmoSpace;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Point the handles at an object — never at the handles themselves.
|
|
147
|
-
*
|
|
148
|
-
* Attaching the control to its own helper makes the helper its own parent's target: three walks
|
|
149
|
-
* `updateMatrixWorld` between the two for ever and the page dies on a stack overflow. It is one
|
|
150
|
-
* mis-routed pick away, and there is no legitimate reason to aim a gizmo at a gizmo, so it is
|
|
151
|
-
* refused here rather than trusted to every caller.
|
|
152
|
-
*/
|
|
153
|
-
attach(object: Object3D | null): void {
|
|
154
|
-
if (object && !this.contains(object)) this.controls.attach(object);
|
|
155
|
-
else this.controls.detach();
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/** True if `object` is part of the gizmo's own helper. */
|
|
159
|
-
contains(object: Object3D): boolean {
|
|
160
|
-
for (let o: Object3D | null = object; o; o = o.parent) if (o === this.helper) return true;
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
dispose(): void {
|
|
165
|
-
this.controls.detach();
|
|
166
|
-
this.scene.remove(this.helper);
|
|
167
|
-
this.controls.dispose();
|
|
168
|
-
}
|
|
169
|
-
}
|
package/app/globals.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The websocket path, substituted into the page at serve time by the editor's Vite config.
|
|
3
|
-
*
|
|
4
|
-
* A constant rather than an import because the page and the server share `src/protocol.ts`, and
|
|
5
|
-
* `src/` is not published — the package ships `dist` and `app`. Everything else the page borrows
|
|
6
|
-
* from that module is a type, which erases; this was the only value, so it comes in through
|
|
7
|
-
* `define` and the import can be type-only.
|
|
8
|
-
*/
|
|
9
|
-
declare const __SCENOCO_WS_PATH__: string;
|
package/app/index.html
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
6
|
-
<title>SceNoCo editor</title>
|
|
7
|
-
<link rel="stylesheet" href="./editor.css" />
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<canvas id="viewport"></canvas>
|
|
11
|
-
<div id="sc-ui"></div>
|
|
12
|
-
<script type="module" src="./main.ts"></script>
|
|
13
|
-
</body>
|
|
14
|
-
</html>
|