@aura3d/cli 5.0.2 → 5.1.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/data/aura.exports.json +20 -0
- package/dist/commands/registry.d.ts +1 -0
- package/dist/commands/registry.d.ts.map +1 -1
- package/dist/commands/registry.js +1 -0
- package/dist/commands/registry.js.map +1 -1
- package/dist/commands/verify/index.d.ts +2 -0
- package/dist/commands/verify/index.d.ts.map +1 -0
- package/dist/commands/verify/index.js +11 -0
- package/dist/commands/verify/index.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/look-hdri-check.d.ts +7 -0
- package/dist/look-hdri-check.d.ts.map +1 -0
- package/dist/look-hdri-check.js +88 -0
- package/dist/look-hdri-check.js.map +1 -0
- package/dist/verify/cdp.d.ts +69 -0
- package/dist/verify/cdp.d.ts.map +1 -0
- package/dist/verify/cdp.js +223 -0
- package/dist/verify/cdp.js.map +1 -0
- package/dist/verify/codes.d.ts +17 -0
- package/dist/verify/codes.d.ts.map +1 -0
- package/dist/verify/codes.js +64 -0
- package/dist/verify/codes.js.map +1 -0
- package/dist/verify/command.d.ts +12 -0
- package/dist/verify/command.d.ts.map +1 -0
- package/dist/verify/command.js +101 -0
- package/dist/verify/command.js.map +1 -0
- package/dist/verify/frame.d.ts +46 -0
- package/dist/verify/frame.d.ts.map +1 -0
- package/dist/verify/frame.js +190 -0
- package/dist/verify/frame.js.map +1 -0
- package/dist/verify/index.d.ts +7 -0
- package/dist/verify/index.d.ts.map +1 -0
- package/dist/verify/index.js +7 -0
- package/dist/verify/index.js.map +1 -0
- package/dist/verify/lint.d.ts +43 -0
- package/dist/verify/lint.d.ts.map +1 -0
- package/dist/verify/lint.js +548 -0
- package/dist/verify/lint.js.map +1 -0
- package/dist/verify/run.d.ts +90 -0
- package/dist/verify/run.d.ts.map +1 -0
- package/dist/verify/run.js +317 -0
- package/dist/verify/run.js.map +1 -0
- package/package.json +6 -6
- package/skills/agent-docs/api-signatures.md +27 -4
- package/skills/agent-docs/recipes.md +4 -3
- package/skills/agent-docs/threejs-to-aura3d.md +1 -1
- package/skills/agent-files/AGENTS.md +1 -1
- package/skills/aura3d-materials-environments/SKILL.md +1 -1
- package/skills/aura3d-materials-environments/references/visual-helpers.md +20 -0
- package/skills/llms.txt +158 -29
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { type VerifyBrowserDriver } from "./cdp.js";
|
|
2
|
+
import { type VerifySeverity, type VerifyStepId } from "./codes.js";
|
|
3
|
+
import { type FrameAnalysis, type MotionAnalysis } from "./frame.js";
|
|
4
|
+
export declare const VERIFY_SCHEMA = "aura3d.verify/1";
|
|
5
|
+
export declare const VERIFY_STEP_ORDER: readonly ["typecheck", "assets", "lint", "build", "serve", "render", "inspect"];
|
|
6
|
+
export type VerifyStep = (typeof VERIFY_STEP_ORDER)[number];
|
|
7
|
+
export interface VerifyFinding {
|
|
8
|
+
readonly code: string;
|
|
9
|
+
readonly severity: VerifySeverity;
|
|
10
|
+
readonly step: VerifyStepId;
|
|
11
|
+
/** What was found, specific to this project. */
|
|
12
|
+
readonly message: string;
|
|
13
|
+
/** Plain-English cause, keyed by code (same text as `aura3d verify --explain <code>`). */
|
|
14
|
+
readonly cause: string;
|
|
15
|
+
/** Concrete fix hint, keyed by code. */
|
|
16
|
+
readonly fix: string;
|
|
17
|
+
/** `file:line:column` for source findings. */
|
|
18
|
+
readonly location?: {
|
|
19
|
+
readonly file: string;
|
|
20
|
+
readonly line: number;
|
|
21
|
+
readonly column: number;
|
|
22
|
+
};
|
|
23
|
+
readonly evidence?: Readonly<Record<string, unknown>>;
|
|
24
|
+
}
|
|
25
|
+
export interface VerifyStepResult {
|
|
26
|
+
readonly id: VerifyStep;
|
|
27
|
+
readonly status: "pass" | "fail" | "skipped";
|
|
28
|
+
readonly durationMs: number;
|
|
29
|
+
readonly detail?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface VerifyReport {
|
|
32
|
+
readonly schema: typeof VERIFY_SCHEMA;
|
|
33
|
+
/** True when no finding has severity "error" and no step crashed. */
|
|
34
|
+
readonly ok: boolean;
|
|
35
|
+
readonly project: string;
|
|
36
|
+
readonly startedAt: string;
|
|
37
|
+
readonly durationMs: number;
|
|
38
|
+
readonly steps: readonly VerifyStepResult[];
|
|
39
|
+
readonly findings: readonly VerifyFinding[];
|
|
40
|
+
readonly counts: {
|
|
41
|
+
readonly error: number;
|
|
42
|
+
readonly warning: number;
|
|
43
|
+
readonly info: number;
|
|
44
|
+
};
|
|
45
|
+
/** Present when the render step produced a frame. */
|
|
46
|
+
readonly render?: {
|
|
47
|
+
readonly driver: string;
|
|
48
|
+
readonly viewport: {
|
|
49
|
+
readonly width: number;
|
|
50
|
+
readonly height: number;
|
|
51
|
+
};
|
|
52
|
+
readonly backend?: string;
|
|
53
|
+
readonly drawCalls?: number;
|
|
54
|
+
readonly frame?: FrameAnalysis;
|
|
55
|
+
readonly motion?: MotionAnalysis;
|
|
56
|
+
readonly degradeCodes: readonly string[];
|
|
57
|
+
/** File names of saved frames (relative to --frames-dir), when requested. */
|
|
58
|
+
readonly frames?: readonly string[];
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export interface VerifyOptions {
|
|
62
|
+
readonly projectDir: string;
|
|
63
|
+
/** Steps to leave out. `inspect` needs `render`. */
|
|
64
|
+
readonly skip?: readonly VerifyStep[];
|
|
65
|
+
readonly distDir?: string;
|
|
66
|
+
readonly buildTimeoutMs?: number;
|
|
67
|
+
/** Replaces the default Chrome/CDP driver (tests inject a mock). */
|
|
68
|
+
readonly driver?: VerifyBrowserDriver;
|
|
69
|
+
readonly chromePath?: string;
|
|
70
|
+
readonly softwareGl?: boolean;
|
|
71
|
+
readonly route?: string;
|
|
72
|
+
readonly width?: number;
|
|
73
|
+
readonly height?: number;
|
|
74
|
+
readonly settleMs?: number;
|
|
75
|
+
readonly motionGapMs?: number;
|
|
76
|
+
readonly timeoutMs?: number;
|
|
77
|
+
readonly readyTimeoutMs?: number;
|
|
78
|
+
/** Save the two captured frames as `<project>-frame1.png` / `-frame2.png` in this directory (paths are recorded in `render.frames`). */
|
|
79
|
+
readonly framesDir?: string;
|
|
80
|
+
/** Directory used as a mutex (mkdir) around the browser steps only, so several verify runs share one GPU/browser without holding it during builds. */
|
|
81
|
+
readonly browserLock?: string;
|
|
82
|
+
/** Test seam: skip real tsc and build processes. */
|
|
83
|
+
readonly runCommand?: (command: string, args: readonly string[], cwd: string, timeoutMs: number) => {
|
|
84
|
+
status: number | null;
|
|
85
|
+
output: string;
|
|
86
|
+
};
|
|
87
|
+
readonly now?: () => number;
|
|
88
|
+
}
|
|
89
|
+
export declare function runVerify(options: VerifyOptions): Promise<VerifyReport>;
|
|
90
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/verify/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
// `aura3d verify`: author -> validate -> render -> inspect -> correct, as one pass that ends in ONE machine-readable report.
|
|
2
|
+
// Steps run in a fixed order (typecheck, assets, lint, build, serve, render, inspect). Every problem becomes a finding with a stable code,
|
|
3
|
+
// a severity, a location (file:line for source findings), a plain-English cause and a fix hint from the explainer table in codes.ts.
|
|
4
|
+
// The browser is a pluggable driver (default: local Chrome over CDP, see cdp.ts); nothing here imports Playwright or the engine.
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync, rmdirSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { createRequire } from "node:module";
|
|
8
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
9
|
+
import { startStaticServer } from "../deploy-browser-check.js";
|
|
10
|
+
import { checkDeploy, validateAssets } from "../index.js";
|
|
11
|
+
import { BrowserUnavailableError, createChromeCdpDriver } from "./cdp.js";
|
|
12
|
+
import { explainCode } from "./codes.js";
|
|
13
|
+
import { analyzeFrame, compareFrames, decodePng } from "./frame.js";
|
|
14
|
+
import { lintProject } from "./lint.js";
|
|
15
|
+
export const VERIFY_SCHEMA = "aura3d.verify/1";
|
|
16
|
+
export const VERIFY_STEP_ORDER = ["typecheck", "assets", "lint", "build", "serve", "render", "inspect"];
|
|
17
|
+
function defaultRunCommand(command, args, cwd, timeoutMs) {
|
|
18
|
+
const result = spawnSync(command, [...args], { cwd, encoding: "utf8", timeout: timeoutMs, maxBuffer: 1 << 26, env: { ...process.env, FORCE_COLOR: "0", CI: "1" } });
|
|
19
|
+
return { status: result.status, output: `${result.stdout ?? ""}${result.stderr ?? ""}${result.error ? `\n${result.error.message}` : ""}` };
|
|
20
|
+
}
|
|
21
|
+
function makeFinding(code, message, extra = {}) {
|
|
22
|
+
const entry = explainCode(code);
|
|
23
|
+
if (!entry)
|
|
24
|
+
throw new Error(`verify: code ${code} is missing from the explainer table`);
|
|
25
|
+
return {
|
|
26
|
+
code, severity: extra.severity ?? entry.severity, step: entry.step, message, cause: entry.cause, fix: entry.fix,
|
|
27
|
+
...(extra.location ? { location: extra.location } : {}), ...(extra.evidence ? { evidence: extra.evidence } : {})
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const tail = (text, lines = 15) => text.split("\n").filter((line) => line.trim()).slice(-lines).join("\n");
|
|
31
|
+
/** Nearest local `tsc`: the project's node_modules (or an ancestor's), else the TypeScript bundled with this CLI. */
|
|
32
|
+
function resolveTsc(projectDir) {
|
|
33
|
+
let dir = projectDir;
|
|
34
|
+
for (let i = 0; i < 8; i++) {
|
|
35
|
+
const candidate = join(dir, "node_modules", "typescript", "bin", "tsc");
|
|
36
|
+
if (existsSync(candidate))
|
|
37
|
+
return candidate;
|
|
38
|
+
const parent = dirname(dir);
|
|
39
|
+
if (parent === dir)
|
|
40
|
+
break;
|
|
41
|
+
dir = parent;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
return createRequire(import.meta.url).resolve("typescript/bin/tsc");
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const SCENE_DEGRADED = /\b[A-Z][A-Z0-9_]*_DEGRADED\b/g;
|
|
51
|
+
const hasDegradeCode = (text) => /\b[A-Z][A-Z0-9_]*_DEGRADED\b/.test(text);
|
|
52
|
+
export async function runVerify(options) {
|
|
53
|
+
const now = options.now ?? Date.now;
|
|
54
|
+
const started = now();
|
|
55
|
+
const projectDir = resolve(options.projectDir);
|
|
56
|
+
const skip = new Set(options.skip ?? []);
|
|
57
|
+
const run = options.runCommand ?? defaultRunCommand;
|
|
58
|
+
const distDir = resolve(projectDir, options.distDir ?? "dist");
|
|
59
|
+
const findings = [];
|
|
60
|
+
const steps = [];
|
|
61
|
+
let render;
|
|
62
|
+
let capture;
|
|
63
|
+
let server;
|
|
64
|
+
let origin;
|
|
65
|
+
const viewport = { width: options.width ?? 960, height: options.height ?? 540 };
|
|
66
|
+
const step = async (id, body) => {
|
|
67
|
+
if (skip.has(id)) {
|
|
68
|
+
steps.push({ id, status: "skipped", durationMs: 0, detail: "skipped by option" });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const before = findings.length;
|
|
72
|
+
const t0 = now();
|
|
73
|
+
let detail;
|
|
74
|
+
try {
|
|
75
|
+
detail = (await body()) || undefined;
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
findings.push(makeFinding("VERIFY_STEP_CRASHED", `${id}: ${String(error.message ?? error).split("\n")[0]}`));
|
|
79
|
+
}
|
|
80
|
+
const failed = findings.slice(before).some((f) => f.severity === "error");
|
|
81
|
+
steps.push({ id, status: failed ? "fail" : "pass", durationMs: now() - t0, ...(detail ? { detail } : {}) });
|
|
82
|
+
};
|
|
83
|
+
// 1. typecheck ----------------------------------------------------------------------------------------------------
|
|
84
|
+
await step("typecheck", () => {
|
|
85
|
+
if (!existsSync(join(projectDir, "tsconfig.json"))) {
|
|
86
|
+
findings.push(makeFinding("TYPECHECK_UNAVAILABLE", "No tsconfig.json in the project."));
|
|
87
|
+
return "no tsconfig.json";
|
|
88
|
+
}
|
|
89
|
+
const tsc = resolveTsc(projectDir);
|
|
90
|
+
if (!tsc) {
|
|
91
|
+
findings.push(makeFinding("TYPECHECK_UNAVAILABLE", "No TypeScript compiler could be resolved."));
|
|
92
|
+
return "no tsc";
|
|
93
|
+
}
|
|
94
|
+
const result = run(process.execPath, [tsc, "--noEmit", "-p", "tsconfig.json", "--pretty", "false"], projectDir, 600_000);
|
|
95
|
+
const errors = result.output.split("\n").map((line) => /^(.+?)\((\d+),(\d+)\): error (TS\d+): (.*)$/.exec(line)).filter((m) => !!m);
|
|
96
|
+
for (const m of errors.slice(0, 20)) {
|
|
97
|
+
findings.push(makeFinding("TYPECHECK_ERROR", `${m[4]}: ${m[5]}`, { location: { file: m[1].replace(/^\.\//, ""), line: Number(m[2]), column: Number(m[3]) }, evidence: { tsCode: m[4] } }));
|
|
98
|
+
}
|
|
99
|
+
if (errors.length > 20)
|
|
100
|
+
findings.push(makeFinding("TYPECHECK_ERROR", `${errors.length - 20} more TypeScript errors not listed.`, { severity: "info" }));
|
|
101
|
+
if (result.status !== 0 && errors.length === 0)
|
|
102
|
+
findings.push(makeFinding("TYPECHECK_ERROR", `tsc exited ${result.status}: ${tail(result.output, 4)}`));
|
|
103
|
+
return `${errors.length} error(s)`;
|
|
104
|
+
});
|
|
105
|
+
// 2. assets -------------------------------------------------------------------------------------------------------
|
|
106
|
+
await step("assets", () => {
|
|
107
|
+
let detail = "no aura.assets.json";
|
|
108
|
+
if (existsSync(join(projectDir, "aura.assets.json"))) {
|
|
109
|
+
const result = validateAssets({ projectDir, source: true });
|
|
110
|
+
for (const failure of result.failures.slice(0, 15))
|
|
111
|
+
findings.push(makeFinding("ASSET_VALIDATION_FAILED", failure));
|
|
112
|
+
for (const warning of result.warnings.slice(0, 10))
|
|
113
|
+
findings.push(makeFinding("ASSET_VALIDATION_WARNING", warning));
|
|
114
|
+
detail = `${result.failures.length} failure(s), ${result.warnings.length} warning(s)`;
|
|
115
|
+
}
|
|
116
|
+
for (const lint of lintProject(projectDir, { group: "assets" }))
|
|
117
|
+
findings.push(makeFinding(lint.code, lint.message, { location: lint.location }));
|
|
118
|
+
return detail;
|
|
119
|
+
});
|
|
120
|
+
// 3. lint ---------------------------------------------------------------------------------------------------------
|
|
121
|
+
await step("lint", () => {
|
|
122
|
+
const results = lintProject(projectDir, { group: "scene" });
|
|
123
|
+
for (const lint of results)
|
|
124
|
+
findings.push(makeFinding(lint.code, lint.message, { location: lint.location }));
|
|
125
|
+
return `${results.length} finding(s)`;
|
|
126
|
+
});
|
|
127
|
+
// 4. build --------------------------------------------------------------------------------------------------------
|
|
128
|
+
await step("build", () => {
|
|
129
|
+
const pkgPath = join(projectDir, "package.json");
|
|
130
|
+
const pkg = existsSync(pkgPath) ? JSON.parse(readFileSync(pkgPath, "utf8")) : {};
|
|
131
|
+
if (!pkg.scripts?.build) {
|
|
132
|
+
findings.push(makeFinding("BUILD_SCRIPT_MISSING", "package.json has no scripts.build."));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const result = run("npm", ["run", "build"], projectDir, options.buildTimeoutMs ?? 600_000);
|
|
136
|
+
if (result.status !== 0) {
|
|
137
|
+
findings.push(makeFinding("BUILD_FAILED", `npm run build exited ${result.status}.`, { evidence: { outputTail: tail(result.output) } }));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (existsSync(join(projectDir, "aura.assets.json"))) {
|
|
141
|
+
const deploy = checkDeploy({ projectDir, distDir: options.distDir ?? "dist" });
|
|
142
|
+
for (const failure of deploy.failures.slice(0, 10))
|
|
143
|
+
findings.push(makeFinding("DEPLOY_CHECK_FAILED", failure));
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
// 5. serve --------------------------------------------------------------------------------------------------------
|
|
147
|
+
const wantsBrowser = !skip.has("render") || !skip.has("inspect");
|
|
148
|
+
await step("serve", async () => {
|
|
149
|
+
if (!wantsBrowser)
|
|
150
|
+
return "no browser step requested";
|
|
151
|
+
if (!existsSync(join(distDir, "index.html"))) {
|
|
152
|
+
findings.push(makeFinding("SERVE_FAILED", `No index.html in ${basename(distDir)}/ (did the build step run?).`));
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
({ server, origin } = await startStaticServer(distDir));
|
|
157
|
+
return origin;
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
findings.push(makeFinding("SERVE_FAILED", String(error.message ?? error)));
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
// 6. render -------------------------------------------------------------------------------------------------------
|
|
164
|
+
const lockDir = options.browserLock && wantsBrowser ? options.browserLock : undefined;
|
|
165
|
+
if (lockDir) {
|
|
166
|
+
for (;;) {
|
|
167
|
+
try {
|
|
168
|
+
mkdirSync(lockDir);
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
if (error.code !== "EEXIST")
|
|
173
|
+
throw error;
|
|
174
|
+
await new Promise((done) => setTimeout(done, 2_000));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const driver = options.driver ?? createChromeCdpDriver({ ...(options.chromePath ? { chromePath: options.chromePath } : {}), ...(options.softwareGl ? { softwareGl: true } : {}) });
|
|
179
|
+
try {
|
|
180
|
+
await step("render", async () => {
|
|
181
|
+
if (!origin)
|
|
182
|
+
return "no server";
|
|
183
|
+
try {
|
|
184
|
+
capture = await driver.capture(`${origin}${options.route ?? "/"}`, { ...viewport, settleMs: options.settleMs ?? 2_000, motionGapMs: options.motionGapMs ?? 1_000, timeoutMs: options.timeoutMs ?? 30_000, readyTimeoutMs: options.readyTimeoutMs ?? 12_000 });
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
const message = String(error.message ?? error).split("\n")[0];
|
|
188
|
+
findings.push(makeFinding(error instanceof BrowserUnavailableError ? "BROWSER_UNAVAILABLE" : "RENDER_NAVIGATION_FAILED", message));
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (capture.status === null || capture.status >= 400) {
|
|
192
|
+
findings.push(makeFinding("RENDER_NAVIGATION_FAILED", `The page answered ${capture.status ?? "no response"}.`));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (capture.appState.ready === undefined)
|
|
196
|
+
findings.push(makeFinding("RENDER_NEVER_READY", `data-aura3d-ready never appeared within ${(options.readyTimeoutMs ?? 12_000) / 1000}s of page load (tab ${capture.appState.page?.visibility ?? "?"}, ${capture.appState.page?.canvases ?? "?"} canvas, size ${capture.appState.page?.canvasSize ?? "?"}).`));
|
|
197
|
+
const diag = capture.appState.routeReady?.diagnostics;
|
|
198
|
+
const consoleText = capture.consoleMessages.map((m) => m.text).join("\n");
|
|
199
|
+
const allText = [consoleText, ...(diag?.errors ?? []), ...(diag?.warnings ?? [])].join("\n");
|
|
200
|
+
const mountText = [...capture.consoleMessages.map((m) => m.text), ...(diag?.errors ?? [])].find((t) => t.includes("RENDERER_MOUNT_FAILED"));
|
|
201
|
+
if (mountText || capture.appState.ready === "error") {
|
|
202
|
+
findings.push(makeFinding("RENDERER_MOUNT_FAILED", (mountText ?? capture.appState.error ?? "The app reported a boot error (data-aura3d-ready=error).").slice(0, 500)));
|
|
203
|
+
}
|
|
204
|
+
const degrade = [...new Set(allText.match(SCENE_DEGRADED) ?? [])].sort();
|
|
205
|
+
for (const code of degrade) {
|
|
206
|
+
const line = allText.split("\n").find((l) => l.includes(code)) ?? code;
|
|
207
|
+
findings.push(makeFinding(code, line.slice(0, 400), { evidence: { degradeCode: code } }));
|
|
208
|
+
}
|
|
209
|
+
render = { driver: capture.driver, viewport, ...(diag?.backend ? { backend: diag.backend } : {}), ...(diag?.drawCalls !== undefined ? { drawCalls: diag.drawCalls } : {}), degradeCodes: degrade };
|
|
210
|
+
return `${capture.driver}, ready=${capture.appState.ready ?? "never"}`;
|
|
211
|
+
});
|
|
212
|
+
// 7. inspect ----------------------------------------------------------------------------------------------------
|
|
213
|
+
await step("inspect", () => {
|
|
214
|
+
if (!capture)
|
|
215
|
+
return "no capture";
|
|
216
|
+
const diag = capture.appState.routeReady?.diagnostics;
|
|
217
|
+
const mountReported = findings.some((f) => f.code === "RENDERER_MOUNT_FAILED");
|
|
218
|
+
for (const text of diag?.errors ?? []) {
|
|
219
|
+
if (text.includes("RENDERER_MOUNT_FAILED") && mountReported)
|
|
220
|
+
continue;
|
|
221
|
+
findings.push(makeFinding("RUNTIME_DIAGNOSTIC_ERROR", text.slice(0, 500)));
|
|
222
|
+
}
|
|
223
|
+
const seenMessages = new Set();
|
|
224
|
+
for (const d of (diag?.degradations ?? []).slice(0, 20)) {
|
|
225
|
+
if (seenMessages.has(d.message))
|
|
226
|
+
continue;
|
|
227
|
+
seenMessages.add(d.message);
|
|
228
|
+
if (hasDegradeCode(d.message) && !/OPTION_IGNORED/.test(d.message))
|
|
229
|
+
continue;
|
|
230
|
+
const ignored = d.code === "option-ignored" || /OPTION_IGNORED/.test(d.message);
|
|
231
|
+
findings.push(makeFinding(ignored ? "RUNTIME_OPTION_IGNORED" : "RUNTIME_DEGRADATION", d.message.slice(0, 500), { evidence: { degradation: d.code, ...(d.nodeId ? { nodeId: d.nodeId } : {}) } }));
|
|
232
|
+
}
|
|
233
|
+
for (const text of (diag?.warnings ?? []).slice(0, 12)) {
|
|
234
|
+
if (hasDegradeCode(text) || seenMessages.has(text))
|
|
235
|
+
continue;
|
|
236
|
+
seenMessages.add(text);
|
|
237
|
+
const code = /OPTION_IGNORED/.test(text) ? "RUNTIME_OPTION_IGNORED" : /^Scene has no lights/i.test(text) ? "RUNTIME_NO_LIGHTS" : /^Scene has no interactions/i.test(text) ? "RUNTIME_NO_INTERACTIONS" : "RUNTIME_DIAGNOSTIC_WARNING";
|
|
238
|
+
findings.push(makeFinding(code, text.slice(0, 500)));
|
|
239
|
+
}
|
|
240
|
+
const hasHttp = capture.badResponses.length > 0 || capture.failedRequests.length > 0;
|
|
241
|
+
for (const message of capture.consoleMessages) {
|
|
242
|
+
if (message.level !== "error")
|
|
243
|
+
continue;
|
|
244
|
+
if (/RENDERER_MOUNT_FAILED/.test(message.text) && mountReported)
|
|
245
|
+
continue;
|
|
246
|
+
if (/^Failed to load resource/i.test(message.text) && hasHttp)
|
|
247
|
+
continue;
|
|
248
|
+
findings.push(makeFinding("CONSOLE_ERROR", message.text));
|
|
249
|
+
}
|
|
250
|
+
for (const text of capture.pageErrors)
|
|
251
|
+
findings.push(makeFinding("PAGE_EXCEPTION", text));
|
|
252
|
+
for (const response of capture.badResponses)
|
|
253
|
+
if (!/^404 \/(favicon\.ico|apple-touch-icon[^/]*\.png)$/.test(response))
|
|
254
|
+
findings.push(makeFinding("REQUEST_FAILED", `HTTP ${response}`));
|
|
255
|
+
for (const failed of capture.failedRequests.slice(0, 5))
|
|
256
|
+
findings.push(makeFinding("REQUEST_FAILED", `request did not complete: ${failed}`, { severity: "warning" }));
|
|
257
|
+
let frame;
|
|
258
|
+
let motion;
|
|
259
|
+
let savedFrames;
|
|
260
|
+
if (options.framesDir) {
|
|
261
|
+
mkdirSync(resolve(options.framesDir), { recursive: true });
|
|
262
|
+
savedFrames = capture.frames.map((png, index) => `${basename(projectDir)}-frame${index + 1}.png`);
|
|
263
|
+
capture.frames.forEach((png, index) => writeFileSync(join(resolve(options.framesDir), savedFrames[index]), png));
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const first = decodePng(capture.frames[0]);
|
|
267
|
+
frame = analyzeFrame(first);
|
|
268
|
+
const metrics = { p99Luma: frame.p99Luma, meanLuma: frame.meanLuma, distinctColors: frame.distinctColors, texturedBlockFraction: frame.texturedBlockFraction };
|
|
269
|
+
if (frame.black)
|
|
270
|
+
findings.push(makeFinding("FRAME_BLACK", `The frame is black (p99 luma ${frame.p99Luma}).`, { evidence: metrics }));
|
|
271
|
+
else if (frame.flat)
|
|
272
|
+
findings.push(makeFinding("FRAME_FLAT", `The frame is one flat colour (${frame.distinctColors} distinct colours).`, { evidence: metrics }));
|
|
273
|
+
else if (frame.empty)
|
|
274
|
+
findings.push(makeFinding("FRAME_EMPTY", `Only ${(frame.texturedBlockFraction * 100).toFixed(1)}% of the frame has scene texture.`, { evidence: metrics }));
|
|
275
|
+
else if (frame.dim)
|
|
276
|
+
findings.push(makeFinding("FRAME_DIM", `The frame is dim (p99 luma ${frame.p99Luma}).`, { evidence: metrics }));
|
|
277
|
+
if (capture.frames[1] && frame.drawn) {
|
|
278
|
+
motion = compareFrames(first, decodePng(capture.frames[1]));
|
|
279
|
+
if (!motion.moved)
|
|
280
|
+
findings.push(makeFinding("MOTION_NONE", `Two frames ${options.motionGapMs ?? 1000} ms apart are identical (${(motion.changedPixelFraction * 100).toFixed(3)}% of pixels changed).`, { evidence: { ...motion } }));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
findings.push(makeFinding("VERIFY_STEP_CRASHED", `frame analysis: ${String(error.message ?? error)}`));
|
|
285
|
+
}
|
|
286
|
+
if (render)
|
|
287
|
+
render = { ...render, ...(frame ? { frame } : {}), ...(motion ? { motion } : {}), ...(savedFrames ? { frames: savedFrames } : {}) };
|
|
288
|
+
return frame ? (frame.drawn ? "frame drawn" : frame.reasons.join("; ")) : "no frame";
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
finally {
|
|
292
|
+
await driver.close().catch(() => undefined);
|
|
293
|
+
if (lockDir) {
|
|
294
|
+
try {
|
|
295
|
+
rmdirSync(lockDir);
|
|
296
|
+
}
|
|
297
|
+
catch { /* already released */ }
|
|
298
|
+
}
|
|
299
|
+
if (server)
|
|
300
|
+
await new Promise((done) => server.close(() => done()));
|
|
301
|
+
}
|
|
302
|
+
const counts = { error: 0, warning: 0, info: 0 };
|
|
303
|
+
for (const f of findings)
|
|
304
|
+
counts[f.severity]++;
|
|
305
|
+
return {
|
|
306
|
+
schema: VERIFY_SCHEMA,
|
|
307
|
+
ok: counts.error === 0,
|
|
308
|
+
project: basename(projectDir),
|
|
309
|
+
startedAt: new Date(started).toISOString(),
|
|
310
|
+
durationMs: now() - started,
|
|
311
|
+
steps,
|
|
312
|
+
findings,
|
|
313
|
+
counts,
|
|
314
|
+
...(render ? { render } : {})
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/verify/run.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aura3d/cli",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"aura3d": "dist/cli.js",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"main": "./dist/index.js",
|
|
28
28
|
"types": "./dist/index.d.ts",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@aura3d/asset-index": "5.0
|
|
31
|
-
"@aura3d/assets": "5.0
|
|
32
|
-
"@aura3d/audio": "5.0
|
|
33
|
-
"@aura3d/rendering": "5.0
|
|
34
|
-
"create-aura3d": "5.0
|
|
30
|
+
"@aura3d/asset-index": "5.1.0",
|
|
31
|
+
"@aura3d/assets": "5.1.0",
|
|
32
|
+
"@aura3d/audio": "5.1.0",
|
|
33
|
+
"@aura3d/rendering": "5.1.0",
|
|
34
|
+
"create-aura3d": "5.1.0",
|
|
35
35
|
"typescript": "^5.8.3"
|
|
36
36
|
},
|
|
37
37
|
"description": "Bring real GLB/glTF assets into Aura3D browser apps with typed references, provenance, catalog search, validation, screenshots, and deploy checks.",
|
|
@@ -58,9 +58,27 @@ const stage = scene({ background: "#101418" }).add(primitives.box({ name: "crate
|
|
|
58
58
|
| `scene().physics(next: AuraPhysicsWorldController)` | `AuraSceneBuilder` | |
|
|
59
59
|
| `scene().diagnostics(enabled?: boolean)` | `AuraSceneBuilder` | |
|
|
60
60
|
|
|
61
|
+
## `camera`
|
|
62
|
+
|
|
63
|
+
`camera.frame(subject | subjects | bounds, { fill, angle, azimuth, elevation, padding, fov, aspect })` returns an orbit camera spec placed so the subject fills `fill` (default 0.6) of the limiting frame axis; `camera.frameScene(scene)` frames a whole scene (ground planes ignored); `camera.framePose(...)` returns the pose for `app.camera.setPose` on resize; `camera.worldBounds(subject)` returns the `{ min, max }` box it frames. Solved for `aspect` (default 16/9).
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
void camera.frame(primitives.box({ name: "subject" }), { fill: 0.6 });
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
| Call | Returns | Options |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| `camera.perspective(options?: Omit<AuraCameraSpec, "mode">)` | `AuraCameraSpec` | options: position?: AuraVec3 \| undefined; target?: AuraVec3 \| undefined; up?: AuraVec3 \| undefined; roll?: number \| undefined; offset?: AuraVec3 \| undefined; targetOffset?: AuraVec3 \| undefined; offsetMode?: "scene" \| "target-yaw" \| …; fov?: number \| undefined; focalLength?: number \| undefined; filmGauge?: number \| undefined; filmOffset?: number \| undefined; viewOffset?: { readonly fullWidth: num…; depth?: { readonly mode?: "standa…; near?: number \| undefined; far?: number \| undefined; layers?: number \| undefined; distance… |
|
|
72
|
+
| `camera.orbit(options?: Omit<AuraCameraSpec, "mode">)` | `AuraCameraSpec` | same as `camera.perspective` |
|
|
73
|
+
| `camera.frame(subject: AuraFrameSubject \| AuraFrameBounds \| readonly AuraFrameSubject[], options?: AuraCameraFrameOptions)` | `AuraCameraSpec` | options: fill?: number \| undefined; angle?: AuraFrameAngle \| undefined; azimuth?: number \| undefined; elevation?: number \| undefined; padding?: number \| undefined; fov?: number \| undefined; aspect?: number \| undefined; minDistance?: number \| undefined; exclude?: ((node: AuraSceneNode) =>… |
|
|
74
|
+
| `camera.frameScene(subject: AuraFrameSubject \| readonly AuraFrameSubject[], options?: AuraCameraFrameOptions)` | `AuraCameraSpec` | same as `camera.frame` |
|
|
75
|
+
| `camera.worldBounds(subject: AuraFrameSubject \| readonly AuraFrameSubject[], options?: AuraCameraFrameOptions)` | `AuraFrameBounds` | same as `camera.frame` |
|
|
76
|
+
| `camera.framePose(subject: AuraFrameSubject \| AuraFrameBounds \| readonly AuraFrameSubject[], options?: AuraCameraFrameOptions)` | `AuraFramePose` | same as `camera.frame` |
|
|
77
|
+
| `camera.frameAsset(asset: AuraAssetRef<"model">, options?: AuraCameraFrameAssetOptions)` | `AuraCameraSpec` | asset: type: "model"; format: string; formatMetadata?: FormatMetadata \| undefined; url: string; hash?: string \| undefined; sha256?: string \| undefined; integrity?: AssetIntegrity \| undefined; request?: AssetRequestOptions \| und…; bounds?: AuraVec3 \| undefined; sizeBytes?: number \| undefined; optional?: boolean \| undefined; metadata?: AuraAssetMetadata \| undef…; variants?: AuraAssetVariants \| undef…; requiredDecoders?: readonly AuraAssetRequire…; lods?: readonly AuraAssetLodLeve…; colliderUrl?: string \| undefined; budget?… |
|
|
78
|
+
|
|
61
79
|
## `looks`
|
|
62
80
|
|
|
63
|
-
Genre look presets: environment, key light, fog and grade in one unit. Spread `looks.appOptions(id)` into `createAuraApp` options.
|
|
81
|
+
Genre look presets: environment, key light, fog and grade in one unit. Spread `looks.appOptions(id)` into `createAuraApp` options. HDRI-backed presets load `/hdri/<file>.hdr` from `public/hdri/`; a missing file degrades to a procedural probe, logs one `LOOK_HDRI_MISSING` console error and lists it in `app.diagnostics().warnings`.
|
|
64
82
|
|
|
65
83
|
```ts
|
|
66
84
|
void looks.preset("product-studio");
|
|
@@ -77,7 +95,7 @@ void looks.preset("product-studio");
|
|
|
77
95
|
|
|
78
96
|
## `material`
|
|
79
97
|
|
|
80
|
-
Colours are CSS strings. Metals need an environment.
|
|
98
|
+
Colours are CSS strings (`#rgb`, `#rrggbbaa`, `rgb()`, `hsl()`, `oklch()`, names); an invalid value throws `COLOR_INVALID` naming the option. Metals need an environment.
|
|
81
99
|
|
|
82
100
|
```ts
|
|
83
101
|
void material.pbr({ color: "#c8ccd4", metallic: 0.9, roughness: 0.38 });
|
|
@@ -87,6 +105,9 @@ void material.pbr({ color: "#c8ccd4", metallic: 0.9, roughness: 0.38 });
|
|
|
87
105
|
|---|---|---|
|
|
88
106
|
| `material.custom(spec: AuraCustomMaterialSpec)` | `AuraMaterialSpec` | spec: glsl: { readonly vertex?: strin…; wgsl?: { readonly vertex?: strin…; uniforms?: Readonly<Record<string, A…; uniformAliases?: Readonly<Record<string, s…; defines?: Readonly<Record<string, s…; transparent?: boolean \| undefined; depthWrite?: boolean \| undefined; depthTest?: boolean \| undefined; side?: "front" \| "back" \| "doubl…; blending?: "custom" \| "normal" \| "ad…; fog?: boolean \| undefined; patch?: Readonly<Record<string, s…; receiveShadow?: boolean \| undefined; castShadow?: boolean \| undefined |
|
|
89
107
|
| `material.toon(options?: AuraToonMaterialOptions)` | `AuraMaterialSpec` | options: color?: string \| undefined; steps?: number \| undefined; ramp?: AuraAssetRef<"texture", s…; shadowColor?: string \| undefined; rim?: AuraMaterialRimSpec \| und… |
|
|
108
|
+
| `material.strata(options?: AuraStrataMaterialOptions)` | `AuraMaterialSpec` | options: bands?: number \| undefined; colors?: readonly string[] \| undef…; heightRange?: readonly [number, number]…; noise?: number \| undefined; noiseScale?: number \| undefined; seam?: number \| undefined; variation?: number \| undefined; slope?: AuraStrataSlopeOptions \| …; roughness?: number \| undefined; seed?: number \| undefined; side?: "front" \| "back" \| "doubl… |
|
|
109
|
+
| `material.caustics(options?: AuraCausticsMaterialOptions)` | `AuraMaterialSpec` | options: color?: string \| undefined; causticColor?: string \| undefined; strength?: number \| undefined; scale?: number \| undefined; speed?: number \| undefined; surfaceY?: number \| undefined; depthFade?: number \| undefined; roughness?: number \| undefined; side?: "front" \| "back" \| "doubl… |
|
|
110
|
+
| `material.lightBeam(options?: AuraLightBeamMaterialOptions)` | `AuraMaterialSpec` | options: color?: string \| undefined; intensity?: number \| undefined; length?: number \| undefined; falloff?: number \| undefined; edgeSoftness?: number \| undefined; noise?: number \| undefined; noiseScale?: number \| undefined; noiseSpeed?: number \| undefined |
|
|
90
111
|
| `material.matcap(options: AuraMatcapMaterialOptions)` | `AuraMaterialSpec` | options: map: AuraAssetRef<"texture"> \|…; color?: string \| undefined; opacity?: number \| undefined; transparent?: boolean \| undefined; side?: "front" \| "back" \| "doubl… |
|
|
91
112
|
| `material.depth(options?: AuraDepthPreviewMaterialOptions)` | `AuraMaterialSpec` | options: near?: number \| undefined; far?: number \| undefined; side?: "front" \| "back" \| "doubl… |
|
|
92
113
|
| `material.normal(options?: AuraNormalMaterialOptions)` | `AuraMaterialSpec` | options: side?: "front" \| "back" \| "doubl… |
|
|
@@ -181,7 +202,7 @@ void environments.neutral({ intensity: 0.8, background: false });
|
|
|
181
202
|
| `environments.metalStudio(options?: AuraEnvironmentOptionsV2)` | `AuraNodeBuilder<AuraEnvironmentNode>` | same as `environments.preset` |
|
|
182
203
|
| `environments.glassStudio(options?: AuraEnvironmentOptionsV2)` | `AuraNodeBuilder<AuraEnvironmentNode>` | same as `environments.preset` |
|
|
183
204
|
| `environments.presets()` | `readonly AuraEnvironmentMapPreset[]` | |
|
|
184
|
-
| `environments.forMaterial(materialClass: "
|
|
205
|
+
| `environments.forMaterial(materialClass: "product" \| "metal" \| "glass" \| "studio")` | `AuraNodeBuilder<AuraEnvironmentNode>` | |
|
|
185
206
|
|
|
186
207
|
## `sky`
|
|
187
208
|
|
|
@@ -235,6 +256,8 @@ void effects.bloom({ intensity: 0.7, threshold: 0.75, radius: 0.55 });
|
|
|
235
256
|
|
|
236
257
|
| Call | Returns | Options |
|
|
237
258
|
|---|---|---|
|
|
259
|
+
| `effects.godRays(options?: AuraGodRaysOptions)` | `AuraNodeBuilder<AuraEffectNode>` | options: name?: string \| undefined; source?: AuraVec3 \| "sun" \| AuraGo…; intensity?: number \| undefined; decay?: number \| undefined; samples?: 64 \| 32 \| 48 \| undefined; color?: string \| undefined; density?: number \| undefined; medium?: number \| undefined |
|
|
260
|
+
| `effects.volumetricBeam(options?: AuraVolumetricBeamOptions)` | `AuraNodeBuilder<AuraPrimitiveNode>` | options: name?: string \| undefined; position?: AuraVec3 \| undefined; direction?: AuraVec3 \| undefined; length?: number \| undefined; endRadius?: number \| undefined; color?: string \| undefined; intensity?: number \| undefined; falloff?: number \| undefined; edgeSoftness?: number \| undefined; noise?: number \| undefined; noiseScale?: number \| undefined; noiseSpeed?: number \| undefined; radialSegments?: number \| undefined |
|
|
238
261
|
| `effects.contactShadows(options?: AuraContactShadowOptions)` | `AuraNodeBuilder<AuraEffectNode>` | options: length?: number \| undefined; thickness?: number \| undefined; steps?: 8 \| 12 \| 16 \| undefined; intensity?: number \| undefined; lights?: "sun" \| "shadowed" \| unde… |
|
|
239
262
|
| `effects.toon(options?: AuraToonOptions)` | `AuraCustomPostPass` | options: name?: string \| undefined; bands?: number \| undefined; bandMix?: number \| undefined; outline?: number \| undefined; ink?: readonly [number, number,…; edgeStart?: number \| undefined; edgeEnd?: number \| undefined; size?: readonly [number, number]…; order?: AuraPostPassOrder \| undef…; inkSource?: AuraToonInkSource \| undef…; fadeDistance?: number \| undefined; inkColor?: string \| undefined |
|
|
240
263
|
| `effects.pixelation(options?: AuraPixelationOptions)` | `AuraNodeBuilder<AuraEffectNode>` | options: size?: number \| undefined; name?: string \| undefined |
|
|
@@ -255,7 +278,7 @@ void effects.bloom({ intensity: 0.7, threshold: 0.75, radius: 0.55 });
|
|
|
255
278
|
| `effects.vignette(options?: PostV3EffectOptions)` | `AuraNodeBuilder<AuraEffectNode>` | |
|
|
256
279
|
| `effects.filmGrain(options?: PostV3EffectOptions)` | `AuraNodeBuilder<AuraEffectNode>` | |
|
|
257
280
|
| `effects.chromaticAberration(options?: PostV3EffectOptions)` | `AuraNodeBuilder<AuraEffectNode>` | |
|
|
258
|
-
| `effects.shaderPass(options: AuraShaderPassOptions)` | `AuraCustomPostPass` | options: name?: string \| undefined; glsl?: string \| undefined; wgsl?: string \| undefined; fragment?: { readonly glsl?: string;…; uniforms?: Readonly<Record<string, n…; inputs?: readonly ("
|
|
281
|
+
| `effects.shaderPass(options: AuraShaderPassOptions)` | `AuraCustomPostPass` | options: name?: string \| undefined; glsl?: string \| undefined; wgsl?: string \| undefined; fragment?: { readonly glsl?: string;…; uniforms?: Readonly<Record<string, n…; inputs?: readonly ("depth" \| "norm…; insertAt?: PostInsertAt \| undefined; order?: AuraPostPassOrder \| undef…; enabled?: boolean \| undefined |
|
|
259
282
|
| `effects.fog(options?: FogNodeOptions)` | `AuraNodeBuilder<AuraEffectNode>` | |
|
|
260
283
|
| `effects.cinematicBloom(options?: Omit<AuraEffectNode, "kind" \| "effect">)` | `AuraNodeBuilder<AuraEffectNode>` | |
|
|
261
284
|
| `effects.volumetricFog(options?: AuraVolumetricFogOptions)` | `AuraNodeBuilder<AuraEffectNode>` | |
|
|
@@ -7,6 +7,7 @@ Page needs a `<div id="app">` (or a `<canvas id="app">`); `createAuraApp("#app",
|
|
|
7
7
|
Rules that every recipe follows:
|
|
8
8
|
|
|
9
9
|
- Orbit control: `interactions.orbit({ target: "<node name>" })`. It takes a node name, nothing else.
|
|
10
|
+
- Frame the subject with `camera.frame(subject, { fill: 0.6 })` (a node or array of nodes, not a hand-placed `camera.perspective`; pass `aspect` if the canvas is not 16:9).
|
|
10
11
|
- Metals need something to reflect: add `environments.neutral(...)` (or a look preset) or a metallic material renders dark.
|
|
11
12
|
- Instancing: `instances.cone/cylinder/sphere/box({ transforms, colors })` draws one draw call per shape; shapes are unit-sized, so `scale` sets the size.
|
|
12
13
|
- A deformed surface needs vertices: build a grid with `geometry.define` and mount it with `geometry.custom(...)`.
|
|
@@ -151,7 +152,7 @@ const water = material.custom({
|
|
|
151
152
|
vertex: /* glsl */ `
|
|
152
153
|
out vec3 vPos;
|
|
153
154
|
void main() {
|
|
154
|
-
vec3 p = position; // prelude names: position, normal, uv, modelViewProjectionMatrix, modelMatrix, cameraPosition, uTime
|
|
155
|
+
vec3 p = position; // prelude names: position, normal, uv, modelViewProjectionMatrix, modelMatrix, cameraPosition, uTime (static scenes do not advance uTime; see below)
|
|
155
156
|
p.y += 0.25 * sin(p.x * 0.8 + waveClock) + 0.15 * sin(p.z * 1.3 - waveClock * 1.4);
|
|
156
157
|
vPos = p;
|
|
157
158
|
gl_Position = modelViewProjectionMatrix * vec4(p, 1.0);
|
|
@@ -176,7 +177,7 @@ app.onFrame(() => app.nodes.require("water").setUniform?.("waveClock", (performa
|
|
|
176
177
|
await app.ready();
|
|
177
178
|
```
|
|
178
179
|
|
|
179
|
-
`material.custom` auto-declares the uniforms you list. Prelude names: `position`, `normal` and `uv` (vertex attributes), `modelViewProjectionMatrix`, `modelMatrix`, `cameraPosition` (a uniform in both stages) and `uTime
|
|
180
|
+
`material.custom` auto-declares the uniforms you list. Prelude names: `position`, `normal` and `uv` (vertex attributes), `modelViewProjectionMatrix`, `modelMatrix`, `cameraPosition` (a uniform in both stages) and `uTime`. `uTime` is wall-clock seconds, but the engine redraws every frame only when the scene declares motion (a `.runtime({ id, mutable: true })` node, an `app.onFrame` callback, an animated model, particles or rain, an auto-rotating orbit camera, a looping timeline). A static scene whose only motion is `uTime` renders one frame and the shader looks frozen (measured on a real GPU). This recipe uses its own `waveClock` uniform written in `onFrame`, which also keeps the loop running; `uTime` works too when the node is `.runtime({ id, mutable: true })`. The fragment stage writes `outColor` (GLSL 3 `in`/`out`). There is no `eyePos`: it fails to compile with `undeclared identifier`. If the shader fails to compile the engine logs `CUSTOM_SHADER_COMPILE_FAILED` with the GLSL log (see [`troubleshooting.md`](troubleshooting.md)).
|
|
180
181
|
|
|
181
182
|
## 6. A ball dribbled by hand (hand and floor contact, handoffs, proof)
|
|
182
183
|
|
|
@@ -496,7 +497,7 @@ await app.ready();
|
|
|
496
497
|
import { camera, createAuraApp, effects, geometry, lights, material, primitives, scene } from "@aura3d/engine";
|
|
497
498
|
|
|
498
499
|
// Water with a custom GLSL material: vertex waves, analytic normal, fresnel mix between deep colour and sky, sun glint.
|
|
499
|
-
// Uniforms listed in `uniforms` are auto-declared in GLSL. Prelude names: position/normal/uv (vertex attributes), modelViewProjectionMatrix, modelMatrix, cameraPosition, uTime.
|
|
500
|
+
// Uniforms listed in `uniforms` are auto-declared in GLSL. Prelude names: position/normal/uv (vertex attributes), modelViewProjectionMatrix, modelMatrix, cameraPosition, uTime (uTime advances only while the scene redraws every frame; this recipe drives its own `waveClock` from onFrame).
|
|
500
501
|
const N = 200, SIZE = 80;
|
|
501
502
|
const positions = new Float32Array((N + 1) ** 2 * 3);
|
|
502
503
|
const normals = new Float32Array(positions.length);
|
|
@@ -10,7 +10,7 @@ Read this first. Aura3D is a standalone engine with its own renderer: you descri
|
|
|
10
10
|
| `Group` / `Object3D` hierarchy, bones as groups | `group("arm", [children], { position }).runtime({ id, mutable: true })` | Children use local transforms; a group's origin is its pivot. |
|
|
11
11
|
| `BufferGeometry` + `setAttribute` + `setIndex` | `geometry.custom(geometry.define({ positions, normals, uvs, colors, indices, bounds }), { name, material })` | Typed arrays in; `bounds` required; `colors` are per-vertex RGBA. `geometry.dynamic` for geometry you rewrite. |
|
|
12
12
|
| `MeshStandardMaterial` | `material.pbr({ color, roughness, metallic, emissive, opacity })` | Also `physical` (clearcoat), `emissive`, `toon`, `matcap`. Colour is a CSS string. |
|
|
13
|
-
| `ShaderMaterial` | `material.custom({ glsl: { vertex, fragment }, uniforms: { t: { type: "f32", value: 0 } } })`; `handle.setUniform("t", v)` | GLSL 3.00 (`in`/`out`, write `outColor`). Prelude names: `position`, `normal`, `uv`, `modelViewProjectionMatrix`, `modelMatrix`, `cameraPosition`, `uTime`. Node/TSL: `material.node`. |
|
|
13
|
+
| `ShaderMaterial` | `material.custom({ glsl: { vertex, fragment }, uniforms: { t: { type: "f32", value: 0 } } })`; `handle.setUniform("t", v)` | GLSL 3.00 (`in`/`out`, write `outColor`). Prelude names: `position`, `normal`, `uv`, `modelViewProjectionMatrix`, `modelMatrix`, `cameraPosition`, `uTime` (wall-clock seconds; advances only while the app redraws every frame: give the node `.runtime({ id, mutable: true })` or register `app.onFrame(...)`, else a static scene draws once and `uTime` looks frozen). Node/TSL: `material.node`. |
|
|
14
14
|
| `DirectionalLight` + `castShadow` | `lights.directional({ position, target, intensity, shadow: true })` | `shadow: true` on the light; meshes take `castShadow` / `receiveShadow`. Also `point`, `spot`, `hemisphere`, `ambient`, `rect`. |
|
|
15
15
|
| `scene.environment = pmrem` | `environments.neutral({ intensity, background: false })` (also `studio`, `outdoor`, `hdri`, `preset`) | Metals render dark without an environment. `looks.preset(id)` bundles environment, key light, fog and grade. |
|
|
16
16
|
| `scene.background = sky shader`, `Sky` | `sky.preetham({ sun: { elevationDeg, azimuthDeg } })`, `sky.gradient`, `sky.dayNight` | Move the sun live with `app.atmosphere.setSky({ sun })`. |
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# Aura3D agent instructions
|
|
2
2
|
|
|
3
|
-
Read ./llms.txt first. Read the `aura3d-art-direction` skill. Every scene gets a look. Run the look-dev loop (`aura3d look capture` → judge → iterate) before calling a scene done.
|
|
3
|
+
Read ./llms.txt first: its first screen holds typechecked, GPU-rendered patterns (scene skeleton, instancing, custom shader, procedural geometry, rigged models, game loop, physics, particles) to copy and adapt; do not open `node_modules` or `dist` for APIs. Read the `aura3d-art-direction` skill. Every scene gets a look. Run the look-dev loop (`aura3d look capture` → judge → iterate) before calling a scene done.
|