mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
- qa-anime-sky keeps only the Milky Way case; the satellites and keyless cases checked an anime shader this branch no longer changes. - Drop qa-sky-sun-moon.mjs: the viewer-options unit test covers it. - VisualEffects sets the sky's visibility directly: the viewer always carries a StarrySky and never outlives the effects. - Drop the unused star intensity knob, the malformed-row tolerance for our own pack, the test-only Transforms parameter and a private-name test. - DATA_SOURCES points to sky/README.md instead of repeating it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
122 lines
4.0 KiB
JavaScript
122 lines
4.0 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* qa-anime-sky — the anime style must leave the sky without bands.
|
|
*
|
|
* Anime's luminance bands turn the faint Milky Way into blotches, so
|
|
* src/ui/visualEffects.js fades the glow out with the style. Headless against
|
|
* a Vite dev server, the real anime style looks away from the Earth at the
|
|
* Galactic Centre: at most 0.5 % of the sky (the stars) may reach the first
|
|
* band.
|
|
*
|
|
* Usage: node scripts/qa-anime-sky.mjs [--url http://localhost:4333/]
|
|
* Exit: 0 pass, 1 fail, 2 the anime style was not reached.
|
|
*/
|
|
import puppeteer from 'puppeteer';
|
|
|
|
const i = process.argv.indexOf('--url');
|
|
const URL_ =
|
|
i > 0 && process.argv[i + 1] ? process.argv[i + 1] : 'http://localhost:4333/';
|
|
|
|
const browser = await puppeteer.launch({
|
|
headless: 'new',
|
|
args: ['--no-sandbox', '--ignore-gpu-blocklist'],
|
|
});
|
|
try {
|
|
const page = await browser.newPage();
|
|
page.on('pageerror', (e) => console.log('PAGEERR', String(e).slice(0, 300)));
|
|
await page.setViewport({ width: 1000, height: 700 });
|
|
await page.evaluateOnNewDocument(() =>
|
|
localStorage.setItem('gev:first-run-mission:v1', 'suppressed'),
|
|
);
|
|
await page.goto(URL_, { waitUntil: 'domcontentloaded' });
|
|
await page.waitForFunction(() => window.__godsEyeView?.viewer?.scene, {
|
|
timeout: 120000,
|
|
});
|
|
await new Promise((r) => setTimeout(r, 12000));
|
|
const r = await page.evaluate(async () => {
|
|
const entry = performance
|
|
.getEntriesByType('resource')
|
|
.map((e) => e.name)
|
|
.find((n) => /\.vite\/deps\/cesium\.js/.test(n));
|
|
if (!entry)
|
|
throw new Error(
|
|
'run against the Vite dev server (needs .vite/deps/cesium.js)',
|
|
);
|
|
const C = await import(entry),
|
|
g = window.__godsEyeView,
|
|
v = g.viewer,
|
|
s = v.scene;
|
|
g.styleManager.setStyle('anime', { userInitiated: true });
|
|
const t = v.clock.currentTime;
|
|
await C.Transforms.preloadIcrfFixed(
|
|
new C.TimeInterval({
|
|
start: C.JulianDate.addDays(t, -1, new C.JulianDate()),
|
|
stop: C.JulianDate.addDays(t, 1, new C.JulianDate()),
|
|
}),
|
|
);
|
|
const m = C.Transforms.computeIcrfToFixedMatrix(t);
|
|
const ra = C.Math.toRadians(266.4),
|
|
dec = C.Math.toRadians(-29);
|
|
const look = C.Matrix3.multiplyByVector(
|
|
m,
|
|
new C.Cartesian3(
|
|
Math.cos(dec) * Math.cos(ra),
|
|
Math.cos(dec) * Math.sin(ra),
|
|
Math.sin(dec),
|
|
),
|
|
new C.Cartesian3(),
|
|
);
|
|
const north = C.Matrix3.multiplyByVector(
|
|
m,
|
|
C.Cartesian3.UNIT_Z,
|
|
new C.Cartesian3(),
|
|
);
|
|
const right = C.Cartesian3.normalize(
|
|
C.Cartesian3.cross(look, north, new C.Cartesian3()),
|
|
new C.Cartesian3(),
|
|
);
|
|
s.camera.cancelFlight();
|
|
s.camera.setView({
|
|
destination: C.Cartesian3.multiplyByScalar(look, 3e7, new C.Cartesian3()),
|
|
orientation: {
|
|
direction: look,
|
|
up: C.Cartesian3.cross(right, look, new C.Cartesian3()),
|
|
},
|
|
});
|
|
await new Promise((res) => setTimeout(res, 2500));
|
|
s.requestRender();
|
|
s.render();
|
|
const gl = s.context._gl,
|
|
w = gl.drawingBufferWidth,
|
|
h = gl.drawingBufferHeight,
|
|
px = new Uint8Array(w * h * 4);
|
|
gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, px);
|
|
let banded = 0;
|
|
for (let i = 0; i < px.length; i += 4)
|
|
if (0.299 * px[i] + 0.587 * px[i + 1] + 0.114 * px[i + 2] >= 51) banded++;
|
|
let animeOn = false;
|
|
for (let i = 0; i < s.postProcessStages.length; i++) {
|
|
const stage = s.postProcessStages.get(i);
|
|
if (stage.name === 'godsEyeView_anime')
|
|
animeOn = stage.enabled && stage.uniforms.intensity > 0.99;
|
|
}
|
|
return {
|
|
total: px.length / 4,
|
|
banded,
|
|
visibility: s.skyBox.milkyWayVisibility,
|
|
animeOn,
|
|
};
|
|
});
|
|
const tag = !r.animeOn
|
|
? 'UNREACHED'
|
|
: r.banded <= 0.005 * r.total
|
|
? 'PASS'
|
|
: 'FAIL';
|
|
console.log(
|
|
`${tag}: ${r.banded} of ${r.total} sky pixels at or above the first cel band (luma >= 0.2)\n ${JSON.stringify(r)}`,
|
|
);
|
|
process.exitCode = tag === 'PASS' ? 0 : tag === 'FAIL' ? 1 : 2;
|
|
} finally {
|
|
await browser.close();
|
|
}
|