hayao 0.2.0 → 0.3.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 (69) hide show
  1. package/README.md +113 -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 +33 -2
  5. package/dist/app/game.d.ts +47 -2
  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 +21 -0
  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 +56 -0
  21. package/dist/audio/theory.d.ts +64 -0
  22. package/dist/content/campaign.d.ts +69 -0
  23. package/dist/content/generate.d.ts +78 -0
  24. package/dist/content/level.d.ts +93 -0
  25. package/dist/content/worldgraph.d.ts +73 -0
  26. package/dist/core/dmath.d.ts +2 -0
  27. package/dist/hayao.global.js +15 -0
  28. package/dist/index.d.ts +30 -1
  29. package/dist/index.js +4293 -434
  30. package/dist/index.js.map +4 -4
  31. package/dist/index.min.js +15 -0
  32. package/dist/input/source.d.ts +52 -1
  33. package/dist/mcp.js +31225 -0
  34. package/dist/rasterize-worker-lite.mjs +13 -0
  35. package/dist/render/canvas.d.ts +6 -1
  36. package/dist/render/commands.d.ts +46 -0
  37. package/dist/render/paint.d.ts +33 -0
  38. package/dist/render/renderer.d.ts +22 -0
  39. package/dist/render/svg.d.ts +4 -1
  40. package/dist/render/svgString.d.ts +6 -2
  41. package/dist/scene/cameraController.d.ts +42 -0
  42. package/dist/scene/node.d.ts +17 -4
  43. package/dist/scene/nodes.d.ts +14 -0
  44. package/dist/scene/parallax.d.ts +15 -0
  45. package/dist/studio/mcpMain.d.ts +1 -0
  46. package/dist/studio/mcpServer.d.ts +2 -0
  47. package/dist/studio/record.d.ts +54 -0
  48. package/dist/studio/run.d.ts +78 -0
  49. package/dist/studio/session.d.ts +80 -0
  50. package/dist/studio/timeline.d.ts +35 -0
  51. package/dist/studio/vitePlugin.d.ts +6 -0
  52. package/dist/studio-plugin.js +228 -0
  53. package/dist/ui/overlay.d.ts +6 -0
  54. package/dist/verify/audioFilmstrip.d.ts +39 -0
  55. package/dist/verify/ethnography.d.ts +67 -0
  56. package/dist/verify/gates.d.ts +160 -0
  57. package/dist/verify/layout.d.ts +30 -3
  58. package/dist/verify/ramp.d.ts +40 -0
  59. package/dist/world.d.ts +38 -2
  60. package/dist-studio/assets/index-C7tty_Wo.js +109 -0
  61. package/dist-studio/assets/index-CM3tjRQo.css +1 -0
  62. package/dist-studio/index.html +18 -0
  63. package/docs/API.md +233 -9
  64. package/docs/CONVENTIONS.md +223 -0
  65. package/docs/EMBED.md +85 -0
  66. package/docs/QUICKSTART.md +129 -0
  67. package/docs/STUDIO.md +97 -0
  68. package/docs/VERIFICATION.md +226 -0
  69. package/package.json +39 -6
@@ -0,0 +1 @@
1
+ :root{--washi: #f1ebdd;--washi-2: #f8f3e9;--sumi: #242019;--sumi-soft: #4f473b;--stone: #6f6555;--ai: #2b4257;--shu: #b5442d;--matsu: #4a7a3a;--line: #ddd3bf;--mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;color-scheme:light}*{box-sizing:border-box}html,body{margin:0;height:100%;background:var(--washi);color:var(--sumi);font-family:Iowan Old Style,Palatino,Georgia,serif;overscroll-behavior:none}#root{height:100%;display:flex;flex-direction:column}header.bar{display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--line);background:var(--washi-2);flex-wrap:wrap}header.bar .brand{font-weight:700;font-size:17px;color:var(--sumi);text-decoration:none;white-space:nowrap}header.bar .brand .js{font-size:11px;color:var(--stone)}header.bar select,header.bar input[type=number]{font:13px var(--mono);padding:6px 8px;border:1px solid var(--line);border-radius:6px;background:var(--washi);color:var(--sumi);max-width:44vw}header.bar .spacer{flex:1}header.bar .build{font:11px var(--mono);color:var(--stone)}main.panes{flex:1;display:flex;min-height:0}.pane{flex:1;min-width:0;display:flex;flex-direction:column;border-right:1px solid var(--line)}.pane:last-child{border-right:none}.pane .pane-head{display:flex;align-items:center;gap:8px;padding:6px 10px;font:12px var(--mono);color:var(--sumi-soft);background:var(--washi-2);border-bottom:1px solid var(--line)}.pane iframe{flex:1;width:100%;border:0;background:#fff}.drawer{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1200;background:#24201959;display:flex;justify-content:flex-end}.drawer>div,.drawer-inner{background:var(--washi)}.drawer-head{display:flex;align-items:center;gap:12px;padding:12px 16px;border-bottom:1px solid var(--line);background:var(--washi-2)}.drawer-head b{font-size:16px}.drawer-head .hy{margin-left:auto}.drawer .drawer-head,.drawer .drawer-body{width:min(520px,100vw)}.drawer{flex-direction:column;align-items:flex-end}.drawer-body{flex:1;overflow-y:auto;background:var(--washi);border-left:1px solid var(--line);padding-bottom:40px}.session-row{display:grid;grid-template-columns:1fr auto;gap:2px 10px;width:100%;text-align:left;padding:11px 16px;background:none;border:none;border-bottom:1px solid var(--line);font:inherit;color:var(--sumi);cursor:pointer}.session-row .game{font-weight:600}.session-row .when{grid-row:1 / 3;grid-column:2;align-self:center}.session-row.open{background:var(--washi-2)}.report{padding:10px 16px 16px;border-bottom:1px solid var(--line);background:var(--washi-2);font-size:14.5px}.report p{margin:7px 0;line-height:1.55}.report .stat-row{display:flex;flex-wrap:wrap;gap:6px 16px;font:600 13px var(--mono);margin:6px 0 10px}.report .good{color:var(--matsu)}.report .warn{color:var(--shu)}.report .moment{padding:5px 10px}.moment-link{background:none;border:none;border-bottom:1px dashed var(--ai);color:var(--ai);font:inherit;cursor:pointer;padding:0 2px;margin-right:8px}.phone-card{margin:auto;background:var(--washi);border:1px solid var(--line);border-radius:12px;padding:22px 26px;display:grid;gap:12px;justify-items:center;max-width:min(340px,92vw);text-align:center}.phone-card b{font-size:17px}.phone-card img{border:1px solid var(--line);border-radius:8px}.phone-card code{font:12.5px var(--mono);color:var(--ai);word-break:break-all}label.hy input[type=file]{display:none}.pane-head .tape{color:var(--shu);font-weight:700}.pane-head .hy{padding:3px 9px;font-size:11px}.timeline{display:flex;gap:10px;align-items:center;padding:8px 14px;border-top:1px solid var(--line);background:var(--washi-2);position:relative}.timeline input[type=range]{flex:1;accent-color:var(--shu);touch-action:none;min-height:28px}.timeline .frames{min-width:86px;text-align:right;font-variant-numeric:tabular-nums}.timeline .probe{position:absolute;right:10px;bottom:100%;margin:0 0 8px;max-height:46vh;max-width:min(420px,92vw);overflow:auto;background:var(--washi-2);border:1px solid var(--line);border-radius:8px;padding:10px 12px;font:11.5px var(--mono);color:var(--sumi-soft);box-shadow:0 6px 24px #2420191f}.actions{display:flex;gap:8px;padding:10px 14px;border-top:1px solid var(--line);background:var(--washi-2);flex-wrap:wrap;align-items:center}button.hy{font:600 13px var(--mono);padding:9px 14px;border-radius:8px;border:1px solid var(--line);background:var(--washi);color:var(--sumi);cursor:pointer;touch-action:manipulation}button.hy:active{transform:translateY(1px)}button.hy.feel{border-color:var(--shu);color:var(--shu)}button.hy.accept{border-color:var(--matsu);color:var(--matsu)}.note{font:11px var(--mono);color:var(--stone)}.toast{position:fixed;left:50%;bottom:86px;transform:translate(-50%);background:var(--sumi);color:var(--washi);font:12px var(--mono);padding:8px 14px;border-radius:8px;z-index:60;pointer-events:none}@media(max-width:720px){main.panes{flex-direction:column}.pane{border-right:none;border-bottom:1px solid var(--line)}header.bar .build{display:none}}
@@ -0,0 +1,18 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Studio · hayao.js</title>
7
+ <meta name="description" content="Hayao Studio — playtest, tune, annotate, and A/B games with an AI co-developer." />
8
+ <link
9
+ rel="icon"
10
+ href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 120'%3E%3Crect width='120' height='120' fill='%23242019'/%3E%3Crect x='32' y='30' width='58' height='58' fill='none' stroke='%23f1ebdd' stroke-width='3' opacity='.4'/%3E%3Ccircle cx='61' cy='59' r='14' fill='%23b5442d'/%3E%3C/svg%3E"
11
+ />
12
+ <script type="module" crossorigin src="./assets/index-C7tty_Wo.js"></script>
13
+ <link rel="stylesheet" crossorigin href="./assets/index-CM3tjRQo.css">
14
+ </head>
15
+ <body>
16
+ <div id="root"></div>
17
+ </body>
18
+ </html>
package/docs/API.md CHANGED
@@ -3,9 +3,9 @@
3
3
  > Auto-generated by `npm run api`. Everything importable from `@hayao`.
4
4
  > Grep here for the real surface — never guess an API from memory.
5
5
 
6
- **440 exports.**
6
+ **664 exports.**
7
7
 
8
- ## classs (47)
8
+ ## classs (52)
9
9
 
10
10
  - `AmbientField`
11
11
  - `AnimationPlayer`
@@ -13,6 +13,7 @@
13
13
  - `BitmapText`
14
14
  - `BroadcastChannelTransport`
15
15
  - `Camera2D`
16
+ - `CameraController`
16
17
  - `Canvas2DRenderer`
17
18
  - `CinematicPlayer`
18
19
  - `Clock`
@@ -33,19 +34,23 @@
33
34
  - `Node`
34
35
  - `NodePool`
35
36
  - `NullStorage`
37
+ - `ParallaxLayer`
36
38
  - `Particles`
37
39
  - `PhaseClock`
38
40
  - `PixelBuffer`
39
41
  - `PlayerInput`
42
+ - `PointerSource`
40
43
  - `RingBuffer`
41
44
  - `Rng`
42
45
  - `RollbackSession`
43
46
  - `RoomHost`
44
47
  - `SaveManager`
45
48
  - `ScreenTransition`
49
+ - `SessionRecorder`
46
50
  - `Shaker`
47
51
  - `Shell`
48
52
  - `Signal`
53
+ - `SnapshotRing`
49
54
  - `SpatialHash`
50
55
  - `Sprite`
51
56
  - `SvgRenderer`
@@ -55,16 +60,22 @@
55
60
  - `UndoStack`
56
61
  - `World`
57
62
 
58
- ## functions (185)
63
+ ## functions (291)
59
64
 
65
+ - `abilitiesOf`: (world: WorldGraphDef, taken: readonly string[]) => Set<string>
60
66
  - `addBody`: (rw: RigidWorld, def: RigidBodyDef) => number
61
67
  - `addDistanceJoint`: (rw: RigidWorld, def: DistanceJointDef) => number
62
68
  - `addRevoluteJoint`: (rw: RigidWorld, def: RevoluteJointDef) => number
63
69
  - `addTransition`: (parent: Node, config?: TransitionConfig) => ScreenTransition
70
+ - `albumTrack`: (id: string) => AlbumTrack | undefined
71
+ - `analyzePlaytest`: (def: GameDefinition, session: PlaytestSession, opts?: AnalyzeOptions) => PlaytestReport
64
72
  - `applyImpulse`: (rw: RigidWorld, id: number, ix: number, iy: number, px?: number | undefined, py?: number | undefined) => void
73
+ - `applyReverb`: (buf: StereoBuffer, opts?: ReverbOptions) => void
65
74
  - `applyTransform`: (m: Transform, p: Vec2) => Vec2
66
75
  - `asciiEntities`: (rowsAscii: string[], tileSize?: number, chars?: Record<string, TileId>) => { char: string; tx: number; ty: number; x: number; y: number; }[]
76
+ - `assertAudio`: (buf: StereoBuffer, exp: AudioExpectation) => AudioAssertion
67
77
  - `assertDeterministic`: (makeWorld: WorldFactory, log: InputLog) => DeterminismReport
78
+ - `assertRamp`: (difficulty: readonly number[], opts?: RampOptions) => void
68
79
  - `assertSnapshotStable`: (makeWorld: WorldFactory, log: InputLog, warmup: number) => { ok: boolean; hashA: string; hashB: string; }
69
80
  - `assertSolvable`: <State, Move>(puzzle: Puzzle<State, Move>, options?: SolveOptions) => SolveResult<Move>
70
81
  - `astar`: <N>(start: N, isGoal: (n: N) => boolean, neighbours: WeightedNeighbours<N>, key: NodeKey<N>, opts?: { heuristic?: ((n: N) => number) | undefined; maxNodes?: …
@@ -72,28 +83,40 @@
72
83
  - `autotile4`: (grid: BoolGrid) => (WangTile | null)[][]
73
84
  - `autotileToCommands`: (grid: BoolGrid, options?: AutotileDrawOptions) => (RectCommand | PolyCommand)[]
74
85
  - `availableUpgrades`: (defs: readonly UpgradeDef[], owned: readonly string[]) => UpgradeDef[]
86
+ - `bandBalance`: (sig: Samples, sampleRate?: number) => BandBalance
75
87
  - `bfs`: <N>(start: N, neighbours: Neighbours<N>, key: NodeKey<N>, opts?: { goal?: ((n: N) => boolean) | undefined; maxNodes?: number | undefined; }) => BfsResult<N>
76
88
  - `blobPath`: (rng: Rng, radius: number, wobble?: number, lobes?: number) => string
77
89
  - `bodyAABB`: (b: RigidBody) => Rect
78
90
  - `bodyContains`: (b: RigidBody, x: number, y: number) => boolean
91
+ - `cadenceResolves`: (romans: string[]) => boolean
92
+ - `cameraIssues`: (samples: readonly Vec2[], opts?: CameraOptions) => string[]
93
+ - `canvasGradient`: (ctx: { createLinearGradient(x0: number, y0: number, x1: number, y1: number): CanvasGradient; createRadialGradient(x0: number, y0: number, r0: number, x1: nu…
79
94
  - `cellFloat`: (x: number, y: number, seed?: number) => number
80
95
  - `cellHash`: (x: number, y: number, seed?: number) => number
81
96
  - `cellInt`: (x: number, y: number, n: number, seed?: number) => number
82
97
  - `changeFrames`: (timeline: ProbeFrame[], key: string) => number[]
83
98
  - `checkDeterministic`: (makeWorld: WorldFactory, log: InputLog) => DeterminismReport
99
+ - `chordChanges`: (symbols: string[], octave?: number) => number[][]
100
+ - `chordNotes`: (symbol: string, octave?: number) => number[]
101
+ - `clientToDesign`: (rect: { left: number; top: number; width: number; height: number; }, width: number, height: number, clientX: number, clientY: number) => Vec2
84
102
  - `collide`: (a: RigidBody, b: RigidBody) => Manifold | null
85
- - `commandsToSVGInner`: (commands: DrawCommand[]) => string
103
+ - `commandsToSVGInner`: (commands: DrawCommand[], idPrefix?: string) => string
104
+ - `composeCampaign`: <State, Move>(spec: CampaignSpec<State, Move>) => Campaign<State, Move>
86
105
  - `composeTransform`: (m: Transform, n: Transform) => Transform
87
106
  - `connectedComponents`: (cols: number, rows: number, passable: Passable, diagonal?: boolean) => Components
88
107
  - `connectWebSocket`: (url: string) => Promise<Transport>
89
108
  - `contourToCommands`: (grid: BoolGrid, options?: AutotileDrawOptions) => PolyCommand[]
109
+ - `contrastRatio`: (a: string, b: string) => number
90
110
  - `createPlanBot`: <Step extends { kind: string; }, Probe>(plan: Step[], execs: Record<string, StepExec<Step, Probe>>) => PlanBot<Probe>
91
111
  - `createPlatformerState`: (x: number, y: number) => PlatformerState
92
112
  - `createRigidWorld`: (opts?: RigidWorldOpts) => RigidWorld
93
- - `createWorld`: (def: GameDefinition, seedOverride?: number | undefined) => World
113
+ - `createStereo`: (durationSec: number, sampleRate?: number) => StereoBuffer
114
+ - `createWorld`: (def: GameDefinition, opts?: number | CreateWorldOptions | undefined) => World
115
+ - `crestFactorDb`: (sig: Samples) => number
94
116
  - `dashJumpDistance`: (cfg?: PlatformerConfig) => number
95
117
  - `datan`: (x: number) => number
96
118
  - `datan2`: (y: number, x: number) => number
119
+ - `dbfs`: (amp: number) => number
97
120
  - `dcos`: (x: number) => number
98
121
  - `decode2bit`: (source: string | bigint, width: number, height: number) => PixelBuffer
99
122
  - `decodeBits`: (source: string | bigint, width: number, height: number) => PixelBuffer
@@ -101,25 +124,48 @@
101
124
  - `decodeRLE`: (runs: readonly number[], width: number, height: number) => PixelBuffer
102
125
  - `defaultStorage`: (prefix?: string | undefined) => StorageAdapter
103
126
  - `defineGame`: (def: GameDefinition) => Required<Pick<GameDefinition, "seed" | "width" | "height" | "inputMap" | "background">> & GameDefinition
127
+ - `defineLevel`: (spec: LevelSpec) => LevelData
104
128
  - `deserializeNode`: (data: SerializedNode) => Node
105
129
  - `dexp`: (x: number) => number
106
130
  - `dexp2`: (x: number) => number
107
131
  - `dhypot`: (x: number, y: number) => number
132
+ - `diatonicChord`: (tonic: number, mode: "major" | "minor" | "harmonicMinor" | "melodicMinor" | "dorian" | "phrygian" | "lydian" | "mixolydian" | "locrian" | "majorPentatonic" …
133
+ - `diffLevels`: (a: LevelData, b: LevelData) => LevelChange[]
134
+ - `distanceGain`: (model: DistanceModel, distance: number, refDistance?: number, maxDistance?: number, rolloff?: number) => number
108
135
  - `dlog`: (x: number) => number
136
+ - `dpow`: (base: number, exp: number) => number
109
137
  - `drive`: (world: World, script: InputScript, until?: ((probe: Record<string, unknown>) => boolean) | undefined) => DriveResult
138
+ - `dropShadow`: (color: string, blur: number, dx?: number, dy?: number) => Shadow
110
139
  - `dsin`: (x: number) => number
140
+ - `duckGain`: (active: boolean, amountDb?: number) => number
111
141
  - `encodeMessage`: (msg: NetMessage) => string
112
142
  - `encodeRLE`: (buf: PixelBuffer) => number[]
143
+ - `encodeWav`: (buf: StereoBuffer) => Uint8Array<ArrayBufferLike>
144
+ - `estimateTempo`: (sig: Samples, sampleRate?: number) => number
145
+ - `evalCurve`: (curve: Breakpoint[], x: number) => number
146
+ - `featureDistance`: (reference: AudioFeatures, candidate: AudioFeatures, weights?: Partial<FeatureWeights>) => MatchResult
147
+ - `features`: (sig: Samples, sampleRate?: number) => AudioFeatures
148
+ - `feedbackIssues`: (contract: FeedbackContract, requiredEvents: readonly string[], opts?: FeedbackOptions) => string[]
149
+ - `fft`: (re: Float32Array<ArrayBufferLike>, im: Float32Array<ArrayBufferLike>) => void
150
+ - `findSoftlocks`: (world: WorldGraphDef, mode?: CompletionMode) => SoftlockReport
113
151
  - `firstFrame`: (timeline: ProbeFrame[], pred: (p: ProbeFrame) => boolean) => number
114
152
  - `floodFill`: (start: Cell, passable: Passable, opts: { cols: number; rows: number; diagonal?: boolean | undefined; }) => Cell[]
153
+ - `fluxEnvelope`: (sig: Samples, frameSize?: number, hop?: number) => Float32Array<ArrayBufferLike>
154
+ - `forgivenessIssues`: (spec: ForgivenessSpec, opts?: ForgivenessOptions) => string[]
115
155
  - `fractalNoise`: (x: number, y: number, seed?: number, opts?: FractalOptions) => number
116
156
  - `frameActions`: (log: InputLog, i: number) => string[]
117
157
  - `gameInputMap`: (def: GameDefinition) => InputMap
118
158
  - `generateCave`: (rng: Rng, opts: CaveOptions) => Grid
119
159
  - `generateDungeon`: (rng: Rng, opts: DungeonOptions) => Dungeon
160
+ - `generateLevels`: <State, Move>(factory: (rng: Rng) => Puzzle<State, Move>, opts: GenerateOptions<State, Move>) => GeneratedLevel<State, Move>[]
161
+ - `generateLevelsReport`: <State, Move>(factory: (rng: Rng) => Puzzle<State, Move>, opts: GenerateOptions<State, Move>) => GenerateReport<State, Move>
162
+ - `genre`: (id: string) => GenreTrack | undefined
120
163
  - `getBody`: (rw: RigidWorld, id: number) => RigidBody | undefined
121
164
  - `getJoint`: (rw: RigidWorld, id: number) => Joint | undefined
165
+ - `glow`: (color: string, blur: number) => Shadow
166
+ - `graceWindowIssues`: (label: string, windowFrames: number, accepts: (delayFrames: number) => boolean) => string[]
122
167
  - `gradient`: (stops: readonly string[], n: number) => string[]
168
+ - `gradientDef`: (g: Gradient, id: string) => string
123
169
  - `gridAt`: (g: Grid, x: number, y: number) => number
124
170
  - `gridFromRows`: (rows: readonly string[], solid?: string) => boolean[][]
125
171
  - `gridSet`: (g: Grid, x: number, y: number, v: number) => void
@@ -147,10 +193,19 @@
147
193
  - `jumpHeight`: (cfg?: PlatformerConfig) => number
148
194
  - `keyMentions`: (code: string) => string[]
149
195
  - `keysToActions`: (map: InputMap, keysDown: Set<string>) => string[]
196
+ - `layerGains`: (layers: MusicLayer[], intensity: number) => Record<string, number>
150
197
  - `layoutIssues`: (commands: DrawCommand[], opts?: LayoutOptions) => string[]
151
198
  - `layoutText`: (font: BitmapFont, input: string | readonly RichChar[], options?: TextLayoutOptions) => TextLayout
199
+ - `levelFromSeed`: <State, Move>(factory: (rng: Rng) => Puzzle<State, Move>, seed: number) => Puzzle<State, Move>
200
+ - `levelIssues`: (data: LevelData) => string[]
201
+ - `levelReachable`: (data: LevelData, opts?: { passable?: Passable | undefined; diagonal?: boolean | undefined; }) => ReachReport
202
+ - `levelToTilemap`: (data: LevelData) => TilemapData
203
+ - `linearGradient`: (stops: readonly StopInput[], angleDeg?: number) => LinearGradient
152
204
  - `lineOfSight`: (map: TilemapData, ax: number, ay: number, bx: number, by: number) => boolean
205
+ - `lintSong`: (song: Song, opts?: LintOptions) => MusicLintResult
153
206
  - `longestLull`: (eventFrames: number[], totalFrames: number) => number
207
+ - `lookAheadIssues`: (cameraSamples: readonly Vec2[], targetSamples: readonly Vec2[], minLead?: number) => string[]
208
+ - `magnitudeSpectrum`: (frame: Samples) => Float32Array<ArrayBufferLike>
154
209
  - `makeGrid`: (cols: number, rows: number, fill?: number) => Grid
155
210
  - `makeReach`: (start?: number, settle?: number) => (target: number, dt: number) => number
156
211
  - `makeTransform`: (pos: Vec2, rotation: number, scale: Vec2) => Transform
@@ -158,29 +213,51 @@
158
213
  - `marchingSquaresContours`: (grid: BoolGrid, options?: ContourOptions) => ContourSegment[]
159
214
  - `mask4`: (grid: BoolGrid, x: number, y: number) => number
160
215
  - `mask8`: (grid: BoolGrid, x: number, y: number) => number
216
+ - `matchReport`: (reference: AudioFeatures, candidate: AudioFeatures) => string
161
217
  - `measureLine`: (font: BitmapFont, chars: readonly RichChar[]) => number
162
218
  - `measureText`: (font: BitmapFont, text: string) => number
163
219
  - `mergePlayerFrames`: (players: readonly string[], inputs: ReadonlyMap<string, readonly string[]>) => string[]
220
+ - `midiToFreq`: (midi: number, a4?: number) => number
221
+ - `midiToName`: (midi: number) => string
164
222
  - `missingControlHints`: (world: World, inputMap: InputMap) => string[]
165
223
  - `mix`: (a: string, b: string, t: number) => string
166
224
  - `mixLinear`: (a: string, b: string, t: number) => string
225
+ - `mixMono`: (bus: StereoBuffer, sig: Samples, startSample: number, gain?: number, pan?: number) => void
167
226
  - `moveRect`: (map: TilemapData, rect: Rect, dx: number, dy: number, opts?: MoveOpts) => MoveResult
168
227
  - `mutateColor`: (rng: Rng, hex: string, amounts?: DriftAmounts) => string
169
228
  - `netMessage`: <T extends Omit<NetMessage, "v">>(msg: T) => T & { v: number; }
170
229
  - `nineSlice`: (rect: Rect, style: NineSliceStyle, z?: number, transform?: Transform) => DrawCommand[]
230
+ - `normalize`: (buf: StereoBuffer, target?: number) => void
231
+ - `noteToMidi`: (name: string) => number
232
+ - `onsetDensity`: (sig: Samples, sampleRate?: number) => number
233
+ - `openVoicing`: (chord: number[]) => number[]
171
234
  - `packVarints`: (nums: readonly number[]) => string
235
+ - `panFromOffset`: (dx: number, spread?: number) => number
236
+ - `panGains`: (pan: number) => { l: number; r: number; }
172
237
  - `parseRich`: (markup: string, colorMap?: Record<string, string>) => RichChar[]
173
238
  - `parseSnapshot`: (text: string | null) => WorldSnapshot | null
174
239
  - `passableFromTilemap`: (map: TilemapData) => Passable
240
+ - `peak`: (buf: StereoBuffer) => number
241
+ - `peakAmp`: (sig: Samples) => number
175
242
  - `pickEntry`: <T>(rng: Rng, entries: readonly WeightedEntry<T>[]) => T
243
+ - `pitchToFreq`: (pitch: string | number, a4?: number) => number
176
244
  - `pixelsToCommands`: (buf: PixelBuffer, palette: readonly Swatch[], options?: PixelDrawOptions) => RectCommand[]
245
+ - `platformerReachable`: (data: LevelData, opts: PlatformerReachOptions) => ReachReport
177
246
  - `playerIds`: (count: number) => string[]
178
247
  - `pointQuery`: (rw: RigidWorld, x: number, y: number, mask?: number) => RigidBody | undefined
179
248
  - `pollDirector`: (waves: readonly WaveDef[], state: DirectorState, time: number, rng?: Rng | undefined) => SpawnEvent[]
180
249
  - `polygonBox`: (w: number, h: number) => RigidShape
250
+ - `progression`: (tonic: number, mode: "major" | "minor" | "harmonicMinor" | "melodicMinor" | "dorian" | "phrygian" | "lydian" | "mixolydian" | "locrian" | "majorPentatonic" …
251
+ - `progressionPuzzle`: (world: WorldGraphDef, mode?: CompletionMode) => Puzzle<ProgressState, ProgressMove>
252
+ - `proveCompletable`: (world: WorldGraphDef) => SolveResult<ProgressMove>
253
+ - `proveFullCompletion`: (world: WorldGraphDef) => SolveResult<ProgressMove>
181
254
  - `pump`: (world: World, frames: number, actions?: string[]) => void
255
+ - `radialGradient`: (stops: readonly StopInput[], opts?: { cx?: number | undefined; cy?: number | undefined; r?: number | undefined; }) => RadialGradient
256
+ - `rampIssues`: (difficulty: readonly number[], opts?: RampOptions) => string[]
257
+ - `rampStats`: (difficulty: readonly number[]) => RampStats
182
258
  - `rayCastRigid`: (rw: RigidWorld, x0: number, y0: number, x1: number, y1: number, mask?: number) => RigidRayHit | null
183
259
  - `raycastTiles`: (map: TilemapData, x0: number, y0: number, x1: number, y1: number) => RayHit
260
+ - `reachableRegions`: (world: WorldGraphDef, abilities: Iterable<string>) => string[]
184
261
  - `reconstructPath`: <N>(cameFrom: Map<string, N>, key: NodeKey<N>, start: N, goal: N) => N[]
185
262
  - `recordTimeline`: (world: World, frames: string[][]) => ProbeFrame[]
186
263
  - `rectBlocked`: (map: TilemapData, x: number, y: number, w: number, h: number, solids?: SolidRect[]) => boolean
@@ -188,39 +265,69 @@
188
265
  - `rectsOverlap`: (a: Rect, b: Rect) => boolean
189
266
  - `registerNode`: (type: string, factory: NodeFactory) => void
190
267
  - `regularPolygon`: (sides: number, radius: number, rotation?: number) => number[]
268
+ - `relLuminance`: (hex: string) => number
191
269
  - `removeBody`: (rw: RigidWorld, id: number) => void
192
270
  - `removeJoint`: (rw: RigidWorld, id: number) => void
271
+ - `renderAudioFilmstrip`: (buf: StereoBuffer, opts?: AudioFilmstripOptions) => string
193
272
  - `renderFilmstrip`: (world: World, frames: string[][], opts: FilmstripOptions) => string
273
+ - `renderSong`: (song: Song, opts?: { sampleRate?: number | undefined; normalizePeak?: number | undefined; }) => StereoBuffer
274
+ - `renderSound`: (spec: SoundSpec, opts?: { rng?: Rng | undefined; sampleRate?: number | undefined; }) => Samples
194
275
  - `renderToSVGString`: (commands: DrawCommand[], width: number, height: number, background?: string) => string
195
276
  - `replay`: (makeWorld: WorldFactory, log: InputLog) => { finalHash: string; hashes: string[]; }
277
+ - `replaySession`: (def: GameDefinition, session: PlaytestSession, opts?: number | ReplayOptions | undefined) => World
196
278
  - `resetNodeIds`: (start?: number) => void
279
+ - `resolveTuning`: (spec: TuningSpec | undefined, overrides?: TuningValues | undefined) => TuningValues
197
280
  - `rigidStep`: (rw: RigidWorld, dt: number) => ContactEvent[]
198
281
  - `rleDecode`: (input: string) => string
199
282
  - `rleEncode`: (input: string) => string
283
+ - `rms`: (sig: Samples) => number
200
284
  - `roomCenter`: (r: Room) => { x: number; y: number; }
285
+ - `rootless`: (chord: number[], targetMidi?: number | undefined) => number[]
201
286
  - `runBrowser`: (def: GameDefinition, mount: HTMLElement, opts?: RunOptions) => GameHandle
202
287
  - `runBrowserNet`: (def: GameDefinition, mount: HTMLElement, opts: NetRunOptions) => NetGameHandle
288
+ - `runFeelGates`: (spec: FeelSpec, ctx?: FeelContext) => FeelReport
203
289
  - `runHeadless`: (def: GameDefinition, inputLog?: InputLog | undefined) => HeadlessResult
290
+ - `runStudio`: (baseDef: GameDefinition, mount: HTMLElement, opts?: StudioOptions) => StudioHandle
291
+ - `salienceIssues`: (commands: DrawCommand[], avatarFill: string, background: string, opts?: SalienceOptions) => string[]
204
292
  - `sampleGradient`: (stops: readonly string[], t: number) => string
293
+ - `scaleMidis`: (tonic: number, mode?: "major" | "minor" | "harmonicMinor" | "melodicMinor" | "dorian" | "phrygian" | "lydian" | "mixolydian" | "locrian" | "majorPentatonic"…
294
+ - `scalePitchClasses`: (tonic: number, mode?: "major" | "minor" | "harmonicMinor" | "melodicMinor" | "dorian" | "phrygian" | "lydian" | "mixolydian" | "locrian" | "majorPentatonic"…
205
295
  - `scatter`: (x: number, y: number, probability: number, seed?: number) => boolean
206
296
  - `scatterCells`: (x0: number, y0: number, cols: number, rows: number, probability: number, seed?: number) => { x: number; y: number; }[]
297
+ - `scoreTrack`: (buf: StereoBuffer, profile: GenreProfile) => QualityScore
207
298
  - `scriptedPlaythrough`: (world: World, script: Segment[]) => PlaythroughResult
208
299
  - `scriptToFrames`: (script: InputScript) => string[][]
300
+ - `scrubTo`: (world: World, def: GameDefinition, ring: SnapshotRing, inputFrames: readonly string[][], axesLog: readonly (readonly [number, string, number])[], knobEvents…
209
301
  - `serializeSnapshot`: (snap: WorldSnapshot) => string
210
302
  - `series`: (timeline: ProbeFrame[], key: string) => unknown[]
211
303
  - `setOverlayHost`: (el: HTMLElement) => void
304
+ - `setScreenObserver`: (cb: ((kind: "show" | "hide", title?: string | undefined) => void) | null) => void
305
+ - `shadowDef`: (s: Shadow, id: string) => string
306
+ - `shapeBBox`: (c: DrawCommand) => BBox | null
212
307
  - `shapeBox`: (cmd: DrawCommand) => { x: number; y: number; w: number; h: number; } | null
213
308
  - `showScreen`: (spec: ScreenSpec) => ScreenHandle
309
+ - `signalHash`: (sig: Samples) => number
214
310
  - `smoothClosedPath`: (points: Vec2[], tension?: number) => string
215
311
  - `smoothOpenPath`: (points: Vec2[], tension?: number) => string
312
+ - `softClip`: (x: number) => number
313
+ - `softClipInPlace`: (buf: StereoBuffer) => void
216
314
  - `solidNeighbours`: (g: Grid, x: number, y: number) => number
217
315
  - `solve`: <State, Move>(puzzle: Puzzle<State, Move>, options?: SolveOptions) => SolveResult<Move>
218
316
  - `solveJoint`: (j: Joint, A: RigidBody, B: RigidBody, dt: number, scratch: JointScratch) => void
317
+ - `songBeats`: (song: Song) => number
318
+ - `songDuration`: (song: Song) => number
219
319
  - `sortCommands`: (cmds: DrawCommand[]) => DrawCommand[]
320
+ - `spatialMix`: (dx: number, dy: number, hearing?: number, rolloff?: number) => SpatialMix
321
+ - `spectralCentroid`: (sig: Samples, sampleRate?: number) => number
220
322
  - `springStep`: (s: SpringState, target: number, omega: number, dt: number) => SpringState
221
323
  - `star`: (points: number, outer: number, inner: number, rotation?: number) => number[]
222
324
  - `steer2D`: (px: number, py: number, tx: number, ty: number, out: string[], dead?: number) => void
223
325
  - `stepPlatformer`: (s: PlatformerState, input: PadInput, dt: number, map: TilemapData, cfg?: PlatformerConfig, platforms?: Platform[]) => PlatformerEvents
326
+ - `stereoDuration`: (buf: StereoBuffer) => number
327
+ - `stereoFrames`: (buf: StereoBuffer) => number
328
+ - `stereoWidth`: (buf: StereoBuffer) => number
329
+ - `subSeed`: (seed: number, i: number) => number
330
+ - `telegraphIssues`: (timeline: readonly TelegraphFrame[], minFrames: number, label?: string) => string[]
224
331
  - `terrainHeight`: (col: number, opts: TerrainOptions) => number
225
332
  - `terrainSlice`: (startCol: number, count: number, opts: TerrainOptions) => number[]
226
333
  - `textBox`: (cmd: TextCommand) => TextBox
@@ -229,10 +336,13 @@
229
336
  - `tileAtPoint`: (map: TilemapData, x: number, y: number) => number
230
337
  - `tilemapFromAscii`: (rowsAscii: string[], tileSize?: number, chars?: Record<string, TileId>) => TilemapData
231
338
  - `toggleFullscreen`: () => void
339
+ - `transpose`: (notes: number[], semitones: number) => number[]
232
340
  - `typewriterCount`: (total: number, elapsedSec: number, charsPerSec: number) => number
233
341
  - `unpackVarints`: (input: string) => number[]
342
+ - `validateWorld`: (world: WorldGraphDef) => string[]
234
343
  - `valueNoise`: (x: number, y: number, seed?: number) => number
235
344
  - `vnorm`: (a: Vec2) => Vec2
345
+ - `voiceLead`: (chords: number[][]) => number[][]
236
346
  - `wait`: (frames: number) => Segment
237
347
  - `wakeBody`: (b: RigidBody) => void
238
348
  - `wangTile`: (mask: number) => WangTile
@@ -242,17 +352,38 @@
242
352
  - `wipeStep`: (transition: ScreenTransition, opts?: WipeOptions & { name?: string | undefined; }) => CinematicStep
243
353
  - `withAlpha`: (hex: string, alpha: number) => string
244
354
  - `worldPoints`: (b: RigidBody) => number[]
355
+ - `zcr`: (sig: Samples, sampleRate?: number) => number
245
356
 
246
- ## interfaces (132)
357
+ ## interfaces (222)
247
358
 
359
+ - `AcceptedProof`
360
+ - `ActBounds`
361
+ - `ActSpec`
362
+ - `AlbumTrack`
248
363
  - `AmbientStyle`
364
+ - `AnalyzeOptions`
365
+ - `Annotation`
366
+ - `AnnotationContext`
367
+ - `AudioAssertion`
368
+ - `AudioExpectation`
369
+ - `AudioFeatures`
370
+ - `AudioFilmstripOptions`
249
371
  - `AutotileDrawOptions`
372
+ - `BandBalance`
373
+ - `BBox`
250
374
  - `Behavior`
251
375
  - `BfsResult`
252
376
  - `BitmapFont`
253
377
  - `BitmapTextConfig`
254
378
  - `BotCtx`
379
+ - `Breakpoint`
380
+ - `CameraBounds`
255
381
  - `CameraConfig`
382
+ - `CameraControllerConfig`
383
+ - `CameraOptions`
384
+ - `Campaign`
385
+ - `CampaignLevel`
386
+ - `CampaignSpec`
256
387
  - `CaptureTarget`
257
388
  - `CaveOptions`
258
389
  - `Cell`
@@ -265,8 +396,11 @@
265
396
  - `ContourOptions`
266
397
  - `ContourSegment`
267
398
  - `CoreEvents`
399
+ - `CreateWorldOptions`
400
+ - `DeathCluster`
268
401
  - `DesyncInfo`
269
402
  - `DeterminismReport`
403
+ - `DifficultyBand`
270
404
  - `DirectorState`
271
405
  - `DistanceJoint`
272
406
  - `DistanceJointDef`
@@ -274,34 +408,63 @@
274
408
  - `DriveResult`
275
409
  - `Dungeon`
276
410
  - `DungeonOptions`
411
+ - `FeatureDelta`
412
+ - `FeedbackOptions`
413
+ - `FeedbackResponse`
414
+ - `FeelContext`
415
+ - `FeelReport`
416
+ - `FeelSpec`
277
417
  - `FilmstripOptions`
278
418
  - `FloatStyle`
419
+ - `ForgivenessOptions`
420
+ - `ForgivenessSpec`
279
421
  - `FractalOptions`
422
+ - `FutileVerb`
280
423
  - `GameDefinition`
281
424
  - `GameHandle`
425
+ - `GeneratedLevel`
426
+ - `GenerateOptions`
427
+ - `GenerateReport`
428
+ - `GenreProfile`
429
+ - `GenreTrack`
430
+ - `GradientStop`
282
431
  - `Grid`
283
432
  - `HayaoCapture`
284
433
  - `HeadlessResult`
434
+ - `HesitationSpan`
435
+ - `HotContext`
285
436
  - `HSL`
286
437
  - `ImageCommand`
287
438
  - `InputLog`
288
439
  - `JointScratch`
440
+ - `KnobEvent`
289
441
  - `LayoutOptions`
442
+ - `LevelChange`
443
+ - `LevelData`
444
+ - `LevelEntity`
445
+ - `LevelSpec`
446
+ - `LinearGradient`
447
+ - `LintOptions`
290
448
  - `LockstepOptions`
291
449
  - `LoopbackOptions`
292
450
  - `Manifold`
451
+ - `MatchResult`
293
452
  - `MenuAction`
294
453
  - `MoveOpts`
295
454
  - `MoveResult`
455
+ - `MusicLayer`
456
+ - `MusicLintResult`
296
457
  - `NetGame`
297
458
  - `NetGameHandle`
298
459
  - `NetRunOptions`
299
460
  - `NetSessionConfig`
300
461
  - `NineSliceStyle`
301
462
  - `NodeConfig`
463
+ - `Note`
302
464
  - `PadInput`
303
465
  - `Paint`
304
466
  - `Palette`
467
+ - `ParallaxLayerConfig`
305
468
  - `ParticleStyle`
306
469
  - `PathCommand`
307
470
  - `PhaseDef`
@@ -311,15 +474,30 @@
311
474
  - `Platform`
312
475
  - `PlatformerConfig`
313
476
  - `PlatformerEvents`
477
+ - `PlatformerReachOptions`
314
478
  - `PlatformerState`
479
+ - `PlaytestReport`
480
+ - `PlaytestSession`
315
481
  - `PlaythroughResult`
482
+ - `PointerReadout`
483
+ - `PointerTarget`
316
484
  - `PolyCommand`
485
+ - `ProgressState`
317
486
  - `Puzzle`
487
+ - `QualityScore`
488
+ - `QuitContext`
489
+ - `RadialGradient`
490
+ - `RampOptions`
491
+ - `RampStats`
318
492
  - `RayHit`
493
+ - `ReachReport`
494
+ - `RecorderInit`
319
495
  - `Rect`
320
496
  - `RectCommand`
321
497
  - `Renderer`
322
498
  - `RendererConfig`
499
+ - `ReplayOptions`
500
+ - `ReverbOptions`
323
501
  - `RevoluteJoint`
324
502
  - `RevoluteJointDef`
325
503
  - `RichChar`
@@ -335,21 +513,33 @@
335
513
  - `RoomClientOptions`
336
514
  - `RoomHostOptions`
337
515
  - `RunOptions`
516
+ - `SalienceOptions`
517
+ - `ScreenEvent`
338
518
  - `ScreenHandle`
339
519
  - `ScreenSpec`
340
520
  - `ScriptSegment`
341
521
  - `Segment`
342
522
  - `SerializedNode`
343
523
  - `Settings`
524
+ - `Shadow`
344
525
  - `ShellOptions`
526
+ - `SoftlockReport`
345
527
  - `SolidRect`
346
528
  - `SolveOptions`
347
529
  - `SolveResult`
530
+ - `Song`
531
+ - `SoundSpec`
532
+ - `SpatialMix`
348
533
  - `SpawnEvent`
534
+ - `SplashConfig`
349
535
  - `SpringState`
350
536
  - `SpriteConfig`
351
537
  - `StateHandlers`
538
+ - `StereoBuffer`
352
539
  - `StorageAdapter`
540
+ - `StudioHandle`
541
+ - `StudioOptions`
542
+ - `TelegraphFrame`
353
543
  - `TerrainOptions`
354
544
  - `TextBox`
355
545
  - `TextCommand`
@@ -359,15 +549,22 @@
359
549
  - `TextLayoutOptions`
360
550
  - `TextureSpriteConfig`
361
551
  - `TilemapData`
552
+ - `TimelineEntry`
362
553
  - `TimerConfig`
363
554
  - `Tone`
555
+ - `Track`
364
556
  - `Transform`
365
557
  - `Transition`
366
558
  - `TransitionConfig`
367
559
  - `Transport`
560
+ - `TuningKnob`
561
+ - `TuningSpec`
368
562
  - `UpgradeDef`
563
+ - `Variant`
564
+ - `VariantRef`
369
565
  - `Vec2`
370
566
  - `Volumes`
567
+ - `WallClockMark`
371
568
  - `WangTile`
372
569
  - `WaveDef`
373
570
  - `WeatherKey`
@@ -376,18 +573,29 @@
376
573
  - `WipeOptions`
377
574
  - `WorldConfig`
378
575
  - `WorldContext`
576
+ - `WorldEdge`
577
+ - `WorldGraphDef`
578
+ - `WorldPickup`
579
+ - `WorldRegion`
379
580
  - `WorldSnapshot`
380
581
 
381
- ## types (27)
582
+ ## types (41)
382
583
 
383
584
  - `BodyKind`
384
585
  - `BoolGrid`
586
+ - `CompletionMode`
587
+ - `DistanceModel`
385
588
  - `DrawCommand`
386
589
  - `Ease`
387
590
  - `Easing`
388
591
  - `Edge`
592
+ - `EndReason`
593
+ - `FeedbackChannel`
594
+ - `FeedbackContract`
595
+ - `Gradient`
389
596
  - `InputMap`
390
597
  - `InputScript`
598
+ - `Instrument`
391
599
  - `Joint`
392
600
  - `Listener`
393
601
  - `Neighbours`
@@ -395,21 +603,29 @@
395
603
  - `NodeFactory`
396
604
  - `NodeKey`
397
605
  - `Passable`
606
+ - `Pitch`
398
607
  - `PlayerId`
399
608
  - `ProbeFrame`
609
+ - `ProgressMove`
400
610
  - `RigidShape`
611
+ - `Samples`
612
+ - `ScaleName`
401
613
  - `Shape`
402
614
  - `StepExec`
403
615
  - `Swatch`
404
616
  - `TextAlign`
405
617
  - `TileId`
618
+ - `TuningValue`
619
+ - `TuningValues`
406
620
  - `WangFrame`
621
+ - `Wave`
407
622
  - `WeightedNeighbours`
408
623
  - `WipeKind`
409
624
  - `WorldFactory`
410
625
 
411
- ## consts (48)
626
+ ## consts (57)
412
627
 
628
+ - `ALBUM`: { title: string; subtitle: string; concept: string; tracks: AlbumTrack[]; }
413
629
  - `AMBIENT_PRESETS`: { readonly snow: (colors?: string[]) => AmbientStyle; readonly rain: (colors?: string[]) => AmbientStyle; readonly ash: (colors?: string[]) => AmbientStyle; }
414
630
  - `audio`: AudioBus
415
631
  - `clamp`: (v: number, lo: number, hi: number) => number
@@ -424,8 +640,13 @@
424
640
  - `EASINGS`: Record<string, Easing>
425
641
  - `FLOAT_PRESETS`: { readonly damage: (color?: string) => FloatStyle; readonly crit: (color?: string) => FloatStyle; readonly heal: (color?: string) => FloatStyle; readonly lab…
426
642
  - `FONT_5`: BitmapFont
643
+ - `GENRE_PROFILES`: Record<string, GenreProfile>
644
+ - `GENRES`: GenreTrack[]
427
645
  - `IDENTITY`: Transform
646
+ - `INSTRUMENTS`: Record<string, Instrument>
428
647
  - `invLerp`: (a: number, b: number, v: number) => number
648
+ - `KENTO`: { readonly gofun: "#f7f1e2"; readonly washi: "#efe7d3"; readonly kinu: "#e4d8bd"; readonly line: "#d8cbac"; readonly kinako: "#b9a882"; readonly stone: "#6c6…
649
+ - `knob`: { num(key: string, opts: { default: number; min?: number | undefined; max?: number | undefined; step?: number | undefined; label?: string | undefined; group?…
429
650
  - `lerp`: (a: number, b: number, t: number) => number
430
651
  - `lerpDamp`: (current: number, target: number, lambda: number, dt: number) => number
431
652
  - `mapHeight`: (map: TilemapData) => number
@@ -443,18 +664,21 @@
443
664
  - `playerInput`: (world: World, player: string) => PlayerInput
444
665
  - `rad2deg`: (r: number) => number
445
666
  - `remap`: (v: number, a0: number, a1: number, b0: number, b1: number) => number
667
+ - `SAMPLE_RATE`: 44100
446
668
  - `SAVE_FORMAT_VERSION`: 1
669
+ - `SCALES`: { readonly major: readonly [0, 2, 4, 5, 7, 9, 11]; readonly minor: readonly [0, 2, 3, 5, 7, 8, 10]; readonly harmonicMinor: readonly [0, 2, 3, 5, 7, 8, 11]; …
447
670
  - `screenRect`: (w: number, h: number) => Rect
448
671
  - `settings`: SettingsStore
449
672
  - `smoothstep`: (edge0: number, edge1: number, v: number) => number
450
673
  - `spring`: (value?: number) => SpringState
451
674
  - `TAU`: number
452
675
  - `TILE`: { readonly EMPTY: 0; readonly SOLID: 1; readonly ONEWAY: 2; readonly HAZARD: 3; }
676
+ - `tileCenter`: (tx: number, ty: number, tileSize: number) => { x: number; y: number; }
453
677
  - `vadd`: (a: Vec2, b: Vec2) => Vec2
454
678
  - `vdist`: (a: Vec2, b: Vec2) => number
455
679
  - `vdot`: (a: Vec2, b: Vec2) => number
456
680
  - `vec2`: (x?: number, y?: number) => Vec2
457
- - `VERSION`: "0.2.0"
681
+ - `VERSION`: "0.3.0"
458
682
  - `vlen`: (a: Vec2) => number
459
683
  - `vscale`: (a: Vec2, s: number) => Vec2
460
684
  - `vsub`: (a: Vec2, b: Vec2) => Vec2