@series-inc/stowkit-cli 0.6.38 → 0.6.40
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/app/disk-project.d.ts +12 -1
- package/dist/app/state.d.ts +10 -2
- package/dist/app/state.js +1 -0
- package/dist/app/stowmeta-io.js +9 -0
- package/dist/app/stowspritesheet-io.d.ts +6 -0
- package/dist/app/stowspritesheet-io.js +40 -0
- package/dist/app/thumbnail-cache.js +1 -1
- package/dist/cleanup.js +7 -6
- package/dist/core/constants.d.ts +2 -0
- package/dist/core/constants.js +2 -0
- package/dist/core/types.d.ts +10 -1
- package/dist/core/types.js +1 -0
- package/dist/format/metadata.d.ts +3 -1
- package/dist/format/metadata.js +23 -1
- package/dist/node-fs.d.ts +1 -0
- package/dist/node-fs.js +11 -4
- package/dist/orchestrator.d.ts +1 -0
- package/dist/orchestrator.js +32 -2
- package/dist/pipeline.js +37 -1
- package/dist/server.js +82 -4
- package/package.json +2 -2
|
@@ -80,6 +80,9 @@ export interface StowMetaAnimationClip extends StowMetaBase {
|
|
|
80
80
|
export interface StowMetaMaterialSchema extends StowMetaBase {
|
|
81
81
|
type: 'materialSchema';
|
|
82
82
|
}
|
|
83
|
+
export interface StowMetaSpriteSheet extends StowMetaBase {
|
|
84
|
+
type: 'spriteSheet';
|
|
85
|
+
}
|
|
83
86
|
export interface StowMetaGlbChild {
|
|
84
87
|
name: string;
|
|
85
88
|
childType: string;
|
|
@@ -108,7 +111,7 @@ export interface StowMetaGlbContainer extends StowMetaBase {
|
|
|
108
111
|
preserveHierarchy?: boolean;
|
|
109
112
|
children: StowMetaGlbChild[];
|
|
110
113
|
}
|
|
111
|
-
export type StowMeta = StowMetaTexture | StowMetaAudio | StowMetaStaticMesh | StowMetaSkinnedMesh | StowMetaAnimationClip | StowMetaMaterialSchema | StowMetaGlbContainer;
|
|
114
|
+
export type StowMeta = StowMetaTexture | StowMetaAudio | StowMetaStaticMesh | StowMetaSkinnedMesh | StowMetaAnimationClip | StowMetaMaterialSchema | StowMetaSpriteSheet | StowMetaGlbContainer;
|
|
112
115
|
export interface StowMatProperty {
|
|
113
116
|
fieldName: string;
|
|
114
117
|
fieldType: string;
|
|
@@ -121,6 +124,14 @@ export interface StowMat {
|
|
|
121
124
|
schemaName: string;
|
|
122
125
|
properties: StowMatProperty[];
|
|
123
126
|
}
|
|
127
|
+
export interface StowSpriteSheet {
|
|
128
|
+
version: 1;
|
|
129
|
+
textureAsset: string | null;
|
|
130
|
+
rows: number;
|
|
131
|
+
columns: number;
|
|
132
|
+
frameCount: number;
|
|
133
|
+
frameRate: number;
|
|
134
|
+
}
|
|
124
135
|
export declare const KTX2_QUALITY_STRINGS: Record<string, KTX2Quality>;
|
|
125
136
|
export declare const KTX2_QUALITY_TO_STRING: Record<number, string>;
|
|
126
137
|
export declare const TEXTURE_RESIZE_STRINGS: Record<string, TextureResize>;
|
package/dist/app/state.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssetType, TextureMetadata, AudioMetadata, MeshMetadata, AnimationClipMetadata, SkinnedMeshMetadata, KTX2Quality, TextureResize, TextureFilterMode, DracoQualityPreset, AacQuality, AudioSampleRate, MaterialFieldType, PreviewPropertyFlag } from '../core/types.js';
|
|
1
|
+
import type { AssetType, TextureMetadata, AudioMetadata, MeshMetadata, AnimationClipMetadata, SkinnedMeshMetadata, SpriteSheetMetadata, KTX2Quality, TextureResize, TextureFilterMode, DracoQualityPreset, AacQuality, AudioSampleRate, MaterialFieldType, PreviewPropertyFlag } from '../core/types.js';
|
|
2
2
|
export interface MaterialProperty {
|
|
3
3
|
fieldName: string;
|
|
4
4
|
fieldType: MaterialFieldType;
|
|
@@ -10,6 +10,13 @@ export interface MaterialConfig {
|
|
|
10
10
|
schemaId: string;
|
|
11
11
|
properties: MaterialProperty[];
|
|
12
12
|
}
|
|
13
|
+
export interface SpriteSheetConfig {
|
|
14
|
+
textureAssetId: string | null;
|
|
15
|
+
rows: number;
|
|
16
|
+
columns: number;
|
|
17
|
+
frameCount: number;
|
|
18
|
+
frameRate: number;
|
|
19
|
+
}
|
|
13
20
|
export interface AssetSettings {
|
|
14
21
|
quality: KTX2Quality;
|
|
15
22
|
resize: TextureResize;
|
|
@@ -21,6 +28,7 @@ export interface AssetSettings {
|
|
|
21
28
|
audioSampleRate: AudioSampleRate;
|
|
22
29
|
targetMeshId: string | null;
|
|
23
30
|
materialConfig: MaterialConfig;
|
|
31
|
+
spritesheetConfig: SpriteSheetConfig;
|
|
24
32
|
materialOverrides: Record<number, string | null>;
|
|
25
33
|
pack: string;
|
|
26
34
|
excluded: boolean;
|
|
@@ -35,7 +43,7 @@ export interface ProjectAsset {
|
|
|
35
43
|
status: 'loading' | 'pending' | 'processing' | 'ready' | 'error';
|
|
36
44
|
error?: string;
|
|
37
45
|
settings: AssetSettings;
|
|
38
|
-
metadata?: TextureMetadata | AudioMetadata | MeshMetadata | AnimationClipMetadata | SkinnedMeshMetadata;
|
|
46
|
+
metadata?: TextureMetadata | AudioMetadata | MeshMetadata | AnimationClipMetadata | SkinnedMeshMetadata | SpriteSheetMetadata;
|
|
39
47
|
sourceSize: number;
|
|
40
48
|
processedSize: number;
|
|
41
49
|
parentId?: string;
|
package/dist/app/state.js
CHANGED
|
@@ -11,6 +11,7 @@ export function defaultAssetSettings() {
|
|
|
11
11
|
audioSampleRate: ASR.Auto,
|
|
12
12
|
targetMeshId: null,
|
|
13
13
|
materialConfig: { schemaId: '', properties: [] },
|
|
14
|
+
spritesheetConfig: { textureAssetId: null, rows: 1, columns: 1, frameCount: 1, frameRate: 12 },
|
|
14
15
|
materialOverrides: {},
|
|
15
16
|
pack: 'default',
|
|
16
17
|
excluded: false,
|
package/dist/app/stowmeta-io.js
CHANGED
|
@@ -114,6 +114,11 @@ export function stowmetaToAssetSettings(meta) {
|
|
|
114
114
|
type: AssetType.MaterialSchema,
|
|
115
115
|
settings: base,
|
|
116
116
|
};
|
|
117
|
+
case 'spriteSheet':
|
|
118
|
+
return {
|
|
119
|
+
type: AssetType.SpriteSheet,
|
|
120
|
+
settings: base,
|
|
121
|
+
};
|
|
117
122
|
case 'glbContainer':
|
|
118
123
|
return {
|
|
119
124
|
type: AssetType.GlbContainer,
|
|
@@ -185,6 +190,8 @@ export function assetSettingsToStowmeta(asset) {
|
|
|
185
190
|
};
|
|
186
191
|
case AssetType.MaterialSchema:
|
|
187
192
|
return { ...base, type: 'materialSchema' };
|
|
193
|
+
case AssetType.SpriteSheet:
|
|
194
|
+
return { ...base, type: 'spriteSheet' };
|
|
188
195
|
case AssetType.GlbContainer:
|
|
189
196
|
return { ...base, type: 'glbContainer', preserveHierarchy: asset.settings.preserveHierarchy || undefined, children: [] };
|
|
190
197
|
default:
|
|
@@ -250,6 +257,8 @@ export function generateDefaultStowmeta(relativePath, type, projectDefaults, ima
|
|
|
250
257
|
return { ...base, type: 'animationClip', targetMeshId: null };
|
|
251
258
|
case AssetType.MaterialSchema:
|
|
252
259
|
return { ...base, type: 'materialSchema' };
|
|
260
|
+
case AssetType.SpriteSheet:
|
|
261
|
+
return { ...base, type: 'spriteSheet' };
|
|
253
262
|
case AssetType.GlbContainer:
|
|
254
263
|
return { ...base, type: 'glbContainer', children: [] };
|
|
255
264
|
default:
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SpriteSheetConfig } from './state.js';
|
|
2
|
+
import type { StowSpriteSheet } from './disk-project.js';
|
|
3
|
+
export declare function readStowSpriteSheet(srcArtDir: string, relativePath: string): Promise<StowSpriteSheet | null>;
|
|
4
|
+
export declare function writeStowSpriteSheet(srcArtDir: string, relativePath: string, sheet: StowSpriteSheet): Promise<void>;
|
|
5
|
+
export declare function spritesheetConfigToStowSpriteSheet(config: SpriteSheetConfig): StowSpriteSheet;
|
|
6
|
+
export declare function stowSpriteSheetToConfig(sheet: StowSpriteSheet): SpriteSheetConfig;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { readTextFile, writeFile } from '../node-fs.js';
|
|
2
|
+
export async function readStowSpriteSheet(srcArtDir, relativePath) {
|
|
3
|
+
const text = await readTextFile(srcArtDir, relativePath);
|
|
4
|
+
if (!text)
|
|
5
|
+
return null;
|
|
6
|
+
try {
|
|
7
|
+
return JSON.parse(text);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function writeStowSpriteSheet(srcArtDir, relativePath, sheet) {
|
|
14
|
+
try {
|
|
15
|
+
const json = JSON.stringify(sheet, null, 2);
|
|
16
|
+
await writeFile(srcArtDir, relativePath, json);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
console.warn(`[stowspritesheet] Failed to write ${relativePath}:`, err);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function spritesheetConfigToStowSpriteSheet(config) {
|
|
23
|
+
return {
|
|
24
|
+
version: 1,
|
|
25
|
+
textureAsset: config.textureAssetId,
|
|
26
|
+
rows: config.rows,
|
|
27
|
+
columns: config.columns,
|
|
28
|
+
frameCount: config.frameCount,
|
|
29
|
+
frameRate: config.frameRate,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function stowSpriteSheetToConfig(sheet) {
|
|
33
|
+
return {
|
|
34
|
+
textureAssetId: sheet.textureAsset ?? null,
|
|
35
|
+
rows: sheet.rows ?? 1,
|
|
36
|
+
columns: sheet.columns ?? 1,
|
|
37
|
+
frameCount: sheet.frameCount ?? 1,
|
|
38
|
+
frameRate: sheet.frameRate ?? 12,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -36,7 +36,7 @@ export async function writeManifest(srcArtDir, manifest) {
|
|
|
36
36
|
export function computeSettingsHash(settings) {
|
|
37
37
|
// Only include settings that affect visual output
|
|
38
38
|
const relevant = {};
|
|
39
|
-
for (const key of ['quality', 'resize', 'generateMipmaps', 'dracoQuality', 'materialConfig', 'targetMeshId', 'materialOverrides']) {
|
|
39
|
+
for (const key of ['quality', 'resize', 'generateMipmaps', 'dracoQuality', 'materialConfig', 'spritesheetConfig', 'targetMeshId', 'materialOverrides']) {
|
|
40
40
|
if (settings[key] !== undefined)
|
|
41
41
|
relevant[key] = settings[key];
|
|
42
42
|
}
|
package/dist/cleanup.js
CHANGED
|
@@ -9,11 +9,12 @@ export async function cleanupProject(projectDir, opts) {
|
|
|
9
9
|
// Build set of source files that exist
|
|
10
10
|
const sourceFiles = new Set(scan.sourceFiles.map(f => f.relativePath));
|
|
11
11
|
const matFiles = new Set(scan.matFiles.map(f => f.relativePath));
|
|
12
|
+
const spritesheetFiles = new Set(scan.spritesheetFiles.map(f => f.relativePath));
|
|
12
13
|
let deletedCaches = 0;
|
|
13
14
|
let deletedMetas = 0;
|
|
14
15
|
let freedBytes = 0;
|
|
15
16
|
// Walk all files looking for orphaned .stowcache and .stowmeta
|
|
16
|
-
await walkForOrphans(config.srcArtDir, '', sourceFiles, matFiles, async (orphanPath, type, size) => {
|
|
17
|
+
await walkForOrphans(config.srcArtDir, '', sourceFiles, matFiles, spritesheetFiles, async (orphanPath, type, size) => {
|
|
17
18
|
const fullPath = path.join(config.srcArtDir, orphanPath);
|
|
18
19
|
await fs.unlink(fullPath);
|
|
19
20
|
freedBytes += size;
|
|
@@ -43,7 +44,7 @@ export async function cleanupProject(projectDir, opts) {
|
|
|
43
44
|
console.log(`Cleaned up ${deletedCaches} cache(s) and ${deletedMetas} meta(s)${thumbNote} (${(freedBytes / 1024).toFixed(0)} KB freed)`);
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
|
-
async function walkForOrphans(basePath, prefix, sourceFiles, matFiles, onOrphan) {
|
|
47
|
+
async function walkForOrphans(basePath, prefix, sourceFiles, matFiles, spritesheetFiles, onOrphan) {
|
|
47
48
|
const dirPath = prefix ? path.join(basePath, prefix) : basePath;
|
|
48
49
|
let entries;
|
|
49
50
|
try {
|
|
@@ -59,21 +60,21 @@ async function walkForOrphans(basePath, prefix, sourceFiles, matFiles, onOrphan)
|
|
|
59
60
|
continue;
|
|
60
61
|
if (entry.name.endsWith('.children'))
|
|
61
62
|
continue;
|
|
62
|
-
await walkForOrphans(basePath, relativePath, sourceFiles, matFiles, onOrphan);
|
|
63
|
+
await walkForOrphans(basePath, relativePath, sourceFiles, matFiles, spritesheetFiles, onOrphan);
|
|
63
64
|
}
|
|
64
65
|
else if (entry.isFile()) {
|
|
65
66
|
if (entry.name.endsWith('.stowcache')) {
|
|
66
67
|
// Cache orphan: source file doesn't exist
|
|
67
68
|
const sourceId = relativePath.replace(/\.stowcache$/, '');
|
|
68
|
-
if (!sourceFiles.has(sourceId) && !matFiles.has(sourceId)) {
|
|
69
|
+
if (!sourceFiles.has(sourceId) && !matFiles.has(sourceId) && !spritesheetFiles.has(sourceId)) {
|
|
69
70
|
const stat = await fs.stat(path.join(basePath, relativePath));
|
|
70
71
|
await onOrphan(relativePath, 'cache', stat.size);
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
else if (entry.name.endsWith('.stowmeta')) {
|
|
74
|
-
// Meta orphan: neither source file nor
|
|
75
|
+
// Meta orphan: neither source file, mat file, nor spritesheet file exists
|
|
75
76
|
const sourceId = relativePath.replace(/\.stowmeta$/, '');
|
|
76
|
-
if (!sourceFiles.has(sourceId) && !matFiles.has(sourceId)) {
|
|
77
|
+
if (!sourceFiles.has(sourceId) && !matFiles.has(sourceId) && !spritesheetFiles.has(sourceId)) {
|
|
77
78
|
const stat = await fs.stat(path.join(basePath, relativePath));
|
|
78
79
|
await onOrphan(relativePath, 'meta', stat.size);
|
|
79
80
|
}
|
package/dist/core/constants.d.ts
CHANGED
|
@@ -69,3 +69,5 @@ export declare const ANIMATION_CLIP_METADATA_FIXED_SIZE = 268;
|
|
|
69
69
|
export declare const TRACK_NAME_SIZE = 64;
|
|
70
70
|
/** Metadata version discriminator for v2 animation clips */
|
|
71
71
|
export declare const ANIMATION_METADATA_VERSION = 2;
|
|
72
|
+
/** Size of SpriteSheetMetadata on disk (bytes) */
|
|
73
|
+
export declare const SPRITESHEET_METADATA_SIZE = 272;
|
package/dist/core/constants.js
CHANGED
|
@@ -70,3 +70,5 @@ export const ANIMATION_CLIP_METADATA_FIXED_SIZE = 268;
|
|
|
70
70
|
export const TRACK_NAME_SIZE = 64;
|
|
71
71
|
/** Metadata version discriminator for v2 animation clips */
|
|
72
72
|
export const ANIMATION_METADATA_VERSION = 2;
|
|
73
|
+
/** Size of SpriteSheetMetadata on disk (bytes) */
|
|
74
|
+
export const SPRITESHEET_METADATA_SIZE = 272;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -6,7 +6,8 @@ export declare enum AssetType {
|
|
|
6
6
|
MaterialSchema = 4,
|
|
7
7
|
SkinnedMesh = 5,
|
|
8
8
|
AnimationClip = 6,
|
|
9
|
-
GlbContainer = 7
|
|
9
|
+
GlbContainer = 7,
|
|
10
|
+
SpriteSheet = 8
|
|
10
11
|
}
|
|
11
12
|
export declare enum KTX2Quality {
|
|
12
13
|
Fastest = 0,
|
|
@@ -142,6 +143,14 @@ export interface MaterialSchemaMetadata {
|
|
|
142
143
|
fieldCount: number;
|
|
143
144
|
fields: MaterialSchemaField[];
|
|
144
145
|
}
|
|
146
|
+
export interface SpriteSheetMetadata {
|
|
147
|
+
stringId: string;
|
|
148
|
+
textureId: string;
|
|
149
|
+
rows: number;
|
|
150
|
+
columns: number;
|
|
151
|
+
frameCount: number;
|
|
152
|
+
frameRate: number;
|
|
153
|
+
}
|
|
145
154
|
export interface MeshMetadata {
|
|
146
155
|
meshGeometryCount: number;
|
|
147
156
|
materialCount: number;
|
package/dist/core/types.js
CHANGED
|
@@ -9,6 +9,7 @@ export var AssetType;
|
|
|
9
9
|
AssetType[AssetType["SkinnedMesh"] = 5] = "SkinnedMesh";
|
|
10
10
|
AssetType[AssetType["AnimationClip"] = 6] = "AnimationClip";
|
|
11
11
|
AssetType[AssetType["GlbContainer"] = 7] = "GlbContainer";
|
|
12
|
+
AssetType[AssetType["SpriteSheet"] = 8] = "SpriteSheet";
|
|
12
13
|
})(AssetType || (AssetType = {}));
|
|
13
14
|
// ─── Texture Enums ──────────────────────────────────────────────────────────
|
|
14
15
|
export var KTX2Quality;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TextureMetadata, AudioMetadata, MeshMetadata, MaterialSchemaMetadata, AnimationClipMetadata, SkinnedMeshMetadata } from '../core/types.js';
|
|
1
|
+
import type { TextureMetadata, AudioMetadata, MeshMetadata, MaterialSchemaMetadata, AnimationClipMetadata, SkinnedMeshMetadata, SpriteSheetMetadata } from '../core/types.js';
|
|
2
2
|
export declare function serializeTextureMetadata(meta: TextureMetadata): Uint8Array;
|
|
3
3
|
export declare function deserializeTextureMetadata(data: Uint8Array): TextureMetadata;
|
|
4
4
|
export declare function serializeAudioMetadata(meta: AudioMetadata): Uint8Array;
|
|
@@ -11,6 +11,8 @@ export declare function serializeAnimationClipMetadata(meta: AnimationClipMetada
|
|
|
11
11
|
export declare function deserializeAnimationClipMetadata(data: Uint8Array): AnimationClipMetadata;
|
|
12
12
|
export declare function serializeSkinnedMeshMetadata(meta: SkinnedMeshMetadata): Uint8Array;
|
|
13
13
|
export declare function deserializeSkinnedMeshMetadata(data: Uint8Array): SkinnedMeshMetadata;
|
|
14
|
+
export declare function serializeSpriteSheetMetadata(meta: SpriteSheetMetadata): Uint8Array;
|
|
15
|
+
export declare function deserializeSpriteSheetMetadata(data: Uint8Array): SpriteSheetMetadata;
|
|
14
16
|
export declare function wrapMetadata(assetMetadata: Uint8Array, tags: string[]): Uint8Array;
|
|
15
17
|
export declare function unwrapMetadata(wrapped: Uint8Array): {
|
|
16
18
|
tags: string[];
|
package/dist/format/metadata.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BinaryReader, BinaryWriter } from '../core/binary.js';
|
|
2
|
-
import { TEXTURE_METADATA_SIZE, AUDIO_METADATA_SIZE, STRING_ID_SIZE, MESH_GEOMETRY_INFO_SIZE, SCENE_NODE_SIZE, MATERIAL_DATA_FIXED_SIZE, MATERIAL_PROPERTY_VALUE_SIZE, MESH_METADATA_FIXED_SIZE, NODE_NAME_SIZE, MATERIAL_NAME_SIZE, MATERIAL_SCHEMA_ID_SIZE, MATERIAL_FIELD_NAME_SIZE, MATERIAL_SCHEMA_NAME_SIZE, MATERIAL_SCHEMA_DEFAULT_TEXTURE_ID_SIZE, MATERIAL_SCHEMA_METADATA_FIXED_SIZE, MATERIAL_SCHEMA_FIELD_SIZE, BONE_NAME_SIZE, SKINNED_MESH_GEOMETRY_INFO_SIZE, SKINNED_MESH_METADATA_FIXED_SIZE, BONE_SIZE, ANIMATION_TRACK_DESCRIPTOR_SIZE, ANIMATION_CLIP_METADATA_FIXED_SIZE, TRACK_NAME_SIZE, ANIMATION_METADATA_VERSION, } from '../core/constants.js';
|
|
2
|
+
import { TEXTURE_METADATA_SIZE, AUDIO_METADATA_SIZE, STRING_ID_SIZE, MESH_GEOMETRY_INFO_SIZE, SCENE_NODE_SIZE, MATERIAL_DATA_FIXED_SIZE, MATERIAL_PROPERTY_VALUE_SIZE, MESH_METADATA_FIXED_SIZE, NODE_NAME_SIZE, MATERIAL_NAME_SIZE, MATERIAL_SCHEMA_ID_SIZE, MATERIAL_FIELD_NAME_SIZE, MATERIAL_SCHEMA_NAME_SIZE, MATERIAL_SCHEMA_DEFAULT_TEXTURE_ID_SIZE, MATERIAL_SCHEMA_METADATA_FIXED_SIZE, MATERIAL_SCHEMA_FIELD_SIZE, BONE_NAME_SIZE, SKINNED_MESH_GEOMETRY_INFO_SIZE, SKINNED_MESH_METADATA_FIXED_SIZE, BONE_SIZE, ANIMATION_TRACK_DESCRIPTOR_SIZE, ANIMATION_CLIP_METADATA_FIXED_SIZE, TRACK_NAME_SIZE, ANIMATION_METADATA_VERSION, SPRITESHEET_METADATA_SIZE, } from '../core/constants.js';
|
|
3
3
|
import { TextureFilterMode } from '../core/types.js';
|
|
4
4
|
// ─── Texture Metadata ───────────────────────────────────────────────────────
|
|
5
5
|
export function serializeTextureMetadata(meta) {
|
|
@@ -361,6 +361,28 @@ export function deserializeSkinnedMeshMetadata(data) {
|
|
|
361
361
|
bones.push(deserializeBone(r));
|
|
362
362
|
return { meshGeometryCount, materialCount, nodeCount, boneCount, stringId, geometries, materials, nodes, meshIndices, bones };
|
|
363
363
|
}
|
|
364
|
+
// ─── SpriteSheet Metadata ────────────────────────────────────────────────────
|
|
365
|
+
export function serializeSpriteSheetMetadata(meta) {
|
|
366
|
+
const w = new BinaryWriter(SPRITESHEET_METADATA_SIZE);
|
|
367
|
+
w.writeFixedString(meta.stringId, STRING_ID_SIZE);
|
|
368
|
+
w.writeFixedString(meta.textureId, STRING_ID_SIZE);
|
|
369
|
+
w.writeUint32(meta.rows);
|
|
370
|
+
w.writeUint32(meta.columns);
|
|
371
|
+
w.writeUint32(meta.frameCount);
|
|
372
|
+
w.writeFloat32(meta.frameRate);
|
|
373
|
+
return w.getUint8Array();
|
|
374
|
+
}
|
|
375
|
+
export function deserializeSpriteSheetMetadata(data) {
|
|
376
|
+
const r = new BinaryReader(data);
|
|
377
|
+
return {
|
|
378
|
+
stringId: r.readFixedString(STRING_ID_SIZE),
|
|
379
|
+
textureId: r.readFixedString(STRING_ID_SIZE),
|
|
380
|
+
rows: r.readUint32(),
|
|
381
|
+
columns: r.readUint32(),
|
|
382
|
+
frameCount: r.readUint32(),
|
|
383
|
+
frameRate: r.readFloat32(),
|
|
384
|
+
};
|
|
385
|
+
}
|
|
364
386
|
// ─── Metadata Wrapping ──────────────────────────────────────────────────────
|
|
365
387
|
export function wrapMetadata(assetMetadata, tags) {
|
|
366
388
|
const tagCsv = tags.length > 0 ? tags.join(',') + '\0' : '\0';
|
package/dist/node-fs.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface ScanResult {
|
|
|
14
14
|
sourceFiles: FileSnapshot[];
|
|
15
15
|
metaFiles: FileSnapshot[];
|
|
16
16
|
matFiles: FileSnapshot[];
|
|
17
|
+
spritesheetFiles: FileSnapshot[];
|
|
17
18
|
folders: string[];
|
|
18
19
|
}
|
|
19
20
|
export declare function scanDirectory(basePath: string): Promise<ScanResult>;
|
package/dist/node-fs.js
CHANGED
|
@@ -98,15 +98,19 @@ function isMetaFile(name) {
|
|
|
98
98
|
function isMatFile(name) {
|
|
99
99
|
return name.endsWith('.stowmat');
|
|
100
100
|
}
|
|
101
|
+
function isSpritesheetFile(name) {
|
|
102
|
+
return name.endsWith('.stowspritesheet');
|
|
103
|
+
}
|
|
101
104
|
export async function scanDirectory(basePath) {
|
|
102
105
|
const sourceFiles = [];
|
|
103
106
|
const metaFiles = [];
|
|
104
107
|
const matFiles = [];
|
|
108
|
+
const spritesheetFiles = [];
|
|
105
109
|
const folders = [];
|
|
106
|
-
await walkDirectory(basePath, '', sourceFiles, metaFiles, matFiles, folders);
|
|
107
|
-
return { sourceFiles, metaFiles, matFiles, folders };
|
|
110
|
+
await walkDirectory(basePath, '', sourceFiles, metaFiles, matFiles, spritesheetFiles, folders);
|
|
111
|
+
return { sourceFiles, metaFiles, matFiles, spritesheetFiles, folders };
|
|
108
112
|
}
|
|
109
|
-
async function walkDirectory(basePath, prefix, sourceFiles, metaFiles, matFiles, folders) {
|
|
113
|
+
async function walkDirectory(basePath, prefix, sourceFiles, metaFiles, matFiles, spritesheetFiles, folders) {
|
|
110
114
|
const dirPath = prefix ? path.join(basePath, prefix) : basePath;
|
|
111
115
|
let entries;
|
|
112
116
|
try {
|
|
@@ -123,7 +127,7 @@ async function walkDirectory(basePath, prefix, sourceFiles, metaFiles, matFiles,
|
|
|
123
127
|
if (entry.name.endsWith('.children'))
|
|
124
128
|
continue;
|
|
125
129
|
folders.push(relativePath);
|
|
126
|
-
await walkDirectory(basePath, relativePath, sourceFiles, metaFiles, matFiles, folders);
|
|
130
|
+
await walkDirectory(basePath, relativePath, sourceFiles, metaFiles, matFiles, spritesheetFiles, folders);
|
|
127
131
|
}
|
|
128
132
|
else if (entry.isFile()) {
|
|
129
133
|
const fullPath = path.join(basePath, relativePath);
|
|
@@ -145,6 +149,9 @@ async function walkDirectory(basePath, prefix, sourceFiles, metaFiles, matFiles,
|
|
|
145
149
|
else if (isMatFile(entry.name)) {
|
|
146
150
|
matFiles.push(snapshot);
|
|
147
151
|
}
|
|
152
|
+
else if (isSpritesheetFile(entry.name)) {
|
|
153
|
+
spritesheetFiles.push(snapshot);
|
|
154
|
+
}
|
|
148
155
|
else if (isSourceFile(entry.name)) {
|
|
149
156
|
sourceFiles.push(snapshot);
|
|
150
157
|
}
|
package/dist/orchestrator.d.ts
CHANGED
package/dist/orchestrator.js
CHANGED
|
@@ -8,6 +8,7 @@ import { readProjectConfig, scanDirectory, readFile, getFileSnapshot, probeImage
|
|
|
8
8
|
import { detectAssetType, readStowmeta, writeStowmeta, stowmetaToAssetSettings, generateDefaultStowmeta, glbChildToAssetSettings, generateDefaultGlbChild, } from './app/stowmeta-io.js';
|
|
9
9
|
import { parseGlb, pbrToMaterialConfig } from './encoders/glb-loader.js';
|
|
10
10
|
import { readStowmat, stowmatToMaterialConfig } from './app/stowmat-io.js';
|
|
11
|
+
import { readStowSpriteSheet, stowSpriteSheetToConfig } from './app/stowspritesheet-io.js';
|
|
11
12
|
import { readCacheBlobs, writeCacheBlobs, buildCacheStamp, isCacheValid, } from './app/process-cache.js';
|
|
12
13
|
import { buildPack, processExtractedAnimations, validatePackDependencies } from './pipeline.js';
|
|
13
14
|
import { WorkerPool } from './workers/worker-pool.js';
|
|
@@ -37,8 +38,9 @@ export async function scanProject(projectDir, opts) {
|
|
|
37
38
|
sourceFiles: scan.sourceFiles.length,
|
|
38
39
|
metaFiles: scan.metaFiles.length,
|
|
39
40
|
matFiles: scan.matFiles.length,
|
|
41
|
+
spritesheetFiles: scan.spritesheetFiles.length,
|
|
40
42
|
newFiles,
|
|
41
|
-
totalAssets: scan.sourceFiles.length + scan.matFiles.length,
|
|
43
|
+
totalAssets: scan.sourceFiles.length + scan.matFiles.length + scan.spritesheetFiles.length,
|
|
42
44
|
};
|
|
43
45
|
}
|
|
44
46
|
// ─── Full Build ──────────────────────────────────────────────────────────────
|
|
@@ -56,7 +58,7 @@ export async function fullBuild(projectDir, opts) {
|
|
|
56
58
|
// 1. Scan
|
|
57
59
|
const scan = await scanDirectory(config.srcArtDir);
|
|
58
60
|
if (verbose)
|
|
59
|
-
console.log(`Found ${scan.sourceFiles.length} source files, ${scan.matFiles.length} materials`);
|
|
61
|
+
console.log(`Found ${scan.sourceFiles.length} source files, ${scan.matFiles.length} materials, ${scan.spritesheetFiles.length} spritesheets`);
|
|
60
62
|
// 2. Build asset list
|
|
61
63
|
const assets = [];
|
|
62
64
|
const assetsById = new Map();
|
|
@@ -139,6 +141,33 @@ export async function fullBuild(projectDir, opts) {
|
|
|
139
141
|
assets.push(asset);
|
|
140
142
|
assetsById.set(id, asset);
|
|
141
143
|
}
|
|
144
|
+
// SpriteSheets from .stowspritesheet files
|
|
145
|
+
for (const ssFile of scan.spritesheetFiles) {
|
|
146
|
+
const id = ssFile.relativePath;
|
|
147
|
+
const sheet = await readStowSpriteSheet(config.srcArtDir, id);
|
|
148
|
+
if (!sheet)
|
|
149
|
+
continue;
|
|
150
|
+
const spritesheetConfig = stowSpriteSheetToConfig(sheet);
|
|
151
|
+
const fileName = id.split('/').pop() ?? id;
|
|
152
|
+
const baseName = fileName.replace(/\.[^.]+$/, '');
|
|
153
|
+
let meta = await readStowmeta(config.srcArtDir, id);
|
|
154
|
+
if (!meta) {
|
|
155
|
+
meta = generateDefaultStowmeta(id, AssetType.SpriteSheet, config.config.defaults);
|
|
156
|
+
await writeStowmeta(config.srcArtDir, id, meta);
|
|
157
|
+
}
|
|
158
|
+
const asset = {
|
|
159
|
+
id,
|
|
160
|
+
fileName,
|
|
161
|
+
stringId: meta.stringId || baseName,
|
|
162
|
+
type: AssetType.SpriteSheet,
|
|
163
|
+
status: 'ready',
|
|
164
|
+
settings: { ...defaultAssetSettings(), spritesheetConfig, pack: meta.pack ?? 'default', tags: meta.tags ?? [] },
|
|
165
|
+
sourceSize: ssFile.size,
|
|
166
|
+
processedSize: 0,
|
|
167
|
+
};
|
|
168
|
+
assets.push(asset);
|
|
169
|
+
assetsById.set(id, asset);
|
|
170
|
+
}
|
|
142
171
|
// 2b. Extract all GLB containers (always re-parse so preserveHierarchy etc. are reflected)
|
|
143
172
|
const glbExtracts = new Map();
|
|
144
173
|
const glbContainers = assets.filter(a => a.type === AssetType.GlbContainer);
|
|
@@ -480,6 +509,7 @@ export async function showStatus(projectDir) {
|
|
|
480
509
|
console.log(`Source dir: ${config.srcArtDir}`);
|
|
481
510
|
console.log(`Source files: ${scan.sourceFiles.length}`);
|
|
482
511
|
console.log(`Material files: ${scan.matFiles.length}`);
|
|
512
|
+
console.log(`SpriteSheet files: ${scan.spritesheetFiles.length}`);
|
|
483
513
|
console.log(`Meta files: ${scan.metaFiles.length}`);
|
|
484
514
|
const packs = config.config.packs ?? [{ name: 'default' }];
|
|
485
515
|
console.log(`Packs: ${packs.map(p => p.name).join(', ')}`);
|
package/dist/pipeline.js
CHANGED
|
@@ -2,7 +2,7 @@ import { AssetType, TextureChannelFormat, TextureResize, AudioSampleRate } from
|
|
|
2
2
|
import { parseGlb } from './encoders/glb-loader.js';
|
|
3
3
|
import { dracoPresetToSettings } from './encoders/draco-encoder.js';
|
|
4
4
|
import { buildSkinnedMeshData } from './encoders/skinned-mesh-builder.js';
|
|
5
|
-
import { serializeTextureMetadata, serializeAudioMetadata, serializeMeshMetadata, serializeAnimationClipMetadata, serializeSkinnedMeshMetadata, serializeMaterialSchemaMetadata, deserializeSkinnedMeshMetadata, deserializeAnimationClipMetadata, } from './format/metadata.js';
|
|
5
|
+
import { serializeTextureMetadata, serializeAudioMetadata, serializeMeshMetadata, serializeAnimationClipMetadata, serializeSkinnedMeshMetadata, serializeMaterialSchemaMetadata, serializeSpriteSheetMetadata, deserializeSkinnedMeshMetadata, deserializeAnimationClipMetadata, } from './format/metadata.js';
|
|
6
6
|
import { StowPacker } from './format/packer.js';
|
|
7
7
|
import { BlobStore } from './app/blob-store.js';
|
|
8
8
|
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
@@ -267,6 +267,22 @@ export function validatePackDependencies(packAssets, allAssetsById) {
|
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
269
|
}
|
|
270
|
+
// SpriteSheet: check texture reference
|
|
271
|
+
if (asset.type === AssetType.SpriteSheet) {
|
|
272
|
+
const texId = asset.settings.spritesheetConfig.textureAssetId;
|
|
273
|
+
if (texId) {
|
|
274
|
+
const tex = allAssetsById.get(texId);
|
|
275
|
+
if (!tex) {
|
|
276
|
+
errors.push({ assetId: asset.id, message: `SpriteSheet "${asset.stringId}" references missing texture "${texId}"` });
|
|
277
|
+
}
|
|
278
|
+
else if (tex.settings.excluded) {
|
|
279
|
+
errors.push({ assetId: asset.id, message: `SpriteSheet "${asset.stringId}" references excluded texture "${tex.stringId}"` });
|
|
280
|
+
}
|
|
281
|
+
else if (!packIds.has(tex.id)) {
|
|
282
|
+
errors.push({ assetId: asset.id, message: `SpriteSheet "${asset.stringId}" references texture "${tex.stringId}" which is not in the same pack` });
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
270
286
|
// AnimationClip: check target mesh reference
|
|
271
287
|
if (asset.type === AssetType.AnimationClip && asset.settings.targetMeshId) {
|
|
272
288
|
const target = allAssetsById.get(asset.settings.targetMeshId);
|
|
@@ -298,6 +314,12 @@ export function buildPack(assets, assetsById) {
|
|
|
298
314
|
packer.addAsset(asset.stringId, AssetType.MaterialSchema, new Uint8Array(0), schemaBytes, asset.settings.tags);
|
|
299
315
|
continue;
|
|
300
316
|
}
|
|
317
|
+
if (asset.type === AssetType.SpriteSheet) {
|
|
318
|
+
const ssMeta = buildSpriteSheetMetadata(asset, assetsById);
|
|
319
|
+
const ssBytes = serializeSpriteSheetMetadata(ssMeta);
|
|
320
|
+
packer.addAsset(asset.stringId, AssetType.SpriteSheet, new Uint8Array(0), ssBytes, asset.settings.tags);
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
301
323
|
const processedData = BlobStore.getProcessed(asset.id);
|
|
302
324
|
if (!processedData) {
|
|
303
325
|
console.warn(`[buildPack] Skipping ${asset.id} (type=${asset.type}): no processed data in BlobStore`);
|
|
@@ -433,6 +455,20 @@ function buildMaterialSchemaMetadata(asset, assetsById) {
|
|
|
433
455
|
fields,
|
|
434
456
|
};
|
|
435
457
|
}
|
|
458
|
+
function buildSpriteSheetMetadata(asset, assetsById) {
|
|
459
|
+
const config = asset.settings.spritesheetConfig;
|
|
460
|
+
const textureAsset = config.textureAssetId
|
|
461
|
+
? assetsById.get(config.textureAssetId)
|
|
462
|
+
: undefined;
|
|
463
|
+
return {
|
|
464
|
+
stringId: asset.stringId,
|
|
465
|
+
textureId: textureAsset?.stringId ?? '',
|
|
466
|
+
rows: config.rows,
|
|
467
|
+
columns: config.columns,
|
|
468
|
+
frameCount: config.frameCount,
|
|
469
|
+
frameRate: config.frameRate,
|
|
470
|
+
};
|
|
471
|
+
}
|
|
436
472
|
// ─── Animation data blob builder (v2) ────────────────────────────────────────
|
|
437
473
|
export function buildAnimationDataBlobsV2(imported) {
|
|
438
474
|
const results = [];
|
package/dist/server.js
CHANGED
|
@@ -8,7 +8,8 @@ import { BlobStore } from './app/blob-store.js';
|
|
|
8
8
|
import { readProjectConfig, scanDirectory, readFile, writeFile, renameFile, deleteFile, getFileSnapshot, probeImageDimensions, } from './node-fs.js';
|
|
9
9
|
import { detectAssetType, readStowmeta, writeStowmeta, stowmetaToAssetSettings, assetSettingsToStowmeta, generateDefaultStowmeta, glbChildToAssetSettings, generateDefaultGlbChild, writeGlbChildSettings, } from './app/stowmeta-io.js';
|
|
10
10
|
import { readStowmat, writeStowmat, stowmatToMaterialConfig, materialConfigToStowmat } from './app/stowmat-io.js';
|
|
11
|
-
import {
|
|
11
|
+
import { readStowSpriteSheet, writeStowSpriteSheet, stowSpriteSheetToConfig, spritesheetConfigToStowSpriteSheet } from './app/stowspritesheet-io.js';
|
|
12
|
+
import { readCacheBlobs, writeCacheBlobs, buildCacheStamp, isCacheValid, deleteCacheFile, } from './app/process-cache.js';
|
|
12
13
|
import { buildPack, validatePackDependencies, processExtractedAnimations } from './pipeline.js';
|
|
13
14
|
import { syncRuntimeAssets } from './sync-runtime-assets.js';
|
|
14
15
|
import { parseGlb, pbrToMaterialConfig } from './encoders/glb-loader.js';
|
|
@@ -637,8 +638,16 @@ async function openProject(projectDir) {
|
|
|
637
638
|
BlobStore.setProcessed(key, data);
|
|
638
639
|
}
|
|
639
640
|
}
|
|
640
|
-
|
|
641
|
-
|
|
641
|
+
const processedData = BlobStore.getProcessed(file.relativePath);
|
|
642
|
+
if (processedData && processedData.length > 0) {
|
|
643
|
+
asset.status = 'ready';
|
|
644
|
+
asset.processedSize = processedData.length;
|
|
645
|
+
}
|
|
646
|
+
else {
|
|
647
|
+
// Cache corrupt or missing processed blob — delete and reprocess
|
|
648
|
+
console.warn(`[cache] Corrupt cache for ${file.relativePath} — deleting and reprocessing`);
|
|
649
|
+
await deleteCacheFile(projectConfig.srcArtDir, file.relativePath);
|
|
650
|
+
}
|
|
642
651
|
}
|
|
643
652
|
}
|
|
644
653
|
}
|
|
@@ -680,6 +689,33 @@ async function openProject(projectDir) {
|
|
|
680
689
|
processedSize: 0,
|
|
681
690
|
});
|
|
682
691
|
}
|
|
692
|
+
// SpriteSheets from .stowspritesheet files
|
|
693
|
+
for (const ssFile of scan.spritesheetFiles) {
|
|
694
|
+
const id = ssFile.relativePath;
|
|
695
|
+
const sheet = await readStowSpriteSheet(projectConfig.srcArtDir, id);
|
|
696
|
+
const fileName = id.split('/').pop() ?? id;
|
|
697
|
+
const baseName = fileName.replace(/\.[^.]+$/, '');
|
|
698
|
+
let meta = await readStowmeta(projectConfig.srcArtDir, id);
|
|
699
|
+
if (!meta) {
|
|
700
|
+
meta = generateDefaultStowmeta(id, AssetType.SpriteSheet, projectConfig.config.defaults);
|
|
701
|
+
await writeStowmeta(projectConfig.srcArtDir, id, meta);
|
|
702
|
+
}
|
|
703
|
+
const spritesheetConfig = sheet ? stowSpriteSheetToConfig(sheet) : { textureAssetId: null, rows: 1, columns: 1, frameCount: 1, frameRate: 12 };
|
|
704
|
+
const settings = defaultAssetSettings();
|
|
705
|
+
settings.spritesheetConfig = spritesheetConfig;
|
|
706
|
+
settings.pack = meta.pack ?? 'default';
|
|
707
|
+
settings.tags = meta.tags ?? [];
|
|
708
|
+
assets.push({
|
|
709
|
+
id,
|
|
710
|
+
fileName: baseName,
|
|
711
|
+
stringId: meta.stringId || baseName,
|
|
712
|
+
type: AssetType.SpriteSheet,
|
|
713
|
+
status: 'ready',
|
|
714
|
+
settings,
|
|
715
|
+
sourceSize: ssFile.size,
|
|
716
|
+
processedSize: 0,
|
|
717
|
+
});
|
|
718
|
+
}
|
|
683
719
|
console.log(`[server] Opened: ${projectConfig.projectName} (${assets.length} assets, ${folders.length} folders)`);
|
|
684
720
|
}
|
|
685
721
|
// ─── Process single asset ─────────────────────────────────────────────────
|
|
@@ -945,6 +981,7 @@ async function handleRequest(req, res, staticApps) {
|
|
|
945
981
|
const diskFiles = new Map([
|
|
946
982
|
...scan.sourceFiles.map(f => [f.relativePath, f]),
|
|
947
983
|
...scan.matFiles.map(f => [f.relativePath, f]),
|
|
984
|
+
...scan.spritesheetFiles.map(f => [f.relativePath, f]),
|
|
948
985
|
]);
|
|
949
986
|
const diskIds = new Set(diskFiles.keys());
|
|
950
987
|
// Check for added/removed files
|
|
@@ -956,7 +993,7 @@ async function handleRequest(req, res, staticApps) {
|
|
|
956
993
|
const modifiedIds = [];
|
|
957
994
|
if (!changed) {
|
|
958
995
|
for (const asset of currentAssets) {
|
|
959
|
-
if (asset.type === AssetType.MaterialSchema)
|
|
996
|
+
if (asset.type === AssetType.MaterialSchema || asset.type === AssetType.SpriteSheet)
|
|
960
997
|
continue;
|
|
961
998
|
const diskFile = diskFiles.get(asset.id);
|
|
962
999
|
if (diskFile && asset.sourceSize > 0 && diskFile.size !== asset.sourceSize) {
|
|
@@ -1146,6 +1183,10 @@ async function handleRequest(req, res, staticApps) {
|
|
|
1146
1183
|
const stowmat = materialConfigToStowmat(merged.materialConfig);
|
|
1147
1184
|
await writeStowmat(projectConfig.srcArtDir, id, stowmat);
|
|
1148
1185
|
}
|
|
1186
|
+
if (asset.type === AssetType.SpriteSheet && body.settings.spritesheetConfig) {
|
|
1187
|
+
const sheet = spritesheetConfigToStowSpriteSheet(merged.spritesheetConfig);
|
|
1188
|
+
await writeStowSpriteSheet(projectConfig.srcArtDir, id, sheet);
|
|
1189
|
+
}
|
|
1149
1190
|
}
|
|
1150
1191
|
}
|
|
1151
1192
|
// Check if needs reprocessing
|
|
@@ -1551,6 +1592,43 @@ async function handleRequest(req, res, staticApps) {
|
|
|
1551
1592
|
json(res, { ok: true, asset });
|
|
1552
1593
|
return;
|
|
1553
1594
|
}
|
|
1595
|
+
// POST /api/create-spritesheet
|
|
1596
|
+
if (pathname === '/api/create-spritesheet' && req.method === 'POST') {
|
|
1597
|
+
if (!projectConfig) {
|
|
1598
|
+
json(res, { error: 'No project open' }, 400);
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
const body = JSON.parse(await readBody(req));
|
|
1602
|
+
const targetFolder = body.targetFolder ?? '';
|
|
1603
|
+
const name = body.name?.trim() || `SpriteSheet ${assets.filter(a => a.type === AssetType.SpriteSheet).length + 1}`;
|
|
1604
|
+
const baseName = `${name.replace(/\s+/g, '_')}.stowspritesheet`;
|
|
1605
|
+
const fileName = targetFolder ? `${targetFolder}/${baseName}` : baseName;
|
|
1606
|
+
const settings = defaultAssetSettings();
|
|
1607
|
+
settings.spritesheetConfig = {
|
|
1608
|
+
textureAssetId: null,
|
|
1609
|
+
rows: 1,
|
|
1610
|
+
columns: 1,
|
|
1611
|
+
frameCount: 1,
|
|
1612
|
+
frameRate: 12,
|
|
1613
|
+
};
|
|
1614
|
+
const asset = {
|
|
1615
|
+
id: fileName,
|
|
1616
|
+
fileName: name,
|
|
1617
|
+
stringId: name,
|
|
1618
|
+
type: AssetType.SpriteSheet,
|
|
1619
|
+
status: 'ready',
|
|
1620
|
+
settings,
|
|
1621
|
+
sourceSize: 0,
|
|
1622
|
+
processedSize: 0,
|
|
1623
|
+
};
|
|
1624
|
+
assets.push(asset);
|
|
1625
|
+
const stowSpriteSheet = spritesheetConfigToStowSpriteSheet(settings.spritesheetConfig);
|
|
1626
|
+
await writeStowSpriteSheet(projectConfig.srcArtDir, fileName, stowSpriteSheet);
|
|
1627
|
+
const meta = assetSettingsToStowmeta(asset);
|
|
1628
|
+
await writeStowmeta(projectConfig.srcArtDir, fileName, meta);
|
|
1629
|
+
json(res, { ok: true, asset });
|
|
1630
|
+
return;
|
|
1631
|
+
}
|
|
1554
1632
|
// POST /api/create-folder
|
|
1555
1633
|
if (pathname === '/api/create-folder' && req.method === 'POST') {
|
|
1556
1634
|
if (!projectConfig) {
|
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.40",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"stowkit": "./dist/cli.js"
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@google/genai": "^1.46.0",
|
|
22
22
|
"@series-inc/stowkit-editor": "^0.1.8",
|
|
23
|
-
"@series-inc/stowkit-packer-gui": "^0.1.
|
|
23
|
+
"@series-inc/stowkit-packer-gui": "^0.1.30",
|
|
24
24
|
"@strangeape/ffmpeg-audio-wasm": "^0.1.0",
|
|
25
25
|
"draco3d": "^1.5.7",
|
|
26
26
|
"fbx-parser": "^2.1.3",
|