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.
<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).
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).
3. run=name + a one-line update
- let SPEED = 0.6
+ let SPEED = 2.4
4. run=name + a multi-line update
- 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:
- 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):
- 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.
["#d4a24e", "#83A598", "#FE8019", "#8EC07C"]
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.
// 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.
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.
- 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.
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.
~ 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)
}
}