@jgengine/convex 0.49.0 → 0.50.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/CHANGELOG.md CHANGED
@@ -26,6 +26,184 @@ At publish, rename this heading to the new version and mirror the entries into
26
26
  `packages/core/src/meta/changelog.ts` (the typed `CHANGELOG` export).
27
27
  -->
28
28
 
29
+ ## 0.50.0
30
+
31
+ ### Migrate
32
+
33
+ - **Bump lockstep SDK packages to `^0.50.0`:** `@jgengine/{core,rapier,react,ws,node,sql,convex,shell,editor,assets,navbake}`. CLI `jgengine` is `0.47.0`; `@jgengine/github` is `0.37.0`.
34
+ - declare the tour's steps in createOnboardingSystem({ steps: [{ id, text, detail, anchor, placement, done: { next: true } }] }) and mount <OnboardingCallout />; a coach-mark condition becomes done: { when } or { event }
35
+
36
+ ### Added
37
+
38
+ - An action's bindings take `locked: true`: players can't rebind it, saved overrides for it are ignored, and controls menus show it read-only. `isActionLocked(codes)` reads the flag.
39
+ - `persist.storage` in `defineGame` also takes any `SaveBackend`, such as `createConvexSaveBackend`, so a solo game's whole-world save can go to the cloud.
40
+ - Brightway Park design brief: core loop, session goal, long loop, second 0, the first 10 minutes and a content budget
41
+ - `OnboardingCallout` (`@jgengine/core/onboarding/onboardingCallout.view`): The onboarding's UI callout, for steps about the interface rather than the world: a step with an `anchor` (a CSS selector) gets a card beside that element with a spotlight around it, and a step that finishes on Next with no anchor gets a centred card. Also `OnboardingCalloutCard`, `OnboardingCalloutCardProps`, `OnboardingCalloutProps`, `OnboardingCalloutTheme`.
42
+ - `OnboardingCallout` (`@jgengine/react`): The onboarding's UI callout, for steps about the interface rather than the world: a step with an `anchor` (a CSS selector) gets a card beside that element with a spotlight around it, and a step that finishes on Next with no anchor gets a centred card. Also `OnboardingCalloutCard`, `OnboardingCalloutCardProps`, `OnboardingCalloutProps`, `OnboardingCalloutTheme`.
43
+ - Fernwild's Survivor's path takes a new survivor from the first tree to the Broodmother in 23 steps, with a star on the map at each target.
44
+ - Fernwild taming works from a new game with no cheats: punch a dodo out and feed it berries, club a phiomia and keep it under with narcotics. A club hit now lands its full torpor.
45
+ - Fernwild has 21 explorer notes, a Dossier tab of species met, tamed and notes read, and an always-on map baked from the island's ground with notes, obelisks, caves and tames marked.
46
+ - Fernwild danger rises with distance (wild levels capped at 5 by the beach, the full 30 from 1250 m), and the start beach holds only grazers.
47
+ - createSpoilage in @jgengine/core/inventory/spoilage; Fernwild meat spoils into spoiled meat and the timers survive a save.
48
+ - an onboarding step can set inArea: false so a teaching-area pointer sends the player past the area.
49
+ - Fernwild's PLAN.md design brief compares it with ARK beat by beat, and its from-zero proof plays 19 minutes from a new game; Fernwild is off the depth known-failing list.
50
+ - `createSpoilage` (`@jgengine/core/inventory/spoilage`): Perishables in an inventory, as ARK keeps them: each stack runs one timer, and every time it runs out one unit spoils and the timer starts again, so a big stack lasts longer than a small one. Also `SpoilRule`, `Spoilage`, `SpoiledUnits`, `SpoilingStack`.
51
+ - every game's PLAN.md carries a design brief (core, session and long loops, second 0, the first 10 minutes beat by beat, content budget, systems, onboarding); check games-design fails a game without a complete one
52
+ - games/scripts/depth-known-failing.json lists the 18 games that fail the brief, from-zero and depth rules today, with why; the list only shrinks
53
+ - every game has a from-zero proof (proofs/flows/from-zero.flow.ts) that boots a new game with no prepared state or save and plays its first 10 minutes through real input; it fails a start beyond the brief's second 0, nothing taught or unlocked by minute 2, or new things stopping at the brief's pace
54
+ - check games-depth plays that proof and measures systems touched, time to first unlock, unlocks per 10 minutes, content against the budget, the longest cycle and minutes of content; it blocks landing, and today's games are on the shrink-only known-failing list
55
+ - a game declares its new-game start as data (defineGame newGame: cash, kit, unlocked items, prebuilt pieces, systems that start running). The engine builds every new game from that declaration only, refuses start items handed out anywhere else, and exposes it on the definition for checks to read
56
+ - Fernwild declares its start: empty-handed, knowing only the Stone Pick and Torch engrams
57
+ - `NewGameConfig` (`@jgengine/core/game/newGame`): A game's new-game declaration, passed as `defineGame({ newGame })`: the {@link NewGameState} plus the hooks that apply its game-owned parts. Also `NewGameKit`, `NewGamePiece`, `NewGameState`.
58
+ - onboarding as data (createOnboardingSystem). A game declares its steps; each has text, can point at an entity, the nearest thing of a kind or a spot (on-screen pin or edge arrow, minimap marker, waypoint), completes from a game event, a condition, a measured amount or a Next press, can lock commands until done, and grants items, xp, currency or unlocks. Three styles: a separate tutorial level, a teaching start area, or hints blended into stage one. Skippable, saved per player, shown in the quest tracker and objective banner (OnboardingHud, OnboardingBanner, OnboardingPointer, onboardingLock)
59
+ - ctx.game.commands.gate, one place to refuse commands before they run
60
+ - Fernwild's first day: punch a tree for thatch, gather stone, craft a Stone Pick, tame a dodo, each pointing at the nearest tree, stones or dodo with an arrow and a minimap star; engram learning waits for the pick
61
+ - `Onboarding` (`@jgengine/core/onboarding/onboarding`): One player's run through an {@link OnboardingConfig}. Also `OnboardingConfig`, `OnboardingDone`, `OnboardingPoint`, `OnboardingSnapshot`, `OnboardingStep`, `OnboardingStepView`, `OnboardingStyle`, `OnboardingTarget`.
62
+ - `OnboardingBanner` (`@jgengine/core/onboarding/onboarding.view`): The step-done banner ("Gather stone" / "Next: Craft a Stone Pick") through `ObjectiveBannerHost`, near the top of the screen. Also `OnboardingHud`, `OnboardingHudProps`, `useOnboarding`.
63
+ - `OnboardingPointer` (`@jgengine/core/onboarding/OnboardingPointer.draw`): The onboarding's on-screen pointer, mounted in a game's `WorldOverlay`: a pin over the current step's target while it is in view, an edge arrow pointing the way with the distance while it is not (`WaypointMarkers` over the onboarding's waypoint).
64
+ - `ONBOARDING_MARK` (`@jgengine/core/onboarding/onboardingSystem`): The id of the waypoint and minimap marker the onboarding owns. Also `OnboardingRuntime`, `OnboardingSystemOptions`, `createOnboardingSystem`, `onboardingLock`, `onboardingOf`.
65
+ - repeat targeted tests under concurrent load with complete failure evidence
66
+ - A from-zero proof plays a new Scrap Signal game for ten minutes through real input: Bolt's quests one at a time, the crash chest's pistol, the whelps, the convoy's bruisers and red crate, Old Tusk and his whelps, the road to Breakwater Shelf and Captain Rusk. Scrap Signal is off the depth known-failing list for both from-zero and depth.
67
+ - Camp enemies carry four times their listed health and shield (one dial); bosses and Overdrive crews keep their own numbers; cleared camps refill after four minutes away.
68
+ - Ammo crates that restock, ammo packs sized to a camp fight, and kills that always drop ammo while you are nearly dry.
69
+ - Named targets behind side quests and quest-reward uniques.
70
+ - browser proof flows can move the mouse, look and aim with real pointer input again (flow.moveMouse, flow.look, flow.aimAt), restoring the pointer-lock look and crosshair aim lost when the JSON drive steps were replaced
71
+ - `FLOW_AIM_TOLERANCE_PX` (`@jgengine/core/play/flow`): How close {@link BrowserFlow.aimAt} must bring the target to the crosshair, in CSS pixels.
72
+ - withField(row, key, value) in @jgengine/core/data/withField sets an optional field, or leaves it out when value is undefined, so a cleared field is never stored as key: undefined.
73
+ - `definedOnly` (`@jgengine/core/data/definedOnly`): `value` without its undefined fields, so `{ ...defaults, ...definedOnly(overrides) }` never erases a default with an explicit `undefined`, and a record built from optional inputs can be written where an optional field must be absent rather than `undefined`. Also `DefinedOnly`.
74
+ - `withField` (`@jgengine/core/data/withField`): A copy of `row` with the optional field `key` set to `value`, or left out when `value` is `undefined`. Also `OptionalKey`.
75
+
76
+ ### Changed
77
+
78
+ - AGENTS.md settles two rules: an agent's own scratch files go in the session scratchpad (.scratch/ is only tool output), and a wait under 10 minutes runs in the foreground with a timeout while only dev servers and game launches run in the background
79
+ - Brightway Park keeps monthly books: eight-day months from 1 March, a report of every line (gate, rides, shops, awards, borrowing, wages, upkeep, restocking, repairs, research, marketing, interest, building), loan interest at each month's close, two red month-ends in a row close the park, and three marketing campaigns that bring more guests while they run
80
+ - Brightway Park has a design brief in its PLAN.md and a from-zero proof that plays the first 10 minutes of a new game
81
+ - Brightway Park's probe reports taught, unlocks, each content kind's seen and total, and one reading per system
82
+ - Brightway Park's lab opens with four short topics and the first-scenario hints now teach the lab, so the first unlock lands inside two minutes
83
+ - A new Brightway ride or shop that is still shut opens its window, where Connect it waits
84
+ - Brightway Park leaves the depth known-failing list
85
+ - Brightway Park restarts its calendar for every new park or scenario: 09:00 on 1 March, day one, one midnight a day, even when a scenario is started or replayed mid-way through another park
86
+ - Brightway Park's midnight uses the engine clock's cancel handle, so re-arming it after a reset cancels the old timer
87
+ - Brightway Park starts on an empty lot: a gate plaza, the gate shut, no guests until the player builds a path and a ride and opens the gate
88
+ - Guests trickle in and ramp with rating and appeal; the rating follows the park over the day instead of in seconds
89
+ - The open-park and staff proofs play from the empty lot by mouse and keyboard
90
+ - Brightway Park scenarios run for months: a new game starts Brightway Beginnings on the empty lot (120 guests and 400 stars by the end of May, Year 1), Star Attraction runs the whole first season and Full House two; each is won the moment its targets hold, unlocks the next, and the HUD shows days left; time runs at up to 8x
91
+ - Brightway Park's first scenario teaches itself: a card says the next step and rings the button that does it, with an arrow over the spot on the lot (lay a path from the gate, build a ride, connect it, open the gate), and at the first breakdown it says to hire a mechanic from Staff; a new proof plays from the empty lot to a natural breakdown and the hired mechanic fixing it
92
+ - Brightway Park's README states the award range and what the balance bot really measures, and jgengine.json describes the loan the park actually has
93
+ - Brightway's balance bot plays a new game the way a player starts one: the first scenario, the gate opened, a mechanic hired, and it prints how the scenario stands
94
+ - Brightway Park rides stay down until a mechanic fixes them: mechanics are hireable from the start and go straight to broken rides, the ride window shows reliability for the next run, the lab takes five times longer (34 topics over about thirteen park months, Dodgems now a topic), and litter bins catch litter
95
+ - Brightway Park's hint cards now run on the engine's onboarding system, keep up while the game is paused, and have a Hide hints button
96
+ - Brightway Park scenarios run for months: a new game starts Brightway Beginnings on the empty lot (120 guests and 400 stars by the end of May, Year 1), Star Attraction runs the whole first season and Full House two; each is won the moment its targets hold, unlocks the next, and the HUD shows days left; time runs at up to 8x
97
+ - drive's command line and help move to scripts/driveArgs.ts and its lockstep recorder to scripts/driveLockstep.ts, so drive-dev.ts is the run alone (1074 to 684 lines); the move drops four type casts
98
+ - New create-game-jg skill: a new game starts by agreeing its direction with the user (references, how faithful, breadth, look, scale, players, platforms, what done means), mapping every feature with one jgengine has call, and writing PLAN.md before jgengine create
99
+ - bun run drive prints the result, its warnings and failures by default; --verbose adds the progress, reuse and timing lines, and the GPU driver's shader precision warnings move there too
100
+ - drive --step: try flow calls on a live game page, with closest-match failures A --step runs one browser-flow call on a page of the game kept running (paused between commands) in the warm browser, so trying a click, wait or check answers in seconds instead of a full proof run. A failed click names the closest controls and whether one is covered; a failed probe check names missing probe keys and the closest real ones; see() names the closest page text; a misspelt f.call names the closest calls. The page work moves out of drive-dev.ts into drivePage.ts, shared by --flow --browser and --step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
101
+ - Landing fails fast: lane:close runs bun run preflight (install, gen, type-checks and gates) first and stops at the first failure, before any test runs
102
+ - bun run preflight is that cheap check on its own; preflight --ship is gone
103
+ - verify:fast starts type-checks and gates before tests and stops starting tests after a failure; --cheap runs only the type-checks and gates
104
+ - bun run gen runs independent generators side by side, and gen barrels reads core's surface once instead of five times
105
+ - lane:close starts the queue for its PR in the background and names the one command that prints the outcome
106
+ - Flaky tests fixed: folder deletes retry on Windows (Bun ignores rm's maxRetries), ws grace-window tests use hand-fired timers, the CDP deadline test waits for the server's message, and scrap-signal's audio test restores fetch instead of deleting it
107
+ - game-making skills start from the PLAN.md design brief: milestones are the next 10 minutes of play proven by the from-zero flow, the greenfield contract folds into the brief, and the first tutorial step no longer has to be doable from starting inventory
108
+ - create-game-jg description back under the 15-word skill limit
109
+ - Changelog: locked bindings and SaveBackend storage
110
+ - Faster frames in every game: half-resolution ambient occlusion, a matrix pass that skips what stood still, and a cheaper per-frame scene walk
111
+ - Ambient occlusion and its denoise run on a quarter of the pixels; at 1080p that cut its GPU time from about 2-3.8 ms to 0.6-1.6 ms in every game that uses it, with no visible change in a side-by-side shot.
112
+ - The scene's matrix pass rebuilds only nodes whose position, rotation, scale, parent or world matrix changed; the shader warmup and other traverseVisible callers use a stack walk (visitVisible), 1.4 ms -> 0.12 ms on fernwild.
113
+ - Dev telemetry reads the GPU name once instead of every second; bun run perf names the engine or game function behind each hot three.js function, and a compile hitch names the draw that waited.
114
+ - bun run perf takes several games in one browser and ends with a table per game; a clean-tree run is cached per commit so --compare HEAD measures only the after side; the process exits once results are written.
115
+ - shoot, verify:fast, preflight and lane:close print only results, warnings, failures and summaries by default; --verbose prints progress, reuse, timing and every pass
116
+ - release --wait: wait on npm serving every package, not on the run's 5-minute check 0.49.0's core reached npm 7m12s after upload, 24 s after publish.yml's 300 s check gave up; release --wait reported a failure and a second release followed (~50 min). release --wait now polls the registry for every lockstep package (bounded at 20 minutes) instead of one npm view of core, and a run that failed only at its registry check keeps waiting on npm and then runs the same artifact check locally. publish.yml's check budget goes from 300 s to 900 s because 300 s was measured too short. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
117
+ - The Rustflat Front's crews wake only after Old Tusk is down; Old Tusk has 2000 health, Captain Rusk 1800 plus a 400 shield.
118
+ - Bruiser Bash now ends at the convoy's red crate, and Old Tusk's quest starts by thinning his whelps.
119
+ - Games: the six strict compiler flags (`noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `noImplicitOverride`, `noPropertyAccessFromIndexSignature`, `noImplicitReturns`, `noFallthroughCasesInSwitch`) are now on for every in-repo game through `games/tsconfig.base.json`, and in llmville's own tsconfig. Each game's `check-types` (run by CI) now enforces them, so new strict errors cannot come back.
120
+ - ember-command, drift-foundry and brightway-park now pass the strictest type settings. Their catalogs name their ids, so a mistyped unit, building or research id is a type error, and save loading reads old saves without casts.
121
+ - New `@jgengine/core/data/untyped` (`isRecord`, `isFiniteNumber`, `recordOf`) narrows parsed JSON and old saves without casts. New `slotText`/`slotNumber` in `@jgengine/core/save/saveSlots` read a save slot's chips.
122
+ - `ModelConfig.dims`, `ModelBodySource.dims`, `DrivableVehicleOptions.modifiers`, `BuildingSurfaceMaterial.roughness`/`metalness` and the kit objective's `steps`/`deadline` accept an explicit `undefined`.
123
+ - scrap-signal now type-checks clean under the strict flags (unchecked index access, exact optional properties, no index-signature dot access): save reads go through named locals, optional fields are passed only when set, and catalog lookups say when a key can be missing.
124
+ - The shared legacy-save reader reads the envelope by key.
125
+ - harbor-heat now type-checks clean under the strict flags (unchecked index access, exact optional properties, no index-signature dot access).
126
+ - harbor-heat reads scene meta through the engine's typed meta readers, so a wrong value in the scene file fails naming the marker instead of silently falling back to a default.
127
+ - harbor-heat's save reader uses the engine's shared record check instead of its own copy, and drops casts it no longer needs.
128
+ - deepward now type-checks clean under the strict flags (unchecked index access, exact optional properties, no index-signature dot access).
129
+ - deepward's save reader checks stored fields through named raw shapes and the engine's shared record check, instead of reading an open record by dot.
130
+ - deepward's probe now reports its own named readings, so its proof flows are checked against the real probe keys instead of any string.
131
+ - odd-orbit now type-checks clean under the strict flags (unchecked index access, exact optional properties, no index-signature dot access).
132
+ - odd-orbit's save checker names every stored field it reads, so a misspelled field is a type error instead of a silent `undefined`.
133
+ - A career rung with no pay value now fails loudly instead of paying `NaN`.
134
+ - New engine helper `definedFields` (`@jgengine/core/data/definedFields`): passes maybe-missing values on as optional fields, leaving out the undefined ones, so code stays correct under exact optional property types.
135
+ - llmville: first pass toward the strict type flags (517 errors down to 303). Builder session, agent asset requests, dev endpoints, generated assets and rack commands read untyped input through the engine's record check instead of dot access; map decor and procedural props pass optional transforms through `definedFields`.
136
+ - llmville: the game package, Convex backend, dev-server bridges and scripts now pass the strict compiler flags (strict-flag errors 303 → 173; the rest are in `src/`).
137
+ - llmville: command and save readers use bracket reads, optional fields that can be unset say so with `| undefined`, and Convex calls only pass optional fields that are set.
138
+ - llmville: the whole game now passes the strict compiler flags (strict-flag errors 173 → 0).
139
+ - llmville: component props and view-model fields that can be unset say so with `| undefined`; list reads check for a missing entry; fixed lists (avatars, builder materials, room templates) are typed as never empty.
140
+ - llmville: the error-report payload only sends fields that are set, and the toast theme no longer needs a cast.
141
+ - Nine games (apex-nights, beacon-bastion, briarcrown, hold-the-line, orbit-watch, outpost-zero, red-frontier, saltwick, the-sunken-crown) now pass the strictest type settings, ahead of those settings turning on for every game.
142
+ - Games read a placed object's authored settings through `metaNumber`, `metaText` and `requireMetaText` (`@jgengine/core/editor/markerMeta`), which fail loudly on a wrong value instead of casting it.
143
+ - `CompassProps.center`, the kit vitals objective's `id`/`goal`, and kit buttons' `cue` accept an explicit `undefined`.
144
+ - Every engine package (assets, convex, editor, github, jgengine, navbake, node, rapier, react, sql) now type-checks with the strict flags core, shell and ws already had. 400 errors fixed with guards and real types, no new casts.
145
+ - definedOnly in @jgengine/core/data/definedOnly is public, and its result keeps always-defined fields required; only fields that may be undefined become optional.
146
+ - Scripts, the UI registry, the dev, web and desktop apps and the host examples now type-check with the same strict flags as the engine packages. About 1000 errors fixed with guards and real types, no new casts.
147
+ - optional fields on registry slot props (ActionBarSlot, ItemGridSlot, BuffChip), EditorAppProps, the ws host's listOpenServers args and a few core option types accept an explicit undefined.
148
+
149
+ ### Fixed
150
+
151
+ - Beacon Bastion's pacing test counts only gold the keep could still have spent: the bounty from the last kill, paid after the final chance to buy, no longer fails a keep that spent everything it could. A keep that stops buying still fails the test.
152
+ - Brightway Park's status card no longer overlaps the goal card at 1600x900; it keeps a steady height as guest thoughts come and go, with mood and cleanliness side by side
153
+ - Brightway's goal hint no longer says to lay a path when the only ride is broken down
154
+ - Fernwild's Harvest Stones prompt no longer shows when you aim at a tree.
155
+ - Fernwild's dehydration test steps whole seconds so it finishes inside CI's test timeout.
156
+ - Fernwild no longer freezes for about a second when you press Play: the island's 33k trees and rocks are placed while the title loads (worst click 940 ms -> 510 ms, menu shows ~0.5 s later)
157
+ - drive --playtest judges a softlock only after the player first acts; a quiet title or idle start no longer counts
158
+ - the capability boot probe presses Play (the game's capture.play) and gives a system 300 frames from there, not from the menu
159
+ - closing a lane again with -m adds the new lines to its change note instead of replacing it
160
+ - the automatic worktree cleanup now removes a lane that never committed once it has sat untouched for an hour with no changed or new files, and its dry run lists only what a real run would take
161
+ - waypoint pins and edge arrows near a screen edge keep their label on screen
162
+ - world-anchored floating text no longer re-renders every frame while nothing floats
163
+ - the worktree cleanup leaves a tree a running process holds whole and reports it in use, instead of half-deleting it and stopping, so the trees after it still go
164
+ - bun run worktree new runs the cleanup from the new tree's own code, not the main checkout's possibly older copy
165
+ - Rockets burst on the first thing they hit instead of flying through it.
166
+ - Chest and crate drops land two metres out on the opener's side, so picking one up no longer puts the camera inside the chest.
167
+ - on Windows a new worktree shares the main checkout's installed packages instead of installing 713 of its own, so it is ready in about 10s instead of 30s to 2 minutes
168
+ - a worktree whose bun.lock moved on gets its own install instead of writing into the shared one
169
+ - the 17 aim and look checks removed with the old drive steps are restored, and the 12 removed drive-step assertion checks now live as browser flow tests (failing expect stops the run, strict value matching, a page error, a timed-out wait)
170
+ - A new game made with `--no-editor` now gets the starter sun angle; it was written in the editor's shape, which `sky()` ignored.
171
+ - the casts and non-null assertions the type-escape baseline was raised to accept (boot sequence, asset prefetch, frame breakdown, perf panel, dev asset plugin, perf scripts) are replaced by real checks.
172
+ - Convex inserts and query results no longer write field: undefined for optional columns.
173
+ - the workspace catalog JSON scanner throws a clear error on truncated JSON instead of reading past the end.
174
+ - script readers of changelog headings, PNG headers and screenshot pixels no longer read past the end of their input.
175
+
176
+ ### Removed
177
+
178
+ - createCoachMarkSequence, CoachMark and CoachMarkHost. UI tours are onboarding steps now: give a step an anchor (CSS selector) and placement, or finish it on Next, and OnboardingCallout shows it as a card with a spotlight, Next and Skip, saved with the game
179
+ - `@jgengine/core/ui` no longer exports `CoachMarkPlacement`, `CoachMarkSequence`, `CoachMarkSequenceOptions`, `CoachMarkSnapshot`, `CoachMarkStep`, `CoachMarkView`, `createCoachMarkSequence`.
180
+ - `@jgengine/core/ui/coachMarks` no longer exports `CoachMarkPlacement`, `CoachMarkSequence`, `CoachMarkSequenceOptions`, `CoachMarkSnapshot`, `CoachMarkStep`, `CoachMarkView`, `createCoachMarkSequence`.
181
+ - `@jgengine/core/ui/coachMarks.view` no longer exports `CoachMark`, `CoachMarkHost`, `CoachMarkHostProps`, `CoachMarkProps`, `CoachMarkTheme`, `useCoachMarks`.
182
+ - `@jgengine/react` no longer exports `CoachMark`, `CoachMarkHost`, `CoachMarkHostProps`, `CoachMarkProps`, `CoachMarkTheme`, `useCoachMarks`.
183
+ - the jgengine plan command; the skill replaces it, and jgengine has stays as the lookup
184
+ - the progression-curve seam from games-framework; a game's own level numbers, unlock order and tutorial beats stay in the game at any length (games/AGENTS.md mechanism signal)
185
+ - system checkboxes from the game READMEs' progression sections; progression is written as what the player gets over hours
186
+
187
+ ## 0.49.1
188
+
189
+ ### Migrate
190
+
191
+ - **Bump lockstep SDK packages to `^0.49.1`:** `@jgengine/{core,rapier,react,ws,node,sql,convex,shell,editor,assets,navbake}`. CLI `jgengine` is `0.46.1`; `@jgengine/github` is `0.36.1`.
192
+
193
+ ### Added
194
+
195
+ - bun run check type-escapes fails a file that gains an any, a non-null !, an as cast or a @ts-ignore; the per-file count lives in scripts/type-escape-baseline.json, bun run gen lowers it, and an unavoidable escape is excused by a // type-escape: <why> comment.
196
+ - `ActionCodeModes` (`@jgengine/core/input/actionBindings`): The hold/toggle form of an {@link ActionCodes} entry, with an optional auto-repeat rate.
197
+
198
+ ### Changed
199
+
200
+ - core, shell and ws type-check with noUncheckedIndexedAccess, exactOptionalPropertyTypes, noImplicitOverride, noPropertyAccessFromIndexSignature and noImplicitReturns. All 1460 errors are fixed with guards, real types and small helpers, not casts: a missing array slot, a missing record key or an optional field that may be undefined is now a compile error.
201
+
202
+ ### Fixed
203
+
204
+ - spreading a game's place physics over the base no longer erases base gravity or jump velocity with an undefined.
205
+ - the four ActionCodes readers (camera, gamepad, touch, rebind) share one isCodeList / allActionCodes / primaryActionCodes instead of four copies with casts.
206
+
29
207
  ## 0.49.0
30
208
 
31
209
  ### Migrate
@@ -13,8 +13,8 @@ export type ConvexBackendOptions<TRawPresenceRow extends {
13
13
  client: ConvexReactClient;
14
14
  gameId: string;
15
15
  userId: string;
16
- api?: ConvexGameApi;
17
- poseTuning?: PoseSyncTuning;
16
+ api?: ConvexGameApi | undefined;
17
+ poseTuning?: PoseSyncTuning | undefined;
18
18
  presence?: {
19
19
  functions: ConvexPresenceFunctions;
20
20
  mapRow: (row: TRawPresenceRow) => TPresenceRow;
@@ -15,23 +15,23 @@ export type ConvexGameApi = {
15
15
  runtime: {
16
16
  joinServer: FunctionReference<"mutation", "public", {
17
17
  gameId: string;
18
- serverId?: string;
18
+ serverId?: string | undefined;
19
19
  mode?: string;
20
20
  visibility?: "public" | "private";
21
21
  joinCode?: string;
22
- externalId?: string;
22
+ externalId?: string | undefined;
23
23
  sessionId?: string;
24
24
  }, JoinServerOutcome>;
25
25
  leaveServer: FunctionReference<"mutation", "public", {
26
26
  serverId: string;
27
- externalId?: string;
27
+ externalId?: string | undefined;
28
28
  sessionId?: string;
29
29
  }, null>;
30
30
  runCommand: FunctionReference<"mutation", "public", {
31
31
  serverId: string;
32
32
  command: string;
33
33
  input: unknown;
34
- externalId?: string;
34
+ externalId?: string | undefined;
35
35
  }, {
36
36
  ok: true;
37
37
  } | {
@@ -42,7 +42,7 @@ export type ConvexGameApi = {
42
42
  serverId: string;
43
43
  action: string;
44
44
  entry: unknown;
45
- externalId?: string;
45
+ externalId?: string | undefined;
46
46
  }, null>;
47
47
  getServer: FunctionReference<"query", "public", {
48
48
  serverId: string;
@@ -55,13 +55,13 @@ export type ConvexGameApi = {
55
55
  getFeed: FunctionReference<"query", "public", {
56
56
  serverId: string;
57
57
  action: string;
58
- externalId?: string;
58
+ externalId?: string | undefined;
59
59
  }, unknown[]>;
60
60
  };
61
61
  presence: {
62
62
  list: FunctionReference<"query", "public", {
63
63
  serverId: string;
64
- externalId?: string;
64
+ externalId?: string | undefined;
65
65
  viewerChunkKey?: string;
66
66
  }, PresencePoseRow[]>;
67
67
  sync: FunctionReference<"mutation", "public", {
@@ -76,7 +76,7 @@ export type ConvexGameApi = {
76
76
  sessionId?: string;
77
77
  kind?: string;
78
78
  label?: string;
79
- externalId?: string;
79
+ externalId?: string | undefined;
80
80
  }, {
81
81
  pose: {
82
82
  x: number;
@@ -98,13 +98,13 @@ export type ConvexGameApi = {
98
98
  messages: FunctionReference<"query", "public", {
99
99
  serverId: string;
100
100
  channelId: string;
101
- externalId?: string;
101
+ externalId?: string | undefined;
102
102
  }, ChatMessage[]>;
103
103
  sendMessage: FunctionReference<"mutation", "public", {
104
104
  serverId: string;
105
105
  channelId: string;
106
106
  body: string;
107
- externalId?: string;
107
+ externalId?: string | undefined;
108
108
  }, ChatSendOutcome>;
109
109
  };
110
110
  leaderboard: {
@@ -53,9 +53,9 @@ export declare function createHostedGameServerFunctions(options: {
53
53
  tickMs?: number;
54
54
  }): {
55
55
  getHostedServer: import("convex/server").RegisteredQuery<"public", {
56
- externalId?: string | undefined;
56
+ externalId?: string;
57
57
  gameId: string;
58
- serverId?: string | undefined;
58
+ serverId?: string;
59
59
  }, Promise<{
60
60
  serverId: string;
61
61
  gameId: string;
@@ -64,24 +64,24 @@ export declare function createHostedGameServerFunctions(options: {
64
64
  memberUserIds: string[];
65
65
  } | null>>;
66
66
  joinHostedServer: import("convex/server").RegisteredMutation<"public", {
67
- externalId?: string | undefined;
67
+ externalId?: string;
68
68
  gameId: string;
69
- serverId?: string | undefined;
69
+ serverId?: string;
70
70
  }, Promise<{
71
71
  serverId: string;
72
72
  isNew: boolean;
73
73
  }>>;
74
74
  leaveHostedServer: import("convex/server").RegisteredMutation<"public", {
75
- externalId?: string | undefined;
75
+ externalId?: string;
76
76
  gameId: string;
77
- serverId?: string | undefined;
77
+ serverId?: string;
78
78
  }, Promise<null>>;
79
79
  runHostedCommand: import("convex/server").RegisteredMutation<"public", {
80
80
  command: string;
81
- externalId?: string | undefined;
81
+ externalId?: string;
82
82
  gameId: string;
83
83
  input: any;
84
- serverId?: string | undefined;
84
+ serverId?: string;
85
85
  }, Promise<{
86
86
  ok: false;
87
87
  reason: string;
@@ -89,10 +89,10 @@ export declare function createHostedGameServerFunctions(options: {
89
89
  ok: true;
90
90
  }>>;
91
91
  submitHostedInput: import("convex/server").RegisteredMutation<"public", {
92
- externalId?: string | undefined;
92
+ externalId?: string;
93
93
  frame: any;
94
94
  gameId: string;
95
- serverId?: string | undefined;
95
+ serverId?: string;
96
96
  }, Promise<null>>;
97
97
  tickHostedWorlds: import("convex/server").RegisteredMutation<"internal", {}, Promise<{
98
98
  ticked: number;
@@ -7,7 +7,7 @@ export declare function randomConvexPlayerId(): string;
7
7
  export declare function resolveConvexMultiplayer(args: {
8
8
  game: GameDefinition;
9
9
  gameId: string;
10
- url?: string;
10
+ url?: string | undefined;
11
11
  client?: ConvexReactClient;
12
12
  api?: ConvexGameApi;
13
13
  userId?: string;