Back to Limb Race
SOURCE / PINNED RELEASE

Made of little things.

Limb Race

Release
6a8ae4fc626e…
Author-recorded commit
008c01ee6454…
License
LICENSE
Author’s source reference
nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-c2869f12ad8

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

tests/challenges-smoke.mjs
import {createRequire} from 'node:module';
import {realpathSync} from 'node:fs';
import assert from 'node:assert/strict';
const require=createRequire(realpathSync(new URL('../node_modules/@napplet/conformance-cli/package.json',import.meta.url)));
const {chromium}=require('playwright');
assert.ok(process.argv[2], 'Pass the URL printed by soyli dev');
const browser=await chromium.launch({headless:true});
try {
  const page=await browser.newPage({viewport:{width:900,height:600}}),errors=[];
  page.on('pageerror',e=>errors.push(e.message));
  await page.goto(process.argv[2]);await page.waitForTimeout(1800);
  let frame=page.frames().find(f=>f.url()==='about:srcdoc');assert.ok(frame);
  async function size(w,h){
    await page.setViewportSize({width:w,height:h});
    await page.locator('iframe').evaluate((el,{w,h})=>{el.style.cssText=`position:fixed;inset:0;width:${w}px;height:${h}px;min-height:0;border:0;z-index:9999`;},{w,h});
    await page.waitForTimeout(100);assert.deepEqual(await frame.evaluate(()=>[innerWidth,innerHeight]),[w,h]);
  }
  async function select(id){await frame.locator('#track-picker').click();await frame.locator(`[data-track="${id}"]`).click();}
  await size(900,600);await select('sawtooth');
  assert.equal(await frame.locator('#track-number').innerText(),'05 / 10');
  await frame.locator('#clear').click();
  const box=await frame.locator('#draw-canvas').boundingBox(),x=box.x+box.width/2,y=box.y+box.height/2,r=box.width*.43+1;
  for(const [dx,dy]of [[1,1],[-1,1],[-1,-1],[1,-1]]){
    await page.mouse.move(x,y);await page.mouse.down();await page.mouse.move(x+dx*r,y+dy*r);await page.mouse.up();
  }
  await frame.locator('#race').click();
  await frame.locator('#message-title').filter({hasText:'Look at you go.'}).waitFor({timeout:45000});
  console.log('CHALLENGE FINISH',await frame.locator('#message-detail').innerText());
  assert.equal(await frame.locator('#share-result').isVisible(),false);
  assert.equal(await frame.locator('.score-row').count(),1);
  await frame.locator('#message-action').click();await frame.locator('#shared').click();
  assert.match(await frame.locator('#score-list').innerText(),/personal challenge/i);
  await frame.locator('#refresh').click();assert.match(await frame.locator('#score-status').innerText(),/Personal records only/);
  await frame.locator('#personal').click();await frame.locator('.score-row').click();
  assert.match(await frame.locator('#design-detail').innerText(),/Sawtooth/);await frame.locator('#use-design').click();
  await select('pinpoint');assert.equal(await frame.locator('.score-row').count(),0);
  await page.reload();await page.waitForTimeout(1500);frame=page.frames().find(f=>f.url()==='about:srcdoc');await size(900,600);
  await select('sawtooth');assert.equal(await frame.locator('.score-row').count(),1);
  for(const scheme of ['light','dark']){
    await page.evaluate(scheme=>document.querySelector('iframe').contentWindow.postMessage({type:'theme.changed',theme:{colors:scheme==='dark'?{background:'#172521',text:'#e5ecdf',primary:'#a8cf8b'}:{background:'#f8f6ed',text:'#292d23',primary:'#72ac98'}}},'*'),scheme);
    for(const [w,h]of [[200,160],[320,560],[900,600],[2400,1200]]){
      await size(w,h);assert.equal(await frame.evaluate(()=>document.documentElement.scrollWidth>innerWidth),false);
      assert.equal(await frame.evaluate(()=>document.documentElement.classList.contains('dark')),scheme==='dark');
      if(w===200){assert.equal(await frame.locator('.too-small').isVisible(),true);continue;}
      await frame.locator('#track-picker').click();assert.equal(await frame.locator('.track-option').count(),10);
      const dialog=await frame.locator('#tracks-dialog').boundingBox();assert.ok(dialog.y>=0&&dialog.y+dialog.height<=h);
      assert.equal(await frame.locator('#tracks-dialog').evaluate(el=>el.scrollWidth>el.clientWidth),false);
      if(h<=600)assert.equal(await frame.locator('#track-options').evaluate(el=>el.scrollHeight>el.clientHeight),true);
      await frame.locator('[data-track="gauntlet"]').scrollIntoViewIfNeeded();
      const close=await frame.locator('[data-close="tracks-dialog"]').boundingBox();assert.ok(close.y>=0&&close.y+close.height<=h);
      assert.equal(await frame.locator('[data-track="gauntlet"] .difficulty').isVisible(),true);
      assert.equal(await frame.locator('.track-option').evaluateAll(items=>items.every(item=>{const parent=item.getBoundingClientRect(),badge=item.querySelector('.difficulty').getBoundingClientRect();return badge.top>=parent.top&&badge.bottom<=parent.bottom;})),true,'difficulty badges stay inside their course rows');
      await frame.locator('[data-track="gauntlet"]').click();assert.equal(await frame.locator('#track-number').innerText(),'10 / 10');
      assert.equal(await frame.locator('#difficulty').innerText(),'EXTREME');
      console.log('COURSE PICKER',scheme,w,h,'OK');
    }
  }
  assert.deepEqual(errors,[]);
  console.log('PASS: ten courses, real challenge finish, personal-only records, persistence, last-course selection and themed scrollable menus.');
} finally {await browser.close();}