// Draw the background-field layer: large, quiet graphics that sit BEHIND content. // usage: yarn node - < make-fields.cjs // // This is a third layer, distinct from the two props.md already defines. Props are the // content; accents (Handcrafts doodles, our sparkle) are marks around it and are capped at // "icon-to-inline size, not hero scale". Neither covers a section background, so these fill // that gap rather than duplicating either. // // Every motif comes from the brand's own world rather than generic geometry: the shelf wall // that doc 07 calls the retail wedge's "visual signature", the paper bag that is our motif, // the shopfront awning and shutter, the counter. Drawn in code, not generated, so they are // reproducible, tiny, and tint from a token like everything else. // // All ship in currentColor. They are BACKGROUNDS, so they must stay quiet enough to put text // on — doc 07 requires text to sit on a ground-toned scrim, never on busy texture. Use them // at low opacity (0.06-0.14 is the working range) and keep the busy area away from the copy. const fs = require('node:fs'); const path = require('node:path'); const OUT = process.argv[2]; fs.mkdirSync(OUT, { recursive: true }); const svg = (vb, body, note) => `\n\n${body}\n\n`; const files = {}; // A tile only repeats cleanly if anything crossing an edge also appears on the opposite one. // Without this the seam shows as a row of half-cut boxes, which is what the first pass did. function wrapX(w, x, width, emit) { const out = [emit(x)]; if (x < 0) out.push(emit(x + w)); if (x + width > w) out.push(emit(x - w)); return out; } // 1. Shelf wall — doc 07: "shelf density is the visual signature" of the retail wedge. // Tiles horizontally and vertically. { const rows = [0, 60, 120].map((y) => { const boxes = []; let x = 6 + (y / 60) * 11; while (x < 240) { const w = 14 + ((x + y) % 23); const h = 18 + ((x * 7 + y) % 14); boxes.push(...wrapX(240, x, w, (bx) => ``)); x += w + 9; } return `\n ${boxes.join('\n ')}`; }); files['shelf-wall.svg'] = svg('0 0 240 180', ' ' + rows.join('\n '), 'Shelf wall — tiles on 240x180. Retail density, the store wedge signature.'); } // 2. Paper-bag fold — the logo's own motif. One large shape for a section corner. { const body = ` `; files['bag-fold.svg'] = svg('0 0 300 120', body, 'Paper-bag fold — the logo motif as a section top edge. Anchor to a full-bleed top.'); } // 3. Awning scallop — the shopfront edge. Tiles horizontally. { const n = 6, w = 240, r = w / n / 2; const arcs = Array.from({ length: n }, (_, i) => `A${r} ${r} 0 0 0 ${(i + 1) * r * 2} 0`).join(' '); files['awning.svg'] = svg('0 0 240 40', ` \n` + ` `, 'Awning scallop — tiles horizontally on 240. Sits on a section top or bottom edge.'); } // 4. Shutter ribs — the rolling shutter every Indian shopfront has. Tiles horizontally. { const ribs = Array.from({ length: 8 }, (_, i) => ``).join('\n '); files['shutter.svg'] = svg('0 0 240 200', ' ' + ribs, 'Shutter ribs — tiles horizontally on 240. Vertical, so keep copy clear of it.'); } // 5. Tile grid — floor tiles. The quietest of the set; safe directly under text. { const dots = []; for (let y = 0; y < 4; y++) for (let x = 0; x < 4; x++) { const cx = (x * 40 + 20 + (y % 2) * 20) % 160, cy = y * 40 + 20; const r = 2.4 + ((x + y) % 3) * 0.7; for (const dx of (cx < r ? [0, 160] : cx > 160 - r ? [0, -160] : [0])) { dots.push(``); } } files['tile-grid.svg'] = svg('0 0 160 160', ' ' + dots.join('\n '), 'Tile grid — tiles on 160. Quietest of the set; safe directly beneath copy.'); } // 6. Counter line — a surface with the companion's own ground shadow under it, so a figure // standing on it belongs to the same room. ry 9 and 0.13 opacity are cast.md rule 3's // numbers, reused deliberately rather than re-picked. { const body = ` `; files['counter-line.svg'] = svg('0 0 360 44', body, 'Counter line — ry 9 at 0.13 opacity, the same ground shadow cast.md rule 3 gives every figure.'); } for (const [name, content] of Object.entries(files)) { fs.writeFileSync(path.join(OUT, name), content); console.log(` ${name.padEnd(18)} ${content.length} bytes`); }