Fence syntax bench

Draft test bench for the unified fence grammar: f= names, run / run=name, update-lines, and override persistence. Not for publishing.

Every mechanism of the unified grammar, one section each, so a glance says whether it still works. This is a draft β€” it never hits a public feed.

html Β· setup
<link rel="stylesheet" href="/demo/reset.css">
<script src="https://cdn.jsdelivr.net/npm/p5@2.3.0/lib/p5.min.js"></script>

1. f=name run β€” name a file and run it

f=orbits names this content orbits; run also runs it here (code + result).

orbits Β· js file
const N = 26
let SPEED = 0.6
function setup() { createCanvas(480, 240) }
function draw() {
  background(22, 19, 16)
  colorMode(HSB, 360, 100, 100)
  noStroke()
  for (let i = 0; i < N; i++) {
    const a = millis() * 0.001 * SPEED + i / N * TWO_PI
    const x = width / 2 + cos(a) * (30 + i * 6)
    const y = height / 2 + sin(a * 1.3) * 90
    fill(i / N * 360, 70, 90)
    circle(x, y, 10)
  }
}

2. run=name β€” replay, result only

Empty body β†’ just the result (the code is already above).

js Β· run orbits

3. run=name + a one-line update

js Β· run orbits
- let SPEED = 0.6
+ let SPEED = 2.4

4. run=name + a multi-line update

js Β· run orbits
-  const x = width / 2 + cos(a) * (30 + i * 6)
-  const y = height / 2 + sin(a * 1.3) * 90
+  const x = width / 2 + cos(a) * (60 + i * 3)
+  const y = height / 2 + sin(a * 2.1) * 70

5. override β€” persist the update to the file

This replay bumps the count to 80 and writes the result back to orbits:

js Β· run orbits
- const N = 26
+ const N = 80

6. …and the next replay sees 80

A plain run=orbits now β€” no update β€” should already be 80 dots, proof the override persisted (v1 β†’ v2). Stack a SPEED update on top β†’ 80 and fast (compounding v2 β†’ v3):

js Β· run orbits
- let SPEED = 0.6
+ let SPEED = 3.0

7. f=name as data + fetch()

palette.json is a virtual file β€” not run, just fetched by the demo below.

palette.json Β· json file
["#d4a24e", "#83A598", "#FE8019", "#8EC07C"]
js Β· run
async function setup() {
  createCanvas(480, 160)
  window.PAL = await (await fetch('palette.json')).json()
  noLoop()
}
function draw() {
  noStroke()
  PAL.forEach((c, i) => { fill(c); rect(i * width / PAL.length, 0, width / PAL.length, height) })
}

8. hide + show=

run hide runs but keeps the code hidden; show= windows the shown lines of a plain block.

js
// line 1 β€” hidden by show=
const kept = 'lines 2 and 3 only'
const also = 'still runs + copies in full'
// line 5 β€” hidden

9. Pure insertion β€” anchor on context, no -

An update needs an anchor, not a removal. Hang a + off an unprefixed context line and it inserts with nothing taken out β€” here a translate slips in right after background, so the whole swarm drifts side to side. A context-less + block would warn nothing to anchor to instead.

js Β· run orbits
  background(22, 19, 16)
+ translate(sin(millis() * 0.001) * 40, 0)

10. ... gap β€” two far-apart edits in one patch

A ... on its own line skips any number of lines, so one fence can change two regions without pasting everything between them. Here: speed up and fatten the dots β€” anchors far apart in orbits, matched in order, the gap untouched.

js Β· run orbits
- let SPEED = 0.6
+ let SPEED = 2.5
...
-     circle(x, y, 10)
+     circle(x, y, 22)

11. patch β€” a slice that knows where it is

No -, no +, nothing changes. patch on the header says the body is a patch anyway, so those lines anchor into orbits and the gutter numbers them where they live in the file β€” not 1, 2. The header reads patch, not variant.

orbits Β· js file
    const x = width / 2 + cos(a) * (30 + i * 6)
    const y = height / 2 + sin(a * 1.3) * 90

12. ~ β€” rewrite a whole block

A rewritten function as a - per old line and a + per new one is a wall of red the reader has to climb. ~ names the block, and what follows stands in its place β€” pasted once, no marker inside it. Bare ~ would find draw from the new text itself; here the prefix is written out, which is what you do when two lines start alike.

js Β· run orbits
~ function draw(
function draw(){
  background(22, 19, 16)
  colorMode(HSB, 360, 100, 100)
  noStroke()
  for (let i = 0; i < N; i++) {
    const a = millis() * 0.001 * SPEED + i / N * TWO_PI
    fill(i / N * 360, 70, 90)
    circle(width / 2 + cos(a) * (40 + i * 5), height / 2 + sin(a) * (40 + i * 5), 12)
  }
}