Back to Drone Zone — deep field
SOURCE / PINNED RELEASE

Made of little things.

Drone Zone — deep field

Release
578f277a8be1
Author-recorded commit
a96742b428de…
License
LICENSE
Author’s source reference
nostr://npub1n8ga89w8h6tvwamxusfyzexw8gjy84yxu9rxgnmk955cxtml4ujswzxydd/wss%3A%2F%2Fgit.napplet.soy%2F/n-9753e6cf3ec

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

tests/browser-smoke.mjs
// Integration fixture only: simulates the runtime contract; never shipped in the napplet.
// Run after building: node tests/browser-smoke.mjs
import assert from 'node:assert/strict';
import { readFile, mkdir, realpath } from 'node:fs/promises';
import { createRequire } from 'node:module';
const root = new URL('../', import.meta.url);
const require = createRequire(await realpath(new URL('node_modules/@napplet/conformance-cli/package.json', root)));
const { chromium } = require('playwright');
const artifact = await readFile(new URL('dist/index.html', root), 'utf8');
assert.doesNotMatch(artifact, /<script[^>]+src=/);
assert.doesNotMatch(artifact, /<link[^>]+href=/);
const output = '/private/tmp/drone-zone-qa-v5';
await mkdir(output, { recursive: true });
const browser = await chromium.launch({ headless: true });
const errors = [];
const page = await browser.newPage({viewport:{width:900,height:600},deviceScaleFactor:1});
page.on('pageerror', error => errors.push(error.message));
let mode='dark';
function fixture(mode, absent=false, deny=false, noGL=false, radio={}) {
  return `<script>(${function(mode,absent,deny,noGL,radio) {
    const log=[];window.__testLog=log;
    window.__calloutSizes=new Set();
    const originalDraw=CanvasRenderingContext2D.prototype.drawImage;
    CanvasRenderingContext2D.prototype.drawImage=function(image,...args){
      if(image instanceof HTMLImageElement)window.__calloutSizes.add(`${image.naturalWidth}x${image.naturalHeight}`);
      return originalDraw.call(this,image,...args);
    };
    if(noGL){const original=HTMLCanvasElement.prototype.getContext;HTMLCanvasElement.prototype.getContext=function(type,...args){return type.startsWith('webgl')?null:original.call(this,type,...args);};}
    if(absent){window.napplet={};return;}
    const station={id:'a'.repeat(64),kind:31237,pubkey:'210f31b6019f5ae13c995c8d83faa41a129f1296842e4c3313ab8a4abb09d1a2',created_at:1774180769,tags:[['d','960eb2e9-0601-11e8-ae97-52543be04c81'],['name','Drone Zone']],content:JSON.stringify({streams:[{url:'https://example.org/radio',format:'audio/mpeg',quality:{bitrate:256000},primary:true}]}),sig:'0'.repeat(128)};
    const colors=mode==='dark'?{background:'#05090d',text:'#d6e4e6',primary:'#94d8df'}:{background:'#f4f2e9',text:'#253331',primary:'#306c70'};
    const sub=()=>({close(){log.push(['close']);}});
    let state,capabilities,status='stopped',volume=.65,queries=0,destroyed=false;
    const snapshot=()=>{if(!destroyed)state?.({status,volume});};
    window.__allowAudio=()=>{status='playing';snapshot();};
    window.napplet={
      theme:{get:async()=>({colors}),onChanged:cb=>{window.__theme=cb;return sub();}},
      config:{subscribe:cb=>{window.__config=cb;cb({motion:.6,stars:1,fog:true,distortion:true});return sub();},openSettings:()=>log.push(['settings'])},
      outbox:{query:async(filters,options)=>{log.push(['query',filters,options]);return{events:radio.lookupFailsOnce&&queries++===0?[]:[{event:station}],incomplete:false};}},
      link:{open:async url=>{log.push(['link',url]);return{status:'opened'};}},
      media:{
        createSession:async options=>{
          log.push(['create',options]);
          if(deny)return{error:'Playback denied by test host'};
          if(radio.createDelay)await new Promise(resolve=>setTimeout(resolve,radio.createDelay));
          setTimeout(()=>{
            if(destroyed)return;
            if(options.autoplay){log.push(['autoplay']);status=radio.autoplayBlocked?'paused':'playing';}
            snapshot();
          },30);
          return{sessionId:'test-radio',owner:'shell'};
        },
        onState:(id,callback)=>{state=callback;return sub();},
        onCapabilities:(id,callback)=>{capabilities=callback;setTimeout(()=>capabilities(['play','pause','volume']),10);return sub();},
        sendCommand:(id,action,value)=>{log.push(['command',action,value]);setTimeout(()=>{if(action==='volume')volume=value;else status=action==='pause'?'paused':'playing';snapshot();},20);},
        destroySession:id=>{destroyed=true;log.push(['destroy',id]);},
      }
    };
    if(radio.mediaAbsent)delete window.napplet.media;
  }.toString()})(${JSON.stringify(mode)},${absent},${deny},${noGL},${JSON.stringify(radio)});</script>`;
}
async function load({absent=false,deny=false,noGL=false,...radio}={}) {
  await page.setContent('<style>html,body{margin:0;width:100%;height:100%;overflow:hidden}iframe{display:block;width:100%;height:100%;border:0}</style><iframe sandbox="allow-scripts"></iframe>');
  await page.locator('iframe').evaluate((iframe,src)=>{iframe.srcdoc=src;}, artifact.replace('<head>',`<head>${fixture(mode,absent,deny,noGL,radio)}`));
  const frame=await page.locator('iframe').elementHandle().then(e=>e.contentFrame());
  await frame.locator('#universe').waitFor();await frame.waitForTimeout(450);return frame;
}
try {
  let frame;
  for(mode of ['dark','light']) {
    frame=await load();
    assert.equal(await frame.evaluate(()=>{const gl=document.querySelector('#galaxy').getContext('webgl');return !!gl?.getParameter(gl.CURRENT_PROGRAM);}),true,'galaxy shader compiled and linked');
    for(const [width,height] of [[200,160],[320,560],[900,600],[2400,1200]]) {
      await page.setViewportSize({width,height});await page.waitForTimeout(450);
      const layout=await frame.evaluate(()=>{
        const rect=document.querySelector('#play').getBoundingClientRect();
        return{width:innerWidth,height:innerHeight,overflow:document.documentElement.scrollWidth>innerWidth,play:[rect.left,rect.top,rect.right,rect.bottom],backgrounds:['html','body','#app'].map(s=>getComputedStyle(document.querySelector(s)).backgroundColor)};
      });
      assert.equal(layout.overflow,false);assert.ok(layout.play[0]>=0&&layout.play[1]>=0&&layout.play[2]<=width&&layout.play[3]<=height);
      assert.ok(layout.backgrounds.every(x=>x===layout.backgrounds[0]));
      await page.screenshot({path:`${output}/${mode}-${width}x${height}.png`});
    }
  }
  mode='dark';await page.setViewportSize({width:900,height:600});frame=await load();
  await frame.waitForFunction(()=>document.querySelector('#radio-status').textContent.includes('Live transmission'));
  const initialRadio=await frame.evaluate(()=>window.__testLog);
  assert.equal(initialRadio.filter(x=>x[0]==='create').length,1,'station lookup creates one session without a click');
  assert.equal(initialRadio.find(x=>x[0]==='create')[1].autoplay,true);
  assert.equal(initialRadio.filter(x=>x[0]==='command'&&x[1]==='play').length,0,'autoplay must not send a duplicate play command');
  assert.equal(await frame.locator('#play').getAttribute('aria-label'),'Pause Drone Zone');
  assert.equal(await frame.locator('#tour').getAttribute('aria-pressed'),'true');
  const tourStart=await frame.locator('#position').innerText();await page.waitForTimeout(1000);
  assert.notEqual(await frame.locator('#position').innerText(),tourStart,'The opening tour must move the camera');
  await page.mouse.move(440,280);await page.mouse.down();await page.mouse.up();
  assert.equal(await frame.locator('#tour').getAttribute('aria-pressed'),'false','Pointer takeover must stop the tour');
  await frame.locator('#tour').click();assert.equal(await frame.locator('#tour').getAttribute('aria-pressed'),'true');
  await frame.locator('#zoom-in').click();assert.equal(await frame.locator('#tour').getAttribute('aria-pressed'),'false','Zooming must stop the tour');

  // The final tape treatment includes the live instrument UI and shares the
  // scene's lifecycle. Zero wear, frozen motion and reduced motion stay usable.
  await frame.locator('#layers').click();
  const wear=frame.locator('#tape-wear');
  async function setWear(value) {await wear.evaluate((el,value)=>{el.value=String(value);el.dispatchEvent(new Event('input',{bubbles:true}));},value);}
  await setWear(0);
  assert.equal(await frame.locator('#app').evaluate(el=>getComputedStyle(el).filter),'none');
  assert.equal(await frame.locator('#tape-overlay').isVisible(),false);
  assert.equal(await frame.locator('#tape-pulse').isDisabled(),true);
  await setWear(100);await frame.locator('#tape-pulse').click();
  await frame.waitForFunction(()=>document.querySelector('#app').dataset.tapeGlitch==='true');
  assert.match(await frame.locator('#app').evaluate(el=>getComputedStyle(el).filter),/url\(/);
  assert.equal(await frame.locator('#play').evaluate(el=>el.closest('#app')?.dataset.tapeGlitch),'true','player shares the final surface filter');
  await frame.waitForFunction(()=>document.querySelector('#app').dataset.tapePhase==='chroma');
  assert.match(await frame.locator('#app').evaluate(el=>getComputedStyle(el).filter),/tape-chroma/,'tracking slip resolves into a color echo');
  await page.screenshot({path:`${output}/tape-pulse.png`});
  await frame.waitForFunction(()=>document.querySelector('#app').dataset.tapeGlitch==='false');
  await frame.locator('#tape-pulse').click();await frame.locator('#motion').click();
  await frame.waitForFunction(()=>document.querySelector('#app').dataset.tapeGlitch==='false');
  assert.equal(await frame.locator('#tape-pulse').isDisabled(),true);
  await frame.locator('#motion').click();
  await frame.evaluate(()=>window.__config({motion:.6,stars:1,fog:true,distortion:true,vhs:.25}));
  assert.equal(await wear.inputValue(),'25');
  await setWear(0);await setWear(45);
  await frame.waitForFunction(()=>document.querySelector('#app').dataset.tapeGlitch==='true',{},{timeout:10000});
  await frame.waitForFunction(()=>document.querySelector('#app').dataset.tapeGlitch==='false');
  await frame.locator('#layers').click();

  await frame.locator('#play').click();await frame.waitForFunction(()=>document.querySelector('#radio-status').textContent.startsWith('Paused'));
  await frame.locator('#retry').click();await frame.waitForFunction(()=>document.querySelector('#radio-status').textContent==='Paused');
  assert.equal(await frame.locator('#app').getAttribute('data-playing'),'false','metadata refresh must not restart paused playback');
  await frame.locator('#play').click();await frame.waitForFunction(()=>document.querySelector('#radio-status').textContent.includes('Live transmission'));
  await frame.locator('#play').click();await frame.waitForFunction(()=>document.querySelector('#radio-status').textContent.startsWith('Paused'));
  const log=await frame.evaluate(()=>window.__testLog);
  assert.equal(log.filter(x=>x[0]==='create').length,1,'pause/resume reuses the autoplay session');
  assert.equal(log.find(x=>x[0]==='create')[1].owner,'shell');assert.equal(log.find(x=>x[0]==='create')[1].source.url,'https://example.org/radio');
  assert.ok(log.some(x=>x[0]==='query'&&x[1][0]['#d'][0]==='960eb2e9-0601-11e8-ae97-52543be04c81'));
  await frame.locator('#inspect').click();assert.equal(await frame.locator('#observation-name').innerText(),'THE HYDROGEN LINE');
  await frame.locator('#next').click();assert.equal(await frame.locator('#observation-name').innerText(),'A DISTANCE MADE OF TIME');assert.equal(await frame.locator('#discovery-count').innerText(),'02 / 20');await frame.locator('#close-observation').click();
  await frame.locator('#home').click();await page.waitForTimeout(800);
  const before=await frame.locator('#position').innerText();
  await page.mouse.move(440,280);await page.mouse.down();await page.mouse.move(580,370,{steps:10});await page.mouse.up();await page.waitForTimeout(700);assert.notEqual(await frame.locator('#position').innerText(),before);
  await frame.locator('#universe').focus();await page.keyboard.press('ArrowLeft');
  for(let i=0;i<15;i++)await frame.locator('#zoom-in').click();await page.waitForTimeout(950);assert.equal(await frame.locator('#zoom').innerText(),'3.60×');
  await page.screenshot({path:`${output}/close-up.png`});
  for(let i=0;i<20;i++)await frame.locator('#zoom-out').click();await page.waitForTimeout(950);assert.equal(await frame.locator('#zoom').innerText(),'0.55×');
  await frame.locator('#motion').click();assert.equal(await frame.locator('#motion').getAttribute('aria-pressed'),'true');
  await frame.locator('#layers').click();await frame.locator('#routes').uncheck();await frame.locator('#fog').uncheck();await frame.locator('#layers').click();
  await frame.evaluate(()=>window.__config({motion:0,stars:.2,fog:false,distortion:false}));assert.equal(await frame.locator('#fog').isChecked(),false);assert.equal(await frame.locator('#tour').getAttribute('aria-pressed'),'false');
  assert.equal(await frame.locator('#tape-pulse').isDisabled(),true);
  await frame.evaluate(()=>window.__theme({colors:{background:'#ffffff',text:'#111111',primary:'#335577'}}));assert.equal(await frame.locator('body').evaluate(e=>getComputedStyle(e).backgroundColor),'rgb(255, 255, 255)');
  await frame.evaluate(()=>window.dispatchEvent(new Event('pagehide')));const after=await frame.evaluate(()=>window.__testLog);assert.ok(after.some(x=>x[0]==='destroy'));assert.ok(after.filter(x=>x[0]==='close').length>=4);
  assert.equal(await frame.locator('#tape-overlay').isVisible(),false);
  frame=await load({absent:true});assert.equal(await frame.locator('#play').isDisabled(),true);await frame.locator('#zoom-in').click();await page.waitForTimeout(500);assert.notEqual(await frame.locator('#zoom').innerText(),'1.00×');
  frame=await load({deny:true});await frame.waitForFunction(()=>document.querySelector('#radio-status').textContent.includes('denied'));assert.equal(await frame.locator('#play').isDisabled(),false);
  assert.equal(await frame.evaluate(()=>window.__testLog.filter(x=>x[0]==='create').length),1,'denied autoplay is attempted once');
  await frame.locator('#play').click();assert.equal(await frame.evaluate(()=>window.__testLog.filter(x=>x[0]==='create').length),2,'denied playback remains manually retryable');
  frame=await load({autoplayBlocked:true});assert.equal(await frame.locator('#radio-status').innerText(),'Paused · the field continues');
  assert.equal(await frame.locator('#play').isDisabled(),false);assert.equal(await frame.locator('#app').getAttribute('data-playing'),'false');
  assert.equal(await frame.evaluate(()=>window.__testLog.filter(x=>x[0]==='command'&&x[1]==='play').length),0,'the app must leave the host activation prompt intact');
  await frame.evaluate(()=>window.__allowAudio());assert.match(await frame.locator('#radio-status').innerText(),/Live transmission/);
  frame=await load({lookupFailsOnce:true});assert.equal(await frame.evaluate(()=>window.__testLog.filter(x=>x[0]==='create').length),0);
  await frame.locator('#play').click();await frame.waitForFunction(()=>document.querySelector('#radio-status').textContent.includes('Live transmission'));
  assert.equal(await frame.evaluate(()=>window.__testLog.filter(x=>x[0]==='create').length),1,'retrying station lookup starts once without toggling back to pause');
  frame=await load({mediaAbsent:true});assert.equal(await frame.locator('#radio-status').innerText(),'Listen in Wavefunc ↗');
  assert.equal(await frame.evaluate(()=>window.__testLog.filter(x=>['create','link'].includes(x[0])).length),0,'missing media must not automatically open an external page');
  await frame.locator('#play').click();assert.equal(await frame.evaluate(()=>window.__testLog.filter(x=>x[0]==='link').length),1);
  frame=await load({createDelay:1500});await frame.evaluate(()=>window.dispatchEvent(new Event('pagehide')));
  await frame.waitForFunction(()=>window.__testLog.some(x=>x[0]==='destroy'));
  assert.equal(await frame.evaluate(()=>window.__testLog.filter(x=>x[0]==='destroy').length),1,'late autoplay sessions are destroyed after teardown');
  frame=await load({noGL:true});await page.screenshot({path:`${output}/canvas-fallback.png`});assert.ok(await frame.locator('#signals').evaluate(canvas=>canvas.getContext('2d').getImageData(450,300,1,1).data[3]>0));
  // Observe a real rendered gate-entry flash in the built artwork. This Canvas
  // spy lives only in the test iframe and does not expose a production debug API.
  frame=await load();await frame.locator('#tour').click();
  await frame.evaluate(()=>{
    window.__entryFlashes=[];
    const original=CanvasRenderingContext2D.prototype.createRadialGradient;
    CanvasRenderingContext2D.prototype.createRadialGradient=function(...args){
      if(args[5]>28)window.__entryFlashes.push({x:args[3],y:args[4]});
      return original.apply(this,args);
    };
    window.__config({motion:1,stars:1,fog:true,distortion:true});
  });
  await frame.waitForFunction(()=>window.__entryFlashes.length>0,{},{timeout:25000});
  await frame.evaluate(()=>window.__config({motion:0,stars:1,fog:true,distortion:true}));
  const flash=await frame.evaluate(()=>window.__entryFlashes[0]);
  assert.ok(flash.x>0&&flash.x<900&&flash.y>0&&flash.y<600,'first hypertravel gate is discoverable in the opening view');
  await page.screenshot({path:`${output}/hypertravel.png`});
  await page.setViewportSize({width:1200,height:750});frame=await load();
  await frame.locator('#inspect').click();
  for(let i=0;i<=18;i++) {
    if(i>0)await frame.locator('#next').click();
    if([0,1,5,8,10,16,18].includes(i))await page.waitForTimeout(650);
    if(i===8) {
      for(let zoom=0;zoom<6;zoom++)await frame.locator('#zoom-in').click();await page.waitForTimeout(800);
      await page.screenshot({path:`${output}/orbital-transfer.png`});
    }
    if(i===10)await page.screenshot({path:`${output}/long-gap.png`});
    if(i===18)await page.screenshot({path:`${output}/patience-transfer.png`});
  }
  const images=await frame.evaluate(()=>[...window.__calloutSizes]);
  assert.deepEqual(images.sort(),['708x648','1040x302','368x248','642x554'].sort(),'all four new callout images render at their native aspect ratios');
  await page.emulateMedia({reducedMotion:'reduce'});frame=await load();assert.equal(await frame.locator('#motion').getAttribute('aria-pressed'),'true');assert.equal(await frame.locator('#tour').getAttribute('aria-pressed'),'false');
  assert.equal(await frame.locator('#tape-overlay').isVisible(),false);
  assert.equal(await frame.locator('#app').evaluate(el=>getComputedStyle(el).filter),'none');
  assert.equal(await frame.locator('#tape-pulse').isDisabled(),true);
  assert.deepEqual(errors,[]);
  console.log('PASS: eight frame/theme pairs, automatic tour, manual takeover/resume, pan, expanded bounded zoom, discovery counts, observations, live config/theme, shell-owned autoplay without a click, pause/refresh/resume, denied/blocked autoplay, lookup recovery, absent domains, late-session cleanup, WebGL fallback, all four callout assets, orbital transfers, rendered hypertravel, whole-surface tape wear, automatic/manual tracking slips, wear off, frozen/zero/reduced motion, and teardown.');
  console.log(`Screenshots: ${output}`);
} finally {await browser.close();}