/** * Neoclassical museum floor must not blow out as near-white marble. * node --test server/__tests__/neoclassical-interior.test.js */ const { describe, it } = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const ROOT = path.join(__dirname, '..', '..'); const STYLES = fs.readFileSync(path.join(ROOT, 'client/src/data/movement-interior-styles.ts'), 'utf8'); function neoclassicalBlock() { const start = STYLES.indexOf("'neoclassical-museum'"); assert.ok(start >= 0, 'neoclassical-museum style must exist'); const next = STYLES.indexOf('mk(', start + 1); return STYLES.slice(start, next > start ? next : undefined); } function floorTintHex(block) { const m = block.match(/floor:\s*'#[0-9a-fA-F]{6}'/); assert.ok(m, 'floor tint hex must be present in tints object'); // Prefer the tints line: `{ wall: '...', ceiling: '...', floor: '#......', trim: '...' }` const tints = block.match(/\{\s*wall:\s*'#[^']+',\s*ceiling:\s*'#[^']+',\s*floor:\s*'(#[0-9a-fA-F]{6})'/); assert.ok(tints, 'tints.floor must be a hex color'); return tints[1]; } function luminance(hex) { const n = parseInt(hex.slice(1), 16); const r = (n >> 16) & 255; const g = (n >> 8) & 255; const b = n & 255; return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255; } describe('Neoclassical interior — subdued stone floor', () => { it('floor tint is mid stone grey, not near-white', () => { const block = neoclassicalBlock(); const hex = floorTintHex(block); assert.ok(luminance(hex) < 0.62, `floor luminance ${luminance(hex).toFixed(2)} for ${hex} is still too bright`); assert.doesNotMatch(block, /floor: '#eceae6'/); }); it('skylight is not overdriven for the marble floor', () => { const block = neoclassicalBlock(); const sky = block.match(/style: 'skylight',\s*lightColor: '[^']+',\s*lightIntensity:\s*([0-9.]+)/); assert.ok(sky, 'skylight must exist'); assert.ok(Number(sky[1]) <= 3.6, `skylight intensity ${sky[1]} is still too strong`); }); });