| 1 | <!doctype html> |
| 2 | <meta charset="utf-8"> |
| 3 | <title>pet · cross-platform tape</title> |
| 4 | <style> |
| 5 | body { margin: 0; background: #06080d; color: #9fb4c4; font: 12px/1.4 ui-monospace, monospace } |
| 6 | #cap { position: fixed; left: 10px; bottom: 8px; } |
| 7 | canvas { display: block; } |
| 8 | </style> |
| 9 | <canvas id="c"></canvas> |
| 10 | <div id="cap"></div> |
| 11 | <script type="module"> |
| 12 | import { PetSim } from './dist/PetSim.js'; |
| 13 | import { drawPet } from './dist/web.js'; |
| 14 | |
| 15 | const points = (await (await fetch('whale-points.tsv')).text()) |
| 16 | .trim().split('\n').map(l => l.split('\t').map(Number)); |
| 17 | const rows = (await (await fetch('tape.tsv')).text()) |
| 18 | .trim().split('\n').slice(1).map(l => l.split('\t')); |
| 19 | |
| 20 | const cv = document.getElementById('c'), ctx = cv.getContext('2d'); |
| 21 | const cap = document.getElementById('cap'); |
| 22 | const W = 900, H = 420; |
| 23 | cv.width = W; cv.height = H; |
| 24 | |
| 25 | const sim = new PetSim(points); |
| 26 | const motion = !matchMedia('(prefers-reduced-motion: reduce)').matches; |
| 27 | let i = 0; |
| 28 | |
| 29 | // Step the sim at the tape's recorded cadence (30fps), looped. |
| 30 | // ?frame=N renders a single frame and stops — for screenshots and diffs. |
| 31 | const single = new URLSearchParams(location.search).get('frame'); |
| 32 | |
| 33 | function rowToState(c) { |
| 34 | return { activity: +c[1], coherence: +c[2], attention: +c[3], channel: c[4], |
| 35 | observed: +c[5], roamX: +c[6], roamY: +c[7], flip: +c[8], lit: +c[9] }; |
| 36 | } |
| 37 | |
| 38 | if (single !== null) { |
| 39 | const target = +single; |
| 40 | for (i = 0; i <= target && i < rows.length; i++) sim.step(+rows[i][0], rowToState(rows[i]), { motion: true, sensitivity: 1 }); |
| 41 | draw(); |
| 42 | } else { |
| 43 | (function tick() { |
| 44 | const c = rows[i % rows.length]; |
| 45 | sim.step(+c[0], rowToState(c), { motion, sensitivity: 1 }); |
| 46 | draw(); |
| 47 | i++; |
| 48 | requestAnimationFrame(tick); |
| 49 | })(); |
| 50 | } |
| 51 | |
| 52 | function draw() { |
| 53 | const st = rowToState(rows[(single !== null ? i - 1 : i) % rows.length]); |
| 54 | ctx.fillStyle = '#06080d'; |
| 55 | ctx.fillRect(0, 0, W, H); |
| 56 | drawPet(ctx, sim, st, W, H); |
| 57 | const f = sim.frame; |
| 58 | cap.textContent = `frame ${i - 1} · ${f.channel} · ${f.arch}${f.hollow ? ' · unobserved' : ''}`; |
| 59 | } |
| 60 | window.__pet = { sim, i }; |
| 61 | </script> |
| 62 |