{
  "components": [
    {
      "name": "AnimatePresence",
      "package": "@getnarro/core",
      "description": "`AnimatePresence` enables the animation of components that have been removed from the tree. When adding/removing more than a single child, every child **must** be given a unique `key` prop. Any `motion` components that have an `exit` property defined will animate out when removed from the tree. ```jsx import { motion, AnimatePresence } from 'framer-motion' export const Items = ({ items }) => ( <AnimatePresence> {items.map(item => ( <motion.div key={item.id} initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} /> ))} </AnimatePresence> ) ``` You can sequence exit animations throughout a tree using variants. If a child contains multiple `motion` components with `exit` props, it will only unmount the child once all `motion` components have finished animating out. Likewise, any components using `usePresence` all need to call `safeToRemove`.",
      "props": []
    },
    {
      "name": "Canvas",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/Canvas.tsx",
      "description": "A container for absolutely positioned elements",
      "behaviour": "A positioning context: children are placed absolutely against it, so\nit only works with `CanvasElement`/`CanvasShape` inside. Reach for it when no\nlayout component expresses the arrangement.",
      "examples": [
        "<Canvas>\n  <CanvasElement x={10} y={20} width={200} height={100}>\n    <div>Positioned content</div>\n  </CanvasElement>\n  <CanvasShape shape=\"circle\" x={50} y={50} size={100} color=\"#3b82f6\" />\n</Canvas>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Children elements to position"
        },
        {
          "name": "background",
          "type": "string",
          "required": false,
          "description": "Background color"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "height",
          "type": "string",
          "required": false,
          "defaultValue": "\"100%\"",
          "description": "Height of the canvas (default: 100%)"
        },
        {
          "name": "width",
          "type": "string",
          "required": false,
          "defaultValue": "\"100%\"",
          "description": "Width of the canvas (default: 100%)"
        }
      ]
    },
    {
      "name": "CanvasElement",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/CanvasElement.tsx",
      "description": "A positioned element within a Canvas",
      "behaviour": "Absolutely positioned against the nearest `Canvas`. `x`/`y` are the\ntop-left corner as a percentage or a length, not a centre point, and\n`width`/`height` default to the content's own size.",
      "examples": [
        "<CanvasElement x={10} y={20} width={200} height={100}>\n  <div>Positioned at 10%, 20%</div>\n</CanvasElement>",
        "Using pixels:\n```tsx\n<CanvasElement x=\"100px\" y=\"50px\" width=\"200px\" height=\"100px\">\n  <div>Positioned at 100px, 50px</div>\n</CanvasElement>\n```"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Children content"
        },
        {
          "name": "x",
          "type": "PositionValue",
          "required": true,
          "description": "X position (% or px)"
        },
        {
          "name": "y",
          "type": "PositionValue",
          "required": true,
          "description": "Y position (% or px)"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "height",
          "type": "PositionValue",
          "required": false,
          "description": "Height (% or px, optional)"
        },
        {
          "name": "opacity",
          "type": "number",
          "required": false,
          "description": "Opacity (0-1)"
        },
        {
          "name": "rotate",
          "type": "number",
          "required": false,
          "description": "Rotation in degrees"
        },
        {
          "name": "width",
          "type": "PositionValue",
          "required": false,
          "description": "Width (% or px, optional)"
        },
        {
          "name": "zIndex",
          "type": "number",
          "required": false,
          "description": "Z-index for layering"
        }
      ]
    },
    {
      "name": "CanvasShape",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/CanvasShape.tsx",
      "description": "A pre-built shape positioned on the Canvas",
      "behaviour": "Absolutely positioned against the nearest `Canvas`, and always square\n— `size` sets both axes. `rotate` turns the SVG in place and does not change the\nbox it occupies.",
      "examples": [
        "<Canvas>\n  <CanvasShape shape=\"circle\" x={50} y={50} size={100} color=\"#3b82f6\" />\n  <CanvasShape shape=\"star\" x={200} y={100} size={80} color=\"#fbbf24\" />\n  <CanvasShape shape=\"arrow\" x={300} y={50} size={120} color=\"#10b981\" rotate={45} />\n</Canvas>"
      ],
      "props": [
        {
          "name": "shape",
          "type": "ShapeType",
          "required": true,
          "description": "Shape type"
        },
        {
          "name": "size",
          "type": "number",
          "required": true,
          "description": "Size of the shape"
        },
        {
          "name": "x",
          "type": "PositionValue",
          "required": true,
          "description": "X position (% or px)"
        },
        {
          "name": "y",
          "type": "PositionValue",
          "required": true,
          "description": "Y position (% or px)"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "color",
          "type": "string",
          "required": false,
          "defaultValue": "\"#000000\"",
          "description": "Fill color"
        },
        {
          "name": "opacity",
          "type": "number",
          "required": false,
          "defaultValue": "1",
          "description": "Opacity (0-1)"
        },
        {
          "name": "rotate",
          "type": "number",
          "required": false,
          "description": "Rotation in degrees"
        },
        {
          "name": "stroke",
          "type": "string",
          "required": false,
          "description": "Stroke color"
        },
        {
          "name": "strokeWidth",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Stroke width"
        },
        {
          "name": "zIndex",
          "type": "number",
          "required": false,
          "description": "Z-index for layering"
        }
      ]
    },
    {
      "name": "ErrorBoundary",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/ErrorOverlay.tsx",
      "description": "Error Boundary component that catches errors and displays the overlay",
      "examples": [
        "<ErrorBoundary onError={(error) => console.error(error)}>\n  <Presentation>\n    <Slide>...</Slide>\n  </Presentation>\n</ErrorBoundary>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Children to render"
        },
        {
          "name": "fallback",
          "type": "ReactNode | ((error: ErrorDetails, reset: () => void) => ReactNode)",
          "required": false,
          "description": "Fallback component to render on error (optional, defaults to ErrorOverlay)"
        },
        {
          "name": "onError",
          "type": "((error: Error, errorInfo: ErrorInfo) => void)",
          "required": false,
          "description": "Callback when an error occurs"
        },
        {
          "name": "showOverlay",
          "type": "boolean",
          "required": false,
          "description": "Enable development overlay (default: true in dev, false in prod)"
        }
      ]
    },
    {
      "name": "ErrorOverlay",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/ErrorOverlay.tsx",
      "description": "Error overlay component for development",
      "examples": [
        "<ErrorOverlay\n  error={{\n    message: \"Something went wrong\",\n    stack: \"Error: Something went wrong\\n  at Component ...\"\n  }}\n  onDismiss={() => setError(null)}\n/>"
      ],
      "props": [
        {
          "name": "error",
          "type": "ErrorDetails",
          "required": true,
          "description": "Error details to display"
        },
        {
          "name": "onDismiss",
          "type": "(() => void)",
          "required": false,
          "description": "Callback to dismiss/reset the error"
        },
        {
          "name": "showDismiss",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Show dismiss button (default: true)"
        }
      ]
    },
    {
      "name": "MarqueeRow",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/backgrounds/TrustedByMarquee.tsx",
      "description": "One scrolling row of a marquee. Usually you want `TrustedByMarquee`, which arranges several of these.",
      "behaviour": "One scrolling row of a `TrustedByMarquee`, full width and sized by its\ncontent.",
      "props": [
        {
          "name": "items",
          "type": "MarqueeItem[]",
          "required": true,
          "description": "Items to display in the marquee"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "defaultValue": "\"\"",
          "description": "Additional CSS class for the container"
        },
        {
          "name": "direction",
          "type": "\"left\" | \"right\"",
          "required": false,
          "defaultValue": "\"left\"",
          "description": "Scroll direction"
        },
        {
          "name": "gap",
          "type": "number",
          "required": false,
          "defaultValue": "16",
          "description": "Gap between items in pixels (default: 16)"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Whether the animation is active"
        },
        {
          "name": "itemMinWidth",
          "type": "number",
          "required": false,
          "defaultValue": "180",
          "description": "Item minimum width in pixels (default: 180)"
        },
        {
          "name": "renderItem",
          "type": "((item: MarqueeItem, index: number) => ReactNode)",
          "required": false,
          "description": "Custom item render function"
        },
        {
          "name": "speed",
          "type": "number",
          "required": false,
          "defaultValue": "0.5",
          "description": "Scroll speed (pixels per frame, default: 0.5)"
        }
      ]
    },
    {
      "name": "MasonryBackground",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/backgrounds/MasonryBackground.tsx",
      "description": "A full-bleed masonry grid of images that crossfades between them. Pauses while its slide is off screen, so an idle deck does no work.",
      "behaviour": "Fills its positioning parent behind the content, in columns sized by\nthe count you pass.",
      "examples": [
        "<MasonryBackground\n  images={[\"/a.jpg\", \"/b.jpg\", \"/c.jpg\"]}\n  gridColumns={12}\n  gridRows={6}\n  swapMinIntervalMs={3000}\n  swapMaxIntervalMs={6000}\n/>"
      ],
      "props": [
        {
          "name": "images",
          "type": "string[]",
          "required": true,
          "description": "Array of image URLs to display and cycle through"
        },
        {
          "name": "backgroundColor",
          "type": "string",
          "required": false,
          "defaultValue": "\"black\"",
          "description": "Background color (default: \"black\")"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "defaultValue": "\"\"",
          "description": "Additional CSS class for the container"
        },
        {
          "name": "gridColumns",
          "type": "number",
          "required": false,
          "defaultValue": "12",
          "description": "Number of grid columns (default: 12)"
        },
        {
          "name": "gridRows",
          "type": "number",
          "required": false,
          "defaultValue": "6",
          "description": "Number of grid rows (default: 6)"
        },
        {
          "name": "imageBorderColor",
          "type": "string",
          "required": false,
          "defaultValue": "\"rgba(255, 255, 255, 0.6)\"",
          "description": "Border color for images (default: \"rgba(255, 255, 255, 0.6)\")"
        },
        {
          "name": "imageBorderWidth",
          "type": "string",
          "required": false,
          "defaultValue": "\"1px\"",
          "description": "Border width for images (default: \"1px\")"
        },
        {
          "name": "imageGap",
          "type": "number",
          "required": false,
          "defaultValue": "6",
          "description": "Gap between images in pixels (default: 6)"
        },
        {
          "name": "initialFillTimeMs",
          "type": "number",
          "required": false,
          "defaultValue": "800",
          "description": "Time in ms to fill the page with initial images (default: 800)"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Whether the animation is active"
        },
        {
          "name": "swapMaxIntervalMs",
          "type": "number",
          "required": false,
          "defaultValue": "2000",
          "description": "Maximum time in ms between image swaps after initial fill (default: 2000)"
        },
        {
          "name": "swapMinIntervalMs",
          "type": "number",
          "required": false,
          "defaultValue": "1000",
          "description": "Minimum time in ms between image swaps after initial fill (default: 1000)"
        },
        {
          "name": "tileLayout",
          "type": "TileLayout[]",
          "required": false,
          "defaultValue": "DEFAULT_TILE_LAYOUT",
          "description": "Grid tile layout configuration"
        },
        {
          "name": "transitionDurationMs",
          "type": "number",
          "required": false,
          "defaultValue": "800",
          "description": "Duration of crossfade transition in ms (default: 800)"
        }
      ]
    },
    {
      "name": "Motion",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/Motion.tsx",
      "description": "A Framer Motion animation wrapper Provides smooth, physics-based animations with 10+ built-in effects.",
      "examples": [
        "<Motion effect=\"slideUp\" duration={0.5}>\n  <h1>Animated Title</h1>\n</Motion>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Children to animate"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional class names"
        },
        {
          "name": "delay",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Animation delay in seconds"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "0.5",
          "description": "Animation duration in seconds"
        },
        {
          "name": "easing",
          "type": "MotionEasing",
          "required": false,
          "defaultValue": "\"easeOut\"",
          "description": "Easing function"
        },
        {
          "name": "effect",
          "type": "MotionEffect",
          "required": false,
          "defaultValue": "\"fadeIn\"",
          "description": "Animation effect to apply"
        },
        {
          "name": "inView",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Whether to trigger animation only when in view"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Whether animation has played (for controlled animations)"
        },
        {
          "name": "onAnimationComplete",
          "type": "(() => void)",
          "required": false,
          "description": "Callback when animation completes"
        },
        {
          "name": "respectReducedMotion",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Enable reduced motion fallback"
        },
        {
          "name": "style",
          "type": "CSSProperties",
          "required": false,
          "description": "Additional styles"
        }
      ]
    },
    {
      "name": "MotionContainer",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/Motion.tsx",
      "description": "Container for staggered child animations",
      "behaviour": "Measures its content and animates its own height between states, so it\nmust not be given a fixed height by a parent — the animation is that height\nchanging.",
      "examples": [
        "<MotionContainer staggerDelay={0.1}>\n  <Motion effect=\"slideUp\">Item 1</Motion>\n  <Motion effect=\"slideUp\">Item 2</Motion>\n  <Motion effect=\"slideUp\">Item 3</Motion>\n</MotionContainer>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Children to animate with stagger"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional class names"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Whether children should animate"
        },
        {
          "name": "staggerDelay",
          "type": "number",
          "required": false,
          "defaultValue": "0.1",
          "description": "Stagger delay between children in seconds"
        },
        {
          "name": "style",
          "type": "CSSProperties",
          "required": false,
          "description": "Additional styles"
        }
      ]
    },
    {
      "name": "MotionList",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/Motion.tsx",
      "description": "MotionList - Staggered list animation",
      "props": [
        {
          "name": "items",
          "type": "ReactNode[]",
          "required": true,
          "description": "List items"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional class names for container"
        },
        {
          "name": "effect",
          "type": "MotionEffect",
          "required": false,
          "defaultValue": "\"slideUp\"",
          "description": "Animation effect for each item"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Whether animations are active"
        },
        {
          "name": "itemClassName",
          "type": "string",
          "required": false,
          "description": "Additional class names for items"
        },
        {
          "name": "listStyle",
          "type": "\"none\" | \"disc\" | \"decimal\" | \"check\"",
          "required": false,
          "defaultValue": "\"none\"",
          "description": "List style type"
        },
        {
          "name": "staggerDelay",
          "type": "number",
          "required": false,
          "defaultValue": "0.1",
          "description": "Stagger delay between items in seconds"
        }
      ]
    },
    {
      "name": "MotionNumber",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/Motion.tsx",
      "description": "Animated number counter",
      "behaviour": "Animates to its target and reserves no space for the widest value it\nwill pass through, so a number that grows in digit count shifts the layout around\nit.",
      "examples": [
        "<MotionNumber value={1000000} prefix=\"$\" separator duration={2} />"
      ],
      "props": [
        {
          "name": "value",
          "type": "number",
          "required": true,
          "description": "Target value"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional class names"
        },
        {
          "name": "decimals",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Number of decimal places"
        },
        {
          "name": "delay",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Delay before starting"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "2",
          "description": "Animation duration in seconds"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Whether animation is active"
        },
        {
          "name": "prefix",
          "type": "string",
          "required": false,
          "defaultValue": "\"\"",
          "description": "Prefix (e.g., \"$\")"
        },
        {
          "name": "separator",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Use thousands separator"
        },
        {
          "name": "style",
          "type": "CSSProperties",
          "required": false,
          "description": "Additional styles"
        },
        {
          "name": "suffix",
          "type": "string",
          "required": false,
          "defaultValue": "\"\"",
          "description": "Suffix (e.g., \"%\")"
        }
      ]
    },
    {
      "name": "MotionPresence",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/Motion.tsx",
      "description": "MotionPresence - Wrapper for AnimatePresence with slide-aware animations",
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Children to animate"
        },
        {
          "name": "mode",
          "type": "\"sync\" | \"wait\" | \"popLayout\"",
          "required": false,
          "defaultValue": "\"wait\"",
          "description": "Animation mode"
        },
        {
          "name": "presenceKey",
          "type": "string",
          "required": false,
          "description": "Custom key for tracking"
        }
      ]
    },
    {
      "name": "MotionSpotlight",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/Motion.tsx",
      "description": "Apple Keynote-style Magic Move for images Creates smooth zoom and pan animations between slides. Uses Framer Motion's layout animations for seamless morphing.",
      "behaviour": "Sizes itself from `containerHeight` and dims everything but the\nhighlighted child; the children keep their own layout, only their opacity\nchanges.",
      "examples": [
        "// Slide 1 - Overview\n<MotionSpotlight\n  layoutId=\"product\"\n  src=\"/product.jpg\"\n  alt=\"Product\"\n  x={50} y={50} scale={1}\n  width={800} height={400}\n/>\n\n// Slide 2 - Zoomed\n<MotionSpotlight\n  layoutId=\"product\"\n  src=\"/product.jpg\"\n  alt=\"Product detail\"\n  x={25} y={50} scale={2.5}\n  width={800} height={400}\n/>"
      ],
      "props": [
        {
          "name": "alt",
          "type": "string",
          "required": true,
          "description": "Alt text for accessibility"
        },
        {
          "name": "src",
          "type": "string",
          "required": true,
          "description": "Image source URL"
        },
        {
          "name": "borderRadius",
          "type": "string | number",
          "required": false,
          "defaultValue": "8",
          "description": "Border radius"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional class names"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "0.8",
          "description": "Animation duration in seconds"
        },
        {
          "name": "height",
          "type": "string | number",
          "required": false,
          "defaultValue": "400",
          "description": "Container height"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Whether currently active"
        },
        {
          "name": "layoutId",
          "type": "string",
          "required": false,
          "description": "Unique ID for cross-slide morphing"
        },
        {
          "name": "onAnimationComplete",
          "type": "(() => void)",
          "required": false,
          "description": "Callback when animation completes"
        },
        {
          "name": "scale",
          "type": "number",
          "required": false,
          "defaultValue": "1",
          "description": "Scale/zoom level"
        },
        {
          "name": "shadow",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Show shadow"
        },
        {
          "name": "width",
          "type": "string | number",
          "required": false,
          "defaultValue": "\"100%\"",
          "description": "Container width"
        },
        {
          "name": "x",
          "type": "number",
          "required": false,
          "defaultValue": "50",
          "description": "X position as percentage (0-100)"
        },
        {
          "name": "y",
          "type": "number",
          "required": false,
          "defaultValue": "50",
          "description": "Y position as percentage (0-100)"
        }
      ]
    },
    {
      "name": "MotionStep",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/Motion.tsx",
      "description": "Individual step within MotionSteps container Shows when the current step is >= this step's number.",
      "examples": [
        "<MotionStep step={1} effect=\"scaleUp\">\n  <div>This appears on step 1</div>\n</MotionStep>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Children to animate"
        },
        {
          "name": "step",
          "type": "number",
          "required": true,
          "description": "Step number (0-indexed) - element shows when currentStep >= this value"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional class name"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "0.5",
          "description": "Animation duration in seconds"
        },
        {
          "name": "easing",
          "type": "MotionEasing",
          "required": false,
          "defaultValue": "\"easeOut\"",
          "description": "Easing function"
        },
        {
          "name": "effect",
          "type": "MotionEffect",
          "required": false,
          "defaultValue": "\"fadeIn\"",
          "description": "Animation effect when revealed"
        },
        {
          "name": "style",
          "type": "CSSProperties",
          "required": false,
          "description": "Additional styles"
        }
      ]
    },
    {
      "name": "MotionSteps",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/Motion.tsx",
      "description": "Container for step-by-step animations triggered by keystrokes Wrap MotionStep children to create a sequence of animations. Press arrow keys (right/down) to advance, (left/up) to go back.",
      "examples": [
        "<MotionSteps totalSteps={3}>\n  <MotionStep step={0} effect=\"scaleUp\">\n    <div>First element (visible immediately)</div>\n  </MotionStep>\n  <MotionStep step={1} effect=\"slideRight\">\n    <div>Second element (press arrow key)</div>\n  </MotionStep>\n  <MotionStep step={2} effect=\"elastic\">\n    <div>Third element (press again)</div>\n  </MotionStep>\n</MotionSteps>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Children - should be MotionStep components"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional class name"
        },
        {
          "name": "loop",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Whether to loop back to start after last step"
        },
        {
          "name": "onComplete",
          "type": "(() => void)",
          "required": false,
          "description": "Callback when all steps are complete"
        },
        {
          "name": "startStep",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Starting step (0-indexed)"
        },
        {
          "name": "totalSteps",
          "type": "number",
          "required": false,
          "description": "Total number of steps"
        }
      ]
    },
    {
      "name": "MotionText",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/Motion.tsx",
      "description": "Animated text with various effects",
      "behaviour": "Animates per word or per character, which means the text is split into\ninline elements — a `text-*` utility on the parent still applies, but a selector\nexpecting one text node will not match.",
      "examples": [
        "<MotionText type=\"typewriter\" duration={0.05}>\n  Hello, World!\n</MotionText>"
      ],
      "props": [
        {
          "name": "children",
          "type": "string",
          "required": true,
          "description": "Text content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional class names"
        },
        {
          "name": "delay",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Delay before starting in seconds"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "0.05",
          "description": "Animation duration per unit in seconds"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Whether animation is active"
        },
        {
          "name": "style",
          "type": "CSSProperties",
          "required": false,
          "description": "Additional styles"
        },
        {
          "name": "type",
          "type": "\"blur\" | \"typewriter\" | \"wave\" | \"wordByWord\" | \"charByChar\"",
          "required": false,
          "defaultValue": "\"typewriter\"",
          "description": "Animation type"
        }
      ]
    },
    {
      "name": "MotionTransform",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/Motion.tsx",
      "description": "Applies cumulative transforms to a single element across steps Use this inside MotionSteps to animate the SAME element through multiple transformation states (fade, zoom, move, rotate, etc.)",
      "examples": [
        "<MotionSteps totalSteps={4}>\n  <MotionTransform\n    transforms={[\n      { opacity: 0 },                           // Step 0 (hidden)\n      { opacity: 1 },                           // Step 1 (fade in)\n      { opacity: 1, scale: 1.5 },              // Step 2 (zoom)\n      { opacity: 1, scale: 1.5, x: 150 },      // Step 3 (move right)\n    ]}\n  >\n    <div className=\"w-64 h-64 bg-blue-500\">\n      Transform me!\n    </div>\n  </MotionTransform>\n</MotionSteps>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Children to transform"
        },
        {
          "name": "transforms",
          "type": "TransformState[]",
          "required": true,
          "description": "Array of transform states for each step"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional class name"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "0.6",
          "description": "Animation duration in seconds"
        },
        {
          "name": "easing",
          "type": "MotionEasing",
          "required": false,
          "defaultValue": "\"easeOut\"",
          "description": "Easing function"
        },
        {
          "name": "style",
          "type": "CSSProperties",
          "required": false,
          "description": "Additional styles"
        }
      ]
    },
    {
      "name": "NebulaBackground",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/backgrounds/NebulaBackground.tsx",
      "description": "An animated starfield with nebula glow, behind whatever you put in it.",
      "behaviour": "Fills its positioning parent and sits behind the content. Give the\nslide `position: relative` (or put it directly in a `Slide`) or it will escape to\nthe nearest positioned ancestor.",
      "examples": [
        "<NebulaBackground isActive>\n  <Heading level={1}>Title over the stars</Heading>\n</NebulaBackground>"
      ],
      "props": [
        {
          "name": "backgroundGradient",
          "type": "string",
          "required": false,
          "defaultValue": "DEFAULT_BACKGROUND_GRADIENT",
          "description": "Background gradient (CSS value)"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children to render on top of the background"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "defaultValue": "\"\"",
          "description": "Additional CSS class for the container"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Whether the animation is active"
        },
        {
          "name": "nebulaColors",
          "type": "NebulaGlow[]",
          "required": false,
          "defaultValue": "DEFAULT_NEBULA_COLORS",
          "description": "Nebula glow effects configuration"
        },
        {
          "name": "shootingStarDuration",
          "type": "number",
          "required": false,
          "defaultValue": "2000",
          "description": "Duration of shooting star animation in ms (default: 2000)"
        },
        {
          "name": "shootingStarFrequency",
          "type": "number",
          "required": false,
          "defaultValue": "3000",
          "description": "Time between shooting stars in ms (default: 3000)"
        },
        {
          "name": "starColors",
          "type": "StarColor[]",
          "required": false,
          "defaultValue": "DEFAULT_STAR_COLORS",
          "description": "Star color distribution"
        },
        {
          "name": "starLayers",
          "type": "StarLayer[]",
          "required": false,
          "defaultValue": "DEFAULT_STAR_LAYERS",
          "description": "Star layer configuration"
        },
        {
          "name": "twinkleSpeed",
          "type": "{ min: number; max: number; }",
          "required": false,
          "defaultValue": "{ min: 2000, max: 6000 }",
          "description": "Twinkle speed range in ms"
        }
      ]
    },
    {
      "name": "Notes",
      "package": "@getnarro/core",
      "source": "packages/core/src/types/index.ts",
      "description": "Notes component - Speaker notes Notes are not rendered in the main presentation view. They are meant to be displayed in presenter mode or exported separately.",
      "examples": [
        "<Slide>\n  <h1>My Slide Title</h1>\n  <Notes>\n    Remember to explain the key points here.\n    - Point 1\n    - Point 2\n  </Notes>\n</Slide>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Speaker notes content"
        }
      ]
    },
    {
      "name": "OverviewGrid",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/OverviewGrid.tsx",
      "description": "OverviewGrid component - Displays slides in a grid for quick navigation",
      "behaviour": "A full-screen overlay, not an in-slide element. `Presentation` renders\nit on `O`; you do not place it yourself.",
      "props": [
        {
          "name": "actions",
          "type": "NavigationActions",
          "required": true,
          "description": "Navigation actions"
        },
        {
          "name": "slidesData",
          "type": "SlideData[]",
          "required": true,
          "description": "Slides data for rendering previews"
        },
        {
          "name": "state",
          "type": "NavigationState",
          "required": true,
          "description": "Navigation state"
        }
      ]
    },
    {
      "name": "Presentation",
      "package": "@getnarro/core",
      "source": "packages/core/src/types/index.ts",
      "description": "Presentation component - Root container",
      "examples": [
        "<Presentation>\n  <Slide id=\"intro\">\n    <h1>Welcome</h1>\n  </Slide>\n  <Slide id=\"content\">\n    <h2>Main Content</h2>\n  </Slide>\n</Presentation>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Children slides"
        },
        {
          "name": "aspectRatio",
          "type": "AspectRatio",
          "required": false,
          "defaultValue": "\"16:9\"",
          "description": "Aspect ratio (default: \"16:9\")"
        },
        {
          "name": "autoPlay",
          "type": "number | boolean | number[]",
          "required": false,
          "defaultValue": "false",
          "description": "Enable auto-play mode to automatically advance slides. Can be a boolean (uses default 5000ms interval) or a number specifying the interval in milliseconds. Can also be an array of numbers specifying the interval for each slide."
        },
        {
          "name": "autoPlayLoop",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Whether to loop back to the first slide when auto-play reaches the end. Default: false"
        },
        {
          "name": "baseHeight",
          "type": "number",
          "required": false,
          "defaultValue": "1080",
          "description": "Base height for viewport scaling (default: 1080). Content scales proportionally from this baseline"
        },
        {
          "name": "baseWidth",
          "type": "number",
          "required": false,
          "defaultValue": "1920",
          "description": "Base width for viewport scaling (default: 1920). Content scales proportionally from this baseline"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "embedded",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Enable embedded mode for presentations in smaller containers. When true, viewport scaling uses container size instead of window size. Useful for embedding presentations in modals, cards, or side panels."
        },
        {
          "name": "enableViewportScaling",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Enable viewport scaling (default: true). Scales content based on viewport size for responsive presentations"
        },
        {
          "name": "favicon",
          "type": "string | null",
          "required": false,
          "description": "Favicon URL or data URI for the presentation. Can be a path to an image file, a data URI, or undefined to use the default Narro favicon. Set to `null` to disable favicon management (keep existing favicon)."
        },
        {
          "name": "initialSlide",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Initial slide index"
        },
        {
          "name": "keepAwake",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Keep the screen awake while the presentation is open (Screen Wake Lock API, best-effort). Useful so the projector/laptop never sleeps mid-talk. Default: false"
        },
        {
          "name": "keyboard",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Enable keyboard navigation (default: true)"
        },
        {
          "name": "maxDuration",
          "type": "number",
          "required": false,
          "description": "Optional maximum duration in minutes for countdown timer in presenter panel"
        },
        {
          "name": "mouse",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Enable mouse navigation (default: true)"
        },
        {
          "name": "onAutoPlayComplete",
          "type": "(() => void)",
          "required": false,
          "description": "Callback when auto-play reaches the last slide and completes. Only called when autoPlay is enabled."
        },
        {
          "name": "onSlideChange",
          "type": "((index: number) => void)",
          "required": false,
          "description": "Callback when slide changes"
        },
        {
          "name": "onSlidesData",
          "type": "((slides: SlideData[]) => void)",
          "required": false,
          "description": "Callback invoked with the registered slide data whenever the slide set changes. Useful for building companion views (notes, overviews) that need access to slide content and speaker notes."
        },
        {
          "name": "preserveAspectRatio",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Preserve aspect ratio (default: true). When false, slides fill viewport"
        },
        {
          "name": "routing",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Enable URL-based routing (default: true)"
        },
        {
          "name": "showAutoPlayIndicator",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Show an auto-play indicator icon at the bottom right of the presentation. Shows a play/pause icon during playback and a replay icon when complete. Clicking the replay icon restarts the presentation. Default: false"
        },
        {
          "name": "sync",
          "type": "PresentationSync",
          "required": false,
          "defaultValue": "false",
          "description": "Broadcast the current slide to a presenter-sync relay so companion views (e.g. a speaker-notes window on a different port) can follow along live. Pass `true` to use the default relay URL, or an object to customise it. Default: false"
        },
        {
          "name": "theme",
          "type": "PresentationTheme",
          "required": false,
          "description": "Theme configuration for the presentation"
        },
        {
          "name": "touch",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Enable touch navigation (default: true)"
        },
        {
          "name": "transform",
          "type": "TransformConfig",
          "required": false,
          "description": "Transform-based animation configuration"
        }
      ]
    },
    {
      "name": "PresenterNotes",
      "package": "@getnarro/core",
      "source": "packages/core/src/types/index.ts",
      "description": "PresenterNotes component - live speaker-notes companion view.",
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "The same slide elements rendered by the deck. Their inline `<Notes>` are harvested and shown in slide order."
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes for the root container."
        },
        {
          "name": "currentSlide",
          "type": "number",
          "required": false,
          "description": "Controlled current slide index. When provided, sync is ignored and the view follows this value (useful for tests or custom wiring)."
        },
        {
          "name": "keepAwake",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Keep the screen awake while the notes view is open (best-effort). Default: true (this is a presenter tool)."
        },
        {
          "name": "pacing",
          "type": "PresenterPacing",
          "required": false,
          "description": "Optional pacing schedule. When provided, the notes view shows an elapsed timer plus an on-time / ahead / over indicator and the planned total."
        },
        {
          "name": "script",
          "type": "((slide: { id: string; index: number; step: number; }) => string | undefined)",
          "required": false,
          "description": "Optional resolver for a fuller, per-slide script (e.g. a verbatim manuscript) shown in a secondary, scrollable pane next to the notes. Return `undefined` for slides that have no script. When omitted, no script pane is shown."
        },
        {
          "name": "sync",
          "type": "PresentationSync",
          "required": false,
          "description": "Subscribe to a live deck via the presenter-sync relay. Pass `true` for the default relay URL or an object to customise it."
        }
      ]
    },
    {
      "name": "Slide",
      "package": "@getnarro/core",
      "source": "packages/core/src/types/index.ts",
      "description": "Slide component - Individual slide wrapper",
      "examples": [
        "<Slide id=\"intro\" layout=\"title\">\n  <h1>Welcome to My Presentation</h1>\n  <p>Subtitle goes here</p>\n</Slide>",
        "With sub-slides\n```tsx\n<Slide id=\"multi-step\" subSlides={[\n{ id: \"step1\", content: <div>Step 1</div> },\n{ id: \"step2\", content: <div>Step 2</div>, transition: \"slide-left\" }\n]} />\n```"
      ],
      "props": [
        {
          "name": "__slideIndex",
          "type": "number",
          "required": false,
          "description": "Internal: Explicit slide index from Presentation component"
        },
        {
          "name": "background",
          "type": "string",
          "required": false,
          "description": "Background color or image"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "id",
          "type": "string",
          "required": false,
          "description": "Unique identifier for the slide"
        },
        {
          "name": "layout",
          "type": "LayoutType",
          "required": false,
          "defaultValue": "\"default\"",
          "description": "Layout type (default: \"default\")"
        },
        {
          "name": "subSlides",
          "type": "SubSlide[]",
          "required": false,
          "description": "Sub-slides for multi-step content within this slide"
        },
        {
          "name": "transition",
          "type": "TransitionEffect",
          "required": false,
          "defaultValue": "\"fade\"",
          "description": "Transition effect"
        }
      ]
    },
    {
      "name": "SlideContent",
      "package": "@getnarro/core",
      "source": "packages/core/src/types/index.ts",
      "description": "SlideContent component - Content layout container",
      "behaviour": "Fills the slide (`h-full w-full`). Every `layout` stacks its\nchildren vertically. `default` sets nothing else, so content anchors to the\ntop and the rest of the canvas stays empty — for a content slide you usually\nwant `fill` (a column, so a child with `flex-1` takes the remaining space) or\n`between`. `className` overrides any of it.",
      "examples": [
        "<Slide>\n  <SlideContent layout=\"centered\">\n    <h1>Centered Content</h1>\n  </SlideContent>\n</Slide>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "layout",
          "type": "\"default\" | \"centered\" | \"top\" | \"bottom\" | \"fill\" | \"between\"",
          "required": false,
          "defaultValue": "\"default\"",
          "description": "How the slide's content is arranged in the canvas. All of these stack vertically. `centered` used to be a flex row with no `flexDirection`, so the canonical title-slide example in the scaffolded `AGENTS.md` — a `Heading` and a `Text` — rendered side by side, and the fit checker passed it because it did not overflow, it was just wrong. - `default` — content stacks from the top. Note this leaves the rest of the canvas empty; `fill` or `between` is usually what a content slide wants. - `centered` — centred on both axes. For title and section slides. - `top` / `bottom` — anchored, horizontally centred. - `fill` — a column that occupies the canvas, so a child with `flex-1` takes the remaining space. This is \"title on top, body fills the rest\". - `between` — a column with the space distributed between children."
        }
      ]
    },
    {
      "name": "TransformSlide",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/TransformSlide.tsx",
      "description": "A slide with multiple sub-slides and transform-based navigation",
      "behaviour": "Owns the whole slide and pans a larger canvas within it, so it cannot\nshare a slide with ordinary content — its sub-slide positions are coordinates on\nthat canvas.",
      "props": [
        {
          "name": "subSlides",
          "type": "TransformSubSlide[]",
          "required": true,
          "description": "Array of sub-slides with their positions"
        },
        {
          "name": "background",
          "type": "string",
          "required": false,
          "description": "Background color or gradient"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "1",
          "description": "Transition duration in seconds (default: 1)"
        },
        {
          "name": "easing",
          "type": "\"linear\" | \"easeIn\" | \"easeOut\" | \"easeInOut\" | \"circInOut\" | \"backInOut\"",
          "required": false,
          "defaultValue": "\"easeInOut\"",
          "description": "Transition easing (default: \"easeInOut\")"
        },
        {
          "name": "initialSubSlide",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Initial sub-slide index (default: 0)"
        },
        {
          "name": "perspective",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Enable 3D perspective (default: true)"
        },
        {
          "name": "perspectiveValue",
          "type": "number",
          "required": false,
          "defaultValue": "1000",
          "description": "Perspective value in pixels (default: 1000)"
        }
      ]
    },
    {
      "name": "TrustedByMarquee",
      "package": "@getnarro/core",
      "source": "packages/core/src/components/backgrounds/TrustedByMarquee.tsx",
      "description": "Rows of logos or names scrolling infinitely in alternating directions.",
      "behaviour": "A full-width column of continuously scrolling rows, sized by its\ncontent. It animates forever, so it is a background rather than something to\nplace beside content.",
      "examples": [
        "<TrustedByMarquee\n  rows={[[{ name: \"Acme\", color: \"#ffffff\" }], [{ name: \"Globex\", color: \"#60a5fa\" }]]}\n  isActive\n  baseSpeed={40}\n/>"
      ],
      "props": [
        {
          "name": "rows",
          "type": "MarqueeItem[][]",
          "required": true,
          "description": "Array of row data, each containing items"
        },
        {
          "name": "baseSpeed",
          "type": "number",
          "required": false,
          "defaultValue": "0.3",
          "description": "Base scroll speed (default: 0.3)"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "defaultValue": "\"\"",
          "description": "Additional CSS class for the container"
        },
        {
          "name": "gap",
          "type": "number",
          "required": false,
          "defaultValue": "16",
          "description": "Gap between items in pixels (default: 16)"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Whether the animation is active"
        },
        {
          "name": "itemMinWidth",
          "type": "number",
          "required": false,
          "defaultValue": "180",
          "description": "Item minimum width in pixels (default: 180)"
        },
        {
          "name": "renderItem",
          "type": "((item: MarqueeItem, index: number) => ReactNode)",
          "required": false,
          "description": "Custom item render function"
        },
        {
          "name": "rowGap",
          "type": "number",
          "required": false,
          "defaultValue": "8",
          "description": "Gap between rows (default: 8)"
        },
        {
          "name": "speedIncrement",
          "type": "number",
          "required": false,
          "defaultValue": "0.05",
          "description": "Speed increment per row (default: 0.05)"
        }
      ]
    },
    {
      "name": "AgendaItem",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A styled agenda item component Displays an agenda item with a centered number in bold with a colored underline, followed by descriptive text. Useful for agenda presentations and step-by-step processes.",
      "examples": [
        "<AgendaItem number={1} title=\"Introduction\" />\n<AgendaItem number={2} title=\"Main Topic\" underlineColor=\"#00BFA5\" />"
      ],
      "props": [
        {
          "name": "number",
          "type": "number",
          "required": true,
          "description": "The number of the agenda item"
        },
        {
          "name": "title",
          "type": "string",
          "required": true,
          "description": "Title of the agenda item"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "underlineColor",
          "type": "string",
          "required": false,
          "defaultValue": "\"#14b8a6\"",
          "description": "Color of the underline"
        }
      ]
    },
    {
      "name": "AnimatedList",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/AnimatedList.tsx",
      "description": "List with staggered animations Note: Import the animations CSS file to use this component: import \"@getnarro/shared-ui/styles/animations.css\";",
      "behaviour": "A vertical column of its items with staggered entry; it does not\ninherit the surrounding list styling, and it is one element per item rather than\na `<ul>`.",
      "examples": [
        "<AnimatedList\n  items={['First point', 'Second point', 'Third point']}\n  animation=\"slide-up\"\n  staggerDelay={150}\n  variant=\"check\"\n/>"
      ],
      "props": [
        {
          "name": "items",
          "type": "ReactNode[]",
          "required": true,
          "description": "List items to animate"
        },
        {
          "name": "animation",
          "type": "ListAnimationType",
          "required": false,
          "defaultValue": "\"fade-in\"",
          "description": "Animation type"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "400",
          "description": "Animation duration per item in milliseconds"
        },
        {
          "name": "initialDelay",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Delay before starting first animation in milliseconds"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Override slide active state"
        },
        {
          "name": "ordered",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Ordered or unordered list"
        },
        {
          "name": "staggerDelay",
          "type": "number",
          "required": false,
          "defaultValue": "150",
          "description": "Delay between each item in milliseconds"
        },
        {
          "name": "variant",
          "type": "\"disc\" | \"decimal\" | \"check\" | \"arrow\" | \"none\"",
          "required": false,
          "defaultValue": "\"none\"",
          "description": "List style variant"
        }
      ]
    },
    {
      "name": "Animation",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A CSS animation wrapper component When used inside a Slide component from narro, animations will only trigger when the slide becomes active. Note: Import the animations CSS file to use this component: import \"@getnarro/shared-ui/styles/animations.css\";",
      "examples": [
        "<Animation type=\"slide-up\" delay={200} duration={500}>\n  <Heading level={1}>Animated Title</Heading>\n</Animation>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "delay",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Animation delay (ms)"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "500",
          "description": "Animation duration (ms)"
        },
        {
          "name": "easing",
          "type": "\"linear\" | \"ease-out\" | \"ease-in-out\" | \"ease\" | \"ease-in\"",
          "required": false,
          "defaultValue": "\"ease-out\"",
          "description": "Animation easing"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Override slide active state (for use without narro context)"
        },
        {
          "name": "trigger",
          "type": "\"mount\" | \"hover\" | \"visible\"",
          "required": false,
          "defaultValue": "\"mount\"",
          "description": "Trigger animation on mount"
        },
        {
          "name": "type",
          "type": "AnimationType",
          "required": false,
          "defaultValue": "\"fade\"",
          "description": "Animation type"
        }
      ]
    },
    {
      "name": "Badge",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "a short inline label.",
      "examples": [
        "<Badge tone=\"success\">WCAG AA</Badge>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "radius",
          "type": "SurfaceRadius",
          "required": false,
          "defaultValue": "\"full\"",
          "description": "Corner rounding. Defaults to a pill."
        },
        {
          "name": "tone",
          "type": "SurfaceTone",
          "required": false,
          "defaultValue": "\"default\"",
          "description": "Colour role of the badge."
        }
      ]
    },
    {
      "name": "BigText",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "Extremely large, impactful text component",
      "examples": [
        "<BigText effect=\"gradient\" animate=\"blur-reveal\">\n  IMPACT\n</BigText>"
      ],
      "props": [
        {
          "name": "align",
          "type": "\"center\" | \"left\" | \"right\"",
          "required": false,
          "defaultValue": "\"center\"",
          "description": "Text alignment"
        },
        {
          "name": "animate",
          "type": "BigTextAnimation",
          "required": false,
          "defaultValue": "\"none\"",
          "description": "Animation preset"
        },
        {
          "name": "animationDuration",
          "type": "number",
          "required": false,
          "defaultValue": "800",
          "description": "Animation duration in milliseconds"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "color",
          "type": "string",
          "required": false,
          "defaultValue": "\"default\"",
          "description": "Text color"
        },
        {
          "name": "effect",
          "type": "BigTextEffect",
          "required": false,
          "defaultValue": "\"none\"",
          "description": "Text effect to apply"
        },
        {
          "name": "gradientColors",
          "type": "string",
          "required": false,
          "defaultValue": "\"from-blue-500 via-purple-500 to-pink-500\"",
          "description": "Custom gradient colors (when effect is \"gradient\")"
        }
      ]
    },
    {
      "name": "Callout",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "a card with a coloured edge, for the one thing on the slide that matters most.",
      "examples": [
        "<Callout tone=\"warning\" title=\"Not swapped\">\n  This one is added, not replaced.\n</Callout>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "icon",
          "type": "ReactNode",
          "required": false,
          "description": "Anything to sit left of the text — an `<Icon>`, an emoji."
        },
        {
          "name": "title",
          "type": "string",
          "required": false,
          "description": "Bold line above the body."
        },
        {
          "name": "tone",
          "type": "SurfaceTone",
          "required": false,
          "defaultValue": "\"primary\"",
          "description": "Colour role of the edge and background."
        }
      ]
    },
    {
      "name": "Card",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "a bordered surface.",
      "examples": [
        "<Card tone=\"primary\" padding=\"lg\">\n  <Heading level={3}>Narro</Heading>\n  <Text>Decks as code.</Text>\n</Card>"
      ],
      "props": [
        {
          "name": "bordered",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Draw the border. Off gives a plain tinted panel."
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "padding",
          "type": "\"none\" | \"sm\" | \"md\" | \"lg\"",
          "required": false,
          "defaultValue": "\"md\"",
          "description": "Inner spacing."
        },
        {
          "name": "radius",
          "type": "SurfaceRadius",
          "required": false,
          "defaultValue": "\"md\"",
          "description": "Corner rounding."
        },
        {
          "name": "tone",
          "type": "SurfaceTone",
          "required": false,
          "defaultValue": "\"default\"",
          "description": "Colour role of the surface."
        }
      ]
    },
    {
      "name": "Chart",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A simple chart component Deliberately small: bar, line, pie and donut, drawn with CSS and SVG, for the one number a slide is about. There is no axis, no gridline, no tooltip and no stacking, and adding them is not the plan — a slide that needs a real chart should render it with a real charting library and place the image, which is a documented workflow rather than a shrug.",
      "behaviour": "Bars are proportional to the largest value **in this chart**,\nunless `max` says otherwise. `height` is the whole component including the\ntitle and legend, and the plot is clamped to 80px, so give a bar chart at\nleast 200px or the bars stop communicating. `showValues` reserves room for the\nvalue beside each bar.",
      "examples": [
        "<Chart\n  type=\"bar\"\n  data={[\n    { label: 'Q1', value: 100 },\n    { label: 'Q2', value: 150 },\n    { label: 'Q3', value: 200 },\n  ]}\n  title=\"Quarterly Sales\"\n/>"
      ],
      "props": [
        {
          "name": "data",
          "type": "ChartDataPoint[]",
          "required": true,
          "description": "Chart data"
        },
        {
          "name": "type",
          "type": "\"line\" | \"bar\" | \"pie\" | \"donut\"",
          "required": true,
          "description": "Chart type"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "colors",
          "type": "string[]",
          "required": false,
          "defaultValue": "defaultColors",
          "description": "Colour palette, applied in data order. To emphasise one point regardless of ordering, set `color` on that `ChartDataPoint` instead — it wins over the palette."
        },
        {
          "name": "height",
          "type": "number",
          "required": false,
          "defaultValue": "300",
          "description": "Chart height"
        },
        {
          "name": "max",
          "type": "number",
          "required": false,
          "description": "The value a full-length bar represents. Defaults to the largest value in this chart's own data, which is what makes two charts on two slides quietly incomparable: each is drawn against its own maximum, so a 60-unit bar and a 90-unit bar can be the same length on consecutive slides and a reader comparing them gets a wrong answer with nothing to warn them. Pin it when the comparison spans slides. Not an axis, and not a step toward one — it is the one piece of scale information a slide can carry without this becoming a chart library."
        },
        {
          "name": "orientation",
          "type": "\"horizontal\" | \"vertical\"",
          "required": false,
          "defaultValue": "\"vertical\"",
          "description": "Bar direction. Horizontal reads better when labels are long: a long label under a narrow column is unreadable, which is what vertical-only forced. Bar charts only."
        },
        {
          "name": "showLegend",
          "type": "boolean",
          "required": false,
          "description": "Show the category legend. Defaults to on for `pie`/`donut` and off for everything else. It used to default to on for all of them, so a single-series bar chart printed the same three names under bars that already carried them — noise, and 40px of plot height gone."
        },
        {
          "name": "showValues",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Print each value on its bar, rather than folding it into the label."
        },
        {
          "name": "title",
          "type": "string",
          "required": false,
          "description": "Chart title"
        },
        {
          "name": "unit",
          "type": "string",
          "required": false,
          "description": "Unit appended to every printed value — `unit=\"KB\"` prints `72 KB`. A bundle-size chart needs \"72 KB\", not \"72\", and folding the unit into the label meant `showValues` then printed the bare number a second time. Declarative because an attribute block in a markdown deck cannot pass a function."
        },
        {
          "name": "valueFormat",
          "type": "((value: number) => string)",
          "required": false,
          "description": "Full control over how a value is printed. Wins over {@link unit}."
        }
      ]
    },
    {
      "name": "Code",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A code block component with optional line numbers and copy button",
      "behaviour": "**Nothing is tokenised here.** `language` is recorded as a\n`language-*` class and used for the label; it does not colour anything. A\nmarkdown fence *is* highlighted — Narro tokenises it when the deck compiles —\nbut this component takes its code as children at runtime, and a React deck has\nno compile step to do it in. Highlighting it would mean shipping a highlighter\nand its grammars to the browser, which for a runtime the docs already\napologise for is a worse trade than grey code.\n\nIf the colour is load-bearing in a React deck, run Shiki's `codeToHtml` at\nbuild time and drop the result in — it keys off the same `language-*` class.\nSee [Limitations](/docs/limitations#the-react-code-component-is-not-highlighted).",
      "examples": [
        "<Code language=\"typescript\" lineNumbers>\n{`const greeting = \"Hello, World!\";\nconsole.log(greeting);`}\n</Code>"
      ],
      "props": [
        {
          "name": "children",
          "type": "string",
          "required": true,
          "description": "Code content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "copyButton",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Show copy button"
        },
        {
          "name": "highlightLines",
          "type": "string",
          "required": false,
          "description": "Lines to highlight (comma-separated or range)"
        },
        {
          "name": "language",
          "type": "string",
          "required": false,
          "description": "Programming language"
        },
        {
          "name": "lineNumbers",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Show line numbers"
        },
        {
          "name": "preClassName",
          "type": "string",
          "required": false,
          "description": "Classes for the inner `<pre>`, which is what carries the type size. The size used to be an inline style, so `className=\"text-[12px]\"` on the block did nothing and there was no way to shrink code to fit a slide. Both work now; this is the direct spelling."
        },
        {
          "name": "theme",
          "type": "\"dark\" | \"light\"",
          "required": false,
          "defaultValue": "\"dark\"",
          "description": "Theme variant"
        }
      ]
    },
    {
      "name": "CommentForm",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A form for creating or editing comments",
      "examples": [
        "<CommentForm\n  slideId=\"slide-1\"\n  defaultAuthor=\"John Doe\"\n  onSubmit={(comment) => handleAddComment(comment)}\n  onCancel={() => setShowForm(false)}\n/>"
      ],
      "props": [
        {
          "name": "onSubmit",
          "type": "(comment: Omit<SlideComment, \"id\" | \"createdAt\">) => void",
          "required": true,
          "description": "Callback when comment is submitted"
        },
        {
          "name": "slideId",
          "type": "string",
          "required": true,
          "description": "Slide ID to add comment to"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "defaultAuthor",
          "type": "string",
          "required": false,
          "defaultValue": "\"\"",
          "description": "Default author name"
        },
        {
          "name": "initialContent",
          "type": "string",
          "required": false,
          "defaultValue": "\"\"",
          "description": "Initial content (for editing)"
        },
        {
          "name": "isEditing",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Whether this is editing an existing comment"
        },
        {
          "name": "onCancel",
          "type": "(() => void)",
          "required": false,
          "description": "Callback when form is cancelled"
        },
        {
          "name": "parentId",
          "type": "string",
          "required": false,
          "description": "Parent comment ID for replies"
        },
        {
          "name": "placeholder",
          "type": "string",
          "required": false,
          "defaultValue": "\"Add a comment...\"",
          "description": "Placeholder text"
        },
        {
          "name": "position",
          "type": "CommentPosition",
          "required": false,
          "description": "Position for inline comments"
        }
      ]
    },
    {
      "name": "CommentItem",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "Displays a single comment with actions",
      "examples": [
        "<CommentItem\n  comment={comment}\n  onEdit={(id) => handleEdit(id)}\n  onDelete={(id) => handleDelete(id)}\n  onResolve={(id, resolved) => handleResolve(id, resolved)}\n/>"
      ],
      "props": [
        {
          "name": "comment",
          "type": "SlideComment",
          "required": true,
          "description": "The comment to display"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "currentUser",
          "type": "string",
          "required": false,
          "description": "Current user's name (to determine if they can edit/delete)"
        },
        {
          "name": "onDelete",
          "type": "((commentId: string) => void)",
          "required": false,
          "description": "Callback when delete is clicked"
        },
        {
          "name": "onEdit",
          "type": "((commentId: string) => void)",
          "required": false,
          "description": "Callback when edit is clicked"
        },
        {
          "name": "onReaction",
          "type": "((commentId: string, emoji: string) => void)",
          "required": false,
          "description": "Callback when a reaction is added"
        },
        {
          "name": "onReply",
          "type": "((commentId: string, content: string) => void)",
          "required": false,
          "description": "Callback when reply is submitted"
        },
        {
          "name": "onResolve",
          "type": "((commentId: string, resolved: boolean) => void)",
          "required": false,
          "description": "Callback when resolve is toggled"
        },
        {
          "name": "replies",
          "type": "SlideComment[]",
          "required": false,
          "defaultValue": "[]",
          "description": "Child comments (replies)"
        },
        {
          "name": "showReplyForm",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Whether to show the reply form"
        }
      ]
    },
    {
      "name": "CommentMarker",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A visual indicator for comment positions on slides",
      "examples": [
        "<CommentMarker\n  position={{ x: 50, y: 30 }}\n  count={3}\n  onClick={() => setShowComments(true)}\n/>"
      ],
      "props": [
        {
          "name": "position",
          "type": "CommentPosition",
          "required": true,
          "description": "Position of the marker on the slide (percentage 0-100)"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "commentId",
          "type": "string",
          "required": false,
          "description": "Comment ID this marker represents"
        },
        {
          "name": "count",
          "type": "number",
          "required": false,
          "defaultValue": "1",
          "description": "Number of comments at this position"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Whether the marker is in an active/selected state"
        },
        {
          "name": "onClick",
          "type": "(() => void)",
          "required": false,
          "description": "Callback when marker is clicked"
        }
      ]
    },
    {
      "name": "CommentPanel",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A sidebar panel for managing comments",
      "examples": [
        "<CommentPanel\n  slideId=\"slide-1\"\n  comments={allComments}\n  onAddComment={(comment) => addComment(comment)}\n  onDeleteComment={(id) => deleteComment(id)}\n  currentUser=\"John Doe\"\n/>"
      ],
      "props": [
        {
          "name": "comments",
          "type": "SlideComment[]",
          "required": true,
          "description": "All comments data"
        },
        {
          "name": "onAddComment",
          "type": "(comment: Omit<SlideComment, \"id\" | \"createdAt\">) => void",
          "required": true,
          "description": "Callback to add a new comment"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "currentUser",
          "type": "string",
          "required": false,
          "description": "Current user name"
        },
        {
          "name": "filter",
          "type": "CommentFilterOptions",
          "required": false,
          "description": "Filter options"
        },
        {
          "name": "isCollapsed",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Whether the panel is in collapsed state"
        },
        {
          "name": "onCollapseChange",
          "type": "((collapsed: boolean) => void)",
          "required": false,
          "description": "Callback when collapse state changes"
        },
        {
          "name": "onDeleteComment",
          "type": "((commentId: string) => void)",
          "required": false,
          "description": "Callback to delete a comment"
        },
        {
          "name": "onFilterChange",
          "type": "((filter: CommentFilterOptions) => void)",
          "required": false,
          "description": "Callback when filter changes"
        },
        {
          "name": "onResolveComment",
          "type": "((commentId: string, resolved: boolean) => void)",
          "required": false,
          "description": "Callback to resolve/unresolve a comment"
        },
        {
          "name": "onUpdateComment",
          "type": "((commentId: string, updates: Partial<SlideComment>) => void)",
          "required": false,
          "description": "Callback to update a comment"
        },
        {
          "name": "slideId",
          "type": "string",
          "required": false,
          "description": "Slide ID to show comments for (if undefined, shows all)"
        }
      ]
    },
    {
      "name": "ContentSlide",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A slide with optional title and content area",
      "examples": [
        "<ContentSlide title=\"Key Features\">\n  <List items={['Feature 1', 'Feature 2', 'Feature 3']} />\n</ContentSlide>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "title",
          "type": "ReactNode",
          "required": false,
          "description": "Slide title"
        }
      ]
    },
    {
      "name": "CountingNumber",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/CountingNumber.tsx",
      "description": "Animated number counter",
      "examples": [
        "<CountingNumber\n  value={1000000}\n  duration={2000}\n  format={{ prefix: \"$\", separator: true }}\n/>"
      ],
      "props": [
        {
          "name": "value",
          "type": "number",
          "required": true,
          "description": "Target value to count to"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "delay",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Delay before starting animation in milliseconds"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "1500",
          "description": "Animation duration in milliseconds"
        },
        {
          "name": "easing",
          "type": "\"linear\" | \"ease-out\" | \"ease-in-out\"",
          "required": false,
          "defaultValue": "\"ease-out\"",
          "description": "Animation easing"
        },
        {
          "name": "format",
          "type": "{ decimals?: number | undefined; prefix?: string | undefined; suffix?: string | undefined; separator?: boolean | undefined; locale?: string | undefined; }",
          "required": false,
          "description": "Number format options"
        },
        {
          "name": "from",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Starting value (default: 0)"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Override slide active state"
        },
        {
          "name": "onComplete",
          "type": "(() => void)",
          "required": false,
          "description": "Callback when animation completes"
        }
      ]
    },
    {
      "name": "Diagram",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "a monospaced block for ASCII diagrams. `children` is `ReactNode`, not a string, so individual nodes of a tree can be coloured with a `<span>` inside the block — which is how \"these components re-rendered and these did not\" gets said without a drawing primitive. The type size lives on the inner `<pre>`: pass `preClassName`, or a `text-*` utility in `className`, which `cn` will resolve in your favour.",
      "examples": [
        "<Diagram preClassName=\"text-xl\">\n{`\n  +--------+     +--------+\n  | Client | --> | Server |\n  +--------+     +--------+\n`}\n</Diagram>",
        "// Individual nodes styled, because children are nodes rather than text.\n<Diagram>\n  {\"Client\\n  \"}\n  <span style={{ color: \"#f43f5e\" }}>{\"Server (re-rendered)\"}</span>\n</Diagram>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "preClassName",
          "type": "string",
          "required": false,
          "description": "Classes for the inner `<pre>`, which is what carries the type size. `className` lands on the wrapper, so sizing the diagram used to need `[&_pre]:!text-xl` — an arbitrary variant plus an `!important`, for the one thing every author changes. The `<pre>`'s own defaults are classes now, so either works; this is the direct spelling."
        },
        {
          "name": "theme",
          "type": "\"dark\" | \"light\" | \"forest\"",
          "required": false,
          "defaultValue": "\"dark\"",
          "description": "Diagram theme"
        }
      ]
    },
    {
      "name": "DottedArc",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "Decorative concentric dotted arcs Creates a series of concentric arcs with dashed lines in varying colors. Used as a decorative element for title slides and maintaining brand consistency.",
      "examples": [
        "<DottedArc\n  colors={[\"#ff6b35\", \"#4ecdc4\", \"#1a535c\"]}\n  position=\"bottom-right\"\n/>",
        "// Custom sizing and spacing\n<DottedArc\n  colors={[\"orange\", \"green\", \"blue\"]}\n  width={3}\n  spacing={10}\n  size={400}\n  position=\"bottom-left\"\n/>"
      ],
      "props": [
        {
          "name": "colors",
          "type": "string[]",
          "required": true,
          "description": "Array of colors for each arc"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "position",
          "type": "\"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\"",
          "required": false,
          "defaultValue": "\"bottom-right\"",
          "description": "Arc position"
        },
        {
          "name": "size",
          "type": "number",
          "required": false,
          "defaultValue": "300",
          "description": "Size of the arc container"
        },
        {
          "name": "spacing",
          "type": "number",
          "required": false,
          "defaultValue": "8",
          "description": "Spacing between arcs"
        },
        {
          "name": "width",
          "type": "number",
          "required": false,
          "defaultValue": "2",
          "description": "Line width for arcs"
        }
      ]
    },
    {
      "name": "DualColumnTextAndImage",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/DualColumnTextAndImage.tsx",
      "description": "A two-column layout where text is on one side and an image is on the other",
      "behaviour": "A full-height flex row: text in one column, image in the other, each\ntaking the whole height. It expects to be the slide's main content rather than to\nsit under a heading.",
      "examples": [
        "<DualColumnTextAndImage\n  text=\"This is the text content\"\n  image=\"/path/to/image.png\"\n  imageAlt=\"Description of image\"\n  gap=\"md\"\n/>"
      ],
      "props": [
        {
          "name": "image",
          "type": "string",
          "required": true,
          "description": "URL of the image to display in the right column"
        },
        {
          "name": "text",
          "type": "ReactNode",
          "required": true,
          "description": "Text content to display in the left column"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "gap",
          "type": "\"sm\" | \"md\" | \"lg\" | \"xl\"",
          "required": false,
          "defaultValue": "\"lg\"",
          "description": "Gap between columns"
        },
        {
          "name": "imageAlt",
          "type": "string",
          "required": false,
          "defaultValue": "\"\"",
          "description": "Alt text for the image"
        },
        {
          "name": "reverse",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Reverse the layout (image left, text right)"
        }
      ]
    },
    {
      "name": "Embed",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "External content embedding component Supports YouTube, Vimeo, Google Slides, websites, web applications, and generic iframes.",
      "examples": [
        "// Embed a YouTube video\n<Embed\n  url=\"https://www.youtube.com/watch?v=dQw4w9WgXcQ\"\n  title=\"Video demonstration\"\n  aspectRatio=\"16:9\"\n/>\n\n// Embed a web application with sandbox restrictions\n<Embed\n  url=\"https://codesandbox.io/embed/...\"\n  title=\"Live code demo\"\n  sandbox=\"allow-scripts allow-same-origin\"\n  loading=\"lazy\"\n/>\n\n// Embed a website\n<Embed\n  url=\"https://example.com\"\n  title=\"Example website\"\n  aspectRatio=\"16:9\"\n/>"
      ],
      "props": [
        {
          "name": "url",
          "type": "string",
          "required": true,
          "description": "URL to embed (YouTube, Vimeo, websites, web apps, etc.)"
        },
        {
          "name": "allow",
          "type": "string",
          "required": false,
          "defaultValue": "\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\"",
          "description": "Custom permissions for iframe (default includes common permissions)"
        },
        {
          "name": "allowFullscreen",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Allow fullscreen"
        },
        {
          "name": "aspectRatio",
          "type": "\"1:1\" | \"16:9\" | \"4:3\"",
          "required": false,
          "defaultValue": "\"16:9\"",
          "description": "Aspect ratio"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "loading",
          "type": "\"lazy\" | \"eager\"",
          "required": false,
          "defaultValue": "\"eager\"",
          "description": "Lazy loading strategy"
        },
        {
          "name": "referrerPolicy",
          "type": "\"no-referrer\" | \"no-referrer-when-downgrade\" | \"origin\" | \"origin-when-cross-origin\" | \"same-origin\" | \"strict-origin\" | \"strict-origin-when-cross-origin\" | \"unsafe-url\"",
          "required": false,
          "description": "Referrer policy"
        },
        {
          "name": "sandbox",
          "type": "string",
          "required": false,
          "description": "Sandbox restrictions for iframe security"
        },
        {
          "name": "title",
          "type": "string",
          "required": false,
          "defaultValue": "\"Embedded content\"",
          "description": "Embed title for accessibility"
        }
      ]
    },
    {
      "name": "FlowDiagram",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/FlowDiagram.tsx",
      "description": "A visual representation of a process flow with steps",
      "behaviour": "Lays its steps along a single axis chosen by `direction`, full width,\nwith connectors between adjacent steps. It draws a chain — there is no branching\nor converging.",
      "examples": [
        "<FlowDiagram\n  steps={[\n    {label: 'Step 1', icon: '/icon1.png', description: 'First step'},\n    {label: 'Step 2', icon: '/icon2.png', description: 'Second step'}\n  ]}\n  direction=\"horizontal\"\n  color=\"#08979c\"\n/>"
      ],
      "props": [
        {
          "name": "steps",
          "type": "FlowStep[]",
          "required": true,
          "description": "List of steps with labels and optional icons"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "color",
          "type": "string",
          "required": false,
          "defaultValue": "\"#08979c\"",
          "description": "Color for step boxes and connectors"
        },
        {
          "name": "direction",
          "type": "\"horizontal\" | \"vertical\"",
          "required": false,
          "defaultValue": "\"vertical\"",
          "description": "Direction of flow"
        },
        {
          "name": "gap",
          "type": "\"sm\" | \"md\" | \"lg\" | \"xl\"",
          "required": false,
          "defaultValue": "\"md\"",
          "description": "Gap between steps"
        }
      ]
    },
    {
      "name": "FourColumn",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A four-column layout component with equal columns",
      "examples": [
        "<FourColumn\n  first={<Text>Column 1</Text>}\n  second={<Text>Column 2</Text>}\n  third={<Text>Column 3</Text>}\n  fourth={<Text>Column 4</Text>}\n  gap=\"lg\"\n  align=\"center\"\n/>"
      ],
      "props": [
        {
          "name": "first",
          "type": "ReactNode",
          "required": true,
          "description": "First column content"
        },
        {
          "name": "fourth",
          "type": "ReactNode",
          "required": true,
          "description": "Fourth column content"
        },
        {
          "name": "second",
          "type": "ReactNode",
          "required": true,
          "description": "Second column content"
        },
        {
          "name": "third",
          "type": "ReactNode",
          "required": true,
          "description": "Third column content"
        },
        {
          "name": "align",
          "type": "\"center\" | \"start\" | \"end\" | \"stretch\"",
          "required": false,
          "defaultValue": "\"stretch\"",
          "description": "Vertical alignment"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "gap",
          "type": "\"sm\" | \"md\" | \"lg\" | \"xl\"",
          "required": false,
          "defaultValue": "\"md\"",
          "description": "Gap between columns"
        },
        {
          "name": "responsive",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Stack columns on small screens"
        }
      ]
    },
    {
      "name": "Fragment",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "Step-by-step reveal component Each Fragment animates in sequence based on its `order` prop. The delay is calculated as: order * staggerDelay When used inside a Slide component from narro, animations will only trigger when the slide becomes active. Note: Import the animations CSS file to use this component: import \"@getnarro/shared-ui/styles/animations.css\";",
      "examples": [
        "<Fragment order={1} effect=\"fade-in\">\n  <Text>This appears first (after 400ms)</Text>\n</Fragment>\n<Fragment order={2} effect=\"slide-up\">\n  <Text>This appears second (after 800ms)</Text>\n</Fragment>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "300",
          "description": "Animation duration (ms)"
        },
        {
          "name": "effect",
          "type": "FragmentEffect",
          "required": false,
          "defaultValue": "DEFAULT_EFFECT",
          "description": "Animation effect"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Override slide active state (for use without narro context)"
        },
        {
          "name": "order",
          "type": "number",
          "required": false,
          "description": "Order in which fragment appears"
        },
        {
          "name": "staggerDelay",
          "type": "number",
          "required": false,
          "defaultValue": "DEFAULT_STAGGER_DELAY",
          "description": "Delay between each fragment (ms) - used to stagger animations"
        },
        {
          "name": "trigger",
          "type": "\"time\" | \"step\"",
          "required": false,
          "defaultValue": "\"step\"",
          "description": "What reveals the fragment. `\"step\"` (the default) waits for the presenter: each press reveals the next fragment and the press after the last one advances the slide. `\"time\"` reveals everything on slide entry, staggered by `order` — the behaviour before reveals were wired to navigation. Outside a `Slide` there is nothing to step, so `\"time\"` is used whatever this says."
        }
      ]
    },
    {
      "name": "Grid",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A flexible grid layout component",
      "examples": [
        "<Grid columns={3} gap=\"md\">\n  <InfoCardWithIcon title=\"First\">Item 1</InfoCardWithIcon>\n  <InfoCardWithIcon title=\"Second\">Item 2</InfoCardWithIcon>\n  <InfoCardWithIcon title=\"Third\">Item 3</InfoCardWithIcon>\n</Grid>"
      ],
      "props": [
        {
          "name": "align",
          "type": "\"center\" | \"start\" | \"end\" | \"stretch\"",
          "required": false,
          "defaultValue": "\"stretch\"",
          "description": "Horizontal alignment"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "columns",
          "type": "2 | 3 | 4 | 5 | 6 | 1",
          "required": false,
          "defaultValue": "3",
          "description": "Number of columns"
        },
        {
          "name": "gap",
          "type": "\"sm\" | \"md\" | \"lg\" | \"xl\"",
          "required": false,
          "defaultValue": "\"md\"",
          "description": "Gap between items"
        },
        {
          "name": "justify",
          "type": "\"center\" | \"start\" | \"end\" | \"stretch\"",
          "required": false,
          "defaultValue": "\"start\"",
          "description": "Vertical alignment"
        }
      ]
    },
    {
      "name": "Heading",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A styled heading component (h1-h6)",
      "behaviour": "`level` picks both the tag and the type scale, and the scale is a\nclass — so `className=\"text-[13rem]\"` replaces it rather than losing to it.\nMargin is zeroed; add your own with `className`.",
      "examples": [
        "<Heading level={1}>Main Title</Heading>\n<Heading level={2} color=\"primary\">Subtitle</Heading>"
      ],
      "props": [
        {
          "name": "align",
          "type": "\"center\" | \"left\" | \"right\"",
          "required": false,
          "defaultValue": "\"left\"",
          "description": "Text alignment"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "color",
          "type": "\"default\" | \"primary\" | \"muted\" | \"accent\"",
          "required": false,
          "defaultValue": "\"default\"",
          "description": "Color variant"
        },
        {
          "name": "level",
          "type": "2 | 3 | 4 | 5 | 6 | 1",
          "required": false,
          "defaultValue": "1",
          "description": "Heading level (1-6)"
        }
      ]
    },
    {
      "name": "HexPatternBackground",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/HexPatternBackground.tsx",
      "description": "A background with a hexagonal pattern",
      "behaviour": "Fills its positioning parent and sits behind the content, like every\nbackground. It sets no size of its own, so an unpositioned parent leaves it\ncovering the viewport.",
      "examples": [
        "<HexPatternBackground backgroundColor=\"#00d9c4\" hexColor=\"#08979c\">\n  <h1>Content here</h1>\n</HexPatternBackground>"
      ],
      "props": [
        {
          "name": "backgroundColor",
          "type": "string",
          "required": false,
          "defaultValue": "\"#00d9c4\"",
          "description": "Background color (hex or rgb)"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Content to be rendered on top of the hexagon pattern background"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "hexColor",
          "type": "string",
          "required": false,
          "defaultValue": "\"#08979c\"",
          "description": "Hexagon stroke color (hex or rgb)"
        },
        {
          "name": "patternSize",
          "type": "\"sm\" | \"md\" | \"lg\"",
          "required": false,
          "defaultValue": "\"md\"",
          "description": "Pattern size (affects hexagon scale)"
        }
      ]
    },
    {
      "name": "Icon",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A simple icon component A small closed set of typographic symbols — see `ICON_NAMES`. It is not a logo set and does not aim to be: an icon library that resolves names at runtime cannot be tree-shaken, so it would ship every glyph to every deck, on a runtime this library's own documentation already apologises for. **For a brand mark, use `Image` with the logo file.** `github` used to be in the set, drawn as `⌘` — the Command key — which is a wrong answer rather than a rough one.",
      "behaviour": "A name outside the set draws nothing and reports to the console.\nIt used to render the name *as text*, so `<Icon name=\"rocket\" />` put the\nword \"rocket\" on the slide. TypeScript catches this now; the runtime guard is\nfor a name computed at runtime, and it reports as an error so\n`narro check --fit` — which fails a deck whose page logged one — catches it\ntoo.",
      "examples": [
        "<Icon name=\"check\" size=\"lg\" color=\"green\" />\n<Icon name=\"terminal\" size={32} />"
      ],
      "props": [
        {
          "name": "name",
          "type": "\"check\" | \"arrow\" | \"code\" | \"link\" | \"search\" | \"cross\" | \"arrow-left\" | \"arrow-up\" | \"arrow-down\" | \"star\" | \"heart\" | \"warning\" | \"info\" | \"question\" | \"plus\" | \"minus\" | \"terminal\" | \"email\" | \"phone\" | \"location\" | \"calendar\" | \"clock\" | \"file\" | \"folder\" | \"settings\" | \"user\" | \"users\"",
          "required": true,
          "description": "Which icon to draw. A closed set — see {@link ICON_NAMES}. This was `string`, documented as \"Icon name or SVG content\". SVG content never worked: the value is rendered as text, so markup arrived on the slide escaped."
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "color",
          "type": "string",
          "required": false,
          "description": "Icon color"
        },
        {
          "name": "label",
          "type": "string",
          "required": false,
          "description": "Accessibility label"
        },
        {
          "name": "size",
          "type": "number | \"sm\" | \"md\" | \"lg\" | \"xl\"",
          "required": false,
          "defaultValue": "\"md\"",
          "description": "Icon size"
        }
      ]
    },
    {
      "name": "Image",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "An optimized image component with filter support",
      "examples": [
        "<Image\n  src=\"/images/photo.jpg\"\n  alt=\"A beautiful landscape\"\n  fit=\"cover\"\n  rounded=\"lg\"\n  shadow\n  filter=\"grayscale\"\n/>",
        "Custom filter:\n```tsx\n<Image\n  src=\"/images/photo.jpg\"\n  alt=\"Custom filtered\"\n  customFilter=\"brightness(80%) contrast(110%)\"\n/>\n```",
        "Color overlay:\n```tsx\n<Image\n  src=\"/images/photo.jpg\"\n  alt=\"Blue tinted\"\n  overlay=\"#3b82f6\"\n  overlayOpacity={0.4}\n/>\n```"
      ],
      "props": [
        {
          "name": "alt",
          "type": "string",
          "required": true,
          "description": "Alt text for accessibility"
        },
        {
          "name": "src",
          "type": "string",
          "required": true,
          "description": "Image source URL"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "customFilter",
          "type": "string",
          "required": false,
          "description": "Custom CSS filter value (overrides filter preset)"
        },
        {
          "name": "filter",
          "type": "ImageFilter",
          "required": false,
          "defaultValue": "\"none\"",
          "description": "Apply CSS filter preset"
        },
        {
          "name": "fit",
          "type": "\"none\" | \"cover\" | \"contain\" | \"fill\"",
          "required": false,
          "defaultValue": "\"cover\"",
          "description": "Object fit mode"
        },
        {
          "name": "height",
          "type": "string | number",
          "required": false,
          "description": "Height constraint"
        },
        {
          "name": "overlay",
          "type": "string",
          "required": false,
          "description": "Color overlay (CSS color value)"
        },
        {
          "name": "overlayOpacity",
          "type": "number",
          "required": false,
          "defaultValue": "0.5",
          "description": "Opacity of the color overlay (0-1, default: 0.5)"
        },
        {
          "name": "rounded",
          "type": "\"none\" | \"sm\" | \"md\" | \"lg\" | \"full\"",
          "required": false,
          "defaultValue": "\"none\"",
          "description": "Border radius"
        },
        {
          "name": "shadow",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Add shadow"
        },
        {
          "name": "width",
          "type": "string | number",
          "required": false,
          "description": "Width constraint"
        }
      ]
    },
    {
      "name": "ImageBackground",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A full-bleed background image with content overlay",
      "examples": [
        "<ImageBackground\n  src=\"/images/hero.jpg\"\n  alt=\"Hero background\"\n  overlay=\"dark\"\n  kenBurns\n>\n  <Heading level={1}>Bold Title</Heading>\n  <Text>Subtitle text here</Text>\n</ImageBackground>"
      ],
      "props": [
        {
          "name": "src",
          "type": "string",
          "required": true,
          "description": "Image source URL"
        },
        {
          "name": "alt",
          "type": "string",
          "required": false,
          "defaultValue": "\"\"",
          "description": "Image alt text for accessibility"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "kenBurns",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Enable Ken Burns animation effect (slow zoom/pan)"
        },
        {
          "name": "kenBurnsDuration",
          "type": "number",
          "required": false,
          "defaultValue": "20",
          "description": "Ken Burns animation duration in seconds"
        },
        {
          "name": "overlay",
          "type": "ImageBackgroundOverlay",
          "required": false,
          "defaultValue": "\"dark\"",
          "description": "Overlay type for text readability"
        },
        {
          "name": "overlayColor",
          "type": "string",
          "required": false,
          "description": "Custom overlay color (CSS color value)"
        },
        {
          "name": "position",
          "type": "\"center\" | \"cover\" | \"contain\" | \"top\" | \"bottom\"",
          "required": false,
          "defaultValue": "\"cover\"",
          "description": "Image positioning"
        }
      ]
    },
    {
      "name": "ImageSlide",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A full-bleed image slide with optional overlay",
      "examples": [
        "<ImageSlide\n  src=\"/images/hero.jpg\"\n  alt=\"Hero image\"\n  overlay={<Heading level={1}>Welcome</Heading>}\n  overlayPosition=\"center\"\n/>"
      ],
      "props": [
        {
          "name": "src",
          "type": "string",
          "required": true,
          "description": "Image source URL"
        },
        {
          "name": "alt",
          "type": "string",
          "required": false,
          "defaultValue": "\"\"",
          "description": "Image alt text"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "fit",
          "type": "\"cover\" | \"contain\" | \"fill\"",
          "required": false,
          "defaultValue": "\"cover\"",
          "description": "Object fit mode"
        },
        {
          "name": "overlay",
          "type": "ReactNode",
          "required": false,
          "description": "Overlay content"
        },
        {
          "name": "overlayPosition",
          "type": "\"center\" | \"top\" | \"bottom\"",
          "required": false,
          "defaultValue": "\"center\"",
          "description": "Overlay position"
        }
      ]
    },
    {
      "name": "ImageSpotlight",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/ImageSpotlight.tsx",
      "description": "Keynote-style Magic Move for images Creates smooth zoom and pan animations between slides. Elements with the same spotlightId will animate smoothly when transitioning between slides.",
      "examples": [
        "// Slide 1 - Overview (centered, no zoom)\n<ImageSpotlight\n  spotlightId=\"diagram\"\n  src=\"/architecture.svg\"\n  alt=\"Architecture diagram\"\n  x={50}\n  y={50}\n  scale={1}\n  width=\"100%\"\n  height={400}\n/>\n\n// Slide 2 - Zoom to top-left element\n<ImageSpotlight\n  spotlightId=\"diagram\"\n  src=\"/architecture.svg\"\n  alt=\"Architecture diagram\"\n  x={25}\n  y={25}\n  scale={2.5}\n  width=\"100%\"\n  height={400}\n/>\n\n// Slide 3 - Pan to bottom-right element\n<ImageSpotlight\n  spotlightId=\"diagram\"\n  src=\"/architecture.svg\"\n  alt=\"Architecture diagram\"\n  x={75}\n  y={75}\n  scale={2.5}\n  width=\"100%\"\n  height={400}\n/>"
      ],
      "props": [
        {
          "name": "alt",
          "type": "string",
          "required": true,
          "description": "Alt text for accessibility"
        },
        {
          "name": "spotlightId",
          "type": "string",
          "required": true,
          "description": "Unique identifier for cross-slide morphing - elements with same id will animate between slides"
        },
        {
          "name": "src",
          "type": "string",
          "required": true,
          "description": "Image source URL"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes for container"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "800",
          "description": "Animation duration in ms, default 800"
        },
        {
          "name": "easing",
          "type": "\"linear\" | \"ease-out\" | \"ease-in-out\" | \"ease\" | \"ease-in\" | \"spring\"",
          "required": false,
          "defaultValue": "\"ease-in-out\"",
          "description": "Animation easing function"
        },
        {
          "name": "height",
          "type": "string | number",
          "required": false,
          "defaultValue": "400",
          "description": "Container height (CSS value or number in px)"
        },
        {
          "name": "imageClassName",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes for image"
        },
        {
          "name": "onAnimationComplete",
          "type": "(() => void)",
          "required": false,
          "description": "Callback when animation completes"
        },
        {
          "name": "overlay",
          "type": "ReactNode",
          "required": false,
          "description": "Optional overlay content that appears on top"
        },
        {
          "name": "rounded",
          "type": "\"none\" | \"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\"",
          "required": false,
          "defaultValue": "\"lg\"",
          "description": "Border radius"
        },
        {
          "name": "scale",
          "type": "number",
          "required": false,
          "defaultValue": "1",
          "description": "Scale/zoom level, default 1"
        },
        {
          "name": "shadow",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Show shadow"
        },
        {
          "name": "width",
          "type": "string | number",
          "required": false,
          "defaultValue": "\"100%\"",
          "description": "Container width (CSS value or number in px)"
        },
        {
          "name": "x",
          "type": "number",
          "required": false,
          "defaultValue": "50",
          "description": "X position as percentage (0-100), default 50 (centered)"
        },
        {
          "name": "y",
          "type": "number",
          "required": false,
          "defaultValue": "50",
          "description": "Y position as percentage (0-100), default 50 (centered)"
        }
      ]
    },
    {
      "name": "InfoCardWithIcon",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A styled information card with icon Displays an icon on the left with bold headings and descriptive text to the right. Uses consistent alignment and spacing. Perfect for concept highlights and important points.",
      "examples": [
        "<InfoCardWithIcon\n  iconSrc=\"/icon.svg\"\n  title=\"Key Feature\"\n  description=\"This is an important concept to highlight\"\n/>"
      ],
      "props": [
        {
          "name": "description",
          "type": "string",
          "required": true,
          "description": "Description text explaining the icon"
        },
        {
          "name": "iconSrc",
          "type": "string",
          "required": true,
          "description": "URL for the icon image"
        },
        {
          "name": "title",
          "type": "string",
          "required": true,
          "description": "Title of the info card"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        }
      ]
    },
    {
      "name": "List",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "An animated list component",
      "examples": [
        "<List\n  items={['First point', 'Second point', 'Third point']}\n  variant=\"check\"\n  animated\n/>"
      ],
      "props": [
        {
          "name": "items",
          "type": "ReactNode[]",
          "required": true,
          "description": "List items"
        },
        {
          "name": "animated",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Enable animations"
        },
        {
          "name": "animationDelay",
          "type": "number",
          "required": false,
          "defaultValue": "100",
          "description": "Animation delay between items (ms)"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "ordered",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Ordered or unordered list"
        },
        {
          "name": "variant",
          "type": "\"disc\" | \"decimal\" | \"check\" | \"arrow\" | \"none\"",
          "required": false,
          "defaultValue": "\"disc\"",
          "description": "List style"
        }
      ]
    },
    {
      "name": "LogoGrid",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/LogoGrid.tsx",
      "description": "A grid layout for displaying multiple logos with even spacing",
      "behaviour": "A CSS grid of exactly `columns` equal columns, full width, each cell\ncentring its logo. Rows wrap as needed; there is no way to size an individual\ncell. An entry with no `src` is set as a wordmark, so a text-only row of names\nis one call rather than a `Grid` of `Card`s.",
      "examples": [
        "<LogoGrid\n  logos={[\n    {src: '/path/to/logo1.png', name: 'Company 1'},\n    {src: '/path/to/logo2.png', name: 'Company 2'}\n  ]}\n  columns={3}\n  gap=\"md\"\n/>"
      ],
      "props": [
        {
          "name": "logos",
          "type": "Logo[]",
          "required": true,
          "description": "Array of logos. `src` is optional: an entry without one is set as a wordmark, so a row of product or company names needs no image files. Mixing the two is fine."
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "columns",
          "type": "2 | 3 | 4 | 5 | 6",
          "required": false,
          "defaultValue": "3",
          "description": "Number of columns"
        },
        {
          "name": "gap",
          "type": "\"sm\" | \"md\" | \"lg\" | \"xl\"",
          "required": false,
          "defaultValue": "\"md\"",
          "description": "Gap between logos"
        }
      ]
    },
    {
      "name": "MorphElement",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/SlideTransition.tsx",
      "description": "Element that morphs across slides using View Transitions API When elements with the same transitionName exist on consecutive slides, they will smoothly morph into each other during slide transitions.",
      "examples": [
        "// Slide 1\n<MorphElement transitionName=\"hero-image\">\n  <img src=\"product.jpg\" style={{ width: 200 }} />\n</MorphElement>\n\n// Slide 2 - same transitionName, different size\n<MorphElement transitionName=\"hero-image\">\n  <img src=\"product.jpg\" style={{ width: \"100%\" }} />\n</MorphElement>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Element content"
        },
        {
          "name": "transitionName",
          "type": "string",
          "required": true,
          "description": "Unique name for cross-slide morphing"
        },
        {
          "name": "as",
          "type": "ElementType<any, keyof IntrinsicElements>",
          "required": false,
          "defaultValue": "\"div\"",
          "description": "HTML tag to render"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "style",
          "type": "CSSProperties",
          "required": false,
          "description": "Additional inline styles"
        }
      ]
    },
    {
      "name": "ProcessFlowChart",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "Interactive flowchart for process visualization Creates a flowchart with customizable nodes and connections. Nodes are automatically laid out based on the direction prop, and connections are drawn between them with arrows.",
      "behaviour": "Draws a **chain**, not a graph: nodes sit in one line in array\norder along `direction`, and `connections` only chooses which arrows appear\nbetween those fixed positions. A fan-in, a branch or a cycle will not lay out\n— use `Canvas` with `CanvasElement`, or an SVG placed with `Image`. Node size\nis 220×90 by default; the chart sizes itself to the nodes.",
      "examples": [
        "<ProcessFlowChart\n  nodes={[\n    { id: \"start\", label: \"Start\", color: \"#4ecdc4\" },\n    { id: \"process\", label: \"Process\", color: \"#ff6b35\" },\n    { id: \"end\", label: \"End\", color: \"#95e1d3\" }\n  ]}\n  connections={[\n    { from: \"start\", to: \"process\" },\n    { from: \"process\", to: \"end\" }\n  ]}\n  direction=\"horizontal\"\n/>",
        "// Vertical flow with custom styling\n<ProcessFlowChart\n  nodes={[\n    { id: \"1\", label: \"Input\", color: \"#1a535c\", textColor: \"#fff\" },\n    { id: \"2\", label: \"Transform\", color: \"#4ecdc4\" },\n    { id: \"3\", label: \"Output\", color: \"#ff6b35\", textColor: \"#fff\" }\n  ]}\n  connections={[\n    { from: \"1\", to: \"2\", label: \"data\" },\n    { from: \"2\", to: \"3\", label: \"result\" }\n  ]}\n  direction=\"vertical\"\n  nodeGap=\"lg\"\n  arrowStyle=\"dashed\"\n/>"
      ],
      "props": [
        {
          "name": "connections",
          "type": "ProcessFlowConnection[]",
          "required": true,
          "description": "Which pairs of nodes get an arrow drawn between them. **This does not affect layout.** Nodes sit in a single line in array order, along the axis `direction` chooses; a connection draws a line between two of those fixed positions and can label it. `nodes` plus `connections` reads like a graph API and is not one — a fan-in, a branch or a cycle will render as a straight line with arrows doubling back along it. For those, use `Canvas` with `CanvasElement`, or draw an SVG and place it with `Image`."
        },
        {
          "name": "nodes",
          "type": "ProcessFlowNode[]",
          "required": true,
          "description": "Array of nodes with labels and colors. Laid out in the order given."
        },
        {
          "name": "arrowStyle",
          "type": "\"solid\" | \"dashed\"",
          "required": false,
          "defaultValue": "\"solid\"",
          "description": "Arrow style for connections"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "direction",
          "type": "\"horizontal\" | \"vertical\"",
          "required": false,
          "defaultValue": "\"horizontal\"",
          "description": "Orientation of the flow"
        },
        {
          "name": "nodeGap",
          "type": "\"sm\" | \"md\" | \"lg\"",
          "required": false,
          "defaultValue": "\"md\"",
          "description": "Gap between nodes"
        },
        {
          "name": "nodeHeight",
          "type": "number",
          "required": false,
          "defaultValue": "90",
          "description": "Node height in pixels. Defaults to 90, for the same reason."
        },
        {
          "name": "nodeWidth",
          "type": "number",
          "required": false,
          "defaultValue": "220",
          "description": "Node width in pixels. Defaults to 220. It was a hardcoded 120, which on the 1920×1080 canvas a deck actually renders at is a postage stamp."
        }
      ]
    },
    {
      "name": "ProfileCard",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A styled profile card component Displays a profile image, name, title, and associated company icons. Perfect for team introductions and speaker introductions.",
      "examples": [
        "<ProfileCard\n  imageSrc=\"/avatar.jpg\"\n  name=\"John Doe\"\n  title=\"CEO & Founder\"\n  companyIcons={[\"/company1.svg\", \"/company2.svg\"]}\n/>"
      ],
      "props": [
        {
          "name": "imageSrc",
          "type": "string",
          "required": true,
          "description": "Source URL for the profile image"
        },
        {
          "name": "name",
          "type": "string",
          "required": true,
          "description": "Name of the individual"
        },
        {
          "name": "title",
          "type": "string",
          "required": true,
          "description": "Title or role of the individual"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "companyIcons",
          "type": "string[]",
          "required": false,
          "description": "Array of icon URLs to display"
        }
      ]
    },
    {
      "name": "ProgressRing",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/ProgressRing.tsx",
      "description": "Animated circular progress indicator",
      "behaviour": "A square of `size` pixels — both axes — laid out inline. The label\nsits at the centre of the ring rather than under it.",
      "examples": [
        "<ProgressRing value={75} size={120} showValue />"
      ],
      "props": [
        {
          "name": "value",
          "type": "number",
          "required": true,
          "description": "Progress value (0-100)"
        },
        {
          "name": "backgroundColor",
          "type": "string",
          "required": false,
          "defaultValue": "\"var(--slide-muted, rgba(107, 114, 128, 0.2))\"",
          "description": "Background ring color"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Custom center content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "color",
          "type": "string",
          "required": false,
          "defaultValue": "\"var(--slide-primary, #3b82f6)\"",
          "description": "Ring color"
        },
        {
          "name": "delay",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Delay before starting animation in milliseconds"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "1500",
          "description": "Animation duration in milliseconds"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Override slide active state"
        },
        {
          "name": "onComplete",
          "type": "(() => void)",
          "required": false,
          "description": "Callback when animation completes"
        },
        {
          "name": "showValue",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Show percentage text in center"
        },
        {
          "name": "size",
          "type": "number",
          "required": false,
          "defaultValue": "100",
          "description": "Size of the ring in pixels"
        },
        {
          "name": "strokeWidth",
          "type": "number",
          "required": false,
          "defaultValue": "8",
          "description": "Stroke width in pixels"
        }
      ]
    },
    {
      "name": "Quote",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A styled blockquote component",
      "examples": [
        "<Quote\n  author=\"Albert Einstein\"\n  source=\"Interview, 1929\"\n>\n  \"Imagination is more important than knowledge.\"\n</Quote>"
      ],
      "props": [
        {
          "name": "author",
          "type": "string",
          "required": false,
          "description": "Quote author"
        },
        {
          "name": "authorStyle",
          "type": "CSSProperties",
          "required": false,
          "description": "Custom style for the author/figcaption"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "source",
          "type": "string",
          "required": false,
          "description": "Source or reference"
        },
        {
          "name": "variant",
          "type": "\"default\" | \"large\" | \"minimal\"",
          "required": false,
          "defaultValue": "\"default\"",
          "description": "Visual variant"
        }
      ]
    },
    {
      "name": "Reveal",
      "package": "@getnarro/shared-ui",
      "description": "Fragment - Step-by-step reveal component Each Fragment animates in sequence based on its `order` prop. The delay is calculated as: order * staggerDelay When used inside a Slide component from narro, animations will only trigger when the slide becomes active. Note: Import the animations CSS file to use this component: import \"@getnarro/shared-ui/styles/animations.css\";",
      "examples": [
        "<Fragment order={1} effect=\"fade-in\">\n  <Text>This appears first (after 400ms)</Text>\n</Fragment>\n<Fragment order={2} effect=\"slide-up\">\n  <Text>This appears second (after 800ms)</Text>\n</Fragment>"
      ],
      "props": []
    },
    {
      "name": "ScrollableImage",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/ScrollableImage.tsx",
      "description": "Displays a scrollable image Perfect for displaying full-page website screenshots that are too tall to fit in a slide.",
      "examples": [
        "// Basic scrollable image\n<ScrollableImage\n  src=\"/screenshots/long-page.png\"\n  alt=\"Full page screenshot\"\n  maxHeight=\"70vh\"\n/>\n\n// With auto-scroll\n<ScrollableImage\n  src=\"/screenshots/website.png\"\n  alt=\"Website screenshot\"\n  maxHeight=\"70vh\"\n  autoScrollSpeed={50}\n  showIndicators\n/>"
      ],
      "props": [
        {
          "name": "alt",
          "type": "string",
          "required": true,
          "description": "Alt text for accessibility"
        },
        {
          "name": "src",
          "type": "string",
          "required": true,
          "description": "Image source URL or path"
        },
        {
          "name": "autoScrollSpeed",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Auto-scroll speed in pixels per second (0 to disable)"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "maxHeight",
          "type": "string",
          "required": false,
          "defaultValue": "\"70vh\"",
          "description": "Maximum height of the container"
        },
        {
          "name": "showIndicators",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Show scroll indicators"
        },
        {
          "name": "smoothScroll",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Enable smooth scrolling"
        }
      ]
    },
    {
      "name": "Text",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A styled text block component",
      "behaviour": "Renders a `<p>` with no margin, so spacing between blocks is\nyours to set — `className=\"mt-16\"` works. Size and weight are classes, so\n`className` overrides them.",
      "examples": [
        "<Text size=\"lg\" weight=\"medium\">\n  This is styled body text for your slides.\n</Text>"
      ],
      "props": [
        {
          "name": "align",
          "type": "\"center\" | \"left\" | \"right\" | \"justify\"",
          "required": false,
          "defaultValue": "\"left\"",
          "description": "Text alignment"
        },
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "color",
          "type": "\"default\" | \"primary\" | \"muted\" | \"accent\"",
          "required": false,
          "defaultValue": "\"default\"",
          "description": "Color variant"
        },
        {
          "name": "size",
          "type": "\"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\"",
          "required": false,
          "defaultValue": "\"md\"",
          "description": "Text size"
        },
        {
          "name": "weight",
          "type": "\"medium\" | \"normal\" | \"semibold\" | \"bold\"",
          "required": false,
          "defaultValue": "\"normal\"",
          "description": "Font weight"
        }
      ]
    },
    {
      "name": "ThreeColumn",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A three-column layout component",
      "examples": [
        "<ThreeColumn\n  first={<Text>First column</Text>}\n  second={<Text>Second column</Text>}\n  third={<Image src=\"image.jpg\" alt=\"Third column\" />}\n  ratio=\"1:2:1\"\n  gap=\"lg\"\n/>"
      ],
      "props": [
        {
          "name": "first",
          "type": "ReactNode",
          "required": true,
          "description": "First column content"
        },
        {
          "name": "second",
          "type": "ReactNode",
          "required": true,
          "description": "Second column content"
        },
        {
          "name": "third",
          "type": "ReactNode",
          "required": true,
          "description": "Third column content"
        },
        {
          "name": "align",
          "type": "\"center\" | \"start\" | \"end\" | \"stretch\"",
          "required": false,
          "defaultValue": "\"stretch\"",
          "description": "Vertical alignment"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "gap",
          "type": "\"sm\" | \"md\" | \"lg\" | \"xl\"",
          "required": false,
          "defaultValue": "\"md\"",
          "description": "Gap between columns"
        },
        {
          "name": "ratio",
          "type": "\"1:1:1\" | \"2:1:1\" | \"1:2:1\" | \"1:1:2\" | \"2:2:1\" | \"1:2:2\"",
          "required": false,
          "defaultValue": "\"1:1:1\"",
          "description": "Column ratio (e.g., \"1:1:1\", \"2:1:1\", \"1:2:1\")"
        },
        {
          "name": "responsive",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Stack columns on small screens"
        }
      ]
    },
    {
      "name": "TimelineWithIndicators",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A horizontal timeline component Creates a horizontal timeline with circular indicators linked by a line. Includes labels below each indicator. Perfect for historical overviews and progress tracking.",
      "examples": [
        "<TimelineWithIndicators\n  events={[\n    { year: \"2020\", label: \"Founded\" },\n    { year: \"2021\", label: \"Series A\" },\n    { year: \"2022\", label: \"Expansion\" },\n  ]}\n  lineColor=\"#14b8a6\"\n/>"
      ],
      "props": [
        {
          "name": "events",
          "type": "TimelineEvent[]",
          "required": true,
          "description": "Array of event objects with year and label"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "lineColor",
          "type": "string",
          "required": false,
          "defaultValue": "\"#14b8a6\"",
          "description": "Color of the connecting line"
        }
      ]
    },
    {
      "name": "TitleSlide",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A centered title slide layout",
      "examples": [
        "<TitleSlide\n  title=\"Welcome to My Presentation\"\n  subtitle=\"An Overview of Our Progress\"\n  author=\"John Doe\"\n  date=\"January 2025\"\n/>"
      ],
      "props": [
        {
          "name": "title",
          "type": "ReactNode",
          "required": true,
          "description": "Main title"
        },
        {
          "name": "author",
          "type": "ReactNode",
          "required": false,
          "description": "Author or presenter name"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "date",
          "type": "ReactNode",
          "required": false,
          "description": "Date or additional info"
        },
        {
          "name": "subtitle",
          "type": "ReactNode",
          "required": false,
          "description": "Subtitle"
        }
      ]
    },
    {
      "name": "TitleSlideWithElement",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A title slide with a flexible element area",
      "examples": [
        "<TitleSlideWithElement\n  title=\"Product Launch\"\n  subtitle=\"Introducing our newest innovation\"\n  element={<Image src=\"product.png\" alt=\"Product\" />}\n  elementPosition=\"right\"\n  elementAnimation=\"fade-in\"\n/>"
      ],
      "props": [
        {
          "name": "element",
          "type": "ReactNode",
          "required": true,
          "description": "Element to display (image, icon, chart, etc.)"
        },
        {
          "name": "title",
          "type": "ReactNode",
          "required": true,
          "description": "Main title"
        },
        {
          "name": "animationDelay",
          "type": "number",
          "required": false,
          "defaultValue": "300",
          "description": "Animation delay in milliseconds"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "elementAnimation",
          "type": "ElementAnimation",
          "required": false,
          "defaultValue": "\"none\"",
          "description": "Animation preset for the element"
        },
        {
          "name": "elementPosition",
          "type": "ElementPosition",
          "required": false,
          "defaultValue": "\"below\"",
          "description": "Position of the element relative to title/subtitle"
        },
        {
          "name": "subtitle",
          "type": "ReactNode",
          "required": false,
          "description": "Subtitle"
        }
      ]
    },
    {
      "name": "TwoColumn",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A two-column layout component",
      "behaviour": "A CSS grid with `p-8` of its own padding. It sizes to its content\nunless you pass `fill`, which makes it take the parent's full height — under a\nheading, `fill` needs `<SlideContent layout=\"fill\">` above it, or the columns\ntake the whole canvas *plus* the heading and overflow.",
      "examples": [
        "<TwoColumn\n  left={<Text>Left content</Text>}\n  right={<Image src=\"image.jpg\" alt=\"Right image\" />}\n  ratio=\"2:1\"\n/>"
      ],
      "props": [
        {
          "name": "left",
          "type": "ReactNode",
          "required": true,
          "description": "Left column content"
        },
        {
          "name": "right",
          "type": "ReactNode",
          "required": true,
          "description": "Right column content"
        },
        {
          "name": "align",
          "type": "\"center\" | \"start\" | \"end\" | \"stretch\"",
          "required": false,
          "defaultValue": "\"stretch\"",
          "description": "Vertical alignment"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "fill",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Take the full height of the parent. Off by default. It used to be unconditional `height: 100%`, which made the most ordinary slide shape there is — a title with a two-column body — overflow by exactly the height of the title: three slides of one deck overflowed by an identical 43px, which is the signature of a structural bug rather than of anyone's content. Pair it with `<SlideContent layout=\"fill\">` for \"title on top, columns take the rest\": the column box then fills what the heading left, rather than the whole canvas plus the heading."
        },
        {
          "name": "gap",
          "type": "\"sm\" | \"md\" | \"lg\" | \"xl\"",
          "required": false,
          "defaultValue": "\"md\"",
          "description": "Gap between columns"
        },
        {
          "name": "ratio",
          "type": "\"1:1\" | \"2:1\" | \"1:2\" | \"3:2\" | \"2:3\"",
          "required": false,
          "defaultValue": "\"1:1\"",
          "description": "Column ratio"
        }
      ]
    },
    {
      "name": "TwoColumnHighlight",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "Two-column layout with highlighted sections A layout component featuring two columns with different backgrounds, typically used for section headers or emphasizing key points. The left column is typically darker with a narrower width.",
      "examples": [
        "<TwoColumnHighlight\n  leftContent={<Heading level={1}>Section Title</Heading>}\n  rightContent={<Text>Description text goes here</Text>}\n  ratio=\"1:2\"\n/>",
        "// With custom colors\n<TwoColumnHighlight\n  leftContent=\"Key Point\"\n  rightContent=\"Detailed explanation\"\n  leftBg=\"#000000\"\n  rightBg=\"#ffffff\"\n  leftTextColor=\"#ffffff\"\n  rightTextColor=\"#000000\"\n  highlightColor=\"#ff6b35\"\n/>"
      ],
      "props": [
        {
          "name": "leftContent",
          "type": "ReactNode",
          "required": true,
          "description": "Content for the left column"
        },
        {
          "name": "rightContent",
          "type": "ReactNode",
          "required": true,
          "description": "Content for the right column"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "highlight",
          "type": "string",
          "required": false,
          "description": "Text to highlight in the right column"
        },
        {
          "name": "highlightColor",
          "type": "string",
          "required": false,
          "defaultValue": "\"#ff6b35\"",
          "description": "Highlight color for emphasized text"
        },
        {
          "name": "leftBg",
          "type": "string",
          "required": false,
          "defaultValue": "\"#000000\"",
          "description": "Left column background color"
        },
        {
          "name": "leftTextColor",
          "type": "string",
          "required": false,
          "defaultValue": "\"#ffffff\"",
          "description": "Left column text color"
        },
        {
          "name": "ratio",
          "type": "\"1:2\" | \"2:3\" | \"1:3\"",
          "required": false,
          "defaultValue": "\"1:2\"",
          "description": "Column width ratio (left:right)"
        },
        {
          "name": "rightBg",
          "type": "string",
          "required": false,
          "defaultValue": "\"#ffffff\"",
          "description": "Right column background color"
        },
        {
          "name": "rightTextColor",
          "type": "string",
          "required": false,
          "defaultValue": "\"#000000\"",
          "description": "Right column text color"
        }
      ]
    },
    {
      "name": "TypewriterText",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/TypewriterText.tsx",
      "description": "Text that appears character by character",
      "behaviour": "Reserves no space for the text it has not typed yet, so the\nsurrounding layout shifts as it types. Give it a fixed-height parent when that\nmatters. The cursor is `1em` tall and part of the line box.",
      "examples": [
        "<TypewriterText speed=\"medium\" cursor>\n  Hello, World!\n</TypewriterText>"
      ],
      "props": [
        {
          "name": "children",
          "type": "string",
          "required": true,
          "description": "Text content to animate"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "cursor",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Show blinking cursor"
        },
        {
          "name": "delay",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Delay before starting animation in milliseconds"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Override slide active state"
        },
        {
          "name": "onComplete",
          "type": "(() => void)",
          "required": false,
          "description": "Callback when animation completes"
        },
        {
          "name": "speed",
          "type": "number | \"slow\" | \"medium\" | \"fast\"",
          "required": false,
          "defaultValue": "\"medium\"",
          "description": "Speed of typing in milliseconds per character"
        }
      ]
    },
    {
      "name": "Video",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A video embedding component",
      "examples": [
        "<Video\n  src=\"/videos/demo.mp4\"\n  poster=\"/images/poster.jpg\"\n  title=\"Product demo video\"\n  autoPlay\n  loop\n  muted\n/>"
      ],
      "props": [
        {
          "name": "src",
          "type": "string",
          "required": true,
          "description": "Video source URL"
        },
        {
          "name": "autoPlay",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Autoplay video"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "controls",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Show controls"
        },
        {
          "name": "fit",
          "type": "\"cover\" | \"contain\" | \"fill\"",
          "required": false,
          "defaultValue": "\"contain\"",
          "description": "Object fit mode"
        },
        {
          "name": "loop",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Loop video"
        },
        {
          "name": "muted",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Mute video"
        },
        {
          "name": "poster",
          "type": "string",
          "required": false,
          "description": "Poster image"
        },
        {
          "name": "title",
          "type": "string",
          "required": false,
          "description": "Accessible title/description for the video"
        }
      ]
    },
    {
      "name": "WaveLine",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/types/index.ts",
      "description": "A decorative curved dashed line component Creates a smooth, curved dashed line that spans across a slide to add dynamic visual elements. Perfect for title slide decoration and section separators.",
      "examples": [
        "<WaveLine />\n<WaveLine color=\"#00BFA5\" dashWidth={3} />"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": false,
          "description": "Children content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "color",
          "type": "string",
          "required": false,
          "defaultValue": "\"#14b8a6\"",
          "description": "Color of the dashed line"
        },
        {
          "name": "dashWidth",
          "type": "number",
          "required": false,
          "defaultValue": "2",
          "description": "Width of each dash"
        }
      ]
    },
    {
      "name": "WordReveal",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/WordReveal.tsx",
      "description": "Text that reveals word by word Note: Import the animations CSS file to use this component: import \"@getnarro/shared-ui/styles/animations.css\";",
      "examples": [
        "<WordReveal animation=\"blur\" staggerDelay={100}>\n  This text will appear word by word\n</WordReveal>"
      ],
      "props": [
        {
          "name": "children",
          "type": "string",
          "required": true,
          "description": "Text content to animate (will be split by words)"
        },
        {
          "name": "animation",
          "type": "WordRevealAnimation",
          "required": false,
          "defaultValue": "\"fade\"",
          "description": "Animation type"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "delay",
          "type": "number",
          "required": false,
          "defaultValue": "0",
          "description": "Delay before starting animation in milliseconds"
        },
        {
          "name": "duration",
          "type": "number",
          "required": false,
          "defaultValue": "300",
          "description": "Animation duration per word in milliseconds"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Override slide active state"
        },
        {
          "name": "onComplete",
          "type": "(() => void)",
          "required": false,
          "description": "Callback when all words are revealed"
        },
        {
          "name": "staggerDelay",
          "type": "number",
          "required": false,
          "defaultValue": "100",
          "description": "Delay between each word in milliseconds"
        }
      ]
    },
    {
      "name": "Workflow",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/Workflow.tsx",
      "description": "Animated workflow diagram Note: Import the animations CSS file to use this component: import \"@getnarro/shared-ui/styles/animations.css\";",
      "behaviour": "Lays its steps along the axis `direction` chooses, with fixed-height\nconnectors between them. The step circles are a fixed 48px regardless of the\ncanvas.",
      "examples": [
        "<Workflow animation=\"progressive\" direction=\"horizontal\">\n  <WorkflowStep icon=\"1\" title=\"Start\">Begin here</WorkflowStep>\n  <WorkflowStep icon=\"2\" title=\"Process\">Do the work</WorkflowStep>\n  <WorkflowStep icon=\"3\" title=\"Complete\">All done!</WorkflowStep>\n</Workflow>"
      ],
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "WorkflowStep children"
        },
        {
          "name": "animation",
          "type": "WorkflowAnimation",
          "required": false,
          "defaultValue": "\"progressive\"",
          "description": "Animation type"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "connectorColor",
          "type": "string",
          "required": false,
          "defaultValue": "\"var(--slide-muted, rgba(107, 114, 128, 0.4))\"",
          "description": "Connector line color"
        },
        {
          "name": "direction",
          "type": "WorkflowDirection",
          "required": false,
          "defaultValue": "\"horizontal\"",
          "description": "Layout direction"
        },
        {
          "name": "highlightActive",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Highlight the currently active step"
        },
        {
          "name": "isActive",
          "type": "boolean",
          "required": false,
          "description": "Override slide active state"
        },
        {
          "name": "showConnectors",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Show connecting lines/arrows between steps"
        },
        {
          "name": "staggerDelay",
          "type": "number",
          "required": false,
          "defaultValue": "500",
          "description": "Delay between each step in milliseconds"
        }
      ]
    },
    {
      "name": "WorkflowStep",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/Workflow.tsx",
      "description": "Individual step in a workflow",
      "behaviour": "One step of a `Workflow`, with a fixed 48px marker. Used on its own it\nstill renders the marker and its own layout, but no connectors.",
      "props": [
        {
          "name": "children",
          "type": "ReactNode",
          "required": true,
          "description": "Step content"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "description",
          "type": "string",
          "required": false,
          "description": "Step description"
        },
        {
          "name": "icon",
          "type": "ReactNode",
          "required": false,
          "description": "Icon or number to display"
        },
        {
          "name": "title",
          "type": "string",
          "required": false,
          "description": "Step title"
        }
      ]
    },
    {
      "name": "ZoomImage",
      "package": "@getnarro/shared-ui",
      "source": "packages/shared-ui/src/components/ZoomImage.tsx",
      "description": "Image with click-to-zoom functionality",
      "behaviour": "Takes its `height` when given one and its natural size otherwise, so a\nzoom inside a fixed-height parent needs an explicit height or it will grow the\nparent.",
      "examples": [
        "<ZoomImage\n  src=\"/diagram.png\"\n  alt=\"Architecture diagram\"\n  zoomable\n  zoomScale={2}\n/>"
      ],
      "props": [
        {
          "name": "alt",
          "type": "string",
          "required": true,
          "description": "Alt text for accessibility"
        },
        {
          "name": "src",
          "type": "string",
          "required": true,
          "description": "Image source URL"
        },
        {
          "name": "className",
          "type": "string",
          "required": false,
          "description": "Additional CSS classes"
        },
        {
          "name": "fit",
          "type": "\"none\" | \"cover\" | \"contain\" | \"fill\"",
          "required": false,
          "defaultValue": "\"contain\"",
          "description": "Object fit mode"
        },
        {
          "name": "height",
          "type": "string | number",
          "required": false,
          "description": "Height constraint"
        },
        {
          "name": "rounded",
          "type": "\"none\" | \"sm\" | \"md\" | \"lg\" | \"full\"",
          "required": false,
          "defaultValue": "\"none\"",
          "description": "Border radius"
        },
        {
          "name": "shadow",
          "type": "boolean",
          "required": false,
          "defaultValue": "false",
          "description": "Add shadow"
        },
        {
          "name": "width",
          "type": "string | number",
          "required": false,
          "description": "Width constraint"
        },
        {
          "name": "zoomable",
          "type": "boolean",
          "required": false,
          "defaultValue": "true",
          "description": "Enable click-to-zoom"
        },
        {
          "name": "zoomScale",
          "type": "number",
          "required": false,
          "defaultValue": "2",
          "description": "Zoom scale factor"
        }
      ]
    }
  ]
}
