@jgengine/assets 0.18.1 → 0.21.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.
@@ -12,6 +12,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
12
12
 
13
13
  - `collectAuthoredTriggers` (function) · `import { collectAuthoredTriggers } from "@jgengine/shell/gameKit"`
14
14
 
15
+ ## chase-view-cycle — cycle a vehicle camera between chase, hood and cockpit views at runtime
16
+
17
+ - `nextChaseView` (function) · `import { nextChaseView } from "@jgengine/core/runtime/cameraDirector"`
18
+
15
19
  ## client-side — input prediction with replay reconciliation
16
20
 
17
21
  - `createPredictionBuffer` (function) · `import { createPredictionBuffer } from "@jgengine/core/runtime/prediction"`
@@ -20,6 +24,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
20
24
 
21
25
  - `GameContextModels` (interface) · `import { GameContextModels } from "@jgengine/core/runtime/gameContext"`
22
26
 
27
+ ## command-number — validate finite, bounded numbers and integers at command boundaries
28
+
29
+ - `readInputNumber` (function) · `import { readInputNumber } from "@jgengine/core/runtime/commandInput"`
30
+
31
+ ## command-parse — parse untrusted command input once so every command stage sees typed, bounded values
32
+
33
+ - `defineCommand` (function) · `import { defineCommand } from "@jgengine/core/runtime/commandRunner"`
34
+
23
35
  ## command-quantity — validate bounded whole-item counts at command boundaries
24
36
 
25
37
  - `readQuantity` (function) · `import { readQuantity } from "@jgengine/core/runtime/commandInput"`
@@ -40,6 +52,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
40
52
 
41
53
  - `EditorCatalogDefinition` (interface) · `import { EditorCatalogDefinition } from "@jgengine/shell/gameKit"`
42
54
 
55
+ ## fire-input — bind a key or mouse button to a named action that runs the same-named command with the aim; repeatMs auto-fires while held
56
+
57
+ - `ActionCodesMap` (type) · `import { ActionCodesMap } from "@jgengine/core/authoring"`
58
+
43
59
  ## game-system — declare a composable capability with its own schedule and lifecycle
44
60
 
45
61
  - `SystemDefinition` (interface) · `import { SystemDefinition } from "@jgengine/shell/gameKit"`
@@ -96,6 +112,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
96
112
 
97
113
  - `createInputRecorder` (function) · `import { createInputRecorder } from "@jgengine/core/runtime/inputRecorder"`
98
114
 
115
+ ## local-players — Couch co-op seats: devices hot-join into slots, each with its own user id and input snapshot.
116
+
117
+ - `createLocalPlayers` (function) · `import { createLocalPlayers } from "@jgengine/core/runtime/localPlayers"`
118
+
99
119
  ## loot-table — validate a loot table definition for use with the registry
100
120
 
101
121
  - `lootTable` (function) · `import { lootTable } from "@jgengine/core/authoring"`
@@ -178,6 +198,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
178
198
 
179
199
  - `defineStore` (function) · `import { defineStore } from "@jgengine/shell/gameKit"`
180
200
 
201
+ ## warn-once — emit a dev-only warning a single time per call site
202
+
203
+ - `warnOnce` (function) · `import { warnOnce } from "@jgengine/core/devtools/warnOnce"`
204
+
181
205
  ## world-chunk-key — map world positions to persisted chunk keys at a declared cell size
182
206
 
183
207
  - `chunkKeyOf` (function) · `import { chunkKeyOf } from "@jgengine/core/runtime/worldChunks"`
@@ -193,3 +217,7 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
193
217
  ## world-environment — compose editor/preset-derived outdoor dressing — terrain, weather, water, structures — into a legacy environment feature
194
218
 
195
219
  - `environment` (function) · `import { environment } from "@jgengine/shell/gameKit"`
220
+
221
+ ## world-item-pickup — pick up dropped items: ctx.scene.worldItem nearestInRadius → pickup into the player's inventory
222
+
223
+ - `SceneWorldItemContext` (interface) · `import { SceneWorldItemContext } from "@jgengine/core/runtime/gameContext"`
@@ -6,6 +6,11 @@ authored scene edited in the browser, one system, one store slot, an empty-canva
6
6
  and a win condition. Every new game starts here; add combat, multiplayer, or deeper
7
7
  world features only after this loop plays.
8
8
 
9
+ Every extension follows the [framework-first decision](../SKILL.md#framework-first-decisions):
10
+ compose an installed SDK capability, improve its upstream contract if needed, then
11
+ remove superseded game glue after published adoption. The game owns its rules and art;
12
+ it should not recreate input, model lifecycle, storage or UI accessibility machinery.
13
+
9
14
  ## 1. Scaffold
10
15
 
11
16
  `npx jgengine create <name>` (inside the engine monorepo: `bun run new:game "<id-or-title>"`).
@@ -45,6 +50,9 @@ spatial place. When the game *is* a place, declare only substrate + laws with `w
45
50
  `@jgengine/core/world/place` (e.g. `{ id, ground: { mode: "flat", size: { x: Infinity, z: Infinity } }, physics: { gravity: -24 } }`,
46
51
  or `mode: "board"` for 2D). Never seed, sky, or vegetation in `world` — the engine renders its
47
52
  default sky until you author one in the editor, and foliage is editor scatter over the ground.
53
+ A created 3D game instead ships hills as a terrain sculpt in `editor.scene.json` and a `world.ts`
54
+ that consumes it with `environment({ sculpt })` via `environmentContentFromDocument`; the file
55
+ holds only the ground palette. Reshape the hills in the editor, not in code.
48
56
 
49
57
 
50
58
  ```ts
@@ -77,8 +85,8 @@ direction. Compose the shipped building blocks the moment you need them (`StatBa
77
85
  `Coins`, `InventoryGrid`, `CharacterSheet`, window shells from `jgengine-ui`), then reskin via
78
86
  `HudTheme` tokens. Reaching for those is using the engine correctly, not incomplete work. What
79
87
  the engine does not ship is a whole finished game *face* or genre theme preset — do not leave an
80
- unarranged, unskinned generic dashboard as the product. Hand-roll markup only where no building
81
- block fits (see `jgengine-ui`).
88
+ unarranged, unskinned generic dashboard as the product. Custom markup can use headless
89
+ SDK behavior; a missing reusable behavior is an upstream gap (see `jgengine-ui`).
82
90
 
83
91
  ## 3. Author, play, win
84
92
 
@@ -13,27 +13,49 @@ Search [capabilities.md](capabilities.md) before adding a resolver or catalog pa
13
13
 
14
14
  ## Canonical workflow
15
15
 
16
- 1. Prefer existing catalog entries and typed asset refs.
16
+ 1. Choose a palette from the game's art direction: silhouette, materials, scale, era, and visual language. Search existing catalog entries and typed asset refs against that palette; catalog availability does not choose the game's look.
17
17
  2. Verify source license and attribution requirements before download.
18
18
  3. Record canonical facing, source units, pivot, footprint, bounds, and placement policy in metadata.
19
19
  4. Pull/index through shared tooling; do not commit remote-library bulk bytes when the catalog is designed to resolve them.
20
20
  5. Preview through the same resolver runtime will use.
21
21
  6. Add required credit in the same PR.
22
22
 
23
+ Reuse import, validation, catalog, and rendering tools to save time. Each game owns its asset selection and visual identity. Source or import licensed assets when the catalog does not fit; do not substitute the same convenient pack into every game. Validate a representative set in the actual scene before filling the world with it. Keep that reviewed palette consistent within the game without treating it as an SDK preset.
24
+
23
25
  ## Reference integrity
24
26
 
25
27
  Every logical asset id has a declared owner: `committed` (a single's shipped URL, resolves on a clean clone), `provisioned` (a pack index entry whose GLB is fetched by `assets pull <source>`), or `dangling` (nothing owns it — a broken contract). Resolve one id with `resolveProvenance(id)`; gate a set of references with `validateAssetReferences(refs)`, which fails on any dangling reference and reports the exact `assets pull <source>` steps a clean checkout still needs. `assets provenance <id>...` exposes the same contract on the CLI and exits non-zero on a dangling id. This resolves references structurally against the catalog — never grep source text as the long-term contract.
26
28
 
27
- A game's catalog is `buildCatalog(...)` over the generated pack index, singles, and aliases; `extras` is its durable escape hatch for assets that aren't in a pack. An editor asset import into a **promoted** game project writes into that `extras` array in `src/game/assets.ts` (bytes land in `public/<basePath>/imported/`), registered after packs (last-writer-wins) and before aliases (so an alias can target one — see `jgengine-editor`). At runtime an extra resolves to exactly its `{ url }`; the `label` is human-facing only and never enters the catalog.
29
+ A game's catalog is `buildCatalog(...)` over the generated pack index, singles, and aliases; `extras` is its durable escape hatch for assets that aren't in a pack. An editor asset import into a **promoted** game project writes into that `extras` array in `src/game/assets.ts` (bytes land in `public/<basePath>/imported/`), registered after packs (last-writer-wins) and before aliases (so an alias can target one — see `jgengine-editor`). At runtime a model extra resolves to its URL and authored `dims`, `space`, `clips` and `collisionMesh`; the `label` is human-facing only and never enters the catalog.
30
+
31
+ For game-owned media, validate `AssetImportSpec` from untrusted input and classify complete bytes with `classifyAssetFile` before choosing a loader. Preserve relative paths, custom roles and JSON metadata; use the [custom import recipe](references/custom-imports.md) for models, textures, sprites, materials, audio, fonts and HDRI. Classification is a format check, not an image/audio/font decoder.
28
32
 
29
33
  At load time the shell classifies a model fetch before parsing via `classifyAssetResponse` (`@jgengine/core/scene/assetDiagnostics`), so a missing file, a dev-server HTML fallback, corrupt bytes, or a non-model format surface as an actionable diagnostic naming the URL — not an opaque GLTF parse error.
30
34
 
31
35
  Reindex measures every GLB's `dims`; assets listed in `COLLISION_MESH_ASSET_IDS` (`collisionMeshAssets.ts`) additionally ship a compact quantized triangle mesh (`collisionMesh` on the index entry) that collider auto-fit raycasts instead of the fitted box — opt in only concave models whose box lies (archways, rings, frames), because each entry adds real index bytes and per-ray BVH cost. Reindex also records every GLB's animation `clips` (names read from the JSON chunk via `readGlbClips`), which flow through `buildCatalog` onto the resolved `ModelAssetRef` — the editor's browser badges rigged assets from it.
32
36
 
37
+ ## Offline asset budgets
38
+
39
+ Run `assets budget <file|directory> --max-bytes <n> --max-triangles <n> --max-texture-dimension <n> --json` on the game's own GLBs before wiring imports. The directory can contain custom art, editor imports, or provisioned packs; it need not be a declared source. Limits belong to the game and apply per model; omit them to inspect. A failing report names each file and exceeded limit, and exits non-zero for CI. Missing GLBs, unreadable geometry/images, remote resources, or required geometry compression fail inspection instead of appearing as zero cost.
40
+
41
+ `readGlbMetrics` measures stored mesh primitives once, not scene instances or GPU memory. PNG, JPEG, WebP, and KTX2 dimensions come from image headers. Model bytes include the GLB and unique external resource URIs; local resources must stay inside the scanned directory. Reindex records successful inspection under `IndexEntry.metrics`; old entries remain valid, so gate the actual served bytes rather than assuming every index entry has measurements. This reports cost and never changes art, encodes compression, or generates LODs.
42
+
43
+ ## Editor-authored static prefab exports
44
+
45
+ Keep composition parts and visible placements in `editor.scene.json`. Add `staticBake` settings to the editable prefab through editor commands, then call `bakeStaticPrefab` in Node/Bun through `@jgengine/assets/staticPrefabBake`. Pin every original GLB by catalog id, absolute read path, byte count and SHA-256. Pin external textures by their exact source URI and full runtime URL; basename matching loses ownership when different art uses the same filename. Paths are only I/O inputs; output reports contain portable hashes and logical ids.
46
+
47
+ The exporter retains source geometry, PBR surfaces, UVs and image URLs, applies each prop's local position, radian yaw and `meta.verticalOffset`, and combines static parts by source material. It rejects animations, skins, morph targets, interactive markers, unsupported transforms and non-model fragment content. Keep such content outside a static artifact. Material overrides also remain outside this bake; an authored assignment must not silently disappear into the source surface.
48
+
49
+ Register the output GLB with its returned `dims`, `space`, `anchor: "origin"` and `collisionMesh`. Origin anchoring preserves the prefab's frame; fitted centering or target-height normalization changes authored placement. Omitted `collisionBoxes` produce a conservative closed exterior; author explicit solid boxes and clearance boxes to preserve openings. Export fails when a clearance overlaps a movement solid. Reports include source-fragment and bake-settings hashes, GLB bytes, total GLB plus unique external-image bytes (`byteLength`), triangles, material submissions, bounds and verified source pins. Repeated export of the same authored data and pinned bytes must match.
50
+
51
+ After package publication and the shared consumer upgrade, delete the equivalent game-local exporter and runtime composition arrays or rendering glue. Keep each game's original catalog selection, credits and art; a prefab export is not a game template.
52
+
33
53
  ## Rigged assets animate by default
34
54
 
35
55
  A model resolved from a catalog string id is stamped `animation: "auto"`: the shell derives speed-driven `idle`/`walk`/`run` states plus `hit`/`death`/`attack` one-shots from the loaded GLB's own clip names via semantic clip roles (`@jgengine/core/game/clipRoles` — `classifyClip`, `defaultAnimationForClips`, exported `DEFAULT_CLIP_ROLE_TABLE` covering KayKit/Quaternius/Mixamo naming). No game-side clip strings needed; a clipless model is unaffected. An explicit `ModelConfig.animation`/`style.animation` always wins, and `animation: "none"` opts a placement back to the bind pose. Games rendering cloned scenes themselves get the same driver from `@jgengine/shell/render/useModelAnimation` instead of hand-rolling an `AnimationMixer`.
36
56
 
57
+ Material sources declare the map roles in their pinned archive through `AssetSource.materialMaps`; `pull` checks those declarations before writing. `buildMaterialCatalog` omits absent `ao`, `roughness`, and `ktx2` URLs. Pass the returned maps directly to model, building, or terrain seams, or explicitly supply a game-owned map. Do not construct optional map filenames or fill every material with synthetic AO. Check the actual archive when changing availability; ambientCG API map metadata covers the catalog, while byte verification covers the downloaded variants.
58
+
37
59
  ## Source rules
38
60
 
39
61
  - Never use or reference Kenney.nl assets.
@@ -46,4 +68,3 @@ A model resolved from a catalog string id is stamped `animation: "auto"`: the sh
46
68
  - Fix wrong scale/facing/pivot upstream in catalog metadata, never with per-game corrective transforms.
47
69
  - Asset ids and metadata are stable data contracts; filenames and URLs are implementation details.
48
70
  - Missing attribution is a release blocker even when the code works.
49
-
@@ -4,59 +4,61 @@
4
4
 
5
5
  ## @jgengine/assets
6
6
 
7
- - `AssetAlias` (interface): interface AssetAlias — ⚠ undocumented
7
+ - `AssetAlias` (interface): interface AssetAlias { key: string; target: string } — ⚠ undocumented · used by `aliases`: Semantic keys → live catalog ids.
8
8
  - `AssetDownload` (type): type AssetDownload = PinnedDownload | ScrapeDownload — ⚠ undocumented
9
9
  - `AssetImportKind` (type): type AssetImportKind = "model" | "texture" | "material" | "sprite" | "spriteSheet" | "audio" | "font" | "hdri" — Supported logical kinds for user-supplied assets.
10
- - `AssetImportSpec` (interface): interface AssetImportSpec — A validated description of files to ingest into a game project.
10
+ - `AssetImportSpec` (interface): interface AssetImportSpec — A game-owned import description; paths are relative POSIX paths, roles are authored labels.
11
11
  - `AssetKind` (type): type AssetKind = "model" | "pack" | "material" | "component" | "icon" | "sprite" | "spritePack" — ⚠ undocumented
12
- - `AssetMatch` (type): type AssetMatch = | { kind: "model"; id: string; source: string; file?: string; via: "index" | "alias" | "single" } | { kind: "pack"; source: string; title: string; categories: readonly string[] } | { kind: "material"; id: string; title: string; categories: readonly string[] } | { kind: "component";… — ⚠ undocumented
12
+ - `AssetMatch` (type): type AssetMatch = | { kind: "model"; id: string; source: string; file?: string; via: "index" | "alias" | "single" } | { kind: "pack"; source: string; title: string; categories: readonly string[] } | { kind: "material"; id: string; title: string; categories: readonly string[] } | { kind: "component";… — ⚠ undocumented · used by `findAssets`: The ranked matches for a query — models, packs, HUD components, and icons in one list.
13
13
  - `AssetProvenance` (interface): interface AssetProvenance — The resolved ownership of one logical asset id — the provisioning contract for that id.
14
14
  - `AssetProvenanceKind` (type): type AssetProvenanceKind = "committed" | "provisioned" | "dangling" — How an asset id's bytes reach a clean checkout: - `committed` — resolves to a self-hosted / remote URL carried in the shipped index (a {@link SingleAsset}); no pull step, available immediately. - `provisioned` — a pack {@link IndexEntry}; the id is declared but its GLB is fetched on demand by `assets pull <source>` into the consumer's served dir. - `dangling` — nothing in the index, singles, or aliases owns the id, so no provisioning step exists and it can never resolve on a clean clone.
15
15
  - `AssetProvider` (type): type AssetProvider = | "quaternius" | "kaykit" | "polypizza" | "itch" | "ambientcg" | "gameicons" | "custom" — ⚠ undocumented
16
16
  - `AssetReference` (interface): interface AssetReference — A logical asset id referenced by some consumer (a game, scene, or config), for validation.
17
- - `AssetSource` (interface): interface AssetSource — ⚠ undocumented
17
+ - `AssetSource` (interface): interface AssetSource { id: string; kind?: AssetSourceKind; provider: AssetProvider; title: string; license: string; author: string; categories: readonly string[]; download: AssetDownload; homepage?: string; materialMaps?: readonly MaterialMapRole[]; mirror?: st… — ⚠ undocumented · used by `ambientcgSources`: Every ambientCG material source, generated per family (`ambientcg-grass001` … ).
18
18
  - `AssetSourceKind` (type): type AssetSourceKind = "model" | "material" | "sprite" — What a source's archive contains: GLB models (default), one PBR material's texture maps, or a pack of individual 2D sprite/icon files (SVG/PNG).
19
19
  - `AssetSpace` (interface): interface AssetSpace — Catalog-level asset-space metadata: how a model is authored relative to the engine, owned by the catalog entry rather than re-derived per game. Every field is optional so an unmeasured asset stays valid; {@link resolveFacingRotationY}/{@link assetUnitScale}/{@link resolveAnchorOffset} supply the documented defaults.
20
- - `BuildCatalogOptions` (interface): interface BuildCatalogOptions — ⚠ undocumented
20
+ - `BuildCatalogOptions` (interface): interface BuildCatalogOptions { basePath?: string; sources?: readonly string[]; includeAliases?: boolean; includeSingles?: boolean; extras?: readonly CatalogExtra[] } — ⚠ undocumented · used by `buildCatalog`: Builds a game's asset catalog from the generated CC0 pack index plus singles, extras, and aliases.
21
21
  - `BuildMaterialCatalogOptions` (interface): interface BuildMaterialCatalogOptions — Options for `buildMaterialCatalog`.
22
22
  - `BuildSpriteCatalogOptions` (interface): interface BuildSpriteCatalogOptions — Options for `buildSpriteCatalog`.
23
23
  - `CollisionMeshData` (interface): interface CollisionMeshData — Compact, serializable triangle collision mesh measured at asset reindex — the renderer-free source of mesh-accurate hitboxes. Positions are welded onto a 16-bit grid spanning `min`..`max` (model space) and stored base64-encoded, so an opted-in catalog asset ships its collision triangles inside the generated index without the runtime ever touching the rendered scene graph.
24
24
  - `ExtractedMaterialMap` (interface): interface ExtractedMaterialMap — One normalized map pulled out of a material archive by `extractMaterialMaps`.
25
25
  - `ExtractedSpriteFile` (interface): interface ExtractedSpriteFile — One SVG/PNG file pulled out of a sprite/icon-pack archive by `extractSpriteFiles`.
26
- - `FindOptions` (interface): interface FindOptions — ⚠ undocumented
27
- - `ImportSpecValidation` (type): type ImportSpecValidation = { ok: true; entry: AssetImportSpec } | { ok: false; reason: string } — Result of validating an import description.
28
- - `IndexEntry` (interface): interface IndexEntry — ⚠ undocumented
26
+ - `FindOptions` (interface): interface FindOptions { kind?: AssetKind; limit?: number } — ⚠ undocumented · used by `findAssets`: The ranked matches for a query — models, packs, HUD components, and icons in one list.
27
+ - `GlbMetrics` (interface): interface GlbMetrics — Stored geometry and image inventory; triangles count mesh primitives once, regardless of scene instances.
28
+ - `GlbTextureMetrics` (interface): interface GlbTextureMetrics — Dimensions and encoded bytes for one glTF image, including images referenced by texture extensions.
29
+ - `ImportSpecValidation` (type): type ImportSpecValidation = { ok: true; entry: AssetImportSpec } | { ok: false; reason: string } — Result of validating an import description; a successful entry is an independent JSON snapshot.
30
+ - `IndexEntry` (interface): interface IndexEntry — A source-owned model or sprite id, with optional offline model measurements.
29
31
  - `MATERIAL_MAP_FILES` (const): const MATERIAL_MAP_FILES: { readonly color: "color.jpg"; readonly normal: "normal.jpg"; readonly roughness: "roughness.jpg"; readonly ao: "ao.jpg"; readonly displacement: "displacement.jpg"; readonly ktx2: "material.ktx2"; } — Normalized filenames a pulled material directory contains, keyed by map role.
30
32
  - `MaterialCatalog` (interface): interface MaterialCatalog — Resolves material ids and `material/…` aliases to `MaterialRef`s.
31
33
  - `MaterialMapRole` (type): type MaterialMapRole = keyof typeof MATERIAL_MAP_FILES — One PBR map's role within a material, including an optional compressed KTX2 asset.
32
- - `MaterialMaps` (interface): interface MaterialMaps — URLs of one material's PBR maps; `ao`/`displacement` files may be absent from a rare pack.
34
+ - `MaterialMaps` (interface): interface MaterialMaps — URLs of one material's PBR maps; `ao`/`roughness`/`ktx2` appear only when declared by its source.
33
35
  - `MaterialRef` (interface): interface MaterialRef — A resolved material: identity, attribution, and its normalized map URLs.
34
36
  - `ModelDims` (interface): interface ModelDims — Measured horizontal footprint, footprint center, and lowest Y of a model in model space.
35
- - `ModelSnippetOptions` (interface): interface ModelSnippetOptions — ⚠ undocumented
36
- - `PinnedDownload` (interface): interface PinnedDownload — ⚠ undocumented
37
- - `RankedMatch` (interface): interface RankedMatch — ⚠ undocumented
37
+ - `ModelSnippetOptions` (interface): interface ModelSnippetOptions { basePath?: string; seam?: "objectModels" | "entityModels" } — ⚠ undocumented · used by `modelWiringSnippet`: Copy-paste wiring for a pulled GLB id: resolve through the catalog, drop into a model seam.
38
+ - `PinnedDownload` (interface): interface PinnedDownload { url: string; sha256?: string } — ⚠ undocumented
39
+ - `RankedMatch` (interface): interface RankedMatch { match: AssetMatch; score: number } — ⚠ undocumented · used by `rankAssets`: Rank every catalog entry — models, packs, HUD components, icons — against one query.
38
40
  - `ReferenceValidation` (interface): interface ReferenceValidation — The verdict for one {@link AssetReference}.
39
- - `RegistryCatalog` (interface): interface RegistryCatalog — ⚠ undocumented
40
- - `RegistryComponent` (interface): interface RegistryComponent — ⚠ undocumented
41
+ - `RegistryCatalog` (interface): interface RegistryCatalog { homepage: string; components: readonly RegistryComponent[]; icons: readonly string[] } — ⚠ undocumented
42
+ - `RegistryComponent` (interface): interface RegistryComponent { name: string; title: string; description: string } — ⚠ undocumented · used by `componentWiringSnippet`: Copy-paste wiring for a HUD component: the `shadcn add` command plus import + usage.
41
43
  - `ReindexSpritesResult` (interface): interface ReindexSpritesResult — Per-source and total counts returned by `reindexSprites`.
42
44
  - `ResolveProvenanceOptions` (interface): interface ResolveProvenanceOptions — Override the data {@link resolveProvenance} resolves against; every field defaults to the shipped catalog.
43
45
  - `STARTER_ASSETS` (const): const STARTER_ASSETS: readonly StarterAsset[] — Flat list of every curated starter asset across themes.
44
46
  - `STARTER_PACKS` (const): const STARTER_PACKS: Readonly<Record<StarterTheme, readonly StarterAsset[]>> — Theme → assets table for browse/docs (`STARTER_PACKS.people`, …).
45
47
  - `STARTER_SOURCE_PACKS` (const): const STARTER_SOURCE_PACKS: readonly string[] — Source pack ids a game must pull so every starter asset URL resolves on disk.
46
48
  - `STARTER_THEMES` (const): const STARTER_THEMES: readonly StarterTheme[] — Ordered starter theme ids: people, props, nature, urban.
47
- - `ScrapeDownload` (interface): interface ScrapeDownload — ⚠ undocumented
48
- - `SingleAsset` (interface): interface SingleAsset — ⚠ undocumented
49
+ - `ScrapeDownload` (interface): interface ScrapeDownload { scrape: string } — ⚠ undocumented
50
+ - `SingleAsset` (interface): interface SingleAsset { id: string; url: string; license: string; author: string; categories: readonly string[] } — ⚠ undocumented
49
51
  - `StarterAsset` (interface): interface StarterAsset — One curated starter model: short id, theme, live catalog target, license, suggested height.
50
52
  - `StarterTheme` (type): type StarterTheme = "people" | "props" | "nature" | "urban" — Curated drop-in starter themes for new games. Each entry maps a short semantic id (also registered as `asset:<id>`) to a live catalog GLB that is already measured (dims/anchor flow from the generated index via the alias target). Games wire them as `entityModels: { guest: "asset:person_casual" }`. Never Kenney — Quaternius / KayKit only.
51
53
  - `ValidateAssetReferencesOptions` (interface): interface ValidateAssetReferencesOptions extends ResolveProvenanceOptions — Options for {@link validateAssetReferences}: the resolution data plus an optional on-disk `present` check.
52
54
  - `ValidateAssetReferencesResult` (interface): interface ValidateAssetReferencesResult — The aggregate result of validating a set of references against the provisioning contract.
53
- - `VerifyResult` (interface): interface VerifyResult — ⚠ undocumented
55
+ - `VerifyResult` (interface): interface VerifyResult { ok: boolean; errors: string[] } — ⚠ undocumented
54
56
  - `aliases` (const): const aliases: readonly AssetAlias[] — Semantic keys → live catalog ids. Prefer these in games so re-homes only touch this table. Never point at kenney-*. Curated starter theme ids (`asset:person_casual`, `nature_tree`, …) come from {@link starterAliases}.
55
57
  - `ambientcgSources` (const): const ambientcgSources: readonly AssetSource[] — Every ambientCG material source, generated per family (`ambientcg-grass001` … ).
56
58
  - `buildCatalog` (function): function buildCatalog(options: BuildCatalogOptions = {}): AssetCatalog — Builds a game's asset catalog from the generated CC0 pack index plus singles, extras, and aliases. Registration order is packs → singles → {@link BuildCatalogOptions.extras | extras} → aliases: packs and singles come first, extras override them last-writer-wins, and aliases resolve last so they can target an extra. See {@link BuildCatalogOptions} for filtering and opt-outs.
57
59
  - `buildMaterialCatalog` (function): function buildMaterialCatalog(options: BuildMaterialCatalogOptions = {}): MaterialCatalog — A resolvable catalog over every `kind: "material"` source. Ids are source ids (`ambientcg-grass001`) plus the `material/…` aliases; every resolve returns the normalized map URLs under `basePath`, matching what `assets pull` writes into `<dir>/materials/<id>/`.
58
60
  - `buildSpriteCatalog` (function): function buildSpriteCatalog(options: BuildSpriteCatalogOptions = {}): AssetCatalog — Resolves individual pulled sprite/icon ids (e.g. `gameicons-icons/sword`) to `{ url }`.
59
- - `classifyAssetFile` (function): function classifyAssetFile(bytes: Uint8Array, filename: string): AssetImportKind | null — Classify common asset bytes, using magic bytes and JSON sprite-sheet metadata.
61
+ - `classifyAssetFile` (function): function classifyAssetFile(bytes: Uint8Array, _filename: string): AssetImportKind | null — Classify supported container headers from complete file bytes; filenames never override bytes. Recognizes GLB/glTF, PNG/JPEG/KTX2, Ogg/WAV/MP3, TTF/OTF/WOFF/WOFF2, HDR/EXR and JSON sprite sheets. This is format detection, not decoder validation. Images classify as texture; authors choose sprite/material in the spec.
60
62
  - `componentInstallUrl` (function): function componentInstallUrl(name: string): string — The `shadcn add` URL for a HUD component, e.g. `https://jgengine.com/r/vital-bar.json`.
61
63
  - `componentWiringSnippet` (function): function componentWiringSnippet(component: RegistryComponent): string — Copy-paste wiring for a HUD component: the `shadcn add` command plus import + usage.
62
64
  - `createStarterCatalog` (function): function createStarterCatalog(options: BuildCatalogOptions = {}): AssetCatalog<ModelAssetRef> — Catalog restricted to the curated starter packs (people/props/nature/urban). Prefer this for scaffolds and probes so `asset:person_casual` etc. resolve without pulling the whole library. Full index: {@link buildCatalog}.
@@ -82,6 +84,7 @@
82
84
  - `quaterniusSources` (const): const quaterniusSources: readonly AssetSource[] — ⚠ undocumented
83
85
  - `rankAssets` (function): function rankAssets(query: string, options: FindOptions = {}): RankedMatch[] — Rank every catalog entry — models, packs, HUD components, icons — against one query.
84
86
  - `readGlbDims` (function): function readGlbDims(bytes: Uint8Array): ModelDims | null — ⚠ undocumented
87
+ - `readGlbMetrics` (function): function readGlbMetrics(bytes: Uint8Array, readResource?: (uri: string) => Uint8Array): GlbMetrics — Inspect GLB v2 geometry accessors and image headers offline. Throws on unreadable resources, malformed geometry, or required geometry compression; never silently reports missing data as zero. External resources are supplied by the caller; this function never fetches or decompresses bytes.
85
88
  - `registryCatalog` (const): const registryCatalog: RegistryCatalog — ⚠ undocumented
86
89
  - `reindexSprites` (function): function reindexSprites(spritesDir: string, outDir: string): ReindexSpritesResult — Same shape as `reindex` (models) but walks SVG/PNG files and skips dims measurement — sprites have no footprint.
87
90
  - `resolveProvenance` (function): function resolveProvenance(id: string, options: ResolveProvenanceOptions = {}): AssetProvenance — Resolve one logical asset id (a pack id, a single id, or an alias key) to its {@link AssetProvenance}. Aliases are followed one hop to their target. An id that matches no declared owner is `dangling` — the signal a clean-clone gate turns into a hard failure, because no provisioning step can ever satisfy it.
@@ -91,16 +94,25 @@
91
94
  - `spriteSources` (const): const spriteSources: readonly AssetSource[] — Every `kind: "sprite"` source — a pack of individual 2D icon/UI files, resolvable via `buildSpriteCatalog`.
92
95
  - `spriteWiringSnippet` (function): function spriteWiringSnippet(id: string, basePath = "/sprites"): string — Copy-paste wiring for a pulled sprite/icon-pack file: resolve through the sprite catalog.
93
96
  - `validateAssetReferences` (function): function validateAssetReferences(references: readonly AssetReference[], options: ValidateAssetReferencesOptions = {}): ValidateAssetReferencesResult — Validate that every {@link AssetReference} resolves against the declared provisioning contract — not by grepping source text, but by resolving each logical id to its committed / provisioned / dangling owner. A `dangling` reference fails with the referencing consumer, the logical id, the (null) resolved path, and the missing provisioning step; a `provisioned` reference passes and contributes its `assets pull <source>` step to `provisioning` (unless `present` is supplied and reports the bytes absent).
94
- - `validateImportSpec` (function): function validateImportSpec(spec: AssetImportSpec): ImportSpecValidation — Validate the stable, serializable import contract before ingesting files.
97
+ - `validateImportSpec` (function): function validateImportSpec(spec: unknown): ImportSpecValidation — Validate untrusted import descriptions without filesystem access or path rewriting. Requires unique relative files, printable non-empty roles and plain JSON metadata (maximum depth 64).
95
98
  - `verifyManifest` (function): function verifyManifest(): VerifyResult — ⚠ undocumented
96
99
 
97
100
  ## @jgengine/assets/aliases
98
101
 
99
102
  - `aliases` (const): const aliases: readonly AssetAlias[] — Semantic keys → live catalog ids. Prefer these in games so re-homes only touch this table. Never point at kenney-*. Curated starter theme ids (`asset:person_casual`, `nature_tree`, …) come from {@link starterAliases}.
100
103
 
104
+ ## @jgengine/assets/assetBudget
105
+
106
+ - `AssetBudget` (interface): interface AssetBudget — Per-model limits chosen by the game; equality passes and omitted limits only report.
107
+ - `AssetBudgetEntry` (interface): interface AssetBudgetEntry — One model's measured inventory or actionable inspection/budget errors.
108
+ - `AssetBudgetReport` (interface): interface AssetBudgetReport — Deterministic offline report; an empty directory or any unreadable model fails.
109
+ - `checkAssetBudget` (function): function checkAssetBudget(metrics: GlbMetrics, budget: AssetBudget): string[] — Check measured per-model bytes, stored triangles, and maximum image dimension against caller-owned limits.
110
+ - `createAssetBudgetReport` (function): function createAssetBudgetReport(target: string, budget: AssetBudget = {}): AssetBudgetReport — Scan a file or directory recursively for GLBs without changing their bytes or the catalog. Paths are relative to the scanned directory, sorted lexically; unknown/custom asset folders work equally.
111
+ - `readGlbFileMetrics` (function): function readGlbFileMetrics(file: string, resourceRoot = dirname(file)): GlbMetrics — Read a GLB plus local resources under `resourceRoot`; remote URLs and symlink escapes fail without fetching.
112
+
101
113
  ## @jgengine/assets/catalogs/build
102
114
 
103
- - `BuildCatalogOptions` (interface): interface BuildCatalogOptions — ⚠ undocumented
115
+ - `BuildCatalogOptions` (interface): interface BuildCatalogOptions { basePath?: string; sources?: readonly string[]; includeAliases?: boolean; includeSingles?: boolean; extras?: readonly CatalogExtra[] } — ⚠ undocumented · used by `buildCatalog`: Builds a game's asset catalog from the generated CC0 pack index plus singles, extras, and aliases.
104
116
  - `CatalogExtra` (interface): interface CatalogExtra — A durable, hand-or-tool authored catalog entry that is not part of the generated pack index, singles, or aliases — the shape the editor writes into a promoted game's `src/game/assets.ts` when an asset is imported. `label` is human-facing only and is intentionally not registered into the catalog (it mirrors how a single asset's author/license live only in the source literal), so at runtime an extra resolves to exactly `{ url }`.
105
117
  - `buildCatalog` (function): function buildCatalog(options: BuildCatalogOptions = {}): AssetCatalog — Builds a game's asset catalog from the generated CC0 pack index plus singles, extras, and aliases. Registration order is packs → singles → {@link BuildCatalogOptions.extras | extras} → aliases: packs and singles come first, extras override them last-writer-wins, and aliases resolve last so they can target an extra. See {@link BuildCatalogOptions} for filtering and opt-outs.
106
118
  - `entryUrl` (function): function entryUrl(basePath: string, entry: IndexEntry): string — ⚠ undocumented
@@ -144,9 +156,9 @@
144
156
  ## @jgengine/assets/download
145
157
 
146
158
  - `DEFAULT_RELEASE_BASE` (const): const DEFAULT_RELEASE_BASE: "https://github.com/Noisemaker111/jgengine/releases/download/packs" — Default asset mirror: this repo's own GitHub Releases, reachable from every cloud sandbox without network-policy changes (github.com is on the default allowlist). Assets live on the rolling `packs` release, one flat zip per pack named `<provider>-<packId>.zip`, kept in sync with the source catalog by `.github/workflows/mirror-assets.yml` — adding a catalog entry is the whole publishing step. Override the chain with `--mirror` / `JGENGINE_ASSETS_MIRROR`, or disable this hop with `JGENGINE_ASSETS_NO_DEFAULT_MIRROR=1`.
147
- - `DownloadPackOptions` (interface): interface DownloadPackOptions — ⚠ undocumented
148
- - `DownloadPackResult` (interface): interface DownloadPackResult — ⚠ undocumented
149
- - `ExtractedGlb` (interface): interface ExtractedGlb — ⚠ undocumented
159
+ - `DownloadPackOptions` (interface): interface DownloadPackOptions { mirrorBase?: string; fetchImpl?: FetchLike } — ⚠ undocumented
160
+ - `DownloadPackResult` (interface): interface DownloadPackResult { archive: Uint8Array; url: string; attempted: readonly string[] } — ⚠ undocumented
161
+ - `ExtractedGlb` (interface): interface ExtractedGlb { file: string; bytes: Uint8Array } — ⚠ undocumented
150
162
  - `ExtractedPack` (interface): interface ExtractedPack — What `extractGlbs` pulls out of a pack archive: the models plus the textures they reference.
151
163
  - `ExtractedPackImage` (interface): interface ExtractedPackImage — An image a pack's models reference, shipped flat beside the `.glb` files.
152
164
  - `ExtractedSpriteFile` (interface): interface ExtractedSpriteFile — One SVG/PNG file pulled out of a sprite/icon-pack archive by `extractSpriteFiles`.
@@ -159,9 +171,9 @@
159
171
  ## @jgengine/assets/find
160
172
 
161
173
  - `AssetKind` (type): type AssetKind = "model" | "pack" | "material" | "component" | "icon" | "sprite" | "spritePack" — ⚠ undocumented
162
- - `AssetMatch` (type): type AssetMatch = | { kind: "model"; id: string; source: string; file?: string; via: "index" | "alias" | "single" } | { kind: "pack"; source: string; title: string; categories: readonly string[] } | { kind: "material"; id: string; title: string; categories: readonly string[] } | { kind: "component";… — ⚠ undocumented
163
- - `FindOptions` (interface): interface FindOptions — ⚠ undocumented
164
- - `RankedMatch` (interface): interface RankedMatch — ⚠ undocumented
174
+ - `AssetMatch` (type): type AssetMatch = | { kind: "model"; id: string; source: string; file?: string; via: "index" | "alias" | "single" } | { kind: "pack"; source: string; title: string; categories: readonly string[] } | { kind: "material"; id: string; title: string; categories: readonly string[] } | { kind: "component";… — ⚠ undocumented · used by `findAssets`: The ranked matches for a query — models, packs, HUD components, and icons in one list.
175
+ - `FindOptions` (interface): interface FindOptions { kind?: AssetKind; limit?: number } — ⚠ undocumented · used by `findAssets`: The ranked matches for a query — models, packs, HUD components, and icons in one list.
176
+ - `RankedMatch` (interface): interface RankedMatch { match: AssetMatch; score: number } — ⚠ undocumented · used by `rankAssets`: Rank every catalog entry — models, packs, HUD components, icons — against one query.
165
177
  - `findAssets` (function): function findAssets(query: string, options: FindOptions = {}): AssetMatch[] — The ranked matches for a query — models, packs, HUD components, and icons in one list.
166
178
  - `rankAssets` (function): function rankAssets(query: string, options: FindOptions = {}): RankedMatch[] — Rank every catalog entry — models, packs, HUD components, icons — against one query.
167
179
 
@@ -175,36 +187,53 @@
175
187
  - `generatedSpriteBySource` (const): const generatedSpriteBySource: Record<string, IndexEntry[]> — Pulled sprite/icon entries grouped by source id.
176
188
  - `generatedSpriteIndex` (const): const generatedSpriteIndex: IndexEntry[] — Every pulled sprite/icon entry across all sources, flattened.
177
189
 
190
+ ## @jgengine/assets/glbMetrics
191
+
192
+ - `GlbMetrics` (interface): interface GlbMetrics — Stored geometry and image inventory; triangles count mesh primitives once, regardless of scene instances.
193
+ - `GlbTextureMetrics` (interface): interface GlbTextureMetrics — Dimensions and encoded bytes for one glTF image, including images referenced by texture extensions.
194
+ - `readGlbMetrics` (function): function readGlbMetrics(bytes: Uint8Array, readResource?: (uri: string) => Uint8Array): GlbMetrics — Inspect GLB v2 geometry accessors and image headers offline. Throws on unreadable resources, malformed geometry, or required geometry compression; never silently reports missing data as zero. External resources are supplied by the caller; this function never fetches or decompresses bytes.
195
+
196
+ ## @jgengine/assets/gltfMaterials
197
+
198
+ - `GLTF_MATERIAL_EXTENSIONS_R182` (const): const GLTF_MATERIAL_EXTENSIONS_R182: readonly string[] — Native material/texture extensions implemented by Three.js GLTFLoader r182. Decoders are still required.
199
+ - `GltfImportedMaterial` (interface): interface GltfImportedMaterial — One imported material with the native definition retained as an independent JSON snapshot.
200
+ - `GltfMaterialDiagnostic` (interface): interface GltfMaterialDiagnostic — Actionable fidelity warning or error; this inspector never changes imported surfaces.
201
+ - `GltfMaterialInspection` (interface): interface GltfMaterialInspection — Native material inventory, primitive selectors, attribution, and renderer compatibility diagnostics.
202
+ - `GltfMaterialSlot` (interface): interface GltfMaterialSlot — A primitive slot retains mesh and material indices even when display names collide.
203
+ - `GltfMaterialTexture` (interface): interface GltfMaterialTexture — A native glTF texture use; embedded images retain their source index instead of an invented URL.
204
+ - `inspectGlbMaterials` (function): function inspectGlbMaterials(bytes: Uint8Array, assetId: string): GltfMaterialInspection — Inspect the JSON chunk of complete GLB v2 bytes, including models with compressed geometry. This measures material metadata only; it never decodes geometry or resolves image URLs.
205
+ - `inspectGltfMaterials` (function): function inspectGltfMaterials(json: GLTF.IGLTF, assetId: string): GltfMaterialInspection — Inventory validated glTF JSON without flattening slots, decoding compressed geometry, or changing materials. IDs use the supplied model namespace plus source indices, and remain stable while its pinned bytes remain stable.
206
+
178
207
  ## @jgengine/assets/importSpec
179
208
 
180
209
  - `AssetImportKind` (type): type AssetImportKind = "model" | "texture" | "material" | "sprite" | "spriteSheet" | "audio" | "font" | "hdri" — Supported logical kinds for user-supplied assets.
181
- - `AssetImportSpec` (interface): interface AssetImportSpec — A validated description of files to ingest into a game project.
182
- - `ImportSpecValidation` (type): type ImportSpecValidation = { ok: true; entry: AssetImportSpec } | { ok: false; reason: string } — Result of validating an import description.
183
- - `classifyAssetFile` (function): function classifyAssetFile(bytes: Uint8Array, filename: string): AssetImportKind | null — Classify common asset bytes, using magic bytes and JSON sprite-sheet metadata.
184
- - `validateImportSpec` (function): function validateImportSpec(spec: AssetImportSpec): ImportSpecValidation — Validate the stable, serializable import contract before ingesting files.
210
+ - `AssetImportSpec` (interface): interface AssetImportSpec — A game-owned import description; paths are relative POSIX paths, roles are authored labels.
211
+ - `ImportSpecValidation` (type): type ImportSpecValidation = { ok: true; entry: AssetImportSpec } | { ok: false; reason: string } — Result of validating an import description; a successful entry is an independent JSON snapshot.
212
+ - `classifyAssetFile` (function): function classifyAssetFile(bytes: Uint8Array, _filename: string): AssetImportKind | null — Classify supported container headers from complete file bytes; filenames never override bytes. Recognizes GLB/glTF, PNG/JPEG/KTX2, Ogg/WAV/MP3, TTF/OTF/WOFF/WOFF2, HDR/EXR and JSON sprite sheets. This is format detection, not decoder validation. Images classify as texture; authors choose sprite/material in the spec.
213
+ - `validateImportSpec` (function): function validateImportSpec(spec: unknown): ImportSpecValidation — Validate untrusted import descriptions without filesystem access or path rewriting. Requires unique relative files, printable non-empty roles and plain JSON metadata (maximum depth 64).
185
214
 
186
215
  ## @jgengine/assets/indexGen
187
216
 
188
- - `ReindexResult` (interface): interface ReindexResult — ⚠ undocumented
189
- - `entryForFile` (function): function entryForFile(source: AssetSource, file: string, dims?: ModelDims, collisionMesh?: CollisionMeshData, clips?: readonly string[]): IndexEntry — ⚠ undocumented
217
+ - `ReindexResult` (interface): interface ReindexResult { perSource: {source: string; count: number}[]; total: number } — ⚠ undocumented
218
+ - `entryForFile` (function): function entryForFile(source: AssetSource, file: string, dims?: ModelDims, collisionMesh?: CollisionMeshData, clips?: readonly string[], metrics?: GlbMetrics): IndexEntry — Build a source-owned model entry, preserving optional measured bounds, collision, clips, and inventory.
190
219
  - `indexSourceDir` (function): function indexSourceDir(source: AssetSource, dir: string): IndexEntry[] — ⚠ undocumented
191
220
  - `keyFromFile` (function): function keyFromFile(file: string): string — ⚠ undocumented
192
221
  - `reindex` (function): function reindex(modelsDir: string, outDir: string): ReindexResult — ⚠ undocumented
193
222
 
194
223
  ## @jgengine/assets/manifest
195
224
 
196
- - `AssetAlias` (interface): interface AssetAlias — ⚠ undocumented
225
+ - `AssetAlias` (interface): interface AssetAlias { key: string; target: string } — ⚠ undocumented · used by `aliases` (@jgengine/assets): Semantic keys → live catalog ids.
197
226
  - `AssetDownload` (type): type AssetDownload = PinnedDownload | ScrapeDownload — ⚠ undocumented
198
227
  - `AssetProvider` (type): type AssetProvider = | "quaternius" | "kaykit" | "polypizza" | "itch" | "ambientcg" | "gameicons" | "custom" — ⚠ undocumented
199
- - `AssetSource` (interface): interface AssetSource — ⚠ undocumented
228
+ - `AssetSource` (interface): interface AssetSource { id: string; kind?: AssetSourceKind; provider: AssetProvider; title: string; license: string; author: string; categories: readonly string[]; download: AssetDownload; homepage?: string; materialMaps?: readonly MaterialMapRole[]; mirror?: st… — ⚠ undocumented · used by `ambientcgSources` (@jgengine/assets): Every ambientCG material source, generated per family (`ambientcg-grass001` … ).
200
229
  - `AssetSourceKind` (type): type AssetSourceKind = "model" | "material" | "sprite" — What a source's archive contains: GLB models (default), one PBR material's texture maps, or a pack of individual 2D sprite/icon files (SVG/PNG).
201
230
  - `AssetSpace` (interface): interface AssetSpace — Catalog-level asset-space metadata: how a model is authored relative to the engine, owned by the catalog entry rather than re-derived per game. Every field is optional so an unmeasured asset stays valid; {@link resolveFacingRotationY}/{@link assetUnitScale}/{@link resolveAnchorOffset} supply the documented defaults.
202
231
  - `CollisionMeshData` (interface): interface CollisionMeshData — Compact, serializable triangle collision mesh measured at asset reindex — the renderer-free source of mesh-accurate hitboxes. Positions are welded onto a 16-bit grid spanning `min`..`max` (model space) and stored base64-encoded, so an opted-in catalog asset ships its collision triangles inside the generated index without the runtime ever touching the rendered scene graph.
203
- - `IndexEntry` (interface): interface IndexEntry — ⚠ undocumented
232
+ - `IndexEntry` (interface): interface IndexEntry — A source-owned model or sprite id, with optional offline model measurements.
204
233
  - `ModelDims` (interface): interface ModelDims — Measured horizontal footprint, footprint center, and lowest Y of a model in model space.
205
- - `PinnedDownload` (interface): interface PinnedDownload — ⚠ undocumented
206
- - `ScrapeDownload` (interface): interface ScrapeDownload — ⚠ undocumented
207
- - `SingleAsset` (interface): interface SingleAsset — ⚠ undocumented
234
+ - `PinnedDownload` (interface): interface PinnedDownload { url: string; sha256?: string } — ⚠ undocumented
235
+ - `ScrapeDownload` (interface): interface ScrapeDownload { scrape: string } — ⚠ undocumented
236
+ - `SingleAsset` (interface): interface SingleAsset { id: string; url: string; license: string; author: string; categories: readonly string[] } — ⚠ undocumented
208
237
  - `isScrapeDownload` (function): function isScrapeDownload(download: AssetDownload): download is ScrapeDownload — ⚠ undocumented
209
238
 
210
239
  ## @jgengine/assets/materials
@@ -214,7 +243,7 @@
214
243
  - `MATERIAL_MAP_FILES` (const): const MATERIAL_MAP_FILES: { readonly color: "color.jpg"; readonly normal: "normal.jpg"; readonly roughness: "roughness.jpg"; readonly ao: "ao.jpg"; readonly displacement: "displacement.jpg"; readonly ktx2: "material.ktx2"; } — Normalized filenames a pulled material directory contains, keyed by map role.
215
244
  - `MaterialCatalog` (interface): interface MaterialCatalog — Resolves material ids and `material/…` aliases to `MaterialRef`s.
216
245
  - `MaterialMapRole` (type): type MaterialMapRole = keyof typeof MATERIAL_MAP_FILES — One PBR map's role within a material, including an optional compressed KTX2 asset.
217
- - `MaterialMaps` (interface): interface MaterialMaps — URLs of one material's PBR maps; `ao`/`displacement` files may be absent from a rare pack.
246
+ - `MaterialMaps` (interface): interface MaterialMaps — URLs of one material's PBR maps; `ao`/`roughness`/`ktx2` appear only when declared by its source.
218
247
  - `MaterialRef` (interface): interface MaterialRef — A resolved material: identity, attribution, and its normalized map URLs.
219
248
  - `buildMaterialCatalog` (function): function buildMaterialCatalog(options: BuildMaterialCatalogOptions = {}): MaterialCatalog — A resolvable catalog over every `kind: "material"` source. Ids are source ids (`ambientcg-grass001`) plus the `material/…` aliases; every resolve returns the normalized map URLs under `basePath`, matching what `assets pull` writes into `<dir>/materials/<id>/`.
220
249
  - `extractMaterialMaps` (function): function extractMaterialMaps(archive: Uint8Array): ExtractedMaterialMap[] — Pulls the recognized PBR maps out of a material archive (ambientCG's flat `<Asset>_<Res>_<Map>.jpg` layout) and normalizes their names so resolved URLs never depend on the provider's naming or the pulled resolution.
@@ -243,8 +272,8 @@
243
272
 
244
273
  ## @jgengine/assets/registry
245
274
 
246
- - `RegistryCatalog` (interface): interface RegistryCatalog — ⚠ undocumented
247
- - `RegistryComponent` (interface): interface RegistryComponent — ⚠ undocumented
275
+ - `RegistryCatalog` (interface): interface RegistryCatalog { homepage: string; components: readonly RegistryComponent[]; icons: readonly string[] } — ⚠ undocumented
276
+ - `RegistryComponent` (interface): interface RegistryComponent { name: string; title: string; description: string } — ⚠ undocumented · used by `componentWiringSnippet` (@jgengine/assets): Copy-paste wiring for a HUD component: the `shadcn add` command plus import + usage.
248
277
  - `componentInstallUrl` (function): function componentInstallUrl(name: string): string — The `shadcn add` URL for a HUD component, e.g. `https://jgengine.com/r/vital-bar.json`.
249
278
  - `registryCatalog` (const): const registryCatalog: RegistryCatalog — ⚠ undocumented
250
279
 
@@ -254,7 +283,7 @@
254
283
 
255
284
  ## @jgengine/assets/snippet
256
285
 
257
- - `ModelSnippetOptions` (interface): interface ModelSnippetOptions — ⚠ undocumented
286
+ - `ModelSnippetOptions` (interface): interface ModelSnippetOptions { basePath?: string; seam?: "objectModels" | "entityModels" } — ⚠ undocumented · used by `modelWiringSnippet`: Copy-paste wiring for a pulled GLB id: resolve through the catalog, drop into a model seam.
258
287
  - `componentWiringSnippet` (function): function componentWiringSnippet(component: RegistryComponent): string — Copy-paste wiring for a HUD component: the `shadcn add` command plus import + usage.
259
288
  - `iconWiringSnippet` (function): function iconWiringSnippet(name: string): string — Copy-paste wiring for a HUD glyph from the registry `game-icon` catalog.
260
289
  - `materialWiringSnippet` (function): function materialWiringSnippet(id: string, basePath = "/materials"): string — Copy-paste wiring for a pulled PBR material: resolve the map URLs through the material catalog, then apply them onto terrain or a model.
@@ -298,9 +327,55 @@
298
327
  - `keyFromSpriteFile` (function): function keyFromSpriteFile(file: string): string — Strips the `.svg`/`.png` extension off a pulled sprite/icon filename to get its id suffix.
299
328
  - `reindexSprites` (function): function reindexSprites(spritesDir: string, outDir: string): ReindexSpritesResult — Same shape as `reindex` (models) but walks SVG/PNG files and skips dims measurement — sprites have no footprint.
300
329
 
330
+ ## @jgengine/assets/staticPrefabBake
331
+
332
+ - `StaticPrefabBakeReport` (interface): interface StaticPrefabBakeReport — Deterministic inventory and provenance for an editor-authored static artifact.
333
+ - `StaticPrefabBakeResult` (interface): interface StaticPrefabBakeResult — GLB bytes and catalog-ready metadata; origin anchoring preserves the editable fragment's local frame.
334
+ - `StaticPrefabSource` (interface): interface StaticPrefabSource — Original static model bytes; paths are absolute and every external image must have a pin.
335
+ - `StaticPrefabTextureSource` (interface): interface StaticPrefabTextureSource — A verified external source image and its complete runtime URL. URI matches the source GLB exactly.
336
+ - `bakeStaticPrefab` (function): function bakeStaticPrefab(prefab: EditorPrefab, sources: readonly StaticPrefabSource[]): Promise<StaticPrefabBakeResult> — Bake pinned static source art in an editor prefab's local frame. Node-only; never mutates authored data.
337
+
301
338
  ## @jgengine/assets/verify
302
339
 
303
- - `VerifyInput` (interface): interface VerifyInput — ⚠ undocumented
304
- - `VerifyResult` (interface): interface VerifyResult — ⚠ undocumented
340
+ - `VerifyInput` (interface): interface VerifyInput { sources: readonly AssetSource[]; singles: readonly SingleAsset[]; aliases: readonly AssetAlias[]; index: readonly IndexEntry[]; materialAliases?: readonly AssetAlias[] } — ⚠ undocumented
341
+ - `VerifyResult` (interface): interface VerifyResult { ok: boolean; errors: string[] } — ⚠ undocumented
305
342
  - `verifyData` (function): function verifyData(input: VerifyInput): VerifyResult — ⚠ undocumented
306
343
  - `verifyManifest` (function): function verifyManifest(): VerifyResult — ⚠ undocumented
344
+
345
+ ## @jgengine/core/material/hairCards
346
+
347
+ - `HAIR_CARD_STRAND_ROTATION` (const): const HAIR_CARD_STRAND_ROTATION: number — Tangents follow card width (UV U); strand length follows UV V. Angles are radians.
348
+ - `HairCardAuthoring` (interface): interface HairCardAuthoring — Serializable geometry authoring, independent of materials, grooming physics and collisions.
349
+ - `HairCardGuide` (interface): interface HairCardGuide — An authored centreline, in model-local metres, with root-to-tip points.
350
+ - `HairCardMesh` (interface): interface HairCardMesh — Renderer-neutral indexed ribbons with an explicit tangent frame and guide ranges.
351
+ - `buildHairCards` (function): function buildHairCards(input: HairCardAuthoring): HairCardMesh — Build deterministic model-local ribbon geometry; guides remain separately editable source data.
352
+ - `validateHairCardAuthoring` (function): function validateHairCardAuthoring(value: unknown): MaterialDiagnostic[] — Validate finite guides, tangent frames and bounded generation; crossing/collision is not solved.
353
+
354
+ ## @jgengine/core/material/materialAsset
355
+
356
+ - `FabricAppearance` (interface): interface FabricAppearance — Procedural cloth surface response; this does not create or bend cloth geometry.
357
+ - `HairAppearance` (interface): interface HairAppearance — Anisotropic surface approximation for existing hair cards or strand meshes, without grooming.
358
+ - `MATERIAL_SURFACE_CAPABILITIES` (const): const MATERIAL_SURFACE_CAPABILITIES: Partial<Record<keyof MaterialSurfaceParameters, MaterialCapability>> — Feature declarations required by each sparse physical parameter.
359
+ - `MATERIAL_TEXTURE_CAPABILITIES` (const): const MATERIAL_TEXTURE_CAPABILITIES: Readonly<Partial<Record<MaterialTextureRole, MaterialCapability>>> — Feature declarations required by authored texture roles.
360
+ - `MATERIAL_TEXTURE_SEMANTICS` (const): const MATERIAL_TEXTURE_SEMANTICS: Readonly<Record<MaterialTextureRole, { colorSpace: "srgb" | "linear"; channel: MaterialTextureChannel }>> — Shader channel defaults; standalone alpha maps use green, base-color alpha stays in its color map.
361
+ - `MaterialAsset` (interface): interface MaterialAsset — Shared, versioned authoring data. IDs survive rename, save and export.
362
+ - `MaterialAssignment` (interface): interface MaterialAssignment — A reusable asset reference with an optional instance-only sparse edit.
363
+ - `MaterialAssignmentValidationOptions` (interface): interface MaterialAssignmentValidationOptions — Optional renderer limits; ordinary model assignment accepts every supported texture role.
364
+ - `MaterialCapability` (type): type MaterialCapability = "pbr" | "sheen" | "anisotropy" | "clearcoat" | "specular" | "transmission" | "volume" | "iridescence" | "alpha" — Renderer features an authored material explicitly requires.
365
+ - `MaterialDiagnostic` (interface): interface MaterialDiagnostic — An actionable authoring/import diagnostic.
366
+ - `MaterialFamily` (type): type MaterialFamily = "standard" | "fabric" | "hair" | "glass" | "metal" | "skin" | "stone" | "plastic" — Physical surface families; these describe appearance, never geometry or simulation.
367
+ - `MaterialProvenance` (interface): interface MaterialProvenance — Portable material or image authorship.
368
+ - `MaterialSelector` (interface): interface MaterialSelector — Names constrain mesh and imported material slot independently; all provided tests must match.
369
+ - `MaterialSurfaceParameters` (interface): interface MaterialSurfaceParameters — Sparse surface edits. Omitted values preserve the imported material. Angles are radians.
370
+ - `MaterialTemplate` (type): type MaterialTemplate = "wool" | "cotton" | "silk" | "brushed-metal" | "glass" | "coated-plastic" | "stone" | "hair-cards" — Editable engine-authored surface starting points, independent of any game's palette or assets.
371
+ - `MaterialTextureChannel` (type): type MaterialTextureChannel = "r" | "g" | "b" | "a" | "rgb" | "rgba" — Texture channels used by the pinned standard/physical shader path.
372
+ - `MaterialTextureMetadata` (interface): interface MaterialTextureMetadata — Serializable sampling and UV metadata; metres are descriptive, UV transforms drive rendering.
373
+ - `MaterialTextureRole` (type): type MaterialTextureRole = "color" | "normal" | "roughness" | "metalness" | "ao" | "emissive" | "alpha" | "height" | "sheenColor" | "sheenRoughness" | "anisotropy" | "clearcoat" | "clearcoatRoughness" | "clearcoatNormal" | "specularIntensity" | "specularColor" | "transmission" | "thickness" | "iride… — Supported texture semantics; packed channels follow glTF and Three's PBR shaders.
374
+ - `createMaterialTemplate` (function): function createMaterialTemplate(template: MaterialTemplate, id: string, name = template): MaterialAsset — Create fresh, serializable material data with provenance; templates create no textures or geometry.
375
+ - `matchesMaterialSelector` (function): function matchesMaterialSelector(selector: MaterialSelector, mesh: string, slot: string, slotIndex: number): boolean — Exact name/index selector matching shared by authoring and rendering.
376
+ - `materialCapabilitiesForAsset` (function): function materialCapabilitiesForAsset(asset: Pick<MaterialAsset, "surface" | "textures" | "fabric" | "hair">): MaterialCapability[] — Determine required shader features from surface fields, maps and appearance adapters without editing them.
377
+ - `materialCapabilitiesForSurface` (function): function materialCapabilitiesForSurface(surface: MaterialSurfaceParameters): MaterialCapability[] — Determine feature requirements from authored fields, including intentional zero values.
378
+ - `parseMaterialAssignments` (function): function parseMaterialAssignments(value: unknown): MaterialAssignment[] — Parse assignment JSON at editor/RPC boundaries. Invalid data fails with an actionable path.
379
+ - `validateMaterialAsset` (function): function validateMaterialAsset(value: unknown): MaterialDiagnostic[] — Validate material JSON and renderer prerequisites before saving or assigning it.
380
+ - `validateMaterialAssignments` (function): function validateMaterialAssignments(assignments: readonly MaterialAssignment[], assets: readonly MaterialAsset[], options: MaterialAssignmentValidationOptions = {}): MaterialDiagnostic[] — Validate references and selectors without accepting accidental whole-model assignment.
381
+ - `validateMaterialSurface` (function): function validateMaterialSurface(value: unknown, path = "surface"): MaterialDiagnostic[] — Validate sparse surface edits without mutating them or guessing unsupported fields.
@@ -4,6 +4,21 @@
4
4
 
5
5
  Reach for these before hand-rolling. Each row is *the thing you need* → *the primitive that already does it*.
6
6
 
7
+ ## asset-budgets — enforce game-owned per-model byte, triangle, and texture-dimension limits
8
+
9
+ - `checkAssetBudget` (function) · `import { checkAssetBudget } from "@jgengine/assets/assetBudget"`
10
+ - `createAssetBudgetReport` (function) · `import { createAssetBudgetReport } from "@jgengine/assets/assetBudget"`
11
+ - `readGlbFileMetrics` (function) · `import { readGlbFileMetrics } from "@jgengine/assets/assetBudget"`
12
+ - `readGlbMetrics` (function) · `import { readGlbMetrics } from "@jgengine/assets"`
13
+
14
+ ## asset-byte-classification — identify custom asset formats from bytes instead of filename extensions
15
+
16
+ - `classifyAssetFile` (function) · `import { classifyAssetFile } from "@jgengine/assets"`
17
+
18
+ ## asset-import-validation — validate game-owned multi-file asset descriptions before ingest
19
+
20
+ - `validateImportSpec` (function) · `import { validateImportSpec } from "@jgengine/assets"`
21
+
7
22
  ## asset-reference-integrity — validate asset references against the provisioning contract (dangling / committed / provisioned)
8
23
 
9
24
  - `validateAssetReferences` (function) · `import { validateAssetReferences } from "@jgengine/assets"`
@@ -24,6 +39,28 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
24
39
 
25
40
  - `creditsForSources` (function) · `import { creditsForSources } from "@jgengine/assets/credits"`
26
41
 
42
+ ## gltf-material-inspection — inspect material slots and texture metadata directly from complete GLB bytes
43
+
44
+ - `inspectGlbMaterials` (function) · `import { inspectGlbMaterials } from "@jgengine/assets/gltfMaterials"`
45
+ - `inspectGltfMaterials` (function) · `import { inspectGltfMaterials } from "@jgengine/assets/gltfMaterials"`
46
+
47
+ ## hair-card-geometry — validate authored ribbon guides and their vertex allocation ceiling
48
+
49
+ - `validateHairCardAuthoring` (function) · `import { validateHairCardAuthoring } from "@jgengine/core/material/hairCards"`
50
+
51
+ ## material-feature-requirements — Declare material shader requirements when authors add maps or appearance adapters.
52
+
53
+ - `materialCapabilitiesForAsset` (function) · `import { materialCapabilitiesForAsset } from "@jgengine/core/material/materialAsset"`
54
+
55
+ ## material-slot-selection — match named meshes and imported material slots independently
56
+
57
+ - `matchesMaterialSelector` (function) · `import { matchesMaterialSelector } from "@jgengine/core/material/materialAsset"`
58
+ - `validateMaterialAssignments` (function) · `import { validateMaterialAssignments } from "@jgengine/core/material/materialAsset"`
59
+
60
+ ## material-surface-validation — diagnose unsupported or physically invalid sparse surface edits
61
+
62
+ - `validateMaterialSurface` (function) · `import { validateMaterialSurface } from "@jgengine/core/material/materialAsset"`
63
+
27
64
  ## sources-for-asset-ids — resolve the asset packs behind the ids a game actually ships
28
65
 
29
66
  - `sourcesForAssetIds` (function) · `import { sourcesForAssetIds } from "@jgengine/assets/credits"`
@@ -35,3 +72,7 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
35
72
  ## starter-packs — themed CC0 model ids (people/props/nature/urban) ready for entityModels
36
73
 
37
74
  - `StarterTheme` (type) · `import { StarterTheme } from "@jgengine/assets"`
75
+
76
+ ## static-prefab-export — export editable prefab compositions with source materials and collision metadata
77
+
78
+ - `bakeStaticPrefab` (function) · `import { bakeStaticPrefab } from "@jgengine/assets/staticPrefabBake"`