{
  "format": "flowstage-source-catalogue",
  "formatVersion": 1,
  "title": "Flowstage source catalogue",
  "description": "Custom source metadata for direct downloads. Not a shadcn registry, npm manifest, or executable installer.",
  "base": "Resolve paths against the directory containing this registry.json. Preserve any hosting path prefix.",
  "instructions": "agent-skill.md",
  "discovery": "llms.txt",
  "itemSchema": {
    "required": [
      "id",
      "name",
      "kind",
      "description",
      "files",
      "entrypoint",
      "anatomy",
      "tokens",
      "states",
      "integration"
    ],
    "files": "Array of {path, type}; path is relative to site root. Include only real fetchable files.",
    "extension": "UI components are added to the same items array with kind 'ui-component'. Each item must list its actual source, entrypoint, anatomy, tokens and supported states."
  },
  "items": [
    {
      "id": "flowkit",
      "name": "FlowKit stage",
      "kind": "flow-diagram",
      "description": "Inputs connect through a central process to selectable outcomes.",
      "preview": "examples/",
      "reference": "docs/api.html",
      "example": "registry/flowkit-starter.html",
      "files": [
        {
          "path": "lib/flowkit.css",
          "type": "stylesheet"
        },
        {
          "path": "lib/flowkit.js",
          "type": "script"
        },
        {
          "path": "registry/flowkit-starter.html",
          "type": "example"
        }
      ],
      "entrypoint": "FlowKit.embed(container, config, options)",
      "dependencies": [],
      "anatomy": [
        {
          "selector": ".fk-sources",
          "purpose": "Labelled input sources"
        },
        {
          "selector": ".fk-wires",
          "purpose": "Curved connectors and SVG signal pulses"
        },
        {
          "selector": ".fk-card",
          "purpose": "Central process and switchable views"
        },
        {
          "selector": ".fk-outcomes",
          "purpose": "Selectable outcomes"
        },
        {
          "selector": ".fk-feedback",
          "purpose": "Feedback explanation"
        }
      ],
      "tokens": [
        "--fk-page-bg",
        "--fk-stage-bg",
        "--fk-stage-border",
        "--fk-text",
        "--fk-text-dim",
        "--fk-text-faint",
        "--fk-wire",
        "--fk-panel",
        "--fk-panel-border",
        "--fk-accent",
        "--fk-font"
      ],
      "states": [
        "Initial view: opts.view or first config.center.views key",
        "Selected outcome: selectOutcome(id)",
        "Active source: setActiveSource(id)",
        "Changed central view: setView(name)",
        "Paused animation: setPaused(true)",
        "Destroyed: destroy()"
      ],
      "integration": "Download the two lib files and the complete starter. Keep lib/ and registry/ as sibling directories or adjust the starter links. FlowKit.embed auto-sizes a fixed design canvas. FlowKit.create requires a sized .fk-root and setView().",
      "trustBoundary": "Configuration includes executable render functions and HTML strings. Use trusted application-owned config; sanitize external content before any HTML insertion."
    },
    {
      "id": "motion-path-pulse",
      "name": "Path pulse",
      "kind": "svg-motion",
      "description": "A signal travels along a curved input-to-output connection.",
      "preview": "motion/#path-pulse",
      "reference": "registry/motion.md",
      "files": [
        {
          "path": "lib/motion.css",
          "type": "stylesheet"
        },
        {
          "path": "lib/motion.js",
          "type": "script"
        }
      ],
      "entrypoint": "FlowstageMotion.mount(container, { type: 'path-pulse', speed: 1 })",
      "dependencies": [],
      "anatomy": [
        "Input node",
        "Curved wire",
        "Gradient pulse and tail",
        "Output node"
      ],
      "tokens": {
        "--fsm-accent": "#b9a2ff",
        "--fsm-pink": "#e5add0",
        "--fsm-wire": "#555b68",
        "--fsm-text": "#ededf0",
        "--fsm-muted": "#9298a5",
        "--fsm-panel": "#15181e"
      },
      "states": [
        "Playing: play()",
        "Paused at current position: pause()",
        "Static: setReducedMotion(true), or system prefers-reduced-motion",
        "Speed: setSpeed(number), clamped 0.25–3",
        "Restart timeline: restart()",
        "Hidden document: effective playback stops",
        "Destroyed: destroy()"
      ],
      "integration": "Save the two files into lib/. Load the stylesheet, create a container, load the script, then call the entrypoint. Include a visible pause control. See reference for a complete snippet and the gallery Copy HTML action for a self-contained document.",
      "accessibility": "SVG role=img with title and description; OS reduced motion always respected. Keep live application status in visible text outside the illustrative SVG.",
      "trustBoundary": "Generated SVG geometry is library-owned; custom label is inserted with textContent."
    },
    {
      "id": "motion-orbit",
      "name": "Orbit",
      "kind": "svg-motion",
      "description": "Signals orbit a central process on two elliptical tracks.",
      "preview": "motion/#orbit",
      "reference": "registry/motion.md",
      "files": [
        {
          "path": "lib/motion.css",
          "type": "stylesheet"
        },
        {
          "path": "lib/motion.js",
          "type": "script"
        }
      ],
      "entrypoint": "FlowstageMotion.mount(container, { type: 'orbit', speed: 1 })",
      "dependencies": [],
      "anatomy": [
        "Core node",
        "Two elliptical tracks",
        "Three signal dots"
      ],
      "tokens": {
        "--fsm-accent": "#b9a2ff",
        "--fsm-pink": "#e5add0",
        "--fsm-wire": "#555b68",
        "--fsm-text": "#ededf0",
        "--fsm-muted": "#9298a5",
        "--fsm-panel": "#15181e"
      },
      "states": [
        "Playing: play()",
        "Paused at current position: pause()",
        "Static: setReducedMotion(true), or system prefers-reduced-motion",
        "Speed: setSpeed(number), clamped 0.25–3",
        "Restart timeline: restart()",
        "Hidden document: effective playback stops",
        "Destroyed: destroy()"
      ],
      "integration": "Save the two files into lib/. Load the stylesheet, create a container, load the script, then call the entrypoint. Include a visible pause control. See reference for a complete snippet and the gallery Copy HTML action for a self-contained document.",
      "accessibility": "SVG role=img with title and description; OS reduced motion always respected. Keep live application status in visible text outside the illustrative SVG.",
      "trustBoundary": "Generated SVG geometry is library-owned; custom label is inserted with textContent."
    },
    {
      "id": "motion-draw-path",
      "name": "Branching paths",
      "kind": "svg-motion",
      "description": "An input trunk and three output branches draw in sequence.",
      "preview": "motion/#draw-path",
      "reference": "registry/motion.md",
      "files": [
        {
          "path": "lib/motion.css",
          "type": "stylesheet"
        },
        {
          "path": "lib/motion.js",
          "type": "script"
        }
      ],
      "entrypoint": "FlowstageMotion.mount(container, { type: 'draw-path', speed: 1 })",
      "dependencies": [],
      "anatomy": [
        "Input node",
        "Trunk",
        "Junction",
        "Three branches",
        "Output nodes"
      ],
      "tokens": {
        "--fsm-accent": "#b9a2ff",
        "--fsm-pink": "#e5add0",
        "--fsm-wire": "#555b68",
        "--fsm-text": "#ededf0",
        "--fsm-muted": "#9298a5",
        "--fsm-panel": "#15181e"
      },
      "states": [
        "Playing: play()",
        "Paused at current position: pause()",
        "Static: setReducedMotion(true), or system prefers-reduced-motion",
        "Speed: setSpeed(number), clamped 0.25–3",
        "Restart timeline: restart()",
        "Hidden document: effective playback stops",
        "Destroyed: destroy()"
      ],
      "integration": "Save the two files into lib/. Load the stylesheet, create a container, load the script, then call the entrypoint. Include a visible pause control. See reference for a complete snippet and the gallery Copy HTML action for a self-contained document.",
      "accessibility": "SVG role=img with title and description; OS reduced motion always respected. Keep live application status in visible text outside the illustrative SVG.",
      "trustBoundary": "Generated SVG geometry is library-owned; custom label is inserted with textContent."
    },
    {
      "id": "motion-state-morph",
      "name": "State morph",
      "kind": "svg-motion",
      "description": "A circle morphs to a rounded square by interpolating cubic Bézier control points.",
      "preview": "motion/#state-morph",
      "reference": "registry/motion.md",
      "files": [
        {
          "path": "lib/motion.css",
          "type": "stylesheet"
        },
        {
          "path": "lib/motion.js",
          "type": "script"
        }
      ],
      "entrypoint": "FlowstageMotion.mount(container, { type: 'state-morph', speed: 1 })",
      "dependencies": [],
      "anatomy": [
        "Morphing shape",
        "Waiting ring",
        "Completion mark",
        "Queued / processing / ready label"
      ],
      "tokens": {
        "--fsm-accent": "#b9a2ff",
        "--fsm-pink": "#e5add0",
        "--fsm-wire": "#555b68",
        "--fsm-text": "#ededf0",
        "--fsm-muted": "#9298a5",
        "--fsm-panel": "#15181e"
      },
      "states": [
        "Playing: play()",
        "Paused at current position: pause()",
        "Static: setReducedMotion(true), or system prefers-reduced-motion",
        "Speed: setSpeed(number), clamped 0.25–3",
        "Restart timeline: restart()",
        "Hidden document: effective playback stops",
        "Destroyed: destroy()"
      ],
      "integration": "Save the two files into lib/. Load the stylesheet, create a container, load the script, then call the entrypoint. Include a visible pause control. See reference for a complete snippet and the gallery Copy HTML action for a self-contained document.",
      "accessibility": "SVG role=img with title and description; OS reduced motion always respected. Keep live application status in visible text outside the illustrative SVG.",
      "trustBoundary": "Generated SVG geometry is library-owned; custom label is inserted with textContent."
    },
    {
      "id": "thinking-trace",
      "name": "Thinking trace",
      "kind": "ui-component",
      "description": "Make progress understandable with an expandable summary of each step.",
      "preview": "components/#thinking-trace",
      "reference": "components/README.md",
      "files": [
        {
          "path": "lib/components.js",
          "type": "script"
        },
        {
          "path": "lib/components.css",
          "type": "stylesheet"
        }
      ],
      "entrypoint": "FlowstageUI.mount(container, { type: \"thinking-trace\", ...options })",
      "dependencies": [],
      "anatomy": [
        "Heading",
        "Progress summary",
        "Step status",
        "Disclosure button",
        "Step detail"
      ],
      "tokens": [
        "--fsui-bg",
        "--fsui-panel",
        "--fsui-border",
        "--fsui-text",
        "--fsui-muted",
        "--fsui-accent",
        "--fsui-radius",
        "--fsui-success",
        "--fsui-blue"
      ],
      "states": [
        "collapsed",
        "expanded",
        "complete",
        "running",
        "queued",
        "error"
      ],
      "accessibility": "Native buttons expose aria-expanded and aria-controls. Details are hidden when collapsed. Status is written in text.",
      "integration": {
        "config": {
          "type": "thinking-trace",
          "title": "Reviewing the project",
          "subtitle": "A summary of the work performed",
          "steps": [
            {
              "title": "Read the project brief",
              "detail": "Identified the audience, required pages, and constraints in the supplied brief.",
              "meta": "Project brief · 4 sections",
              "status": "complete"
            },
            {
              "title": "Compare the existing screens",
              "detail": "Checked navigation, content density, and repeated controls across the three example screens.",
              "meta": "3 screens reviewed",
              "status": "complete"
            },
            {
              "title": "Prepare a focused proposal",
              "detail": "Grouped the findings into navigation, typography, and interaction changes for review.",
              "meta": "Proposal ready",
              "status": "complete"
            }
          ]
        },
        "snippet": "const component = FlowstageUI.mount(\n  document.querySelector('#demo'),\n  {\n    \"type\": \"thinking-trace\",\n    \"title\": \"Reviewing the project\",\n    \"subtitle\": \"A summary of the work performed\",\n    \"steps\": [\n      {\n        \"title\": \"Read the project brief\",\n        \"detail\": \"Identified the audience, required pages, and constraints in the supplied brief.\",\n        \"meta\": \"Project brief · 4 sections\",\n        \"status\": \"complete\"\n      },\n      {\n        \"title\": \"Compare the existing screens\",\n        \"detail\": \"Checked navigation, content density, and repeated controls across the three example screens.\",\n        \"meta\": \"3 screens reviewed\",\n        \"status\": \"complete\"\n      },\n      {\n        \"title\": \"Prepare a focused proposal\",\n        \"detail\": \"Grouped the findings into navigation, typography, and interaction changes for review.\",\n        \"meta\": \"Proposal ready\",\n        \"status\": \"complete\"\n      }\n    ]\n  }\n);\n\n// Read a snapshot; clean up when the view leaves.\ncomponent.getState();\n// component.destroy();",
        "methods": [
          "toggle(index)",
          "expandAll()",
          "collapseAll()"
        ],
        "instructions": "Show task progress and short summaries of work performed. The sample content is authored, not a model reasoning transcript."
      }
    },
    {
      "id": "streaming-response",
      "name": "Streaming response",
      "kind": "ui-component",
      "description": "A readable response with pause, resume, and replay controls.",
      "preview": "components/#streaming-response",
      "reference": "components/README.md",
      "files": [
        {
          "path": "lib/components.js",
          "type": "script"
        },
        {
          "path": "lib/components.css",
          "type": "stylesheet"
        }
      ],
      "entrypoint": "FlowstageUI.mount(container, { type: \"streaming-response\", ...options })",
      "dependencies": [],
      "anatomy": [
        "Assistant identity",
        "Status",
        "Response text",
        "Playback controls"
      ],
      "tokens": [
        "--fsui-bg",
        "--fsui-panel",
        "--fsui-border",
        "--fsui-text",
        "--fsui-muted",
        "--fsui-accent",
        "--fsui-radius",
        "--fsui-success",
        "--fsui-blue"
      ],
      "states": [
        "complete",
        "streaming",
        "paused"
      ],
      "accessibility": "Completion is announced once through a polite status region. Streaming text does not announce every token. Reduced motion reveals the whole response immediately.",
      "integration": {
        "config": {
          "type": "streaming-response",
          "title": "Project assistant",
          "subtitle": "Example response",
          "text": "Start with a single project overview. Keep the current task, recent activity, and next decision together so people can understand the project at a glance.\n\nMove secondary settings into a separate panel. Use a consistent status label on every task, and show the next available action beside it.",
          "interval": 55
        },
        "snippet": "const component = FlowstageUI.mount(\n  document.querySelector('#demo'),\n  {\n    \"type\": \"streaming-response\",\n    \"title\": \"Project assistant\",\n    \"subtitle\": \"Example response\",\n    \"text\": \"Start with a single project overview. Keep the current task, recent activity, and next decision together so people can understand the project at a glance.\\n\\nMove secondary settings into a separate panel. Use a consistent status label on every task, and show the next available action beside it.\",\n    \"interval\": 55\n  }\n);\n\n// Read a snapshot; clean up when the view leaves.\ncomponent.getState();\n// component.destroy();",
        "methods": [
          "replay()",
          "pause()",
          "resume()"
        ],
        "instructions": "Preview a progressive text response. Playback uses a local timer and supplied text; it does not connect to a model."
      }
    },
    {
      "id": "approval-card",
      "name": "Approval card",
      "kind": "ui-component",
      "description": "Put the scope and consequence of a change beside the decision.",
      "preview": "components/#approval-card",
      "reference": "components/README.md",
      "files": [
        {
          "path": "lib/components.js",
          "type": "script"
        },
        {
          "path": "lib/components.css",
          "type": "stylesheet"
        }
      ],
      "entrypoint": "FlowstageUI.mount(container, { type: \"approval-card\", ...options })",
      "dependencies": [],
      "anatomy": [
        "Requested action",
        "Change facts",
        "Scope radio group",
        "Approve and reject actions",
        "Decision receipt"
      ],
      "tokens": [
        "--fsui-bg",
        "--fsui-panel",
        "--fsui-border",
        "--fsui-text",
        "--fsui-muted",
        "--fsui-accent",
        "--fsui-radius"
      ],
      "states": [
        "pending",
        "approved",
        "rejected"
      ],
      "accessibility": "The scope uses a labeled native radio group. A polite region announces decisions; reset restores focus to the first scope.",
      "integration": {
        "config": {
          "type": "approval-card",
          "title": "Review the proposed change",
          "subtitle": "Your decision is required",
          "action": "Update project settings",
          "description": "Change the default project view from Board to Overview.",
          "facts": [
            {
              "label": "Project",
              "value": "Website refresh"
            },
            {
              "label": "Change",
              "value": "Default view → Overview"
            }
          ],
          "options": [
            {
              "id": "once",
              "label": "Approve this change only",
              "detail": "Ask again for the next change."
            },
            {
              "id": "session",
              "label": "Allow view changes this session",
              "detail": "Other settings still need approval."
            }
          ]
        },
        "snippet": "const component = FlowstageUI.mount(\n  document.querySelector('#demo'),\n  {\n    \"type\": \"approval-card\",\n    \"title\": \"Review the proposed change\",\n    \"subtitle\": \"Your decision is required\",\n    \"action\": \"Update project settings\",\n    \"description\": \"Change the default project view from Board to Overview.\",\n    \"facts\": [\n      {\n        \"label\": \"Project\",\n        \"value\": \"Website refresh\"\n      },\n      {\n        \"label\": \"Change\",\n        \"value\": \"Default view → Overview\"\n      }\n    ],\n    \"options\": [\n      {\n        \"id\": \"once\",\n        \"label\": \"Approve this change only\",\n        \"detail\": \"Ask again for the next change.\"\n      },\n      {\n        \"id\": \"session\",\n        \"label\": \"Allow view changes this session\",\n        \"detail\": \"Other settings still need approval.\"\n      }\n    ]\n  }\n);\n\n// Read a snapshot; clean up when the view leaves.\ncomponent.getState();\n// component.destroy();",
        "methods": [
          "select(scopeId)",
          "approve()",
          "reject()"
        ],
        "instructions": "Collect an explicit decision. This component only reports UI state; the host application must enforce permissions before performing an action."
      }
    },
    {
      "id": "task-list",
      "name": "Task list",
      "kind": "ui-component",
      "description": "Keep completion, failure, and the next action visible in one list.",
      "preview": "components/#task-list",
      "reference": "components/README.md",
      "files": [
        {
          "path": "lib/components.js",
          "type": "script"
        },
        {
          "path": "lib/components.css",
          "type": "stylesheet"
        }
      ],
      "entrypoint": "FlowstageUI.mount(container, { type: \"task-list\", ...options })",
      "dependencies": [],
      "anatomy": [
        "Workflow heading",
        "Progress bar",
        "Task rows",
        "Status labels",
        "Run and retry controls"
      ],
      "tokens": [
        "--fsui-bg",
        "--fsui-panel",
        "--fsui-border",
        "--fsui-text",
        "--fsui-muted",
        "--fsui-accent",
        "--fsui-radius",
        "--fsui-success",
        "--fsui-blue"
      ],
      "states": [
        "queued",
        "running",
        "complete",
        "error",
        "paused"
      ],
      "accessibility": "Each task has a text status. Progress uses a native progress element; workflow updates use a polite status region. Timers stop on pause or destroy.",
      "integration": {
        "config": {
          "type": "task-list",
          "title": "Prepare the project update",
          "subtitle": "A small, recoverable workflow",
          "tasks": [
            {
              "id": "brief",
              "title": "Read project brief",
              "detail": "Requirements collected",
              "status": "complete"
            },
            {
              "id": "screens",
              "title": "Check screen references",
              "detail": "Example failure · retry to continue",
              "status": "error"
            },
            {
              "id": "summary",
              "title": "Write the change summary",
              "detail": "Waiting for references",
              "status": "queued"
            }
          ],
          "duration": 850
        },
        "snippet": "const component = FlowstageUI.mount(\n  document.querySelector('#demo'),\n  {\n    \"type\": \"task-list\",\n    \"title\": \"Prepare the project update\",\n    \"subtitle\": \"A small, recoverable workflow\",\n    \"tasks\": [\n      {\n        \"id\": \"brief\",\n        \"title\": \"Read project brief\",\n        \"detail\": \"Requirements collected\",\n        \"status\": \"complete\"\n      },\n      {\n        \"id\": \"screens\",\n        \"title\": \"Check screen references\",\n        \"detail\": \"Example failure · retry to continue\",\n        \"status\": \"error\"\n      },\n      {\n        \"id\": \"summary\",\n        \"title\": \"Write the change summary\",\n        \"detail\": \"Waiting for references\",\n        \"status\": \"queued\"\n      }\n    ],\n    \"duration\": 850\n  }\n);\n\n// Read a snapshot; clean up when the view leaves.\ncomponent.getState();\n// component.destroy();",
        "methods": [
          "run()",
          "retry(id)",
          "pause()"
        ],
        "instructions": "Present a short sequential workflow. Run and retry simulate local work without accessing files or services."
      }
    },
    {
      "id": "context-sources",
      "name": "Context sources",
      "kind": "ui-component",
      "description": "Let people see and choose the information available for a task.",
      "preview": "components/#context-sources",
      "reference": "components/README.md",
      "files": [
        {
          "path": "lib/components.js",
          "type": "script"
        },
        {
          "path": "lib/components.css",
          "type": "stylesheet"
        }
      ],
      "entrypoint": "FlowstageUI.mount(container, { type: \"context-sources\", ...options })",
      "dependencies": [],
      "anatomy": [
        "Context heading",
        "Source icon",
        "Title and type",
        "Description",
        "Selection checkbox",
        "Selection summary"
      ],
      "tokens": [
        "--fsui-bg",
        "--fsui-panel",
        "--fsui-border",
        "--fsui-text",
        "--fsui-muted",
        "--fsui-accent",
        "--fsui-radius"
      ],
      "states": [
        "selected",
        "unselected",
        "empty"
      ],
      "accessibility": "Every source is a native labeled checkbox with a visible title and description. The selected count is a polite status region.",
      "integration": {
        "config": {
          "type": "context-sources",
          "title": "Project context",
          "subtitle": "Choose what the assistant can use",
          "sources": [
            {
              "id": "brief",
              "title": "Project brief",
              "kind": "Document",
              "meta": "4 sections",
              "excerpt": "Audience, goals, and requirements for the website refresh."
            },
            {
              "id": "screens",
              "title": "Screen references",
              "kind": "Collection",
              "meta": "3 screens",
              "excerpt": "The current overview, task detail, and project settings."
            },
            {
              "id": "notes",
              "title": "Review notes",
              "kind": "Notes",
              "meta": "6 comments",
              "excerpt": "Feedback about navigation, spacing, and task states."
            }
          ],
          "selected": [
            "brief",
            "screens"
          ]
        },
        "snippet": "const component = FlowstageUI.mount(\n  document.querySelector('#demo'),\n  {\n    \"type\": \"context-sources\",\n    \"title\": \"Project context\",\n    \"subtitle\": \"Choose what the assistant can use\",\n    \"sources\": [\n      {\n        \"id\": \"brief\",\n        \"title\": \"Project brief\",\n        \"kind\": \"Document\",\n        \"meta\": \"4 sections\",\n        \"excerpt\": \"Audience, goals, and requirements for the website refresh.\"\n      },\n      {\n        \"id\": \"screens\",\n        \"title\": \"Screen references\",\n        \"kind\": \"Collection\",\n        \"meta\": \"3 screens\",\n        \"excerpt\": \"The current overview, task detail, and project settings.\"\n      },\n      {\n        \"id\": \"notes\",\n        \"title\": \"Review notes\",\n        \"kind\": \"Notes\",\n        \"meta\": \"6 comments\",\n        \"excerpt\": \"Feedback about navigation, spacing, and task states.\"\n      }\n    ],\n    \"selected\": [\n      \"brief\",\n      \"screens\"\n    ]\n  }\n);\n\n// Read a snapshot; clean up when the view leaves.\ncomponent.getState();\n// component.destroy();",
        "methods": [
          "select(id, selected)",
          "selectAll()",
          "clear()"
        ],
        "instructions": "Make context selection visible. Sample source cards are descriptive fixtures and do not read or upload any documents."
      }
    },
    {
      "id": "prompt-composer",
      "name": "Prompt composer",
      "kind": "ui-component",
      "description": "Write a prompt, send it, and display a local example reply.",
      "preview": "components/#prompt-composer",
      "reference": "components/README.md",
      "files": [
        {
          "path": "lib/components.js",
          "type": "script"
        },
        {
          "path": "lib/components.css",
          "type": "stylesheet"
        }
      ],
      "entrypoint": "FlowstageUI.mount(container, { type: \"prompt-composer\", ...options })",
      "dependencies": [],
      "anatomy": [
        "Label",
        "Suggestion buttons",
        "Textarea",
        "Character count",
        "Submit button",
        "Example reply"
      ],
      "tokens": [
        "--fsui-bg",
        "--fsui-panel",
        "--fsui-border",
        "--fsui-text",
        "--fsui-muted",
        "--fsui-accent",
        "--fsui-radius"
      ],
      "states": [
        "empty",
        "editing",
        "submitting",
        "complete",
        "cancelled"
      ],
      "accessibility": "A visible label names the textarea; help text describes Enter and Shift+Enter. IME composition is respected. Submission and cancellation are announced politely.",
      "integration": {
        "config": {
          "type": "prompt-composer",
          "title": "What should we work on?",
          "subtitle": "Try a prompt using the example context",
          "placeholder": "Describe a task or ask about the project…",
          "suggestions": [
            "Summarize the project",
            "Plan the next steps"
          ],
          "responseText": "Example reply: I would review the project brief, list the proposed changes, and ask you to confirm the next step. Connect your own handler to use this composer in an application.",
          "duration": 700,
          "maxLength": 2000
        },
        "snippet": "const component = FlowstageUI.mount(\n  document.querySelector('#demo'),\n  {\n    \"type\": \"prompt-composer\",\n    \"title\": \"What should we work on?\",\n    \"subtitle\": \"Try a prompt using the example context\",\n    \"placeholder\": \"Describe a task or ask about the project…\",\n    \"suggestions\": [\n      \"Summarize the project\",\n      \"Plan the next steps\"\n    ],\n    \"responseText\": \"Example reply: I would review the project brief, list the proposed changes, and ask you to confirm the next step. Connect your own handler to use this composer in an application.\",\n    \"duration\": 700,\n    \"maxLength\": 2000\n  }\n);\n\n// Read a snapshot; clean up when the view leaves.\ncomponent.getState();\n// component.destroy();",
        "methods": [
          "setValue(text)",
          "submit()",
          "cancel()"
        ],
        "instructions": "Collect a prompt and emit its value. The built-in reply is explicitly labeled as a local example; replace the surrounding application behavior for real requests."
      }
    }
  ]
}
