Skill_Type_Simulation / index.html
eaglelandsonce's picture
Update index.html
9b02e56 verified
Raw History Blame Contribute Delete
27.1 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The Five Core Skill Patterns - Interactive Simulation</title>
<style>
:root {
--bg: #0b0f19;
--card: #131b2e;
--border: #1e293b;
--text: #f8fafc;
--text-muted: #94a3b8;
--info: #3b82f6;
--tool: #64748b;
--gen: #f59e0b;
--review: #ef4444;
--workflow: #22c55e;
}
* { box-sizing: border-box; margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
body { background-color: var(--bg); color: var(--text); padding: 20px; line-height: 1.5; }
.container { max-width: 1200px; margin: 0 auto; display: flex; flex-direction: column; gap: 20px; }
/* Header */
.header {
background: var(--card);
border: 1px solid var(--border);
border-radius: 16px;
padding: 20px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: 16px;
box-shadow: 0 10px 25px -5px rgba(0,0,0,0.4);
}
.title-group h1 { font-size: 1.5rem; font-weight: 700; display: flex; align-items: center; gap: 10px; }
.status-dot { width: 10px; height: 10px; background: #10b981; border-radius: 50%; display: inline-block; box-shadow: 0 0 10px #10b981; }
.title-group p { color: var(--text-muted); font-size: 0.9rem; margin-top: 4px; }
/* Controls */
.controls { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
button, select {
background: #1e293b;
color: #f1f5f9;
border: 1px solid #334155;
padding: 8px 14px;
border-radius: 8px;
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
}
button:hover { background: #334155; }
button.btn-primary { background: #059669; border-color: #10b981; color: white; }
button.btn-primary:hover { background: #10b981; }
button.btn-pause { background: #d97706; border-color: #f59e0b; color: white; }
button.btn-pause:hover { background: #f59e0b; }
/* Layout */
.main-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 20px; }
@media (max-width: 900px) { .main-grid { grid-template-columns: 1fr; } }
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 16px;
padding: 20px;
box-shadow: 0 10px 25px -5px rgba(0,0,0,0.3);
}
/* Stage Header */
.stage-indicator {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid var(--border);
padding-bottom: 12px;
margin-bottom: 16px;
font-size: 0.85rem;
}
.badge {
display: inline-block;
padding: 3px 10px;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.badge-info { background: rgba(59, 130, 246, 0.2); color: #60a5fa; border: 1px solid rgba(59, 130, 246, 0.4); }
.badge-gen { background: rgba(245, 158, 11, 0.2); color: #fbbf24; border: 1px solid rgba(245, 158, 11, 0.4); }
.badge-tool { background: rgba(100, 116, 139, 0.2); color: #cbd5e1; border: 1px solid rgba(100, 116, 139, 0.4); }
.badge-review { background: rgba(239, 68, 68, 0.2); color: #f87171; border: 1px solid rgba(239, 68, 68, 0.4); }
.badge-workflow { background: rgba(34, 197, 94, 0.2); color: #4ade80; border: 1px solid rgba(34, 197, 94, 0.4); }
/* SVG Styles */
svg { width: 100%; height: auto; user-select: none; }
.cursor-pointer { cursor: pointer; }
@keyframes pulseNode {
0%, 100% { filter: drop-shadow(0 0 4px rgba(59, 130, 246, 0.5)); }
50% { filter: drop-shadow(0 0 16px rgba(59, 130, 246, 1)); }
}
.node-active { animation: pulseNode 1.2s infinite ease-in-out; }
/* Log & Inspector */
.log-container {
margin-top: 16px;
background: #090d16;
border: 1px solid #1e293b;
border-radius: 10px;
padding: 12px;
font-family: monospace;
font-size: 0.8rem;
height: 120px;
overflow-y: auto;
}
.log-item { margin-bottom: 4px; color: #cbd5e1; }
.log-pass { color: #34d399; font-weight: bold; }
.log-fail { color: #f87171; font-weight: bold; }
.inspector-row { margin-bottom: 14px; }
.inspector-label { font-size: 0.7rem; font-weight: 700; color: #64748b; text-transform: uppercase; margin-bottom: 2px; }
.inspector-val { font-size: 0.85rem; color: #e2e8f0; }
.code-box {
background: #090d16;
border: 1px solid #1e293b;
padding: 10px;
border-radius: 8px;
font-family: monospace;
font-size: 0.78rem;
color: #94a3b8;
margin-top: 4px;
}
.pattern-btn-list { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }
.btn-pattern-select {
background: #0f172a;
border: 1px solid #1e293b;
padding: 8px 12px;
border-radius: 8px;
display: flex;
justify-content: space-between;
align-items: center;
text-align: left;
font-size: 0.8rem;
}
.btn-pattern-select:hover { border-color: #475569; background: #1e293b; }
</style>
</head>
<body>
<div class="container">
<!-- Header -->
<header class="header">
<div class="title-group">
<h1><span class="status-dot"></span> The Five Core Skill Patterns</h1>
<p>Interactive Architecture & Lifecycle Simulation (Zero External Dependencies)</p>
</div>
<div class="controls">
<button id="btnPlay" class="btn-primary">β–Ά Run Simulation</button>
<button id="btnStep">⏭ Step</button>
<button id="btnReset">β†Ί Reset</button>
<select id="scenarioSelect">
<option value="happy">✨ Happy Path (Pass First Try)</option>
<option value="fail_retry">πŸ” Reviewer Failure & Auto-Revision</option>
<option value="strict">πŸ›‘οΈ Strict Security Gate</option>
</select>
</div>
</header>
<!-- Main Grid -->
<div class="main-grid">
<!-- Canvas / Simulation Diagram -->
<div class="card">
<div class="stage-indicator">
<div>
<span style="color: var(--text-muted);">Current Phase:</span>
<span id="phaseBadge" class="badge badge-workflow">Ready</span>
</div>
<div style="font-size: 0.8rem; color: var(--text-muted);">Click any node to inspect details</div>
</div>
<!-- SVG Diagram -->
<svg id="simSvg" viewBox="0 0 820 520">
<defs>
<filter id="glow">
<feGaussianBlur stdDeviation="3" result="coloredBlur"/>
<feMerge>
<feMergeNode in="coloredBlur"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
<marker id="arrow" viewBox="0 0 10 10" refX="6" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 1 L 10 5 L 0 9 z" fill="#475569" />
</marker>
<marker id="arrow-green" viewBox="0 0 10 10" refX="6" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 1 L 10 5 L 0 9 z" fill="#22c55e" />
</marker>
<marker id="arrow-red" viewBox="0 0 10 10" refX="6" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 1 L 10 5 L 0 9 z" fill="#ef4444" />
</marker>
</defs>
<!-- Flow Connectors -->
<g stroke="#334155" stroke-width="2" fill="none" stroke-dasharray="4,4">
<path d="M 170 85 L 280 85" marker-end="url(#arrow)" />
<path d="M 520 120 L 410 120" marker-end="url(#arrow)" />
<path d="M 610 145 L 610 220 L 390 220 L 390 250" marker-end="url(#arrow)" />
<path d="M 350 145 L 350 250" marker-end="url(#arrow)" />
<path d="M 450 290 L 530 290" marker-end="url(#arrow)" />
<path d="M 640 335 L 640 410 L 440 410" marker-end="url(#arrow)" />
<!-- Reviewer Loop back to Generator -->
<path d="M 280 410 L 220 410 L 220 290 L 270 290" stroke="#ef4444" stroke-width="2" marker-end="url(#arrow-red)" />
<!-- Reviewer Pass to Goal -->
<path d="M 360 450 L 360 490 L 670 490" stroke="#22c55e" stroke-width="2.5" marker-end="url(#arrow-green)" />
</g>
<!-- 🟒 WORKFLOW Container -->
<rect x="230" y="20" width="570" height="465" rx="16" fill="rgba(34, 197, 94, 0.04)" stroke="#22c55e" stroke-width="2" />
<rect x="245" y="10" width="260" height="24" rx="6" fill="#14532d" stroke="#22c55e" stroke-width="1.5" />
<text x="255" y="26" fill="#86efac" font-size="11" font-weight="bold">🟒 WORKFLOW (Lifecycle Orchestrator)</text>
<!-- Trigger -->
<g id="node_trigger" class="cursor-pointer" onclick="inspect('trigger')">
<rect x="20" y="60" width="150" height="50" rx="25" fill="#581c87" stroke="#a855f7" stroke-width="2" />
<text x="95" y="85" fill="#f3e8ff" font-size="11" font-weight="bold" text-anchor="middle">⚑ User Request</text>
<text x="95" y="100" fill="#d8b4fe" font-size="9" text-anchor="middle">Task Trigger</text>
</g>
<!-- πŸ”΅ INFORMATIONAL Skill -->
<g id="node_info" class="cursor-pointer" onclick="inspect('info')">
<rect x="520" y="50" width="250" height="95" rx="12" fill="#1e293b" stroke="#3b82f6" stroke-width="2.5" />
<rect x="520" y="50" width="250" height="26" rx="12" fill="#1e3a8a" />
<text x="645" y="68" fill="#93c5fd" font-size="11" font-weight="bold" text-anchor="middle">πŸ”΅ INFORMATIONAL SKILL</text>
<text x="535" y="94" fill="#cbd5e1" font-size="10">β€’ Architecture Standards</text>
<text x="535" y="112" fill="#cbd5e1" font-size="10">β€’ API Contracts & Constraints</text>
<text x="535" y="130" fill="#cbd5e1" font-size="10">β€’ Domain Context & Schemas</text>
</g>
<!-- Stage 1 -->
<g id="node_s1" class="cursor-pointer" onclick="inspect('workflow')">
<rect x="270" y="60" width="160" height="65" rx="10" fill="#0f172a" stroke="#475569" stroke-width="1.5" />
<text x="350" y="85" fill="#f1f5f9" font-size="11" font-weight="bold" text-anchor="middle">Stage 1: Context & Plan</text>
<text x="350" y="105" fill="#94a3b8" font-size="9" text-anchor="middle">Parse goal & rules</text>
</g>
<!-- 🟑 GENERATOR -->
<g id="node_gen" class="cursor-pointer" onclick="inspect('gen')">
<rect x="270" y="240" width="180" height="85" rx="10" fill="#1e293b" stroke="#f59e0b" stroke-width="2.5" />
<rect x="270" y="240" width="180" height="24" rx="10" fill="#78350f" />
<text x="360" y="256" fill="#fde68a" font-size="11" font-weight="bold" text-anchor="middle">🟑 GENERATOR</text>
<text x="360" y="281" fill="#f8fafc" font-size="10" text-anchor="middle" font-weight="semibold">Produces Artifacts</text>
<text x="360" y="299" fill="#cbd5e1" font-size="9" text-anchor="middle">Code, Specs, Configs, Docs</text>
</g>
<!-- πŸ”˜ TOOL WRAPPER -->
<g id="node_tool" class="cursor-pointer" onclick="inspect('tool')">
<rect x="530" y="240" width="220" height="85" rx="10" fill="#1e293b" stroke="#64748b" stroke-width="2.5" />
<rect x="530" y="240" width="220" height="24" rx="10" fill="#334155" />
<text x="640" y="256" fill="#e2e8f0" font-size="11" font-weight="bold" text-anchor="middle">πŸ”˜ TOOL WRAPPER</text>
<text x="640" y="281" fill="#f8fafc" font-size="10" text-anchor="middle" font-weight="semibold">Runs Commands / CLI</text>
<text x="640" y="299" fill="#cbd5e1" font-size="9" text-anchor="middle">kubectl, git, terraform, APIs</text>
</g>
<!-- πŸ”΄ REVIEWER Gate -->
<g id="node_reviewer" class="cursor-pointer" onclick="inspect('reviewer')">
<polygon points="360,360 440,410 360,460 280,410" fill="#450a0a" stroke="#ef4444" stroke-width="2.5" />
<text x="360" y="405" fill="#fca5a5" font-size="11" font-weight="bold" text-anchor="middle">πŸ”΄ REVIEWER</text>
<text x="360" y="420" fill="#fee2e2" font-size="9" text-anchor="middle">Validation Gate</text>
</g>
<text x="180" y="395" fill="#f87171" font-size="9" font-weight="bold">❌ Fail & Revise</text>
<text x="490" y="480" fill="#4ade80" font-size="10" font-weight="bold">βœ… PASS: Verified Quality</text>
<!-- 🏁 Final Goal -->
<g id="node_goal" class="cursor-pointer" onclick="inspect('goal')">
<rect x="650" y="465" width="150" height="50" rx="25" fill="#064e3b" stroke="#10b981" stroke-width="2" />
<text x="725" y="488" fill="#d1fae5" font-size="10" font-weight="bold" text-anchor="middle">🏁 Goal Achieved</text>
<text x="725" y="503" fill="#a7f3d0" font-size="9" text-anchor="middle">State Change Done</text>
</g>
<!-- Moving Token -->
<circle id="animToken" cx="-50" cy="-50" r="9" fill="#10b981" filter="url(#glow)" />
<text id="tokenLabel" x="-50" y="-50" fill="#ffffff" font-size="8" font-weight="bold" text-anchor="middle"></text>
</svg>
<!-- Logs -->
<div class="log-container" id="logBox">
<div class="log-item" style="color: #64748b;">[System] Simulation ready. Select scenario and click Run.</div>
</div>
</div>
<!-- Pattern Inspector Panel -->
<div class="card">
<div class="stage-indicator">
<h2 style="font-size: 1rem; font-weight: 700;">πŸ” Pattern Inspector</h2>
<span id="inspectBadge" class="badge badge-workflow">Workflow</span>
</div>
<div id="inspector">
<div class="inspector-row">
<div class="inspector-label">Pattern Name</div>
<div id="inspectName" class="inspector-val" style="font-weight: 700; font-size: 1.05rem;">🟒 Workflow</div>
</div>
<div class="inspector-row">
<div class="inspector-label">Primary Function</div>
<div id="inspectFunc" class="inspector-val">Orchestrates a repeatable, multi-step sequence of tasks.</div>
</div>
<div class="inspector-row">
<div class="inspector-label">Output Type</div>
<div id="inspectOutput" class="inspector-val" style="color: #4ade80; font-weight: 600;">State Change / Process Completion</div>
</div>
<div class="inspector-row">
<div class="inspector-label">Example Implementation</div>
<div id="inspectExample" class="code-box">release-hotfix-deploy, cloud-migration-pipeline</div>
</div>
<div class="inspector-row">
<div class="inspector-label">Role in Multi-Skill Architecture</div>
<div id="inspectCollab" class="inspector-val">Coordinates knowledge loading, generation, command execution, and quality gating.</div>
</div>
</div>
<div class="pattern-btn-list">
<button class="btn-pattern-select" onclick="inspect('info')">
<span style="color: #60a5fa; font-weight: 600;">πŸ”΅ Informational</span>
<span style="color: #64748b; font-size: 0.75rem;">Knowledge</span>
</button>
<button class="btn-pattern-select" onclick="inspect('gen')">
<span style="color: #fbbf24; font-weight: 600;">🟑 Generator</span>
<span style="color: #64748b; font-size: 0.75rem;">Artifacts</span>
</button>
<button class="btn-pattern-select" onclick="inspect('tool')">
<span style="color: #cbd5e1; font-weight: 600;">πŸ”˜ Tool Wrapper</span>
<span style="color: #64748b; font-size: 0.75rem;">Execution</span>
</button>
<button class="btn-pattern-select" onclick="inspect('reviewer')">
<span style="color: #f87171; font-weight: 600;">πŸ”΄ Reviewer</span>
<span style="color: #64748b; font-size: 0.75rem;">Gate</span>
</button>
<button class="btn-pattern-select" onclick="inspect('workflow')">
<span style="color: #4ade80; font-weight: 600;">🟒 Workflow</span>
<span style="color: #64748b; font-size: 0.75rem;">Orchestrator</span>
</button>
</div>
</div>
</div>
</div>
<script>
const data = {
workflow: {
name: "🟒 Workflow",
badge: "badge-workflow",
func: "Orchestrates a repeatable, multi-step sequence of tasks and coordinates state changes across specialized skills.",
output: "State Change / Process Completion",
example: "release-hotfix-deploy, cloud-migration-pipeline",
collab: "Acts as the top-level conductor that invokes the other 4 skills in strict dependency order."
},
info: {
name: "πŸ”΅ Informational",
badge: "badge-info",
func: "Provides domain standards, API documentation, environment rules, and schema definitions without mutating state.",
output: "Context / Knowledge Ingestion",
example: "cloud-architecture-standards, internal-api-spec",
collab: "Supplies reference standards to Workflow planning, Generator schema templates, and Reviewer checklists."
},
gen: {
name: "🟑 Generator",
badge: "badge-gen",
func: "Guides the agent on producing strictly formatted content, structured code, configuration files, or markdown specifications.",
output: "Structured Artifacts (YAML, JSON, Code, MD)",
example: "terraform-hcl-generator, openapi-spec-writer",
collab: "Turns informational standards into code/configs, then passes deliverables to Tool Wrapper."
},
tool: {
name: "πŸ”˜ Tool Wrapper",
badge: "badge-tool",
func: "Instructs the agent on how to use external CLIs, scripts, or APIs safely with proper flags, dry-runs, and exit codes.",
output: "Command Execution & Environment Mutation",
example: "kubectl-helm-ops, aws-cli-wrapper, psql-runner",
collab: "Executes the generated artifacts against the infrastructure or environment."
},
reviewer: {
name: "πŸ”΄ Reviewer",
badge: "badge-review",
func: "Defines strict evaluation criteria and automated checklists for assessing human or agent work against quality/security requirements.",
output: "Pass/Fail Validation & Audit Findings",
example: "owasp-security-auditor, pr-linter-gate",
collab: "Quality gate. Rejects failing work back to Generator for auto-correction; approves compliant work to complete Workflow."
},
trigger: {
name: "⚑ User Request / Trigger",
badge: "badge-workflow",
func: "The initial prompt or webhook starting the task.",
output: "Intent / Objective Payload",
example: "'Deploy payment auth endpoint to staging'",
collab: "Initiates Stage 1 of the Workflow."
},
goal: {
name: "🏁 Goal Achieved",
badge: "badge-workflow",
func: "Confirms verified completion and records the state transition.",
output: "Verified Final State",
example: "All services healthy, tests passed 100%.",
collab: "Terminates the Workflow successfully."
}
};
function inspect(key) {
const p = data[key] || data.workflow;
document.getElementById('inspectName').innerText = p.name;
document.getElementById('inspectFunc').innerText = p.func;
document.getElementById('inspectOutput').innerText = p.output;
document.getElementById('inspectExample').innerText = p.example;
document.getElementById('inspectCollab').innerText = p.collab;
const b = document.getElementById('inspectBadge');
b.className = 'badge ' + p.badge;
b.innerText = p.name.split(' ')[1] || p.name;
}
const scenarios = {
happy: [
{ node: 'node_trigger', token: [95, 85], label: "Trigger", log: "[WORKFLOW] Task Trigger: 'Deploy API endpoint'", phase: "Planning" },
{ node: 'node_info', token: [645, 95], label: "Context", log: "[INFORMATIONAL] Injected OpenAPI v3.1 schema & VPC rules", phase: "Knowledge" },
{ node: 'node_s1', token: [350, 90], label: "Plan", log: "[WORKFLOW] Formulated DAG plan", phase: "Planning" },
{ node: 'node_gen', token: [360, 280], label: "Artifact", log: "[GENERATOR] Created auth_route.py & openapi.yaml", phase: "Creation" },
{ node: 'node_tool', token: [640, 280], label: "Command", log: "[TOOL WRAPPER] Executed 'kubectl apply -f auth.yaml'", phase: "Execution" },
{ node: 'node_reviewer', token: [360, 410], label: "Audit", log: "[REVIEWER] Audit check passed. VERDICT: PASS βœ…", phase: "Validation" },
{ node: 'node_goal', token: [725, 490], label: "Success", log: "[WORKFLOW] Goal achieved. State change committed 🏁", phase: "Done" }
],
fail_retry: [
{ node: 'node_trigger', token: [95, 85], label: "Trigger", log: "[WORKFLOW] Task Trigger: 'Run DB migration'", phase: "Planning" },
{ node: 'node_info', token: [645, 95], label: "Context", log: "[INFORMATIONAL] Ingested Postgres DDL rules", phase: "Knowledge" },
{ node: 'node_s1', token: [350, 90], label: "Plan", log: "[WORKFLOW] Formulated SQL migration plan", phase: "Planning" },
{ node: 'node_gen', token: [360, 280], label: "Draft v1", log: "[GENERATOR] Created 001_migration.sql (unindexed)", phase: "Creation" },
{ node: 'node_tool', token: [640, 280], label: "Lint", log: "[TOOL WRAPPER] Ran 'sqlfluff lint 001_migration.sql'", phase: "Execution" },
{ node: 'node_reviewer', token: [360, 410], label: "FAIL", log: "[REVIEWER] ⚠️ Table lock violation! Rejecting to Generator.", phase: "Rejected" },
{ node: 'node_gen', token: [360, 280], label: "Fix v2", log: "[GENERATOR] Auto-revised script with CONCURRENTLY lock.", phase: "Revision" },
{ node: 'node_tool', token: [640, 280], label: "Deploy", log: "[TOOL WRAPPER] Applied fixed migration to staging DB.", phase: "Execution" },
{ node: 'node_reviewer', token: [360, 410], label: "PASS", log: "[REVIEWER] Re-audit passed: 0 lock risks. PASS βœ…", phase: "Validation" },
{ node: 'node_goal', token: [725, 490], label: "Success", log: "[WORKFLOW] Migration completed safely 🏁", phase: "Done" }
],
strict: [
{ node: 'node_trigger', token: [95, 85], label: "Trigger", log: "[WORKFLOW] Strict Security Trigger: 'PCI-DSS Transfer'", phase: "Planning" },
{ node: 'node_info', token: [645, 95], label: "PCI-DSS", log: "[INFORMATIONAL] Loaded encryption standards & KMS policy", phase: "Knowledge" },
{ node: 'node_gen', token: [360, 280], label: "Payload", log: "[GENERATOR] Built envelope-encrypted payload", phase: "Creation" },
{ node: 'node_tool', token: [640, 280], label: "KMS Sign", log: "[TOOL WRAPPER] gcloud kms asym-sign completed", phase: "Execution" },
{ node: 'node_reviewer', token: [360, 410], label: "PASS", log: "[REVIEWER] Cryptographic validation passed. PASS βœ…", phase: "Validation" },
{ node: 'node_goal', token: [725, 490], label: "Success", log: "[WORKFLOW] High-security transaction recorded 🏁", phase: "Done" }
]
};
let timer = null;
let playing = false;
let stepIdx = 0;
function addLog(msg) {
const box = document.getElementById('logBox');
const time = new Date().toTimeString().split(' ')[0];
const d = document.createElement('div');
d.className = "log-item";
if (msg.includes('PASS') || msg.includes('🏁')) d.className += " log-pass";
if (msg.includes('FAIL') || msg.includes('Rejecting')) d.className += " log-fail";
d.innerText = `[${time}] ${msg}`;
box.appendChild(d);
box.scrollTop = box.scrollHeight;
}
function render(s) {
document.querySelectorAll('#simSvg g').forEach(el => el.classList.remove('node-active'));
const n = document.getElementById(s.node);
if (n) n.classList.add('node-active');
const tok = document.getElementById('animToken');
const lbl = document.getElementById('tokenLabel');
tok.setAttribute('cx', s.token[0]);
tok.setAttribute('cy', s.token[1]);
tok.setAttribute('fill', s.label.includes('FAIL') ? '#ef4444' : (s.label.includes('Context') ? '#3b82f6' : (s.label.includes('Draft') || s.label.includes('Artifact') ? '#f59e0b' : '#10b981')));
lbl.setAttribute('x', s.token[0]);
lbl.setAttribute('y', s.token[1] - 12);
lbl.textContent = s.label;
document.getElementById('phaseBadge').innerText = s.phase;
addLog(s.log);
if (s.node === 'node_info') inspect('info');
else if (s.node === 'node_gen') inspect('gen');
else if (s.node === 'node_tool') inspect('tool');
else if (s.node === 'node_reviewer') inspect('reviewer');
else if (s.node === 'node_goal') inspect('goal');
else inspect('workflow');
}
function step() {
const sKey = document.getElementById('scenarioSelect').value;
const list = scenarios[sKey] || scenarios.happy;
if (stepIdx >= list.length) stepIdx = 0;
render(list[stepIdx]);
stepIdx++;
if (stepIdx >= list.length && playing) toggle(false);
}
function toggle(force) {
playing = typeof force === 'boolean' ? force : !playing;
const btn = document.getElementById('btnPlay');
if (playing) {
btn.innerText = "⏸ Pause";
btn.className = "btn-pause";
timer = setInterval(step, 1000);
} else {
btn.innerText = "β–Ά Run Simulation";
btn.className = "btn-primary";
if (timer) clearInterval(timer);
}
}
function reset() {
toggle(false);
stepIdx = 0;
document.querySelectorAll('#simSvg g').forEach(el => el.classList.remove('node-active'));
document.getElementById('animToken').setAttribute('cx', -50);
document.getElementById('tokenLabel').textContent = '';
document.getElementById('phaseBadge').innerText = "Ready";
addLog("[System] Reset simulation.");
}
document.getElementById('btnPlay').addEventListener('click', () => toggle());
document.getElementById('btnStep').addEventListener('click', () => { toggle(false); step(); });
document.getElementById('btnReset').addEventListener('click', reset);
document.getElementById('scenarioSelect').addEventListener('change', reset);
</script>
</body>
</html>