Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions .claude/skills/jgengine-editor/api.md

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions .claude/skills/jgengine-editor/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@

Reach for these before hand-rolling. Each row is *the thing you need* → *the primitive that already does it*.

## editor-catalogs — Persist gameplay tuning rows on the scene document.

- `EditorCatalogData` (interface) · `import { EditorCatalogData } from "@jgengine/core/editor"`
- `EditorCatalogDefinition` (interface) · `import { EditorCatalogDefinition } from "@jgengine/core/editor"`
- `EditorCatalogEntry` (interface) · `import { EditorCatalogEntry } from "@jgengine/core/editor"`
- `findEditorCatalog` (function) · `import { findEditorCatalog } from "@jgengine/core/editor"`
- `findEditorCatalogEntry` (function) · `import { findEditorCatalogEntry } from "@jgengine/core/editor"`
- `seedEditorCatalogs` (function) · `import { seedEditorCatalogs } from "@jgengine/core/editor"`

## editor-live-sync — apply a versioned document patch onto a live scene document

- `applyDocumentPatch` (function) · `import { applyDocumentPatch } from "@jgengine/core/editor"`
Expand Down
4 changes: 1 addition & 3 deletions .claude/skills/jgengine-gameplay/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ description: Gameplay systems: items, quests, economy, crafting, turns, objectiv

# jgengine-gameplay

**Import from the curated barrel** `@jgengine/core/gameplay` (stable, re-exports this domain's public API) — deep paths `@jgengine/core/<domain>/<file>` still work for anything not re-exported.

**Composable systems** — `defineSystem` / `composeGameLoop` / `compileSystemSchedule` / `DEFAULT_FIXED_STAGES` / `DEFAULT_FRAME_STAGES` / `SystemDefinition` / `SystemTick` / `SystemEventHandlers` / `CompiledSystemSchedule`: list capabilities in `defineGame({ systems })` instead of a manual `onTick` fan-out. Full contract: [reference-systems.md](reference-systems.md).
**Import from the curated barrel** `@jgengine/core/gameplay` (stable, re-exports this domain's public API) — deep paths `@jgengine/core/<domain>/<file>` still work for anything not re-exported. **Composable systems** — `defineSystem` / `composeGameLoop` / `compileSystemSchedule` / `DEFAULT_FIXED_STAGES` / `DEFAULT_FRAME_STAGES` / `SystemDefinition` / `SystemTick` / `SystemEventHandlers` / `CompiledSystemSchedule`: list capabilities in `defineGame({ systems })` instead of a manual `onTick` fan-out. Full contract: [reference-systems.md](reference-systems.md).

## Content catalogs

Expand Down
13 changes: 11 additions & 2 deletions .claude/skills/jgengine-gameplay/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@
- `BindingOverrides` (type): type BindingOverrides = Record<string, ActionCodes> — Player-rebound keys, keyed by action name. Values mirror an `ActionCodes` entry so hold/toggle/repeat semantics survive a rebind — the settings menu only swaps which physical codes drive the action.
- `CAMERA_FRUSTUM_DEFAULTS` (const): const CAMERA_FRUSTUM_DEFAULTS: { readonly fov: 55; readonly near: 0.1; readonly far: 300; readonly zoom: 50; } — ⚠ undocumented
- `CameraKeyframe` (interface): interface CameraKeyframe — One stop on a scripted camera path (#29).
- `CameraRigKind` (type): type CameraRigKind = | "orbit" | "first" | "topDown" | "rts" | "shoulder" | "lockOn" | "chase" | "observer" | "turntable" | "sideScroll" | "inspection" | "none" — Which camera rig the shell mounts. Every rig accepts `followEntityId: null` (avatar-less games — city-builders, card games, auto-battlers — still get a camera). Rigs are tuned through their config block below, never by writing camera positions from `onTick`. - `orbit` — third-person chase (the historical default; `perspective: "third"`). - `first` — pointer-lock mouse-look (`perspective: "first"`). - `topDown` — fixed height/pitch/yaw with decoupled follow (ARPG iso, top-down). - `rts` — free-pan / edge-scroll / rotate / zoom, optional follow. - `shoulder` — over-the-shoulder with ADS transition + shoulder swap. - `lockOn` — yaw bound to the player→target vector; move axis becomes strafe. - `chase` — speed-reactive vehicle chase (speed→FOV, spring arm, shake) + cockpit/hood/rear views. - `observer` — detached spectator/photo cam bound to any entity or fixed point; never reads player input. - `turntable` — slow auto-orbit of a fixed point: a rotating display stand for a scene. The friendly, flat spelling of `observer`'s point-orbit mode; providing `camera.turntable` selects it without an explicit `rig`. - `sideScroll` — fixed lateral follow (2.5D platformer/beat-'em-up side view); reads no player input. - `inspection` — model-viewer rig (#207.7): left-drag orbit, middle/right-drag pan, scroll zoom toward a configurable anchor; orbits a fixed point, reads no player/entity input. - `none` — no camera rig is mounted; use for HUD-only presentations or a game that manages its own camera.
- `CameraRigKind` (type): type CameraRigKind = | "orbit" | "first" | "topDown" | "rts" | "shoulder" | "lockOn" | "chase" | "observer" | "turntable" | "sideScroll" | "inspection" | "none" — Which camera rig the shell mounts. Every rig accepts `followEntityId: null` (avatar-less games — city-builders, card games, auto-battlers — still get a camera). Rigs are tuned through their config block below, never by writing camera positions from `onTick`. - `orbit` — third-person chase (the historical default; `perspective: "third"`). - `first` — pointer-lock mouse-look (`perspective: "first"`). - `topDown` — fixed height/pitch/yaw with decoupled follow (ARPG iso, top-down). - `rts` — free-pan / edge-scroll / rotate / zoom, optional follow. - `shoulder` — over-the-shoulder with ADS transition + shoulder swap. - `lockOn` — yaw bound to the player→target vector; move axis becomes strafe. - `chase` — speed-reactive vehicle chase (speed→FOV, spring arm, shake) + cockpit/hood/rear views. - `observer` — detached spectator/photo cam bound to any entity or fixed point; never reads player input. - `turntable` — slow auto-orbit of a fixed point: a rotating display stand for a scene. The friendly, flat spelling of `observer`'s point-orbit mode; providing `camera.turntable` selects it without an explicit `rig`. - `sideScroll` — fixed lateral follow (2.5D platformer/beat-'em-up side view); reads no player input. - `inspection` — model-viewer / editor rig (#207.7, #866): middle-drag pan, right-drag orbit, scroll zoom toward a configurable anchor; orbits a fixed point, reads no player/entity input. - `none` — no camera rig is mounted; use for HUD-only presentations or a game that manages its own camera.
- `CardPile` (interface): interface CardPile — ⚠ undocumented
- `CardPileState` (interface): interface CardPileState — ⚠ undocumented
- `Cell` (type): type Cell = readonly [number, number] — ⚠ undocumented
Expand All @@ -710,12 +710,15 @@
- `CinematicCameraConfig` (interface): interface CinematicCameraConfig — Scripted keyframe / path player (#29). When set it overrides the active rig.
- `CombatTelegraphEvent` (interface): interface CombatTelegraphEvent — ⚠ undocumented
- `CombatVfxEvent` (interface): interface CombatVfxEvent — A transient sprite-particle effect the shell renders once and expires — one burst of `kind`, tinted `color`, anchored at `from` (and `to` for travel/beam effects).
- `CompiledSystemSchedule` (interface): interface CompiledSystemSchedule — Deterministic compiled schedule: stage buckets, multi-subscribe channels, dependency validation. Order never depends on import order — only stage tables + explicit before/after constraints.
- `CropDef` (interface): interface CropDef — ⚠ undocumented
- `CropTileState` (interface): interface CropTileState — ⚠ undocumented
- `Curve` (type): type Curve = CurveDef & CurveShape — ⚠ undocumented
- `DEFAULT_CHAT_BODY_LENGTH` (const): const DEFAULT_CHAT_BODY_LENGTH: 500 — ⚠ undocumented
- `DEFAULT_CHAT_HISTORY_LIMIT` (const): const DEFAULT_CHAT_HISTORY_LIMIT: 100 — ⚠ undocumented
- `DEFAULT_CHAT_RATE_LIMIT` (const): const DEFAULT_CHAT_RATE_LIMIT: ChatRateLimit — ⚠ undocumented
- `DEFAULT_FIXED_STAGES` (const): const DEFAULT_FIXED_STAGES: readonly ["input", "movement", "combat", "ai", "activities", "cleanup"] — Default fixed-sim stage order — systems pick a stage; most need only this.
- `DEFAULT_FRAME_STAGES` (const): const DEFAULT_FRAME_STAGES: readonly ["input", "movement", "combat", "ai", "activities", "cleanup", "animation", "camera", "effects"] — Default frame stage order. Gameplay stages mirror the fixed table so once-per-frame systems (`type: "frame"`) can pick `combat`/`ai`/… without falling into the unknown-stage bucket; presentation stages follow.
- `DEFAULT_PICKUP_RADIUS` (const): const DEFAULT_PICKUP_RADIUS: 2 — ⚠ undocumented
- `DEFAULT_PING_CATEGORIES` (const): const DEFAULT_PING_CATEGORIES: Record<PingCategory, PingCategoryDef> — Content-agnostic default ping wheel: enemy / loot / location / danger.
- `DEFAULT_TOUCH_STYLE` (const): const DEFAULT_TOUCH_STYLE: TouchStyle — Skin used when neither the game nor the player picks one.
Expand Down Expand Up @@ -817,6 +820,9 @@
- `Social` (interface): interface Social — ⚠ undocumented
- `SocialDeps` (interface): interface SocialDeps — ⚠ undocumented
- `StatLevelUpEvent` (interface): interface StatLevelUpEvent — ⚠ undocumented
- `SystemDefinition` (interface): interface SystemDefinition — A reusable game capability — lifecycle, timing, events, and optional save / replication / reset / disposal. Pass instances via `defineGame({ systems })`. Prefer one system per meaningful capability (`combat`, `quests`), not per micro-tick.
- `SystemEventHandlers` (type): type SystemEventHandlers = { readonly [eventName: string]: (ctx: GameContext, event: unknown) => void; } — Event name → handler. Payload is the engine event shape for that name.
- `SystemTick` (type): type SystemTick = | { type: "fixed"; /** Steps per game-second. Default 60. */ rate?: number; stage?: string; after?: string | readonly string[]; before?: string | readonly string[]; } | { type: "frame"; stage?: string; after?: string | readonly string[]; before?: string | readonly string[]; } | { t… — How a system is scheduled. Omit `tick` (or use only `events`) for event-driven systems. Multiple systems may share the same channel; order within a channel is deterministic by stage then optional `before`/`after` constraints — never import order.
- `TOUCH_STYLES` (const): const TOUCH_STYLES: readonly TouchStyle[] — Every touch skin id, in menu order.
- `TOUCH_STYLE_OPTIONS` (const): const TOUCH_STYLE_OPTIONS: readonly { value: TouchStyle; label: string }[] — Touch skins as `{ value, label }` rows for the Settings → Controls selector.
- `TalentNodeDef` (interface): interface TalentNodeDef<TStat extends string = string> — ⚠ undocumented
Expand Down Expand Up @@ -849,6 +855,8 @@
- `charge` (function): function charge(state: WalletState, currency: string, amount: number, options?: ChargeOptions): ChargeResult — Deduct `amount`, rejecting when it would leave the balance negative unless `options.overdraft` opts into carrying debt (`true` unlimited, `{ max }` capped) — the strict same-tick affordability check stays the default with `options` omitted.
- `chargeAll` (function): function chargeAll(state: WalletState, costs: Readonly<Record<string, number>>, options?: ChargeOptions): ChargeResult — ⚠ undocumented
- `clearBindingOverride` (function): function clearBindingOverride(gameId: string, action: string, storage: Pick<WebStorageLike, "getItem" | "setItem" | "removeItem"> | null | undefined = defaultStorage()): BindingOverrides — ⚠ undocumented
- `compileSystemSchedule` (function): function compileSystemSchedule(systems: readonly SystemDefinition[], options?: CompileSystemScheduleOptions): CompiledSystemSchedule — Compile system definitions into a deterministic schedule. Validates unique ids, `dependsOn`, and before/after cycles.
- `composeGameLoop` (function): function composeGameLoop(systems: readonly SystemDefinition[] | undefined, loop: GameLoop<GameContext> | undefined, options?: ComposeGameLoopOptions): GameLoop<GameContext> — Merge a system list with an optional classic `GameLoop` into one loop the shell/runners drive. Systems install on first `onInit`; classic hooks still run for incremental migration.
- `computeEffectiveStats` (function): function computeEffectiveStats(def: ModularItemDef, installed: readonly InstalledPart[]): Record<string, number> — ⚠ undocumented
- `craft` (function): function craft(state: InventoryState, layout: InventoryLayout, traits: ItemTraits, recipe: RecipeDef, context: CraftContext = {}): CraftResult — ⚠ undocumented
- `craftSeconds` (function): function craftSeconds(recipe: RecipeDef): number — ⚠ undocumented
Expand Down Expand Up @@ -901,7 +909,8 @@
- `createUnlocks` (function): function createUnlocks(defs: UnlockDef[] = []): Unlocks — ⚠ undocumented
- `createWeaponStats` (function): function createWeaponStats(resolveEntry: (itemId: string) => WeaponEntry | null | undefined): WeaponStats — Resolve per-weapon stat values — damage, fire rate, spread — for combat math.
- `curve` (function): function curve(spec: Curve): (x: number) => number — ⚠ undocumented
- `defineGame` (function): function defineGame<TAssetRef extends ModelAssetRef, TMultiplayer>(config: GameDefinitionConfig<TAssetRef, TMultiplayer>): GameDefinition<TAssetRef, TMultiplayer> — Task-first entry point for authoring a game: fills in `scene` and default `assets`, validates `name`.
- `defineGame` (function): function defineGame<TAssetRef extends ModelAssetRef, TMultiplayer>(config: GameDefinitionConfig<TAssetRef, TMultiplayer>): GameDefinition<TAssetRef, TMultiplayer> — Task-first entry point for authoring a game: fills in `scene` and default `assets`, validates `name`, OR-merges `features` from installed systems, and composes `loop` from `systems` + any classic hooks.
- `defineSystem` (function): function defineSystem(definition: SystemDefinition): SystemDefinition — Declare a composable game system. Pure data + hooks — the engine compiles the schedule and installs lifecycle when the game boots.
- `deriveTouchScheme` (function): function deriveTouchScheme(input: ActionCodesMap | undefined, { reserved, firstPerson, config }: DeriveTouchSchemeOptions): TouchScheme | null — Null means "render no touch controls" — either the game opted out or there is nothing to synthesize.
- `dialogueSlot` (const): const dialogueSlot: StoreHandle<string | undefined> — Typed handle onto the open-dialogue slot — React reads it via `useOpenDialogueId`; game code uses `ctx.game.dialogue`.
- `drainOutput` (function): function drainOutput(state: ProductionState, itemId: string, count?: number): { state: ProductionState; taken: number } — ⚠ undocumented
Expand Down
16 changes: 16 additions & 0 deletions .claude/skills/jgengine-gameplay/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p

- `createRecordBook` (function) · `import { createRecordBook } from "@jgengine/core/gameplay"`

## compose-game-loop — fold composable systems into the game loop without a manual tick fan-out

- `composeGameLoop` (function) · `import { composeGameLoop } from "@jgengine/core/gameplay"`

## consumables — use/consume items with cooldowns and effects

- `createItemUse` (function) · `import { createItemUse } from "@jgengine/core/gameplay"`
Expand All @@ -20,6 +24,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p

- `createDecayMeterSet` (function) · `import { createDecayMeterSet } from "@jgengine/core/gameplay"`

## define-game — single public game-authoring path — compose systems, world, and loop in one definition

- `defineGame` (function) · `import { defineGame } from "@jgengine/core/gameplay"`

## dialogue-bridge — open/close the talkable→DialogueBox flow with no per-game store or command glue

- `createGameDialogue` (function) · `import { createGameDialogue } from "@jgengine/core/gameplay"`
Expand All @@ -40,6 +48,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p

- `createSaveStore` (function) · `import { createSaveStore } from "@jgengine/core/gameplay"`

## game-system — declare a composable capability with its own schedule and lifecycle

- `SystemDefinition` (interface) · `import { SystemDefinition } from "@jgengine/core/gameplay"`

## item-instance-registry — a runtime store for procedurally generated item instances

- `createItemInstanceRegistry` (function) · `import { createItemInstanceRegistry } from "@jgengine/core/gameplay"`
Expand Down Expand Up @@ -137,6 +149,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p

- `createSpawnPoints` (function) · `import { createSpawnPoints } from "@jgengine/core/gameplay"`

## system-schedule — compile fixed/frame/interval system ticks into deterministic ordered stages

- `compileSystemSchedule` (function) · `import { compileSystemSchedule } from "@jgengine/core/gameplay"`

## toast-feed — queue of transient self-expiring on-screen messages (toasts, announcer, kill-feed)

- `appendToast` (function) · `import { appendToast } from "@jgengine/core/gameplay"`
Expand Down
Loading
Loading