Create an interactive HTML architecture explorer playground for the current project
56
62%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./playground-project-architecture/SKILL.mdCreates a self-contained HTML playground that visualizes the current project's architecture with three panels: component tree (left), workflow/data flow/file diagrams (center), and component details with annotations (right).
Files in docs/playground/ directory:
{context-name}-architecture-{timestamp}.html - The interactive playground{context-name}-architecture-{timestamp}-config.js - The configuration dataWhere {context-name} is a short descriptive name based on the focus area (e.g., "tools", "api", "auth") and {timestamp} is in format YYYYMMDD-HHMM.
Features:
Scope Discovery (do this first):
Analyze the project to identify:
For each component, capture:
Generate a CONFIG object with this structure:
const CONFIG = {
projectName: "Your Project",
// IMPORTANT: Add entries for ALL selectable elements across all diagrams
componentData: {
// Tree/workflow components
"component-id": {
title: "Component Name",
badge: "entry", // entry, node, llm, tool, state
badgeLabel: "ENTRY",
file: "src/path/to/file.ts",
description: "Description of what this component does.",
responsibilities: ["Responsibility 1", "Responsibility 2"],
code: "interface Example { prop: string; }"
},
// Workflow V2 nodes - use the componentId from nodes
"validator": {
title: "Input Validator",
badge: "node",
badgeLabel: "NODE",
file: "src/validator.ts",
description: "Validates incoming requests.",
responsibilities: ["Schema validation", "Type checking"],
code: "function validate(input: unknown): Result"
},
// Sequence diagram participants
"client": {
title: "Client Application",
badge: "entry",
badgeLabel: "CLIENT",
file: "src/client/index.ts",
description: "Frontend client that initiates requests.",
responsibilities: ["User interaction", "API calls"],
code: "class Client { async login(credentials) }"
},
// Sequence diagram messages
"msg-1": {
title: "POST /login",
badge: "tool",
badgeLabel: "HTTP",
file: "src/api/routes/auth.ts",
description: "HTTP endpoint for user authentication.",
responsibilities: ["Validate payload", "Forward to auth service"],
code: "router.post('/login', async (req, res) => { ... })"
}
},
treeStructure: [
{
header: "Entry Points",
items: [{ id: "component-id", icon: "E", iconClass: "icon-entry" }]
}
],
dataFlowLayers: [
{ label: "Input", items: ["component-id"] }
],
fileTreeEntries: [
{ indent: "", icon: "D", text: "src/", component: null },
{ indent: "L--", icon: "F", text: "file.ts", component: "component-id" }
],
workflowStructure: [
{ phase: "phase-1", nodes: ["component-id-1", "component-id-2"] }
],
// Enhanced workflow with conditionals, branches, and loops (optional)
workflowStructureV2: {
nodes: [
{ id: "start", type: "start", label: "Start" },
{ id: "validate", type: "process", label: "Validate", componentId: "validator", phase: "phase-1" },
{ id: "check", type: "decision", label: "Valid?" },
{ id: "success", type: "process", label: "Process", componentId: "processor", phase: "phase-2" },
{ id: "error", type: "process", label: "Handle Error", componentId: "error-handler", phase: "phase-2" },
{ id: "merge", type: "merge" },
{ id: "end", type: "end", label: "End" }
],
edges: [
{ from: "start", to: "validate" },
{ from: "validate", to: "check" },
{ from: "check", to: "success", label: "Yes", branch: "primary" },
{ from: "check", to: "error", label: "No", branch: "secondary" },
{ from: "success", to: "merge" },
{ from: "error", to: "merge" },
{ from: "merge", to: "end" },
{ from: "error", to: "validate", label: "Retry", type: "loop" }
]
},
sequenceFlows: [
{
name: "Authentication Flow",
participants: [
{ id: "client", name: "Client" },
{ id: "api", name: "API Gateway" },
{ id: "auth", name: "Auth Service" },
{ id: "db", name: "Database" }
],
messages: [
{ id: "msg-1", from: "client", to: "api", label: "POST /login", type: "sync" },
{ id: "msg-2", from: "api", to: "auth", label: "validateCredentials()", type: "sync" },
{ id: "msg-3", from: "auth", to: "db", label: "query user", type: "async" },
{ id: "msg-4", from: "db", to: "auth", label: "user record", type: "return" },
{ id: "msg-5", from: "auth", to: "auth", label: "verifyPassword()", type: "sync" },
{ id: "msg-6", from: "auth", to: "api", label: "token", type: "return" },
{ id: "msg-7", from: "api", to: "client", label: "200 OK + token", type: "return" }
]
},
// IMPORTANT: Subsequent flows also need IDs on ALL messages!
{
name: "Logout Flow",
participants: [
{ id: "client", name: "Client" },
{ id: "api", name: "API Gateway" },
{ id: "auth", name: "Auth Service" }
],
messages: [
{ id: "logout-1", from: "client", to: "api", label: "POST /logout", type: "sync" },
{ id: "logout-2", from: "api", to: "auth", label: "invalidateSession()", type: "sync" },
{ id: "logout-3", from: "auth", to: "api", label: "success", type: "return" },
{ id: "logout-4", from: "api", to: "client", label: "200 OK", type: "return" }
]
}
]
};File Naming Convention:
Generate filenames based on context and timestamp:
YYYYMMDD-HHMM (e.g., 20260205-1430)Example filenames:
tools-architecture-20260205-1430.htmltools-architecture-20260205-1430-config.jsGeneration Steps:
Create the docs/playground directory if needed:
mkdir -p docs/playgroundWrite the CONFIG object directly as a JS file (do NOT create a JSON file):
docs/playground/{context-name}-architecture-{timestamp}-config.jsThe file should contain:
window.EXTERNAL_CONFIG = {
// ... your CONFIG object here
};Copy the template:
cp ~/.claude/skills/playground-project-architecture/templates/architecture-explorer.html docs/playground/{context-name}-architecture-{timestamp}.htmlEdit the HTML file to add the config script tag before the main <script> tag:
<script src="{context-name}-architecture-{timestamp}-config.js"></script>Open in browser:
open docs/playground/{context-name}-architecture-{timestamp}.html| Badge | Use For |
|---|---|
entry | Main entry points, orchestrators, CLI handlers |
node | Workflow/pipeline nodes, processing steps |
llm | LLM-related: models, prompts, schemas |
tool | Tools, utilities, executors |
state | State objects, types, DTOs |
The sequenceFlows array defines UML-style sequence diagrams showing message flows between participants.
Define actors/systems that send/receive messages:
{ id: "unique-id", name: "Display Name" }id: Unique identifier (can reference existing componentData)name: Display name (fallback if component not in componentData)Define interactions between participants:
{
id: "msg-1", // REQUIRED for interactivity: enables click selection, context menu, and annotations
from: "participant-id",
to: "participant-id",
label: "message text",
type: "sync" // sync, async, return
}IMPORTANT: Every message in every sequence flow MUST have a unique id. Without an id, the message arrow will not be clickable and users cannot select it or add annotations. Use a consistent naming pattern like:
msg-1, msg-2, msg-3, ...msg-2-1, msg-2-2, msg-2-3, ... (or flow2-msg-1, etc.)msg-login-request, msg-auth-response, etc.| Type | Visual | Use For |
|---|---|---|
sync | Solid blue arrow | Synchronous calls |
async | Solid purple arrow | Asynchronous calls |
return | Dashed gray arrow | Return values/responses |
When from === to, renders as a loop back to the same participant. Use for internal processing steps.
Add message details to componentData for rich details panel:
"msg-1": {
title: "POST /login",
badge: "tool",
badgeLabel: "HTTP",
file: "src/api/routes/auth.ts",
description: "HTTP endpoint for user authentication",
responsibilities: ["Validate payload", "Forward to auth service"],
code: "router.post('/login', async (req, res) => { ... })"
}For complex workflows with conditionals, parallel branches, and loops, use workflowStructureV2 instead of the legacy workflowStructure.
| Type | Visual | Use For |
|---|---|---|
start | Green rounded pill | Entry point of workflow |
process | Rectangle box | Processing steps (supports phase colors) |
decision | Orange diamond | Conditional branching points |
merge | Gray circle | Where branches rejoin |
end | Red rounded pill | Exit point of workflow |
{
id: "unique-id", // Required: unique identifier
type: "process", // Required: start, process, decision, merge, end
label: "Display Text", // Optional: text shown in node
componentId: "comp-id", // Optional: links to componentData for details panel
phase: "phase-1" // Optional: adds phase color (phase-1 to phase-4)
}{
id: "edge-id", // Optional: enables selection/annotation
from: "source-node-id", // Required: source node
to: "target-node-id", // Required: target node
label: "Yes", // Optional: text label on edge
branch: "primary", // Optional: "primary" (blue) or "secondary" (gray)
type: "loop" // Optional: "loop" for back-edges (curved purple dashed)
}The system automatically computes top-down layered layout:
If workflowStructureV2 is not defined, the legacy workflowStructure (array of phase rows) is used.
Use real codebase elements - Find actual component names, file paths
Include file paths - Every component should have its source file path
Write helpful descriptions - 2-3 sentences explaining what each component does
List concrete responsibilities - Specific things the component handles
Include code snippets - Key interfaces, types, or function signatures
Open in browser - Always run open command after creating
MANDATORY: Add componentData for ALL diagram elements - Every selectable element in every diagram MUST have a corresponding entry in componentData. This includes:
componentId to link)id)id)component setWithout componentData entries, the details panel will be empty when users click elements. The details panel is essential for understanding what each element represents.
MANDATORY: Every sequence message needs an id - ALL messages in ALL sequence flows must have unique id properties. Messages without IDs cannot be clicked, selected, or annotated. This applies to EVERY sequence flow, not just the first one. Double-check that subsequent sequence flows have IDs on all their messages.
3f469de
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.