Back to Soybert 3D
SOURCE / PINNED RELEASE

Made of little things.

Soybert 3D

Release
4bf80e758af1…
Author-recorded commit
298fa2d0e8b1…
License
LICENSE
Author’s source reference
nostr://npub1n8ga89w8h6tvwamxusfyzexw8gjy84yxu9rxgnmk955cxtml4ujswzxydd/wss%3A%2F%2Fgit.napplet.soy%2F/n-9021e1b6a96

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

tests/browser-smoke.mjs
/** Built-artifact regression checks in real opaque-origin Chromium iframes. */
import assert from 'node:assert/strict';
import { readFile, mkdir, writeFile } from 'node:fs/promises';
import { createRequire } from 'node:module';
import { dirname, resolve } from 'node:path';
const require = createRequire(import.meta.url);
const { chromium } = require(require.resolve('playwright', { paths: [dirname(require.resolve('@napplet/conformance-cli/package.json'))] }));
const html = await readFile('dist/index.html', 'utf8');
const out = resolve('.napplet-space/verification'); await mkdir(out, { recursive: true });
const browser = await chromium.launch({ headless: true, args: ['--use-angle=swiftshader', '--enable-unsafe-swiftshader'] });
const page = await browser.newPage();
const errors = []; page.on('pageerror', e => errors.push(e.message));
const themes = {
  dark: { colors: { background: '#171c18', text: '#f3eddd', primary: '#c8e79c' } },
  light: { colors: { background: '#f6f2e8', text: '#292b21', primary: '#526c34' } },
};
const report = [];
async function mount(width, height, theme, missing = false) {
  await page.setViewportSize({width: Math.max(width, 320), height: Math.max(height, 240)});
  await page.setContent('<style>body{margin:0}iframe{display:block;border:0}</style><iframe sandbox="allow-scripts"></iframe>');
  const fixture = `<script>window.__closed=0; window.__settingsOpened=0; window.__themeHandler=null; window.napplet=${missing ? '{}' : `{theme:{get:async()=>(${JSON.stringify(themes[theme])}),onChanged:(fn)=>{window.__themeHandler=fn;return {close:()=>window.__closed++}}},config:{schema:{type:'object'},subscribe:fn=>{fn({sound:false,reducedMotion:true,movementSpeed:6.2});return {close:()=>window.__closed++}},openSettings:()=>window.__settingsOpened++}}`};<\/script>`;
  await page.locator('iframe').evaluate((iframe, {html, fixture, width, height}) => { iframe.style.width=width+'px'; iframe.style.height=height+'px'; iframe.srcdoc=html.replace('<head>', '<head>'+fixture); }, {html, fixture, width, height});
  const f = page.frames().find(f => f.parentFrame());
  await f.waitForSelector('#app[data-ready="true"]');
  await f.waitForFunction(() => document.querySelector('canvas').width > 1);
  // Let camera framing settle, independently of machine frame rate.
  await page.waitForTimeout(700);
  return f;
}
async function layout(f, width, height) {
  const metrics = await f.evaluate(() => {
    const box = document.querySelector('#app').getBoundingClientRect();
    const buttons = [...document.querySelectorAll('button')].filter(b => b.getClientRects().length);
    return { overflow: document.documentElement.scrollWidth > innerWidth || document.documentElement.scrollHeight > innerHeight,
      clipped: buttons.filter(b => {const r=b.getBoundingClientRect();return r.left < 0 || r.top < 0 || r.right > box.right+.5 || r.bottom > box.bottom+.5;}).map(b=>b.id),
      bg: [document.documentElement, document.body, document.querySelector('#app')].map(e=>getComputedStyle(e).backgroundColor),
      width: box.width,height: box.height, errors: document.querySelector('#error').hidden,
    };
  });
  assert.equal(metrics.overflow,false); assert.deepEqual(metrics.clipped,[]); assert.equal(metrics.width,width); assert.equal(metrics.height,height); assert.equal(metrics.errors,true);
  assert.equal(new Set(metrics.bg).size,1);
  return metrics;
}
try {
  for (const theme of ['dark','light']) for (const [w,h] of [[200,160],[320,560],[900,600],[960,900],[2400,1200]]) {
    const f=await mount(w,h,theme);
    await layout(f,w,h);
    await page.locator('iframe').screenshot({path:`${out}/${theme}-${w}x${h}-intro.png`});
    await f.locator('#enter').click();
    await f.waitForSelector('#app[data-mode="stage"]');
    await page.waitForTimeout(650);
    const metrics=await layout(f,w,h);
    await page.locator('iframe').screenshot({path:`${out}/${theme}-${w}x${h}-stage.png`});
    report.push({theme,width:w,height:h,passed:true,bg:metrics.bg[0]});
  }
  const f=await mount(900,600,'dark'); await f.locator('#enter').click();
  await f.locator('#app').press('Space');
  await f.waitForSelector('#app[data-airborne="true"]');
  await f.waitForSelector('#app[data-airborne="false"]');
  await f.locator('#shoot').click(); await f.waitForSelector('#app[data-action="shoot"]');
  await f.locator('#celebrate').click(); await f.waitForSelector('#app[data-action="celebrate"]');
  await page.waitForTimeout(2900);
  await f.locator('#app').focus(); await page.keyboard.down('w'); await f.waitForSelector('#app[data-moving="true"]'); await page.keyboard.up('w');
  await f.locator('#app').press('Escape'); await f.waitForSelector('#app[data-paused="true"]');
  await f.locator('#resume').click(); await f.waitForSelector('#app[data-paused="false"]');
  await f.locator('#reset').click(); await f.waitForSelector('#app[data-moving="false"]');
  // Pointer movement and release, including release outside the pad via pointer capture.
  const pad=await f.locator('#joystick').boundingBox(); await page.mouse.move(pad.x+pad.width/2,pad.y+pad.height/2); await page.mouse.down(); await page.mouse.move(pad.x+pad.width,pad.y+pad.height/2); await f.waitForSelector('#app[data-moving="true"]'); await page.mouse.up();
  await f.waitForSelector('#app[data-moving="false"]');
  await f.locator('#settings').click(); assert.equal(await f.evaluate(()=>window.__settingsOpened),1);
  await f.evaluate(theme=>window.__themeHandler(theme),themes.light);
  await page.waitForTimeout(100); assert.equal((await layout(f,900,600)).bg[0],'rgb(246, 242, 232)');
  await f.evaluate(()=>window.dispatchEvent(new Event('pagehide'))); assert.equal(await f.evaluate(()=>window.__closed),2);
  const bare=await mount(320,560,'dark',true); await bare.locator('#enter').click(); await bare.locator('#jump').click(); await bare.waitForSelector('#app[data-airborne="true"]'); assert.equal(await bare.locator('#settings').isVisible(),false);
  assert.deepEqual(errors,[]);
  await writeFile(`${out}/report.json`,JSON.stringify({frames:report,interactionChecks:['jump and landing','shoot','celebrate','keyboard movement','pointer movement and release','pause/resume','reset','settings SDK operation','live theme change','subscription teardown','missing optional domains'],errors},null,2));
  console.log('PASS: 10 frame/theme pairs, intro + stage; 11 interaction/lifecycle checks; no page errors.');
} finally { await browser.close(); }