@jgengine/assets 0.12.0 → 0.14.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 +73 -1
- package/README.md +1 -1
- package/dist/catalogs/build.js +2 -0
- package/dist/dims.d.ts +7 -0
- package/dist/dims.js +21 -0
- package/dist/generated/kaykit-adventurers.json +395 -5
- package/dist/generated/kaykit-skeletons.json +426 -21
- package/dist/generated/kaykit-space-base.json +114 -57
- package/dist/generated/quaternius-medieval-village.json +352 -176
- package/dist/generated/quaternius-modular-scifi.json +405 -196
- package/dist/indexGen.d.ts +1 -1
- package/dist/indexGen.js +12 -3
- package/dist/manifest.d.ts +2 -0
- package/package.json +2 -2
- package/skills/jgengine/SKILL.md +5 -2
- package/skills/jgengine/api.md +13 -5
- package/skills/jgengine-assets/SKILL.md +5 -1
- package/skills/jgengine-assets/api.md +2 -1
- package/skills/jgengine-assets/capabilities.md +4 -0
package/dist/indexGen.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AssetSource, CollisionMeshData, IndexEntry, ModelDims } from "./manifest.js";
|
|
2
2
|
export declare function keyFromFile(file: string): string;
|
|
3
|
-
export declare function entryForFile(source: AssetSource, file: string, dims?: ModelDims, collisionMesh?: CollisionMeshData): IndexEntry;
|
|
3
|
+
export declare function entryForFile(source: AssetSource, file: string, dims?: ModelDims, collisionMesh?: CollisionMeshData, clips?: readonly string[]): IndexEntry;
|
|
4
4
|
export declare function indexSourceDir(source: AssetSource, dir: string): IndexEntry[];
|
|
5
5
|
export interface ReindexResult {
|
|
6
6
|
perSource: {
|
package/dist/indexGen.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { COLLISION_MESH_ASSET_IDS } from "./collisionMeshAssets.js";
|
|
4
|
-
import { readGlbCollisionMesh, readGlbDims } from "./dims.js";
|
|
4
|
+
import { readGlbClips, readGlbCollisionMesh, readGlbDims } from "./dims.js";
|
|
5
5
|
import { sourceById } from "./sources/index.js";
|
|
6
6
|
export function keyFromFile(file) {
|
|
7
7
|
return file.replace(/\.gltf\.glb$/i, "").replace(/\.glb$/i, "");
|
|
8
8
|
}
|
|
9
|
-
export function entryForFile(source, file, dims, collisionMesh) {
|
|
9
|
+
export function entryForFile(source, file, dims, collisionMesh, clips) {
|
|
10
10
|
return {
|
|
11
11
|
id: `${source.id}/${keyFromFile(file)}`,
|
|
12
12
|
source: source.id,
|
|
@@ -14,6 +14,7 @@ export function entryForFile(source, file, dims, collisionMesh) {
|
|
|
14
14
|
file,
|
|
15
15
|
...(dims === undefined ? {} : { dims }),
|
|
16
16
|
...(collisionMesh === undefined ? {} : { collisionMesh }),
|
|
17
|
+
...(clips === undefined ? {} : { clips }),
|
|
17
18
|
};
|
|
18
19
|
}
|
|
19
20
|
function collectGlbFiles(dir) {
|
|
@@ -45,6 +46,14 @@ function measureCollisionMesh(bytes) {
|
|
|
45
46
|
return undefined;
|
|
46
47
|
}
|
|
47
48
|
}
|
|
49
|
+
function measureClips(bytes) {
|
|
50
|
+
try {
|
|
51
|
+
return readGlbClips(bytes) ?? undefined;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
48
57
|
function entryFromGlb(source, file, full) {
|
|
49
58
|
let bytes;
|
|
50
59
|
try {
|
|
@@ -55,7 +64,7 @@ function entryFromGlb(source, file, full) {
|
|
|
55
64
|
}
|
|
56
65
|
const id = `${source.id}/${keyFromFile(file)}`;
|
|
57
66
|
const collisionMesh = COLLISION_MESH_ASSET_IDS.has(id) ? measureCollisionMesh(bytes) : undefined;
|
|
58
|
-
return entryForFile(source, file, measureDims(bytes), collisionMesh);
|
|
67
|
+
return entryForFile(source, file, measureDims(bytes), collisionMesh, measureClips(bytes));
|
|
59
68
|
}
|
|
60
69
|
export function indexSourceDir(source, dir) {
|
|
61
70
|
const seen = new Set();
|
package/dist/manifest.d.ts
CHANGED
|
@@ -42,6 +42,8 @@ export interface IndexEntry {
|
|
|
42
42
|
dims?: ModelDims;
|
|
43
43
|
/** Opt-in compact triangle mesh extracted at reindex (see {@link "@jgengine/core/scene/collisionMesh".CollisionMeshData}); present only for ids in `COLLISION_MESH_ASSET_IDS` whose geometry extracted. */
|
|
44
44
|
collisionMesh?: CollisionMeshData;
|
|
45
|
+
/** Animation clip names read from the GLB at reindex; absent for unrigged/unreadable models. */
|
|
46
|
+
clips?: readonly string[];
|
|
45
47
|
/** Authored asset-space metadata (canonical facing, unit scale, footprint, anchor, bounds, rotation policy); absent unless a curator overrides the measured defaults. */
|
|
46
48
|
space?: AssetSpace;
|
|
47
49
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jgengine/assets",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Self-generating, license-verified index of thousands of CC0 3D models for JGengine. Sources fetch from providers' own CDNs at pull time; the npm tarball ships only the typed index and CLI (no GLB bytes).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"test": "bun test src"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@jgengine/core": "^0.
|
|
38
|
+
"@jgengine/core": "^0.14.0",
|
|
39
39
|
"fflate": "^0.8.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
package/skills/jgengine/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ description: Route game work to the smallest useful JGengine guidance set.
|
|
|
5
5
|
|
|
6
6
|
# JGengine intake and router
|
|
7
7
|
|
|
8
|
-
Read the
|
|
8
|
+
Read the JGengine README for package truth, commands, layering, and license — the repo-root [`README.md`](../../../README.md) in the monorepo, or [jgengine.com](https://jgengine.com) from a scaffolded consumer project (where the relative link does not resolve). This skill decides what to load; it is not an engine manual.
|
|
9
9
|
|
|
10
10
|
## 1. Establish the target
|
|
11
11
|
|
|
@@ -20,6 +20,8 @@ Treat the pitch as a unique composition of needs, not a genre to fill in — nev
|
|
|
20
20
|
|
|
21
21
|
For a new in-repo game, scaffold with `bun run new:game "<id-or-title>"` (thin script alias for `jgengine create`, auto-detects the in-repo variant). Outside this monorepo, start with `npx jgengine create`; never copy `Games/*`.
|
|
22
22
|
|
|
23
|
+
For an existing game asked to pick up a new engine release ("jgengine published a new version, grab it"), run `npx jgengine upgrade` in the project first: it diffs installed `@jgengine/*` versions against the latest release and prints every Migrate step and Adopt-worthy addition in between (`--json` for structured output). Bump, migrate oldest-first, then work the Adopt lists instead of reconstructing the changelog by hand.
|
|
24
|
+
|
|
23
25
|
## 2. Select domains
|
|
24
26
|
|
|
25
27
|
Load only rows the target needs. Do not preload every domain.
|
|
@@ -42,7 +44,8 @@ World content routes editor-first: any request that adds, moves, restyles, or re
|
|
|
42
44
|
|
|
43
45
|
Within each selected domain:
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
0. Fastest start for a common composition: `npx jgengine recipe <name>` prints a vetted, SDK-typechecked snippet (imports + wired code) for `combat-loop`, `boss-telegraph`, `loot`, `quest`, `coop-presence`, `third-person-camera`; `npx jgengine recipe` lists them. Copy that instead of reconning per-file.
|
|
48
|
+
1. Search `capabilities.md` by intent; it maps needs to imports. Outside the monorepo (or before a domain skill is even loaded), `npx jgengine find <intent>` greps every shipped capability index at once and prints the primitive + import — reach for it the moment you're tempted to hand-roll a HUD window, inventory grid, paperdoll, hotkey listener, minimap, stat bar, or character motion. If you're writing a `z-index`, a `keydown` for a panel, a `<div>` inventory, or a limb bob, a shipped drop-in almost certainly exists (`usePanels`/`PanelHost`, `InventoryGrid`, `CharacterSheet`/`Paperdoll`, `PartMotionRig`, `EntityPreview`); games own the *skin*, not the re-derivation.
|
|
46
49
|
2. Open `api.md` only when exact signatures or export inventory are needed.
|
|
47
50
|
3. Open the linked reference only for a deeper recipe or trap.
|
|
48
51
|
4. For how several primitives wire into a running loop, read the domain's `recipes/` — connected, genre-free walkthroughs organized by composition seam; this skill's own [recipes/minimal-game.md](recipes/minimal-game.md) is the default whole-game walkthrough. Prefer a recipe over reading a game's source; the games under `Games/*` are not templates or references, and a hybrid game is just a different composition of the same primitives.
|
package/skills/jgengine/api.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
- `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
|
|
8
8
|
- `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
|
|
9
|
-
- `VERSION` (const): const VERSION: "0.
|
|
9
|
+
- `VERSION` (const): const VERSION: "0.14.0" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
|
|
10
10
|
|
|
11
11
|
## @jgengine/core/authoring
|
|
12
12
|
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
- `WorldFeature` (type): type WorldFeature = | PlaceWorldFeature | ({ kind: "biomes" } & BiomesWorldConfig) | ({ kind: "voxel" } & VoxelWorldConfig) | ({ kind: "plots" } & PlotsWorldConfig) | ({ kind: "tilemap" } & TilemapWorldConfig) | EnvironmentWorldFeature | { kind: "flat" } — A declared world shape passed to `defineGame`. The preferred model is the place feature from `world()` (`@jgengine/core/world/place`): substrate + laws, with all dressing authored in the editor. The remaining members — biomes, voxel grid, plots, tilemap, environment, flat — are the legacy code-declared shapes kept for existing games.
|
|
39
39
|
- `auditManifest` (function): function auditManifest(manifest: SceneOwnershipManifest): OwnershipDiagnostic[] — Audit every declaration in a manifest, keying diagnostics by each object's provenance id. An empty result means the manifest declares all of its content cleanly — every object is authored, generated, bakeable, or a reasoned runtime/transient object.
|
|
40
40
|
- `biomes` (function): function biomes(config: BiomesWorldConfig): WorldFeature — Declares a biome-painted world — the whole-world alternative to a single `environment()` terrain.
|
|
41
|
-
- `building` (function): function building(config: BuildingEnvironmentConfig = {}): BuildingEnvironmentDescriptor — Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style.
|
|
41
|
+
- `building` (function): function building(config: BuildingEnvironmentConfig = {}): BuildingEnvironmentDescriptor — Declares a cluster of procedurally-massed buildings for `environment()` — count, footprint, stories, style. Pass `along` to line road frontage instead of gridding around `position`.
|
|
42
42
|
- `classifyOwnership` (function): function classifyOwnership(declaration: SceneOwnershipDeclaration): OwnershipVerdict — Resolve one declaration into a single boundary verdict.
|
|
43
43
|
- `collectOwnershipDiagnostics` (function): function collectOwnershipDiagnostics(entries: Iterable<readonly [string, SceneOwnershipDeclaration]>): OwnershipDiagnostic[] — Audit a keyed set of declarations and return one diagnostic per object that breaks the boundary contract (a `reject` verdict carrying a `violation`). Deterministic: diagnostics come back in the iteration order of `entries`.
|
|
44
44
|
- `contextVerb` (function): function contextVerb(label: string, command: string, args?: Record<string, unknown>): ContextVerb — Builds a {@link ContextVerb} for a right-click menu entry.
|
|
@@ -209,11 +209,18 @@
|
|
|
209
209
|
- `Tunable` (interface): interface Tunable<T> — Typed handle to a registered control, exposing its live value and subscribe/set/reset operations.
|
|
210
210
|
- `TunableAccessor` (interface): interface TunableAccessor — Get/set accessor pair plus initial value used to bind a discovered field to a control.
|
|
211
211
|
|
|
212
|
+
## @jgengine/core/devtools/urlFlags
|
|
213
|
+
|
|
214
|
+
- `readUrlFlag` (function): function readUrlFlag(param: string): boolean — True when `param` is present and not an explicit off value (`0`/`false`/`off`/`no`).
|
|
215
|
+
- `readUrlParam` (function): function readUrlParam(param: string): string | null — The current query value of `param`, or null when absent (or no DOM).
|
|
216
|
+
- `subscribeUrlChange` (function): function subscribeUrlChange(listener: () => void): () => void — Fires `listener` whenever the query string may have changed out from under a flag — browser back/forward (`popstate`). Manual address-bar edits reload the page, so initial reads cover those; this keeps in-app state honest across history navigation. Returns an unsubscribe.
|
|
217
|
+
- `writeUrlParam` (function): function writeUrlParam(param: string, value: string | null): void — Sets `param` to `value`, or removes it when `value` is null, rewriting the URL in place with `history.replaceState` so the rest of the query and the hash survive and no history entry is pushed. No-ops without a DOM, and skips the write when the URL already matches.
|
|
218
|
+
|
|
212
219
|
## @jgengine/core/meta/changelog
|
|
213
220
|
|
|
214
221
|
- `CHANGELOG` (const): const CHANGELOG: Record<string, ChangelogEntry> — Per-version engine changelog keyed by semver string (e.g. `"0.10.0"`).
|
|
215
222
|
- `ChangelogEntry` (interface): interface ChangelogEntry — One release's migrate steps plus added/changed/removed notes (typed mirror of CHANGELOG.md).
|
|
216
|
-
- `VERSION` (const): const VERSION: "0.
|
|
223
|
+
- `VERSION` (const): const VERSION: "0.14.0" — Installed `@jgengine/core` semver — compare against {@link CHANGELOG} keys when migrating.
|
|
217
224
|
|
|
218
225
|
## @jgengine/core/runtime/adapter
|
|
219
226
|
|
|
@@ -276,7 +283,7 @@
|
|
|
276
283
|
- `SceneObjectContext` (interface): interface SceneObjectContext extends ObjectStore — ⚠ undocumented
|
|
277
284
|
- `SceneWorldItemContext` (interface): interface SceneWorldItemContext — ⚠ undocumented
|
|
278
285
|
- `TelegraphInput` (interface): interface TelegraphInput — ⚠ undocumented
|
|
279
|
-
- `VfxInput` (interface): interface VfxInput — Request a transient spell/ability VFX burst; `from`/`to` accept an instance id or a world point
|
|
286
|
+
- `VfxInput` (interface): interface VfxInput — Request a transient spell/ability VFX burst. The easy path is a named `preset` — `vfx({ preset: "arrow", from: caster, to: enemy })` renders a visible bolt with no color or archetype tuning; `"lightning"`, `"web"`, `"slash"`, `"shield"`, `"heal"`, `"explosion"` and the rest of {@link vfxPresets} likewise just work. `from`/`to` accept an instance id (the shell follows its live pose) or a fixed world point. Anything you also pass — `kind`, `color` (`0xRRGGBB`), `radius`, `durationMs` — overrides the preset; supply `kind` + `color` yourself for a fully custom burst with no preset. `durationMs` defaults per `kind`.
|
|
280
287
|
- `WorldItemPickupResult` (type): type WorldItemPickupResult = | { status: "ok"; record: WorldItemRecord } | { status: "rejected"; reason: string } — ⚠ undocumented
|
|
281
288
|
- `createGameContext` (function): function createGameContext<TAssetRef extends ModelAssetRef, TMultiplayer>(options: GameContextOptions<TAssetRef, TMultiplayer>): GameContext — ⚠ undocumented
|
|
282
289
|
|
|
@@ -307,7 +314,7 @@
|
|
|
307
314
|
- `SceneObjectContext` (interface): interface SceneObjectContext extends ObjectStore — ⚠ undocumented
|
|
308
315
|
- `SceneWorldItemContext` (interface): interface SceneWorldItemContext — ⚠ undocumented
|
|
309
316
|
- `TelegraphInput` (interface): interface TelegraphInput — ⚠ undocumented
|
|
310
|
-
- `VfxInput` (interface): interface VfxInput — Request a transient spell/ability VFX burst; `from`/`to` accept an instance id or a world point
|
|
317
|
+
- `VfxInput` (interface): interface VfxInput — Request a transient spell/ability VFX burst. The easy path is a named `preset` — `vfx({ preset: "arrow", from: caster, to: enemy })` renders a visible bolt with no color or archetype tuning; `"lightning"`, `"web"`, `"slash"`, `"shield"`, `"heal"`, `"explosion"` and the rest of {@link vfxPresets} likewise just work. `from`/`to` accept an instance id (the shell follows its live pose) or a fixed world point. Anything you also pass — `kind`, `color` (`0xRRGGBB`), `radius`, `durationMs` — overrides the preset; supply `kind` + `color` yourself for a fully custom burst with no preset. `durationMs` defaults per `kind`.
|
|
311
318
|
- `WorldItemPickupResult` (type): type WorldItemPickupResult = | { status: "ok"; record: WorldItemRecord } | { status: "rejected"; reason: string } — ⚠ undocumented
|
|
312
319
|
|
|
313
320
|
## @jgengine/core/runtime/gameRuntime
|
|
@@ -322,6 +329,7 @@
|
|
|
322
329
|
|
|
323
330
|
## @jgengine/core/runtime/headlessRunner
|
|
324
331
|
|
|
332
|
+
- `HeadlessCommandInterface` (interface): interface HeadlessCommandInterface — Canvas-free command/intent surface for {@link HeadlessRunner} — invoke a game's registered UI commands and read the resulting reactive state off `ctx`.
|
|
325
333
|
- `HeadlessInput` (interface): interface HeadlessInput — One step's worth of player intent handed to {@link HeadlessRunner.step} — the held-action set and pointer state the shell would otherwise publish from the browser each frame.
|
|
326
334
|
- `HeadlessRunner` (interface): interface HeadlessRunner — A renderer-free driver for a game loop: builds a {@link GameContext} from a {@link GameDefinition}, runs the init hooks, then advances the simulation one step at a time from injected input. No React, R3F, or three.js — the whole play path (time, input, `onTick`, behaviour nav, optional player movement) runs from `core` primitives alone, so a non-React host (a server tick, a test, a CLI replay) can play a real game and read its world snapshot. The shell's FrameDriver is one such driver bolted to `useFrame`; this is the same step distilled out of the render tree.
|
|
327
335
|
- `HeadlessRunnerOptions` (interface): interface HeadlessRunnerOptions<TAssetRef extends ModelAssetRef, TMultiplayer> — ⚠ undocumented
|
|
@@ -28,7 +28,11 @@ A game's catalog is `buildCatalog(...)` over the generated pack index, singles,
|
|
|
28
28
|
|
|
29
29
|
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
30
|
|
|
31
|
-
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.
|
|
31
|
+
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
|
+
|
|
33
|
+
## Rigged assets animate by default
|
|
34
|
+
|
|
35
|
+
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`.
|
|
32
36
|
|
|
33
37
|
## Source rules
|
|
34
38
|
|
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
## @jgengine/assets/dims
|
|
123
123
|
|
|
124
124
|
- `ModelDims` (interface): interface ModelDims — Measured horizontal footprint, footprint center, and lowest Y of a model in model space.
|
|
125
|
+
- `readGlbClips` (function): function readGlbClips(bytes: Uint8Array): string[] | null — Animation clip names read from a GLB's JSON chunk, de-duplicated and order-preserving; `null` for an unreadable GLB or one with no (named) animations.
|
|
125
126
|
- `readGlbCollisionMesh` (function): function readGlbCollisionMesh(bytes: Uint8Array): CollisionMeshData | null — Extract a model-space collision triangle soup from a GLB and compress it with {@link encodeCollisionMesh}. Walks the default scene, transforming each TRIANGLES primitive's float32 VEC3 positions by the node's world matrix, and returns `null` for a JSON-only GLB or when no triangle survives quantization.
|
|
126
127
|
- `readGlbDims` (function): function readGlbDims(bytes: Uint8Array): ModelDims | null — ⚠ undocumented
|
|
127
128
|
|
|
@@ -162,7 +163,7 @@
|
|
|
162
163
|
## @jgengine/assets/indexGen
|
|
163
164
|
|
|
164
165
|
- `ReindexResult` (interface): interface ReindexResult — ⚠ undocumented
|
|
165
|
-
- `entryForFile` (function): function entryForFile(source: AssetSource, file: string, dims?: ModelDims, collisionMesh?: CollisionMeshData): IndexEntry — ⚠ undocumented
|
|
166
|
+
- `entryForFile` (function): function entryForFile(source: AssetSource, file: string, dims?: ModelDims, collisionMesh?: CollisionMeshData, clips?: readonly string[]): IndexEntry — ⚠ undocumented
|
|
166
167
|
- `indexSourceDir` (function): function indexSourceDir(source: AssetSource, dir: string): IndexEntry[] — ⚠ undocumented
|
|
167
168
|
- `keyFromFile` (function): function keyFromFile(file: string): string — ⚠ undocumented
|
|
168
169
|
- `reindex` (function): function reindex(modelsDir: string, outDir: string): ReindexResult — ⚠ undocumented
|
|
@@ -8,6 +8,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
8
8
|
|
|
9
9
|
- `validateAssetReferences` (function) · `import { validateAssetReferences } from "@jgengine/assets"`
|
|
10
10
|
|
|
11
|
+
## clip-metadata — read a GLB's animation clip names for the asset index at reindex
|
|
12
|
+
|
|
13
|
+
- `readGlbClips` (function) · `import { readGlbClips } from "@jgengine/assets/dims"`
|
|
14
|
+
|
|
11
15
|
## starter-packs — themed CC0 model ids (people/props/nature/urban) ready for entityModels
|
|
12
16
|
|
|
13
17
|
- `StarterTheme` (type) · `import { StarterTheme } from "@jgengine/assets"`
|