/* StudioCanvas — contemporary-art background layer.
*
* Replaces the old grid. Scatters hand-drawn-style squiggles, outlined shapes,
* asterisks, crescents, dot clusters, and edge wave ribbons across the viewport.
*
* Design discipline:
* - Deterministic: ELEMENTS is a fixed list. No randomness. Tweak positions here.
* - Corner-clustered: most density at TL/TR/BL/BR + edge ribbons; center viewport
* is nearly empty so body text never competes with art.
* - Low opacity (set in CSS via --art-opacity) so it reads as texture, not content.
* - Three tones reuse existing tokens: red #ff6b8a, yellow #f0c674, blue #7cb0ff.
*
* ViewBox is 1600x1200 with preserveAspectRatio="xMidYMid slice" so the SVG fills
* any window size. Elements positioned in viewBox coordinates.
*/
const STUDIO_TONES = {
r: '#ff6b8a', // red
y: '#f0c674', // yellow
b: '#7cb0ff', // blue
};
/* ---------- Element catalog — tweak here to adjust the layout ---------- */
const STUDIO_ELEMENTS = [
// ── TOP-LEFT cluster ────────────────────────────────────────────────
{ k:'squiggle', d:'M20,60 C80,20 140,100 200,60 S320,80 380,40', tone:'r', sw:1.8 },
{ k:'circle', cx:70, cy:40, r:22, tone:'b', dashed:true },
{ k:'circle', cx:300, cy:180, r:14, tone:'y' },
{ k:'triangle', cx:400, cy:120, size:20, tone:'y', rot:15 },
{ k:'plus', cx:360, cy:100, size:14, tone:'r' },
{ k:'asterisk', cx:180, cy:220, size:12, tone:'b' },
{ k:'dots', cx:220, cy:50, dots:[[0,0,'r'],[10,6,'b'],[-6,12,'y'],[4,-8,'r']] },
// ── TOP-RIGHT cluster ───────────────────────────────────────────────
{ k:'squiggle', d:'M1220,150 C1280,100 1360,170 1440,110 S1540,160 1580,90', tone:'b', sw:1.6 },
{ k:'circle', cx:1480, cy:50, r:30, tone:'r', dashed:true },
{ k:'circle', cx:1280, cy:180, r:18, tone:'y' },
{ k:'triangle', cx:1380, cy:220, size:30, tone:'y', rot:-10 },
{ k:'plus', cx:1260, cy:40, size:18, tone:'y' },
{ k:'asterisk', cx:1560, cy:180, size:16, tone:'r' },
// ── BOTTOM-LEFT cluster ─────────────────────────────────────────────
{ k:'squiggle', d:'M20,1090 C100,1050 160,1130 240,1080 S340,1120 380,1070', tone:'y', sw:1.8 },
{ k:'circle', cx:60, cy:1140, r:26, tone:'r' },
{ k:'circle', cx:320, cy:1000, r:14, tone:'b', dashed:true },
{ k:'triangle', cx:180, cy:1050, size:40, tone:'b', rot:25 },
{ k:'crescent', cx:280, cy:1170, r:24, tone:'y' },
{ k:'asterisk', cx:100, cy:1020, size:14, tone:'y' },
{ k:'dots', cx:350, cy:1150, dots:[[0,0,'r'],[8,-6,'b'],[-10,4,'r']] },
// ── BOTTOM-RIGHT cluster ────────────────────────────────────────────
{ k:'squiggle', d:'M1220,1050 C1300,1090 1380,1020 1460,1060 S1540,1030 1580,1070', tone:'r', sw:1.6 },
{ k:'circle', cx:1480, cy:1160, r:22, tone:'y', dashed:true },
{ k:'circle', cx:1280, cy:980, r:16, tone:'b' },
{ k:'triangle', cx:1560, cy:1080, size:36, tone:'r', rot:-20 },
{ k:'crescent', cx:1240, cy:1120, r:22, tone:'y' },
{ k:'plus', cx:1420, cy:1000, size:16, tone:'y' },
{ k:'asterisk', cx:1380, cy:1170, size:14, tone:'b' },
// ── LEFT edge ribbon (y 300-900) ────────────────────────────────────
{ k:'squiggle', d:'M40,600 C80,540 40,680 120,640', tone:'b', sw:1.4 },
{ k:'asterisk', cx:120, cy:450, size:12, tone:'y' },
{ k:'dots', cx:60, cy:500, dots:[[0,0,'b'],[8,8,'y'],[-4,14,'b']] },
// ── RIGHT edge ribbon (y 300-900) ───────────────────────────────────
{ k:'squiggle', d:'M1500,550 C1550,470 1580,580 1560,480', tone:'y', sw:1.4 },
{ k:'asterisk', cx:1560, cy:400, size:12, tone:'r' },
{ k:'dots', cx:1500, cy:800, dots:[[0,0,'r'],[-10,-6,'y'],[6,10,'b'],[14,0,'r']] },
// ── CENTER (whisper-quiet — 3 elements max) ─────────────────────────
{ k:'crescent', cx:800, cy:600, r:18, tone:'y' },
{ k:'plus', cx:600, cy:320, size:10, tone:'b' },
{ k:'asterisk', cx:1000, cy:880, size:10, tone:'r' },
// ── WAVE BARS (horizontal sines at top + bottom edges) ──────────────
{ k:'wave', y:28, tone:'b', sw:1.2, amp:10, period:160 },
{ k:'wave', y:1182, tone:'r', sw:1.2, amp:10, period:200 },
];
/* ---------- Element renderers ---------- */
const StudioSquiggle = ({ d, tone, sw }) => (
);
const StudioCircle = ({ cx, cy, r, tone, dashed }) => (
);
const StudioTriangle = ({ cx, cy, size, tone, rot = 0 }) => {
const h = size * Math.sqrt(3) / 2;
const pts = `${cx},${cy-h*0.66} ${cx-size/2},${cy+h*0.33} ${cx+size/2},${cy+h*0.33}`;
return ;
};
const StudioAsterisk = ({ cx, cy, size, tone }) => (
);
const StudioPlus = ({ cx, cy, size, tone }) => (
);
const StudioCrescent = ({ cx, cy, r, tone }) => {
// Outer arc then inner arc offset, forming a crescent outline
const d = `M${cx-r},${cy} A${r},${r} 0 0,1 ${cx+r},${cy} A${r*0.75},${r*0.6} 0 0,0 ${cx-r},${cy} Z`;
return ;
};
const StudioDots = ({ cx, cy, dots }) => (
{dots.map(([dx, dy, tone], i) => (
))}
);
const StudioWave = ({ y, tone, sw, amp, period }) => {
// Build a sine-like cubic-Bézier path across the full 1600 viewBox width.
let d = `M0,${y}`;
for (let x = 0; x < 1600; x += period) {
d += ` C${x + period/4},${y - amp} ${x + 3*period/4},${y + amp} ${x + period},${y}`;
}
return ;
};
/* ---------- Kind → renderer dispatch ---------- */
const STUDIO_RENDERERS = {
squiggle: StudioSquiggle,
circle: StudioCircle,
triangle: StudioTriangle,
asterisk: StudioAsterisk,
plus: StudioPlus,
crescent: StudioCrescent,
dots: StudioDots,
wave: StudioWave,
};
/* ---------- Main component ---------- */
const StudioCanvas = () => (
);
/* ---------- Mount into its own root (separate from the React app) ---------- */
const __studioCanvasRoot = document.getElementById('studio-canvas-root');
if (__studioCanvasRoot) {
ReactDOM.createRoot(__studioCanvasRoot).render();
}
window.StudioCanvas = StudioCanvas;