@jgengine/assets 0.10.0 → 0.11.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 +13 -2
- package/README.md +103 -50
- package/dist/aliases.d.ts +5 -0
- package/dist/aliases.js +28 -9
- package/dist/catalogs/build.js +9 -0
- package/dist/catalogs/buildSprites.d.ts +10 -0
- package/dist/catalogs/buildSprites.js +15 -0
- package/dist/catalogs/starter.d.ts +5 -0
- package/dist/catalogs/starter.js +10 -1
- package/dist/cli/paths.d.ts +9 -1
- package/dist/cli/paths.js +11 -1
- package/dist/cli/pull.d.ts +12 -0
- package/dist/cli/pull.js +210 -15
- package/dist/download.d.ts +46 -3
- package/dist/download.js +158 -9
- package/dist/find.d.ts +20 -1
- package/dist/find.js +52 -2
- package/dist/generated/index.js +18 -6
- package/dist/generated/kaykit-adventurers.json +674 -0
- package/dist/generated/kaykit-city-builder.json +863 -0
- package/dist/generated/kaykit-dungeon.json +4265 -0
- package/dist/generated/kaykit-furniture.json +1115 -0
- package/dist/generated/kaykit-skeletons.json +410 -0
- package/dist/generated/kaykit-space-base.json +1199 -0
- package/dist/generated/quaternius-medieval-village.json +3698 -0
- package/dist/generated/quaternius-modular-scifi.json +4013 -0
- package/dist/generated/quaternius-stylized-nature.json +1430 -0
- package/dist/generated-sprites/index.d.ts +5 -0
- package/dist/generated-sprites/index.js +4 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.js +9 -2
- package/dist/indexGen.js +7 -5
- package/dist/manifest.d.ts +12 -1
- package/dist/materials.d.ts +61 -0
- package/dist/materials.js +98 -0
- package/dist/packs/starter.d.ts +46 -0
- package/dist/packs/starter.js +248 -0
- package/dist/provisioning.d.ts +88 -0
- package/dist/provisioning.js +74 -0
- package/dist/registry-catalog.json +40 -0
- package/dist/snippet.d.ts +4 -0
- package/dist/snippet.js +27 -0
- package/dist/sources/ambientcg.d.ts +5 -0
- package/dist/sources/ambientcg.js +64 -0
- package/dist/sources/gameicons.d.ts +10 -0
- package/dist/sources/gameicons.js +21 -0
- package/dist/sources/index.d.ts +9 -2
- package/dist/sources/index.js +11 -3
- package/dist/sources/kaykit.js +55 -6
- package/dist/sources/quaternius.js +60 -9
- package/dist/spriteIndexGen.d.ts +17 -0
- package/dist/spriteIndexGen.js +108 -0
- package/dist/verify.d.ts +1 -0
- package/dist/verify.js +38 -1
- package/package.json +4 -4
- package/skills/jgengine/SKILL.md +51 -0
- package/skills/jgengine/api.md +434 -0
- package/skills/jgengine/capabilities.md +29 -0
- package/skills/jgengine/reference-cartridge.md +72 -0
- package/skills/jgengine-assets/SKILL.md +41 -0
- package/skills/jgengine-assets/api.md +273 -0
- package/skills/jgengine-assets/capabilities.md +13 -0
- package/dist/generated/kenney-blaster.json +0 -362
- package/dist/generated/kenney-nature.json +0 -3292
- package/dist/generated/kenney-space.json +0 -1532
- package/dist/sources/kenney.d.ts +0 -2
- package/dist/sources/kenney.js +0 -36
- package/llms.txt +0 -1010
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { AssetAlias, IndexEntry, SingleAsset } from "./manifest.js";
|
|
2
|
+
/**
|
|
3
|
+
* How an asset id's bytes reach a clean checkout:
|
|
4
|
+
* - `committed` — resolves to a self-hosted / remote URL carried in the shipped
|
|
5
|
+
* index (a {@link SingleAsset}); no pull step, available immediately.
|
|
6
|
+
* - `provisioned` — a pack {@link IndexEntry}; the id is declared but its GLB is
|
|
7
|
+
* fetched on demand by `assets pull <source>` into the consumer's served dir.
|
|
8
|
+
* - `dangling` — nothing in the index, singles, or aliases owns the id, so no
|
|
9
|
+
* provisioning step exists and it can never resolve on a clean clone.
|
|
10
|
+
*/
|
|
11
|
+
export type AssetProvenanceKind = "committed" | "provisioned" | "dangling";
|
|
12
|
+
/** The resolved ownership of one logical asset id — the provisioning contract for that id. */
|
|
13
|
+
export interface AssetProvenance {
|
|
14
|
+
id: string;
|
|
15
|
+
kind: AssetProvenanceKind;
|
|
16
|
+
/**
|
|
17
|
+
* Where the bytes live once available: the committed URL for `committed`, the
|
|
18
|
+
* `<source>/<file>` served path for `provisioned`, or `null` for `dangling`.
|
|
19
|
+
*/
|
|
20
|
+
resolvedPath: string | null;
|
|
21
|
+
/** The pack source that must be pulled, for `provisioned` ids. */
|
|
22
|
+
sourceId?: string;
|
|
23
|
+
/** The exact command that makes a `provisioned` id resolve, e.g. `assets pull quaternius-stylized-nature`. */
|
|
24
|
+
provisioningStep?: string;
|
|
25
|
+
/** When the id was reached through an alias, the alias key that pointed at it. */
|
|
26
|
+
viaAlias?: string;
|
|
27
|
+
}
|
|
28
|
+
/** Override the data {@link resolveProvenance} resolves against; every field defaults to the shipped catalog. */
|
|
29
|
+
export interface ResolveProvenanceOptions {
|
|
30
|
+
/** Index entries to resolve against; defaults to the shipped generated index. */
|
|
31
|
+
index?: readonly IndexEntry[];
|
|
32
|
+
singles?: readonly SingleAsset[];
|
|
33
|
+
aliases?: readonly AssetAlias[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve one logical asset id (a pack id, a single id, or an alias key) to its
|
|
37
|
+
* {@link AssetProvenance}. Aliases are followed one hop to their target. An id
|
|
38
|
+
* that matches no declared owner is `dangling` — the signal a clean-clone gate
|
|
39
|
+
* turns into a hard failure, because no provisioning step can ever satisfy it.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveProvenance(id: string, options?: ResolveProvenanceOptions): AssetProvenance;
|
|
42
|
+
/** A logical asset id referenced by some consumer (a game, scene, or config), for validation. */
|
|
43
|
+
export interface AssetReference {
|
|
44
|
+
/** Who references the id — a game id, scene path, or config name — surfaced in the failure. */
|
|
45
|
+
consumer: string;
|
|
46
|
+
/** The logical asset id / alias key the consumer expects to resolve. */
|
|
47
|
+
id: string;
|
|
48
|
+
}
|
|
49
|
+
/** The verdict for one {@link AssetReference}. */
|
|
50
|
+
export interface ReferenceValidation {
|
|
51
|
+
reference: AssetReference;
|
|
52
|
+
provenance: AssetProvenance;
|
|
53
|
+
ok: boolean;
|
|
54
|
+
/** Set only when `ok` is false — a one-line diagnostic naming consumer, id, and resolved path. */
|
|
55
|
+
error?: string;
|
|
56
|
+
}
|
|
57
|
+
/** Options for {@link validateAssetReferences}: the resolution data plus an optional on-disk `present` check. */
|
|
58
|
+
export interface ValidateAssetReferencesOptions extends ResolveProvenanceOptions {
|
|
59
|
+
/**
|
|
60
|
+
* Optional predicate reporting whether a `provisioned` id's bytes are already
|
|
61
|
+
* on disk (its `resolvedPath`). When supplied, a provisioned-but-absent id is a
|
|
62
|
+
* failure — the stricter "clean checkout with a provisioning pass already run"
|
|
63
|
+
* mode. Omit it for the pre-merge gate, where a declared provisioning owner is
|
|
64
|
+
* enough and the pull runs later in `ensure-ready`.
|
|
65
|
+
*/
|
|
66
|
+
present?: (resolvedPath: string) => boolean;
|
|
67
|
+
}
|
|
68
|
+
/** The aggregate result of validating a set of references against the provisioning contract. */
|
|
69
|
+
export interface ValidateAssetReferencesResult {
|
|
70
|
+
ok: boolean;
|
|
71
|
+
results: readonly ReferenceValidation[];
|
|
72
|
+
/** One diagnostic line per failing reference. */
|
|
73
|
+
errors: readonly string[];
|
|
74
|
+
/** The unique provisioning steps every `provisioned` reference needs, e.g. for `ensure-ready`. */
|
|
75
|
+
provisioning: readonly string[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Validate that every {@link AssetReference} resolves against the declared
|
|
79
|
+
* provisioning contract — not by grepping source text, but by resolving each
|
|
80
|
+
* logical id to its committed / provisioned / dangling owner. A `dangling`
|
|
81
|
+
* reference fails with the referencing consumer, the logical id, the (null)
|
|
82
|
+
* resolved path, and the missing provisioning step; a `provisioned` reference
|
|
83
|
+
* passes and contributes its `assets pull <source>` step to `provisioning`
|
|
84
|
+
* (unless `present` is supplied and reports the bytes absent).
|
|
85
|
+
*
|
|
86
|
+
* @capability asset-reference-integrity validate asset references against the provisioning contract (dangling / committed / provisioned)
|
|
87
|
+
*/
|
|
88
|
+
export declare function validateAssetReferences(references: readonly AssetReference[], options?: ValidateAssetReferencesOptions): ValidateAssetReferencesResult;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { aliases } from "./aliases.js";
|
|
2
|
+
import { generatedIndex } from "./generated/index.js";
|
|
3
|
+
import { singles } from "./singles.js";
|
|
4
|
+
function provisionedPath(entry) {
|
|
5
|
+
return `${entry.source}/${entry.file}`;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Resolve one logical asset id (a pack id, a single id, or an alias key) to its
|
|
9
|
+
* {@link AssetProvenance}. Aliases are followed one hop to their target. An id
|
|
10
|
+
* that matches no declared owner is `dangling` — the signal a clean-clone gate
|
|
11
|
+
* turns into a hard failure, because no provisioning step can ever satisfy it.
|
|
12
|
+
*/
|
|
13
|
+
export function resolveProvenance(id, options = {}) {
|
|
14
|
+
const index = options.index ?? generatedIndex;
|
|
15
|
+
const singleList = options.singles ?? singles;
|
|
16
|
+
const aliasList = options.aliases ?? aliases;
|
|
17
|
+
const alias = aliasList.find((entry) => entry.key === id);
|
|
18
|
+
if (alias !== undefined) {
|
|
19
|
+
const resolved = resolveProvenance(alias.target, { index, singles: singleList, aliases: aliasList });
|
|
20
|
+
return { ...resolved, id, viaAlias: alias.key };
|
|
21
|
+
}
|
|
22
|
+
const entry = index.find((candidate) => candidate.id === id);
|
|
23
|
+
if (entry !== undefined) {
|
|
24
|
+
return {
|
|
25
|
+
id,
|
|
26
|
+
kind: "provisioned",
|
|
27
|
+
resolvedPath: provisionedPath(entry),
|
|
28
|
+
sourceId: entry.source,
|
|
29
|
+
provisioningStep: `assets pull ${entry.source}`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const single = singleList.find((candidate) => candidate.id === id);
|
|
33
|
+
if (single !== undefined) {
|
|
34
|
+
return { id, kind: "committed", resolvedPath: single.url };
|
|
35
|
+
}
|
|
36
|
+
return { id, kind: "dangling", resolvedPath: null };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Validate that every {@link AssetReference} resolves against the declared
|
|
40
|
+
* provisioning contract — not by grepping source text, but by resolving each
|
|
41
|
+
* logical id to its committed / provisioned / dangling owner. A `dangling`
|
|
42
|
+
* reference fails with the referencing consumer, the logical id, the (null)
|
|
43
|
+
* resolved path, and the missing provisioning step; a `provisioned` reference
|
|
44
|
+
* passes and contributes its `assets pull <source>` step to `provisioning`
|
|
45
|
+
* (unless `present` is supplied and reports the bytes absent).
|
|
46
|
+
*
|
|
47
|
+
* @capability asset-reference-integrity validate asset references against the provisioning contract (dangling / committed / provisioned)
|
|
48
|
+
*/
|
|
49
|
+
export function validateAssetReferences(references, options = {}) {
|
|
50
|
+
const results = [];
|
|
51
|
+
const errors = [];
|
|
52
|
+
const provisioning = new Set();
|
|
53
|
+
for (const reference of references) {
|
|
54
|
+
const provenance = resolveProvenance(reference.id, options);
|
|
55
|
+
if (provenance.kind === "dangling") {
|
|
56
|
+
const error = `${reference.consumer}: asset "${reference.id}" is dangling — no committed/provisioned owner declares it (resolved path: none). Add a source in packages/assets/src/sources/*.ts or a single, or remove the reference.`;
|
|
57
|
+
results.push({ reference, provenance, ok: false, error });
|
|
58
|
+
errors.push(error);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (provenance.kind === "provisioned") {
|
|
62
|
+
if (provenance.provisioningStep !== undefined)
|
|
63
|
+
provisioning.add(provenance.provisioningStep);
|
|
64
|
+
if (options.present !== undefined && provenance.resolvedPath !== null && !options.present(provenance.resolvedPath)) {
|
|
65
|
+
const error = `${reference.consumer}: asset "${reference.id}" is not provisioned — expected bytes at "${provenance.resolvedPath}". Run \`${provenance.provisioningStep}\`.`;
|
|
66
|
+
results.push({ reference, provenance, ok: false, error });
|
|
67
|
+
errors.push(error);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
results.push({ reference, provenance, ok: true });
|
|
72
|
+
}
|
|
73
|
+
return { ok: errors.length === 0, results, errors, provisioning: [...provisioning].sort() };
|
|
74
|
+
}
|
|
@@ -51,6 +51,11 @@
|
|
|
51
51
|
"title": "Buff Tray",
|
|
52
52
|
"description": "Row of chamfered buff/debuff chips with stack counts and a remaining-duration underline, driven by a plain chip array."
|
|
53
53
|
},
|
|
54
|
+
{
|
|
55
|
+
"name": "cartridge-panels",
|
|
56
|
+
"title": "Cartridge Panels",
|
|
57
|
+
"description": "Standard panel bindings for @jgengine/shell/cartridge: vital/xp/timer/score/ability-bar HUD items, upgrade-draft modal, and win/lose screens composed from the jgengine UI kit."
|
|
58
|
+
},
|
|
54
59
|
{
|
|
55
60
|
"name": "cast-bar",
|
|
56
61
|
"title": "Cast Bar",
|
|
@@ -61,6 +66,11 @@
|
|
|
61
66
|
"title": "Charge Meter",
|
|
62
67
|
"description": "Slant-clipped charge or ultimate meter with tier ticks and a ready-state glow animation."
|
|
63
68
|
},
|
|
69
|
+
{
|
|
70
|
+
"name": "chat-bubble",
|
|
71
|
+
"title": "Chat Bubble",
|
|
72
|
+
"description": "Over-entity speech bubble for proximity chat — presentational, value-driven."
|
|
73
|
+
},
|
|
64
74
|
{
|
|
65
75
|
"name": "combat-float-layer",
|
|
66
76
|
"title": "Combat Float Layer",
|
|
@@ -106,6 +116,11 @@
|
|
|
106
116
|
"title": "Dialogue Panel",
|
|
107
117
|
"description": "Notched dialogue box with speaker nameplate, portrait well, and skill-check-annotated branching choices."
|
|
108
118
|
},
|
|
119
|
+
{
|
|
120
|
+
"name": "entity-chat-bubble",
|
|
121
|
+
"title": "Entity Chat Bubble",
|
|
122
|
+
"description": "ChatBubble bound to a live entity's latest proximity chat message via useEntityChatBubble — the one-line speech bubble for any entity instance."
|
|
123
|
+
},
|
|
109
124
|
{
|
|
110
125
|
"name": "entity-vital-bar",
|
|
111
126
|
"title": "Entity Vital Bar",
|
|
@@ -216,6 +231,11 @@
|
|
|
216
231
|
"title": "Lock-On Marker",
|
|
217
232
|
"description": "Rotating corner-bracket lock-on reticle that snaps into a diamond frame when a target is acquired, with an optional label."
|
|
218
233
|
},
|
|
234
|
+
{
|
|
235
|
+
"name": "loop-dial",
|
|
236
|
+
"title": "Loop Dial",
|
|
237
|
+
"description": "Radial position-around-a-loop dial: markers at cycle fractions plus live/forecast arc windows — laps, patrols, rotation schedules."
|
|
238
|
+
},
|
|
219
239
|
{
|
|
220
240
|
"name": "loot-card",
|
|
221
241
|
"title": "Loot Card",
|
|
@@ -241,6 +261,11 @@
|
|
|
241
261
|
"title": "Moodle Tray",
|
|
242
262
|
"description": "Buff Tray adapter for survival-game Moodle records — maps severity to buff/debuff tint and fraction to the duration ring."
|
|
243
263
|
},
|
|
264
|
+
{
|
|
265
|
+
"name": "mount",
|
|
266
|
+
"title": "Mount",
|
|
267
|
+
"description": "One-call React root mount for a PlayableGame: mountGame(game) renders GameHost into #root."
|
|
268
|
+
},
|
|
244
269
|
{
|
|
245
270
|
"name": "objective-channel",
|
|
246
271
|
"title": "Objective Channel",
|
|
@@ -256,6 +281,16 @@
|
|
|
256
281
|
"title": "Pickup Toast Stack",
|
|
257
282
|
"description": "Stacked, fading pickup toasts with rarity-tinted icon/label/count — presentational, list-driven."
|
|
258
283
|
},
|
|
284
|
+
{
|
|
285
|
+
"name": "playing-card",
|
|
286
|
+
"title": "Playing Card",
|
|
287
|
+
"description": "French-deck card face with rank, suit pips, and a patterned back when face-down, plus an overlapping stack."
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"name": "progress-strip",
|
|
291
|
+
"title": "Progress Strip",
|
|
292
|
+
"description": "Linear 1D minimap: lanes with moving markers and live/forecast segments — race standings along a lap, couriers along a line."
|
|
293
|
+
},
|
|
259
294
|
{
|
|
260
295
|
"name": "quest-tracker",
|
|
261
296
|
"title": "Quest Tracker",
|
|
@@ -286,6 +321,11 @@
|
|
|
286
321
|
"title": "Reticle",
|
|
287
322
|
"description": "Configurable crosshair reticle — dot, cross, circle, chevron, or shotgun spread pattern — with an optional hit-flash tick overlay."
|
|
288
323
|
},
|
|
324
|
+
{
|
|
325
|
+
"name": "schematic-diagram",
|
|
326
|
+
"title": "Schematic Diagram",
|
|
327
|
+
"description": "Fixed-panel node+edge schematic independent of world positions — circuit layouts, rail networks, heist floor plans, with dashed forecast edges."
|
|
328
|
+
},
|
|
289
329
|
{
|
|
290
330
|
"name": "score-readout",
|
|
291
331
|
"title": "Score Readout",
|
package/dist/snippet.d.ts
CHANGED
|
@@ -7,7 +7,11 @@ export interface ModelSnippetOptions {
|
|
|
7
7
|
}
|
|
8
8
|
/** Copy-paste wiring for a pulled GLB id: resolve through the catalog, drop into a model seam. */
|
|
9
9
|
export declare function modelWiringSnippet(id: string, options?: ModelSnippetOptions): string;
|
|
10
|
+
/** Copy-paste wiring for a pulled PBR material: resolve the map URLs through the material catalog, then apply them onto terrain or a model. */
|
|
11
|
+
export declare function materialWiringSnippet(id: string, basePath?: string): string;
|
|
10
12
|
/** Copy-paste wiring for a HUD component: the `shadcn add` command plus import + usage. */
|
|
11
13
|
export declare function componentWiringSnippet(component: RegistryComponent): string;
|
|
14
|
+
/** Copy-paste wiring for a pulled sprite/icon-pack file: resolve through the sprite catalog. */
|
|
15
|
+
export declare function spriteWiringSnippet(id: string, basePath?: string): string;
|
|
12
16
|
/** Copy-paste wiring for a HUD glyph from the registry `game-icon` catalog. */
|
|
13
17
|
export declare function iconWiringSnippet(name: string): string;
|
package/dist/snippet.js
CHANGED
|
@@ -22,6 +22,23 @@ export function modelWiringSnippet(id, options = {}) {
|
|
|
22
22
|
`}`,
|
|
23
23
|
].join("\n");
|
|
24
24
|
}
|
|
25
|
+
/** Copy-paste wiring for a pulled PBR material: resolve the map URLs through the material catalog, then apply them onto terrain or a model. */
|
|
26
|
+
export function materialWiringSnippet(id, basePath = "/materials") {
|
|
27
|
+
return [
|
|
28
|
+
`// src/game/assets.ts`,
|
|
29
|
+
`import { buildMaterialCatalog } from "@jgengine/assets";`,
|
|
30
|
+
`export const materials = buildMaterialCatalog({ basePath: ${JSON.stringify(basePath)} });`,
|
|
31
|
+
``,
|
|
32
|
+
`const material = materials.resolve(${JSON.stringify(id)})!;`,
|
|
33
|
+
`// material.maps => { color, normal, roughness, ao, displacement } URLs under ${basePath}/${id}/`,
|
|
34
|
+
``,
|
|
35
|
+
`// onto the ground (terrain() in defineGame({ world: environment({ terrain: ... }) })):`,
|
|
36
|
+
`terrain({ detail: { material: { maps: material.maps, repeat: 4 } } })`,
|
|
37
|
+
``,
|
|
38
|
+
`// onto a model (entityModels / objectModels ModelConfig):`,
|
|
39
|
+
`{ url: ..., material: { maps: material.maps } }`,
|
|
40
|
+
].join("\n");
|
|
41
|
+
}
|
|
25
42
|
/** Copy-paste wiring for a HUD component: the `shadcn add` command plus import + usage. */
|
|
26
43
|
export function componentWiringSnippet(component) {
|
|
27
44
|
const symbol = pascalCase(component.name);
|
|
@@ -34,6 +51,16 @@ export function componentWiringSnippet(component) {
|
|
|
34
51
|
`// <${symbol} … /> — ${component.description}`,
|
|
35
52
|
].join("\n");
|
|
36
53
|
}
|
|
54
|
+
/** Copy-paste wiring for a pulled sprite/icon-pack file: resolve through the sprite catalog. */
|
|
55
|
+
export function spriteWiringSnippet(id, basePath = "/sprites") {
|
|
56
|
+
return [
|
|
57
|
+
`// src/game/assets.ts`,
|
|
58
|
+
`import { buildSpriteCatalog } from "@jgengine/assets";`,
|
|
59
|
+
`export const sprites = buildSpriteCatalog({ basePath: ${JSON.stringify(basePath)} });`,
|
|
60
|
+
``,
|
|
61
|
+
`sprites.resolve(${JSON.stringify(id)})!.url; // e.g. an <img src> or a HUD icon slot`,
|
|
62
|
+
].join("\n");
|
|
63
|
+
}
|
|
37
64
|
/** Copy-paste wiring for a HUD glyph from the registry `game-icon` catalog. */
|
|
38
65
|
export function iconWiringSnippet(name) {
|
|
39
66
|
return [
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AssetSource } from "../manifest.js";
|
|
2
|
+
/** Upstream asset id (`Grass001`) for a material source id (`ambientcg-grass001`). */
|
|
3
|
+
export declare function ambientcgAssetId(source: AssetSource): string;
|
|
4
|
+
/** Every ambientCG material source, generated per family (`ambientcg-grass001` … ). */
|
|
5
|
+
export declare const ambientcgSources: readonly AssetSource[];
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ambientCG (https://ambientcg.com) — CC0 PBR materials, downloaded as flat
|
|
3
|
+
* 1K-JPG zips from the site's stable `/get?file=` endpoint and mirrored to
|
|
4
|
+
* this repo's `packs` release like every other source. Each entry is one
|
|
5
|
+
* material; families are numbered `Family001…FamilyNNN` upstream, so the
|
|
6
|
+
* catalog is generated per family instead of hand-typing hundreds of ids.
|
|
7
|
+
*/
|
|
8
|
+
const RESOLUTION = "1K-JPG";
|
|
9
|
+
const FAMILIES = [
|
|
10
|
+
{ family: "Grass", count: 5, categories: ["ground", "grass", "nature"] },
|
|
11
|
+
{ family: "Ground", count: 25, categories: ["ground", "dirt", "mud"] },
|
|
12
|
+
{ family: "Rock", count: 25, categories: ["rock", "cliff", "stone"] },
|
|
13
|
+
{ family: "Rocks", count: 8, categories: ["rock", "scatter"] },
|
|
14
|
+
{ family: "Gravel", count: 15, categories: ["ground", "gravel"] },
|
|
15
|
+
{ family: "Snow", count: 6, categories: ["ground", "snow", "winter"] },
|
|
16
|
+
{ family: "Ice", count: 3, categories: ["ice", "winter"] },
|
|
17
|
+
{ family: "Lava", count: 4, categories: ["lava", "volcanic"] },
|
|
18
|
+
{ family: "Moss", count: 2, categories: ["moss", "nature"] },
|
|
19
|
+
{ family: "Bark", count: 8, categories: ["bark", "wood", "nature"] },
|
|
20
|
+
{ family: "Wood", count: 30, categories: ["wood"] },
|
|
21
|
+
{ family: "WoodFloor", count: 25, categories: ["wood", "floor", "interior"] },
|
|
22
|
+
{ family: "Planks", count: 12, categories: ["wood", "planks"] },
|
|
23
|
+
{ family: "Bricks", count: 30, categories: ["brick", "wall"] },
|
|
24
|
+
{ family: "PavingStones", count: 25, categories: ["paving", "stone", "path"] },
|
|
25
|
+
{ family: "Tiles", count: 30, categories: ["tile", "floor", "interior"] },
|
|
26
|
+
{ family: "Concrete", count: 25, categories: ["concrete", "urban"] },
|
|
27
|
+
{ family: "Asphalt", count: 12, categories: ["asphalt", "road", "urban"] },
|
|
28
|
+
{ family: "Metal", count: 25, categories: ["metal"] },
|
|
29
|
+
{ family: "MetalPlates", count: 10, categories: ["metal", "plates", "scifi"] },
|
|
30
|
+
{ family: "Fabric", count: 25, categories: ["fabric", "cloth"] },
|
|
31
|
+
{ family: "Leather", count: 12, categories: ["leather"] },
|
|
32
|
+
{ family: "Marble", count: 12, categories: ["marble", "stone", "interior"] },
|
|
33
|
+
{ family: "Plaster", count: 7, categories: ["plaster", "wall", "interior"] },
|
|
34
|
+
{ family: "Facade", count: 6, categories: ["facade", "building"] },
|
|
35
|
+
{ family: "Terrazzo", count: 8, categories: ["floor", "interior"] },
|
|
36
|
+
{ family: "Wicker", count: 4, categories: ["wicker"] },
|
|
37
|
+
{ family: "Rope", count: 2, categories: ["rope"] },
|
|
38
|
+
{ family: "Cardboard", count: 3, categories: ["cardboard", "prop"] },
|
|
39
|
+
{ family: "Paper", count: 3, categories: ["paper", "prop"] },
|
|
40
|
+
{ family: "RoofingTiles", count: 8, categories: ["roof", "tile", "building"] },
|
|
41
|
+
];
|
|
42
|
+
/** Upstream asset id (`Grass001`) for a material source id (`ambientcg-grass001`). */
|
|
43
|
+
export function ambientcgAssetId(source) {
|
|
44
|
+
const suffix = source.id.replace(/^ambientcg-/, "");
|
|
45
|
+
const digits = suffix.match(/\d+$/)?.[0] ?? "";
|
|
46
|
+
const family = FAMILIES.find((entry) => entry.family.toLowerCase() === suffix.slice(0, suffix.length - digits.length));
|
|
47
|
+
return `${family?.family ?? suffix}${digits}`;
|
|
48
|
+
}
|
|
49
|
+
function materialSource(family, index) {
|
|
50
|
+
const assetId = `${family.family}${String(index).padStart(3, "0")}`;
|
|
51
|
+
return {
|
|
52
|
+
id: `ambientcg-${assetId.toLowerCase()}`,
|
|
53
|
+
kind: "material",
|
|
54
|
+
provider: "ambientcg",
|
|
55
|
+
title: `${family.family} ${String(index).padStart(3, "0")} (PBR material)`,
|
|
56
|
+
license: "CC0-1.0",
|
|
57
|
+
author: "ambientCG",
|
|
58
|
+
categories: family.categories,
|
|
59
|
+
download: { url: `https://ambientcg.com/get?file=${assetId}_${RESOLUTION}.zip` },
|
|
60
|
+
homepage: `https://ambientcg.com/view?id=${assetId}`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Every ambientCG material source, generated per family (`ambientcg-grass001` … ). */
|
|
64
|
+
export const ambientcgSources = FAMILIES.flatMap((family) => Array.from({ length: family.count }, (_, index) => materialSource(family, index + 1)));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AssetSource } from "../manifest.js";
|
|
2
|
+
/**
|
|
3
|
+
* game-icons.net (https://game-icons.net) — ~4,000 CC BY 3.0 SVG item/ability
|
|
4
|
+
* icons from 40+ contributing artists, mirrored as one GitHub repo
|
|
5
|
+
* (github.com/game-icons/icons). `HEAD` resolves the default branch without
|
|
6
|
+
* pinning a name or commit, so this always mirrors the current set; the
|
|
7
|
+
* per-artist `license.txt` files inside the repo carry the individual
|
|
8
|
+
* credits behind this pack's single collective `author` field.
|
|
9
|
+
*/
|
|
10
|
+
export declare const gameiconsSources: readonly AssetSource[];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* game-icons.net (https://game-icons.net) — ~4,000 CC BY 3.0 SVG item/ability
|
|
3
|
+
* icons from 40+ contributing artists, mirrored as one GitHub repo
|
|
4
|
+
* (github.com/game-icons/icons). `HEAD` resolves the default branch without
|
|
5
|
+
* pinning a name or commit, so this always mirrors the current set; the
|
|
6
|
+
* per-artist `license.txt` files inside the repo carry the individual
|
|
7
|
+
* credits behind this pack's single collective `author` field.
|
|
8
|
+
*/
|
|
9
|
+
export const gameiconsSources = [
|
|
10
|
+
{
|
|
11
|
+
id: "gameicons-icons",
|
|
12
|
+
kind: "sprite",
|
|
13
|
+
provider: "gameicons",
|
|
14
|
+
title: "Game-Icons.net — Icon Library",
|
|
15
|
+
license: "CC BY 3.0",
|
|
16
|
+
author: "game-icons.net contributors (Lorc, Delapouite, and 40+ others — see homepage for per-icon credit)",
|
|
17
|
+
categories: ["icon", "item", "ability", "ui"],
|
|
18
|
+
download: { url: "https://codeload.github.com/game-icons/icons/zip/HEAD" },
|
|
19
|
+
homepage: "https://game-icons.net",
|
|
20
|
+
},
|
|
21
|
+
];
|
package/dist/sources/index.d.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import type { AssetSource } from "../manifest.js";
|
|
2
|
+
import { ambientcgSources } from "./ambientcg.js";
|
|
3
|
+
import { gameiconsSources } from "./gameicons.js";
|
|
2
4
|
import { kaykitSources } from "./kaykit.js";
|
|
3
|
-
import { kenneySources } from "./kenney.js";
|
|
4
5
|
import { quaterniusSources } from "./quaternius.js";
|
|
5
6
|
export declare const sources: readonly AssetSource[];
|
|
7
|
+
/** Every source whose archive holds GLB models (Quaternius, KayKit packs). */
|
|
8
|
+
export declare const modelSources: readonly AssetSource[];
|
|
9
|
+
/** Every `kind: "material"` source — one CC0 PBR material each, resolvable via `buildMaterialCatalog`. */
|
|
10
|
+
export declare const materialSources: readonly AssetSource[];
|
|
11
|
+
/** Every `kind: "sprite"` source — a pack of individual 2D icon/UI files, resolvable via `buildSpriteCatalog`. */
|
|
12
|
+
export declare const spriteSources: readonly AssetSource[];
|
|
6
13
|
export declare const sourceById: ReadonlyMap<string, AssetSource>;
|
|
7
|
-
export {
|
|
14
|
+
export { ambientcgSources, gameiconsSources, kaykitSources, quaterniusSources };
|
package/dist/sources/index.js
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
import { ambientcgSources } from "./ambientcg.js";
|
|
2
|
+
import { gameiconsSources } from "./gameicons.js";
|
|
1
3
|
import { kaykitSources } from "./kaykit.js";
|
|
2
|
-
import { kenneySources } from "./kenney.js";
|
|
3
4
|
import { quaterniusSources } from "./quaternius.js";
|
|
4
5
|
export const sources = [
|
|
5
|
-
...kenneySources,
|
|
6
6
|
...quaterniusSources,
|
|
7
7
|
...kaykitSources,
|
|
8
|
+
...ambientcgSources,
|
|
9
|
+
...gameiconsSources,
|
|
8
10
|
];
|
|
11
|
+
/** Every source whose archive holds GLB models (Quaternius, KayKit packs). */
|
|
12
|
+
export const modelSources = sources.filter((source) => (source.kind ?? "model") === "model");
|
|
13
|
+
/** Every `kind: "material"` source — one CC0 PBR material each, resolvable via `buildMaterialCatalog`. */
|
|
14
|
+
export const materialSources = sources.filter((source) => source.kind === "material");
|
|
15
|
+
/** Every `kind: "sprite"` source — a pack of individual 2D icon/UI files, resolvable via `buildSpriteCatalog`. */
|
|
16
|
+
export const spriteSources = sources.filter((source) => source.kind === "sprite");
|
|
9
17
|
export const sourceById = new Map(sources.map((source) => [source.id, source]));
|
|
10
|
-
export {
|
|
18
|
+
export { ambientcgSources, gameiconsSources, kaykitSources, quaterniusSources };
|
package/dist/sources/kaykit.js
CHANGED
|
@@ -1,9 +1,57 @@
|
|
|
1
1
|
const KAYKIT_PACKS = [
|
|
2
|
-
{
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
{
|
|
3
|
+
id: "kaykit-adventurers",
|
|
4
|
+
repo: "KayKit-Character-Pack-Adventures-1.0",
|
|
5
|
+
itch: "kaykit-adventurers",
|
|
6
|
+
title: "KayKit Adventurers",
|
|
7
|
+
categories: ["character", "rigged", "fantasy"],
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
id: "kaykit-skeletons",
|
|
11
|
+
repo: "KayKit-Character-Pack-Skeletons-1.0",
|
|
12
|
+
itch: "kaykit-skeletons",
|
|
13
|
+
title: "KayKit Skeletons",
|
|
14
|
+
categories: ["character", "monster", "creature", "undead", "rigged", "halloween"],
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "kaykit-dungeon",
|
|
18
|
+
repo: "KayKit-Dungeon-Remastered-1.0",
|
|
19
|
+
itch: "kaykit-dungeon-remastered",
|
|
20
|
+
title: "KayKit Dungeon (Remastered)",
|
|
21
|
+
categories: ["dungeon", "environment", "prop"],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: "kaykit-medieval-hexagon",
|
|
25
|
+
repo: "KayKit-Medieval-Hexagon-Pack-1.0",
|
|
26
|
+
itch: "kaykit-medieval-hexagon-pack",
|
|
27
|
+
title: "KayKit Medieval Hexagon Pack",
|
|
28
|
+
categories: ["hexagon", "medieval", "environment"],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "kaykit-furniture",
|
|
32
|
+
repo: "KayKit-Furniture-Bits-1.0",
|
|
33
|
+
itch: "kaykit-furniture-bits",
|
|
34
|
+
title: "KayKit Furniture Bits",
|
|
35
|
+
categories: ["furniture", "prop", "interior"],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "kaykit-city-builder",
|
|
39
|
+
repo: "KayKit-City-Builder-Bits-1.0",
|
|
40
|
+
itch: "kaykit-city-builder-bits",
|
|
41
|
+
title: "KayKit City Builder Bits",
|
|
42
|
+
categories: ["building", "city", "environment"],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "kaykit-space-base",
|
|
46
|
+
repo: "KayKit-Space-Base-Bits-1.0",
|
|
47
|
+
itch: "kaykit-space-base-bits",
|
|
48
|
+
title: "KayKit Space Base Bits",
|
|
49
|
+
categories: ["scifi", "environment", "prop"],
|
|
50
|
+
},
|
|
6
51
|
];
|
|
52
|
+
function githubArchiveUrl(repo) {
|
|
53
|
+
return `https://github.com/KayKit-Game-Assets/${repo}/archive/refs/heads/main.zip`;
|
|
54
|
+
}
|
|
7
55
|
export const kaykitSources = KAYKIT_PACKS.map((pack) => ({
|
|
8
56
|
id: pack.id,
|
|
9
57
|
provider: "kaykit",
|
|
@@ -11,6 +59,7 @@ export const kaykitSources = KAYKIT_PACKS.map((pack) => ({
|
|
|
11
59
|
license: "CC0-1.0",
|
|
12
60
|
author: "Kay Lousberg",
|
|
13
61
|
categories: pack.categories,
|
|
14
|
-
download: {
|
|
15
|
-
homepage: `https://kaylousberg.itch.io/${pack.
|
|
62
|
+
download: { url: githubArchiveUrl(pack.repo) },
|
|
63
|
+
homepage: `https://kaylousberg.itch.io/${pack.itch}`,
|
|
64
|
+
mirror: githubArchiveUrl(pack.repo),
|
|
16
65
|
}));
|
|
@@ -1,12 +1,60 @@
|
|
|
1
|
+
const OGA_FILES = "https://opengameart.org/sites/default/files";
|
|
1
2
|
const QUATERNIUS_PACKS = [
|
|
2
|
-
{
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{
|
|
3
|
+
{
|
|
4
|
+
id: "quaternius-stylized-nature",
|
|
5
|
+
slug: "stylizednaturemegakit",
|
|
6
|
+
title: "Stylized Nature MegaKit",
|
|
7
|
+
categories: ["nature", "environment", "prop"],
|
|
8
|
+
ogaZip: `${OGA_FILES}/stylized_nature_megakitstandard.zip`,
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "quaternius-medieval-village",
|
|
12
|
+
slug: "medievalvillagemegakit",
|
|
13
|
+
title: "Medieval Village MegaKit",
|
|
14
|
+
categories: ["building", "medieval", "environment"],
|
|
15
|
+
ogaZip: `${OGA_FILES}/medieval_village_megakitstandard.zip`,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: "quaternius-downtown-city",
|
|
19
|
+
slug: "downtowncitymegakit",
|
|
20
|
+
title: "Downtown City MegaKit",
|
|
21
|
+
categories: ["building", "city", "environment"],
|
|
22
|
+
// Street Pack is the free modular city/street kit on OGA (CC0 Quaternius).
|
|
23
|
+
ogaZip: `${OGA_FILES}/Street%20Pack%20by%20%40Quaternius.zip`,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: "quaternius-modular-scifi",
|
|
27
|
+
slug: "modularscifimegakit",
|
|
28
|
+
title: "Modular SciFi MegaKit",
|
|
29
|
+
categories: ["scifi", "environment", "prop"],
|
|
30
|
+
ogaZip: `${OGA_FILES}/modular_scifi_megakitstandard.zip`,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "quaternius-fantasy-props",
|
|
34
|
+
slug: "fantasypropsmegakit",
|
|
35
|
+
title: "Fantasy Props MegaKit",
|
|
36
|
+
categories: ["fantasy", "prop"],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "quaternius-base-characters",
|
|
40
|
+
slug: "universalbasecharacters",
|
|
41
|
+
title: "Universal Base Characters",
|
|
42
|
+
categories: ["character", "rigged"],
|
|
43
|
+
// OGA free dump is FBX/OBJ only — needs Pro/glTF source; scrape stays until pinned.
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "quaternius-animated-animals",
|
|
47
|
+
slug: "ultimateanimatedanimals",
|
|
48
|
+
title: "Ultimate Animated Animal Pack",
|
|
49
|
+
categories: ["animal", "creature", "wildlife", "rigged", "animated"],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "quaternius-monsters",
|
|
53
|
+
slug: "ultimatemonsters",
|
|
54
|
+
title: "Ultimate Monsters",
|
|
55
|
+
categories: ["monster", "creature", "fantasy", "rigged", "animated"],
|
|
56
|
+
// OGA free dump is FBX/OBJ only — needs Pro/glTF source; scrape stays until pinned.
|
|
57
|
+
},
|
|
10
58
|
];
|
|
11
59
|
export const quaterniusSources = QUATERNIUS_PACKS.map((pack) => ({
|
|
12
60
|
id: pack.id,
|
|
@@ -15,6 +63,9 @@ export const quaterniusSources = QUATERNIUS_PACKS.map((pack) => ({
|
|
|
15
63
|
license: "CC0-1.0",
|
|
16
64
|
author: "Quaternius",
|
|
17
65
|
categories: pack.categories,
|
|
18
|
-
download:
|
|
66
|
+
download: pack.ogaZip !== undefined
|
|
67
|
+
? { url: pack.ogaZip }
|
|
68
|
+
: { scrape: `https://quaternius.com/packs/${pack.slug}.html` },
|
|
19
69
|
homepage: `https://quaternius.com/packs/${pack.slug}.html`,
|
|
70
|
+
...(pack.ogaZip !== undefined ? { mirror: pack.ogaZip } : {}),
|
|
20
71
|
}));
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AssetSource, IndexEntry } from "./manifest.js";
|
|
2
|
+
/** Strips the `.svg`/`.png` extension off a pulled sprite/icon filename to get its id suffix. */
|
|
3
|
+
export declare function keyFromSpriteFile(file: string): string;
|
|
4
|
+
/** Builds one sprite/icon `IndexEntry` — same shape as a model entry, minus `dims`. */
|
|
5
|
+
export declare function entryForSpriteFile(source: AssetSource, file: string): IndexEntry;
|
|
6
|
+
/** Walks a pulled sprite-pack directory and returns one `IndexEntry` per SVG/PNG, deduped by filename. */
|
|
7
|
+
export declare function indexSpriteSourceDir(source: AssetSource, dir: string): IndexEntry[];
|
|
8
|
+
/** Per-source and total counts returned by `reindexSprites`. */
|
|
9
|
+
export interface ReindexSpritesResult {
|
|
10
|
+
perSource: {
|
|
11
|
+
source: string;
|
|
12
|
+
count: number;
|
|
13
|
+
}[];
|
|
14
|
+
total: number;
|
|
15
|
+
}
|
|
16
|
+
/** Same shape as `reindex` (models) but walks SVG/PNG files and skips dims measurement — sprites have no footprint. */
|
|
17
|
+
export declare function reindexSprites(spritesDir: string, outDir: string): ReindexSpritesResult;
|