Back to Napplet Machines V8
SOURCE / PINNED RELEASE

Made of little things.

Napplet Machines V8

Release
b3f614e739f0…
Author-recorded commit
534f19acb4ba…
License
LICENSE
Author’s source reference
nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-b5572362d4a

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

tests/driving.mjs
import { mkdir } from 'node:fs/promises';

export default async ({ players, check, measure }) => {
  const { page, frame } = players[0];
  const element = await frame.frameElement();
  await page.setViewportSize({ width: 1200, height: 750 });
  await element.evaluate((el) =>
    Object.assign(el.style, {
      position: 'fixed',
      top: 0,
      left: 0,
      width: '1200px',
      height: '750px',
      minHeight: 0,
      border: 0,
      zIndex: 9999,
    }),
  );
  await frame.waitForFunction(() => innerWidth === 1200 && innerHeight === 750);
  await frame.evaluate(() => document.fonts.ready);
  await mkdir('.napplet-space/promotion', { recursive: true });
  const idleDraws = await frame.evaluate(async () => {
    const proto = WebGLRenderingContext.prototype,
      original = proto.drawArrays;
    let draws = 0;
    proto.drawArrays = function (...args) {
      draws++;
      return original.apply(this, args);
    };
    try {
      // A resize eases the camera. Wait for it to settle before measuring idle work.
      for (let i = 0; i < 16; i++) {
        draws = 0;
        await new Promise((resolve) => setTimeout(resolve, 500));
        if (draws === 0) break;
      }
      draws = 0;
      await new Promise((resolve) => setTimeout(resolve, 800));
      return draws;
    } finally {
      proto.drawArrays = original;
    }
  });
  check('settled previews avoid redundant GPU draws', idleDraws < 10);
  await element.screenshot({ path: '.napplet-space/promotion/buildings.png' });
  check(
    'trackside buildings render',
    Number(await frame.locator('#scene').getAttribute('data-buildings')) >= 5,
  );
  await frame.locator('#gridSize').selectOption('2');
  await frame.locator('#raceButton').click();
  await frame.waitForFunction(
    () => document.querySelector('#scene').dataset.countdown === '0',
  );
  const result = await frame.evaluate(async () => {
    const scene = document.querySelector('#scene');
    const key = (code, down) =>
      scene.dispatchEvent(
        new KeyboardEvent(down ? 'keydown' : 'keyup', { code, bubbles: true }),
      );
    const wait = (ms) =>
      new Promise((resolve) => {
        const start = performance.now();
        const tick = () =>
          performance.now() - start >= ms
            ? resolve()
            : requestAnimationFrame(tick);
        requestAnimationFrame(tick);
      });
    key('KeyW', true);
    await wait(1200);
    key('KeyA', true);
    key('Space', true);
    await wait(430);
    const drift = { ...scene.dataset };
    key('KeyA', false);
    key('Space', false);
    key('KeyD', true);
    await wait(160);
    key('KeyD', false);
    // Let the tires catch before returning control to the test process.
    await wait(450);
    key('KeyW', false);
    return { drift, recovered: { ...scene.dataset } };
  });
  check(
    'handbrake produces a momentum-carrying slide',
    Number(result.drift.localHandbrake) > 0.7 &&
      Math.abs(Number(result.drift.localSlip)) > 0.22 &&
      Number(result.drift.localSpeed) > 5,
  );
  check(
    'release returns rear traction',
    Number(result.recovered.localHandbrake) < 0.04,
  );
  await element.screenshot({ path: '.napplet-space/promotion/drift.png' });
  const frames = await frame.evaluate(async () => {
    const times = [];
    let last = performance.now();
    for (let i = 0; i < 60; i++) {
      await new Promise(requestAnimationFrame);
      const now = performance.now();
      times.push(now - last);
      last = now;
    }
    times.sort((a, b) => a - b);
    return times[Math.floor(times.length * 0.95)];
  });
  measure('local render frame p95', frames, 50);
  await frame.locator('#exitRace').click();
  await frame.locator('#trackSelect').selectOption('2');
  await frame.locator('#raceButton').click();
  await frame.locator('#pauseButton').click();
  for (let i = 0; i < 4; i++) await frame.locator('#zoomIn').click();
  await page.waitForTimeout(300);
  await element.screenshot({ path: '.napplet-space/promotion/slopes.png' });
  check(
    'grid chassis follows a steep downhill slope',
    Number(await frame.locator('#scene').getAttribute('data-local-pitch')) <
      -0.2,
  );
  await frame.locator('#exitRace').click();
};