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 assert from 'node:assert/strict';
import {createRequire} from 'node:module';
import {realpathSync} from 'node:fs';
import {mkdir} from 'node:fs/promises';
import {execFileSync} from 'node:child_process';
import {openAnatomy,closeAnatomy} from './anatomy-ui-helpers.mjs';
const require=createRequire(realpathSync('node_modules/@napplet/conformance-cli/package.json'));
const {chromium}=require('playwright'),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/pose-handle-checks';await mkdir(output,{recursive:true});
try {
const page=await browser.newPage({viewport:{width:1600,height:1000}}),errors=[];page.on('pageerror',e=>errors.push(e.message));page.setDefaultTimeout(15000);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();
const settle=()=>f.evaluate(()=>new Promise(r=>requestAnimationFrame(()=>requestAnimationFrame(r))));
assert.ok(await f.locator('#anatomyPanel').isVisible(),'anatomy browser starts open');await page.screenshot({path:`${output}/default.png`});
await f.locator('#anatomySearch').fill('left arm');await f.locator('[data-visibility="region:left-arm"]').uncheck();
assert.equal(await f.locator('[data-visibility="region:left-index"]').isChecked(),false);assert.equal(await f.locator('#bodyViewport').getAttribute('data-focus'),'whole');
await f.locator('[data-visibility="region:left-index"]').check();assert.ok(await f.locator('[data-visibility="region:left-arm"]').evaluate(e=>e.indeterminate));
await f.locator('[data-focus="region:left-hand"]').click();assert.equal(await f.locator('#bodyViewport').getAttribute('data-focus'),'whole');const hidden=await f.locator('#bodyViewport').getAttribute('data-hidden');await f.locator('#applyFocus').click();assert.equal(await f.locator('#bodyViewport').getAttribute('data-hidden'),hidden);
await f.locator('#showAllAnatomy').click();await f.locator('#wholeBody').click();await closeAnatomy(f);await settle();await f.locator('[data-mode=pose]').click();await settle();
assert.equal(await f.locator('.pose-handle:visible').count(),4,'wrist and ankle handles at whole-body scale');
const drag=async(id,dx,dy,button='left')=>{const b=await f.locator(`[data-handle="${id}"]`).boundingBox();assert.ok(b,id);await page.mouse.move(b.x+b.width/2,b.y+b.height/2);await page.mouse.down({button});await page.mouse.move(b.x+b.width/2+dx,b.y+b.height/2+dy,{steps:15});await page.mouse.up({button});await settle();};
const before=await f.locator('[data-handle="left-arm"]').boundingBox();await drag('left-arm',35,-80);const moved=await f.locator('[data-handle="left-arm"]').boundingBox();assert.ok(Math.hypot(moved.x-before.x,moved.y-before.y)>30,'wrist moves with arm IK');
await page.screenshot({path:`${output}/limb-handles.png`});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();assert.equal(await f.locator('#anatomyToggle').getAttribute('aria-expanded'),'false','panel preference persists');await f.locator('[data-mode=pose]').click();await settle();
const restored=await f.locator('[data-handle="left-arm"]').boundingBox();assert.ok(Math.hypot(restored.x-moved.x,restored.y-moved.y)<2,'unmarked limb IK survives reload');
await f.locator('[data-pose=standing]').click();await f.locator('#fingerControls').click();await settle();assert.equal(await f.locator('#bodyViewport').getAttribute('data-mode'),'pose');
assert.ok(await f.locator('[data-handle="left-index"]').isVisible(),'fingertip handles at hand scale');assert.equal(await f.locator('[data-handle^="right-"]:visible').count(),0,'opposite hand handles do not show through close-up');await page.screenshot({path:`${output}/hand-before.png`});
await drag('left-index',-15,-65);const bends=await f.locator('[data-bend]').evaluateAll(es=>es.map(e=>Number(e.value)));assert.ok(bends.some(n=>n>10),`drag curls finger: ${bends}`);assert.equal(await f.locator('#handDigit').inputValue(),'index');
await page.screenshot({path:`${output}/hand-bent.png`});await f.locator('#handDigit').selectOption('middle');assert.deepEqual(await f.locator('[data-bend]').evaluateAll(es=>es.map(e=>Number(e.value))),[0,0,0]);await f.locator('#handDigit').selectOption('index');
await f.locator('[data-handle="left-index"]').focus();await f.locator('[data-handle="left-index"]').press('ArrowUp');const keyed=await f.locator('[data-bend]').evaluateAll(es=>es.map(e=>Number(e.value)));assert.notDeepEqual(keyed,bends,'keyboard moves selected tip');
await drag('left-index',30,10,'right');assert.equal(await f.locator('#bodyViewport').getAttribute('data-mode'),'pose');assert.deepEqual(await f.locator('[data-bend]').evaluateAll(es=>es.map(e=>Number(e.value))),keyed,'right drag rotates without bending');
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 f.locator('#fingerControls').click();await settle();assert.deepEqual(await f.locator('[data-bend]').evaluateAll(es=>es.map(e=>Number(e.value))),keyed,'unmarked finger IK survives reload');
await f.locator('#handSide').selectOption('right');await settle();await drag('right-index',15,-55);assert.ok((await f.locator('[data-bend]').evaluateAll(es=>es.map(e=>Number(e.value)))).some(n=>n>5));
// Profile fit proof for both shapes, plus front and open-jaw views.
await f.locator('#closeHandControls').click();await f.locator('#anatomyLayer').selectOption('mouth');
for(const sex of ['Male','Female']){await f.locator('#sex').selectOption(sex);await f.locator('#focusMouth').click();await f.locator('[data-view=left]').click();await settle();await page.screenshot({path:`${output}/mouth-${sex}-profile.png`});await f.locator('[data-view=front]').click();await settle();await page.screenshot({path:`${output}/mouth-${sex}-front.png`});}
await f.locator('#openJaw').click();await settle();await page.screenshot({path:`${output}/mouth-open.png`});assert.deepEqual(errors,[]);
// Actual touch drag through the same pointer/gesture path, in both orientations.
const touch=await browser.newContext({viewport:{width:390,height:844},hasTouch:true,isMobile:true}),tp=await touch.newPage();tp.on('pageerror',e=>errors.push(e.message));await tp.goto(process.argv[2]);
const ti=tp.locator('iframe');await ti.waitFor();const touchSize=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 touchSize(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();
const cdp=await touch.newCDPSession(tp);
for(const [w,h] of [[390,844],[844,390]]){
await touchSize(w,h);await tf.locator('#openHand').tap();await tf.locator('[data-view=left]').tap();await tf.evaluate(()=>new Promise(r=>requestAnimationFrame(()=>requestAnimationFrame(r))));
const handle=tf.locator('[data-handle="left-index"]'),b=await handle.boundingBox();assert.ok(b&&b.width>=44&&b.height>=44,'touch handle target');
const x=b.x+b.width/2,y=b.y+b.height/2;
await cdp.send('Input.dispatchTouchEvent',{type:'touchStart',touchPoints:[{x,y,id:1}]});
for(let n=1;n<=10;n++)await cdp.send('Input.dispatchTouchEvent',{type:'touchMove',touchPoints:[{x:x-8*n/10,y:y-38*n/10,id:1}]});
await cdp.send('Input.dispatchTouchEvent',{type:'touchEnd',touchPoints:[]});
assert.ok((await tf.locator('[data-bend]').evaluateAll(es=>es.map(e=>Number(e.value)))).some(n=>n>5),'touch drag bends selected finger');
await tp.screenshot({path:`${output}/touch-${w}.png`});
}
assert.deepEqual(errors,[]);await touch.close();
console.log('PASS: unified hierarchy/focus, visible limb/finger handles, wrist and bilateral fingertip drag, keyboard movement, secondary rotation, unmarked SDK pose/drawer persistence, mouth front/profile evidence. No provider calls.');
} finally {await browser.close();}
