hayao 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +123 -24
  2. package/bin/create-hayao.mjs +380 -0
  3. package/bin/hayao-mcp-cli.mjs +11 -0
  4. package/dist/app/browser.d.ts +65 -4
  5. package/dist/app/game.d.ts +59 -10
  6. package/dist/app/tuning.d.ts +68 -0
  7. package/dist/art/palette.d.ts +41 -0
  8. package/dist/audio/adaptive.d.ts +58 -0
  9. package/dist/audio/album.d.ts +16 -0
  10. package/dist/audio/analysis.d.ts +59 -0
  11. package/dist/audio/audio.d.ts +39 -1
  12. package/dist/audio/chord.d.ts +17 -0
  13. package/dist/audio/genres.d.ts +11 -0
  14. package/dist/audio/lint.d.ts +29 -0
  15. package/dist/audio/match.d.ts +38 -0
  16. package/dist/audio/music.d.ts +88 -0
  17. package/dist/audio/pcm.d.ts +54 -0
  18. package/dist/audio/quality.d.ts +28 -0
  19. package/dist/audio/reverb.d.ts +15 -0
  20. package/dist/audio/synth.d.ts +63 -0
  21. package/dist/audio/theory.d.ts +64 -0
  22. package/dist/audio/zzfx.d.ts +14 -0
  23. package/dist/content/campaign.d.ts +69 -0
  24. package/dist/content/generate.d.ts +78 -0
  25. package/dist/content/level.d.ts +93 -0
  26. package/dist/content/worldgraph.d.ts +73 -0
  27. package/dist/core/clock.d.ts +1 -1
  28. package/dist/core/dmath.d.ts +2 -0
  29. package/dist/core/projection.d.ts +36 -0
  30. package/dist/core/rng.d.ts +9 -0
  31. package/dist/hayao.global.js +200 -0
  32. package/dist/index.d.ts +39 -1
  33. package/dist/index.js +6558 -686
  34. package/dist/index.js.map +4 -4
  35. package/dist/index.min.js +200 -0
  36. package/dist/input/actions.d.ts +60 -6
  37. package/dist/input/gamepad.d.ts +101 -0
  38. package/dist/input/source.d.ts +133 -1
  39. package/dist/logic/coroutine.d.ts +68 -0
  40. package/dist/mcp.js +31225 -0
  41. package/dist/rasterize-worker-lite.mjs +13 -0
  42. package/dist/render/canvas.d.ts +6 -5
  43. package/dist/render/canvas2d-core.d.ts +9 -0
  44. package/dist/render/commands.d.ts +82 -2
  45. package/dist/render/paint.d.ts +41 -0
  46. package/dist/render/renderer.d.ts +47 -0
  47. package/dist/render/svg.d.ts +5 -1
  48. package/dist/render/svgString.d.ts +6 -2
  49. package/dist/render/webgl.d.ts +176 -0
  50. package/dist/scene/cameraController.d.ts +42 -0
  51. package/dist/scene/iso.d.ts +73 -0
  52. package/dist/scene/node.d.ts +98 -6
  53. package/dist/scene/nodes.d.ts +48 -0
  54. package/dist/scene/parallax.d.ts +15 -0
  55. package/dist/scene/particles.d.ts +19 -0
  56. package/dist/scene/verletChain.d.ts +76 -0
  57. package/dist/studio/mcpMain.d.ts +1 -0
  58. package/dist/studio/mcpServer.d.ts +2 -0
  59. package/dist/studio/record.d.ts +54 -0
  60. package/dist/studio/run.d.ts +78 -0
  61. package/dist/studio/session.d.ts +80 -0
  62. package/dist/studio/timeline.d.ts +35 -0
  63. package/dist/studio/vitePlugin.d.ts +6 -0
  64. package/dist/studio-plugin.js +228 -0
  65. package/dist/ui/overlay.d.ts +6 -0
  66. package/dist/ui/touch.d.ts +51 -0
  67. package/dist/verify/audioFilmstrip.d.ts +39 -0
  68. package/dist/verify/dom.d.ts +26 -0
  69. package/dist/verify/ethnography.d.ts +67 -0
  70. package/dist/verify/gates.d.ts +160 -0
  71. package/dist/verify/layout.d.ts +30 -3
  72. package/dist/verify/ramp.d.ts +40 -0
  73. package/dist/world.d.ts +109 -8
  74. package/dist-studio/assets/index-C7tty_Wo.js +109 -0
  75. package/dist-studio/assets/index-CM3tjRQo.css +1 -0
  76. package/dist-studio/index.html +18 -0
  77. package/docs/API.md +300 -23
  78. package/docs/CONVENTIONS.md +511 -0
  79. package/docs/EMBED.md +90 -0
  80. package/docs/QUICKSTART.md +141 -0
  81. package/docs/STUDIO.md +97 -0
  82. package/docs/VERIFICATION.md +256 -0
  83. package/package.json +40 -6
package/dist/world.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { Clock, type ClockConfig } from './core/clock';
2
2
  import { EventBus } from './core/events';
3
3
  import { Rng } from './core/rng';
4
- import { InputState } from './input/actions';
4
+ import { InputState, type AxisFrame } from './input/actions';
5
5
  import { Node, type WorldContext } from './scene/node';
6
6
  import type { Camera2D } from './scene/nodes';
7
- import { type Transform } from './core/math';
7
+ import { type Transform, type Vec2 } from './core/math';
8
8
  import type { DrawCommand } from './render/commands';
9
9
  export interface WorldConfig {
10
10
  seed?: number;
@@ -12,12 +12,20 @@ export interface WorldConfig {
12
12
  /** Design-space dimensions (default 1280×720). */
13
13
  width?: number;
14
14
  height?: number;
15
+ /** Resolved tuning values (see app/tuning.ts). Sim state: hashed + snapshotted. */
16
+ tuning?: Record<string, number | string>;
17
+ /**
18
+ * Dev guard: during each step(), `Math.random`/`Date.now` are wrapped so a
19
+ * stray call inside the sim warns ONCE (with a stack hint) instead of
20
+ * silently breaking determinism. Never throws; safe to leave on in tests.
21
+ */
22
+ guardDeterminism?: boolean;
15
23
  }
16
24
  /** Default engine event map; games extend it with their own keys. */
17
25
  export interface CoreEvents {
18
26
  [key: string]: unknown;
19
27
  }
20
- export declare class World implements WorldContext {
28
+ export declare class World<TState extends Record<string, unknown> = Record<string, unknown>> implements WorldContext {
21
29
  readonly rng: Rng;
22
30
  readonly clock: Clock;
23
31
  readonly input: InputState;
@@ -29,15 +37,45 @@ export declare class World implements WorldContext {
29
37
  * `hash()` and `snapshot()`, so hidden state here cannot escape determinism
30
38
  * checks the way ad-hoc module variables can.
31
39
  */
32
- state: Record<string, unknown>;
40
+ state: TState;
33
41
  readonly width: number;
34
42
  readonly height: number;
43
+ /**
44
+ * Pause switch. While true, only `pauseMode: 'always'` subtrees update —
45
+ * rendering, input sampling, and the clock keep ticking, so a pause menu
46
+ * (an 'always' subtree) stays live. Sim state: hashed + snapshotted, but
47
+ * only when true, so pinned hashes of unpaused games are unchanged.
48
+ */
49
+ paused: boolean;
50
+ /**
51
+ * Sim-time multiplier: the tree receives `clock.dt * timeScale` (slow-mo /
52
+ * fast-forward), while `'always'` subtrees get the unscaled dt so UI keeps
53
+ * realtime feel. The clock itself ticks normally. Hashed/snapshotted only
54
+ * when ≠ 1.
55
+ */
56
+ timeScale: number;
35
57
  root: Node;
36
58
  activeCamera: Camera2D | null;
37
59
  private seed;
38
60
  private freeQueue;
39
61
  private started;
62
+ private tuningValues;
63
+ private guardDeterminism;
64
+ private warnedClamp;
65
+ private warnedNondet;
40
66
  constructor(config?: WorldConfig);
67
+ /**
68
+ * Read a tuning value resolved at world creation (declared default unless
69
+ * overridden). Throws on an undeclared key — a typo here would otherwise
70
+ * silently read `undefined` into the sim.
71
+ */
72
+ tune<T extends number | string = number>(key: string): T;
73
+ /**
74
+ * Read a shared resource by key. Throws on a missing key (listing what IS
75
+ * available) — a typo here would otherwise silently read `undefined` into
76
+ * the sim, exactly like an undeclared tuning knob.
77
+ */
78
+ resource<T>(key: string): T;
41
79
  get time(): number;
42
80
  get frame(): number;
43
81
  /** Replace the scene root, entering the tree. */
@@ -48,12 +86,69 @@ export declare class World implements WorldContext {
48
86
  * Advance exactly one fixed step with the given actions held down.
49
87
  * This is THE deterministic transition — call it from Node or the browser loop.
50
88
  */
51
- step(actionsDown?: Iterable<string>): void;
52
- /** Feed real elapsed ms; runs 0+ fixed steps. Returns steps run. */
53
- advance(realMs: number, actionsDown?: Iterable<string>): number;
54
- private flushFree;
89
+ step(actionsDown?: Iterable<string>, axes?: AxisFrame): void;
90
+ /**
91
+ * Wrap `Math.random`/`Date.now` for the duration of a step so a stray call
92
+ * inside the sim warns ONCE per world (with a stack hint) — the values still
93
+ * flow through, so nothing breaks mid-frame. Returns the restore function;
94
+ * properly nested re-entry (a world stepped inside another's step) is safe
95
+ * because each install restores exactly what it replaced.
96
+ */
97
+ private installGuard;
98
+ /**
99
+ * Feed REAL elapsed ms; runs 0+ fixed steps. Returns steps run. This is the
100
+ * realtime driver entry point — it CLAMPS realMs to the clock's maxFrameMs
101
+ * (default 250) to avoid a spiral of death, so `advance(1200)` runs ~15 steps,
102
+ * not 72. For headless tests/harnesses that want to fast-forward an exact
103
+ * number of steps, use `runSteps(n)` or `step()` — never `advance` with a big ms.
104
+ */
105
+ advance(realMs: number, actionsDown?: Iterable<string>, axes?: AxisFrame): number;
106
+ /**
107
+ * Run exactly `n` fixed steps — the deterministic fast-forward for tests and
108
+ * headless drivers (unlike `advance`, no realtime clamp). Pass `actionsFor(i)`
109
+ * to script the input per step; omit it to hold nothing down.
110
+ */
111
+ runSteps(n: number, actionsFor?: (i: number) => Iterable<string>, axesFor?: (i: number) => AxisFrame | undefined): void;
112
+ /**
113
+ * Run pending frees NOW instead of at the end of the step. `free()` is
114
+ * deferred (safe during iteration), which means freed nodes survive until
115
+ * the step ends — during a scene swap that lets old nodes contaminate the
116
+ * first frame of the new scene. Pattern: `oldRoot.free(); world.flushFree();
117
+ * buildNewScene()`. Called automatically at the end of every step.
118
+ */
119
+ flushFree(): void;
120
+ /** Visit every live node depth-first (root first, child-index order). */
121
+ walk(fn: (node: Node) => void): void;
122
+ /** Total live nodes in the tree (root included). */
123
+ get nodeCount(): number;
124
+ /**
125
+ * One indented line per node — `name (type) [flags] @x,y` — for quick tree
126
+ * audits in a REPL or test failure message.
127
+ */
128
+ debugTree(): string;
129
+ /** The active camera's world position + zoom, or null (see WorldContext.camera). */
130
+ camera(): {
131
+ pos: {
132
+ x: number;
133
+ y: number;
134
+ };
135
+ zoom: number;
136
+ } | null;
55
137
  /** The view transform (inverse of the active camera), mapping world → screen. */
56
138
  viewTransform(): Transform;
139
+ /**
140
+ * Map a world-space point to screen/design space (the forward view transform).
141
+ * With no active camera this is the identity, so world == screen.
142
+ */
143
+ worldToScreen(p: Vec2): Vec2;
144
+ /**
145
+ * Map a screen/design-space point back to world space — the inverse of the
146
+ * view transform. Use this to turn a pointer position (in design units) into
147
+ * a world coordinate under a scrolled/zoomed camera. Keep raw pointer values
148
+ * OUT of the sim: convert at the host edge and feed the result in as a
149
+ * quantized action/axis, or determinism breaks (see docs/CONVENTIONS.md).
150
+ */
151
+ screenToWorld(p: Vec2): Vec2;
57
152
  /** Project the whole scene to a display list (already camera-applied). */
58
153
  render(): DrawCommand[];
59
154
  /** Deterministic structural hash of the whole sim state. */
@@ -72,4 +167,10 @@ export interface WorldSnapshot {
72
167
  input: ReturnType<InputState['getState']>;
73
168
  state: Record<string, unknown>;
74
169
  tree: ReturnType<Node['serialize']>;
170
+ /** Resolved tuning values (absent in pre-tuning saves). */
171
+ tuning?: Record<string, number | string>;
172
+ /** Pause flag (absent when false — keeps old snapshots byte-identical). */
173
+ paused?: boolean;
174
+ /** Sim-time multiplier (absent when 1). */
175
+ timeScale?: number;
75
176
  }