lecodes-cli 0.19.0 → 0.20.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 +1 -0
- package/dist/index.js +1069 -396
- package/package.json +14 -13
- package/runtime/scene-harness.json +1 -1
- package/runtime/sdk-types.json +1 -1
- package/runtime/web/assets/Roboto-Variable-DHm9jpd-.woff2 +0 -0
- package/runtime/web/assets/__vite-browser-external-BIHI7g3E.js +1 -0
- package/runtime/web/assets/basis-C64VHDVD.js +1 -0
- package/runtime/web/assets/basis_transcoder-VXdx5NbI.wasm +0 -0
- package/runtime/web/assets/createViewerLite-BvHobVhp.js +852 -0
- package/runtime/web/assets/draco-BiISTFcR.js +118 -0
- package/runtime/web/assets/draco_decoder-DsQ12WqX.wasm +0 -0
- package/runtime/web/assets/index-CfNCCBjN.js +2 -0
- package/runtime/web/assets/mapViewImpl-B2JcES8l.js +810 -0
- package/runtime/web/assets/maplibre-gl-worker-CJfwIrte.js +8 -0
- package/runtime/web/assets/neutral_ibl128-D-lzdkLN.ktx +0 -0
- package/runtime/web/assets/worker-Caf-yYEI.js +2 -0
- package/runtime/web/embed.html +32 -0
- package/runtime/web/embed.js +171 -0
- package/src/api.ts +302 -0
- package/src/browserAuth.ts +87 -0
- package/src/cmgenTool.ts +104 -0
- package/src/commands/app.ts +896 -0
- package/src/commands/appAndroid.ts +603 -0
- package/src/commands/appDesktop.ts +339 -0
- package/src/commands/appDesktopMac.ts +470 -0
- package/src/commands/appIcon.ts +187 -0
- package/src/commands/appShared.ts +542 -0
- package/src/commands/appTemplates.ts +907 -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 +127 -0
- package/src/commands/dev.ts +236 -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 +130 -0
- package/src/commands/pull.ts +109 -0
- package/src/commands/push.ts +173 -0
- package/src/commands/render.ts +416 -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 +371 -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 +545 -0
- package/src/desktopScript.ts +276 -0
- package/src/dev/clientTemplates.ts +160 -0
- package/src/dev/devServer.ts +333 -0
- package/src/dev/webRunner.ts +22 -0
- package/src/dev/wsServer.ts +144 -0
- package/src/distRoot.ts +20 -0
- package/src/ignore.ts +163 -0
- package/src/index.ts +494 -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/compile/aspectMacro.ts +0 -86
- package/runtime/sdk/compile/assetIconMacro.ts +0 -384
- package/runtime/sdk/compile/assetMacro.ts +0 -146
- package/runtime/sdk/compile/assetName.ts +0 -50
- package/runtime/sdk/compile/bundler.ts +0 -287
- package/runtime/sdk/compile/compileProject.ts +0 -129
- package/runtime/sdk/compile/detectEntry.ts +0 -128
- package/runtime/sdk/compile/fontMacro.ts +0 -459
- package/runtime/sdk/compile/fontRegistry.ts +0 -78
- package/runtime/sdk/compile/header.ts +0 -67
- package/runtime/sdk/compile/index.ts +0 -100
- package/runtime/sdk/compile/libraryImports.ts +0 -52
- package/runtime/sdk/compile/liteMaterial.ts +0 -247
- package/runtime/sdk/compile/sceneEditor.ts +0 -88
- package/runtime/sdk/compile/serverSplit.ts +0 -233
- package/runtime/sdk/compile/serverTypes.ts +0 -227
- package/runtime/sdk/compile/sfnt.ts +0 -98
- package/runtime/sdk/compile/shaderSchema.ts +0 -202
- package/runtime/sdk/compile/shaderTargets.ts +0 -81
- package/runtime/sdk/compile/sourcemap.ts +0 -25
- package/runtime/sdk/core/Aspect.ts +0 -568
- package/runtime/sdk/core/InspectorUI.ts +0 -212
- package/runtime/sdk/core/StateMachine.ts +0 -308
- 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 -84
- 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 -107
- package/runtime/sdk/gl/Lightmap.ts +0 -256
- package/runtime/sdk/gl/Material.ts +0 -260
- package/runtime/sdk/gl/Mesh.ts +0 -83
- package/runtime/sdk/gl/Model.ts +0 -124
- package/runtime/sdk/gl/NavAgent.ts +0 -337
- package/runtime/sdk/gl/NavMesh.ts +0 -397
- 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/Ragdoll.ts +0 -270
- package/runtime/sdk/gl/Ray.ts +0 -16
- package/runtime/sdk/gl/Scene.ts +0 -486
- package/runtime/sdk/gl/Shape.ts +0 -409
- package/runtime/sdk/gl/Terrain.ts +0 -1092
- package/runtime/sdk/gl/Texture.ts +0 -63
- 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 -120
- package/runtime/sdk/gl/animation/Layer.ts +0 -31
- package/runtime/sdk/gl/animation/Loop.ts +0 -30
- package/runtime/sdk/gl/animation/Playback.ts +0 -44
- package/runtime/sdk/gl/animation/core.ts +0 -336
- 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/terrainMesh.ts +0 -219
- package/runtime/sdk/gl/touch.ts +0 -68
- package/runtime/sdk/inject.ts +0 -197
- 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/net/codec.ts +0 -119
- package/runtime/sdk/net/core.ts +0 -384
- package/runtime/sdk/net/index.ts +0 -181
- package/runtime/sdk/net/replication.ts +0 -622
- 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 -1353
- package/runtime/sdk/scene/editorPlugins.ts +0 -110
- 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 -830
- 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,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
|
-
}
|
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
// Fine-grained reactivity for the retained-mode UI: signal() / computed() / effect() globals plus
|
|
2
|
-
// the element-binding helpers UINode/UIText use for function-valued style props and text.
|
|
3
|
-
//
|
|
4
|
-
// Design notes (the parts that are deliberate, not incidental):
|
|
5
|
-
// - Dependents (effects, computeds) hold their sources STRONGLY; sources hold dependents WEAKLY
|
|
6
|
-
// (a WeakRef in the subscriber set). An element owns its binding effects, the effect's closure
|
|
7
|
-
// owns the element — so when user code drops a subtree, the whole element+effect subgraph
|
|
8
|
-
// becomes unreachable and collects, and the signal prunes the dead WeakRef on its next write.
|
|
9
|
-
// No unmount hook is needed and re-appending a kept subtree keeps its bindings alive.
|
|
10
|
-
// - Free-standing effect() computations are additionally held in a strong root set (otherwise a
|
|
11
|
-
// `effect(() => ...)` whose handle the user discards would be GC'd mid-flight); dispose()
|
|
12
|
-
// releases them. Element bindings are NOT in the root set — the element is their owner.
|
|
13
|
-
// - Writes are batched: a signal write schedules a microtask flush; each dirty effect runs once
|
|
14
|
-
// per flush. The first run of any effect/binding is synchronous, so element styles hold
|
|
15
|
-
// concrete values immediately after construction (hosts serialize _style at mount).
|
|
16
|
-
// - QuickJS-safe: promise microtasks (the hosts drain pending jobs), WeakRef with a strong-ref
|
|
17
|
-
// fallback for engines without it (then stale subscribers just live until the run ends —
|
|
18
|
-
// every run executes in a fresh JSRuntime anyway).
|
|
19
|
-
|
|
20
|
-
interface WeakRefLike<T extends object> { deref(): T | undefined }
|
|
21
|
-
|
|
22
|
-
const WeakRefImpl: new <T extends object>(target: T) => WeakRefLike<T> =
|
|
23
|
-
typeof WeakRef !== "undefined" ? WeakRef : class StrongRef<T extends object> {
|
|
24
|
-
private _t: T
|
|
25
|
-
constructor(target: T) { this._t = target }
|
|
26
|
-
deref(): T | undefined { return this._t }
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface Computation {
|
|
30
|
-
_ref: WeakRefLike<Computation>
|
|
31
|
-
_deps: Dep[]
|
|
32
|
-
_disposed: boolean
|
|
33
|
-
_invalidate(): void
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
let activeComputation: Computation | null = null
|
|
37
|
-
|
|
38
|
-
/** Removes `c` from every source it subscribed to on its last run. */
|
|
39
|
-
const cleanupDeps = (c: Computation) => {
|
|
40
|
-
for (const dep of c._deps) dep._subs.delete(c._ref)
|
|
41
|
-
c._deps.length = 0
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
class Dep {
|
|
45
|
-
_subs = new Set<WeakRefLike<Computation>>()
|
|
46
|
-
|
|
47
|
-
_track() {
|
|
48
|
-
const c = activeComputation
|
|
49
|
-
if (c === null || this._subs.has(c._ref)) return
|
|
50
|
-
this._subs.add(c._ref)
|
|
51
|
-
c._deps.push(this)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
_notify() {
|
|
55
|
-
for (const ref of [ ...this._subs ]) {
|
|
56
|
-
const c = ref.deref()
|
|
57
|
-
if (c === undefined || c._disposed) {
|
|
58
|
-
this._subs.delete(ref) // lazy pruning of collected/disposed subscribers
|
|
59
|
-
} else {
|
|
60
|
-
c._invalidate()
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// ---- effect scheduling (microtask batch) ----
|
|
67
|
-
|
|
68
|
-
const queue = new Set<EffectImpl>()
|
|
69
|
-
let flushScheduled = false
|
|
70
|
-
|
|
71
|
-
const flush = () => {
|
|
72
|
-
// Effects may write signals, re-filling the queue mid-flush; drain until empty with a guard
|
|
73
|
-
// against write-loops (effect A invalidating itself / a cycle of effects).
|
|
74
|
-
let runs = 0
|
|
75
|
-
while (queue.size > 0) {
|
|
76
|
-
if (++runs > 10000) {
|
|
77
|
-
queue.clear()
|
|
78
|
-
console.warn("signals: effect flush exceeded 10000 runs — possible infinite update loop, remaining effects dropped")
|
|
79
|
-
break
|
|
80
|
-
}
|
|
81
|
-
const first: EffectImpl = queue.values().next().value!
|
|
82
|
-
queue.delete(first)
|
|
83
|
-
first._run()
|
|
84
|
-
}
|
|
85
|
-
flushScheduled = false
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const schedule = (fx: EffectImpl) => {
|
|
89
|
-
queue.add(fx)
|
|
90
|
-
if (!flushScheduled) {
|
|
91
|
-
flushScheduled = true
|
|
92
|
-
Promise.resolve().then(flush)
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/** Runs every pending effect now instead of waiting for the microtask (test/host hook). */
|
|
97
|
-
export const flushEffects = (): void => {
|
|
98
|
-
if (queue.size > 0) flush()
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
class EffectImpl implements Computation {
|
|
102
|
-
_ref: WeakRefLike<Computation>
|
|
103
|
-
_deps: Dep[] = []
|
|
104
|
-
_disposed = false
|
|
105
|
-
private _fn: () => void
|
|
106
|
-
|
|
107
|
-
constructor(fn: () => void) {
|
|
108
|
-
this._fn = fn
|
|
109
|
-
this._ref = new WeakRefImpl(this)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
_run() {
|
|
113
|
-
if (this._disposed) return
|
|
114
|
-
cleanupDeps(this)
|
|
115
|
-
const prev = activeComputation
|
|
116
|
-
activeComputation = this
|
|
117
|
-
try {
|
|
118
|
-
this._fn()
|
|
119
|
-
} finally {
|
|
120
|
-
activeComputation = prev
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
_invalidate() {
|
|
125
|
-
schedule(this)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
_dispose() {
|
|
129
|
-
if (this._disposed) return
|
|
130
|
-
this._disposed = true
|
|
131
|
-
cleanupDeps(this)
|
|
132
|
-
queue.delete(this)
|
|
133
|
-
rootEffects.delete(this)
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Free-standing effect() handles the user may never store — kept alive here until disposed.
|
|
138
|
-
const rootEffects = new Set<EffectImpl>()
|
|
139
|
-
|
|
140
|
-
// ---- public surface ----
|
|
141
|
-
|
|
142
|
-
export interface Signal<T> {
|
|
143
|
-
value: T,
|
|
144
|
-
/** Read without subscribing the current effect/computed. */
|
|
145
|
-
peek(): T,
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export interface Computed<T> {
|
|
149
|
-
readonly value: T,
|
|
150
|
-
/** Read without subscribing the current effect/computed (still recomputes if stale). */
|
|
151
|
-
peek(): T,
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
class SignalImpl<T> {
|
|
155
|
-
private _dep = new Dep()
|
|
156
|
-
private _v: T
|
|
157
|
-
|
|
158
|
-
constructor(value: T) {
|
|
159
|
-
this._v = value
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
get value(): T {
|
|
163
|
-
this._dep._track()
|
|
164
|
-
return this._v
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
set value(next: T) {
|
|
168
|
-
if (Object.is(next, this._v)) return
|
|
169
|
-
this._v = next
|
|
170
|
-
this._dep._notify()
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
peek(): T {
|
|
174
|
-
return this._v
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
class ComputedImpl<T> implements Computation {
|
|
179
|
-
_ref: WeakRefLike<Computation>
|
|
180
|
-
_deps: Dep[] = []
|
|
181
|
-
_disposed = false
|
|
182
|
-
private _dep = new Dep()
|
|
183
|
-
private _fn: () => T
|
|
184
|
-
private _stale = true
|
|
185
|
-
private _v!: T
|
|
186
|
-
|
|
187
|
-
constructor(fn: () => T) {
|
|
188
|
-
this._fn = fn
|
|
189
|
-
this._ref = new WeakRefImpl(this)
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
get value(): T {
|
|
193
|
-
this._dep._track()
|
|
194
|
-
if (this._stale) this._recompute()
|
|
195
|
-
return this._v
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
peek(): T {
|
|
199
|
-
if (this._stale) this._recompute()
|
|
200
|
-
return this._v
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
private _recompute() {
|
|
204
|
-
cleanupDeps(this)
|
|
205
|
-
const prev = activeComputation
|
|
206
|
-
activeComputation = this
|
|
207
|
-
try {
|
|
208
|
-
this._v = this._fn()
|
|
209
|
-
this._stale = false
|
|
210
|
-
} finally {
|
|
211
|
-
activeComputation = prev
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Lazy: a dep change only marks the memo stale and passes the wave downstream; the next read
|
|
216
|
-
// recomputes.
|
|
217
|
-
_invalidate() {
|
|
218
|
-
if (this._stale) return
|
|
219
|
-
this._stale = true
|
|
220
|
-
this._dep._notify()
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* A reactive value. Reading `.value` inside an `effect`/`computed` (or a function-valued style
|
|
226
|
-
* prop / `UIText` content) subscribes it; writing `.value` re-runs subscribers (batched — once
|
|
227
|
-
* per microtask).
|
|
228
|
-
*/
|
|
229
|
-
export function signal<T>(initialValue: T): Signal<T>
|
|
230
|
-
export function signal<T = undefined>(): Signal<T | undefined>
|
|
231
|
-
export function signal<T>(initialValue?: T): Signal<T | undefined> {
|
|
232
|
-
return new SignalImpl(initialValue)
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/** A lazily-cached derived value: recomputes on read after any of its dependencies changed. */
|
|
236
|
-
export function computed<T>(fn: () => T): Computed<T> {
|
|
237
|
-
return new ComputedImpl(fn)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Runs `fn` now and again whenever any signal/computed it read changes (batched per microtask).
|
|
242
|
-
* Returns a dispose function; an undisposed effect lives for the rest of the app run.
|
|
243
|
-
*/
|
|
244
|
-
export function effect(fn: () => void): () => void {
|
|
245
|
-
const fx = new EffectImpl(fn)
|
|
246
|
-
rootEffects.add(fx)
|
|
247
|
-
fx._run()
|
|
248
|
-
return () => fx._dispose()
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// ---- element bindings (internal — used by UINode/UIText for function-valued props) ----
|
|
252
|
-
|
|
253
|
-
/** The shape UINode's Element exposes for binding ownership. */
|
|
254
|
-
export interface BindingHost {
|
|
255
|
-
/** @internal */ _fx?: Map<string, EffectImpl>
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* @internal Creates (or replaces) the reactive binding stored under `key` on the element. The
|
|
260
|
-
* effect is owned by the element (strong ref in `_fx`), NOT by the root set — discard the element
|
|
261
|
-
* and the binding collects with it. Runs synchronously once.
|
|
262
|
-
*/
|
|
263
|
-
export function createBinding(el: BindingHost, key: string, run: () => void): void {
|
|
264
|
-
const map = el._fx ?? (el._fx = new Map())
|
|
265
|
-
map.get(key)?._dispose()
|
|
266
|
-
const fx = new EffectImpl(run)
|
|
267
|
-
map.set(key, fx)
|
|
268
|
-
fx._run()
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/** @internal Disposes the binding stored under `key`, if any (static value overriding a binding). */
|
|
272
|
-
export function disposeBinding(el: BindingHost, key: string): void {
|
|
273
|
-
const fx = el._fx?.get(key)
|
|
274
|
-
if (fx === undefined) return
|
|
275
|
-
fx._dispose()
|
|
276
|
-
el._fx!.delete(key)
|
|
277
|
-
}
|
package/runtime/sdk/core/time.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
// The game clock: one place that owns "how fast does the game run" — `Time.scale` (slow-motion, 0.5),
|
|
2
|
-
// `Time.paused` (a menu over a frozen world) — and what a frame is worth (`Time.dt`).
|
|
3
|
-
//
|
|
4
|
-
// The aspect dispatcher (core/Aspect.ts) calls `_beginFrame(rawDt)` once per frame with the host's
|
|
5
|
-
// wall-clock delta; `update*(dt)` callbacks then receive the SCALED delta (0 while paused). The same
|
|
6
|
-
// scale is pushed to every engine that registered a sink (creator-gl / creator-2d `setTimeScale`),
|
|
7
|
-
// so physics, animators and particles slow down and freeze together with the game code — a paused
|
|
8
|
-
// aspect and a paused rigid body agree. `Time.unscaledDt` is the wall-clock delta for things that
|
|
9
|
-
// must keep moving while the game is paused (a HUD fade, a pause-menu animation): those aspects set
|
|
10
|
-
// `updateWhilePaused = true` and read it themselves, exactly like Unity's unscaledDeltaTime.
|
|
11
|
-
|
|
12
|
-
type ScaleSink = (scale: number) => void
|
|
13
|
-
const sinks: ScaleSink[] = []
|
|
14
|
-
|
|
15
|
-
class TimeClock {
|
|
16
|
-
private _scale = 1
|
|
17
|
-
private _paused = false
|
|
18
|
-
/** The fixed step: what `updateFixed(dt)` receives, every time, on every machine (1/60). Under
|
|
19
|
-
* `scale` the NUMBER of fixed steps per frame changes, never this value. */
|
|
20
|
-
readonly fixedDt = 1 / 60
|
|
21
|
-
/** Seconds of GAME time since the app started (scaled; stops while paused). */
|
|
22
|
-
now = 0
|
|
23
|
-
/** Seconds of wall-clock time since the app started (never stops). */
|
|
24
|
-
unscaledNow = 0
|
|
25
|
-
/** This frame's delta in game seconds — what `update(dt)` receives. 0 while paused. */
|
|
26
|
-
dt = 0
|
|
27
|
-
/** This frame's wall-clock delta in seconds (the host's frame time, clamped by the engine). */
|
|
28
|
-
unscaledDt = 0
|
|
29
|
-
/** Frames dispatched since the app started (counts paused frames too). */
|
|
30
|
-
frame = 0
|
|
31
|
-
|
|
32
|
-
/** Speed of the game relative to wall-clock: 1 normal, 0.5 half speed, 2 double. Applied to
|
|
33
|
-
* `dt`, `now` AND the engines' physics / animation / particle clocks. Negative or NaN → 0. */
|
|
34
|
-
get scale(): number { return this._scale }
|
|
35
|
-
set scale(v: number) {
|
|
36
|
-
const s = Number.isFinite(v) && v > 0 ? v : 0
|
|
37
|
-
if (s === this._scale) return
|
|
38
|
-
this._scale = s
|
|
39
|
-
this._push()
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Freeze the game: `dt` reads 0, aspects without `updateWhilePaused` are skipped, the engines'
|
|
43
|
-
* simulations stop. `scale` is remembered and restored on resume. */
|
|
44
|
-
get paused(): boolean { return this._paused }
|
|
45
|
-
set paused(v: boolean) {
|
|
46
|
-
if (v === this._paused) return
|
|
47
|
-
this._paused = v
|
|
48
|
-
this._push()
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** The scale the engines currently run at (0 while paused). */
|
|
52
|
-
get effectiveScale(): number { return this._paused ? 0 : this._scale }
|
|
53
|
-
|
|
54
|
-
private _push(): void {
|
|
55
|
-
const s = this.effectiveScale
|
|
56
|
-
for (const sink of sinks) sink(s)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** @internal Called by the aspect dispatcher at the top of every frame with the host's raw delta. */
|
|
60
|
-
_beginFrame(rawDt: number): void {
|
|
61
|
-
const raw = Number.isFinite(rawDt) && rawDt > 0 ? rawDt : 0
|
|
62
|
-
this.frame++
|
|
63
|
-
this.unscaledNow += raw
|
|
64
|
-
this.now += this._phaseDt(raw)
|
|
65
|
-
}
|
|
66
|
-
/** @internal A phase's scaled delta from its raw one; records both as this frame's `dt`. */
|
|
67
|
-
_phaseDt(rawDt: number): number {
|
|
68
|
-
const raw = Number.isFinite(rawDt) && rawDt > 0 ? rawDt : 0
|
|
69
|
-
this.unscaledDt = raw
|
|
70
|
-
this.dt = raw * this.effectiveScale
|
|
71
|
-
return this.dt
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/** The game clock — scale / pause the whole game, read `dt` / `now` anywhere. */
|
|
76
|
-
export const Time = new TimeClock()
|
|
77
|
-
|
|
78
|
-
/** @internal Engine layers (Scene / Scene2D) register the bridge call that forwards the effective
|
|
79
|
-
* scale to their native clocks. Pushed immediately with the current value so a scene created after
|
|
80
|
-
* `Time.paused = true` starts frozen. */
|
|
81
|
-
export const _registerTimeScaleSink = (sink: ScaleSink): void => {
|
|
82
|
-
sinks.push(sink)
|
|
83
|
-
sink(Time.effectiveScale)
|
|
84
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
// Orthographic camera for a Scene2D. Position / zoom / rotation live natively. To make the camera
|
|
2
|
-
// track a node, attach a small update(dt) aspect that eases camera.position toward the node — there's
|
|
3
|
-
// no built-in follow() (and so nothing to dispose).
|
|
4
|
-
|
|
5
|
-
import { Vec2, cx, cy, type Vec2Like } from "../math/vec"
|
|
6
|
-
import type { CompAxis, CompWriter } from "../core/compWrite"
|
|
7
|
-
|
|
8
|
-
export class Camera2D implements CompWriter {
|
|
9
|
-
private _x = 0
|
|
10
|
-
private _y = 0
|
|
11
|
-
private _zoom = 1
|
|
12
|
-
private _rotation = 0
|
|
13
|
-
|
|
14
|
-
private readonly sceneId: number
|
|
15
|
-
constructor(sceneId: number) { this.sceneId = sceneId }
|
|
16
|
-
|
|
17
|
-
get position(): Vec2 { return new Vec2(this._x, this._y) }
|
|
18
|
-
set position(v: Vec2Like) { this._x = cx(v); this._y = cy(v); _creator2d.cameraSetPosition(this.sceneId, this._x, this._y) }
|
|
19
|
-
/** @internal chisel `comp_write` (see core/compWrite.ts): `camera.position.<axis> = v` compiles to a call here. */
|
|
20
|
-
static _comps = [ "position" ]
|
|
21
|
-
_writeComp(_prop: string, axis: CompAxis, v: number): void {
|
|
22
|
-
if (axis === "x") this.position = [ v, this._y ]
|
|
23
|
-
else if (axis === "y") this.position = [ this._x, v ]
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
get zoom(): number { return this._zoom }
|
|
27
|
-
set zoom(z: number) { this._zoom = z; _creator2d.cameraSetZoom(this.sceneId, z) }
|
|
28
|
-
|
|
29
|
-
get rotation(): number { return this._rotation }
|
|
30
|
-
set rotation(deg: number) { this._rotation = deg; _creator2d.cameraSetRotation(this.sceneId, deg) }
|
|
31
|
-
|
|
32
|
-
screenToWorld(screenX: number, screenY: number): Vec2 {
|
|
33
|
-
const o = _creator2d.cameraScreenToWorld(this.sceneId, screenX, screenY)
|
|
34
|
-
return new Vec2(o[0], o[1])
|
|
35
|
-
}
|
|
36
|
-
worldToScreen(worldX: number, worldY: number): Vec2 {
|
|
37
|
-
const o = _creator2d.cameraWorldToScreen(this.sceneId, worldX, worldY)
|
|
38
|
-
return new Vec2(o[0], o[1])
|
|
39
|
-
}
|
|
40
|
-
}
|