Top: a graph's past holds still — columns draw the peak of their own fixed slice of history
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
be0f2a5aaf
commit
ec94cb8bff
@@ -0,0 +1,42 @@
|
||||
// node scripts/test-graphcols.mjs — the rule in src/graphcols.ts, on a curve scrolled one point at a time.
|
||||
// (No test runner in this project: esbuild, which vite already brings, turns the one file into something node can load.)
|
||||
import { buildSync } from 'esbuild'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { mkdtempSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
|
||||
const out = join(mkdtempSync(join(tmpdir(), 'graphcols-')), 'graphcols.mjs')
|
||||
buildSync({ entryPoints: [new URL('../src/graphcols.ts', import.meta.url).pathname], outfile: out, format: 'esm', logLevel: 'error' })
|
||||
const { columnsOf } = await import(pathToFileURL(out).href)
|
||||
|
||||
const fails = []
|
||||
const check = (ok, what, detail) => { if (!ok) fails.push(what + (detail !== undefined ? ' — ' + JSON.stringify(detail).slice(0, 200) : '')) }
|
||||
const CAP = 300, COLS = 90 // the net graph: 300 points of history in about 90 dot-columns
|
||||
const base = Array.from({ length: CAP }, (_, i) => (i === 100 ? 900 : i === 180 ? 500 : i === 251 ? 700 : 10))
|
||||
const spikes = (cols) => cols.filter((v) => v > 100).sort((a, b) => b - a).join(',')
|
||||
|
||||
// what Top drew before 2026-09-21: the nearest point for each column, counted from the right edge
|
||||
const nearest = (values, cap, cols) => { const n = Math.min(values.length, cap), seen = []; for (let c = 0; c < cols; c++) { const i = Math.floor((c * cap) / cols) - (cap - n); if (i >= 0) seen.push(values[values.length - n + i]) } return seen }
|
||||
|
||||
let values = base.slice(), advance = CAP - 1, prev = null
|
||||
const oldShapes = new Set(), newShapes = new Set()
|
||||
for (let step = 0; step < 40; step++) {
|
||||
oldShapes.add(spikes(nearest(values, CAP, COLS)))
|
||||
const cols = columnsOf(values, advance, CAP, COLS)
|
||||
newShapes.add(spikes(cols))
|
||||
if (prev) check([0, 1].some((sh) => cols.slice(0, -1).every((v, j) => prev[j + sh] === undefined || prev[j + sh] === v)), `frame ${step} is the one before, slid left by a column at most`)
|
||||
prev = cols
|
||||
values.push(10); values.shift(); advance++
|
||||
}
|
||||
check(oldShapes.size > 1, 'the test reproduces the fault it guards against (spikes flickering under nearest-point drawing)', [...oldShapes])
|
||||
check(newShapes.size === 1 && [...newShapes][0] === '900,700,500', 'every spike is drawn, at its height, on every frame', [...newShapes])
|
||||
check(columnsOf(base, CAP - 1, CAP, COLS).length === COLS, 'a full curve fills the box')
|
||||
const young = columnsOf(base.slice(-30), 29, CAP, COLS).length
|
||||
check(young >= 8 && young <= 10, 'a tenth of a history takes a tenth of the box, from the right', young)
|
||||
const wide = columnsOf(base, CAP - 1, CAP, 390)
|
||||
check(wide.length === 390 && Math.max(...wide) === 900, 'a box wider than the history is filled, nothing invented', wide.length)
|
||||
check(columnsOf([], 0, CAP, COLS).length === 0 && columnsOf([5], 0, 2, 50).length >= 1, 'empty and single-point curves')
|
||||
|
||||
if (fails.length) { console.error('graphcols: FAIL\n ' + fails.join('\n ')); process.exit(1) }
|
||||
console.log('graphcols: ok')
|
||||
Reference in New Issue
Block a user