@vibecook/ice 0.3.0 → 0.6.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 +4 -4
- package/dist/{chunk-2GUYATUM.js → chunk-BFT7YWS2.js} +44 -11
- package/dist/chunk-BFT7YWS2.js.map +1 -0
- package/dist/{chunk-PKK6GLSA.js → chunk-ELCBCTKY.js} +138 -13
- package/dist/chunk-ELCBCTKY.js.map +1 -0
- package/dist/{chunk-5QY7HK6G.js → chunk-JLXETATP.js} +5594 -2712
- package/dist/chunk-JLXETATP.js.map +1 -0
- package/dist/devtools.js +5 -2
- package/dist/devtools.js.map +1 -1
- package/dist/dom.js +16 -2
- package/dist/ground.js +1 -1
- package/dist/index.js +39 -1
- package/dist/r3f.js +3 -3
- package/dist/react.js +5 -3
- package/dist/types/packages/core/src/behavior/compile.d.ts +74 -0
- package/dist/types/packages/core/src/behavior/define-behavior.d.ts +55 -0
- package/dist/types/packages/core/src/behavior/differ.d.ts +91 -0
- package/dist/types/packages/core/src/behavior/harness.d.ts +65 -0
- package/dist/types/packages/core/src/behavior/migrate.d.ts +87 -0
- package/dist/types/packages/core/src/behavior/public-reads.d.ts +31 -0
- package/dist/types/packages/core/src/behavior/runtime.d.ts +88 -0
- package/dist/types/packages/core/src/behavior/types.d.ts +312 -0
- package/dist/types/packages/core/src/behavior/world-view.d.ts +36 -0
- package/dist/types/packages/core/src/catalog/pointer.d.ts +11 -0
- package/dist/types/packages/core/src/catalog/selection-presence.d.ts +10 -0
- package/dist/types/packages/core/src/doc/rename-sweep.d.ts +3 -0
- package/dist/types/packages/core/src/doc/rename.d.ts +7 -0
- package/dist/types/packages/core/src/doc/version-gate.d.ts +14 -1
- package/dist/types/packages/core/src/engine/engine.d.ts +38 -1
- package/dist/types/packages/core/src/engine/guests.d.ts +196 -0
- package/dist/types/packages/core/src/engine/reflectors.d.ts +8 -0
- package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +16 -0
- package/dist/types/packages/core/src/guards/guarded-tx.d.ts +57 -0
- package/dist/types/packages/core/src/index.d.ts +10 -3
- package/dist/types/packages/core/src/input/queue.d.ts +9 -0
- package/dist/types/packages/core/src/schema/meta.d.ts +12 -0
- package/dist/types/packages/core/src/widget/define-widget.d.ts +89 -0
- package/dist/types/packages/core/src/widget/props.d.ts +35 -1
- package/dist/types/packages/core/src/widget/spawn.d.ts +14 -0
- package/dist/types/packages/dom/src/index.d.ts +2 -0
- package/dist/types/packages/dom/src/input-ownership.d.ts +52 -0
- package/dist/types/packages/dom/src/loop.d.ts +9 -0
- package/dist/types/packages/dom/src/pointer-adapter.d.ts +16 -3
- package/dist/types/packages/dom/src/widget-focus.d.ts +58 -0
- package/dist/types/packages/react/src/hooks.d.ts +12 -1
- package/dist/types/packages/react/src/index.d.ts +1 -1
- package/dist/types/packages/react/src/infinite-canvas.d.ts +20 -2
- package/dist/types/packages/react/src/keymap.d.ts +23 -4
- package/package.json +5 -5
- package/dist/chunk-2GUYATUM.js.map +0 -1
- package/dist/chunk-5QY7HK6G.js.map +0 -1
- package/dist/chunk-PKK6GLSA.js.map +0 -1
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The guest runtime (petition I14 — the literal PA-28 "spine scheduler").
|
|
3
|
+
*
|
|
4
|
+
* A GUEST is frame-cadence work the engine did not write: a plugin's declared
|
|
5
|
+
* system, a host's derived-state job, and (from design-009) every compiled
|
|
6
|
+
* behavior. Guests get a NAMED slot in the frame contract — design-002 §1 as
|
|
7
|
+
* amended 2026-08-15:
|
|
8
|
+
*
|
|
9
|
+
* setFrameInfo → sync → tick → GUESTS → publish hooks → notify → reflect
|
|
10
|
+
*
|
|
11
|
+
* Guests run BEFORE the publish hooks so derived state has settled by the time
|
|
12
|
+
* presence I/O reads it, and before `notify()` so the same frame reflects their
|
|
13
|
+
* writes. Three properties the engine owes anything it hosts here:
|
|
14
|
+
*
|
|
15
|
+
* 1. **Fault isolation.** A throwing guest is caught, struck, and skipped — it
|
|
16
|
+
* never kills the loop, its neighbours, or the frame. (Engine systems and
|
|
17
|
+
* publish hooks keep propagating loudly by design; guests are the untrusted
|
|
18
|
+
* tier, and the breaker below is what makes hosting them honest.)
|
|
19
|
+
* 2. **The snapshot rule.** `runAll` iterates a snapshot with a liveness check,
|
|
20
|
+
* so a guest that adds or removes guests mid-run never skips a neighbour —
|
|
21
|
+
* the bug this same release fixed in the publish-hook and reflector loops.
|
|
22
|
+
* A guest added during a run starts NEXT frame.
|
|
23
|
+
* 3. **A circuit breaker, named honestly.** A main-thread body cannot be
|
|
24
|
+
* preempted: by the time we measure, the frame is already spent. What the
|
|
25
|
+
* breaker guarantees is that no guest hurts the canvas TWICE sustained.
|
|
26
|
+
*
|
|
27
|
+
* GENERATIONS. `make(gen)` builds a per-generation instance; the generation
|
|
28
|
+
* boundary in ICE is `world.reset()` (doc close/switch — the world is reset in
|
|
29
|
+
* place, so systems, observers and this registry all survive while every entity
|
|
30
|
+
* dies). On reset we mark the generation dirty and rebuild at the TOP of the
|
|
31
|
+
* next guest step — never inside the observer emit, where structural writes are
|
|
32
|
+
* illegal and user code has no business running. `gen.signal` aborts when the
|
|
33
|
+
* generation ends or the guest is removed.
|
|
34
|
+
*
|
|
35
|
+
* THE LEDGER IS HOST-INJECTABLE. Downstream (VibeField) an engine is per-doc, so
|
|
36
|
+
* a registry-local ledger would reset on every doc switch and hand chronic
|
|
37
|
+
* offenders a fresh probation forever. `add({ledger})` seeds prior state and
|
|
38
|
+
* `onLedgerChange` reports every transition, so the host persists across
|
|
39
|
+
* generations it owns.
|
|
40
|
+
*/
|
|
41
|
+
import type { World } from "@vibecook/strata-ecs";
|
|
42
|
+
/** Frame facts a guest may read (FrameInfo, pre-read by the engine). */
|
|
43
|
+
export interface GuestFrame {
|
|
44
|
+
readonly dtMs: number;
|
|
45
|
+
readonly tick: number;
|
|
46
|
+
/** Accumulated CLAMPED dt — under-reports across freezes; never accumulate
|
|
47
|
+
* wall time from it (frame-info.ts). */
|
|
48
|
+
readonly clock: number;
|
|
49
|
+
}
|
|
50
|
+
export type GuestRun = (frame: GuestFrame) => void;
|
|
51
|
+
export interface GuestInstance {
|
|
52
|
+
run: GuestRun;
|
|
53
|
+
dispose?: () => void;
|
|
54
|
+
/**
|
|
55
|
+
* "I still owe visible work." Feeds the frame gate's settle walk, so a
|
|
56
|
+
* freeze taken mid-derive parks only AFTER the guest has caught up — the
|
|
57
|
+
* canvas is never photographed between a structural change and its reflow.
|
|
58
|
+
* A guest with no owed-work notion simply omits it (the frame gate then
|
|
59
|
+
* treats it as quiet, which is the honest default).
|
|
60
|
+
*/
|
|
61
|
+
busy?: () => boolean;
|
|
62
|
+
}
|
|
63
|
+
export interface GuestGeneration {
|
|
64
|
+
readonly world: World;
|
|
65
|
+
/** Aborts at generation teardown (world reset), removal, or engine dispose. */
|
|
66
|
+
readonly signal: AbortSignal;
|
|
67
|
+
}
|
|
68
|
+
export type GuestFactory = (gen: GuestGeneration) => GuestInstance | GuestRun;
|
|
69
|
+
/** The persistable half of a guest's breaker state. */
|
|
70
|
+
export interface GuestLedgerRecord {
|
|
71
|
+
/** Cumulative over-budget/fault strikes (never reset by resume — honesty). */
|
|
72
|
+
readonly strikes: number;
|
|
73
|
+
readonly suspended: boolean;
|
|
74
|
+
}
|
|
75
|
+
export interface GuestSpec {
|
|
76
|
+
/** Stable id — the ledger key, the profiler lane name, the doctor's row. */
|
|
77
|
+
readonly id: string;
|
|
78
|
+
readonly make: GuestFactory;
|
|
79
|
+
/** Per-invocation budget request; the effective budget is
|
|
80
|
+
* `min(budgetMs, seamCapMs)` — no single guest may claim the whole seam. */
|
|
81
|
+
readonly budgetMs?: number;
|
|
82
|
+
/** RESERVED. v1 hosts the publish slot only; pipeline-group values arrive
|
|
83
|
+
* with the behavior framework (design-009 M13a), wrapped by this breaker. */
|
|
84
|
+
readonly phase?: "publish";
|
|
85
|
+
/** Seed prior breaker state (host-persisted across engine generations). */
|
|
86
|
+
readonly ledger?: GuestLedgerRecord;
|
|
87
|
+
}
|
|
88
|
+
export interface GuestStatus {
|
|
89
|
+
readonly id: string;
|
|
90
|
+
readonly status: "running" | "suspended" | "failed";
|
|
91
|
+
/** Last invocation, ms. */
|
|
92
|
+
readonly lastMs: number;
|
|
93
|
+
/** p95 over the rolling window, ms. */
|
|
94
|
+
readonly p95Ms: number;
|
|
95
|
+
readonly strikes: number;
|
|
96
|
+
readonly budgetMs: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* A guest whose CADENCE its owner drives (design-009 §7): compiled behaviors
|
|
100
|
+
* run as ordinary pipeline systems, in their declared phase, inside the tick —
|
|
101
|
+
* so nothing here can call their bodies. What they still need is everything
|
|
102
|
+
* ELSE a guest gets: one breaker, one ledger, one doctor row, one seam total.
|
|
103
|
+
* That is what this handle is — the breaker, detached from the scheduler.
|
|
104
|
+
*/
|
|
105
|
+
export interface DrivenGuest {
|
|
106
|
+
/** Breaker verdict. Cheap and never throws — poll it from a system `runIf`. */
|
|
107
|
+
suspended(): boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Run `body` inside this guest's fault domain, ACCRUING its cost into the
|
|
110
|
+
* current frame's charge. Returns false when the guest is suspended (the
|
|
111
|
+
* body did not run) or the body threw (contained).
|
|
112
|
+
*
|
|
113
|
+
* Accrual, not per-call recording, is what makes the budget mean "per frame"
|
|
114
|
+
* for a CHUNKED body: a tick system's body runs once per matching chunk, and
|
|
115
|
+
* recording each chunk as its own invocation would compare a 2ms frame budget
|
|
116
|
+
* against a fraction of the work it was meant to bound. The accrued total is
|
|
117
|
+
* closed as ONE invocation at the guest slot, every frame.
|
|
118
|
+
*/
|
|
119
|
+
run(body: () => void): boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Report a fault the caller already CONTAINED — a per-instance hook throw
|
|
122
|
+
* that the delivery loop caught so one bad node cannot kill a 1000-node
|
|
123
|
+
* behavior (BF-D18). It takes the ordinary throw ladder.
|
|
124
|
+
*/
|
|
125
|
+
fault(err: unknown): void;
|
|
126
|
+
/** Idempotent. */
|
|
127
|
+
remove(): void;
|
|
128
|
+
}
|
|
129
|
+
export interface DrivenGuestSpec {
|
|
130
|
+
readonly id: string;
|
|
131
|
+
readonly budgetMs?: number;
|
|
132
|
+
readonly ledger?: GuestLedgerRecord;
|
|
133
|
+
/** Owed-work reporter for the frame gate's settle walk. */
|
|
134
|
+
readonly busy?: () => boolean;
|
|
135
|
+
}
|
|
136
|
+
export interface GuestRegistry {
|
|
137
|
+
/** Register a guest. Returns a remover (idempotent; disposes the instance). */
|
|
138
|
+
add(spec: GuestSpec): () => void;
|
|
139
|
+
/**
|
|
140
|
+
* Register a guest the registry does NOT call (see {@link DrivenGuest}).
|
|
141
|
+
* Its cost still lands in this frame's seam total, its strikes in the same
|
|
142
|
+
* ledger, and its row in `list()`.
|
|
143
|
+
*/
|
|
144
|
+
addDriven(spec: DrivenGuestSpec): DrivenGuest;
|
|
145
|
+
/** Live status for devtools/doctor — never throws, safe to poll. */
|
|
146
|
+
list(): readonly GuestStatus[];
|
|
147
|
+
/** Fires whenever a guest's persistable breaker state changes. */
|
|
148
|
+
onLedgerChange(cb: (id: string, record: GuestLedgerRecord) => void): () => void;
|
|
149
|
+
/** Clear a suspension (the doctor's explicit action). Cumulative strikes
|
|
150
|
+
* survive; the rolling window is cleared so probation starts fresh. */
|
|
151
|
+
resume(id: string): void;
|
|
152
|
+
}
|
|
153
|
+
/** The engine-facing half (step drives it; hosts never see these). */
|
|
154
|
+
export interface GuestRegistryInternal extends GuestRegistry {
|
|
155
|
+
runAll(frame: GuestFrame): void;
|
|
156
|
+
/** Any live guest reporting owed work — the engine's settle reporter. */
|
|
157
|
+
anyBusy(): boolean;
|
|
158
|
+
dispose(): void;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Breaker constants (design-009 §12 / door ED-D3). Exported so tests and the
|
|
162
|
+
* downstream doctor cite ONE source rather than re-deriving thresholds.
|
|
163
|
+
*/
|
|
164
|
+
export declare const GUEST_BUDGET: {
|
|
165
|
+
/** Default per-invocation budget when a guest declares none. */
|
|
166
|
+
readonly defaultBudgetMs: 2;
|
|
167
|
+
/** The whole guest seam's sustained budget — also the per-guest ceiling. */
|
|
168
|
+
readonly seamCapMs: 8;
|
|
169
|
+
/** Rolling window length, in invocations. */
|
|
170
|
+
readonly window: 120;
|
|
171
|
+
/** Trip: more than this many of the last `window` invocations over budget. */
|
|
172
|
+
readonly overBudgetTrip: 30;
|
|
173
|
+
/** Trip: this many CONSECUTIVE invocations at ≥ `heavyFactor` × budget. */
|
|
174
|
+
readonly consecutiveHeavy: 3;
|
|
175
|
+
readonly heavyFactor: 4;
|
|
176
|
+
/** Trip: this many CONSECUTIVE invocations over `stallMs` (one GC pause or
|
|
177
|
+
* debugger breakpoint must never suspend — hence 2, not 1). */
|
|
178
|
+
readonly consecutiveStall: 2;
|
|
179
|
+
readonly stallMs: 50;
|
|
180
|
+
/** Trip: this many consecutive throws. */
|
|
181
|
+
readonly consecutiveThrows: 3;
|
|
182
|
+
/** Frames the whole seam may sit over `seamCapMs` before the worst offender
|
|
183
|
+
* is suspended. */
|
|
184
|
+
readonly seamOverFrames: 3;
|
|
185
|
+
};
|
|
186
|
+
export interface GuestRegistryOpts {
|
|
187
|
+
/**
|
|
188
|
+
* Dev leniency: while true, TIMING strikes log and never suspend (the throw
|
|
189
|
+
* ladder still bites). Wired to `engine.enableTelemetry()` — i.e. devtools
|
|
190
|
+
* attached — so stepping in a debugger cannot suspend a healthy guest.
|
|
191
|
+
*/
|
|
192
|
+
readonly lenient?: () => boolean;
|
|
193
|
+
readonly onFault?: (id: string, err: unknown) => void;
|
|
194
|
+
readonly onNotice?: (message: string) => void;
|
|
195
|
+
}
|
|
196
|
+
export declare function createGuestRegistry(world: World, opts?: GuestRegistryOpts): GuestRegistryInternal;
|
|
@@ -50,6 +50,14 @@ export interface ReflectorRegistry {
|
|
|
50
50
|
/** Every registered reflector, registration order (devtools enumeration —
|
|
51
51
|
* independent of telemetry; a reflector idle since boot still lists). */
|
|
52
52
|
names(): readonly string[];
|
|
53
|
+
/** Arm flush timing (idempotent). Costs one `performance.now()` pair per
|
|
54
|
+
* flushed reflector per frame, so it rides `engine.enableTelemetry()` and is
|
|
55
|
+
* off by default — the same opt-in posture as per-system timing. */
|
|
56
|
+
armTelemetry(): void;
|
|
57
|
+
/** Total µs of the most recent `flushAll` (0 until armed). */
|
|
58
|
+
lastFlushMicros(): number;
|
|
59
|
+
/** Per-reflector µs of the most recent `flushAll` (empty until armed). */
|
|
60
|
+
lastFlushDetail(): ReadonlyMap<string, number>;
|
|
53
61
|
}
|
|
54
62
|
export declare function createReflectorRegistry(world: World, opts?: {
|
|
55
63
|
onFault?: (name: string, err: unknown) => void;
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
* remain reviewed constants (RUNTIME_BUDGETS) in v1 — recorded.
|
|
20
20
|
*/
|
|
21
21
|
import type { Entity, World } from "@vibecook/strata-ecs";
|
|
22
|
+
import { type BehaviorRuntime } from "../behavior/runtime";
|
|
23
|
+
import type { AnyBehaviorDef } from "../behavior/types";
|
|
22
24
|
import { type Engine } from "../engine/engine";
|
|
23
25
|
import type { FrameControl } from "../engine/frame-control";
|
|
24
26
|
import { type InteractionStack } from "../interaction/install";
|
|
@@ -42,6 +44,13 @@ export interface CanvasEngineOpts {
|
|
|
42
44
|
}[];
|
|
43
45
|
/** Registered tools (definition happens at defineTool; validated). */
|
|
44
46
|
readonly tools?: readonly Tool[];
|
|
47
|
+
/**
|
|
48
|
+
* Behaviors this engine runs (design-009). Definition is the import
|
|
49
|
+
* side-effect; listing them here COMPILES and installs them — a behavior that
|
|
50
|
+
* is defined but never registered costs nothing and does nothing, which is
|
|
51
|
+
* what makes "a plugin declared it" and "this engine runs it" separable.
|
|
52
|
+
*/
|
|
53
|
+
readonly behaviors?: readonly AnyBehaviorDef[];
|
|
45
54
|
readonly budgets?: {
|
|
46
55
|
readonly keepMounted?: number;
|
|
47
56
|
readonly fboBytes?: number;
|
|
@@ -166,6 +175,13 @@ export interface StageControl {
|
|
|
166
175
|
export interface CanvasEngine {
|
|
167
176
|
readonly world: World;
|
|
168
177
|
readonly engine: Engine;
|
|
178
|
+
/**
|
|
179
|
+
* The behavior runtime (design-009 §6): attach/detach/has/read for
|
|
180
|
+
* runtime-class behaviors, plus `list()` for devtools and the doctor.
|
|
181
|
+
* DURABLE attachment is deliberately absent — it is a document op and goes
|
|
182
|
+
* through `tx.attach` inside a transaction, so it syncs and undoes.
|
|
183
|
+
*/
|
|
184
|
+
readonly behaviors: BehaviorRuntime;
|
|
169
185
|
readonly stack: InteractionStack;
|
|
170
186
|
readonly runtime: WidgetRuntime & {
|
|
171
187
|
uninstall(): void;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import type { Component, Entity, OrderPlace, Relation, Resource, Tag, World } from "@vibecook/strata-ecs";
|
|
15
15
|
import type { Mutator } from "@vibecook/strata-ecs/durable";
|
|
16
16
|
import { type ComponentInit, type Prefab } from "../schema/prefab";
|
|
17
|
+
import type { LiveWriter } from "./live-writer";
|
|
17
18
|
export interface GuardedTx {
|
|
18
19
|
spawnPrefab(prefab: Prefab, overrides?: readonly ComponentInit[]): Entity;
|
|
19
20
|
/** Raw spawn — entity is unknown to the guard (prefer spawnPrefab). */
|
|
@@ -32,6 +33,29 @@ export interface GuardedTx {
|
|
|
32
33
|
/** Reorder within the current parent's sibling sequence — ordered relations only (petition 8). */
|
|
33
34
|
moveRelation(e: Entity, r: Relation, place: OrderPlace): void;
|
|
34
35
|
setResource<S>(res: Resource<S>, v: S): void;
|
|
36
|
+
/**
|
|
37
|
+
* Animation-integrated write (petition I15): ONE commit owns the capture, the
|
|
38
|
+
* durable final, and the glide. `from` is read AT CALL TIME (pre-commit by
|
|
39
|
+
* construction), the final lands in THIS transaction — inheriting its
|
|
40
|
+
* `undoable` — and after a successful seal the tail installs the verified
|
|
41
|
+
* public-surface glide: `TransformTween` (which GRANTS the divergence) then a
|
|
42
|
+
* live rewind to `from`. One commit, one undo entry, no double-write.
|
|
43
|
+
*
|
|
44
|
+
* `animateMs` absent/0 = snap (no tween attached at all). A `Grab`-held
|
|
45
|
+
* entity is SKIPPED — the gesture owns its divergence. An entity already
|
|
46
|
+
* tweening is RETARGETED (its `toX/toY` rewritten) rather than restarted, so
|
|
47
|
+
* a re-layout mid-glide re-aims instead of completing at a stale target.
|
|
48
|
+
*
|
|
49
|
+
* Requires `opts.live` (the session's LiveWriter) — without it the rewind
|
|
50
|
+
* could not be divergence-guarded, so the call refuses rather than writing
|
|
51
|
+
* around the guard.
|
|
52
|
+
*/
|
|
53
|
+
move(e: Entity, to: {
|
|
54
|
+
x: number;
|
|
55
|
+
y: number;
|
|
56
|
+
}, opts?: {
|
|
57
|
+
animateMs?: number;
|
|
58
|
+
}): void;
|
|
35
59
|
}
|
|
36
60
|
interface GuardedEditor {
|
|
37
61
|
set<S>(c: Component<S>, v: S): GuardedEditor;
|
|
@@ -39,6 +63,7 @@ interface GuardedEditor {
|
|
|
39
63
|
interface TxDoc {
|
|
40
64
|
transaction(fn: (tx: Mutator) => void, opts?: {
|
|
41
65
|
undoable?: boolean;
|
|
66
|
+
meta?: Record<string, unknown>;
|
|
42
67
|
}): void;
|
|
43
68
|
}
|
|
44
69
|
export interface GuardedTxOpts {
|
|
@@ -48,6 +73,38 @@ export interface GuardedTxOpts {
|
|
|
48
73
|
* first-⌘Z-removes-a-seed quirk). Default true: one tx = one undo step.
|
|
49
74
|
*/
|
|
50
75
|
readonly undoable?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* The session's live writer. Required by {@link GuardedTx.move} (its
|
|
78
|
+
* post-commit rewind is a live write to a doc cell, legal only under the
|
|
79
|
+
* tween grant) and by the post-seal retarget sweep below.
|
|
80
|
+
*/
|
|
81
|
+
readonly live?: LiveWriter;
|
|
82
|
+
/** Optional entity → doc-key probe; when absent every entity is treated as
|
|
83
|
+
* durable-if-Position-eligible. Used to skip runtime-only movers' tx write. */
|
|
84
|
+
readonly keyOf?: (e: Entity) => string | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* Per-commit PROVENANCE (strata 0.12.0, petition 9): a small record carried
|
|
87
|
+
* in-CRDT with the batch, so a receiving peer can say who wrote this and why.
|
|
88
|
+
* The behavior framework stamps `{ behavior, label }` on every `ctx.commit`
|
|
89
|
+
* (design-009 §4.4 — `label` is a stable machine id, never display text).
|
|
90
|
+
* Note that shallow saves erase provenance below the compaction boundary, so
|
|
91
|
+
* it is diagnostics, never a data dependency.
|
|
92
|
+
*/
|
|
93
|
+
readonly meta?: Record<string, unknown>;
|
|
51
94
|
}
|
|
52
95
|
export declare function guardedTransaction(doc: TxDoc, world: World, run: (tx: GuardedTx) => void, opts?: GuardedTxOpts): void;
|
|
96
|
+
/**
|
|
97
|
+
* Retarget every live tween onto its DURABLE truth — the undo/redo chokepoint
|
|
98
|
+
* (petition I15). Undo does not pass through {@link guardedTransaction}: it is
|
|
99
|
+
* strata's own local batch, so a glide in flight when ⌘Z lands would otherwise
|
|
100
|
+
* complete at the pre-undo target and strand the cell exactly as above.
|
|
101
|
+
*
|
|
102
|
+
* `durablePositionOf` reads the committed value (the doc's, not the runtime's).
|
|
103
|
+
* A tween whose entity has no durable Position is left alone — nothing to
|
|
104
|
+
* reconcile against.
|
|
105
|
+
*/
|
|
106
|
+
export declare function retargetTweensToDoc(world: World, entities: Iterable<Entity>, durablePositionOf: (e: Entity) => {
|
|
107
|
+
x: number;
|
|
108
|
+
y: number;
|
|
109
|
+
} | undefined): void;
|
|
53
110
|
export {};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* scene systems · doc kit · publish step · engine facade · reflector registry.
|
|
4
4
|
* Import wall: strata-ecs + @ice/kernel ONLY — never react/dom/three (enforced).
|
|
5
5
|
*/
|
|
6
|
-
export declare const CORE_VERSION = "0.
|
|
6
|
+
export declare const CORE_VERSION = "0.6.0";
|
|
7
7
|
export { defineSchemaOnce, hmrInvalidateOnSchemaChange } from "./boot/hmr";
|
|
8
8
|
export { All, Any, Not, Related, createWorld, defineQuery, defineSystem, defineTickSystem, enumOf, field, Local, } from "@vibecook/strata-ecs";
|
|
9
9
|
export type { Batch, Component, Condition, Entity, OrderPlace, Pipeline, Query, Relation, Resource, System, SystemCtx, Tag, TickSystem, World, } from "@vibecook/strata-ecs";
|
|
@@ -15,6 +15,12 @@ export { createPipelineRegistry, PHASE_GROUPS, type AnySystem, type PhaseGroup,
|
|
|
15
15
|
export { createReflectorRegistry, type ReflectorDef, type ReflectorObserve, type ReflectorQuerySpec, type ReflectorRegistry, } from "./engine/reflectors";
|
|
16
16
|
export { createEngine, type Engine, type EngineOpts, type FrameTelemetry, type PublishHook, type SystemRunRecord, } from "./engine/engine";
|
|
17
17
|
export { createFrameControl, SETTLE_CAP, type FrameControl } from "./engine/frame-control";
|
|
18
|
+
export { createGuestRegistry, GUEST_BUDGET, type GuestFactory, type GuestFrame, type GuestGeneration, type GuestInstance, type GuestLedgerRecord, type GuestRegistry, type GuestRegistryOpts, type GuestRun, type GuestSpec, type GuestStatus, } from "./engine/guests";
|
|
19
|
+
export { behaviors, defineBehavior } from "./behavior/define-behavior";
|
|
20
|
+
export { BEHAVIOR_DEFAULT_PHASE, BEHAVIOR_PHASES, type AnyBehaviorAttachSpec, type AnyBehaviorDef, type BehaviorAttachSpec, type BehaviorChanges, type BehaviorCtxBase, type BehaviorCtxFor, type BehaviorFrame, type BehaviorHandle, type BehaviorHooks, type BehaviorPhase, type BehaviorQuery, type BehaviorQuerySpec, type BehaviorRead, type BehaviorSchema, type BehaviorSpec, type BehaviorStore, type BehaviorTx, type BehaviorWorld, type DataOf, type DurableBehaviorCtx, type EphemeralBehaviorCtx, type PeerFacet, type RuntimeBehaviorCtx, } from "./behavior/types";
|
|
21
|
+
export { compileBehavior, isDurableEligible, type CompiledBehavior } from "./behavior/compile";
|
|
22
|
+
export { behaviorMarkerKey, classifyBehaviorVersion, docBehaviorVersion, stampBehaviorMarker, BEHAVIOR_MARKER_PREFIX, type BehaviorMeta, type BehaviorVerdict, } from "./behavior/migrate";
|
|
23
|
+
export { createBehaviorHarness, type BehaviorHarness, type BehaviorHarnessOpts, type HarnessCommit, } from "./behavior/harness";
|
|
18
24
|
export { devGuardsEnabled, setDevGuards } from "./guards/dev";
|
|
19
25
|
export { createLiveWriter, type LiveWriter, type LiveWriterOpts } from "./guards/live-writer";
|
|
20
26
|
export { guardedTransaction, type GuardedTx, type GuardedTxOpts } from "./guards/guarded-tx";
|
|
@@ -22,6 +28,7 @@ export { writeRuntimeResource } from "./guards/resource-writer";
|
|
|
22
28
|
export * from "./catalog";
|
|
23
29
|
export * from "./helpers/phase-set";
|
|
24
30
|
export * from "./helpers/version-stamps";
|
|
31
|
+
export * from "./helpers/churn-guard";
|
|
25
32
|
export * from "./ops/arrange";
|
|
26
33
|
export * from "./ops/selection";
|
|
27
34
|
export * from "./ops/cascade";
|
|
@@ -48,9 +55,9 @@ export type { DurableUndoStatusValue } from "@vibecook/strata-ecs/durable";
|
|
|
48
55
|
export { createDocSession, openDocSession, type DocSession, type DocSessionOpts, type OpenDocResult, } from "./doc/doc-kit";
|
|
49
56
|
export { runMigrations, type MigrationCtx, type MigrationOutcome } from "./doc/migrate";
|
|
50
57
|
export { p, type JsonShape, type PropSpec, type PropsDecl, type StandardSchemaV1 } from "./widget/props";
|
|
51
|
-
export { WidgetEquipped, defineWidget, widgets, type SizeMode, type WidgetDef, type WidgetGroup, type WidgetInteraction, type WidgetPortDecl, type WidgetSurface, type WidgetType, } from "./widget/define-widget";
|
|
58
|
+
export { WidgetEquipped, defineWidget, renames, widgets, type SizeMode, type WidgetDef, type WidgetGroup, type WidgetInteraction, type WidgetPortDecl, type WidgetBehaviorDecl, type WidgetBehaviorEntry, type WidgetRename, type WidgetRenameEntry, type WidgetSurface, type WidgetType, } from "./widget/define-widget";
|
|
52
59
|
export { createWidgetEquipSystem } from "./widget/equip";
|
|
53
|
-
export { attachSpawnParent, spawnWidget, widgetSpawnInits, type SpawnWidgetOpts } from "./widget/spawn";
|
|
60
|
+
export { attachSpawnBehaviors, attachSpawnParent, spawnWidget, widgetSpawnInits, type SpawnWidgetOpts } from "./widget/spawn";
|
|
54
61
|
export { setWidgetProps } from "./widget/set-props";
|
|
55
62
|
export { createWidgetRuntime, installWidgetRuntime, type MountEntry, type WidgetMountStore, type WidgetRuntime, } from "./widget/mount-store";
|
|
56
63
|
export * from "./settings/defaults";
|
|
@@ -40,6 +40,15 @@ export interface InputEvent {
|
|
|
40
40
|
};
|
|
41
41
|
/** GL-island opt-out (pinned widget-event contract, design-002 §8): fact still lands, recognizers skip. */
|
|
42
42
|
readonly surfaceHandled?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Wheel-only opt-out (design-007 §3.5, petition I4): this wheel's deltas were
|
|
45
|
+
* ceded to scrollable widget content — the adapter skipped `preventDefault`
|
|
46
|
+
* and native scroll consumed them. The fact still lands (one input path);
|
|
47
|
+
* ingest stamps the one-tick `WheelHandled` tag so the wheel recognizers skip
|
|
48
|
+
* the tick. DISTINCT from `surfaceHandled` on purpose: the shared latch on
|
|
49
|
+
* the persistent mouse pointer would collide with a same-tick canvas down.
|
|
50
|
+
*/
|
|
51
|
+
readonly wheelHandled?: boolean;
|
|
43
52
|
/**
|
|
44
53
|
* Hover-time widget-boundary fact (design-002 §8 amendment, 2026-07-18): the
|
|
45
54
|
* pointer is currently over content that would opt a down out — a native
|
|
@@ -28,6 +28,18 @@ export interface ResourceMeta {
|
|
|
28
28
|
durable: boolean;
|
|
29
29
|
}
|
|
30
30
|
export declare function defineComponent<const Sch extends RawSchema>(name: string, schema: Sch): ReturnType<typeof strataDefineComponent<Sch>>;
|
|
31
|
+
/**
|
|
32
|
+
* Reuse-or-define by NAME (design-008 §3.1): strata's schema registry throws
|
|
33
|
+
* on duplicate identifiers (its registry.ts:38), and rename legacy components
|
|
34
|
+
* (`<oldType>:<group>`) can legitimately re-enter the process — a test that
|
|
35
|
+
* defined the old widget before resetting ice registries, or a hot-reload
|
|
36
|
+
* double-eval — while strata's global registry survives. An existing
|
|
37
|
+
* SAME-SHAPED component is the same component: reuse its handle. A mismatched
|
|
38
|
+
* shape under the same name is a real collision: throw. The shape compare is
|
|
39
|
+
* JSON-stringify over the recorded raw schema — sound here because both sides
|
|
40
|
+
* are built by the same `strataFieldOf` constructors in the same field order.
|
|
41
|
+
*/
|
|
42
|
+
export declare function ensureComponent<const Sch extends RawSchema>(name: string, schema: Sch): Component;
|
|
31
43
|
export declare function defineTag(name: string): Tag;
|
|
32
44
|
export declare function defineRelation(name: string, opts?: {
|
|
33
45
|
arity?: "one" | "many";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Component, Tag } from "@vibecook/strata-ecs";
|
|
2
|
+
import type { AnyBehaviorAttachSpec, AnyBehaviorDef } from "../behavior/types";
|
|
2
3
|
import { type Prefab } from "../schema/prefab";
|
|
3
4
|
import type { PropSpec, PropsDecl } from "./props";
|
|
4
5
|
export type WidgetSurface = "dom" | "gl";
|
|
@@ -11,6 +12,42 @@ export interface WidgetPortDecl {
|
|
|
11
12
|
/** Compatibility keys (empty = connects to anything). */
|
|
12
13
|
readonly accepts?: readonly string[];
|
|
13
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* A prior durable id of this widget type (design-008 §3, petition I5). Docs
|
|
17
|
+
* written under the old id fold to this type at open (doc/rename.ts) and via
|
|
18
|
+
* the live zombie sweep (doc/rename-sweep.ts) — replicas converge through
|
|
19
|
+
* ordinary CRDT delivery, retiring offline byte surgery. Declares group-NAME
|
|
20
|
+
* continuity at the rename boundary (the pack runner's existing fence).
|
|
21
|
+
*/
|
|
22
|
+
export interface WidgetRename {
|
|
23
|
+
/** The old durable type id (`PrefabId.id` in pre-rename docs). */
|
|
24
|
+
readonly type: string;
|
|
25
|
+
/**
|
|
26
|
+
* The pack version old-build writers of `type` were at (default 1). Only
|
|
27
|
+
* the SWEEP consumes it — a late old-shape delivery carries no marker, so
|
|
28
|
+
* its values chain-fold from here; the open-path runner reads the version
|
|
29
|
+
* off the doc's own markers instead (design-008 §6.3).
|
|
30
|
+
*/
|
|
31
|
+
readonly atVersion?: number;
|
|
32
|
+
}
|
|
33
|
+
/** A rename registry entry (doc/rename runner + sweep input). */
|
|
34
|
+
export interface WidgetRenameEntry {
|
|
35
|
+
readonly widget: WidgetType;
|
|
36
|
+
readonly oldType: string;
|
|
37
|
+
readonly atVersion: number;
|
|
38
|
+
/** Legacy `<oldType>:<group>` components, index-aligned with `widget.groups`. */
|
|
39
|
+
readonly legacyGroups: readonly Component[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A behavior pre-attachment on a widget type: the bare handle for defaults, or
|
|
43
|
+
* `Behavior.with({...})` for a starting value (design-009 §6).
|
|
44
|
+
*/
|
|
45
|
+
export type WidgetBehaviorDecl = AnyBehaviorDef | AnyBehaviorAttachSpec;
|
|
46
|
+
/** Normalized pre-attachment (registry truth for the spawn + equip paths). */
|
|
47
|
+
export interface WidgetBehaviorEntry {
|
|
48
|
+
readonly behavior: AnyBehaviorDef;
|
|
49
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
50
|
+
}
|
|
14
51
|
export interface WidgetInteraction {
|
|
15
52
|
readonly selectable?: boolean;
|
|
16
53
|
readonly movable?: boolean;
|
|
@@ -26,6 +63,25 @@ export interface WidgetInteraction {
|
|
|
26
63
|
* membership — never reparenting). Default false.
|
|
27
64
|
*/
|
|
28
65
|
readonly sweepContained?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Keyboard claim (design-007 §3.1, petitions I1/I4). `"exclusive"`: while a
|
|
68
|
+
* node inside this widget holds browser focus, the engine keymap and the
|
|
69
|
+
* adapter's Space pan modifier stand down — keys flow to the widget's own
|
|
70
|
+
* handlers (the engine stops competing; it never delivers behavior). The
|
|
71
|
+
* dom-widgets reflector marks the host `data-canvas-keyboard` + `tabindex=-1`
|
|
72
|
+
* so a click anywhere in the widget acquires focus, and plain wheel over the
|
|
73
|
+
* widget's scrollable content cedes to native scroll (ctrl/pinch stays
|
|
74
|
+
* canvas zoom always). Default `"shared"` — today's behavior, byte-identical.
|
|
75
|
+
*/
|
|
76
|
+
readonly keyboard?: "shared" | "exclusive";
|
|
77
|
+
/**
|
|
78
|
+
* Escape ownership under an exclusive claim (design-007 §3.3 / §7-Q1).
|
|
79
|
+
* `"release"` (default): Escape is the engine-reserved release gesture — it
|
|
80
|
+
* blurs the widget; the NEXT Escape, with focus gone, cancels gestures.
|
|
81
|
+
* `"widget"`: even Escape flows to the widget (vim-grade terminals); release
|
|
82
|
+
* is click-away or `blurFocus()`. Ignored unless `keyboard: "exclusive"`.
|
|
83
|
+
*/
|
|
84
|
+
readonly keyboardEscape?: "release" | "widget";
|
|
29
85
|
}
|
|
30
86
|
export interface WidgetDef {
|
|
31
87
|
readonly type: string;
|
|
@@ -101,6 +157,28 @@ export interface WidgetDef {
|
|
|
101
157
|
* (its `provides` wins).
|
|
102
158
|
*/
|
|
103
159
|
readonly provides?: readonly string[];
|
|
160
|
+
/**
|
|
161
|
+
* Prior durable ids folded to this type (design-008; petition I5). Additive:
|
|
162
|
+
* registers read-only LEGACY group components under the old names so
|
|
163
|
+
* pre-rename cells project, gates pre-rename docs "migrate" instead of
|
|
164
|
+
* read-only, and arms the live zombie sweep on every writable session.
|
|
165
|
+
*/
|
|
166
|
+
readonly renamedFrom?: readonly WidgetRename[];
|
|
167
|
+
/**
|
|
168
|
+
* Behaviors every instance of this type carries (design-009 §6). The store
|
|
169
|
+
* class routes HOW, exactly as it routes everything else:
|
|
170
|
+
* - `durable` behaviors are attached as post-spawn `addComponent` calls in
|
|
171
|
+
* the SAME spawn transaction — document truth, so they sync and undo with
|
|
172
|
+
* the widget. (Not spawn-init overrides: those hit the prefab's
|
|
173
|
+
* all-builds eligibility throw in `instantiate.ts`.)
|
|
174
|
+
* - `runtime` behaviors are stamped at PROJECTION by the equip system,
|
|
175
|
+
* beside the capability tags. That is the only mechanism that also equips
|
|
176
|
+
* a widget arriving from a remote peer or a restored file, which a rider
|
|
177
|
+
* attached at spawn time would miss on every peer but the author's.
|
|
178
|
+
* Ephemeral behaviors are refused: an ephemeral instance IS the local
|
|
179
|
+
* presence peer, so it cannot ride a widget at all.
|
|
180
|
+
*/
|
|
181
|
+
readonly behaviors?: readonly WidgetBehaviorDecl[];
|
|
104
182
|
/**
|
|
105
183
|
* fromVersion → idempotent absolute transform (M9's `runMigrations` runs the
|
|
106
184
|
* chain at open; `prev`/return are flat prop records spanning every group).
|
|
@@ -146,7 +224,13 @@ export interface WidgetType {
|
|
|
146
224
|
readonly ports: readonly WidgetPortDecl[];
|
|
147
225
|
/** Runtime capability tags the equip system stamps at projection. */
|
|
148
226
|
readonly capabilityTags: readonly Tag[];
|
|
227
|
+
/** Keyboard claim (design-007): the dom layer reads THIS (registry truth), not the tag. */
|
|
228
|
+
readonly keyboard: "shared" | "exclusive";
|
|
229
|
+
/** Escape ownership under an exclusive claim ("release" = engine-reserved). */
|
|
230
|
+
readonly keyboardEscape: "release" | "widget";
|
|
149
231
|
readonly migrate: Readonly<Record<number, (prev: Record<string, unknown>) => Record<string, unknown>>>;
|
|
232
|
+
/** Pre-attached behaviors, normalized (spawn tx for durable, equip for runtime). */
|
|
233
|
+
readonly behaviors: readonly WidgetBehaviorEntry[];
|
|
150
234
|
/** Normalized author preview component (opaque; react narrows). null = none declared. */
|
|
151
235
|
readonly previewComponent: unknown;
|
|
152
236
|
/** Prop overrides for the default real-component preview mount (validated names). */
|
|
@@ -158,6 +242,11 @@ export declare const widgets: {
|
|
|
158
242
|
get(type: string): WidgetType | undefined;
|
|
159
243
|
all(): WidgetType[];
|
|
160
244
|
};
|
|
245
|
+
/** The rename registry (design-008 §3): old durable id → fold target. */
|
|
246
|
+
export declare const renames: {
|
|
247
|
+
get(oldType: string): WidgetRenameEntry | undefined;
|
|
248
|
+
all(): WidgetRenameEntry[];
|
|
249
|
+
};
|
|
161
250
|
export declare function defineWidget(def: WidgetDef): WidgetType;
|
|
162
251
|
/** TEST-ONLY wipe (mirrors __resetPrefabsForTests; not on the barrel). */
|
|
163
252
|
export declare function __resetWidgetsForTests(): void;
|
|
@@ -25,7 +25,7 @@ export interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
export type PropSpec = StringSpec | NumberSpec | BooleanSpec | EnumSpec | JsonSpec;
|
|
28
|
+
export type PropSpec = StringSpec | NumberSpec | BooleanSpec | EnumSpec | JsonSpec | EntityKeySpec;
|
|
29
29
|
export interface StringSpec extends StandardSchemaV1<unknown, string> {
|
|
30
30
|
readonly kind: "string";
|
|
31
31
|
readonly default?: string;
|
|
@@ -52,6 +52,19 @@ export interface JsonSpec extends StandardSchemaV1<unknown, unknown> {
|
|
|
52
52
|
/** Serialized default (derived from the inner root when not given). */
|
|
53
53
|
readonly default?: string;
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* A DURABLE entity reference (design-009 §4.2): the doc key of another entity,
|
|
57
|
+
* stored as a plain string cell. This is the ONLY legal cross-entity reference
|
|
58
|
+
* in behavior data — Law 7 bans `eid` from durable cells because a runtime
|
|
59
|
+
* handle means nothing to the peer that receives it, while a doc key survives
|
|
60
|
+
* the wire, the file, and a reload. Empty string = no reference; resolution is
|
|
61
|
+
* `ctx.entityFor(key)`, which may legitimately return undefined while the
|
|
62
|
+
* target is not yet projected.
|
|
63
|
+
*/
|
|
64
|
+
export interface EntityKeySpec extends StandardSchemaV1<unknown, string> {
|
|
65
|
+
readonly kind: "entityKey";
|
|
66
|
+
readonly default?: string;
|
|
67
|
+
}
|
|
55
68
|
/** Shapes legal only INSIDE p.json (validation-only, never components). */
|
|
56
69
|
export type JsonShape = {
|
|
57
70
|
readonly kind: "string";
|
|
@@ -91,8 +104,29 @@ export declare const p: {
|
|
|
91
104
|
json(inner: JsonShape, opts?: {
|
|
92
105
|
default?: unknown;
|
|
93
106
|
}): JsonSpec;
|
|
107
|
+
/**
|
|
108
|
+
* A durable reference to another entity by DOC KEY (design-009 §4.2).
|
|
109
|
+
* Behavior-facing: `defineWidget` props have no use for it (a widget's
|
|
110
|
+
* references are relations), but nothing rejects it there either — it is an
|
|
111
|
+
* ordinary string cell with a declared meaning.
|
|
112
|
+
*/
|
|
113
|
+
entityKey(opts?: {
|
|
114
|
+
default?: string;
|
|
115
|
+
}): EntityKeySpec;
|
|
94
116
|
array(item: JsonShape): JsonShape;
|
|
95
117
|
object(fields: Readonly<Record<string, JsonShape>>): JsonShape;
|
|
96
118
|
};
|
|
97
119
|
/** A widget props declaration: top-level named specs (the compiler's input). */
|
|
98
120
|
export type PropsDecl = Readonly<Record<string, PropSpec>>;
|
|
121
|
+
/**
|
|
122
|
+
* The CELL default for a spec — the value a whole-component write fills in for
|
|
123
|
+
* an untouched field, and the value a generated strata field declares.
|
|
124
|
+
*
|
|
125
|
+
* One function, three callers (widget spawn defaults, `defineWidget`'s
|
|
126
|
+
* essential set, `defineBehavior`'s attach defaults): each used to carry its
|
|
127
|
+
* own else-if chain over `spec.kind`, and each chain had to be found and
|
|
128
|
+
* amended when `p.entityKey` was added — one of them by inspection rather than
|
|
129
|
+
* by a type error, since the chains end in a catch-all `else`. It lives here,
|
|
130
|
+
* beside the specs whose shape it reads.
|
|
131
|
+
*/
|
|
132
|
+
export declare function defaultValueOf(spec: PropSpec): string | number | boolean;
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { Entity, OrderPlace, Relation, World } from "@vibecook/strata-ecs";
|
|
10
10
|
import type { DurableStore } from "@vibecook/strata-ecs/durable";
|
|
11
|
+
import { type GuardedTx } from "../guards/guarded-tx";
|
|
11
12
|
import { type ComponentInit } from "../schema/prefab";
|
|
13
|
+
import { type WidgetType } from "./define-widget";
|
|
12
14
|
export interface SpawnWidgetOpts {
|
|
13
15
|
readonly x: number;
|
|
14
16
|
readonly y: number;
|
|
@@ -47,4 +49,16 @@ export declare function widgetSpawnInits(type: string, opts: SpawnWidgetOpts): {
|
|
|
47
49
|
prefab: import("../schema/prefab").Prefab;
|
|
48
50
|
overrides: ComponentInit[];
|
|
49
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* Attach a widget type's DURABLE pre-attached behaviors (design-009 §6), as
|
|
54
|
+
* post-spawn `addComponent` calls inside the spawn transaction.
|
|
55
|
+
*
|
|
56
|
+
* Post-spawn rather than spawn-init overrides: `instantiate` checks every
|
|
57
|
+
* override against the prefab's eligible set, and a behavior is eligible on
|
|
58
|
+
* every entity by definition (BF-D6) — it is not in any prefab's set and never
|
|
59
|
+
* will be. Runtime pre-attachments are NOT here: they ride projection (the
|
|
60
|
+
* equip system), which is the only path that also equips a widget arriving
|
|
61
|
+
* from a peer or a restored file.
|
|
62
|
+
*/
|
|
63
|
+
export declare function attachSpawnBehaviors(tx: GuardedTx, widget: WidgetType, e: Entity): void;
|
|
50
64
|
export declare function spawnWidget(store: DurableStore, world: World, type: string, opts: SpawnWidgetOpts): Entity;
|
|
@@ -10,6 +10,8 @@ export { createGrayboxReflector } from "./reflectors/graybox";
|
|
|
10
10
|
export { createDomWidgetsReflector, type DomWidgetsHost, type DomWidgetsReflector, } from "./reflectors/dom-widgets";
|
|
11
11
|
export { startRafLoop } from "./loop";
|
|
12
12
|
export { attachPointerAdapter, type GLRoute, type GLRouteVerdict, type PointerAdapterOpts } from "./pointer-adapter";
|
|
13
|
+
export { CLAIM_OWNS_ESCAPE, KEYBOARD_CLAIM_ATTR, isEditableTarget, keyboardClaimOf, wheelCede, type KeyboardClaim, } from "./input-ownership";
|
|
14
|
+
export { FOCUS_PROXY_ATTR, attachWidgetFocus, type FocusHostLookup, type WidgetFocusHandle, } from "./widget-focus";
|
|
13
15
|
export { createCursorReflector } from "./reflectors/cursor";
|
|
14
16
|
export { createRemoteCursorsReflector, type RemoteCursorsReflector } from "./reflectors/remote-cursors";
|
|
15
17
|
export { createChromeReflector } from "./reflectors/chrome";
|