SOURCE / PINNED RELEASE
Made of little things.
Body Journal
- Release
- e8049f8da4e2…
- Author-recorded commit
- 61c04bf0e8aa…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-6c4554844c7
Archive hash verified: 4369d778da046a8b…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import {openAnatomy,closeAnatomy} from './anatomy-ui-helpers.mjs';
import assert from 'node:assert/strict';
import {createRequire} from 'node:module';
import {realpathSync} from 'node:fs';
import {mkdir,writeFile,readFile} from 'node:fs/promises';
import {execFileSync} from 'node:child_process';
const require=createRequire(realpathSync('node_modules/@napplet/conformance-cli/package.json'));
const {chromium}=require('playwright');
const info=JSON.parse(execFileSync('soyli',['browser','path','--json'],{encoding:'utf8'}));
const browser=await chromium.launch({executablePath:info.executables.find(e=>e.name==='chromium'&&e.installed).path,headless:true});
const output='.napplet-space/finger-checks';await mkdir(output,{recursive:true});
try{
const context=await browser.newContext({viewport:{width:1600,height:1000}}),page=await context.newPage(),errors=[];
page.on('pageerror',e=>errors.push(e.message));await page.goto(process.argv[2]);
const iframe=page.locator('iframe');await iframe.waitFor();
const size=async(w,h)=>{await page.setViewportSize({width:w,height:h});await iframe.evaluate((e,[w,h])=>e.style.cssText=`position:fixed;inset:0;width:${w}px;height:${h}px;z-index:9999;border:0;min-width:0;min-height:0`,[w,h]);};
await size(1600,1000);let f=await(await iframe.elementHandle()).contentFrame();await f.locator('#app[data-ready="true"]').waitFor();await closeAnatomy(f);
const settle=()=>f.evaluate(()=>new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(resolve))));
const focus=async(search,label,mode)=>{
await openAnatomy(f);await f.locator('#anatomySearch').fill(search);
const previous=await f.locator('#bodyViewport').getAttribute('data-focus'),hidden=await f.locator('#bodyViewport').getAttribute('data-hidden');
const option=f.locator('.anatomy-name').filter({hasText:label}).first();const target=await option.getAttribute('data-focus');await option.click();
assert.equal(await f.locator('#bodyViewport').getAttribute('data-focus'),previous,'selecting alone does not focus');
await f.locator('#applyFocus').click();await closeAnatomy(f);await settle();assert.equal(await f.locator('#bodyViewport').getAttribute('data-hidden'),hidden,'focusing does not change visibility');
if(mode){await openAnatomy(f);await f.locator('#hideAllAnatomy').click();await f.locator('#anatomySearch').fill(search);await f.locator(`[data-visibility="${target}"]`).check();await closeAnatomy(f);await settle();}
};
const mark=async(label)=>{
await f.locator('button[data-mode="paint"]').click();const b=await f.locator('canvas').boundingBox();
for(const y of [.5,.45,.55,.4,.6,.35,.65])for(const x of [.5,.45,.55,.4,.6,.35,.65]){
await page.mouse.move(b.x+b.width*x,b.y+b.height*y);
if((await f.locator('#sceneHint').innerText()).toLowerCase().includes(label.toLowerCase())){await page.mouse.click(b.x+b.width*x,b.y+b.height*y);return;}
}
throw new Error(`Cannot paint ${label}`);
};
const bend=async(i,n)=>{await f.locator(`#fingerBend${i}`).fill(String(n));await f.locator(`#fingerBend${i}`).dispatchEvent('change');};
const values=()=>Promise.all([0,1,2].map(i=>f.locator(`#fingerBend${i}`).inputValue()));
await f.locator('#fingerControls').click();await settle();await f.locator('#handDigit').selectOption('index');
await bend(0,50);await bend(1,65);await bend(2,35);
await f.waitForFunction(()=>document.querySelector('#sessionStatus').textContent==='Session saved');
await page.reload();await iframe.waitFor();await size(1600,1000);f=await(await iframe.elementHandle()).contentFrame();await f.locator('#app[data-ready="true"]').waitFor();await closeAnatomy(f);
await f.locator('#fingerControls').click();await settle();assert.deepEqual(await values(),['50','65','35'],'unmarked working pose survives reload');
await focus('left index','Left index finger','isolate');await mark('Left index finger');await f.locator('#description').fill('Synthetic bent left index observation.');assert.match(await f.locator('#handScope').innerText(),/Editing concern 1/);
await page.screenshot({path:`${output}/left-hand.png`});
await f.locator('#closeHandControls').click();await f.locator('[data-pose="sitting"]').click();await f.locator('#fingerControls').click();await settle();assert.deepEqual(await values(),['50','65','35'],'body presets preserve finger bends');
await f.locator('#anatomyLayer').selectOption('skeleton');await settle();await page.screenshot({path:`${output}/left-skeleton.png`});
await f.locator('#anatomyLayer').selectOption('muscles');await settle();await page.screenshot({path:`${output}/left-muscles.png`});
await f.locator('#anatomyLayer').selectOption('skin');await settle();
await f.locator('#newConcern').click();await f.locator('#handSide').selectOption('right');await f.locator('#handDigit').selectOption('ring');await bend(0,70);await bend(1,30);await bend(2,20);
await focus('right ring','Right ring finger','isolate');await mark('Right ring finger');await f.locator('#description').fill('Synthetic bent right ring observation.');
await f.locator('#handSide').selectOption('left');await f.locator('#openHand').click();await f.locator('#handSide').selectOption('right');assert.deepEqual(await values(),['70','30','20'],'opening the other hand leaves this hand unchanged');
await f.locator('#handDigit').selectOption('thumb');await bend(1,45);await f.locator('#resetFinger').click();assert.deepEqual(await values(),['0','0','0']);await f.locator('#handDigit').selectOption('ring');assert.deepEqual(await values(),['70','30','20']);
await f.locator('#closeHandControls').click();await f.locator('[data-pose="standing"]').click();
await f.waitForFunction(()=>document.querySelector('#sessionStatus').textContent==='Session saved');await page.reload();await iframe.waitFor();await size(1600,1000);f=await(await iframe.elementHandle()).contentFrame();await f.locator('#app[data-ready="true"]').waitFor();await closeAnatomy(f);
await f.locator('#fingerControls').click();await f.locator('#handDigit').selectOption('ring');await settle();assert.equal(await f.locator('#handSide').inputValue(),'right');assert.deepEqual(await values(),['70','30','20']);
await f.locator('#concern-toggle-1').click();await f.locator('#handDigit').selectOption('index');assert.equal(await f.locator('#handSide').inputValue(),'left');assert.deepEqual(await values(),['50','65','35']);assert.equal(await f.locator('[data-pose="sitting"]').getAttribute('aria-pressed'),'true');
await f.locator('#concern-toggle-2').click();await f.locator('#handDigit').selectOption('ring');assert.deepEqual(await values(),['70','30','20']);
await f.locator('#connectionsButton').click();await f.locator('#apiKey').fill('dummy-finger-test');await f.locator('#bridgePubkey').fill('a'.repeat(64));await f.locator('#bridgeTrust').check();await f.locator('#closeModal').click();
await f.locator('[data-page="review"]').first().click();assert.match(await f.locator('.review-report').innerText(),/left index finger bent at base \/ middle \/ tip/);assert.match(await f.locator('.review-report').innerText(),/right ring finger bent at base \/ middle \/ tip/);
await f.locator('[data-ai="request"]').click();assert.equal(await f.locator('.evidence-gallery img').count(),2);
const captions=await f.locator('.evidence-gallery figcaption').allTextContents();assert.match(captions[0],/left index finger bent/);assert.match(captions[1],/right ring finger bent/);
for(let i=0;i<2;i++){const data=await f.locator('.evidence-gallery img').nth(i).getAttribute('src');await writeFile(`${output}/evidence-${i+1}.jpg`,Buffer.from(data.split(',')[1],'base64'));}
await f.locator('#closeModal').click();await f.locator('[data-page="map"]').first().click();assert.deepEqual(await values(),['70','30','20'],'capture restores working pose');
for(const [w,h] of [[900,600],[320,560],[390,844],[844,390],[200,160]]){
await size(w,h);assert.deepEqual(await f.evaluate(()=>[innerWidth,innerHeight]),[w,h]);if(w<280||h<280){assert.ok(await f.locator('.minimum-notice').isVisible());continue;}
if(w<761&&h>440)await f.locator('button[data-panel="body"]').click();
for(const selector of ['#handSide','#handDigit','#fingerBend0','#fingerBend1','#fingerBend2','#closeHandControls','#openHand'])assert.ok(await f.locator(selector).evaluate(e=>{const b=e.getBoundingClientRect();return b.left>=0&&b.top>=0&&b.right<=innerWidth&&b.bottom<=innerHeight;}),selector);
const box=await f.locator('canvas').boundingBox();assert.ok(box.height>=100&&box.width>=150,`live canvas ${w}x${h}: ${JSON.stringify(box)}`);
await settle();await page.screenshot({path:`${output}/controls-${w}x${h}.png`});
}
// Check the new editor itself under both explicit host appearances.
for(const theme of ['light','dark']){
await size(900,600);await iframe.evaluate(e=>e.style.cssText='');
const appearance=page.getByRole('button',{name:/Appearance:/});
let label='';for(let i=0;i<4;i++){label=(await appearance.getAttribute('aria-label')) || await appearance.innerText();if(label.toLowerCase().includes(theme))break;await appearance.click();}
assert.ok(label.toLowerCase().includes(theme),`host ${theme}: ${label}`);
for(const [w,h] of [[1600,1000],[900,600],[320,560],[200,160]]){
await size(w,h);await settle();assert.deepEqual(await f.evaluate(()=>[innerWidth,innerHeight]),[w,h]);
const palette=await f.evaluate(()=>({accent:getComputedStyle(document.documentElement).getPropertyValue('--emphasis').trim(),background:getComputedStyle(document.querySelector('#handControls')).backgroundColor,ink:getComputedStyle(document.querySelector('#handControls')).color}));
assert.deepEqual(palette,{accent:'#c43c20',background:'rgb(255, 255, 255)',ink:'rgb(32, 33, 36)'});
await page.screenshot({path:`${output}/${theme}-${w}x${h}.png`});
}
}
assert.deepEqual(errors,[]);
const absent=await browser.newContext({viewport:{width:900,height:600}}),ap=await absent.newPage();ap.on('pageerror',e=>errors.push(e.message));
await ap.setContent('<iframe sandbox="allow-scripts" style="position:fixed;inset:0;width:900px;height:600px;border:0"></iframe>');
await ap.locator('iframe').evaluate((el,html)=>el.srcdoc=html,await readFile('dist/index.html','utf8'));const af=await(await ap.locator('iframe').elementHandle()).contentFrame();
await af.locator('#app[data-ready="true"]').waitFor();await closeAnatomy(af);await af.locator('#fingerControls').click();await af.locator('#handDigit').selectOption('index');await af.locator('#fingerBend2').fill('65');await af.locator('#fingerBend2').dispatchEvent('change');
assert.equal(await af.locator('#fingerBend2').inputValue(),'65');assert.match(await af.locator('#sessionStatus').innerText(),/session only/i);assert.deepEqual(errors,[]);await absent.close();
// Exercise real pointer input with touch emulation in an isolated host session.
const touch=await browser.newContext({viewport:{width:390,height:844},hasTouch:true,isMobile:true}),tp=await touch.newPage();await tp.goto(process.argv[2]);
const ti=tp.locator('iframe');await ti.waitFor();const resizeTouch=async(w,h)=>{await tp.setViewportSize({width:w,height:h});await ti.evaluate((e,[w,h])=>e.style.cssText=`position:fixed;inset:0;width:${w}px;height:${h}px;z-index:9999;border:0;min-width:0;min-height:0`,[w,h]);};
await resizeTouch(390,844);const tf=await(await ti.elementHandle()).contentFrame();await tf.locator('#app[data-ready="true"]').waitFor();await closeAnatomy(tf);await tf.locator('#fingerControls').tap();await tf.locator('#handDigit').selectOption('index');
const slider=await tf.locator('#fingerBend1').boundingBox();await tp.touchscreen.tap(slider.x+slider.width*.75,slider.y+slider.height/2);assert.ok(Number(await tf.locator('#fingerBend1').inputValue())>50);
await tp.screenshot({path:`${output}/touch-portrait.png`});await resizeTouch(844,390);await tp.screenshot({path:`${output}/touch-landscape.png`});
await tf.locator('#resetFinger').tap();assert.equal(await tf.locator('#fingerBend1').inputValue(),'0');await tf.locator('#closeHandControls').tap();assert.ok(await tf.locator('#fingerControls').isVisible());
console.log('PASS: independent digit controls, per-finger/per-hand reset, unmarked and observed pose persistence, body presets, three layers, summaries, saved-pose evidence and restoration, responsive canvas/controls in both host themes, missing optional domains and emulated touch; no provider requests.');
}finally{await browser.close();}
