mirror of
https://github.com/samvallad33/vestige.git
synced 2026-07-24 23:41:01 +02:00
Turn all 17 sparse organs from text-on-black voids into full-bleed, moving, bioluminescent WebGPU fields. Each cell maps to a real backend fact; verified live on the real brain with a decoded fill% + motion + zero-error probe. Foundation: one reusable LivingFieldPass (src/lib/observatory/field/) does splat -> separable-blur (render passes) -> membrane base coat -> HDR cells with orbital drift and a CPU pick-mirror. Each organ writes a ~20-line data->cells mapper (cell-layout.ts: layoutGalaxy / layoutRings / FIELD_HUE). Organs brought alive (fill% before -> after, all zero WebGPU errors): stats 0.8->80.9, observatory 10.8->81.4, graph 12.3->82.4, memories ->78.4, blackbox 18.2->83.3, contradictions 1.6->69.6, dreams 0.3->64.5, settings 2.7->76.4, reasoning 2.7->39.2, patterns 7.1->45.6, activation 10->64.9, feed ->89, explore ->83.3, intentions ->66.6, importance ->73.7, memory-prs ->74.4, schedule ->37.1. Backend surfaces: add api.memoryChangelog() + ChangelogResponse; surface suppress/unsuppress on the memories field (shift/alt-click -> scar). Tests: palace-launch-gate now asserts fillPct>30 + isAnimating (not just non-black), with a longer settle for reasoning's deep_reference and a raised timeout for the curated tour. all-routes-smoke treats settings as the WebGPU field it now is. Gates green: check 0/0, build ok, palace-launch-gate 22/22 + tour, all-routes-smoke 20/20. Protected work untouched: MemoryCinema, graph/cinema, observatory scene shaders, node-renderer, palace-map. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
65 lines
3 KiB
TypeScript
65 lines
3 KiB
TypeScript
// ─────────────────────────────────────────────────────────────────────────────
|
|
// TIMELINE — motion + moving-target picking.
|
|
//
|
|
// Two things the audit flagged that need a test:
|
|
// 1. the growth-rings field ACTUALLY MOVES (orbital rotation), not a frozen
|
|
// frame — this is the "make it alive" requirement.
|
|
// 2. picking a cell works EVEN THOUGH the cells orbit: the CPU pickAt mirrors
|
|
// the WGSL orbit() so the clickable hitbox tracks the animated position.
|
|
// Regression guard for the "clicks land where cells used to be" bug.
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
import { test, expect } from '@playwright/test';
|
|
import { BASE, captureErrors, expectNoErrors, gotoRoute, sampleCanvas, isAnimating } from './helpers/dashboard';
|
|
|
|
test('timeline renders a living, MOVING growth-rings field', async ({ page }) => {
|
|
const errors = captureErrors(page);
|
|
await gotoRoute(page, '/timeline');
|
|
await page.waitForTimeout(3500);
|
|
|
|
const sample = await sampleCanvas(page);
|
|
expect(sample.rendered, `timeline field should render (avgLum=${sample.avgLum})`).toBe(true);
|
|
|
|
// The rings orbit continuously. Under full-suite GPU/timing load two adjacent
|
|
// compositor frames can occasionally hash-match, so retry a few windows —
|
|
// a genuinely frozen field never moves across ANY window, an alive one does.
|
|
let moved = false;
|
|
for (let i = 0; i < 4 && !moved; i++) {
|
|
moved = await isAnimating(page, 700);
|
|
}
|
|
expect(moved, 'timeline growth-rings should be animating (orbital motion)').toBe(true);
|
|
|
|
expectNoErrors(errors);
|
|
});
|
|
|
|
test('clicking the moving timeline field never crashes and picking tracks motion', async ({ page }) => {
|
|
const errors = captureErrors(page);
|
|
const canvas = await gotoRoute(page, '/timeline');
|
|
await page.waitForTimeout(3500);
|
|
|
|
const box = await canvas.boundingBox();
|
|
expect(box).not.toBeNull();
|
|
if (!box) return;
|
|
|
|
// Click a grid of points across the field over time — while it's ROTATING —
|
|
// and assert no click ever throws a WebGPU/page error (the pickAt orbit
|
|
// mirror must handle the animated positions). We can't assert an exact cell
|
|
// id headlessly, but crash-free picking on a MOVING field is the real gate.
|
|
const pts = [
|
|
[0.5, 0.35],
|
|
[0.62, 0.5],
|
|
[0.5, 0.65],
|
|
[0.38, 0.5],
|
|
[0.58, 0.42],
|
|
[0.44, 0.58]
|
|
];
|
|
for (const [fx, fy] of pts) {
|
|
await page.mouse.click(box.x + box.width * fx, box.y + box.height * fy);
|
|
await page.waitForTimeout(350); // let the field rotate between clicks
|
|
}
|
|
|
|
// Field still renders after all the clicks (no state corruption).
|
|
const after = await sampleCanvas(page);
|
|
expect(after.rendered, 'timeline still renders after clicking the moving field').toBe(true);
|
|
|
|
expectNoErrors(errors);
|
|
});
|