visualise Agent Skill

repository·main·Indexed 19 days ago

https://github.com/bentossell/visualise

An Agent Skill that enables coding agents to generate rich, interactive visual content, including SVG diagrams, HTML widgets, and charts, directly within chat interfaces. It provides a progressive disclosure mechanism for design systems, components, and data visualization patterns using Chart.js and D3.js. The skill outputs HTML/SVG fragments wrapped in a `visualizer` code fence, requiring a client-side renderer to display content within a sandboxed <iframe>.

Tokens
10.5K
Snippets
19
Records
42
Agent score
67%

What's inside visualise

  1. How the Inline Visualizer works

    main

    The Inline Visualizer renders rich visual content like SVG diagrams, HTML interactive widgets, and charts directly within a chat conversation using a sandboxed iframe.

    Content is provided as raw HTML or SVG fragments. The client automatically detects the mode based on the starting tag:

    • SVG mode: Output starts with <svg>. The client wraps this in a card. Best for static diagrams.
    • HTML mode: Raw HTML fragments. Best for interactive content (sliders, tabs, charts, controls). You can embed <svg> elements inside HTML mode.

    Important: Do not include <!DOCTYPE>, <html>, <head>, or <body> tags. Only provide the content fragments.

    <svg width="100%" viewBox="0 0 680 400">
      <!-- SVG content here -->
    </svg>
  2. Choose the correct diagram type based on intent

    main

    Select a diagram family based on the user's question (the 'trigger') rather than the subject matter:

    • Flowchart: Use for sequential steps, decision branching, workflows, pipelines, or request lifecycles. (Trigger: "what are the steps")
    • Structural: Use for containment, architecture, or hierarchy (e.g., VPC/subnets, file systems). (Trigger: "where does X live")
    • Illustrative: Use to explain the internal mechanism or build intuition. Use spatial metaphors for abstract concepts (e.g., LLM layers) or cross-sections for physical objects. (Trigger: "how does X actually work")
  3. Adhere to iframe sandbox rules

    main

    Visuals render in a sandboxed iframe with strict security and layout constraints:

    • No localStorage / sessionStorage: All state must be managed in-memory.
    • No position: fixed: The iframe auto-sizes to content height; fixed elements will cause the container to collapse.
    • No external fetches: Content Security Policy (CSP) blocks all API calls from inside the widget.
    • CDN Allowlist: You may only load libraries via <script src="..."> from these CDNs:
      • cdnjs.cloudflare.com (Recommended for UMD globals)
      • esm.sh
      • cdn.jsdelivr.net
      • unpkg.com
    • Transparent Background: The host provides the container/card styling; do not attempt to style the background of the iframe itself.
  4. How the visualise skill generates content

    main

    The skill uses a progressive disclosure mechanism to minimize token usage. It starts by loading only the name and description, then pulls in specific reference documentation only when needed:

    • design-system.md: CSS variables, color ramps, and typography.
    • components.md: Interactive explainers, comparisons, cards, and steppers.
    • diagrams.md: Flowcharts, structural, and illustrative diagrams.
    • charts.md: Chart.js and data visualization patterns.

    Output is provided as raw HTML/SVG fragments. There is no build step or external dependencies required.

  5. How the Visualizer architecture works

    main

    The visualizer operates through a specific lifecycle to render model-generated code safely within a chat interface:

    1. Generation: The model generates code guided by SKILL.md and references.
    2. Fencing: The code is wrapped in a ```visualizer code fence.
    3. Detection: The client detects the fence and strips the markdown tags.
    4. Sandboxing: A sandboxed <iframe> is created to isolate the execution.
    5. Injection: The client injects Theme CSS, SVG classes, and the widget code into the iframe.
    6. Auto-sizing: A ResizeObserver inside the client automatically adjusts the iframe height based on the content.
    7. Communication: A sendPrompt bridge is established to connect interactions (like clicks) inside the iframe back to the main chat interface.
  6. Apply the core aesthetic and design tokens

    main

    The visualise UI follows a flat, clean aesthetic with white surfaces and minimal borders. When building components, use the following design tokens to maintain consistency:

    • Borders: Use 0.5px solid var(--color-border-tertiary) for standard borders, or var(--color-border-secondary) for emphasis.
    • Corner Radius: Use var(--border-radius-md) for most elements and var(--border-radius-lg) for cards.
    • Cards: Use a white background, 0.5px border, var(--border-radius-lg), and padding of 1rem 1.25rem.
    • Spacing: Use rem for vertical rhythm and specific pixel values (8px, 12px, 16px) for internal gaps.
    • Form Elements: Inputs, selects, buttons, and range sliders are pre-styled. Use bare HTML tags and only override specific properties if necessary. For buttons that trigger sendPrompt, append a arrow.
  7. Assign Colors using Color Ramps

    main

    The design system uses 9 named color ramps (purple, teal, coral, pink, gray, blue, green, amber, red), each with 7 stops (50 to 900).

    Color Assignment Rules:

    • Meaning over sequence: Do not cycle colors like a rainbow. Group nodes by category.
    • Neutrality: Use gray for structural nodes (start, end, generic steps).
    • Complexity: Limit to 2-3 colors per diagram.
    • Semantic Mapping: Use blue, green, amber, red for info, success, warning, and error. Use purple, teal, coral, pink for general categories.
    • Text on Color: When placing text on a colored background, use the 800 or 900 stop from the same ramp. Use 800 for titles and 600 for subtitles.

    Light/Dark Mode Logic:

    • Light mode: 50 fill + 600 stroke + 800 title / 600 subtitle
    • Dark mode: 800 fill + 200 stroke + 100 title / 200 subtitle
  8. Set up Chart.js for data visualization

    main

    To use Chart.js, you must use HTML mode. Wrap the <canvas> element in a container with an explicit height and position: relative. Ensure the chart configuration includes responsive: true and maintainAspectRatio: false.

    To maintain visual consistency with the application theme, do not hardcode gray colors for text or borders; instead, use getComputedStyle to read CSS variables like --color-text-secondary and --color-border-tertiary.

    <div style="position: relative; height: 300px;">
      <canvas id="chart"></canvas>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js"></script>
    <script>
    const ctx = document.getElementById('chart').getContext('2d');
    const style = getComputedStyle(document.documentElement);
    const textSecondary = style.getPropertyValue('--color-text-secondary').trim();
    const borderDefault = style.getPropertyValue('--color-border-tertiary').trim();
    
    new Chart(ctx, {
      type: 'bar',
      data: {
        labels: ['Q1', 'Q2', 'Q3', 'Q4'],
        datasets: [{
          label: 'Revenue',
          data: [12, 19, 8, 15],
          backgroundColor: '#5DCAA5',
          borderRadius: 4,
          borderSkipped: false,
        }]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
          legend: { labels: { color: textSecondary, font: { size: 12 } } }
        },
        scales: {
          x: { grid: { display: false }, ticks: { color: textSecondary, font: { size: 12 } }, border: { color: borderDefault } },
          y: { grid: { color: borderDefault }, ticks: { color: textSecondary, font: { size: 12 } }, border: { display: false } }
        }
      }
    });
    </script>
  9. Follow critical rules for Chart.js styling

    main

    When implementing Chart.js, adhere to these styling constraints to ensure consistency:

    • Container: Wrap canvas in a container with explicit height and position: relative.
    • Responsiveness: Set responsive: true and maintainAspectRatio: false.
    • Theming: Read CSS variables for text/border colors—never hardcode grays.
    • Colors: Use ramp colors for data series. For area or line fills, use the same color at 20% opacity.
    • Geometry: Use borderRadius: 4 on bars.
    • Grid Lines: Hide the x-axis grid; show the y-axis grid using the border color.
    • Typography: Use a font size of 12px for all chart text.
  10. Wrap visual output in visualizer code fences

    main

    To trigger the client's iframe renderer, you must wrap your HTML or SVG content in a code fence with the visualizer language tag. The client will strip the fence and inject the content into the sandboxed iframe with design system theme variables prepended.

    <svg width="100%" viewBox="0 0 680 400">
      <rect width="100" height="100" fill="blue" />
    </svg>
  11. Use D3.js for complex custom visualizations

    main

    Use D3.js only when Chart.js cannot handle the required layout. D3.js is intended for complex custom visualizations such as force graphs, maps, or treemaps.

    <div id="viz"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js"></script>
    <script>
    const svg = d3.select('#viz').append('svg')
      .attr('width', '100%').attr('viewBox', '0 0 680 400');
    </script>
  12. Follow structural diagram rules for containment

    main

    Structural diagrams represent things inside other things using nested rectangles:

    • Containers (Outermost): Use rx=20-24, the lightest fill (50 stop), and a 0.5px stroke.
    • Inner Regions: Use rx=8-12, a darker shade (100-200 stop), and a different color ramp if semantically distinct.
    • Padding: Maintain a minimum of 20px padding inside every container.
    • Nesting: Limit to a maximum of 2-3 nesting levels.
    • Hierarchy: Use distinct color ramps for nested regions; using the same class on parent and child flattens the hierarchy.
    • ERDs: Do not use SVG for Entity Relationship Diagrams; use mermaid.js via esm.sh/mermaid@11 instead.