[object Object]

← back to Ticket System

canvas-design: LUMEN INDEX plate — Fleet Office as a scientific light-survey (philosophy .md + rendered .png)

9e4763775ec5efb44b2cd64fcff622150a839f2a · 2026-07-27 08:49:31 -0700 · Steve Abrams

Movement 'Lumen Index' (the survey of ordered light). Museum-plate composition:
4 fields (10/16/11/24 cells echoing the live board), 48 operator points, 8 transit
arcs, ticket-rule anchor 'nothing moves that is not first recorded.' Fonts: Jura /
IBM Plex Mono / Instrument Serif. Rendered via Playwright at 2.5x.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 9e4763775ec5efb44b2cd64fcff622150a839f2a
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jul 27 08:49:31 2026 -0700

    canvas-design: LUMEN INDEX plate — Fleet Office as a scientific light-survey (philosophy .md + rendered .png)
    
    Movement 'Lumen Index' (the survey of ordered light). Museum-plate composition:
    4 fields (10/16/11/24 cells echoing the live board), 48 operator points, 8 transit
    arcs, ticket-rule anchor 'nothing moves that is not first recorded.' Fonts: Jura /
    IBM Plex Mono / Instrument Serif. Rendered via Playwright at 2.5x.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 marketing/canvas/lumen-index.plate.html | 171 ++++++++++++++++++++++++++++++++
 marketing/canvas/lumen-index.png        | Bin 0 -> 2757417 bytes
 2 files changed, 171 insertions(+)

diff --git a/marketing/canvas/lumen-index.plate.html b/marketing/canvas/lumen-index.plate.html
new file mode 100644
index 0000000..09ad752
--- /dev/null
+++ b/marketing/canvas/lumen-index.plate.html
@@ -0,0 +1,171 @@
+<!doctype html><html><head><meta charset="utf-8">
+<style>
+  @font-face{ font-family:'Jura'; src:url('file:///Users/macstudio3/.claude/skills/canvas-design/canvas-fonts/Jura-Light.ttf'); font-weight:300 }
+  @font-face{ font-family:'Jura'; src:url('file:///Users/macstudio3/.claude/skills/canvas-design/canvas-fonts/Jura-Medium.ttf'); font-weight:500 }
+  @font-face{ font-family:'PlexMono'; src:url('file:///Users/macstudio3/.claude/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf') }
+  @font-face{ font-family:'InstrSerif'; src:url('file:///Users/macstudio3/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf'); font-style:italic }
+  html,body{margin:0;background:#06070c}
+  #plate{width:1400px;height:1900px}
+</style></head>
+<body>
+<div id="plate"></div>
+<script>
+const W=1400,H=1900;
+const NS='http://www.w3.org/2000/svg';
+// palette
+const GROUND='#06070c', BONE='#e7ebf2', FAINT='rgba(146,154,172,0.62)', HAIR='rgba(146,154,172,0.30)', TICK='rgba(146,154,172,0.55)';
+const LANES=[
+  {roman:'I',   n:10, c:'#6d93c4', label:'FIELD I'},
+  {roman:'II',  n:16, c:'#c47d86', label:'FIELD II'},
+  {roman:'III', n:11, c:'#9aa4b8', label:'FIELD III'},
+  {roman:'IV',  n:24, c:'#6db89a', label:'FIELD IV'},
+];
+const VIOLET='#a892d4';
+// deterministic RNG (LCG)
+let _s=1337; const rnd=()=>{ _s=(_s*1103515245+12345)&0x7fffffff; return _s/0x7fffffff; };
+const rr=(a,b)=>a+(b-a)*rnd();
+
+let s='';
+const A=(x)=>{ s+=x; };
+const esc=t=>String(t).replace(/&/g,'&amp;').replace(/</g,'&lt;');
+function line(x1,y1,x2,y2,stroke,w=1,op=1,dash){ A(`<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${stroke}" stroke-width="${w}" opacity="${op}"${dash?` stroke-dasharray="${dash}"`:''}/>`); }
+function txt(x,y,t,{f='Jura',s:sz=13,fill=BONE,ls=0,anchor='start',op=1,weight=300,style=''}={}){
+  A(`<text x="${x}" y="${y}" font-family="${f}" font-size="${sz}" fill="${fill}" opacity="${op}" letter-spacing="${ls}" text-anchor="${anchor}" font-weight="${weight}" font-style="${style}">${esc(t)}</text>`);
+}
+function cross(x,y,r=6,stroke=TICK,w=1){ line(x-r,y,x+r,y,stroke,w); line(x,y-r,x,y+r,stroke,w); }
+
+// ── defs: glow + halo gradient ──
+A(`<svg width="${W}" height="${H}" viewBox="0 0 ${W} ${H}" xmlns="${NS}">`);
+A(`<defs>
+  <filter id="glow" x="-60%" y="-60%" width="220%" height="220%"><feGaussianBlur stdDeviation="3.2" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
+  <filter id="soft" x="-120%" y="-120%" width="340%" height="340%"><feGaussianBlur stdDeviation="6"/></filter>
+  <radialGradient id="vig" cx="50%" cy="40%" r="70%"><stop offset="0%" stop-color="#0b0e16"/><stop offset="100%" stop-color="#06070c"/></radialGradient>
+</defs>`);
+A(`<rect width="${W}" height="${H}" fill="url(#vig)"/>`);
+
+// ── frame (double rule) + registration crosses ──
+const fx0=150,fy0=150,fx1=1250,fy1=1750;
+A(`<rect x="${fx0}" y="${fy0}" width="${fx1-fx0}" height="${fy1-fy0}" fill="none" stroke="${HAIR}" stroke-width="1"/>`);
+A(`<rect x="${fx0+11}" y="${fy0+11}" width="${fx1-fx0-22}" height="${fy1-fy0-22}" fill="none" stroke="${HAIR}" stroke-width="0.6" opacity="0.7"/>`);
+[[fx0,fy0],[fx1,fy0],[fx0,fy1],[fx1,fy1]].forEach(([x,y])=>cross(x,y,9,HAIR,0.8));
+
+// ── header apparatus ──
+txt(fx0+4,132,'INDEX OF ORDERED LIGHT',{f:'Jura',s:12,fill:FAINT,ls:6,weight:500});
+txt(fx1-4,132,'PL. IV',{f:'PlexMono',s:12,fill:FAINT,anchor:'end',ls:2});
+txt(700,205,'PLATE IV · AN ONGOING SURVEY',{f:'PlexMono',s:11.5,fill:FAINT,anchor:'middle',ls:4});
+line(fx0+11,225,fx1-11,225,HAIR,0.6,0.7);
+
+// ── title ──
+txt(700,320,'LUMEN INDEX',{f:'Jura',s:62,fill:BONE,anchor:'middle',ls:17,weight:300});
+txt(700,364,'index luminum',{f:'InstrSerif',s:24,fill:FAINT,anchor:'middle',style:'italic'});
+line(620,392,780,392,HAIR,0.8);
+
+// ── field geometry ──
+const fieldTop=470, laneCX=[400,600,800,1000], cellW=100, cellH=14, pitch=24;
+// faint lane guides + a unifying survey datum across the field head
+laneCX.forEach(cx=>line(cx,fieldTop-8,cx,fieldTop+24*pitch,'rgba(146,154,172,0.06)',0.8));
+line(348,fieldTop-3,1052,fieldTop-3,'rgba(146,154,172,0.16)',0.7);
+
+// cell records — collect centers for point/arc anchoring
+const cellCenters=[];
+LANES.forEach((L,li)=>{
+  const cx=laneCX[li];
+  // lane header
+  txt(cx,fieldTop-30,L.roman,{f:'Jura',s:18,fill:L.c,anchor:'middle',ls:2,weight:500,op:0.95});
+  for(let i=0;i<L.n;i++){
+    const y=fieldTop+i*pitch;
+    const x=cx-cellW/2;
+    // brightness: a few cells 'active' — quiet plotted records, not bars
+    const active = rnd()<0.20;
+    const baseOp = active? 0.26 : (0.08+0.06*rnd());
+    A(`<rect x="${x}" y="${y}" width="${cellW}" height="${cellH}" rx="2.5" fill="${L.c}" opacity="${baseOp}"/>`);
+    A(`<rect x="${x}" y="${y}" width="${cellW}" height="${cellH}" rx="2.5" fill="none" stroke="${L.c}" stroke-width="0.6" opacity="${active?0.9:0.34}"/>`);
+    // thin inner tick (a 'record' entered)
+    line(x+7,y+cellH/2,x+7+ (active?15:6),y+cellH/2, L.c, 0.7, active?0.85:0.42);
+    cellCenters.push({x:cx,y:y+cellH/2,c:L.c,li});
+    // catalogue index every 4th cell
+    if(i%4===0){
+      const rightmost = li===3;
+      txt(rightmost? x-8 : x+cellW+8, y+cellH-3, String(li+1)+'.'+String(i).padStart(2,'0'),
+        {f:'PlexMono',s:8.5,fill:FAINT,anchor:rightmost?'end':'start',op:0.8});
+    }
+  }
+  // lane census at foot
+  txt(cx,fieldTop+L.n*pitch+22,'n='+L.n,{f:'PlexMono',s:10,fill:FAINT,anchor:'middle',ls:1});
+});
+
+// ── left ruler ──
+const rulerX=278, rTop=fieldTop-4, rBot=fieldTop+24*pitch;
+line(rulerX,rTop,rulerX,rBot,HAIR,0.8);
+for(let y=rTop,k=0;y<=rBot;y+=12.5,k++){ const big=k%8===0; line(rulerX,y,rulerX+(big?12:6),y,TICK,big?1:0.6,big?0.8:0.5);
+  if(big) txt(rulerX-8,y+3,String(k).padStart(2,'0'),{f:'PlexMono',s:8,fill:FAINT,anchor:'end',op:0.7}); }
+
+// ── operator points (48) ──
+const pts=[];
+for(let i=0;i<48;i++){
+  const src=cellCenters[(rnd()*cellCenters.length)|0];
+  const x=src.x + rr(-cellW/2+8, cellW/2-8);
+  const y=src.y + rr(-2,2) + (rnd()<0.3? rr(-pitch,pitch):0);
+  pts.push({x,y,c:src.c});
+  A(`<circle cx="${x}" cy="${y}" r="6.5" fill="${src.c}" opacity="0.14" filter="url(#soft)"/>`);
+  A(`<circle cx="${x}" cy="${y}" r="2.1" fill="${BONE}" opacity="0.92" filter="url(#glow)"/>`);
+}
+// a few labelled operators
+const labelIdx=[4,12,19,27,35,44];
+labelIdx.forEach((pi,n)=>{ const p=pts[pi]; const dx=(n%2?1:-1)*22, dy=(n<3?-1:1)*14;
+  line(p.x,p.y,p.x+dx,p.y+dy,FAINT,0.6,0.7);
+  txt(p.x+dx+(dx>0?4:-4), p.y+dy+3, 'op·'+String(17+n*3), {f:'PlexMono',s:8.5,fill:FAINT,anchor:dx>0?'start':'end',op:0.85});
+});
+
+// ── transit arcs (8) ──
+for(let i=0;i<8;i++){
+  let a=pts[(rnd()*pts.length)|0], b=pts[(rnd()*pts.length)|0];
+  let guard=0; while(Math.abs(a.x-b.x)<140 && guard++<12) b=pts[(rnd()*pts.length)|0];
+  const mx=(a.x+b.x)/2, my=(a.y+b.y)/2 - (60+Math.abs(a.x-b.x)*0.16);
+  A(`<path d="M ${a.x} ${a.y} Q ${mx} ${my} ${b.x} ${b.y}" fill="none" stroke="${VIOLET}" stroke-width="0.8" opacity="0.55"/>`);
+  A(`<circle cx="${mx}" cy="${(a.y+b.y)/2 - (30+Math.abs(a.x-b.x)*0.08)}" r="1.4" fill="${VIOLET}" opacity="0.8"/>`);
+  txt(mx+5,(a.y+b.y)/2 - (30+Math.abs(a.x-b.x)*0.08)+3,'t·'+String(i+1).padStart(2,'0'),{f:'PlexMono',s:7.5,fill:VIOLET,op:0.7});
+}
+
+// ── divider before apparatus ──
+line(fx0+11,1200,fx1-11,1200,HAIR,0.6,0.7);
+
+// ── legend / key ──
+const lx=300, ly=1258; const keyRows=[
+  ['UNIT','a task held in the field', LANES[0].c, 'cell'],
+  ['OPERATOR','a mover of light', BONE, 'point'],
+  ['TRANSIT','a message in passage', VIOLET, 'arc'],
+  ['RECORD','entered, never erased', FAINT, 'tick'],
+];
+txt(lx,ly-24,'KEY',{f:'Jura',s:12,fill:FAINT,ls:6,weight:500});
+keyRows.forEach((r,i)=>{ const y=ly+i*30; const gx=lx+10;
+  if(r[3]==='cell'){ A(`<rect x="${gx-8}" y="${y-9}" width="26" height="12" rx="2.5" fill="${r[2]}" opacity="0.4"/>`);A(`<rect x="${gx-8}" y="${y-9}" width="26" height="12" rx="2.5" fill="none" stroke="${r[2]}" stroke-width="0.6" opacity="0.8"/>`);}
+  else if(r[3]==='point'){ A(`<circle cx="${gx+4}" cy="${y-3}" r="5" fill="${r[2]}" opacity="0.14" filter="url(#soft)"/>`);A(`<circle cx="${gx+4}" cy="${y-3}" r="2" fill="${BONE}" opacity="0.9" filter="url(#glow)"/>`);}
+  else if(r[3]==='arc'){ A(`<path d="M ${gx-8} ${y-1} Q ${gx+4} ${y-14} ${gx+18} ${y-1}" fill="none" stroke="${VIOLET}" stroke-width="0.9" opacity="0.7"/>`);}
+  else { line(gx-8,y-3,gx-8,y+3,r[2],1,0.7); line(gx-2,y-3,gx-2,y+3,r[2],1,0.7); line(gx+4,y-3,gx+4,y+3,r[2],1,0.7); }
+  txt(lx+40,y-4,r[0],{f:'Jura',s:12.5,fill:BONE,ls:3,weight:500,op:0.92});
+  txt(lx+40,y+9,r[1],{f:'InstrSerif',s:13,fill:FAINT,style:'italic'});
+});
+
+// coordinate block (right, mirrors the key)
+const cxx=1100;
+txt(cxx,ly-24,'COORDINATES',{f:'Jura',s:12,fill:FAINT,ls:5,weight:500,anchor:'end'});
+[['decl.','+34.05'],['h.a.','−118.24'],['epoch','append-only'],['plate','iv / ∞']].forEach((r,i)=>{ const y=ly+i*30;
+  txt(cxx-96,y,r[0],{f:'PlexMono',s:10,fill:FAINT,op:0.8});
+  txt(cxx,y,r[1],{f:'PlexMono',s:10.5,fill:BONE,anchor:'end',op:0.9});
+});
+
+// ── anchor phrase ──
+txt(700,1462,'nothing moves that is not first recorded.',{f:'InstrSerif',s:32,fill:BONE,anchor:'middle',style:'italic',op:0.94});
+line(640,1492,760,1492,HAIR,0.7);
+
+// ── bottom caption + signature ──
+txt(700,1672,'fig. iv — distribution of luminous units across four ordered fields · n = 61 · observed by patient attention',
+  {f:'PlexMono',s:10,fill:FAINT,anchor:'middle',ls:1,op:0.85});
+txt(fx1-4,1712,'— L.I.',{f:'InstrSerif',s:16,fill:FAINT,anchor:'end',style:'italic'});
+txt(fx0+4,1712,'graphite / bone / four accents',{f:'PlexMono',s:9,fill:FAINT,op:0.7});
+
+A('</svg>');
+document.getElementById('plate').innerHTML=s;
+</script>
+</body></html>
diff --git a/marketing/canvas/lumen-index.png b/marketing/canvas/lumen-index.png
new file mode 100644
index 0000000..02b6c23
Binary files /dev/null and b/marketing/canvas/lumen-index.png differ

← 85274f3 auto-save: 2026-07-27T08:49:12 (1 files) — marketing/canvas/  ·  back to Ticket System  ·  office: seat working agents in their doing room (rank active ee1e135 →