- 466px round layout, designWidth 466 (S4 41mm 466x466) - solar position + dayProgress in src/common/solar.js (pure, TDD'd) - sunrise/sunset sweep, night moon, countdown, 30s refresh - tests: solar math, page logic, circle geometry/contrast
35 lines
2.1 KiB
JavaScript
35 lines
2.1 KiB
JavaScript
|
|
// Circle geometry: sun marker orbit, horizon line, center text block — all inside 466px circle.
|
|
const fs = require('node:fs');
|
|
const assert = require('node:assert/strict');
|
|
const ux = fs.readFileSync('src/pages/index/index.ux', 'utf8');
|
|
const num = (re) => { const m = ux.match(re); assert.ok(m, 'missing: '+re); return Number(m[1]); };
|
|
const SCREEN = 466, R = 233;
|
|
const skyD = num(/\.sky\s*{[^}]*width:\s*(\d+)px/);
|
|
assert.ok(skyD <= SCREEN - 40, 'sky dial should leave bezel margin: ' + skyD);
|
|
// horizon line spans within circle at y=233 (widest point) → width <= 466
|
|
const hzW = num(/\.horizon\s*{[^}]*width:\s*(\d+)px/);
|
|
assert.ok(hzW <= SCREEN, 'horizon width fits');
|
|
// Actual template-bound coordinates are exercised in marker.cjs.
|
|
const orbit = num(/orbitR:\s*(\d+)/);
|
|
assert.ok(orbit <= skyD / 2 - 30, `sun orbit ${orbit} must stay within sky dial ${skyD/2} minus marker radius`);
|
|
// center text block vertical span inside circle
|
|
const cTop = num(/\.center\s*{[^}]*top:\s*(\d+)px/);
|
|
const bigH = num(/\.big\s*{[^}]*height:\s*(\d+)px/);
|
|
const phaseH = num(/\.phase\s*{[^}]*height:\s*(\d+)px/);
|
|
const countH = num(/\.count\s*{[^}]*height:\s*(\d+)px/);
|
|
const cBot = cTop + bigH + phaseH + countH;
|
|
// text content is centered and narrow (~240px wide worst case = clock at 66px font); check half-width 120px fits chord
|
|
const TEXT_HALF = 120;
|
|
for (const y of [cTop, cBot]) {
|
|
const halfW = Math.sqrt(Math.max(0, R*R - Math.abs(y-R)**2));
|
|
assert.ok(TEXT_HALF <= halfW, `center text at y=${y} exceeds chord: needs ${TEXT_HALF}, has ${halfW.toFixed(0)}`);
|
|
}
|
|
// contrast
|
|
const lum = h => { const c=h.match(/\w\w/g).map(x=>parseInt(x,16)/255).map(v=>v<=0.03928?v/12.92:((v+0.055)/1.055)**2.4); return .2126*c[0]+.7152*c[1]+.0722*c[2]; };
|
|
const ratio = (a,b)=>(Math.max(lum(a),lum(b))+.05)/(Math.min(lum(a),lum(b))+.05);
|
|
assert.ok(ratio('#ffffff','#000000') >= 4.5, 'clock contrast');
|
|
assert.ok(ratio('#f3a633','#000000') >= 4.5, 'phase contrast');
|
|
assert.ok(ratio('#9aa0aa','#000000') >= 4.5, 'count contrast');
|
|
console.log('GEOMETRY ESTIMATES PASS (not renderer validation): dial', skyD, 'orbit', orbit, 'center block y', cTop, '-', cBot);
|