// Position — first-person, earned-authority narrative. // The 18 years as preparation, not pedigree. function Position() { const { lang } = React.useContext(window.LangContext); const { isMobile, isTablet } = window.useBreakpoint(); const [vw, setVw] = React.useState(window.innerWidth); React.useEffect(() => { const h = () => setVw(window.innerWidth); window.addEventListener('resize', h, { passive: true }); return () => window.removeEventListener('resize', h); }, []); const [refH2, visH2] = window.useReveal(); const [refStats, visStats] = window.useReveal({ threshold: 0.08 }); const [refDiagram, visDiagram] = window.useReveal({ threshold: 0.15 }); const statConfig = [ { target: 18, fmt: function(n) { return String(n); } }, { target: 11, fmt: function(n) { return String(n); } }, { target: 100, fmt: function(n) { return n + "+"; } }, { target: 1, fmt: function(n) { return (n < 10 ? "0" : "") + n; } }, ]; const [animCounts, setAnimCounts] = React.useState([0, 0, 0, 0]); React.useEffect(function() { if (!visStats) { setAnimCounts([0, 0, 0, 0]); return; } var dur = 1800, startTime = null; var targets = [18, 11, 100, 1]; function step(ts) { if (!startTime) startTime = ts; var progress = Math.min((ts - startTime) / dur, 1); var eased = 1 - Math.pow(1 - progress, 3); setAnimCounts(targets.map(function(t) { return Math.round(eased * t); })); if (progress < 1) requestAnimationFrame(step); } var raf = requestAnimationFrame(step); return function() { cancelAnimationFrame(raf); }; }, [visStats]); const en = { eyebrow: "07 · Position", h2line1: "Between domain,", h2line2: "technology, and leadership.", subtitle: "My strength is understanding and translating between these levels.", body1: "What users need, what domain teams know, what IT must secure, what developers can build, and which decisions leadership needs to make.", body3: "Live production is an extreme form of systems thinking: zero fault tolerance, real-time decisions, all departments that need to work simultaneously.", body4: "That is exactly what AI systems in production require: they need to work under pressure, be understood by people with different backgrounds — and still deliver clear results.", body5: "That creates a workflow that makes sense for everyone and actually works.", pills: ["Systems Thinking", "Technical Conception", "Custom UI & Interaction", "Interactive Live Systems"], bridgeLabel: "The bridge, in plain terms", bridge: [ { before: "Director", after: "Management", label: "Outcomes & intent" }, { before: "Creatives", after: "Domain experts", label: "How the work actually happens" }, { before: "Tech department", after: "IT & engineering", label: "What the stack can safely carry" }, { before: "Show safety", after: "Legal & governance", label: "What must be auditable, by when" }, ], thenLabel: "Then", nowLabel: "Now", nodes: ["Domain", "IT", "Development", "Management", "Project Lead", "Users"], stats: [ ["18", "Years in live production"], ["11", "Years leading motion & interactive development"], ["100+", "Productions delivered under live conditions"], ["01", "Focus: systems built for production"], ], }; const de = { eyebrow: "07 · Positionierung", h2line1: "Zwischen Fachbereich,", h2line2: "Technik und Führung.", subtitle: "Meine Stärke ist es, die unterschiedlichen Sprachen dieser Ebenen zu verstehen und zu übersetzen.", body1: "Was Nutzer brauchen, was Fachbereiche wissen, was IT absichern muss, was Entwickler umsetzen können und welche Entscheidungen das Management treffen muss.", body3: "Live-Produktion ist eine Extremform von Systemdenken: Keine Fehlertoleranz, Entscheidungen in Echtzeit, alle Gewerke, die gleichzeitig funktionieren müssen.", body4: "Genau das ist die Anforderung an KI-Systeme im Betrieb: Sie müssen unter Druck funktionieren, von Menschen mit unterschiedlichem Hintergrund verstanden werden — und trotzdem klare Ergebnisse liefern.", body5: "So entsteht ein Ablauf, der für alle sinnvoll ist und funktioniert.", pills: ["Systemdenken", "Technische Konzeption", "Custom UI & Interaction", "Interaktive Live-Systeme"], bridgeLabel: "Die Verbindung, in klaren Worten", bridge: [ { before: "Regie", after: "Management", label: "Ziele & Absichten" }, { before: "Kreative", after: "Fachexperten", label: "Wie Arbeit wirklich funktioniert" }, { before: "Technik", after: "IT & Engineering", label: "Was der Stack leisten kann" }, { before: "Show-Sicherheit", after: "Legal & Governance", label: "Was dokumentiert werden muss" }, ], thenLabel: "Damals", nowLabel: "Heute", nodes: ["Fachbereich", "IT", "Entwicklung", "Management", "Projektleitung", "Nutzer"], stats: [ ["18", "Jahre in Event-Produktion"], ["11", "Jahre Interactive-Entwicklung"], ["100+", "Produktionen unter Live-Bedingungen realisiert"], ["01", "Fokus: Systeme, die in der Produktion funktionieren"], ], }; const t = lang === 'de' ? de : en; return (
{/* Blob-iridescent as background gravity */}
07
{t.eyebrow}

{t.h2line1}
{t.h2line2}

{/* Left: key sentence + body + pills */}

{t.subtitle}

{t.body1}

{t.body2}

{t.body3 && (

{t.body3}

)} {t.body4 && (

{t.body4}

)}
{t.pills.map(p => ( {p} ))}
{/* Right: stakeholder network — rich circular diagram */}
{(() => { const cx = 550, cy = 390, R = 246, nodeR = 43, innerR = 91, arrowSz = 6; const angles = [0,1,2,3,4,5].map(i => -Math.PI/2 + i * Math.PI * 2 / 6); const pts = angles.map(a => ({ x: cx + R * Math.cos(a), y: cy + R * Math.sin(a) })); const colors = ['#06b6d4','#8b5cf6','#f97316','#eab308','#22c55e','#0db8cc']; const adjPairs = [[0,1],[1,2],[2,3],[3,4],[4,5],[5,0]]; const nodeData = lang === 'de' ? [ { label: "Fachbereich", sub: ["Prozesse verstehen.", "Domänenwissen kennen."] }, { label: "IT", sub: ["Machbarkeit prüfen.", "Sicherheit gewährleisten."] }, { label: "Entwicklung", sub: ["Anforderungen strukturieren.", "Bauplan schaffen."] }, { label: "Management", sub: ["Entscheidungen treffen.", "Wert schaffen."] }, { label: "Projektleitung",sub: ["Ablauf steuern.", "Ergebnisse liefern."] }, { label: "Nutzer", sub: ["Intuitiv nutzbar machen.", "Alltag erleichtern."] }, ] : [ { label: "Domain", sub: ["Understand processes.", "Know the domain."] }, { label: "IT", sub: ["Check feasibility.", "Ensure security."] }, { label: "Development", sub: ["Structure requirements.", "Create blueprint."] }, { label: "Management", sub: ["Make decisions.", "Create value."] }, { label: "Project Lead", sub: ["Manage workflow.", "Deliver outcomes."] }, { label: "Users", sub: ["Make it intuitive.", "Ease daily work."] }, ]; const centerText = lang === 'de' ? ["KLARHEIT", "VERBINDET"] : ["CLARITY", "CONNECTS"]; const lc = [ { anchor: "middle", lx: pts[0].x, ly: pts[0].y - nodeR - 24 }, { anchor: "start", lx: pts[1].x + nodeR + 16, ly: pts[1].y - 14 }, { anchor: "start", lx: pts[2].x + nodeR + 16, ly: pts[2].y - 14 }, { anchor: "middle", lx: pts[3].x, ly: pts[3].y + nodeR + 32 }, { anchor: "end", lx: pts[4].x - nodeR - 16, ly: pts[4].y - 14 }, { anchor: "end", lx: pts[5].x - nodeR - 16, ly: pts[5].y - 14 }, ]; const icon = (i, col) => { const s = { stroke: col, fill: "none", strokeWidth: 1.6, strokeLinecap: "round", strokeLinejoin: "round" }; if (i === 0) return ; if (i === 1) return ; if (i === 2) return ; if (i === 3) return ; if (i === 4) return ; return ; }; // Convert SVG coords to % of viewBox (viewBox: "0 -30 1100 830") const toP = (x, y) => ({ left: `${(x / 1100 * 100).toFixed(2)}%`, top: `${((y + 30) / 830 * 100).toFixed(2)}%`, }); const labelTransforms = [ "translateX(-50%) translateY(-100%)", // 0 top — bottom of div sits at coord "translateY(-50%)", // 1 right-top — vertically centered "translateY(-50%)", // 2 right-bottom "translateX(-50%)", // 3 bottom — top of div sits at coord "translateX(-100%) translateY(-50%)", // 4 left-bottom "translateX(-100%) translateY(-50%)", // 5 left-top ]; const labelAligns = ["center","left","left","center","right","right"]; return (
{adjPairs.map(([i,j], k) => ( ))} {pts.map((p, i) => { const dx = p.x - cx, dy = p.y - cy; const len = Math.sqrt(dx*dx + dy*dy); const nx = dx/len, ny = dy/len; const x1 = cx + nx * innerR, y1 = cy + ny * innerR; const x2 = p.x - nx * (nodeR + 3), y2 = p.y - ny * (nodeR + 3); const px = -ny * arrowSz * 0.55, py = nx * arrowSz * 0.55; return ( ); })} {adjPairs.map(([i,j], k) => ( ))} {pts.map((p, i) => ( {icon(i, colors[i])} ))} {centerText[0]} {centerText[1]} {/* HTML labels — full HD only; laptop and below get legend grid */} {!isMobile && !isTablet && vw >= 1440 && lc.map((l, i) => (
{nodeData[i].label}
{nodeData[i].sub.map((s, si) => (
{s}
))}
))}
); })()} {/* Node legend — mobile, tablet, and laptop (below Full HD) */} {(isMobile || isTablet || vw < 1440) && (() => { const colors = ['#06b6d4','#8b5cf6','#f97316','#eab308','#22c55e','#0db8cc']; const nodeData = lang === 'de' ? [ { label: "Fachbereich" }, { label: "IT" }, { label: "Entwicklung" }, { label: "Management" }, { label: "Projektleitung" }, { label: "Nutzer" }, ] : [ { label: "Domain" }, { label: "IT" }, { label: "Development" }, { label: "Management" }, { label: "Project Lead" }, { label: "Users" }, ]; return (
{nodeData.map((nd, i) => (
{nd.label}
))}
); })()}
{/* Stats strip */}
{t.stats.map(([n, l], idx) => (
{statConfig[idx].fmt(animCounts[idx])}
{l}
))}
); } window.Position = Position;