/* eslint-disable */ const { useState: enS, useMemo: enM, useRef: enR, useEffect: enE } = React; // Hand-placed positions on a 1000x600 canvas (no physics; deterministic) const NODES = { p_mert: { x: 360, y: 230, color: "var(--ember)" }, p_leyla: { x: 580, y: 150, color: "var(--plum)" }, p_arda: { x: 760, y: 360, color: "var(--moss)" }, p_aysel: { x: 200, y: 410, color: "var(--gold)" }, p_kaan: { x: 470, y: 470, color: "var(--sky)" }, p_irem: { x: 240, y: 130, color: "var(--ruby)" }, p_renee: { x: 800, y: 130, color: "var(--ink-2)" }, p_dmitri: { x: 870, y: 240, color: "var(--ink-3)" }, }; const EDGES = [ { a:"p_mert", b:"p_leyla", type:"ex-lover", strength:0.9, since:"8 yr", note:"Üniversite. Ayrıldıktan sonra bir kez konuştular." }, { a:"p_mert", b:"p_aysel", type:"mentor", strength:0.7, since:"life", note:"Aysel hanım Mert'in lise edebiyat öğretmeniydi." }, { a:"p_mert", b:"p_irem", type:"client", strength:0.5, since:"6 mo", note:"Mert haftada bir görüşmeye gidiyor; kabullenmiyor." }, { a:"p_leyla", b:"p_arda", type:"sibling", strength:0.95, since:"birth", note:"Anne aynı, baba farklı. Yıllarca konuşmadılar." }, { a:"p_leyla", b:"p_kaan", type:"source", strength:0.6, since:"2 yr", note:"Kaan, Leyla'nın gizli kaynağı; mahalleyi anlatıyor." }, { a:"p_arda", b:"p_renee", type:"acquaintance",strength:0.3, since:"3 yr", note:"Lyon'da bir konferansta tanıştılar." }, { a:"p_renee", b:"p_dmitri", type:"rival", strength:0.55, since:"15 yr", note:"Bir aşçılık yarışmasında jüri ikilemi." }, { a:"p_aysel", b:"p_kaan", type:"family", strength:0.85, since:"life", note:"Aysel hanım Kaan'ın anneannesi." }, { a:"p_irem", b:"p_leyla", type:"friend", strength:0.7, since:"4 yr", note:"Yoga sınıfında tanışmışlar." }, { a:"p_mert", b:"p_dmitri", type:"correspondent",strength:0.4, since:"2 yr", note:"Mektupla satranç oynuyorlar." }, ]; const REL_COLOR = { "ex-lover": "var(--ruby)", "mentor": "var(--gold)", "client": "var(--plum)", "sibling": "var(--ember)", "source": "var(--sky)", "acquaintance": "var(--ink-3)", "rival": "var(--ruby)", "family": "var(--moss)", "friend": "var(--moss)", "correspondent": "var(--ink-2)", }; const REL_DASH = { "ex-lover": "4 4", "acquaintance": "2 6", "correspondent": "1 4", "rival": "8 4", }; const PageEnsemble = ({ go }) => { const personas = D.personas; const byId = enM(()=>Object.fromEntries(personas.map(p=>[p.id,p])), [personas]); const [selected, setSelected] = enS("p_mert"); const [edgeHover, setEdgeHover] = enS(null); const [filter, setFilter] = enS(new Set()); const [scenarioOpen, setScenarioOpen] = enS(false); const [castIds, setCastIds] = enS(["p_mert","p_leyla"]); const [scenarioSetting, setScenarioSetting] = enS("Beyoğlu, sahafın arka odası, 22:00."); const openScenario = (ids, setting) => { if (ids) setCastIds(ids); if (setting) setScenarioSetting(setting); setScenarioOpen(true); }; const toggleCast = (id) => { setCastIds(prev => prev.includes(id) ? prev.filter(x=>x!==id) : [...prev, id]); }; const visibleEdges = enM(()=>( filter.size === 0 ? EDGES : EDGES.filter(e => filter.has(e.type)) ), [filter]); const sel = byId[selected]; const selEdges = EDGES.filter(e => e.a === selected || e.b === selected); const toggleFilter = (t) => { const n = new Set(filter); if (n.has(t)) n.delete(t); else n.add(t); setFilter(n); }; const allTypes = [...new Set(EDGES.map(e=>e.type))]; return (
Studio · Ensemble

The cast, in relation. 10 ties across 8 personas — three of them, complicated.

Drag a thread to ground a multi-persona scenario. Conflicts surface when two personas you're casting share a wound.
{/* Filter bar */}
Filter ties: {allTypes.map(t => { const active = filter.size===0 || filter.has(t); return ( toggleFilter(t)} className="tag" style={{ cursor:"pointer", opacity: active?1:0.4, fontSize:11, borderColor: REL_COLOR[t], color: REL_COLOR[t], background: `color-mix(in oklch, ${REL_COLOR[t]} 10%, transparent)` }}> {t} ); })} {visibleEdges.length}/{EDGES.length} edges {filter.size>0 && setFilter(new Set())} className="muted" style={{fontSize:11, cursor:"pointer", textDecoration:"underline"}}>clear}
{/* Graph canvas */}
Ensemble graph · workspace
Click a node to inspect. Hover an edge for context.
{["all","clusters","arcs"].map((m,i)=>( {m} ))}
{/* Edges */} {visibleEdges.map((e,i)=>{ const a = NODES[e.a], b = NODES[e.b]; const mx = (a.x+b.x)/2, my=(a.y+b.y)/2; const isHover = edgeHover === i; const isSel = e.a===selected || e.b===selected; const c = REL_COLOR[e.type] || "var(--ink-3)"; return ( setEdgeHover(i)} onMouseLeave={()=>setEdgeHover(null)} style={{cursor:"pointer"}}> {(isHover||isSel) && ( {e.type} )} ); })} {/* Nodes */} {personas.map(p => { const n = NODES[p.id]; if (!n) return null; const isSel = selected === p.id; const initials = p.name.split(" ").map(w=>w[0]).slice(0,2).join(""); return ( setSelected(p.id)}> {isSel && } {initials} {p.name.split(" ")[0]} {p.archetype.replace("The ","")} ); })} {/* Legend */}
thicker = stronger tie
distant / dormant
focused persona
{/* Right panel — selected persona */}
{sel && (
portrait
focused
{sel.name}
{sel.tagline}
{sel.archetype} {sel.lang}
{selEdges.length} relationships
{selEdges.map((e,i) => { const otherId = e.a===selected ? e.b : e.a; const o = byId[otherId]; const c = REL_COLOR[e.type]; return (
setSelected(otherId)} style={{ padding:"10px 12px", border:"1px solid var(--line)", borderRadius:"var(--r-md)", background:"var(--bg-2)", cursor:"pointer", borderLeft: `3px solid ${c}` }}>
{o?.name}
{e.type}
{e.note}
since {e.since} strength {Math.round(e.strength*100)}
); })}
)} {/* Scenario suggestions */}
Suggested scenes
{[ {ids:["p_mert","p_leyla"], who:"Mert × Leyla", note:"Ex-lovers run into each other at a book fair.", ten:"high", set:"Kadıköy kitap fuarı, kapanışa yarım saat."}, {ids:["p_aysel","p_kaan"], who:"Aysel × Kaan", note:"Grandmother gives the taxi-driver grandson advice on a long ride.", ten:"warm", set:"İzmir → Eskişehir, gece otoyolu, 03:10."}, {ids:["p_leyla","p_arda"], who:"Leyla × Arda", note:"Estranged siblings forced to settle a parent's estate.", ten:"high", set:"Bir noter ofisi, Ankara, sabah."}, {ids:["p_mert","p_dmitri","p_renee"], who:"Mert × Dmitri × Renée", note:"Three strangers locked into a small dinner party.", ten:"awkward", set:"Lyon, 8 kişilik masada üç sandalye boş."}, ].map((s,i)=>(
openScenario(s.ids, s.set)} style={{padding:"10px 12px", border:"1px solid var(--line)", borderRadius:"var(--r-md)", background:"var(--bg-2)", cursor:"pointer"}}>
{s.who}
{s.ten}
{s.note}
))}
{/* Stats row */}
Personas in graph
8
+1 this week
Relationships
10
3 strong, 4 weak
Tightest cluster
Mert · Leyla · Arda
density 0.83
Orphans
0
fully connected
{/* Scenario modal */} {scenarioOpen && (
setScenarioOpen(false)}>
e.stopPropagation()} style={{width:620}}>

New ensemble scenario

setScenarioOpen(false)} style={{cursor:"pointer", color:"var(--ink-3)", fontSize:18}}>×
Pick 2–4 personas and a setting. Persona will run a multi-agent rehearsal and surface conflicts before you commit.
{personas.map(p => { const on = castIds.includes(p.id); return ( toggleCast(p.id)} className={"tag "+(on?"ember":"")} style={{cursor:"pointer", fontSize:11, opacity: on?1:0.55}}> {p.name} ); })}
setScenarioSetting(e.target.value)}/>
)}
); }; window.PageEnsemble = PageEnsemble;