lecodes-cli 0.18.2 → 0.19.2
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/dist/index.js +1866 -301
- package/package.json +14 -12
- package/runtime/scene-harness.json +1 -1
- package/runtime/sdk-types.json +1 -1
- package/src/api.ts +302 -0
- package/src/browserAuth.ts +87 -0
- package/src/cmgenTool.ts +104 -0
- package/src/commands/app.ts +891 -0
- package/src/commands/appAndroid.ts +603 -0
- package/src/commands/appDesktop.ts +326 -0
- package/src/commands/appDesktopMac.ts +470 -0
- package/src/commands/appIcon.ts +187 -0
- package/src/commands/appShared.ts +448 -0
- package/src/commands/appTemplates.ts +883 -0
- package/src/commands/appTemplatesAndroid.ts +599 -0
- package/src/commands/appTemplatesGradlew.ts +9 -0
- package/src/commands/assets.ts +28 -0
- package/src/commands/clone.ts +60 -0
- package/src/commands/compile.ts +253 -0
- package/src/commands/create.ts +59 -0
- package/src/commands/design.ts +863 -0
- package/src/commands/designTemplates.ts +11 -0
- package/src/commands/desktop.ts +122 -0
- package/src/commands/dev.ts +214 -0
- package/src/commands/diff.ts +59 -0
- package/src/commands/init.ts +191 -0
- package/src/commands/install.ts +198 -0
- package/src/commands/lightmap.ts +290 -0
- package/src/commands/link.ts +147 -0
- package/src/commands/login.ts +24 -0
- package/src/commands/navmesh.ts +225 -0
- package/src/commands/pn.ts +305 -0
- package/src/commands/projectTemplates.ts +129 -0
- package/src/commands/pull.ts +109 -0
- package/src/commands/push.ts +173 -0
- package/src/commands/render.ts +414 -0
- package/src/commands/scene.ts +148 -0
- package/src/commands/shaders.ts +157 -0
- package/src/commands/status.ts +29 -0
- package/src/commands/test.ts +370 -0
- package/src/commands/thumbs.ts +178 -0
- package/src/commands/types.ts +87 -0
- package/src/commands/update.ts +190 -0
- package/src/compile/assetIcons.ts +214 -0
- package/src/compile/collect.ts +46 -0
- package/src/compile/collectLocal.ts +37 -0
- package/src/compile/designCompile.ts +104 -0
- package/src/compile/fonts.ts +156 -0
- package/src/compile/headlessBundle.ts +129 -0
- package/src/compile/nativeStack.ts +21 -0
- package/src/compile/projectCompile.ts +109 -0
- package/src/compile/sceneCompile.ts +113 -0
- package/src/compile/screenEntry.ts +127 -0
- package/src/compile/shaders.ts +245 -0
- package/src/config.ts +42 -0
- package/src/designMeta.ts +35 -0
- package/src/desktopRenderer.ts +532 -0
- package/src/desktopScript.ts +276 -0
- package/src/dev/clientTemplates.ts +160 -0
- package/src/dev/devServer.ts +292 -0
- package/src/dev/wsServer.ts +144 -0
- package/src/distRoot.ts +20 -0
- package/src/ignore.ts +163 -0
- package/src/index.ts +491 -0
- package/src/lecodes-3d-editor.d.ts +41 -0
- package/src/lecodes-assets.d.ts +7 -0
- package/src/lecodes-design.d.ts +191 -0
- package/src/lecodes-renderer.d.ts +131 -0
- package/src/localFiles.ts +144 -0
- package/src/manifest.ts +46 -0
- package/src/matcTool.ts +137 -0
- package/src/peers.ts +40 -0
- package/src/project.ts +61 -0
- package/src/projectEnv.ts +94 -0
- package/src/qrcode-terminal.d.ts +9 -0
- package/src/releases.ts +125 -0
- package/src/serverDiff.ts +78 -0
- package/src/textDiff.ts +103 -0
- package/src/types.ts +0 -0
- package/src/util.ts +146 -0
- package/runtime/sdk/animate/animate.ts +0 -238
- package/runtime/sdk/animate/bezier.ts +0 -138
- package/runtime/sdk/animate/easings.ts +0 -126
- package/runtime/sdk/canvas/Canvas.ts +0 -305
- package/runtime/sdk/core/Aspect.ts +0 -512
- package/runtime/sdk/core/InspectorUI.ts +0 -212
- package/runtime/sdk/core/color.ts +0 -66
- package/runtime/sdk/core/compWrite.ts +0 -42
- package/runtime/sdk/core/events.ts +0 -38
- package/runtime/sdk/core/fields.ts +0 -120
- package/runtime/sdk/core/registry.ts +0 -23
- package/runtime/sdk/core/signals.ts +0 -277
- package/runtime/sdk/core/time.ts +0 -81
- package/runtime/sdk/g2/Camera2D.ts +0 -40
- package/runtime/sdk/g2/CharacterController2D.ts +0 -276
- package/runtime/sdk/g2/Node2D.ts +0 -267
- package/runtime/sdk/g2/OneWay2D.ts +0 -66
- package/runtime/sdk/g2/Physics2D.ts +0 -346
- package/runtime/sdk/g2/Scene2D.ts +0 -209
- package/runtime/sdk/g2/Shape2D.ts +0 -259
- package/runtime/sdk/g2/Sprite.ts +0 -89
- package/runtime/sdk/g2/SpriteAnimation.ts +0 -171
- package/runtime/sdk/g2/SpriteSheet.ts +0 -166
- package/runtime/sdk/g2/Texture2D.ts +0 -47
- package/runtime/sdk/g2/Tilemap.ts +0 -41
- package/runtime/sdk/g2/Tileset.ts +0 -71
- package/runtime/sdk/g2/Trigger2D.ts +0 -77
- package/runtime/sdk/g2/autotile.ts +0 -433
- package/runtime/sdk/g2/cells.ts +0 -91
- package/runtime/sdk/g2/defineScene2d.ts +0 -381
- package/runtime/sdk/g2/groups2d.ts +0 -106
- package/runtime/sdk/g2/loop.ts +0 -50
- package/runtime/sdk/g2/scenarios2d.ts +0 -69
- package/runtime/sdk/g2/touch.ts +0 -83
- package/runtime/sdk/gl/Camera.ts +0 -160
- package/runtime/sdk/gl/CameraPlace.ts +0 -52
- package/runtime/sdk/gl/CharacterController.ts +0 -238
- package/runtime/sdk/gl/Gearbox.ts +0 -212
- package/runtime/sdk/gl/Geometry.ts +0 -279
- package/runtime/sdk/gl/IK.ts +0 -193
- package/runtime/sdk/gl/InstancedMesh.ts +0 -132
- package/runtime/sdk/gl/Light.ts +0 -99
- package/runtime/sdk/gl/Lightmap.ts +0 -179
- package/runtime/sdk/gl/Material.ts +0 -245
- package/runtime/sdk/gl/Mesh.ts +0 -83
- package/runtime/sdk/gl/Model.ts +0 -64
- package/runtime/sdk/gl/Node.ts +0 -350
- package/runtime/sdk/gl/Noise.ts +0 -30
- package/runtime/sdk/gl/Particles.ts +0 -676
- package/runtime/sdk/gl/Physics.ts +0 -222
- package/runtime/sdk/gl/Plane.ts +0 -53
- package/runtime/sdk/gl/Ray.ts +0 -16
- package/runtime/sdk/gl/Scene.ts +0 -479
- package/runtime/sdk/gl/Shape.ts +0 -377
- package/runtime/sdk/gl/Texture.ts +0 -46
- package/runtime/sdk/gl/Trigger.ts +0 -45
- package/runtime/sdk/gl/Vehicle.ts +0 -473
- package/runtime/sdk/gl/Wheel.ts +0 -240
- package/runtime/sdk/gl/animation/AnimationClip.ts +0 -204
- package/runtime/sdk/gl/animation/Animator.ts +0 -87
- package/runtime/sdk/gl/animation/Layer.ts +0 -29
- package/runtime/sdk/gl/animation/Loop.ts +0 -25
- package/runtime/sdk/gl/animation/Playback.ts +0 -43
- package/runtime/sdk/gl/animation/core.ts +0 -294
- package/runtime/sdk/gl/controls.ts +0 -95
- package/runtime/sdk/gl/physicsEvents.ts +0 -20
- package/runtime/sdk/gl/scenarios.ts +0 -291
- package/runtime/sdk/gl/state.ts +0 -6
- package/runtime/sdk/gl/touch.ts +0 -68
- package/runtime/sdk/inject.ts +0 -186
- package/runtime/sdk/math/Mathf.ts +0 -118
- package/runtime/sdk/math/mat4.ts +0 -278
- package/runtime/sdk/math/quat.ts +0 -232
- package/runtime/sdk/math/vec.ts +0 -255
- package/runtime/sdk/plugins/camera.ts +0 -81
- package/runtime/sdk/plugins/geolocation.ts +0 -123
- package/runtime/sdk/plugins/oauth.ts +0 -61
- package/runtime/sdk/plugins/permission.ts +0 -7
- package/runtime/sdk/plugins/push.ts +0 -132
- package/runtime/sdk/plugins/qr.ts +0 -73
- package/runtime/sdk/plugins/service.ts +0 -47
- package/runtime/sdk/runtime/app.ts +0 -101
- package/runtime/sdk/runtime/appEvents.ts +0 -54
- package/runtime/sdk/runtime/channel.ts +0 -61
- package/runtime/sdk/runtime/clipboard.ts +0 -20
- package/runtime/sdk/runtime/datetime.ts +0 -329
- package/runtime/sdk/runtime/device.ts +0 -293
- package/runtime/sdk/runtime/fetch.ts +0 -77
- package/runtime/sdk/runtime/files.ts +0 -23
- package/runtime/sdk/runtime/input.ts +0 -175
- package/runtime/sdk/runtime/media.ts +0 -111
- package/runtime/sdk/runtime/misc.ts +0 -16
- package/runtime/sdk/runtime/net.ts +0 -36
- package/runtime/sdk/runtime/rpc.ts +0 -218
- package/runtime/sdk/runtime/service.ts +0 -83
- package/runtime/sdk/runtime/share.ts +0 -9
- package/runtime/sdk/runtime/storage.ts +0 -13
- package/runtime/sdk/runtime/touch.ts +0 -76
- package/runtime/sdk/scene/defineScene.ts +0 -1227
- package/runtime/sdk/scene/editorPlugins.ts +0 -92
- package/runtime/sdk/scene/gizmos.ts +0 -148
- package/runtime/sdk/scene/grammar.ts +0 -120
- package/runtime/sdk/scene/material.ts +0 -188
- package/runtime/sdk/server/auth/appConfig.ts +0 -12
- package/runtime/sdk/server/auth/global.ts +0 -80
- package/runtime/sdk/server/auth/host.ts +0 -318
- package/runtime/sdk/server/auth/models.ts +0 -83
- package/runtime/sdk/server/auth/types.ts +0 -50
- package/runtime/sdk/server/channel.ts +0 -56
- package/runtime/sdk/server/context.ts +0 -36
- package/runtime/sdk/server/db/defineDb.ts +0 -237
- package/runtime/sdk/server/db/fields.ts +0 -132
- package/runtime/sdk/server/db/httpTransport.ts +0 -93
- package/runtime/sdk/server/db/index.ts +0 -7
- package/runtime/sdk/server/db/marci/query.ts +0 -412
- package/runtime/sdk/server/db/types.ts +0 -202
- package/runtime/sdk/server/errors.ts +0 -12
- package/runtime/sdk/server/host.ts +0 -74
- package/runtime/sdk/server/inject.ts +0 -13
- package/runtime/sdk/server/runtime.ts +0 -133
- package/runtime/sdk/server/validate.ts +0 -87
- package/runtime/sdk/ui/NativeView.ts +0 -142
- package/runtime/sdk/ui/UI.ts +0 -39
- package/runtime/sdk/ui/UIBottomSheet.ts +0 -139
- package/runtime/sdk/ui/UIButton.ts +0 -101
- package/runtime/sdk/ui/UIContainer.ts +0 -60
- package/runtime/sdk/ui/UIImage.ts +0 -83
- package/runtime/sdk/ui/UIInput.ts +0 -185
- package/runtime/sdk/ui/UIModal.ts +0 -139
- package/runtime/sdk/ui/UINode.ts +0 -826
- package/runtime/sdk/ui/UIPager.ts +0 -362
- package/runtime/sdk/ui/UIPopover.ts +0 -100
- package/runtime/sdk/ui/UIScreen.ts +0 -123
- package/runtime/sdk/ui/UIScrollable.ts +0 -87
- package/runtime/sdk/ui/UISpacer.ts +0 -14
- package/runtime/sdk/ui/UITabs.ts +0 -236
- package/runtime/sdk/ui/UIText.ts +0 -51
- package/runtime/sdk/ui/UIVideo.ts +0 -88
- package/runtime/sdk/ui/UIVirtualizedList.ts +0 -241
- package/runtime/sdk/ui/UIWidget.ts +0 -127
- package/runtime/sdk/ui/fonts.ts +0 -13
- package/runtime/sdk/ui/presentable.ts +0 -117
- package/runtime/sdk/ui/router.ts +0 -132
- package/runtime/sdk/ui/theme.ts +0 -84
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
// The scene editor's immediate-mode inspector protocol (docs/scene-editor-plan.md, phase 9).
|
|
2
|
-
//
|
|
3
|
-
// Custom editor UI never renders into the editor panel directly — the live data (aspect instances,
|
|
4
|
-
// nodes, `model.anim.clips`, generated meshes) lives in the SCENE WORLD (the compiled bundle), on
|
|
5
|
-
// the other side of the controller. So a custom view is an imgui-style function running in the
|
|
6
|
-
// world: it re-runs on every change/event and emits a WIDGET LIST (plain data); the editor panel is
|
|
7
|
-
// a dumb renderer of that list; user events `{ id, value }` come back and trigger the next run —
|
|
8
|
-
// `ui.button()` returns `true` on the run that consumes the click.
|
|
9
|
-
//
|
|
10
|
-
// class Road extends Aspect<'road'> {
|
|
11
|
-
// from: Node | null = null
|
|
12
|
-
// to: Node | null = null
|
|
13
|
-
// width = 2
|
|
14
|
-
// static editor = { rebuild: true }
|
|
15
|
-
// static inspector(ui: InspectorUI, road: Road) {
|
|
16
|
-
// ui.auto() // the inferred fields, as usual
|
|
17
|
-
// if (road.from && road.to) ui.info(`${road.generated.children.length} pieces`)
|
|
18
|
-
// else ui.warn('Assign both endpoints')
|
|
19
|
-
// if (ui.button('Shuffle')) road.rebuild()
|
|
20
|
-
// }
|
|
21
|
-
// }
|
|
22
|
-
//
|
|
23
|
-
// BINDING RULE: a field whose key is a declared aspect field (a public class field) is DOC-BOUND —
|
|
24
|
-
// the editor persists edits to the scene file through its normal commit/undo path. Any other key is
|
|
25
|
-
// EDITOR STATE — transient, kept on this InspectorUI instance across runs, never written to a file
|
|
26
|
-
// (the animation card's clip choice, a tool's brush size). One vocabulary, two lifetimes.
|
|
27
|
-
|
|
28
|
-
import type { FieldDescriptor, FieldEditor } from "./fields"
|
|
29
|
-
|
|
30
|
-
/** One user interaction coming back from the editor panel: the widget's id (+ value for fields). */
|
|
31
|
-
export type InspectorEvent = { id: string, value?: unknown }
|
|
32
|
-
|
|
33
|
-
export type InspectorFieldWidget = {
|
|
34
|
-
kind: "field"
|
|
35
|
-
id: string
|
|
36
|
-
/** The bound key — an aspect field (doc-bound) or an editor-state key. */
|
|
37
|
-
key: string
|
|
38
|
-
label: string
|
|
39
|
-
editor: FieldEditor | undefined
|
|
40
|
-
value: unknown
|
|
41
|
-
/** True = persisted to the scene file by the editor; false = transient editor state. */
|
|
42
|
-
doc: boolean
|
|
43
|
-
/** True = emitted by `ui.auto()` — the editor may overlay its syntactic hints (options/node). */
|
|
44
|
-
auto?: boolean
|
|
45
|
-
min?: number
|
|
46
|
-
max?: number
|
|
47
|
-
step?: number
|
|
48
|
-
options?: readonly (string | number)[]
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export type InspectorWidget =
|
|
52
|
-
| InspectorFieldWidget
|
|
53
|
-
| { kind: "button", id: string, label: string }
|
|
54
|
-
| { kind: "toolButton", id: string, label: string, tool: string }
|
|
55
|
-
| { kind: "header", id: string, label: string }
|
|
56
|
-
| { kind: "info" | "warn", id: string, text: string }
|
|
57
|
-
|
|
58
|
-
type FieldOpts = {
|
|
59
|
-
label?: string
|
|
60
|
-
min?: number
|
|
61
|
-
max?: number
|
|
62
|
-
step?: number
|
|
63
|
-
/** Default for EDITOR-STATE keys (doc keys default from the class field). */
|
|
64
|
-
value?: unknown
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* The widget builder handed to `static inspector(ui, aspect)` (and to editor windows/tools later).
|
|
69
|
-
* One instance lives per card and persists across runs — it carries the card's editor state.
|
|
70
|
-
*/
|
|
71
|
-
export class InspectorUI {
|
|
72
|
-
/** @internal This run's emitted widgets. */
|
|
73
|
-
_widgets: InspectorWidget[] = []
|
|
74
|
-
/** @internal Transient editor state (non-doc field keys), kept across runs. */
|
|
75
|
-
_state: Record<string, unknown> = {}
|
|
76
|
-
/** @internal The aspect entry's doc props (live reference — the runner keeps it current). */
|
|
77
|
-
_props: Record<string, unknown> = {}
|
|
78
|
-
/** @internal Keys that are declared aspect fields → doc-bound. Empty for node/window cards. */
|
|
79
|
-
_docKeys = new Set<string>()
|
|
80
|
-
/** @internal Field descriptors for auto() + doc-key defaults (describeFields output). */
|
|
81
|
-
_fields: FieldDescriptor[] = []
|
|
82
|
-
/** @internal The unconsumed button event of the current run. */
|
|
83
|
-
_event: InspectorEvent | null = null
|
|
84
|
-
|
|
85
|
-
// ---- fields (each emits one widget AND returns the current value) ---------------------------
|
|
86
|
-
|
|
87
|
-
/** Numeric field (min/max/step render as a slider-style scrub range). */
|
|
88
|
-
number(key: string, opts?: FieldOpts): number {
|
|
89
|
-
const v = this._field("number", key, opts)
|
|
90
|
-
return typeof v === "number" ? v : 0
|
|
91
|
-
}
|
|
92
|
-
/** Alias of `number` — give it min/max/step and the editor renders a scrubable range. */
|
|
93
|
-
slider(key: string, opts?: FieldOpts): number { return this.number(key, opts) }
|
|
94
|
-
|
|
95
|
-
text(key: string, opts?: FieldOpts): string {
|
|
96
|
-
const v = this._field("text", key, opts)
|
|
97
|
-
return typeof v === "string" ? v : ""
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
color(key: string, opts?: FieldOpts): string {
|
|
101
|
-
const v = this._field("color", key, opts)
|
|
102
|
-
return typeof v === "string" ? v : "#ffffff"
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
switch(key: string, opts?: FieldOpts): boolean {
|
|
106
|
-
return this._field("switch", key, opts) === true
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/** Dropdown — `options` may be computed fresh every run (dynamic lists come free). */
|
|
110
|
-
select(key: string, options: readonly (string | number)[], opts?: FieldOpts): string | number {
|
|
111
|
-
const v = this._field("select", key, { ...opts, value: opts?.value ?? options[0] }, options)
|
|
112
|
-
return (typeof v === "string" || typeof v === "number") && options.includes(v) ? v : options[0]
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
vec2(key: string, opts?: FieldOpts): [number, number] { return this._vec("vec2", key, 2, opts) as [number, number] }
|
|
116
|
-
vec3(key: string, opts?: FieldOpts): [number, number, number] { return this._vec("vec3", key, 3, opts) as [number, number, number] }
|
|
117
|
-
vec4(key: string, opts?: FieldOpts): [number, number, number, number] { return this._vec("vec4", key, 4, opts) as [number, number, number, number] }
|
|
118
|
-
|
|
119
|
-
/** Scene-node reference (`ref()` fields): name dropdown + pick-in-viewport. Returns the RAW doc
|
|
120
|
-
* value (`{ $ref }` marker or null) — read the resolved live node off the aspect instance. */
|
|
121
|
-
node(key: string, opts?: FieldOpts): unknown {
|
|
122
|
-
return this._field("node", key, opts)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/** Project-asset path (the editor renders a dropdown of the project's GLBs). "" = none picked. */
|
|
126
|
-
asset(key: string, opts?: FieldOpts): string {
|
|
127
|
-
const v = this._field("asset", key, { ...opts, value: opts?.value ?? "" })
|
|
128
|
-
return typeof v === "string" ? v : ""
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// ---- everything else --------------------------------------------------------------------------
|
|
132
|
-
|
|
133
|
-
/** True on the run that consumes this button's click — do the action right there. */
|
|
134
|
-
button(label: string, opts?: { id?: string }): boolean {
|
|
135
|
-
const id = opts?.id ?? `b:${label}`
|
|
136
|
-
this._widgets.push({ kind: "button", id, label })
|
|
137
|
-
if (this._event?.id === id) {
|
|
138
|
-
this._event = null
|
|
139
|
-
return true
|
|
140
|
-
}
|
|
141
|
-
return false
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/** A toggle that activates/deactivates the named viewport tool (`registerEditorTool`). The
|
|
145
|
-
* editor owns the active-tool state — the click never round-trips into the scene world. */
|
|
146
|
-
toolButton(label: string, tool: string): void {
|
|
147
|
-
this._widgets.push({ kind: "toolButton", id: `t:${tool}`, label, tool })
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
header(label: string): void { this._widgets.push({ kind: "header", id: `h:${label}`, label }) }
|
|
151
|
-
info(text: string): void { this._widgets.push({ kind: "info", id: `i:${this._widgets.length}`, text }) }
|
|
152
|
-
warn(text: string): void { this._widgets.push({ kind: "warn", id: `w:${this._widgets.length}`, text }) }
|
|
153
|
-
|
|
154
|
-
/** Emit the inferred field widgets (all declared aspect fields, or just the named ones) — the
|
|
155
|
-
* zero-ceremony baseline; append custom widgets around it. */
|
|
156
|
-
auto(...keys: string[]): void {
|
|
157
|
-
for (const f of this._fields) {
|
|
158
|
-
if (keys.length > 0 && !keys.includes(f.key)) continue
|
|
159
|
-
const value = this._props[f.key] !== undefined ? this._props[f.key] : f.value
|
|
160
|
-
this._widgets.push({
|
|
161
|
-
kind: "field", id: `f:${f.key}`, key: f.key, label: f.label, editor: f.editor,
|
|
162
|
-
value, doc: true, auto: true, min: f.min, max: f.max, step: f.step, options: f.options,
|
|
163
|
-
})
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// ---- internals ----------------------------------------------------------------------------
|
|
168
|
-
|
|
169
|
-
private _vec(editor: FieldEditor, key: string, size: number, opts?: FieldOpts): number[] {
|
|
170
|
-
const v = this._field(editor, key, opts)
|
|
171
|
-
const arr = Array.isArray(v) ? v : []
|
|
172
|
-
return Array.from({ length: size }, (_, i) => (typeof arr[i] === "number" ? arr[i] as number : 0))
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
private _field(
|
|
176
|
-
editor: FieldEditor, key: string, opts?: FieldOpts, options?: readonly (string | number)[],
|
|
177
|
-
): unknown {
|
|
178
|
-
const doc = this._docKeys.has(key)
|
|
179
|
-
const fallback = doc ? this._fields.find((f) => f.key === key)?.value : opts?.value
|
|
180
|
-
const stored = doc ? this._props[key] : this._state[key]
|
|
181
|
-
const value = stored !== undefined ? stored : fallback
|
|
182
|
-
this._widgets.push({
|
|
183
|
-
kind: "field", id: `f:${key}`, key, label: opts?.label ?? key, editor, value, doc,
|
|
184
|
-
min: opts?.min, max: opts?.max, step: opts?.step, options,
|
|
185
|
-
})
|
|
186
|
-
return value
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* @internal One immediate-mode pass: deliver `event`, run `fn`, return the widget list.
|
|
191
|
-
* Editor-state field events are applied here; DOC-key field events must be applied by the
|
|
192
|
-
* caller beforehand (they go through the scene loader's prop machinery — rebuilds, ref
|
|
193
|
-
* resolution); button events are consumed by the matching `button()` call during the run.
|
|
194
|
-
* A throwing inspector logs and shows the error as a warn line — it can't take the editor down.
|
|
195
|
-
*/
|
|
196
|
-
_run(fn: (ui: this) => void, event?: InspectorEvent): InspectorWidget[] {
|
|
197
|
-
if (event && event.id.startsWith("f:") && !this._docKeys.has(event.id.slice(2))) {
|
|
198
|
-
this._state[event.id.slice(2)] = event.value
|
|
199
|
-
event = undefined
|
|
200
|
-
}
|
|
201
|
-
this._event = event ?? null
|
|
202
|
-
this._widgets = []
|
|
203
|
-
try {
|
|
204
|
-
fn(this)
|
|
205
|
-
} catch (e) {
|
|
206
|
-
console.error("[scene] inspector render failed:", e)
|
|
207
|
-
this.warn(String((e as Error)?.message ?? e))
|
|
208
|
-
}
|
|
209
|
-
this._event = null
|
|
210
|
-
return this._widgets
|
|
211
|
-
}
|
|
212
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
// Shared color parsing for both engines. Users pass colors the natural ways — a CSS-ish hex string
|
|
2
|
-
// ('#10131a', '#abc', '#rrggbbaa'), a packed number (0xff0000), or normalized components
|
|
3
|
-
// ([r,g,b] / [r,g,b,a] in 0..1). The engines want different forms (2D wants 0..1 floats, 3D wants a
|
|
4
|
-
// packed int), so this module is the single place that converts.
|
|
5
|
-
|
|
6
|
-
export type ColorInput =
|
|
7
|
-
| string
|
|
8
|
-
| number
|
|
9
|
-
| readonly [number, number, number]
|
|
10
|
-
| readonly [number, number, number, number]
|
|
11
|
-
|
|
12
|
-
const parseHexString = (input: string): [number, number, number, number] => {
|
|
13
|
-
let s = input.trim()
|
|
14
|
-
if (s[0] === "#") s = s.slice(1)
|
|
15
|
-
// #rgb / #rgba shorthand → double each nibble
|
|
16
|
-
if (s.length === 3 || s.length === 4) s = s.split("").map((c) => c + c).join("")
|
|
17
|
-
const int = parseInt(s, 16)
|
|
18
|
-
if (s.length === 8) return [ (int >>> 24) & 255, (int >> 16) & 255, (int >> 8) & 255, int & 255 ]
|
|
19
|
-
// default 6-digit (rrggbb); anything malformed falls back to opaque black
|
|
20
|
-
if (s.length === 6) return [ (int >> 16) & 255, (int >> 8) & 255, int & 255, 255 ]
|
|
21
|
-
return [ 0, 0, 0, 255 ]
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Normalize any ColorInput to four 0..1 float components (array inputs pass through losslessly). */
|
|
25
|
-
const toFloats = (c: ColorInput): [number, number, number, number] => {
|
|
26
|
-
if (typeof c === "number") return [ ((c >> 16) & 255) / 255, ((c >> 8) & 255) / 255, (c & 255) / 255, 1 ]
|
|
27
|
-
if (typeof c === "string") {
|
|
28
|
-
const b = parseHexString(c)
|
|
29
|
-
return [ b[0] / 255, b[1] / 255, b[2] / 255, b[3] / 255 ]
|
|
30
|
-
}
|
|
31
|
-
return [ c[0], c[1], c[2], (c as readonly number[])[3] ?? 1 ]
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const toBytes = (c: ColorInput): [number, number, number, number] => {
|
|
35
|
-
const f = toFloats(c)
|
|
36
|
-
return [ Math.round(f[0] * 255), Math.round(f[1] * 255), Math.round(f[2] * 255), Math.round(f[3] * 255) ]
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const Color = {
|
|
40
|
-
/** [r,g,b] in 0..1 — for the 2D engine's float color setters. */
|
|
41
|
-
toRgb01(c: ColorInput): [number, number, number] {
|
|
42
|
-
const f = toFloats(c)
|
|
43
|
-
return [ f[0], f[1], f[2] ]
|
|
44
|
-
},
|
|
45
|
-
/** [r,g,b,a] in 0..1. */
|
|
46
|
-
toRgba01(c: ColorInput): [number, number, number, number] {
|
|
47
|
-
return toFloats(c)
|
|
48
|
-
},
|
|
49
|
-
/** 0xRRGGBB packed int — for the 3D engine's color uniforms / skybox. */
|
|
50
|
-
toPackedRgb(c: ColorInput): number {
|
|
51
|
-
const b = toBytes(c)
|
|
52
|
-
return (b[0] << 16) | (b[1] << 8) | b[2]
|
|
53
|
-
},
|
|
54
|
-
/** 0xRRGGBBAA packed int (unsigned). */
|
|
55
|
-
toPackedRgba(c: ColorInput): number {
|
|
56
|
-
const b = toBytes(c)
|
|
57
|
-
return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]) >>> 0
|
|
58
|
-
},
|
|
59
|
-
/** '#rrggbb' (or '#rrggbbaa' when alpha < 1) — for the 3D material color uniforms. */
|
|
60
|
-
toHexString(c: ColorInput): string {
|
|
61
|
-
const b = toBytes(c)
|
|
62
|
-
const hex = (n: number) => n.toString(16).padStart(2, "0")
|
|
63
|
-
const base = `#${hex(b[0])}${hex(b[1])}${hex(b[2])}`
|
|
64
|
-
return b[3] >= 255 ? base : base + hex(b[3])
|
|
65
|
-
},
|
|
66
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// Component writes on SDK-owned vectors — the runtime half of chisel's `comp_write` pass.
|
|
2
|
-
//
|
|
3
|
-
// hero.controller.velocity.y = 7 → __compWrite(hero.controller, "velocity", "y", 7)
|
|
4
|
-
// hero.controller.velocity.y += 3 → __compOp(hero.controller, "velocity", "y", 0, 3)
|
|
5
|
-
//
|
|
6
|
-
// A getter like `velocity` hands out a fresh Vec3, so the literal spelling would write to a copy and
|
|
7
|
-
// silently do nothing. chisel rewrites the exact `<owner>.<prop>.<x|y|z|w> = v` shape into these
|
|
8
|
-
// helpers, which ask the OWNER to apply the component write (no getter call, no allocation) and
|
|
9
|
-
// fall back to the plain write on anything else, so a user record `{ velocity: { x, y } }` behaves
|
|
10
|
-
// exactly as written. Only the direct spelling is covered: `const v = c.velocity; v.y = 7` is still
|
|
11
|
-
// a write to a copy.
|
|
12
|
-
//
|
|
13
|
-
// Owners today: Node / Node2D / Camera2D (`position` → the scalar setters, physics routing included),
|
|
14
|
-
// Physics (`velocity`, `angularVelocity`), CharacterController / CharacterController2D (`velocity`).
|
|
15
|
-
//
|
|
16
|
-
// An owner declares WHICH getters qualify as compile-time data and answers them at runtime:
|
|
17
|
-
//
|
|
18
|
-
// static _comps = ["velocity"] // chisel reads the list, then strips it (0 bytes shipped)
|
|
19
|
-
// _writeComp(prop, axis, value) { … } // called for listed props only; a hook without the
|
|
20
|
-
// // list is a build diagnostic and routes nothing
|
|
21
|
-
|
|
22
|
-
export type CompAxis = "x" | "y" | "z" | "w"
|
|
23
|
-
|
|
24
|
-
/** Implemented by a class whose vector getters accept component writes (see above). The class also
|
|
25
|
-
* carries `static _comps: string[]` naming those getters — compile-time data, absent at runtime. */
|
|
26
|
-
export interface CompWriter {
|
|
27
|
-
_writeComp(prop: string, axis: CompAxis, value: number): void
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** `<o>.<prop>.<axis> = value`, routed to the owner when it has the hook. Returns the value. */
|
|
31
|
-
export const __compWrite = (o: any, prop: string, axis: CompAxis, value: number): number => {
|
|
32
|
-
if (o._writeComp !== undefined) o._writeComp(prop, axis, value) // a direct call, not .call — cheaper on QuickJS
|
|
33
|
-
else o[prop][axis] = value
|
|
34
|
-
return value
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** `<o>.<prop>.<axis> op= v` — `op`: 0 `+=`, 1 `-=`, 2 `*=`, 3 `/=`. The current component is read
|
|
38
|
-
* through the normal getter (one fresh vector), the result written like `__compWrite`. */
|
|
39
|
-
export const __compOp = (o: any, prop: string, axis: CompAxis, op: number, v: number): number => {
|
|
40
|
-
const cur = o[prop][axis] as number
|
|
41
|
-
return __compWrite(o, prop, axis, op === 0 ? cur + v : op === 1 ? cur - v : op === 2 ? cur * v : cur / v)
|
|
42
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// Tiny typed event dispatcher shared by media players, sockets, and (later) nodes. Keeps the
|
|
2
|
-
// addEventListener / removeEventListener / dispatch boilerplate in one place.
|
|
3
|
-
|
|
4
|
-
export type EventMap = Record<string, (...args: any[]) => void>
|
|
5
|
-
|
|
6
|
-
export class Emitter<E extends EventMap> {
|
|
7
|
-
private _listeners: { [K in keyof E]?: E[K][] } = {}
|
|
8
|
-
|
|
9
|
-
addEventListener<K extends keyof E>(channel: K, callback: E[K]): void {
|
|
10
|
-
const list = this._listeners[channel]
|
|
11
|
-
if (list) list.push(callback)
|
|
12
|
-
else this._listeners[channel] = [ callback ]
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
removeEventListener<K extends keyof E>(channel: K, callback: E[K]): void {
|
|
16
|
-
const list = this._listeners[channel]
|
|
17
|
-
if (!list) return
|
|
18
|
-
const i = list.indexOf(callback)
|
|
19
|
-
if (i >= 0) list.splice(i, 1)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Fire all listeners on a channel. Protected: only the owning class emits. */
|
|
23
|
-
protected dispatch<K extends keyof E>(channel: K, ...args: Parameters<E[K]>): void {
|
|
24
|
-
const list = this._listeners[channel]
|
|
25
|
-
if (!list) return
|
|
26
|
-
for (const fn of list.slice()) fn(...args)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
protected hasListeners<K extends keyof E>(channel: K): boolean {
|
|
30
|
-
const list = this._listeners[channel]
|
|
31
|
-
return !!list && list.length > 0
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Drop every listener on every channel (used when the owning object is disposed). */
|
|
35
|
-
protected clearListeners(): void {
|
|
36
|
-
this._listeners = {}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// Field introspection for the scene-editor inspector: what's editable on an aspect, and with which
|
|
2
|
-
// editor widget. Engine-agnostic (works for 2D and 3D aspects alike).
|
|
3
|
-
//
|
|
4
|
-
// The editable surface of an aspect is its public class fields with defaults — the same convention
|
|
5
|
-
// aspects already follow for `node.aspect(Ctor, opts)` configuration. Editors are layered:
|
|
6
|
-
// 1. inference from the default value's shape (number → number field, '#rrggbb' → color, …), free
|
|
7
|
-
// for every user aspect with zero ceremony;
|
|
8
|
-
// 2. optional `static fields: FieldMeta<T>` on the class for ranges/labels/options/overrides
|
|
9
|
-
// (mirrors how `static aspect` declares the accessor name).
|
|
10
|
-
|
|
11
|
-
/** Editor widget kinds the inspector knows how to render. `"node"` = a scene-node reference
|
|
12
|
-
* (`ref('name')` in the file, name dropdown + pick-in-viewport in the inspector) — declare it via
|
|
13
|
-
* `static fields` on fields typed `Node | null`; a `Node | null` type annotation is also picked
|
|
14
|
-
* up syntactically by the editor's source scan. `"asset"` = a project-asset path (the editor
|
|
15
|
-
* fills the dropdown with the project's GLBs — `ui.asset()` in windows/tools/cards). */
|
|
16
|
-
export type FieldEditor =
|
|
17
|
-
| "number" | "text" | "color" | "switch" | "select"
|
|
18
|
-
| "vec2" | "vec3" | "vec4" | "node" | "asset"
|
|
19
|
-
|
|
20
|
-
export type FieldMetaEntry = {
|
|
21
|
-
/** Inspector label (default: the field name). */
|
|
22
|
-
label?: string
|
|
23
|
-
min?: number
|
|
24
|
-
max?: number
|
|
25
|
-
step?: number
|
|
26
|
-
/** Allowed values — renders a dropdown (editor "select"). */
|
|
27
|
-
options?: readonly (string | number)[]
|
|
28
|
-
/** Override the editor inferred from the default value. */
|
|
29
|
-
editor?: FieldEditor
|
|
30
|
-
/** Exclude the field from the inspector. */
|
|
31
|
-
hidden?: boolean
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Declared on an aspect class as `static fields: FieldMeta<MyAspect> = { … }`. All optional. */
|
|
35
|
-
export type FieldMeta<T = unknown> = { [K in Extract<keyof T, string>]?: FieldMetaEntry }
|
|
36
|
-
|
|
37
|
-
/** One editable field: key + default value + resolved editor + merged metadata. */
|
|
38
|
-
export type FieldDescriptor = {
|
|
39
|
-
key: string
|
|
40
|
-
label: string
|
|
41
|
-
/** The default value (from a freshly constructed instance; undefined if only declared in meta). */
|
|
42
|
-
value: unknown
|
|
43
|
-
/** Resolved editor kind; undefined = no editor known (inspector shows it read-only). */
|
|
44
|
-
editor: FieldEditor | undefined
|
|
45
|
-
min?: number
|
|
46
|
-
max?: number
|
|
47
|
-
step?: number
|
|
48
|
-
options?: readonly (string | number)[]
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export type AspectClassInfo = {
|
|
52
|
-
/** The accessor name (`static aspect`, injected by chisel for user aspects). */
|
|
53
|
-
name: string
|
|
54
|
-
className: string
|
|
55
|
-
fields: FieldDescriptor[]
|
|
56
|
-
/** True for editor-run classes (`static editor` — generators). The editor routes their
|
|
57
|
-
* structural changes through a re-run instead of a live patch. */
|
|
58
|
-
editor?: boolean
|
|
59
|
-
/** True when the class declares a custom `static inspector(ui, aspect)` card. */
|
|
60
|
-
inspector?: boolean
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Instance fields every aspect inherits from the Aspect base — configuration plumbing, not content.
|
|
64
|
-
// `generated` is declare-only in TS, but the bundler lowers it to a real (undefined) class field.
|
|
65
|
-
const BASE_FIELDS = new Set([ "node", "generated", "updateOrder", "updateWhilePaused", "updateWhenVisible" ])
|
|
66
|
-
|
|
67
|
-
/** Infer the editor widget from a default value's shape. */
|
|
68
|
-
export const inferFieldEditor = (value: unknown): FieldEditor | undefined => {
|
|
69
|
-
if (typeof value === "boolean") return "switch"
|
|
70
|
-
if (typeof value === "number") return "number"
|
|
71
|
-
if (typeof value === "string") return value.startsWith("#") ? "color" : "text"
|
|
72
|
-
if (Array.isArray(value) && value.length >= 2 && value.length <= 4 && value.every((n) => typeof n === "number")) {
|
|
73
|
-
return value.length === 2 ? "vec2" : value.length === 3 ? "vec3" : "vec4"
|
|
74
|
-
}
|
|
75
|
-
return undefined
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const cloneValue = (v: unknown): unknown => (Array.isArray(v) ? [ ...v ] : v)
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Enumerate the editable fields of a class: construct a default instance, take its own enumerable
|
|
82
|
-
* non-underscore fields (minus the Aspect base plumbing), infer editors from the default values, and
|
|
83
|
-
* merge the class's optional `static fields` metadata (which can also add keys that have no runtime
|
|
84
|
-
* default, e.g. fields declared without an initializer).
|
|
85
|
-
*/
|
|
86
|
-
export const describeFields = (ctor: abstract new () => unknown): FieldDescriptor[] => {
|
|
87
|
-
let defaults: Record<string, unknown> = {}
|
|
88
|
-
// Aspects have no-arg constructors by convention (the engine creates them via node.aspect()); a
|
|
89
|
-
// class that throws here just loses default-value inference, it doesn't break the inspector.
|
|
90
|
-
try { defaults = new (ctor as new () => Record<string, unknown>)() } catch { /* meta-only */ }
|
|
91
|
-
|
|
92
|
-
const meta = ((ctor as { fields?: FieldMeta }).fields ?? {}) as Record<string, FieldMetaEntry>
|
|
93
|
-
|
|
94
|
-
const keys = new Set<string>()
|
|
95
|
-
for (const k of Object.keys(defaults)) {
|
|
96
|
-
if (BASE_FIELDS.has(k) || k.startsWith("_")) continue
|
|
97
|
-
if (typeof defaults[k] === "function") continue
|
|
98
|
-
keys.add(k)
|
|
99
|
-
}
|
|
100
|
-
for (const k of Object.keys(meta)) keys.add(k)
|
|
101
|
-
|
|
102
|
-
const out: FieldDescriptor[] = []
|
|
103
|
-
for (const key of keys) {
|
|
104
|
-
const m = meta[key] ?? {}
|
|
105
|
-
if (m.hidden) continue
|
|
106
|
-
const value = defaults[key]
|
|
107
|
-
const editor = m.editor ?? (m.options ? "select" : inferFieldEditor(value))
|
|
108
|
-
out.push({ key, label: m.label ?? key, value: cloneValue(value), editor, min: m.min, max: m.max, step: m.step, options: m.options })
|
|
109
|
-
}
|
|
110
|
-
return out
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/** Describe an aspect class for the inspector: accessor name + class name + editable fields. */
|
|
114
|
-
export const describeAspect = (ctor: abstract new () => unknown): AspectClassInfo => ({
|
|
115
|
-
name: (ctor as { aspect?: string }).aspect ?? "",
|
|
116
|
-
className: (ctor as { name?: string }).name ?? "",
|
|
117
|
-
fields: describeFields(ctor),
|
|
118
|
-
editor: (ctor as { editor?: unknown }).editor ? true : undefined,
|
|
119
|
-
inspector: typeof (ctor as { inspector?: unknown }).inspector === "function" ? true : undefined,
|
|
120
|
-
})
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// Maps a native handle (the integer id the engine returns) back to its JS wrapper, so callbacks
|
|
2
|
-
// the host fires by id (animation events, touch hits, media events) can be routed to the owning
|
|
3
|
-
// object. Each engine/domain keeps its own Registry instance.
|
|
4
|
-
|
|
5
|
-
export class Registry<T> {
|
|
6
|
-
private map = new Map<number, T>()
|
|
7
|
-
|
|
8
|
-
set(id: number, value: T): void {
|
|
9
|
-
this.map.set(id, value)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
get(id: number): T | undefined {
|
|
13
|
-
return this.map.get(id)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
delete(id: number): void {
|
|
17
|
-
this.map.delete(id)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
has(id: number): boolean {
|
|
21
|
-
return this.map.has(id)
|
|
22
|
-
}
|
|
23
|
-
}
|