Back to Shiftfield
SOURCE / PINNED RELEASE

Made of little things.

Shiftfield

Release
5a170c505f6b…
Author-recorded commit
a2e23e0171aa…
License
LICENSE
Author’s source reference
nostr://npub16nzc4ql748r2kv9202rgzrt0fmtk4n3tzsjl86yf6ty9agqe9u0qjcc7hc/wss%3A%2F%2Fgit.napplet.soy%2F/n-e4fb6341ccd

Archive hash verified: 66de7623efd91da1…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

tests/recalc-isolate.mjs
// Isolate the ~60/s RecalcStyleCount seen while armed at d>=6:
// DOM telegraph chip vs canvas wind loop vs neither. Run from repo root.
import { chromium } from 'playwright';
import { spawn } from 'node:child_process';
import net from 'node:net';

const PORT = 4188;
const srv = spawn('npx', ['vite', 'preview', '--host', '127.0.0.1', '--port', String(PORT)], { stdio: 'ignore' });
for (let i = 0; i < 40; i++) {
  const up = await new Promise(res => { const s = net.connect(PORT, '127.0.0.1'); s.once('connect', () => { s.destroy(); res(true); }); s.once('error', () => res(false)); });
  if (up) break; await new Promise(r => setTimeout(r, 500));
}
const browser = await chromium.launch({ args: ['--disable-gpu', '--disable-accelerated-2d-canvas'] });
const page = await browser.newPage({ viewport: { width: 1600, height: 1000 }, deviceScaleFactor: 2 });
await page.goto(`http://127.0.0.1:${PORT}/`);
await page.waitForSelector('#startRunBtn'); await page.click('#startRunBtn');
await page.waitForSelector('.board');

const cdp = await page.context().newCDPSession(page);
await cdp.send('Performance.enable');
await cdp.send('Emulation.setCPUThrottlingRate', { rate: 6 });

const armed = async () => page.evaluate(() => {
  const g = window.minesweeperDx.board.game;
  g.depth = 6; g.nextShiftIn = 8; g.telegraph = [-1, 1]; g.world.mineCount = 20;
  window.minesweeperDx.board.refresh(); window.minesweeperDx.sync(g);
});
const measure = async (label) => {
  const g = (m, n) => m.metrics.find(x => x.name === n)?.value ?? -1;
  const m0 = await cdp.send('Performance.getMetrics');
  const t0 = Date.now();
  await page.waitForTimeout(3000);
  const m1 = await cdp.send('Performance.getMetrics');
  const s = (Date.now() - t0) / 1000;
  console.log(`${label}: RecalcStyle/s=${((g(m1,'RecalcStyleCount')-g(m0,'RecalcStyleCount'))/s).toFixed(1)} Layout/s=${((g(m1,'LayoutCount')-g(m0,'LayoutCount'))/s).toFixed(1)}`);
};

await measure('a) depth1 no telegraph (baseline)');
await armed();
await measure('b) armed d6: chip+wind both on');
await page.evaluate(() => { window.minesweeperDx.fx.setTelegraph(null); }); // canvas wind off, chip stays
await measure('c) chip ON, canvas wind OFF');
await page.evaluate(() => {
  const g = window.minesweeperDx.board.game;
  g.telegraph = null;
  window.minesweeperDx.sync(g); // chip off too (wind was already off)
});
await measure('d) neither (depth6, no telegraph)');

await browser.close(); srv.kill();