Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/thatstupidcomputer / scripts/native-contact-sheets.mjs |
| Date | Not specified in source |
| Repository | Janady13/thatstupidcomputer |
| Revision | 57555cde46910102dd25d6c1c1fb2c359e9655bd |
| Branch | main |
| Path or archive member | scripts/native-contact-sheets.mjs |
| Original SHA-256 | c94190aa07a27c77f4b7500be45250f5390c279d008d3db5fc1493995ab6c879 |
| Git blob SHA | 30a22ecb556787677cc41f6b089c97471345b600 |
| Reading-copy SHA-256 | c94190aa07a27c77f4b7500be45250f5390c279d008d3db5fc1493995ab6c879 |
Recovered source transcript
Download complete source text ↓41 lines · 3.6 KB
/** Exact-byte native/source contact sheets, paginated for complete readable review. */
import { createCanvas, loadImage } from '@napi-rs/canvas';
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { resolve } from 'node:path';
import { createHash } from 'node:crypto';
const root = fileURLToPath(new URL('..', import.meta.url));
const reports = resolve(root, 'native/reports');
const report = JSON.parse(readFileSync(resolve(reports, 'native-canvas.json'), 'utf8'));
if (report.status !== 'PASS') throw new Error('Fresh passing native proof is required before contact-sheet generation');
const digest = bytes => createHash('sha256').update(bytes).digest('hex');
const details = resolve(reports, 'contact-sheets'); mkdirSync(details, { recursive: true });
const output = { status: 'GENERATED_AWAITING_VISUAL_REVIEW', generatedAt: new Date().toISOString(), proofSHA256: digest(readFileSync(resolve(reports, 'native-canvas.json'))), capture: 'Authored peakSeconds from the performance catalog, native left / authoritative source right', files: [] };
async function sheet(file, checks, path, columns = 2, scale = 1, pageLabel = '') {
const cellW = 520 * scale, cellH = 286 * scale, headerH = 65, width = Math.ceil(columns * cellW), height = Math.ceil(headerH + Math.ceil(checks.length / columns) * cellH + 20);
const canvas = createCanvas(width, height), ctx = canvas.getContext('2d');
ctx.fillStyle = '#f4e5c4'; ctx.fillRect(0, 0, width, height);
ctx.fillStyle = '#29261f'; ctx.font = 'bold 21px sans-serif'; ctx.fillText(`${file.slug} · ${pageLabel || 'all actions'}`, 18, 27);
ctx.font = '14px sans-serif'; ctx.fillText(`Native / source · authored peak · SHA-256 ${file.sha256.slice(0, 20)}…`, 18, 49);
for (let index = 0; index < checks.length; index++) {
const check = checks[index], x = (index % columns) * cellW, y = Math.floor(index / columns) * cellH + headerH;
ctx.font = `bold ${Math.max(13, 16 * scale)}px sans-serif`; ctx.fillStyle = '#29261f';
ctx.fillText(`${check.action} · ${check.captureSeconds.toFixed(2)}s · ${check.status}`, x + 18 * scale, y + 18 * scale);
for (const [column, mode] of ['native', 'svg'].entries()) {
const image = await loadImage(resolve(reports, `canvas/${file.slug}--${check.action}--${mode}.png`));
ctx.drawImage(image, x + (25 + column * 240) * scale, y + 28 * scale, 188 * scale, 240 * scale);
}
}
const bytes = canvas.toBuffer('image/png'); writeFileSync(path, bytes);
return { path: path.slice(root.length), sha256: digest(bytes), width, height, actions: checks.map(check => check.action) };
}
for (const file of report.files) {
if (digest(readFileSync(resolve(root, `native/compiled/${file.slug}.riv`))) !== file.sha256) throw new Error(`Native bytes changed before sheet creation: ${file.slug}`);
const pages = [];
for (let start = 0; start < file.checks.length; start += 8) pages.push(await sheet(file, file.checks.slice(start, start + 8), resolve(details, `${file.slug}-${String(start / 8 + 1).padStart(2, '0')}.png`), 2, 1, `actions ${start + 1}–${Math.min(start + 8, file.checks.length)} / ${file.checks.length}`));
const overview = await sheet(file, file.checks, resolve(reports, `${file.slug}-parity.png`), 4, .8);
output.files.push({ slug: file.slug, nativeSHA256: file.sha256, actionCount: file.checks.length, overview, pages });
}
writeFileSync(resolve(reports, 'contact-sheets.json'), JSON.stringify(output, null, 2) + '\n');
console.log(`Generated ${output.files.length} overview sheets and ${output.files.reduce((sum, file) => sum + file.pages.length, 0)} readable detail sheets; visual review remains a separate step.`);