diff --git a/parsa/.codex/skills/excalidraw-pr-diagrams/.gitignore b/parsa/.codex/skills/excalidraw-pr-diagrams/.gitignore new file mode 100644 index 0000000..ef27a06 --- /dev/null +++ b/parsa/.codex/skills/excalidraw-pr-diagrams/.gitignore @@ -0,0 +1,4 @@ +.venv/ +*.png +uv.lock +__pycache__/ diff --git a/parsa/.codex/skills/excalidraw-pr-diagrams/README.md b/parsa/.codex/skills/excalidraw-pr-diagrams/README.md new file mode 100644 index 0000000..129290c --- /dev/null +++ b/parsa/.codex/skills/excalidraw-pr-diagrams/README.md @@ -0,0 +1,63 @@ +# Excalidraw Diagram Skill + +A coding agent skill that generates beautiful and practical Excalidraw diagrams from natural language descriptions. Not just boxes-and-arrows - diagrams that **argue visually**. + +Compatible with any coding agent that supports skills. For agents that read from `.claude/skills/` (like [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and [OpenCode](https://github.com/nicepkg/OpenCode)), just drop it in and go. + +## What Makes This Different + +- **Diagrams that argue, not display.** Every shape/group of shapes mirrors the concept it represents — fan-outs for one-to-many, timelines for sequences, convergence for aggregation. No uniform card grids. +- **Evidence artifacts.** As an example, technical diagrams include real code snippets and actual JSON payloads. +- **Built-in visual validation.** A Playwright-based render pipeline lets the agent see its own output, catch layout issues (overlapping text, misaligned arrows, unbalanced spacing), and fix them in a loop before delivering. +- **Brand-customizable.** All colors and brand styles live in a single file (`references/color-palette.md`). Swap it out and every diagram follows your palette. + +## Installation + +Clone or download this repo, then copy it into your project's `.claude/skills/` directory: + +```bash +git clone https://github.com/coleam00/excalidraw-diagram-skill.git +cp -r excalidraw-diagram-skill .claude/skills/excalidraw-diagram +``` + +## Setup + +The skill includes a render pipeline that lets the agent visually validate its diagrams. There are two ways to set it up: + +**Option A: Ask your coding agent (easiest)** + +Just tell your agent: *"Set up the Excalidraw diagram skill renderer by following the instructions in SKILL.md."* It will run the commands for you. + +**Option B: Manual** + +```bash +cd .claude/skills/excalidraw-diagram/references +uv sync +uv run playwright install chromium +``` + +## Usage + +Ask your coding agent to create a diagram: + +> "Create an Excalidraw diagram showing how the AG-UI protocol streams events from an AI agent to a frontend UI" + +The skill handles the rest — concept mapping, layout, JSON generation, rendering, and visual validation. + +## Customize Colors + +Edit `references/color-palette.md` to match your brand. Everything else in the skill is universal design methodology. + +## File Structure + +``` +excalidraw-diagram/ + SKILL.md # Design methodology + workflow + references/ + color-palette.md # Brand colors (edit this to customize) + element-templates.md # JSON templates for each element type + json-schema.md # Excalidraw JSON format reference + render_excalidraw.py # Render .excalidraw to PNG + render_template.html # Browser template for rendering + pyproject.toml # Python dependencies (playwright) +``` diff --git a/parsa/.codex/skills/excalidraw-pr-diagrams/SKILL.md b/parsa/.codex/skills/excalidraw-pr-diagrams/SKILL.md new file mode 100644 index 0000000..e152f55 --- /dev/null +++ b/parsa/.codex/skills/excalidraw-pr-diagrams/SKILL.md @@ -0,0 +1,663 @@ +--- +name: excalidraw-diagram +description: Create Excalidraw diagram JSON files that make visual arguments. Use when the user wants to visualize workflows, architectures, or concepts. +--- + +# Excalidraw Diagram Creator + +Generate `.excalidraw` JSON files that **argue visually**, not just display information. + +**Setup:** If the user asks you to set up this skill (renderer, dependencies, etc.), see `README.md` for instructions. + +## Local Codex PR Workflow + +When using this skill for pull request diagrams in Codex: + +- Always create and edit diagram working files under `/tmp`, preferably `/tmp/codex-pr-diagrams//`. +- Do not create generated `.excalidraw`, `.png`, or temporary render files inside the repository unless the user explicitly asks for tracked diagram assets. +- For PR descriptions, use the rendered Excalidraw image as the primary visual. Do not add Mermaid diagrams by default; they are usually redundant once the Excalidraw image includes before/after flow and reviewer explainers. Add Mermaid only if the user explicitly asks for a durable text-rendered fallback. +- Save matching `.excalidraw` source files under `/tmp` for local iteration and future reuse. +- PR visual overviews must include explicit `Before` and `After` diagrams so reviewers can see both the old behavior and the new behavior without inferring the diff from prose. +- Keep each PR diagram focused on the change boundary: before, after, and why the new flow is safer. +- After generating diagrams, update the PR description with a dedicated `## Visual Overview` section. + +### PR Diagram Standard + +For PR diagrams, a simple pair of red/green cards is not acceptable. The diagram must teach the change in a way prose cannot. + +Before drawing, identify the visual truth of the PR: + +- **Boundary changed**: draw walls, membranes, trust zones, or origin/process boundaries. +- **Lifecycle changed**: draw a state machine, gate sequence, or retry loop. +- **Responsibility moved**: draw before/after ownership regions and move the action across them. +- **Failure mode removed**: draw the old failure path visibly dead-ending and the new path avoiding it. +- **Concurrency/race fixed**: draw clocks, timelines, joins, or retry circuits. +- **Validation/permissions changed**: draw a decision path, lock/gate, and what passes through it. + +Every PR visual overview must include: + +- A **before path** showing where the old system failed or was fragile. +- An **after path** showing the new route/control point. +- At least one **semantic visual structure**: boundary, timeline, loop, funnel, state machine, swimlane, queue, fan-out, convergence, or layered stack. +- One short **truth statement** that explains the visual argument in plain language. +- A small **term explainer** when the diagram uses protocol/framework words that a reviewer may not know. Do not assume terms like header, preflight, origin, token, cookie, CORS, WebSocket upgrade, cache key, breakpoint, or trace are self-explanatory. + +Do not use the same diagram structure for a series of PRs unless the code changes truly have the same shape. Split PRs usually need different visual metaphors because they fix different kinds of problems. + +### Reviewer Explainers + +When a PR involves technical protocol behavior, include a compact teaching layer in the visual: + +- Define the technical noun in a concrete metaphor before using it. Example: `headers = extra notes the browser wants to attach`, `preflight = permission check before the real request`, `origin = website address the browser trusts or blocks`. +- Show who performs each action. Example: `Browser asks`, `API answers`, `Browser blocks`, not just `headers requested`. +- Use concrete examples sparingly: `login badge`, `Sentry trace`, `Firebase app id` is clearer than a long raw header list. +- Keep the official term visible in parentheses after the plain-English term when useful: `permission check (CORS preflight)`. +- If the diagram has a metaphor, keep it mapped to the real system with labels. A security desk can teach CORS, but the browser/API roles must remain visible. + +For review diagrams, assume the reader is smart but has not learned this subsystem yet. If the reader would ask "who does that?" or "what is that?", add a visual cue or one-line explainer instead of relying on the PR prose. + +## Customization + +**All colors and brand-specific styles live in one file:** `references/color-palette.md`. Read it before generating any diagram and use it as the single source of truth for all color choices — shape fills, strokes, text colors, evidence artifact backgrounds, everything. + +To make this skill produce diagrams in your own brand style, edit `color-palette.md`. Everything else in this file is universal design methodology and Excalidraw best practices. + +--- + +## Core Philosophy + +**Diagrams should ARGUE, not DISPLAY.** + +A diagram isn't formatted text. It's a visual argument that shows relationships, causality, and flow that words alone can't express. The shape should BE the meaning. + +**The Isomorphism Test**: If you removed all text, would the structure alone communicate the concept? If not, redesign. + +**The Education Test**: Could someone learn something concrete from this diagram, or does it just label boxes? A good diagram teaches—it shows actual formats, real event names, concrete examples. + +**The Redundancy Test**: If the diagram is just the PR description broken into red and green rectangles, discard it. A good diagram uses spatial relationships, arrows, boundaries, and shape to reveal something the prose does not. + +**The High-Schooler Test**: A smart high-schooler should be able to point at the diagram and explain the core before/after change without reading the full PR. If they would only read labels out loud, redesign. + +--- + +## Depth Assessment (Do This First) + +Before designing, determine what level of detail this diagram needs: + +### Simple/Conceptual Diagrams +Use abstract shapes when: +- Explaining a mental model or philosophy +- The audience doesn't need technical specifics +- The concept IS the abstraction (e.g., "separation of concerns") + +### Comprehensive/Technical Diagrams +Use concrete examples when: +- Diagramming a real system, protocol, or architecture +- The diagram will be used to teach or explain (e.g., YouTube video) +- The audience needs to understand what things actually look like +- You're showing how multiple technologies integrate + +**For technical diagrams, you MUST include evidence artifacts** (see below). + +--- + +## Research Mandate (For Technical Diagrams) + +**Before drawing anything technical, research the actual specifications.** + +If you're diagramming a protocol, API, or framework: +1. Look up the actual JSON/data formats +2. Find the real event names, method names, or API endpoints +3. Understand how the pieces actually connect +4. Use real terminology, not generic placeholders + +Bad: "Protocol" → "Frontend" +Good: "AG-UI streams events (RUN_STARTED, STATE_DELTA, A2UI_UPDATE)" → "CopilotKit renders via createA2UIMessageRenderer()" + +**Research makes diagrams accurate AND educational.** + +--- + +## Evidence Artifacts + +Evidence artifacts are concrete examples that prove your diagram is accurate and help viewers learn. Include them in technical diagrams. + +**Types of evidence artifacts** (choose what's relevant to your diagram): + +| Artifact Type | When to Use | How to Render | +|---------------|-------------|---------------| +| **Code snippets** | APIs, integrations, implementation details | Dark rectangle + syntax-colored text (see color palette for evidence artifact colors) | +| **Data/JSON examples** | Data formats, schemas, payloads | Dark rectangle + colored text (see color palette) | +| **Event/step sequences** | Protocols, workflows, lifecycles | Timeline pattern (line + dots + labels) | +| **UI mockups** | Showing actual output/results | Nested rectangles mimicking real UI | +| **Real input content** | Showing what goes IN to a system | Rectangle with sample content visible | +| **API/method names** | Real function calls, endpoints | Use actual names from docs, not placeholders | + +**Example**: For a diagram about a streaming protocol, you might show: +- The actual event names from the spec (not just "Event 1", "Event 2") +- A code snippet showing how to connect +- What the streamed data actually looks like + +**Example**: For a diagram about a data transformation pipeline: +- Show sample input data (actual format, not "Input") +- Show sample output data (actual format, not "Output") +- Show intermediate states if relevant + +The key principle: **show what things actually look like**, not just what they're called. + +--- + +## Multi-Zoom Architecture + +Comprehensive diagrams operate at multiple zoom levels simultaneously. Think of it like a map that shows both the country borders AND the street names. + +### Level 1: Summary Flow +A simplified overview showing the full pipeline or process at a glance. Often placed at the top or bottom of the diagram. + +*Example*: `Input → Processing → Output` or `Client → Server → Database` + +### Level 2: Section Boundaries +Labeled regions that group related components. These create visual "rooms" that help viewers understand what belongs together. + +*Example*: Grouping by responsibility (Backend / Frontend), by phase (Setup / Execution / Cleanup), or by team (User / System / External) + +### Level 3: Detail Inside Sections +Evidence artifacts, code snippets, and concrete examples within each section. This is where the educational value lives. + +*Example*: Inside a "Backend" section, you might show the actual API response format, not just a box labeled "API Response" + +**For comprehensive diagrams, aim to include all three levels.** The summary gives context, the sections organize, and the details teach. + +### Bad vs Good + +| Bad (Displaying) | Good (Arguing) | +|------------------|----------------| +| 5 equal boxes with labels | Each concept has a shape that mirrors its behavior | +| Card grid layout | Visual structure matches conceptual structure | +| Icons decorating text | Shapes that ARE the meaning | +| Same container for everything | Distinct visual vocabulary per concept | +| Everything in a box | Free-floating text with selective containers | +| Red card titled "Before" beside green card titled "After" | A before failure path and an after success path with different routing | +| Repeating the same template across unrelated PRs | Choosing a visual metaphor per PR: boundary, lifecycle, race, permission gate, retry loop | +| Paragraphs pasted into shapes | Short labels plus visual evidence, arrows, gates, and concrete artifacts | + +### Hard Anti-Patterns + +Never ship these unless the user explicitly asks for a deliberately minimal sketch: + +- Two large cards that simply summarize "Before" and "After". +- A diagram whose boxes could be replaced by bullets with no loss of meaning. +- Red/green color as the only source of meaning. +- Multiple PR diagrams with the same layout when the PRs solve different problems. +- Oversized headings that force the rest of the diagram to sprawl. +- Long prose inside Excalidraw text boxes. +- Rendered output where any text, title, arrow, or shape is clipped. +- Rendered output where key content requires horizontal scrolling to understand. + +### Simple vs Comprehensive (Know Which You Need) + +| Simple Diagram | Comprehensive Diagram | +|----------------|----------------------| +| Generic labels: "Input" → "Process" → "Output" | Specific: shows what the input/output actually looks like | +| Named boxes: "API", "Database", "Client" | Named boxes + examples of actual requests/responses | +| "Events" or "Messages" label | Timeline with real event/message names from the spec | +| "UI" or "Dashboard" rectangle | Mockup showing actual UI elements and content | +| ~30 seconds to explain | ~2-3 minutes of teaching content | +| Viewer learns the structure | Viewer learns the structure AND the details | + +**Simple diagrams** are fine for abstract concepts, quick overviews, or when the audience already knows the details. **Comprehensive diagrams** are needed for technical architectures, tutorials, educational content, or when you want the diagram itself to teach. + +--- + +## Container vs. Free-Floating Text + +**Not every piece of text needs a shape around it.** Default to free-floating text. Add containers only when they serve a purpose. + +| Use a Container When... | Use Free-Floating Text When... | +|------------------------|-------------------------------| +| It's the focal point of a section | It's a label or description | +| It needs visual grouping with other elements | It's supporting detail or metadata | +| Arrows need to connect to it | It describes something nearby | +| The shape itself carries meaning (decision diamond, etc.) | Typography alone creates sufficient hierarchy | +| It represents a distinct "thing" in the system | It's a section title, subtitle, or annotation | + +**Typography as hierarchy**: Use font size, weight, and color to create visual hierarchy without boxes. A 28px title doesn't need a rectangle around it. + +**The container test**: For each boxed element, ask "Would this work as free-floating text?" If yes, remove the container. + +## Canvas, Text, and Fit Rules + +Excalidraw text does not wrap exactly like normal HTML. Design for the renderer, not for wishful JSON dimensions. + +### Canvas + +- Start with a larger canvas than you think you need. For PR diagrams, plan around roughly **1600-2200 px wide** and **900-1400 px tall** before export. +- Use the larger canvas for meaningful spatial structure, not for giant titles or long paragraphs. +- Prefer two or three clear regions over many cramped micro-panels. +- Leave at least **80 px** outer margin and **50 px** between major regions. + +### Text + +- Keep titles short: ideally under 55 characters. +- Use smaller title type than instinct suggests: **24-30 px** is usually enough. +- Use labels at **14-18 px** and truth statements at **16-20 px**. +- Keep shape labels to **1-4 short lines**. If a label needs more, split it into multiple nearby annotations or make the diagram itself carry more meaning. +- Manually insert line breaks. Do not rely on Excalidraw/renderer wrapping. +- Make text boxes wider than the text appears to need. Add at least **30-50% extra width** as a safety margin. +- For every text element, set `width` and `height` generously. Clipping is a hard failure. + +### Render Fit + +After rendering, inspect at the exact PNG that will be shown in the PR: + +- If anything is clipped, increase canvas space or shrink/reposition text. +- If the diagram is mostly text, remove prose and add visual structure. +- If the title dominates the image, shrink it. +- If labels overlap arrows or shapes, move labels out of the flow path. +- If the image is too wide to understand in GitHub, reduce prose and stack regions vertically. + +--- + +## Design Process (Do This BEFORE Generating JSON) + +### Step 0: Assess Depth Required +Before anything else, determine if this needs to be: +- **Simple/Conceptual**: Abstract shapes, labels, relationships (mental models, philosophies) +- **Comprehensive/Technical**: Concrete examples, code snippets, real data (systems, architectures, tutorials) + +**If comprehensive**: Do research first. Look up actual specs, formats, event names, APIs. + +### Step 1: Understand Deeply +Read the content. For each concept, ask: +- What does this concept **DO**? (not what IS it) +- What relationships exist between concepts? +- What's the core transformation or flow? +- **What would someone need to SEE to understand this?** (not just read about) + +### Step 2: Map Concepts to Patterns +For each concept, find the visual pattern that mirrors its behavior: + +| If the concept... | Use this pattern | +|-------------------|------------------| +| Spawns multiple outputs | **Fan-out** (radial arrows from center) | +| Combines inputs into one | **Convergence** (funnel, arrows merging) | +| Has hierarchy/nesting | **Tree** (lines + free-floating text) | +| Is a sequence of steps | **Timeline** (line + dots + free-floating labels) | +| Loops or improves continuously | **Spiral/Cycle** (arrow returning to start) | +| Is an abstract state or context | **Cloud** (overlapping ellipses) | +| Transforms input to output | **Assembly line** (before → process → after) | +| Compares two things | **Side-by-side** (parallel with contrast) | +| Separates into phases | **Gap/Break** (visual separation between sections) | + +### Step 3: Ensure Variety +For multi-concept diagrams: **each major concept must use a different visual pattern**. No uniform cards or grids. + +### Step 4: Sketch the Flow +Before JSON, mentally trace how the eye moves through the diagram. There should be a clear visual story. + +### Step 5: Generate JSON +Only now create the Excalidraw elements. **See below for how to handle large diagrams.** + +### Step 6: Render & Validate (MANDATORY) +After generating the JSON, you MUST run the render-view-fix loop until the diagram looks right. This is not optional — see the **Render & Validate** section below for the full process. + +--- + +## Large / Comprehensive Diagram Strategy + +**For comprehensive or technical diagrams, you MUST build the JSON one section at a time.** Do NOT attempt to generate the entire file in a single pass. This is a hard constraint — Claude Code has a ~32,000 token output limit per response, and a comprehensive diagram easily exceeds that in one shot. Even if it didn't, generating everything at once leads to worse quality. Section-by-section is better in every way. + +### The Section-by-Section Workflow + +**Phase 1: Build each section** + +1. **Create the base file** with the JSON wrapper (`type`, `version`, `appState`, `files`) and the first section of elements. +2. **Add one section per edit.** Each section gets its own dedicated pass — take your time with it. Think carefully about the layout, spacing, and how this section connects to what's already there. +3. **Use descriptive string IDs** (e.g., `"trigger_rect"`, `"arrow_fan_left"`) so cross-section references are readable. +4. **Namespace seeds by section** (e.g., section 1 uses 100xxx, section 2 uses 200xxx) to avoid collisions. +5. **Update cross-section bindings** as you go. When a new section's element needs to bind to an element from a previous section (e.g., an arrow connecting sections), edit the earlier element's `boundElements` array at the same time. + +**Phase 2: Review the whole** + +After all sections are in place, read through the complete JSON and check: +- Are cross-section arrows bound correctly on both ends? +- Is the overall spacing balanced, or are some sections cramped while others have too much whitespace? +- Do IDs and bindings all reference elements that actually exist? + +Fix any alignment or binding issues before rendering. + +**Phase 3: Render & validate** + +Now run the render-view-fix loop from the Render & Validate section. This is where you'll catch visual issues that aren't obvious from JSON — overlaps, clipping, imbalanced composition. + +### Section Boundaries + +Plan your sections around natural visual groupings from the diagram plan. A typical large diagram might split into: + +- **Section 1**: Entry point / trigger +- **Section 2**: First decision or routing +- **Section 3**: Main content (hero section — may be the largest single section) +- **Section 4-N**: Remaining phases, outputs, etc. + +Each section should be independently understandable: its elements, internal arrows, and any cross-references to adjacent sections. + +### What NOT to Do + +- **Don't generate the entire diagram in one response.** You will hit the output token limit and produce truncated, broken JSON. Even if the diagram is small enough to fit, splitting into sections produces better results. +- **Don't use a coding agent** to generate the JSON. The agent won't have sufficient context about the skill's rules, and the coordination overhead negates any benefit. +- **Don't write a Python generator script.** The templating and coordinate math seem helpful but introduce a layer of indirection that makes debugging harder. Hand-crafted JSON with descriptive IDs is more maintainable. + +--- + +## Visual Pattern Library + +### Fan-Out (One-to-Many) +Central element with arrows radiating to multiple targets. Use for: sources, PRDs, root causes, central hubs. +``` + ○ + ↗ + □ → ○ + ↘ + ○ +``` + +### Convergence (Many-to-One) +Multiple inputs merging through arrows to single output. Use for: aggregation, funnels, synthesis. +``` + ○ ↘ + ○ → □ + ○ ↗ +``` + +### Tree (Hierarchy) +Parent-child branching with connecting lines and free-floating text (no boxes needed). Use for: file systems, org charts, taxonomies. +``` + label + ├── label + │ ├── label + │ └── label + └── label +``` +Use `line` elements for the trunk and branches, free-floating text for labels. + +### Spiral/Cycle (Continuous Loop) +Elements in sequence with arrow returning to start. Use for: feedback loops, iterative processes, evolution. +``` + □ → □ + ↑ ↓ + □ ← □ +``` + +### Cloud (Abstract State) +Overlapping ellipses with varied sizes. Use for: context, memory, conversations, mental states. + +### Assembly Line (Transformation) +Input → Process Box → Output with clear before/after. Use for: transformations, processing, conversion. +``` + ○○○ → [PROCESS] → □□□ + chaos order +``` + +### Side-by-Side (Comparison) +Two parallel structures with visual contrast. Use for: before/after, options, trade-offs. + +### Gap/Break (Separation) +Visual whitespace or barrier between sections. Use for: phase changes, context resets, boundaries. + +### Lines as Structure +Use lines (type: `line`, not arrows) as primary structural elements instead of boxes: +- **Timelines**: Vertical or horizontal line with small dots (10-20px ellipses) at intervals, free-floating labels beside each dot +- **Tree structures**: Vertical trunk line + horizontal branch lines, with free-floating text labels (no boxes needed) +- **Dividers**: Thin dashed lines to separate sections +- **Flow spines**: A central line that elements relate to, rather than connecting boxes + +``` +Timeline: Tree: + ●─── Label 1 │ + │ ├── item + ●─── Label 2 │ ├── sub + │ │ └── sub + ●─── Label 3 └── item +``` + +Lines + free-floating text often creates a cleaner result than boxes + contained text. + +--- + +## Shape Meaning + +Choose shape based on what it represents—or use no shape at all: + +| Concept Type | Shape | Why | +|--------------|-------|-----| +| Labels, descriptions, details | **none** (free-floating text) | Typography creates hierarchy | +| Section titles, annotations | **none** (free-floating text) | Font size/weight is enough | +| Markers on a timeline | small `ellipse` (10-20px) | Visual anchor, not container | +| Start, trigger, input | `ellipse` | Soft, origin-like | +| End, output, result | `ellipse` | Completion, destination | +| Decision, condition | `diamond` | Classic decision symbol | +| Process, action, step | `rectangle` | Contained action | +| Abstract state, context | overlapping `ellipse` | Fuzzy, cloud-like | +| Hierarchy node | lines + text (no boxes) | Structure through lines | + +**Rule**: Default to no container. Add shapes only when they carry meaning. Aim for <30% of text elements to be inside containers. + +--- + +## Color as Meaning + +Colors encode information, not decoration. Every color choice should come from `references/color-palette.md` — the semantic shape colors, text hierarchy colors, and evidence artifact colors are all defined there. + +**Key principles:** +- Each semantic purpose (start, end, decision, AI, error, etc.) has a specific fill/stroke pair +- Free-floating text uses color for hierarchy (titles, subtitles, details — each at a different level) +- Evidence artifacts (code snippets, JSON examples) use their own dark background + colored text scheme +- Always pair a darker stroke with a lighter fill for contrast + +**Do not invent new colors.** If a concept doesn't fit an existing semantic category, use Primary/Neutral or Secondary. + +--- + +## Modern Aesthetics + +For clean, professional diagrams: + +### Roughness +- `roughness: 0` — Clean, crisp edges. Use for modern/technical diagrams. +- `roughness: 1` — Hand-drawn, organic feel. Use for brainstorming/informal diagrams. + +**Default to 0** for most professional use cases. + +### Stroke Width +- `strokeWidth: 1` — Thin, elegant. Good for lines, dividers, subtle connections. +- `strokeWidth: 2` — Standard. Good for shapes and primary arrows. +- `strokeWidth: 3` — Bold. Use sparingly for emphasis (main flow line, key connections). + +### Opacity +**Always use `opacity: 100` for all elements.** Use color, size, and stroke width to create hierarchy instead of transparency. + +### Small Markers Instead of Shapes +Instead of full shapes, use small dots (10-20px ellipses) as: +- Timeline markers +- Bullet points +- Connection nodes +- Visual anchors for free-floating text + +--- + +## Layout Principles + +### Hierarchy Through Scale +- **Hero**: 300×150 - visual anchor, most important +- **Primary**: 180×90 +- **Secondary**: 120×60 +- **Small**: 60×40 + +### Whitespace = Importance +The most important element has the most empty space around it (200px+). + +### Flow Direction +Guide the eye: typically left→right or top→bottom for sequences, radial for hub-and-spoke. + +### Connections Required +Position alone doesn't show relationships. If A relates to B, there must be an arrow. + +--- + +## Text Rules + +**CRITICAL**: The JSON `text` property contains ONLY readable words. + +```json +{ + "id": "myElement1", + "text": "Start", + "originalText": "Start" +} +``` + +Settings: `fontSize: 16`, `fontFamily: 3`, `textAlign: "center"`, `verticalAlign: "middle"` + +--- + +## JSON Structure + +```json +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [...], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": 20 + }, + "files": {} +} +``` + +## Element Templates + +See `references/element-templates.md` for copy-paste JSON templates for each element type (text, line, dot, rectangle, arrow). Pull colors from `references/color-palette.md` based on each element's semantic purpose. + +--- + +## Render & Validate (MANDATORY) + +You cannot judge a diagram from JSON alone. After generating or editing the Excalidraw JSON, you MUST render it to PNG, view the image, and fix what you see — in a loop until it's right. This is a core part of the workflow, not a final check. + +### How to Render + +```bash +cd .claude/skills/excalidraw-diagram/references && uv run python render_excalidraw.py +``` + +This outputs a PNG next to the `.excalidraw` file. Then use the **Read tool** on the PNG to actually view it. + +### The Loop + +After generating the initial JSON, run this cycle: + +**1. Render & View** — Run the render script, then Read the PNG. + +**2. Audit against your original vision** — Before looking for bugs, compare the rendered result to what you designed in Steps 1-4. Ask: +- Does the visual structure match the conceptual structure you planned? +- Does each section use the pattern you intended (fan-out, convergence, timeline, etc.)? +- Does the eye flow through the diagram in the order you designed? +- Is the visual hierarchy correct — hero elements dominant, supporting elements smaller? +- For technical diagrams: are the evidence artifacts (code snippets, data examples) readable and properly placed? +- For PR diagrams: does the rendered image tell a non-redundant before/after story through structure, not just labels? +- Would the image still communicate the main change if the prose paragraphs were removed? + +**3. Check for visual defects:** +- Text clipped by or overflowing its container +- Text or shapes overlapping other elements +- Arrows crossing through elements instead of routing around them +- Arrows landing on the wrong element or pointing into empty space +- Labels floating ambiguously (not clearly anchored to what they describe) +- Uneven spacing between elements that should be evenly spaced +- Sections with too much whitespace next to sections that are too cramped +- Text too small to read at the rendered size +- Overall composition feels lopsided or unbalanced +- Any part of the title, subtitle, truth statement, or major region clipped by the screenshot bounds +- A horizontally sprawling image whose important content is hard to scan in a GitHub PR + +**4. Fix** — Edit the JSON to address everything you found. Common fixes: +- Widen containers when text is clipped +- Adjust `x`/`y` coordinates to fix spacing and alignment +- Add intermediate waypoints to arrow `points` arrays to route around elements +- Reposition labels closer to the element they describe +- Resize elements to rebalance visual weight across sections +- Shrink titles and labels before enlarging the diagram further. +- Replace long labels with a diagrammatic construct: boundary, queue, gate, loop, timeline, or swimlane. + +**5. Re-render & re-view** — Run the render script again and Read the new PNG. + +**6. Repeat** — Keep cycling until the diagram passes both the vision check (Step 2) and the defect check (Step 3). Typically takes 2-4 iterations. Don't stop after one pass just because there are no critical bugs — if the composition could be better, improve it. + +### When to Stop + +The loop is done when: +- The rendered diagram matches the conceptual design from your planning steps +- No text is clipped, overlapping, or unreadable +- Arrows route cleanly and connect to the right elements +- Spacing is consistent and the composition is balanced +- You'd be comfortable showing it to someone without caveats +- For PR diagrams, the before and after are visually different in a way that reflects the actual code change. +- The diagram would not be equally useful as a plain bullet list. + +### First-Time Setup +If the render script hasn't been set up yet: +```bash +cd .claude/skills/excalidraw-diagram/references +uv sync +uv run playwright install chromium +``` + +--- + +## Quality Checklist + +### Depth & Evidence (Check First for Technical Diagrams) +1. **Research done**: Did you look up actual specs, formats, event names? +2. **Evidence artifacts**: Are there code snippets, JSON examples, or real data? +3. **Multi-zoom**: Does it have summary flow + section boundaries + detail? +4. **Concrete over abstract**: Real content shown, not just labeled boxes? +5. **Educational value**: Could someone learn something concrete from this? + +### Conceptual +6. **Isomorphism**: Does each visual structure mirror its concept's behavior? +7. **Argument**: Does the diagram SHOW something text alone couldn't? +8. **Variety**: Does each major concept use a different visual pattern? +9. **No uniform containers**: Avoided card grids and equal boxes? +10. **Non-redundant**: The image is not just the PR description repeated in boxes. +11. **Before/after story**: The old failure path and new success path are visibly different. +12. **Metaphor fit**: The chosen metaphor matches the change type (boundary, lifecycle, race, permission, ownership, etc.). + +### Container Discipline +13. **Minimal containers**: Could any boxed element work as free-floating text instead? +14. **Lines as structure**: Are tree/timeline patterns using lines + text rather than boxes? +15. **Typography hierarchy**: Are font size and color creating visual hierarchy (reducing need for boxes)? + +### Structural +16. **Connections**: Every relationship has an arrow or line +17. **Flow**: Clear visual path for the eye to follow +18. **Hierarchy**: Important elements are larger/more isolated + +### Technical +19. **Text clean**: `text` contains only readable words +20. **Font**: `fontFamily: 3` +21. **Roughness**: `roughness: 0` for clean/modern (unless hand-drawn style requested) +22. **Opacity**: `opacity: 100` for all elements (no transparency) +23. **Container ratio**: <30% of text elements should be inside containers + +### Visual Validation (Render Required) +24. **Rendered to PNG**: Diagram has been rendered and visually inspected +25. **No text overflow**: All text fits within its container +26. **No clipping**: Screenshot bounds include every title, label, arrow, and shape +27. **No overlapping elements**: Shapes and text don't overlap unintentionally +28. **Even spacing**: Similar elements have consistent spacing +29. **Arrows land correctly**: Arrows connect to intended elements without crossing others +30. **Readable at export size**: Text is legible in the rendered PNG +31. **Balanced composition**: No large empty voids or overcrowded regions +32. **GitHub readable**: The image is understandable when embedded in a PR without opening it full-size diff --git a/parsa/.codex/skills/excalidraw-pr-diagrams/references/color-palette.md b/parsa/.codex/skills/excalidraw-pr-diagrams/references/color-palette.md new file mode 100644 index 0000000..711ea27 --- /dev/null +++ b/parsa/.codex/skills/excalidraw-pr-diagrams/references/color-palette.md @@ -0,0 +1,67 @@ +# Color Palette & Brand Style + +**This is the single source of truth for all colors and brand-specific styles.** To customize diagrams for your own brand, edit this file — everything else in the skill is universal. + +--- + +## Shape Colors (Semantic) + +Colors encode meaning, not decoration. Each semantic purpose has a fill/stroke pair. + +| Semantic Purpose | Fill | Stroke | +|------------------|------|--------| +| Primary/Neutral | `#3b82f6` | `#1e3a5f` | +| Secondary | `#60a5fa` | `#1e3a5f` | +| Tertiary | `#93c5fd` | `#1e3a5f` | +| Start/Trigger | `#fed7aa` | `#c2410c` | +| End/Success | `#a7f3d0` | `#047857` | +| Warning/Reset | `#fee2e2` | `#dc2626` | +| Decision | `#fef3c7` | `#b45309` | +| AI/LLM | `#ddd6fe` | `#6d28d9` | +| Inactive/Disabled | `#dbeafe` | `#1e40af` (use dashed stroke) | +| Error | `#fecaca` | `#b91c1c` | + +**Rule**: Always pair a darker stroke with a lighter fill for contrast. + +--- + +## Text Colors (Hierarchy) + +Use color on free-floating text to create visual hierarchy without containers. + +| Level | Color | Use For | +|-------|-------|---------| +| Title | `#1e40af` | Section headings, major labels | +| Subtitle | `#3b82f6` | Subheadings, secondary labels | +| Body/Detail | `#64748b` | Descriptions, annotations, metadata | +| On light fills | `#374151` | Text inside light-colored shapes | +| On dark fills | `#ffffff` | Text inside dark-colored shapes | + +--- + +## Evidence Artifact Colors + +Used for code snippets, data examples, and other concrete evidence inside technical diagrams. + +| Artifact | Background | Text Color | +|----------|-----------|------------| +| Code snippet | `#1e293b` | Syntax-colored (language-appropriate) | +| JSON/data example | `#1e293b` | `#22c55e` (green) | + +--- + +## Default Stroke & Line Colors + +| Element | Color | +|---------|-------| +| Arrows | Use the stroke color of the source element's semantic purpose | +| Structural lines (dividers, trees, timelines) | Primary stroke (`#1e3a5f`) or Slate (`#64748b`) | +| Marker dots (fill + stroke) | Primary fill (`#3b82f6`) | + +--- + +## Background + +| Property | Value | +|----------|-------| +| Canvas background | `#ffffff` | diff --git a/parsa/.codex/skills/excalidraw-pr-diagrams/references/element-templates.md b/parsa/.codex/skills/excalidraw-pr-diagrams/references/element-templates.md new file mode 100644 index 0000000..30dbf4a --- /dev/null +++ b/parsa/.codex/skills/excalidraw-pr-diagrams/references/element-templates.md @@ -0,0 +1,182 @@ +# Element Templates + +Copy-paste JSON templates for each Excalidraw element type. The `strokeColor` and `backgroundColor` values are placeholders — always pull actual colors from `color-palette.md` based on the element's semantic purpose. + +## Free-Floating Text (no container) +```json +{ + "type": "text", + "id": "label1", + "x": 100, "y": 100, + "width": 200, "height": 25, + "text": "Section Title", + "originalText": "Section Title", + "fontSize": 20, + "fontFamily": 3, + "textAlign": "left", + "verticalAlign": "top", + "strokeColor": "", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 11111, + "version": 1, + "versionNonce": 22222, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "containerId": null, + "lineHeight": 1.25 +} +``` + +## Line (structural, not arrow) +```json +{ + "type": "line", + "id": "line1", + "x": 100, "y": 100, + "width": 0, "height": 200, + "strokeColor": "<structural line color from palette>", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 44444, + "version": 1, + "versionNonce": 55555, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [[0, 0], [0, 200]] +} +``` + +## Small Marker Dot +```json +{ + "type": "ellipse", + "id": "dot1", + "x": 94, "y": 94, + "width": 12, "height": 12, + "strokeColor": "<marker dot color from palette>", + "backgroundColor": "<marker dot color from palette>", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 66666, + "version": 1, + "versionNonce": 77777, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false +} +``` + +## Rectangle +```json +{ + "type": "rectangle", + "id": "elem1", + "x": 100, "y": 100, "width": 180, "height": 90, + "strokeColor": "<stroke from palette based on semantic purpose>", + "backgroundColor": "<fill from palette based on semantic purpose>", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 12345, + "version": 1, + "versionNonce": 67890, + "isDeleted": false, + "groupIds": [], + "boundElements": [{"id": "text1", "type": "text"}], + "link": null, + "locked": false, + "roundness": {"type": 3} +} +``` + +## Text (centered in shape) +```json +{ + "type": "text", + "id": "text1", + "x": 130, "y": 132, + "width": 120, "height": 25, + "text": "Process", + "originalText": "Process", + "fontSize": 16, + "fontFamily": 3, + "textAlign": "center", + "verticalAlign": "middle", + "strokeColor": "<text color — match parent shape's stroke or use 'on light/dark fills' from palette>", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 11111, + "version": 1, + "versionNonce": 22222, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "containerId": "elem1", + "lineHeight": 1.25 +} +``` + +## Arrow +```json +{ + "type": "arrow", + "id": "arrow1", + "x": 282, "y": 145, "width": 118, "height": 0, + "strokeColor": "<arrow color — typically matches source element's stroke from palette>", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "angle": 0, + "seed": 33333, + "version": 1, + "versionNonce": 44444, + "isDeleted": false, + "groupIds": [], + "boundElements": null, + "link": null, + "locked": false, + "points": [[0, 0], [118, 0]], + "startBinding": {"elementId": "elem1", "focus": 0, "gap": 2}, + "endBinding": {"elementId": "elem2", "focus": 0, "gap": 2}, + "startArrowhead": null, + "endArrowhead": "arrow" +} +``` + +For curves: use 3+ points in `points` array. diff --git a/parsa/.codex/skills/excalidraw-pr-diagrams/references/json-schema.md b/parsa/.codex/skills/excalidraw-pr-diagrams/references/json-schema.md new file mode 100644 index 0000000..60383bb --- /dev/null +++ b/parsa/.codex/skills/excalidraw-pr-diagrams/references/json-schema.md @@ -0,0 +1,71 @@ +# Excalidraw JSON Schema + +## Element Types + +| Type | Use For | +|------|---------| +| `rectangle` | Processes, actions, components | +| `ellipse` | Entry/exit points, external systems | +| `diamond` | Decisions, conditionals | +| `arrow` | Connections between shapes | +| `text` | Labels inside shapes | +| `line` | Non-arrow connections | +| `frame` | Grouping containers | + +## Common Properties + +All elements share these: + +| Property | Type | Description | +|----------|------|-------------| +| `id` | string | Unique identifier | +| `type` | string | Element type | +| `x`, `y` | number | Position in pixels | +| `width`, `height` | number | Size in pixels | +| `strokeColor` | string | Border color (hex) | +| `backgroundColor` | string | Fill color (hex or "transparent") | +| `fillStyle` | string | "solid", "hachure", "cross-hatch" | +| `strokeWidth` | number | 1, 2, or 4 | +| `strokeStyle` | string | "solid", "dashed", "dotted" | +| `roughness` | number | 0 (smooth), 1 (default), 2 (rough) | +| `opacity` | number | 0-100 | +| `seed` | number | Random seed for roughness | + +## Text-Specific Properties + +| Property | Description | +|----------|-------------| +| `text` | The display text | +| `originalText` | Same as text | +| `fontSize` | Size in pixels (16-20 recommended) | +| `fontFamily` | 3 for monospace (use this) | +| `textAlign` | "left", "center", "right" | +| `verticalAlign` | "top", "middle", "bottom" | +| `containerId` | ID of parent shape | + +## Arrow-Specific Properties + +| Property | Description | +|----------|-------------| +| `points` | Array of [x, y] coordinates | +| `startBinding` | Connection to start shape | +| `endBinding` | Connection to end shape | +| `startArrowhead` | null, "arrow", "bar", "dot", "triangle" | +| `endArrowhead` | null, "arrow", "bar", "dot", "triangle" | + +## Binding Format + +```json +{ + "elementId": "shapeId", + "focus": 0, + "gap": 2 +} +``` + +## Rectangle Roundness + +Add for rounded corners: +```json +"roundness": { "type": 3 } +``` diff --git a/parsa/.codex/skills/excalidraw-pr-diagrams/references/pyproject.toml b/parsa/.codex/skills/excalidraw-pr-diagrams/references/pyproject.toml new file mode 100644 index 0000000..d88119e --- /dev/null +++ b/parsa/.codex/skills/excalidraw-pr-diagrams/references/pyproject.toml @@ -0,0 +1,7 @@ +[project] +name = "excalidraw-render" +version = "0.1.0" +requires-python = ">=3.11" +dependencies = [ + "playwright>=1.40.0", +] diff --git a/parsa/.codex/skills/excalidraw-pr-diagrams/references/render_excalidraw.py b/parsa/.codex/skills/excalidraw-pr-diagrams/references/render_excalidraw.py new file mode 100644 index 0000000..e7f36fd --- /dev/null +++ b/parsa/.codex/skills/excalidraw-pr-diagrams/references/render_excalidraw.py @@ -0,0 +1,189 @@ +"""Render Excalidraw JSON to PNG using Playwright + headless Chromium. + +Usage: + cd .claude/skills/excalidraw-diagram/references + uv run python render_excalidraw.py <path-to-file.excalidraw> [--output path.png] [--scale 2] [--width 1920] + +First-time setup: + cd .claude/skills/excalidraw-diagram/references + uv sync + uv run playwright install chromium +""" + +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path + + +def validate_excalidraw(data: dict) -> list[str]: + """Validate Excalidraw JSON structure. Returns list of errors (empty = valid).""" + errors: list[str] = [] + + if data.get("type") != "excalidraw": + errors.append(f"Expected type 'excalidraw', got '{data.get('type')}'") + + if "elements" not in data: + errors.append("Missing 'elements' array") + elif not isinstance(data["elements"], list): + errors.append("'elements' must be an array") + elif len(data["elements"]) == 0: + errors.append("'elements' array is empty — nothing to render") + + return errors + + +def compute_bounding_box(elements: list[dict]) -> tuple[float, float, float, float]: + """Compute bounding box (min_x, min_y, max_x, max_y) across all elements.""" + min_x = float("inf") + min_y = float("inf") + max_x = float("-inf") + max_y = float("-inf") + + for el in elements: + if el.get("isDeleted"): + continue + x = el.get("x", 0) + y = el.get("y", 0) + w = el.get("width", 0) + h = el.get("height", 0) + + # For arrows/lines, points array defines the shape relative to x,y + if el.get("type") in ("arrow", "line") and "points" in el: + for px, py in el["points"]: + min_x = min(min_x, x + px) + min_y = min(min_y, y + py) + max_x = max(max_x, x + px) + max_y = max(max_y, y + py) + else: + min_x = min(min_x, x) + min_y = min(min_y, y) + max_x = max(max_x, x + abs(w)) + max_y = max(max_y, y + abs(h)) + + if min_x == float("inf"): + return (0, 0, 800, 600) + + return (min_x, min_y, max_x, max_y) + + +def render( + excalidraw_path: Path, + output_path: Path | None = None, + scale: int = 2, + max_width: int = 1920, +) -> Path: + """Render an .excalidraw file to PNG. Returns the output PNG path.""" + # Import playwright here so validation errors show before import errors + try: + from playwright.sync_api import sync_playwright + except ImportError: + print("ERROR: playwright not installed.", file=sys.stderr) + print("Run: cd .claude/skills/excalidraw-diagram/references && uv sync && uv run playwright install chromium", file=sys.stderr) + sys.exit(1) + + # Read and validate + raw = excalidraw_path.read_text(encoding="utf-8") + try: + data = json.loads(raw) + except json.JSONDecodeError as e: + print(f"ERROR: Invalid JSON in {excalidraw_path}: {e}", file=sys.stderr) + sys.exit(1) + + errors = validate_excalidraw(data) + if errors: + print(f"ERROR: Invalid Excalidraw file:", file=sys.stderr) + for err in errors: + print(f" - {err}", file=sys.stderr) + sys.exit(1) + + # Compute viewport size from element bounding box + elements = [e for e in data["elements"] if not e.get("isDeleted")] + min_x, min_y, max_x, max_y = compute_bounding_box(elements) + padding = 80 + diagram_w = max_x - min_x + padding * 2 + diagram_h = max_y - min_y + padding * 2 + + # Cap viewport width, let height be natural + vp_width = min(int(diagram_w), max_width) + vp_height = max(int(diagram_h), 600) + + # Output path + if output_path is None: + output_path = excalidraw_path.with_suffix(".png") + + # Template path (same directory as this script) + template_path = Path(__file__).parent / "render_template.html" + if not template_path.exists(): + print(f"ERROR: Template not found at {template_path}", file=sys.stderr) + sys.exit(1) + + template_url = template_path.as_uri() + + with sync_playwright() as p: + try: + browser = p.chromium.launch(headless=True) + except Exception as e: + if "Executable doesn't exist" in str(e) or "browserType.launch" in str(e): + print("ERROR: Chromium not installed for Playwright.", file=sys.stderr) + print("Run: cd .claude/skills/excalidraw-diagram/references && uv run playwright install chromium", file=sys.stderr) + sys.exit(1) + raise + + page = browser.new_page( + viewport={"width": vp_width, "height": vp_height}, + device_scale_factor=scale, + ) + + # Load the template + page.goto(template_url) + + # Wait for the ES module to load (imports from esm.sh) + page.wait_for_function("window.__moduleReady === true", timeout=30000) + + # Inject the diagram data and render + json_str = json.dumps(data) + result = page.evaluate(f"window.renderDiagram({json_str})") + + if not result or not result.get("success"): + error_msg = result.get("error", "Unknown render error") if result else "renderDiagram returned null" + print(f"ERROR: Render failed: {error_msg}", file=sys.stderr) + browser.close() + sys.exit(1) + + # Wait for render completion signal + page.wait_for_function("window.__renderComplete === true", timeout=15000) + + # Screenshot the SVG element + svg_el = page.query_selector("#root svg") + if svg_el is None: + print("ERROR: No SVG element found after render.", file=sys.stderr) + browser.close() + sys.exit(1) + + svg_el.screenshot(path=str(output_path)) + browser.close() + + return output_path + + +def main() -> None: + parser = argparse.ArgumentParser(description="Render Excalidraw JSON to PNG") + parser.add_argument("input", type=Path, help="Path to .excalidraw JSON file") + parser.add_argument("--output", "-o", type=Path, default=None, help="Output PNG path (default: same name with .png)") + parser.add_argument("--scale", "-s", type=int, default=2, help="Device scale factor (default: 2)") + parser.add_argument("--width", "-w", type=int, default=1920, help="Max viewport width (default: 1920)") + args = parser.parse_args() + + if not args.input.exists(): + print(f"ERROR: File not found: {args.input}", file=sys.stderr) + sys.exit(1) + + png_path = render(args.input, args.output, args.scale, args.width) + print(str(png_path)) + + +if __name__ == "__main__": + main() diff --git a/parsa/.codex/skills/excalidraw-pr-diagrams/references/render_template.html b/parsa/.codex/skills/excalidraw-pr-diagrams/references/render_template.html new file mode 100644 index 0000000..877e33d --- /dev/null +++ b/parsa/.codex/skills/excalidraw-pr-diagrams/references/render_template.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8" /> + <style> + * { margin: 0; padding: 0; box-sizing: border-box; } + body { background: #ffffff; overflow: hidden; } + #root { display: inline-block; } + #root svg { display: block; } + </style> +</head> +<body> + <div id="root"></div> + + <script type="module"> + import { exportToSvg } from "https://esm.sh/@excalidraw/excalidraw@0.18.0?bundle"; + + window.renderDiagram = async function(jsonData) { + try { + const data = typeof jsonData === "string" ? JSON.parse(jsonData) : jsonData; + const elements = data.elements || []; + const appState = data.appState || {}; + const files = data.files || {}; + + // Force white background in appState + appState.viewBackgroundColor = appState.viewBackgroundColor || "#ffffff"; + appState.exportWithDarkMode = false; + + const svg = await exportToSvg({ + elements: elements, + appState: { + ...appState, + exportBackground: true, + }, + files: files, + }); + + // Clear any previous render + const root = document.getElementById("root"); + root.innerHTML = ""; + root.appendChild(svg); + + window.__renderComplete = true; + window.__renderError = null; + return { success: true, width: svg.getAttribute("width"), height: svg.getAttribute("height") }; + } catch (err) { + window.__renderComplete = true; + window.__renderError = err.message; + return { success: false, error: err.message }; + } + }; + + // Signal that the module is loaded and ready + window.__moduleReady = true; + </script> +</body> +</html> diff --git a/parsa/.codex/skills/prepare-pr/SKILL.md b/parsa/.codex/skills/prepare-pr/SKILL.md index fd819af..8ea4416 100644 --- a/parsa/.codex/skills/prepare-pr/SKILL.md +++ b/parsa/.codex/skills/prepare-pr/SKILL.md @@ -13,8 +13,14 @@ Workflow: 3. Fetch and rebase onto `origin/main`. 4. Resolve obvious conflicts directly. Ask the user about semantic conflicts. 5. Run the relevant build steps and fix straightforward failures. -6. Create or update the PR with a summary built from the plans and current diff. -7. Push with `--force-with-lease` only when rebase made it necessary. +6. Create a visual PR diagram before opening/updating the PR: + - Use the `excalidraw-pr-diagrams` skill. + - Keep all generated diagram working files under `/tmp`, usually `/tmp/codex-pr-diagrams/<branch-or-pr>/`. + - Add a `## Visual Overview` section to the PR body. + - Include explicit `Before` and `After` diagrams in the visual overview. + - Prefer GitHub-rendered Mermaid in the PR body and save matching `.excalidraw` source under `/tmp`. +7. Create or update the PR with a summary built from the plans, current diff, and visual overview. +8. Push with `--force-with-lease` only when rebase made it necessary. Rules: - Never use blanket staging.