oxedyne/daimond/dev/shot_permchip_ladder.mjs
2.8 KiB, 1 run
created by r2519314175:169, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | // shot_permchip_ladder.mjs — the same chip at several nudges, 8x, stacked. |
| 2 | // |
| 3 | // The numbers in shot_permchip.mjs say where each band is; they cannot say which |
| 4 | // band looks right, and that is a judgement that has to be made by looking. This |
| 5 | // renders the chip at a ladder of offsets, magnifies each nearest-neighbour, and |
| 6 | // stacks them with their values, for each of the three labels in turn. |
| 7 | // |
| 8 | // node dev/shot_permchip_ladder.mjs → dev/shots/permchip-ladder.png |
| 9 | import fs from 'node:fs'; |
| 10 | import path from 'node:path'; |
| 11 | import { fileURLToPath } from 'node:url'; |
| 12 | import { open, chat } from './harness.mjs'; |
| 13 | |
| 14 | const HERE = path.dirname(fileURLToPath(import.meta.url)); |
| 15 | const SHOTS = path.join(HERE, 'shots'); |
| 16 | fs.mkdirSync(SHOTS, { recursive: true }); |
| 17 | |
| 18 | const NUDGES = [-0.5, 0, 0.25, 0.5, 1]; |
| 19 | const LABELS = ['Guarded', 'Bypass', 'Ask every time']; |
| 20 | |
| 21 | const s = await open({ name: 'permladder' }); |
| 22 | const p = s.page; |
| 23 | await chat(s, '@text hello'); |
| 24 | |
| 25 | const shots = []; |
| 26 | for (const label of LABELS) { |
| 27 | for (const n of NUDGES) { |
| 28 | await p.evaluate(({ label, n }) => { |
| 29 | document.getElementById('hand-mode-chip-txt').textContent = label; |
| 30 | document.querySelector('.mode-chip-dot').style.transform = `translateY(${n}px)`; |
| 31 | }, { label, n }); |
| 32 | await p.waitForTimeout(80); |
| 33 | shots.push({ label, n, png: (await p.locator('#hand-mode-chip').screenshot()).toString('base64') }); |
| 34 | } |
| 35 | } |
| 36 | // Put the chip back the way the stylesheet has it. |
| 37 | await p.evaluate(() => { |
| 38 | document.querySelector('.mode-chip-dot').style.transform = ''; |
| 39 | document.getElementById('hand-mode-chip-txt').textContent = 'Guarded'; |
| 40 | }); |
| 41 | |
| 42 | await p.evaluate(async (shots) => { |
| 43 | const imgs = []; |
| 44 | for (const s of shots) { |
| 45 | const im = new Image(); |
| 46 | await new Promise((res) => { im.onload = res; im.src = 'data:image/png;base64,' + s.png; }); |
| 47 | imgs.push(im); |
| 48 | } |
| 49 | const S = 8, PAD = 10, LAB = 130; |
| 50 | const w = LAB + Math.max(...imgs.map(i => i.width)) * S + PAD * 2; |
| 51 | const h = imgs.reduce((a, i) => a + i.height * S + PAD, PAD); |
| 52 | const c = document.createElement('canvas'); |
| 53 | c.id = '__ladder'; c.width = w; c.height = h; |
| 54 | c.style.cssText = 'position:fixed;left:0;top:0;z-index:99999;'; |
| 55 | const g = c.getContext('2d'); |
| 56 | g.imageSmoothingEnabled = false; |
| 57 | g.fillStyle = '#606060'; g.fillRect(0, 0, w, h); |
| 58 | let y = PAD; |
| 59 | imgs.forEach((im, i) => { |
| 60 | g.drawImage(im, LAB, y, im.width * S, im.height * S); |
| 61 | g.fillStyle = '#fff'; g.font = '16px monospace'; |
| 62 | g.fillText(`${shots[i].n >= 0 ? '+' : ''}${shots[i].n}px`, 8, y + 24); |
| 63 | g.fillText(shots[i].label.slice(0, 9), 8, y + 44); |
| 64 | // A hairline through the middle of each strip, so the eye has a datum. |
| 65 | y += im.height * S + PAD; |
| 66 | }); |
| 67 | document.body.appendChild(c); |
| 68 | }, shots); |
| 69 | await p.locator('#__ladder').screenshot({ path: path.join(SHOTS, 'permchip-ladder.png') }); |
| 70 | await s.close(); |
| 71 | console.log('wrote dev/shots/permchip-ladder.png'); |