create-aura3d 1.3.0 → 1.3.2
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 +0 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -3
- package/templates/animation-channel/package.json +1 -1
- package/templates/animation-studio/dist/episodes/scene/episode-3d.webm +0 -0
- package/templates/animation-studio/dist/episodes/scene/frames/action.png +0 -0
- package/templates/animation-studio/dist/episodes/scene/frames/dialogue.png +0 -0
- package/templates/animation-studio/dist/episodes/scene/frames/final.png +0 -0
- package/templates/animation-studio/dist/episodes/scene/frames/first.png +0 -0
- package/templates/animation-studio/dist/episodes/scene/frames/mouth-closed.png +0 -0
- package/templates/animation-studio/dist/episodes/scene/frames/mouth-open.png +0 -0
- package/templates/animation-studio/dist/episodes/scene/render-live-summary.json +2086 -6754
- package/templates/animation-studio/dist/episodes/scene/skeleton-overlays/broken.png +0 -0
- package/templates/animation-studio/dist/episodes/scene/skeleton-overlays/chefs.png +0 -0
- package/templates/animation-studio/dist/episodes/scene/skeleton-overlays/customer.png +0 -0
- package/templates/animation-studio/dist/episodes/scene/skeleton-overlays/worker-1.png +0 -0
- package/templates/animation-studio/dist/episodes/scene/skeleton-overlays/worker-2.png +0 -0
- package/templates/animation-studio/dist/scene/working.document.json +219 -348
- package/templates/animation-studio/package-lock.json +1307 -55
- package/templates/animation-studio/package.json +11 -5
- package/templates/animation-studio/studio/dist/assets/index-i8URxOOt.css +1 -0
- package/templates/animation-studio/studio/dist/assets/index-pC9hdZ-B.js +11 -0
- package/templates/animation-studio/studio/dist/index.html +19 -0
- package/templates/animation-studio/studio/index.html +18 -0
- package/templates/animation-studio/studio/src/App.tsx +430 -0
- package/templates/animation-studio/studio/src/components/Console.tsx +366 -0
- package/templates/animation-studio/studio/src/components/Icon.tsx +90 -0
- package/templates/animation-studio/studio/src/components/Inspector.tsx +209 -0
- package/templates/animation-studio/studio/src/components/Outliner.tsx +210 -0
- package/templates/animation-studio/studio/src/components/Palette.tsx +204 -0
- package/templates/animation-studio/studio/src/components/Stage.tsx +339 -0
- package/templates/animation-studio/studio/src/components/Timeline.tsx +183 -0
- package/templates/animation-studio/studio/src/components/Topbar.tsx +66 -0
- package/templates/animation-studio/studio/src/main.tsx +10 -0
- package/templates/animation-studio/studio/src/state/backend.ts +108 -0
- package/templates/animation-studio/studio/src/state/fidelity.ts +110 -0
- package/templates/animation-studio/studio/src/state/mapDocument.ts +419 -0
- package/templates/animation-studio/studio/src/state/sceneTool.ts +55 -0
- package/templates/animation-studio/studio/src/state/types.ts +165 -0
- package/templates/animation-studio/studio/src/state/util.ts +46 -0
- package/templates/animation-studio/studio/src/styles.css +528 -0
- package/templates/animation-studio/studio/vite.config.ts +175 -0
- package/templates/character-controller/package.json +3 -3
- package/templates/cinematic-scene/package.json +1 -1
- package/templates/episode-builder/package.json +1 -1
- package/templates/fighting-game/package.json +1 -1
- package/templates/mini-game/package.json +1 -1
- package/templates/product-viewer/package.json +1 -1
- package/templates/prompt-animation-channel/package.json +1 -1
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createReadStream, existsSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { dirname, extname, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { defineConfig, type Plugin, type ViteDevServer } from "vite";
|
|
6
|
+
import react from "@vitejs/plugin-react";
|
|
7
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
8
|
+
|
|
9
|
+
// Aura3D Animation Studio — bundled inside the animation-studio template.
|
|
10
|
+
// Adapts the monorepo paths (REPO_ROOT, tsconfig.base.json) to the template's
|
|
11
|
+
// standalone project layout so `npm run studio` works in a scaffolded project.
|
|
12
|
+
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
// The template root (parent of this studio/ directory).
|
|
15
|
+
const TEMPLATE_DIR = resolve(__dirname, "..");
|
|
16
|
+
// The Scene-Tool CLI lives inside the template's scripts/ folder.
|
|
17
|
+
const SCENE_CLI = resolve(TEMPLATE_DIR, "scripts", "animation-scene.ts");
|
|
18
|
+
// Persisted working document the Scene-Tool CLI mutates.
|
|
19
|
+
const WORKING_DOC = resolve(TEMPLATE_DIR, "dist", "scene", "working.document.json");
|
|
20
|
+
// Command/result history alongside the working document.
|
|
21
|
+
const WORKING_HISTORY = resolve(TEMPLATE_DIR, "dist", "scene", "working.history.json");
|
|
22
|
+
// Where `animation-scene render` writes frames + episode-3d.webm.
|
|
23
|
+
const RENDER_OUT_DIR = resolve(TEMPLATE_DIR, "dist", "episodes", "scene");
|
|
24
|
+
|
|
25
|
+
const MIME: Record<string, string> = {
|
|
26
|
+
".webm": "video/webm",
|
|
27
|
+
".png": "image/png",
|
|
28
|
+
".jpg": "image/jpeg",
|
|
29
|
+
".json": "application/json"
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function readBody(req: IncomingMessage): Promise<string> {
|
|
33
|
+
return new Promise((res, rej) => {
|
|
34
|
+
const chunks: Buffer[] = [];
|
|
35
|
+
req.on("data", (c: Buffer) => chunks.push(c));
|
|
36
|
+
req.on("end", () => res(Buffer.concat(chunks).toString("utf8")));
|
|
37
|
+
req.on("error", rej);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function json(res: ServerResponse, code: number, body: unknown): void {
|
|
42
|
+
res.statusCode = code;
|
|
43
|
+
res.setHeader("content-type", "application/json");
|
|
44
|
+
res.end(JSON.stringify(body));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function tokenize(command: string): string[] {
|
|
48
|
+
const out: string[] = [];
|
|
49
|
+
const re = /"([^"]*)"|'([^']*)'|(\S+)/g;
|
|
50
|
+
let m: RegExpExecArray | null;
|
|
51
|
+
while ((m = re.exec(command))) out.push(m[1] ?? m[2] ?? m[3] ?? "");
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Spawn the Scene-Tool CLI from the template root using npx tsx. */
|
|
56
|
+
function runCli(args: string[], extraEnv: Record<string, string> = {}): Promise<{ code: number; out: string }> {
|
|
57
|
+
return new Promise((res) => {
|
|
58
|
+
const child = spawn(
|
|
59
|
+
"npx",
|
|
60
|
+
["tsx", SCENE_CLI, ...args],
|
|
61
|
+
{ cwd: TEMPLATE_DIR, env: { ...process.env, ...extraEnv } }
|
|
62
|
+
);
|
|
63
|
+
let out = "";
|
|
64
|
+
child.stdout.on("data", (d: Buffer) => (out += d.toString("utf8")));
|
|
65
|
+
child.stderr.on("data", (d: Buffer) => (out += d.toString("utf8")));
|
|
66
|
+
child.on("error", (e) => res({ code: 1, out: out + String(e) }));
|
|
67
|
+
child.on("close", (code) => res({ code: code ?? 0, out: out.trim() }));
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function docHash(): string {
|
|
72
|
+
if (!existsSync(WORKING_DOC)) return "—";
|
|
73
|
+
let h = 5381;
|
|
74
|
+
const buf = readFileSync(WORKING_DOC);
|
|
75
|
+
for (let i = 0; i < buf.length; i++) h = ((h << 5) + h + buf[i]!) >>> 0;
|
|
76
|
+
return h.toString(16).slice(-3);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function auraBackend(): Plugin {
|
|
80
|
+
return {
|
|
81
|
+
name: "aura-studio-backend",
|
|
82
|
+
apply: "serve",
|
|
83
|
+
configureServer(server: ViteDevServer) {
|
|
84
|
+
server.middlewares.use("/api/document", (req, res, next) => {
|
|
85
|
+
if (req.method !== "GET") return next();
|
|
86
|
+
try {
|
|
87
|
+
if (!existsSync(WORKING_DOC)) return json(res, 200, { exists: false });
|
|
88
|
+
const doc = JSON.parse(readFileSync(WORKING_DOC, "utf8")) as unknown;
|
|
89
|
+
json(res, 200, doc);
|
|
90
|
+
} catch (e) {
|
|
91
|
+
json(res, 500, { ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
server.middlewares.use("/api/history", (req, res, next) => {
|
|
96
|
+
if (req.method !== "GET") return next();
|
|
97
|
+
try {
|
|
98
|
+
if (!existsSync(WORKING_HISTORY)) return json(res, 200, []);
|
|
99
|
+
const hist = JSON.parse(readFileSync(WORKING_HISTORY, "utf8")) as unknown;
|
|
100
|
+
json(res, 200, Array.isArray(hist) ? hist : []);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
json(res, 500, { ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
server.middlewares.use("/api/scene", (req, res, next) => {
|
|
107
|
+
if (req.method !== "POST") return next();
|
|
108
|
+
void (async () => {
|
|
109
|
+
const started = Date.now();
|
|
110
|
+
try {
|
|
111
|
+
const { command } = JSON.parse((await readBody(req)) || "{}") as { command?: string };
|
|
112
|
+
if (!command || !command.trim()) return json(res, 400, { ok: false, error: "empty command" });
|
|
113
|
+
const { code, out } = await runCli(tokenize(command.trim()));
|
|
114
|
+
const ok = code === 0;
|
|
115
|
+
json(res, 200, { ok, output: out, rejected: !ok, ms: Date.now() - started, hash: docHash() });
|
|
116
|
+
} catch (e) {
|
|
117
|
+
json(res, 500, { ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
118
|
+
}
|
|
119
|
+
})();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
server.middlewares.use("/api/render", (req, res, next) => {
|
|
123
|
+
if (req.method === "GET") {
|
|
124
|
+
const webm = resolve(RENDER_OUT_DIR, "episode-3d.webm");
|
|
125
|
+
const poster = resolve(RENDER_OUT_DIR, "frames", "first.png");
|
|
126
|
+
const hasVideo = existsSync(webm);
|
|
127
|
+
json(res, 200, {
|
|
128
|
+
ok: true, exists: hasVideo,
|
|
129
|
+
video: hasVideo ? "/preview/episode-3d.webm" : null,
|
|
130
|
+
poster: existsSync(poster) ? "/preview/frames/first.png" : null,
|
|
131
|
+
hash: docHash()
|
|
132
|
+
});
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (req.method !== "POST") return next();
|
|
136
|
+
void (async () => {
|
|
137
|
+
const started = Date.now();
|
|
138
|
+
try {
|
|
139
|
+
const body = JSON.parse((await readBody(req)) || "{}") as { lowFi?: boolean; range?: string };
|
|
140
|
+
const args = ["render"];
|
|
141
|
+
if (body.range) args.push("--range", body.range);
|
|
142
|
+
const env: Record<string, string> = { AURA_LOW_FIDELITY: body.lowFi === false ? "0" : "1" };
|
|
143
|
+
const { code, out } = await runCli(args, env);
|
|
144
|
+
if (code !== 0) return json(res, 500, { ok: false, output: out });
|
|
145
|
+
const webm = resolve(RENDER_OUT_DIR, "episode-3d.webm");
|
|
146
|
+
const poster = resolve(RENDER_OUT_DIR, "frames", "first.png");
|
|
147
|
+
json(res, 200, {
|
|
148
|
+
ok: true, output: out, ms: Date.now() - started,
|
|
149
|
+
video: existsSync(webm) ? "/preview/episode-3d.webm" : null,
|
|
150
|
+
poster: existsSync(poster) ? "/preview/frames/first.png" : null,
|
|
151
|
+
hash: docHash()
|
|
152
|
+
});
|
|
153
|
+
} catch (e) {
|
|
154
|
+
json(res, 500, { ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
155
|
+
}
|
|
156
|
+
})();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
server.middlewares.use("/preview", (req, res, next) => {
|
|
160
|
+
const rel = decodeURIComponent((req.url ?? "/").split("?")[0]!).replace(/^\/+/, "");
|
|
161
|
+
const file = resolve(RENDER_OUT_DIR, rel);
|
|
162
|
+
if (!file.startsWith(RENDER_OUT_DIR) || !existsSync(file) || !statSync(file).isFile()) return next();
|
|
163
|
+
res.setHeader("content-type", MIME[extname(file)] ?? "application/octet-stream");
|
|
164
|
+
res.setHeader("cache-control", "no-store");
|
|
165
|
+
createReadStream(file).pipe(res);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export default defineConfig({
|
|
172
|
+
plugins: [react(), auraBackend()],
|
|
173
|
+
server: { host: "127.0.0.1", port: 5188 },
|
|
174
|
+
build: { outDir: "dist", emptyOutDir: true }
|
|
175
|
+
});
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"test": "playwright test tests/route-health.spec.ts tests/screenshot.spec.ts --workers=1"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@aura3d/animation": "1.3.
|
|
15
|
-
"@aura3d/engine": "1.3.
|
|
16
|
-
"@aura3d/physics": "1.3.
|
|
14
|
+
"@aura3d/animation": "1.3.2",
|
|
15
|
+
"@aura3d/engine": "1.3.2",
|
|
16
|
+
"@aura3d/physics": "1.3.2"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@playwright/test": "^1.52.0",
|