drive-between-the-lines/vite.config.ts
dejvino 405f1b0dfe Make the running game inspectable, and stop the beacons swallowing the view
The pane this build runs in does not composite, so requestAnimationFrame never
fires, the loop stalls, and nothing can be screenshotted from outside. Adds a
`?debug=1` handle that steps the simulation by hand and renders on demand, plus
a dev-only endpoint that takes a POSTed frame and writes it to shots/. Moving
the image as bytes rather than a pasted data URL matters: a truncated base64
string decodes to nothing.

Looking at the result immediately found a real problem. Base beacons were wide
translucent cylinders — legible from a distance, a solid green wall from inside,
and the car parks in the middle of one. Now a slim pillar plus a ring on the
ground that marks where to stop. Also raised the sky and fog brightness, which
was dark enough to read as night.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 15:38:27 +02:00

56 lines
1.9 KiB
TypeScript

import { mkdirSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import type { Plugin } from 'vite';
import { defineConfig } from 'vite';
/**
* Dev-only: lets the running game POST a rendered frame to disk.
*
* The game cannot always be looked at — a backgrounded or non-compositing tab
* never fires requestAnimationFrame, so nothing draws and nothing can be
* screenshotted from outside. With this, plus the `?debug=1` handle in
* src/debug.ts, a script can step the simulation, render a frame, and drop the
* image somewhere it can actually be opened.
*
* Never registered in a production build.
*/
function screenshotEndpoint(): Plugin {
const directory = resolve(process.cwd(), 'shots');
return {
name: 'dbtl-screenshot',
apply: 'serve',
configureServer(server) {
server.middlewares.use('/__shot', (req, res) => {
if (req.method !== 'POST') {
res.statusCode = 405;
res.end('POST only');
return;
}
const name = (new URL(req.url ?? '', 'http://x').searchParams.get('name') ?? 'frame')
// Keep this from writing outside the shots directory.
.replace(/[^a-z0-9_-]/gi, '');
const chunks: Buffer[] = [];
req.on('data', (chunk: Buffer) => chunks.push(chunk));
req.on('end', () => {
try {
mkdirSync(directory, { recursive: true });
const file = resolve(directory, `${name || 'frame'}.jpg`);
writeFileSync(file, Buffer.concat(chunks));
res.setHeader('content-type', 'application/json');
res.end(JSON.stringify({ ok: true, file, bytes: Buffer.concat(chunks).length }));
} catch (err) {
res.statusCode = 500;
res.end(String(err));
}
});
});
},
};
}
export default defineConfig({
plugins: [screenshotEndpoint()],
});