@series-inc/stowkit-cli 0.6.20 → 0.6.22
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/dist/cli.js +35 -5
- package/dist/server.js +33 -1
- package/dist/store.d.ts +2 -0
- package/dist/store.js +6 -1
- package/package.json +2 -2
- package/skill.md +38 -144
package/dist/cli.js
CHANGED
|
@@ -110,6 +110,7 @@ Options:
|
|
|
110
110
|
--dry-run Show what would be published without uploading
|
|
111
111
|
--json Output store results as JSON (for AI agents)
|
|
112
112
|
--type Filter store search by asset type
|
|
113
|
+
--limit Max number of results to return (default: all)
|
|
113
114
|
--help Show this help message
|
|
114
115
|
`.trim());
|
|
115
116
|
}
|
|
@@ -167,6 +168,8 @@ async function main() {
|
|
|
167
168
|
const bucket = bucketIdx >= 0 ? args[bucketIdx + 1] : undefined;
|
|
168
169
|
const typeIdx = args.indexOf('--type');
|
|
169
170
|
const typeFilter = typeIdx >= 0 ? args[typeIdx + 1] : undefined;
|
|
171
|
+
const limitIdx = args.indexOf('--limit');
|
|
172
|
+
const limitFilter = limitIdx >= 0 ? parseInt(args[limitIdx + 1], 10) : undefined;
|
|
170
173
|
const opts = { force, verbose };
|
|
171
174
|
try {
|
|
172
175
|
switch (command) {
|
|
@@ -301,17 +304,37 @@ async function main() {
|
|
|
301
304
|
break;
|
|
302
305
|
case 'store': {
|
|
303
306
|
const subCmd = args[1];
|
|
304
|
-
const
|
|
307
|
+
const serverUrl = `http://localhost:${port}`;
|
|
308
|
+
const serverUp = await isStowKitRunning(port);
|
|
305
309
|
if (subCmd === 'search') {
|
|
306
310
|
const query = args.filter(a => !a.startsWith('-') && a !== 'store' && a !== 'search').join(' ');
|
|
307
311
|
if (!query) {
|
|
308
|
-
console.error('Usage: stowkit store search <query> [--type <type>] [--json]');
|
|
312
|
+
console.error('Usage: stowkit store search <query> [--type <type>] [--limit <n>] [--json]');
|
|
309
313
|
process.exit(1);
|
|
310
314
|
}
|
|
311
|
-
|
|
315
|
+
if (serverUp) {
|
|
316
|
+
const params = new URLSearchParams({ q: query });
|
|
317
|
+
if (typeFilter)
|
|
318
|
+
params.set('type', typeFilter);
|
|
319
|
+
if (limitFilter)
|
|
320
|
+
params.set('limit', String(limitFilter));
|
|
321
|
+
const res = await fetch(`${serverUrl}/api/asset-store/search?${params}`);
|
|
322
|
+
const results = await res.json();
|
|
323
|
+
console.log(JSON.stringify(results, null, 2));
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
await storeSearch(query, { json: jsonOutput, bucket, type: typeFilter, limit: limitFilter });
|
|
327
|
+
}
|
|
312
328
|
}
|
|
313
329
|
else if (subCmd === 'list') {
|
|
314
|
-
|
|
330
|
+
if (serverUp) {
|
|
331
|
+
const res = await fetch(`${serverUrl}/api/asset-store/packages`);
|
|
332
|
+
const packages = await res.json();
|
|
333
|
+
console.log(JSON.stringify(packages, null, 2));
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
await storeList({ json: jsonOutput, bucket });
|
|
337
|
+
}
|
|
315
338
|
}
|
|
316
339
|
else if (subCmd === 'info') {
|
|
317
340
|
const pkgName = args.find(a => !a.startsWith('-') && a !== 'store' && a !== 'info');
|
|
@@ -319,7 +342,14 @@ async function main() {
|
|
|
319
342
|
console.error('Usage: stowkit store info <package-name> [--json]');
|
|
320
343
|
process.exit(1);
|
|
321
344
|
}
|
|
322
|
-
|
|
345
|
+
if (serverUp) {
|
|
346
|
+
const res = await fetch(`${serverUrl}/api/asset-store/package/${encodeURIComponent(pkgName)}`);
|
|
347
|
+
const info = await res.json();
|
|
348
|
+
console.log(JSON.stringify(info, null, 2));
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
await storeInfo(pkgName, { json: jsonOutput, bucket });
|
|
352
|
+
}
|
|
323
353
|
}
|
|
324
354
|
else {
|
|
325
355
|
console.error('Usage: stowkit store <search|list|info> [args]');
|
package/dist/server.js
CHANGED
|
@@ -1785,9 +1785,13 @@ async function handleRequest(req, res, staticApps) {
|
|
|
1785
1785
|
const type = url.searchParams.get('type') ?? undefined;
|
|
1786
1786
|
const pkg = url.searchParams.get('package') ?? undefined;
|
|
1787
1787
|
const bucketParam = url.searchParams.get('bucket') ?? undefined;
|
|
1788
|
+
const limitParam = url.searchParams.get('limit');
|
|
1789
|
+
const limit = limitParam ? parseInt(limitParam, 10) : undefined;
|
|
1788
1790
|
const { fetchRegistry, searchAssets } = await import('./store.js');
|
|
1789
1791
|
const registry = await fetchRegistry(bucketParam);
|
|
1790
|
-
|
|
1792
|
+
let results = searchAssets(registry, query, { type, package: pkg });
|
|
1793
|
+
if (limit && limit > 0)
|
|
1794
|
+
results = results.slice(0, limit);
|
|
1791
1795
|
json(res, results);
|
|
1792
1796
|
}
|
|
1793
1797
|
catch (err) {
|
|
@@ -1809,6 +1813,34 @@ async function handleRequest(req, res, staticApps) {
|
|
|
1809
1813
|
}
|
|
1810
1814
|
return;
|
|
1811
1815
|
}
|
|
1816
|
+
// GET /api/asset-store/package/:name — get package details
|
|
1817
|
+
if (pathname.startsWith('/api/asset-store/package/') && req.method === 'GET') {
|
|
1818
|
+
try {
|
|
1819
|
+
const packageName = decodeURIComponent(pathname.slice('/api/asset-store/package/'.length));
|
|
1820
|
+
const bucketParam = url.searchParams.get('bucket') ?? undefined;
|
|
1821
|
+
const { fetchRegistry } = await import('./store.js');
|
|
1822
|
+
const registry = await fetchRegistry(bucketParam);
|
|
1823
|
+
const pkg = registry.packages[packageName];
|
|
1824
|
+
if (!pkg) {
|
|
1825
|
+
json(res, { error: `Package "${packageName}" not found` }, 404);
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1828
|
+
const ver = pkg.versions[pkg.latest];
|
|
1829
|
+
json(res, {
|
|
1830
|
+
name: packageName,
|
|
1831
|
+
description: pkg.description,
|
|
1832
|
+
author: pkg.author,
|
|
1833
|
+
tags: pkg.tags ?? [],
|
|
1834
|
+
latest: pkg.latest,
|
|
1835
|
+
versions: Object.keys(pkg.versions),
|
|
1836
|
+
assets: ver?.assets ?? [],
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1839
|
+
catch (err) {
|
|
1840
|
+
json(res, { error: err.message }, 500);
|
|
1841
|
+
}
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1812
1844
|
// POST /api/asset-store/download — download assets (with transitive deps) into project
|
|
1813
1845
|
if (pathname === '/api/asset-store/download' && req.method === 'POST') {
|
|
1814
1846
|
if (!projectConfig) {
|
package/dist/store.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export interface SearchResult {
|
|
|
12
12
|
thumbnail: boolean;
|
|
13
13
|
thumbnailFormat: 'png' | 'webp' | 'webm';
|
|
14
14
|
thumbnailUrl: string | null;
|
|
15
|
+
audioUrl: string | null;
|
|
15
16
|
filtering?: 'linear' | 'nearest';
|
|
16
17
|
}
|
|
17
18
|
export interface PackageInfo {
|
|
@@ -39,6 +40,7 @@ export declare function storeSearch(query: string, opts?: {
|
|
|
39
40
|
type?: string;
|
|
40
41
|
json?: boolean;
|
|
41
42
|
bucket?: string;
|
|
43
|
+
limit?: number;
|
|
42
44
|
}): Promise<void>;
|
|
43
45
|
export declare function storeList(opts?: {
|
|
44
46
|
json?: boolean;
|
package/dist/store.js
CHANGED
|
@@ -52,6 +52,9 @@ export function searchAssets(registry, query, opts) {
|
|
|
52
52
|
thumbnailUrl: asset.thumbnail
|
|
53
53
|
? `https://storage.googleapis.com/${bucket}/packages/${pkgName}/${verStr}/thumbnails/${asset.stringId.split('/').map(encodeURIComponent).join('/')}.${asset.thumbnailFormat ?? 'png'}`
|
|
54
54
|
: null,
|
|
55
|
+
audioUrl: asset.type === 'audio'
|
|
56
|
+
? `https://storage.googleapis.com/${bucket}/packages/${pkgName}/${verStr}/${asset.file.split('/').map(encodeURIComponent).join('/')}`
|
|
57
|
+
: null,
|
|
55
58
|
...(asset.filtering ? { filtering: asset.filtering } : {}),
|
|
56
59
|
},
|
|
57
60
|
});
|
|
@@ -219,7 +222,9 @@ export function resolveAssetDeps(registry, packageName, stringIds, version) {
|
|
|
219
222
|
// ─── CLI Commands ────────────────────────────────────────────────────────────
|
|
220
223
|
export async function storeSearch(query, opts) {
|
|
221
224
|
const registry = await fetchRegistry(opts?.bucket);
|
|
222
|
-
|
|
225
|
+
let results = searchAssets(registry, query, { type: opts?.type });
|
|
226
|
+
if (opts?.limit && opts.limit > 0)
|
|
227
|
+
results = results.slice(0, opts.limit);
|
|
223
228
|
if (opts?.json) {
|
|
224
229
|
console.log(JSON.stringify(results, null, 2));
|
|
225
230
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@series-inc/stowkit-cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.22",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"stowkit": "./dist/cli.js"
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dev": "tsc --watch"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@series-inc/stowkit-packer-gui": "^0.1.
|
|
20
|
+
"@series-inc/stowkit-packer-gui": "^0.1.22",
|
|
21
21
|
"@series-inc/stowkit-editor": "^0.1.8",
|
|
22
22
|
"draco3d": "^1.5.7",
|
|
23
23
|
"fbx-parser": "^2.1.3",
|
package/skill.md
CHANGED
|
@@ -2,17 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
StowKit is a game asset pipeline that compresses and packs assets into `.stow` binary files for runtime loading.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## How "Adding an Asset" Works
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
When the user says "add this asset" or "use this model/texture/sound", this is always a two-step process:
|
|
8
8
|
|
|
9
|
-
1
|
|
10
|
-
2. Run `stowkit build` (or `stowkit scan`)
|
|
11
|
-
3. The CLI detects the new file, generates the correct `.stowmeta` with proper defaults, and processes it
|
|
9
|
+
**Step 1 — Pipeline (this skill):** Place the source file (FBX, GLB, PNG, WAV, etc.) into the project's `srcArtDir` folder, then run `stowkit build`. The CLI compresses it and packs it into a `.stow` file. That's it for this step.
|
|
12
10
|
|
|
13
|
-
**
|
|
11
|
+
**Step 2 — Runtime (three-loader skill):** In the game code, load the asset from the `.stow` pack using `StowKitLoader` and the asset's `stringId`. For example: `pack.loadMesh('hero_model')`.
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
**Never load raw source files (FBX, PNG, GLB, WAV) directly in game code.** No `THREE.FBXLoader`, no `THREE.TextureLoader` on raw PNGs, no `fetch('assets/model.fbx')`. All assets go through the StowKit pipeline first and are loaded from `.stow` packs at runtime.
|
|
14
|
+
|
|
15
|
+
**Never use the asset store to find local project files.** The store is a remote registry for shared reusable packs. To find what assets are in the current project, read `.stowmeta` files, glob for files in `srcArtDir`, or run `stowkit status`.
|
|
16
|
+
|
|
17
|
+
## Quick Decision Guide
|
|
18
|
+
|
|
19
|
+
| User wants to... | Do this |
|
|
20
|
+
|---|---|
|
|
21
|
+
| Add a new asset (texture, mesh, audio, GLB) | Place file in `srcArtDir`, run `stowkit build`, then load from pack in game code |
|
|
22
|
+
| Change compression/quality settings | Edit the **existing** `.stowmeta` (never create one), run `stowkit build` |
|
|
23
|
+
| Create a new material | `stowkit create-material <path>` then `stowkit build` |
|
|
24
|
+
| Rename / move / delete an asset | `stowkit rename`, `stowkit move`, or `stowkit delete` |
|
|
25
|
+
| See what's in a built pack | `stowkit inspect <file.stow>` |
|
|
26
|
+
| Check project health | `stowkit status` |
|
|
27
|
+
| Visually browse/edit assets | `stowkit packer` |
|
|
28
|
+
| Load assets at runtime (Three.js) | Use `@series-inc/stowkit-three-loader` — see Runtime Reader section |
|
|
29
|
+
|
|
30
|
+
## CRITICAL Rules
|
|
31
|
+
|
|
32
|
+
1. **Never manually create `.stowmeta` files.** They are auto-generated by `stowkit build` / `stowkit scan`. Only **edit** an existing one (to change quality, pack, stringId, etc.).
|
|
33
|
+
2. **Never manually create GLB `children` arrays.** The build populates them automatically on first run.
|
|
34
|
+
3. **Never load raw FBX/PNG/GLB/WAV files directly in game code.** Everything goes through the pipeline (`stowkit build`) and is loaded from `.stow` packs at runtime via `StowKitLoader`.
|
|
35
|
+
4. **To create materials, use `stowkit create-material`** — don't hand-write `.stowmat` unless you have a specific reason.
|
|
36
|
+
5. **Always run `stowkit build` after changes** — the CLI handles scanning, processing, and packing in one step.
|
|
16
37
|
|
|
17
38
|
## Project Structure
|
|
18
39
|
|
|
@@ -53,9 +74,6 @@ stowkit move <path> <folder> # Move an asset to a different folder (updates G
|
|
|
53
74
|
stowkit delete <path> # Delete an asset and its .stowmeta/.stowcache files
|
|
54
75
|
stowkit set-id <path> <id> # Change an asset's stringId
|
|
55
76
|
stowkit inspect <file.stow> # Show manifest of a built .stow pack (use -v for details)
|
|
56
|
-
stowkit store search <query> # Search the asset store (add --json for machine-readable output)
|
|
57
|
-
stowkit store list # List all packages in the store
|
|
58
|
-
stowkit store info <package> # Show package details and all assets
|
|
59
77
|
stowkit packer [dir] # Open the packer GUI in browser
|
|
60
78
|
stowkit editor [dir] # Open the level editor in browser
|
|
61
79
|
stowkit serve [dir] # Start API server only (no GUI)
|
|
@@ -66,8 +84,6 @@ All commands default to the current directory.
|
|
|
66
84
|
**Options:**
|
|
67
85
|
- `--force` — Ignore cache and reprocess everything
|
|
68
86
|
- `--verbose` / `-v` — Detailed output
|
|
69
|
-
- `--json` — Output store results as JSON (for programmatic/AI use)
|
|
70
|
-
- `--type <type>` — Filter store search by asset type (e.g. `staticMesh`, `texture`)
|
|
71
87
|
- `--port <number>` — Server port (default 3210)
|
|
72
88
|
- `--schema <name>` — Material schema template for `create-material` (default: `pbr`)
|
|
73
89
|
|
|
@@ -530,130 +546,17 @@ To refresh skill files without updating the CLI: `stowkit init --update`
|
|
|
530
546
|
|
|
531
547
|
**When to run this:** If you notice this skill file is missing documentation for commands that exist in `stowkit --help`, or if the user asks you to update StowKit.
|
|
532
548
|
|
|
533
|
-
##
|
|
534
|
-
|
|
535
|
-
StowKit includes a shared asset store for publishing, searching, and importing reusable asset packs across projects. Assets are stored in a GCS bucket with a central `registry.json` manifest.
|
|
536
|
-
|
|
537
|
-
### Publishing to the store
|
|
538
|
-
|
|
539
|
-
To publish a pack, you need an `assets-package.json` in the project root:
|
|
540
|
-
|
|
541
|
-
```json
|
|
542
|
-
{
|
|
543
|
-
"name": "my-pack",
|
|
544
|
-
"version": "1.0.0",
|
|
545
|
-
"author": "your-name",
|
|
546
|
-
"description": "A short description of what's in this pack",
|
|
547
|
-
"tags": ["environment", "fantasy", "low-poly"],
|
|
548
|
-
"bucket": "gs://venus-shared-assets-test"
|
|
549
|
-
}
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
Then run `stowkit publish` from the packer GUI's Publish modal, or programmatically via the CLI server's `/api/publish` endpoint. The publish flow:
|
|
553
|
-
|
|
554
|
-
1. Scans all assets in the `srcArtDir` and builds a dependency graph
|
|
555
|
-
2. Uploads all source files to `packages/{name}/{version}/` in GCS
|
|
556
|
-
3. Uploads per-asset thumbnails (captured in the packer GUI)
|
|
557
|
-
4. Uploads a pack-level thumbnail if present (see below)
|
|
558
|
-
5. Updates the central `registry.json` with the new version
|
|
559
|
-
|
|
560
|
-
**Pack-level thumbnail:** Place a `thumbnail.webp`, `thumbnail.png`, or `thumbnail.jpg` in the project root directory. During publish, this file is uploaded alongside the package and displayed as the pack's cover image in the store. If no custom thumbnail is provided, the store shows a collage of individual asset thumbnails.
|
|
561
|
-
|
|
562
|
-
**Version management:** Bump the `version` field in `assets-package.json` before each publish. Publishing the same version again requires `--force`.
|
|
563
|
-
|
|
564
|
-
### Searching the store (CLI)
|
|
565
|
-
|
|
566
|
-
```bash
|
|
567
|
-
stowkit store search coral # Find assets matching "coral"
|
|
568
|
-
stowkit store search "boss, idle" # AND search — both terms must match
|
|
569
|
-
stowkit store search ocean --type texture # Find textures tagged/named "ocean"
|
|
570
|
-
stowkit store search staticMesh --json # Machine-readable JSON output
|
|
571
|
-
stowkit store list # List all published packages
|
|
572
|
-
stowkit store info ninja-adventure # Show all assets in a package
|
|
573
|
-
stowkit store info ninja-adventure --json # Full package details as JSON
|
|
574
|
-
```
|
|
575
|
-
|
|
576
|
-
The `--json` flag outputs structured data for programmatic/AI consumption.
|
|
577
|
-
|
|
578
|
-
### Search scoring algorithm
|
|
579
|
-
|
|
580
|
-
Search uses a ranked scoring system with AND semantics. Each search term must independently clear a minimum threshold — weak matches alone won't surface results.
|
|
581
|
-
|
|
582
|
-
**Scoring tiers (per term, highest match wins):**
|
|
583
|
-
|
|
584
|
-
| Score | Match type | Example |
|
|
585
|
-
|-------|-----------|---------|
|
|
586
|
-
| 100 | Exact stringId match | "boss" matches asset "boss" |
|
|
587
|
-
| 90 | Exact package name match | "ninja-adventure" matches the pack |
|
|
588
|
-
| 80 | Exact asset tag match | "coral" matches tag "coral" |
|
|
589
|
-
| 60 | Word match in stringId or tag | "boss" matches "actor/boss/idle" |
|
|
590
|
-
| 50 | stringId starts with term | "act" matches "actor/boss/idle" |
|
|
591
|
-
| 45-50 | Word match in package name/tag | "ninja" matches pack "ninja-adventure" |
|
|
592
|
-
| 40 | Word prefix in stringId | "att" matches "attack" |
|
|
593
|
-
| 25-35 | Substring/prefix matches | Various partial matches |
|
|
594
|
-
| < 20 | File path, type, description | Below threshold — boost only |
|
|
595
|
-
|
|
596
|
-
**Key behaviors:**
|
|
597
|
-
- **AND semantics:** Multi-term queries (comma-separated) require ALL terms to match. "boss, idle" only returns assets matching both words.
|
|
598
|
-
- **Minimum threshold (20):** Weak signals like file path matches or type name matches can't surface assets on their own. They only boost already-qualifying results.
|
|
599
|
-
- **Tags score high:** Asset tags are curated metadata and rank just below exact name matches. If an asset has a tag that matches your query, it will surface prominently.
|
|
600
|
-
- **Package metadata scoped:** When searching within a specific pack, package-level fields (name, description, tags) are excluded from scoring to prevent every asset from matching.
|
|
601
|
-
|
|
602
|
-
**Word splitting:** StringIds and names are split on underscores, hyphens, dots, slashes, camelCase, and spaces. "NinjaBoss_Attack" becomes ["ninja", "boss", "attack"].
|
|
603
|
-
|
|
604
|
-
### Searching in the Packer GUI
|
|
605
|
-
|
|
606
|
-
The packer GUI has a **Store** button that opens a full-featured asset store browser:
|
|
607
|
-
|
|
608
|
-
- **Global search:** Type a query without selecting a pack — shows matching **packs** (not individual assets), sorted by number of matches. Click a pack to browse its assets with the search term preserved.
|
|
609
|
-
- **In-pack search:** Select a pack first, then search — shows individual assets within that pack, flat (no folder grouping), with AND scoring.
|
|
610
|
-
- **Type filters:** Filter by asset type (texture, staticMesh, skinnedMesh, audio, materialSchema, animationClip) using toggle pills.
|
|
611
|
-
- **Show All:** Checkbox to flatten the folder hierarchy and see all assets in the current pack at once. Combines with type filters.
|
|
612
|
-
- **Folder browsing:** When not searching, navigate the pack's folder structure. Breadcrumbs below the filter bar show your current path.
|
|
613
|
-
- **Thumbnail size:** Slider in the footer to adjust grid card size.
|
|
614
|
-
- **Selection + dependencies:** Click assets to select them. Transitive dependencies are auto-resolved and shown with amber badges. The Import button downloads all selected assets and their deps into the project's `srcArtDir`.
|
|
615
|
-
|
|
616
|
-
### JSON search result format
|
|
617
|
-
|
|
618
|
-
```json
|
|
619
|
-
[
|
|
620
|
-
{
|
|
621
|
-
"stringId": "coral_1",
|
|
622
|
-
"type": "staticMesh",
|
|
623
|
-
"packageName": "ocean_pack",
|
|
624
|
-
"version": "1.0.0",
|
|
625
|
-
"file": "Meshes/Coral_1.fbx",
|
|
626
|
-
"size": 59952,
|
|
627
|
-
"tags": ["coral", "environment"],
|
|
628
|
-
"dependencies": ["M_Sea_Floor"],
|
|
629
|
-
"thumbnail": true,
|
|
630
|
-
"thumbnailFormat": "png",
|
|
631
|
-
"thumbnailUrl": "https://storage.googleapis.com/venus-shared-assets-test/packages/ocean_pack/1.0.0/thumbnails/coral_1.png"
|
|
632
|
-
}
|
|
633
|
-
]
|
|
634
|
-
```
|
|
635
|
-
|
|
636
|
-
### Dependency resolution
|
|
637
|
-
|
|
638
|
-
Assets have dependency chains: meshes depend on materials, materials depend on textures. When importing an asset, all transitive dependencies are automatically resolved and downloaded. If two assets share the same dependency, it's only downloaded once.
|
|
639
|
-
|
|
640
|
-
### Importing from the store
|
|
641
|
-
|
|
642
|
-
The packer GUI's Store modal handles importing. Selected assets and their transitive dependencies are downloaded directly into the project's `srcArtDir`. Already-imported assets are marked with a green "Imported" badge.
|
|
643
|
-
|
|
644
|
-
### Thumbnail URLs
|
|
645
|
-
|
|
646
|
-
Per-asset thumbnails (captured in the packer GUI during publish):
|
|
647
|
-
```
|
|
648
|
-
https://storage.googleapis.com/{bucket}/packages/{packageName}/{version}/thumbnails/{stringId}.{format}
|
|
649
|
-
```
|
|
650
|
-
|
|
651
|
-
Pack-level thumbnails (from project root `thumbnail.webp`):
|
|
652
|
-
```
|
|
653
|
-
https://storage.googleapis.com/{bucket}/packages/{packageName}/{version}/thumbnail.webp
|
|
654
|
-
```
|
|
549
|
+
## Common AI Mistakes to Avoid
|
|
655
550
|
|
|
656
|
-
|
|
551
|
+
| Mistake | Why it's wrong | What to do instead |
|
|
552
|
+
|---|---|---|
|
|
553
|
+
| Loading raw FBX/PNG/GLB in game code (`THREE.FBXLoader`, `THREE.TextureLoader`, `fetch('assets/...')`) | StowKit projects never load raw source files at runtime — they're compressed and packed | Place file in `srcArtDir`, `stowkit build`, then `pack.loadMesh()`/`pack.loadTexture()` from the `.stow` pack |
|
|
554
|
+
| Searching the asset store to find files in the local project | The store is a remote registry for shared packs, not the local project | Glob for files in `srcArtDir`, read `.stowmeta` files, or run `stowkit status` |
|
|
555
|
+
| Creating a `.stowmeta` file from scratch | The CLI generates these with correct defaults and cache stamps | Place the source file in `srcArtDir`, run `stowkit build` |
|
|
556
|
+
| Writing a `.stowmat` by hand when `create-material` exists | Hand-written materials often have wrong structure | `stowkit create-material <path>` |
|
|
557
|
+
| Running `stowkit process` without `stowkit scan` first | New files won't have `.stowmeta` yet | Just use `stowkit build` — it does scan + process + pack |
|
|
558
|
+
| Editing a GLB's `children` array before first build | The array doesn't exist yet — it's populated by the build | Run `stowkit build` first, then edit the generated children |
|
|
559
|
+
| Deleting files manually instead of using `stowkit delete` | Orphans the `.stowmeta` and `.stowcache` sidecars | `stowkit delete <path>` handles everything |
|
|
657
560
|
|
|
658
561
|
## Common Tasks for AI Agents
|
|
659
562
|
|
|
@@ -720,12 +623,3 @@ This is useful for verifying build output, checking which assets ended up in whi
|
|
|
720
623
|
- **Clean orphaned files:** `stowkit clean`
|
|
721
624
|
- **Set up with engine:** `stowkit init --with-engine` (installs `@series-inc/rundot-3d-engine` + `three`)
|
|
722
625
|
- **Update CLI + skill files:** `stowkit update`
|
|
723
|
-
- **Search the asset store:** `stowkit store search sword --json` (returns JSON array of matching assets with thumbnailUrls)
|
|
724
|
-
- **AND search:** `stowkit store search "boss, idle" --json` (both terms must match)
|
|
725
|
-
- **Find all meshes in the store:** `stowkit store search mesh --type staticMesh --json`
|
|
726
|
-
- **List all published packages:** `stowkit store list --json`
|
|
727
|
-
- **Get package details:** `stowkit store info ocean_pack --json`
|
|
728
|
-
- **Show a thumbnail to the user:** Use the `thumbnailUrl` from search results — it's a public URL
|
|
729
|
-
- **Add a pack thumbnail:** Place `thumbnail.webp` (or `.png`/`.jpg`) in the project root before publishing
|
|
730
|
-
- **Publish a pack:** Open the packer GUI (`stowkit packer`), click Publish, fill in version/description/tags, and publish
|
|
731
|
-
- **Browse the store visually:** Open the packer GUI, click the Store button to browse, search, filter by type, and import assets
|