{
  "name": "loomui",
  "homepage": "https://loomui.design",
  "items": [
    {
      "name": "weave-text",
      "type": "registry:ui",
      "title": "Weave Text",
      "description": "Text filled with a slow-drifting gradient, woven from a palette you control.",
      "registryDependencies": [
        "utils",
        "use-in-viewport"
      ],
      "files": [
        {
          "path": "registry/loomui/weave-text.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "animate-weave": "weave 8s linear infinite"
        }
      },
      "css": {
        "@keyframes weave": {
          "from": {
            "background-position": "0% 50%"
          },
          "to": {
            "background-position": "200% 50%"
          }
        }
      }
    },
    {
      "name": "stagger-text",
      "type": "registry:ui",
      "title": "Stagger Text",
      "description": "Words or characters that rise into place one after another, on mount or on scroll.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/stagger-text.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)",
          "animate-stagger-reveal": "stagger-reveal 500ms var(--ease-out-quart) both"
        }
      },
      "css": {
        "@keyframes stagger-reveal": {
          "from": {
            "opacity": "0",
            "transform": "translateY(0.4em)"
          },
          "to": {
            "opacity": "1",
            "transform": "translateY(0)"
          }
        }
      }
    },
    {
      "name": "typewriter",
      "type": "registry:ui",
      "title": "Typewriter",
      "description": "Phrases typed out and deleted in a loop, with a caret and no layout shift.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/typewriter.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "animate-caret-blink": "caret-blink 1.1s steps(2, jump-none) infinite"
        }
      },
      "css": {
        "@keyframes caret-blink": {
          "0%, 100%": {
            "opacity": "1"
          },
          "50%": {
            "opacity": "0"
          }
        }
      }
    },
    {
      "name": "scramble-text",
      "type": "registry:ui",
      "title": "Scramble Text",
      "description": "A string that resolves out of random glyphs, left to right, on mount, on scroll, or on hover.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/scramble-text.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "name": "count-up",
      "type": "registry:ui",
      "title": "Count Up",
      "description": "A number that counts to its value when it scrolls into view, without a render per frame.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/count-up.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "name": "lens-text",
      "type": "registry:ui",
      "title": "Lens Text",
      "description": "Text held out of focus until the pointer passes over it like a magnifying glass.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/lens-text.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "name": "split-flap",
      "type": "registry:ui",
      "title": "Split Flap",
      "description": "A departure board that flaps through its glyphs, one cell behind the last, until it lands on the value.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/split-flap.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "animate-split-flap-out": "split-flap-out calc(var(--flap-duration, 62ms) * 0.5) ease-in both",
          "animate-split-flap-in": "split-flap-in calc(var(--flap-duration, 62ms) * 0.5) ease-out calc(var(--flap-duration, 62ms) * 0.5) both"
        }
      },
      "css": {
        "@keyframes split-flap-out": {
          "from": {
            "transform": "rotateX(0deg)"
          },
          "to": {
            "transform": "rotateX(-90deg)"
          }
        },
        "@keyframes split-flap-in": {
          "from": {
            "transform": "rotateX(90deg)"
          },
          "to": {
            "transform": "rotateX(0deg)"
          }
        }
      }
    },
    {
      "name": "grid-backdrop",
      "type": "registry:ui",
      "title": "Grid Backdrop",
      "description": "An SVG grid with cells that fade in and out at a deterministic, seeded scatter.",
      "registryDependencies": [
        "utils",
        "use-in-viewport"
      ],
      "files": [
        {
          "path": "registry/loomui/grid-backdrop.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-in-out-cubic": "cubic-bezier(0.645, 0.045, 0.355, 1)",
          "animate-grid-pulse": "grid-pulse 5s var(--ease-in-out-cubic) infinite"
        }
      },
      "css": {
        "@keyframes grid-pulse": {
          "0%, 100%": {
            "opacity": "0"
          },
          "50%": {
            "opacity": "1"
          }
        }
      }
    },
    {
      "name": "spotlight-card",
      "type": "registry:ui",
      "title": "Spotlight Card",
      "description": "A surface with a soft highlight that follows the pointer and fades out on leave.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/spotlight-card.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "light-curtain",
      "type": "registry:ui",
      "title": "Light Curtain",
      "description": "An aurora hanging from the top edge, broad bands of colour leaning across each other and falling away down the page.",
      "registryDependencies": [
        "utils",
        "use-in-viewport"
      ],
      "files": [
        {
          "path": "registry/loomui/light-curtain.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "animate-light-curtain": "light-curtain 16s ease-in-out infinite"
        }
      },
      "css": {
        "@keyframes light-curtain": {
          "0%, 100%": {
            "translate": "calc(var(--curtain-drift) * -1) 0",
            "scale": "var(--curtain-narrow) 1",
            "opacity": "var(--curtain-low)"
          },
          "50%": {
            "translate": "var(--curtain-drift) 0",
            "scale": "var(--curtain-wide) 1",
            "opacity": "var(--curtain-high)"
          }
        }
      }
    },
    {
      "name": "grid-beams",
      "type": "registry:ui",
      "title": "Grid Beams",
      "description": "A ruled grid with neon beams running down random lines, fading out toward the edges.",
      "registryDependencies": [
        "utils",
        "use-in-viewport"
      ],
      "files": [
        {
          "path": "registry/loomui/grid-beams.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "animate-grid-beam": "grid-beam 4s linear infinite",
          "animate-grid-beam-x": "grid-beam-x 4s linear infinite"
        }
      },
      "css": {
        "@keyframes grid-beam": {
          "from": {
            "transform": "translateY(calc(-1 * var(--beam-length, 24%)))"
          },
          "to": {
            "transform": "translateY(100%)"
          }
        },
        "@keyframes grid-beam-x": {
          "from": {
            "transform": "translateX(calc(-1 * var(--beam-length, 24%)))"
          },
          "to": {
            "transform": "translateX(100%)"
          }
        }
      }
    },
    {
      "name": "aurora-backdrop",
      "type": "registry:ui",
      "title": "Aurora Backdrop",
      "description": "A wash of blurred colour that drifts behind content on cycles that never line up.",
      "registryDependencies": [
        "utils",
        "use-in-viewport"
      ],
      "files": [
        {
          "path": "registry/loomui/aurora-backdrop.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-in-out-cubic": "cubic-bezier(0.645, 0.045, 0.355, 1)",
          "animate-aurora-drift": "aurora-drift 18s var(--ease-in-out-cubic) infinite"
        }
      },
      "css": {
        "@keyframes aurora-drift": {
          "0%, 100%": {
            "transform": "translate(0%, 0%) scale(1)"
          },
          "33%": {
            "transform": "translate(26%, -22%) scale(1.35)"
          },
          "66%": {
            "transform": "translate(-24%, 18%) scale(0.75)"
          }
        }
      }
    },
    {
      "name": "stitch-path",
      "type": "registry:ui",
      "title": "Stitch Path",
      "description": "A running stitch sewn along an SVG path as the page scrolls, following the holes it is laid over.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/stitch-path.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "name": "tilt-card",
      "type": "registry:ui",
      "title": "Tilt Card",
      "description": "A surface that leans away from the pointer in 3D and settles back on leave.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/tilt-card.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "flip-card",
      "type": "registry:ui",
      "title": "Flip Card",
      "description": "A card with two faces that turns in 3D when it is clicked, controlled or on its own.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/flip-card.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-back-out": "cubic-bezier(0.34, 1.32, 0.52, 1)"
        }
      }
    },
    {
      "name": "hold-button",
      "type": "registry:ui",
      "title": "Hold Button",
      "description": "A button that fires only after a deliberate press and hold, with a fill sweeping across to count out the wait.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/hold-button.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "ripple-button",
      "type": "registry:ui",
      "title": "Ripple Button",
      "description": "A button that sends a circle out from wherever it was pressed, sized to reach the furthest corner.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/ripple-button.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)",
          "animate-ripple-expand": "ripple-expand var(--ripple-duration, 280ms) var(--ease-out-quart) forwards"
        }
      },
      "css": {
        "@keyframes ripple-expand": {
          "from": {
            "transform": "scale(0)",
            "opacity": "1"
          },
          "to": {
            "transform": "scale(1)",
            "opacity": "0"
          }
        }
      }
    },
    {
      "name": "confetti-button",
      "type": "registry:ui",
      "title": "Confetti Button",
      "description": "A button that throws a handful of paper into the air on press, each piece lobbed on its own arc.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/confetti-button.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "animate-confetti-drift": "confetti-drift var(--confetti-duration, 900ms) linear forwards",
          "animate-confetti-fall": "confetti-fall var(--confetti-duration, 900ms) forwards"
        }
      },
      "css": {
        "@keyframes confetti-drift": {
          "0%": {
            "transform": "translateX(0)",
            "opacity": "1"
          },
          "70%": {
            "opacity": "1"
          },
          "100%": {
            "transform": "translateX(var(--drift, 0px))",
            "opacity": "0"
          }
        },
        "@keyframes confetti-fall": {
          "0%": {
            "transform": "translateY(0) rotate(0deg)",
            "animation-timing-function": "cubic-bezier(0.165, 0.84, 0.44, 1)"
          },
          "32%": {
            "transform": "translateY(var(--rise, 0px)) rotate(calc(var(--spin, 0deg) * 0.3))",
            "animation-timing-function": "cubic-bezier(0.55, 0.06, 0.68, 0.19)"
          },
          "100%": {
            "transform": "translateY(var(--fall, 0px)) rotate(var(--spin, 0deg))"
          }
        }
      }
    },
    {
      "name": "elastic-tabs",
      "type": "registry:ui",
      "title": "Elastic Tabs",
      "description": "A tab group whose pill stretches to cover both tabs before it contracts onto the one you picked.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/elastic-tabs.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "ticket-stub",
      "type": "registry:ui",
      "title": "Ticket Stub",
      "description": "A card torn along a perforation, with a notch bitten out of the paper at each end of it.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/ticket-stub.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "compare-slider",
      "type": "registry:ui",
      "title": "Compare Slider",
      "description": "Two versions of the same frame, split by a divider you drag, or move with the arrow keys.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/compare-slider.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "sticker-peel",
      "type": "registry:ui",
      "title": "Sticker Peel",
      "description": "A card whose corner lifts off the page on hover, folded back over the crease to show its backing.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/sticker-peel.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "magnetic",
      "type": "registry:ui",
      "title": "Magnetic",
      "description": "A wrapper that pulls its child toward the pointer as the pointer gets close.",
      "dependencies": [
        "@radix-ui/react-slot"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/magnetic.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "marquee",
      "type": "registry:ui",
      "title": "Marquee",
      "description": "A seamless scrolling row or column, in either direction, that pauses on hover.",
      "registryDependencies": [
        "utils",
        "use-in-viewport"
      ],
      "files": [
        {
          "path": "registry/loomui/marquee.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "animate-marquee": "marquee var(--marquee-duration, 40s) linear infinite",
          "animate-marquee-vertical": "marquee-vertical var(--marquee-duration, 40s) linear infinite"
        }
      },
      "css": {
        "@keyframes marquee": {
          "from": {
            "transform": "translateX(0)"
          },
          "to": {
            "transform": "translateX(calc(-100% - var(--marquee-gap, 1rem)))"
          }
        },
        "@keyframes marquee-vertical": {
          "from": {
            "transform": "translateY(0)"
          },
          "to": {
            "transform": "translateY(calc(-100% - var(--marquee-gap, 1rem)))"
          }
        }
      }
    },
    {
      "name": "reading-progress",
      "type": "registry:ui",
      "title": "Reading Progress",
      "description": "A pinned bar that tracks how far through the page, or a chosen element, the reader is.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/reading-progress.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "name": "testimonial-wall",
      "type": "registry:ui",
      "title": "Testimonial Wall",
      "description": "Columns of quotes drifting past each other at different speeds, faded at both ends.",
      "registryDependencies": [
        "utils",
        "use-in-viewport"
      ],
      "files": [
        {
          "path": "registry/loomui/testimonial-wall.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "animate-marquee-vertical": "marquee-vertical var(--marquee-duration, 40s) linear infinite"
        }
      },
      "css": {
        "@keyframes marquee-vertical": {
          "from": {
            "transform": "translateY(0)"
          },
          "to": {
            "transform": "translateY(calc(-100% - var(--marquee-gap, 1rem)))"
          }
        }
      }
    },
    {
      "name": "logo-loom",
      "type": "registry:ui",
      "title": "Logo Loom",
      "description": "A logo row woven into place, every other mark arriving from the other side of the thread.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/logo-loom.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)",
          "animate-loom-weave": "loom-weave 700ms var(--ease-out-quart) both"
        }
      },
      "css": {
        "@keyframes loom-weave": {
          "from": {
            "opacity": "0",
            "transform": "translateY(var(--loom-from, 1.5rem))"
          },
          "to": {
            "opacity": "1",
            "transform": "translateY(0)"
          }
        }
      }
    },
    {
      "name": "iphone",
      "type": "registry:ui",
      "title": "iPhone",
      "description": "A device frame drawn from the real measurements, with a screen you put anything in.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/iphone.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "name": "ipad",
      "type": "registry:ui",
      "title": "iPad",
      "description": "A tablet frame drawn from the real measurements, upright or on its side, with a screen you put anything in.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/ipad.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "name": "macbook",
      "type": "registry:ui",
      "title": "MacBook",
      "description": "A laptop frame with the camera housing cut into the display and the scoop cut into its base.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/macbook.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "name": "thread-timeline",
      "type": "registry:ui",
      "title": "Thread Timeline",
      "description": "A timeline whose thread is sewn down the page as you read, lighting each node as it reaches it.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/thread-timeline.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "loom-loader",
      "type": "registry:ui",
      "title": "Loom Loader",
      "description": "Threads drawn through a frame and pulled off the far side, with a shuttle crossing them.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/loom-loader.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-in-out-cubic": "cubic-bezier(0.645, 0.045, 0.355, 1)",
          "animate-loom-thread": "loom-thread var(--loom-duration, 1400ms) ease-in-out infinite",
          "animate-loom-shuttle": "loom-shuttle var(--loom-duration, 1400ms) var(--ease-in-out-cubic) infinite alternate"
        }
      },
      "css": {
        "@keyframes loom-thread": {
          "0%": {
            "stroke-dashoffset": "1"
          },
          "40%, 60%": {
            "stroke-dashoffset": "0"
          },
          "100%": {
            "stroke-dashoffset": "-1"
          }
        },
        "@keyframes loom-shuttle": {
          "from": {
            "transform": "translateX(0)"
          },
          "to": {
            "transform": "translateX(var(--loom-sweep, 30px))"
          }
        }
      }
    },
    {
      "name": "loom-slider",
      "type": "registry:ui",
      "title": "Loom Slider",
      "description": "A row of dashes where the one you are holding stands tallest, with the rise travelling the track as you drag.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/loom-slider.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "name": "progress-ring",
      "type": "registry:ui",
      "title": "Progress Ring",
      "description": "A circular progress ring whose value springs to its target, so a number that changes mid travel keeps the speed it already had.",
      "registryDependencies": [
        "utils",
        "use-spring"
      ],
      "files": [
        {
          "path": "registry/loomui/progress-ring.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "name": "spool",
      "type": "registry:ui",
      "title": "Spool",
      "description": "A container that changes shape to fit whatever it is showing, on a spring that carries its velocity through an interruption.",
      "registryDependencies": [
        "utils",
        "use-spring"
      ],
      "files": [
        {
          "path": "registry/loomui/spool.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)",
          "animate-spool-leave": "spool-leave 140ms var(--ease-out-quart) forwards"
        }
      },
      "css": {
        "@keyframes spool-leave": {
          "to": {
            "opacity": "0",
            "filter": "blur(4px)"
          }
        }
      }
    },
    {
      "name": "icon-morph",
      "type": "registry:ui",
      "title": "Icon Morph",
      "description": "One icon that turns into another by moving its own pieces, so there is never a frame with both glyphs on screen.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/icon-morph.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "photo-stamp",
      "type": "registry:ui",
      "title": "Photo Stamp",
      "description": "A photo that lifts off the page at full size over a blurred backdrop, the same element the whole way.",
      "registryDependencies": [
        "utils",
        "use-spring"
      ],
      "files": [
        {
          "path": "registry/loomui/photo-stamp.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)",
          "animate-photo-stamp-veil-in": "photo-stamp-veil-in 240ms var(--ease-out-quart)",
          "animate-photo-stamp-veil-out": "photo-stamp-veil-out 300ms var(--ease-out-quart) forwards",
          "animate-photo-stamp-caption-in": "photo-stamp-caption-in 240ms var(--ease-out-quart) 160ms backwards"
        }
      },
      "css": {
        "@keyframes photo-stamp-veil-in": {
          "from": {
            "opacity": "0"
          }
        },
        "@keyframes photo-stamp-veil-out": {
          "to": {
            "opacity": "0"
          }
        },
        "@keyframes photo-stamp-caption-in": {
          "from": {
            "opacity": "0",
            "translate": "0 6px"
          }
        }
      }
    },
    {
      "name": "trend-stack",
      "type": "registry:ui",
      "title": "Trend Stack",
      "description": "Stacked series under a line each, revealed left to right, with the headline and the legend following the pointer.",
      "registryDependencies": [
        "utils",
        "chart-frame"
      ],
      "files": [
        {
          "path": "registry/loomui/trend-stack.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "gauge-arc",
      "type": "registry:ui",
      "title": "Gauge Arc",
      "description": "Half a ring divided into segments, drawn one after another, with the share of whichever one is in focus in the middle.",
      "registryDependencies": [
        "utils",
        "chart-frame"
      ],
      "files": [
        {
          "path": "registry/loomui/gauge-arc.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "funnel-rows",
      "type": "registry:ui",
      "title": "Funnel Rows",
      "description": "A funnel as a row per stage, each bar scaled to its share of the first, growing one after another.",
      "registryDependencies": [
        "utils",
        "chart-frame"
      ],
      "files": [
        {
          "path": "registry/loomui/funnel-rows.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "drawer",
      "type": "registry:ui",
      "title": "Drawer",
      "description": "A panel that comes in from any edge and covers most of the screen, dragged anywhere on its face to send it back out.",
      "dependencies": [
        "@radix-ui/react-dialog"
      ],
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/drawer.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-drawer": "cubic-bezier(0.32, 0.72, 0, 1)",
          "animate-drawer-in": "drawer-in 260ms var(--ease-drawer)",
          "animate-drawer-out": "drawer-out 200ms var(--ease-drawer) forwards",
          "animate-drawer-rise": "drawer-content-rise 200ms var(--ease-drawer) 60ms both",
          "animate-drawer-overlay-in": "drawer-overlay-in 260ms var(--ease-drawer)",
          "animate-drawer-overlay-out": "drawer-overlay-out 200ms var(--ease-drawer) forwards"
        }
      },
      "css": {
        "@keyframes drawer-in": {
          "from": {
            "translate": "var(--drawer-closed)"
          }
        },
        "@keyframes drawer-out": {
          "to": {
            "translate": "var(--drawer-closed)"
          }
        },
        "@keyframes drawer-overlay-in": {
          "from": {
            "opacity": "0"
          },
          "to": {
            "opacity": "1"
          }
        },
        "@keyframes drawer-overlay-out": {
          "to": {
            "opacity": "0"
          }
        },
        "@keyframes drawer-content-rise": {
          "from": {
            "opacity": "0",
            "translate": "var(--drawer-rise)"
          },
          "60%": {
            "opacity": "1"
          },
          "to": {
            "opacity": "1",
            "translate": "0 0"
          }
        },
        "[data-slot=\"drawer-content\"]::after": {
          "content": "\"\"",
          "position": "absolute",
          "background": "inherit"
        },
        "[data-slot=\"drawer-content\"][data-side=\"bottom\"]::after": {
          "top": "100%",
          "right": "0",
          "left": "0",
          "height": "200%"
        },
        "[data-slot=\"drawer-content\"][data-side=\"top\"]::after": {
          "bottom": "100%",
          "right": "0",
          "left": "0",
          "height": "200%"
        },
        "[data-slot=\"drawer-content\"][data-side=\"left\"]::after": {
          "top": "0",
          "right": "100%",
          "bottom": "0",
          "width": "200%"
        },
        "[data-slot=\"drawer-content\"][data-side=\"right\"]::after": {
          "top": "0",
          "bottom": "0",
          "left": "100%",
          "width": "200%"
        }
      }
    },
    {
      "name": "shimmer-skeleton",
      "type": "registry:ui",
      "title": "Shimmer Skeleton",
      "description": "A placeholder block with a shimmer that passes across it while the real thing loads.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/shimmer-skeleton.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "animate-skeleton-shimmer": "skeleton-shimmer var(--shimmer-duration, 1600ms) linear var(--shimmer-delay, 0ms) infinite"
        }
      },
      "css": {
        "@keyframes skeleton-shimmer": {
          "from": {
            "transform": "translateX(-100%)"
          },
          "to": {
            "transform": "translateX(100%)"
          }
        }
      }
    },
    {
      "name": "card-stack",
      "type": "registry:ui",
      "title": "Card Stack",
      "description": "Cards that pin one behind another as the page scrolls, each settling behind the next.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/card-stack.tsx",
          "type": "registry:ui"
        }
      ]
    },
    {
      "name": "image-trail",
      "type": "registry:ui",
      "title": "Image Trail",
      "description": "Images dropped along the pointer's path, spaced by distance travelled rather than by time.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/image-trail.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)",
          "animate-trail-fade": "trail-fade var(--trail-duration, 900ms) var(--ease-out-quart) forwards"
        }
      },
      "css": {
        "@keyframes trail-fade": {
          "0%": {
            "opacity": "0",
            "transform": "scale(0.7) rotate(0deg)"
          },
          "14%": {
            "opacity": "1",
            "transform": "scale(1) rotate(var(--trail-tilt, 0deg))"
          },
          "70%": {
            "opacity": "1"
          },
          "100%": {
            "opacity": "0",
            "transform": "scale(0.86) rotate(var(--trail-tilt, 0deg))"
          }
        }
      }
    },
    {
      "name": "bento-grid",
      "type": "registry:ui",
      "title": "Bento Grid",
      "description": "A grid of tiles of different sizes that arrive one after another when the grid is reached.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/bento-grid.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)",
          "animate-bento-rise": "bento-rise 360ms var(--ease-out-quart) var(--bento-delay, 0ms) both"
        }
      },
      "css": {
        "@keyframes bento-rise": {
          "from": {
            "opacity": "0",
            "transform": "translateY(14px) scale(0.98)"
          },
          "to": {
            "opacity": "1",
            "transform": "translateY(0) scale(1)"
          }
        }
      }
    },
    {
      "name": "terminal",
      "type": "registry:ui",
      "title": "Terminal",
      "description": "A window that types its commands out and prints their output a beat later.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/terminal.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)",
          "animate-caret-blink": "caret-blink 1.1s steps(2, jump-none) infinite",
          "animate-terminal-print": "terminal-print 240ms var(--ease-out-quart) both"
        }
      },
      "css": {
        "@keyframes caret-blink": {
          "0%, 100%": {
            "opacity": "1"
          },
          "50%": {
            "opacity": "0"
          }
        },
        "@keyframes terminal-print": {
          "from": {
            "opacity": "0",
            "transform": "translateY(3px)"
          },
          "to": {
            "opacity": "1",
            "transform": "translateY(0)"
          }
        }
      }
    },
    {
      "name": "unfold-list",
      "type": "registry:ui",
      "title": "Unfold List",
      "description": "A disclosure list whose panels turn down onto the page from their top edge.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/loomui/unfold-list.tsx",
          "type": "registry:ui"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)"
        }
      }
    },
    {
      "name": "weave-text-demo",
      "type": "registry:example",
      "title": "Weave Text Demo",
      "description": "Weave Text used as a headline accent.",
      "registryDependencies": [
        "@loomui/weave-text"
      ],
      "files": [
        {
          "path": "registry/example/weave-text-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "stagger-text-demo",
      "type": "registry:example",
      "title": "Stagger Text Demo",
      "description": "A sentence revealed word by word when it scrolls into view.",
      "registryDependencies": [
        "@loomui/stagger-text"
      ],
      "files": [
        {
          "path": "registry/example/stagger-text-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "typewriter-demo",
      "type": "registry:example",
      "title": "Typewriter Demo",
      "description": "A rotating list of phrases typed into a fixed-width slot.",
      "registryDependencies": [
        "@loomui/typewriter"
      ],
      "files": [
        {
          "path": "registry/example/typewriter-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "scramble-text-demo",
      "type": "registry:example",
      "title": "Scramble Text Demo",
      "description": "A wordmark decoding out of noise on every hover.",
      "registryDependencies": [
        "@loomui/scramble-text"
      ],
      "files": [
        {
          "path": "registry/example/scramble-text-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "count-up-demo",
      "type": "registry:example",
      "title": "Count Up Demo",
      "description": "Three statistics counting to their values in step.",
      "registryDependencies": [
        "@loomui/count-up"
      ],
      "files": [
        {
          "path": "registry/example/count-up-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "lens-text-demo",
      "type": "registry:example",
      "title": "Lens Text Demo",
      "description": "A blurred headline pulled into focus under the pointer.",
      "registryDependencies": [
        "@loomui/lens-text"
      ],
      "files": [
        {
          "path": "registry/example/lens-text-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "split-flap-demo",
      "type": "registry:example",
      "title": "Split Flap Demo",
      "description": "A departure board cycling through four destinations.",
      "registryDependencies": [
        "@loomui/split-flap"
      ],
      "files": [
        {
          "path": "registry/example/split-flap-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "grid-backdrop-demo",
      "type": "registry:example",
      "title": "Grid Backdrop Demo",
      "description": "A grid pulsing behind a headline.",
      "registryDependencies": [
        "@loomui/grid-backdrop"
      ],
      "files": [
        {
          "path": "registry/example/grid-backdrop-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "spotlight-card-demo",
      "type": "registry:example",
      "title": "Spotlight Card Demo",
      "description": "Two cards lit by the pointer as it crosses them.",
      "registryDependencies": [
        "@loomui/spotlight-card"
      ],
      "files": [
        {
          "path": "registry/example/spotlight-card-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "light-curtain-demo",
      "type": "registry:example",
      "title": "Light Curtain Demo",
      "description": "An aurora hanging from the top of a panel, leaning across itself.",
      "registryDependencies": [
        "@loomui/light-curtain"
      ],
      "files": [
        {
          "path": "registry/example/light-curtain-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "grid-beams-demo",
      "type": "registry:example",
      "title": "Grid Beams Demo",
      "description": "Neon beams running down a ruled grid behind a panel of copy.",
      "registryDependencies": [
        "@loomui/grid-beams"
      ],
      "files": [
        {
          "path": "registry/example/grid-beams-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "aurora-backdrop-demo",
      "type": "registry:example",
      "title": "Aurora Backdrop Demo",
      "description": "A drifting colour wash behind a panel of copy.",
      "registryDependencies": [
        "@loomui/aurora-backdrop"
      ],
      "files": [
        {
          "path": "registry/example/aurora-backdrop-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "stitch-path-demo",
      "type": "registry:example",
      "title": "Stitch Path Demo",
      "description": "A seam sewn between two lines of copy as the page scrolls.",
      "registryDependencies": [
        "@loomui/stitch-path"
      ],
      "files": [
        {
          "path": "registry/example/stitch-path-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "tilt-card-demo",
      "type": "registry:example",
      "title": "Tilt Card Demo",
      "description": "A card that leans away from the pointer with a soft sheen.",
      "registryDependencies": [
        "@loomui/tilt-card"
      ],
      "files": [
        {
          "path": "registry/example/tilt-card-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "flip-card-demo",
      "type": "registry:example",
      "title": "Flip Card Demo",
      "description": "A two-by-two matching game played by turning cards over.",
      "registryDependencies": [
        "@loomui/flip-card"
      ],
      "files": [
        {
          "path": "registry/example/flip-card-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "hold-button-demo",
      "type": "registry:example",
      "title": "Hold Button Demo",
      "description": "A destructive action that only goes through if you keep holding.",
      "registryDependencies": [
        "@loomui/hold-button"
      ],
      "files": [
        {
          "path": "registry/example/hold-button-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "ripple-button-demo",
      "type": "registry:example",
      "title": "Ripple Button Demo",
      "description": "Three buttons, each pressed anywhere on its face.",
      "registryDependencies": [
        "@loomui/ripple-button"
      ],
      "files": [
        {
          "path": "registry/example/ripple-button-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "confetti-button-demo",
      "type": "registry:example",
      "title": "Confetti Button Demo",
      "description": "The same throw at three different sizes.",
      "registryDependencies": [
        "@loomui/confetti-button"
      ],
      "files": [
        {
          "path": "registry/example/confetti-button-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "elastic-tabs-demo",
      "type": "registry:example",
      "title": "Elastic Tabs Demo",
      "description": "Four categories with a pill that stretches between them.",
      "registryDependencies": [
        "@loomui/elastic-tabs"
      ],
      "files": [
        {
          "path": "registry/example/elastic-tabs-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "ticket-stub-demo",
      "type": "registry:example",
      "title": "Ticket Stub Demo",
      "description": "A boarding pass torn along its perforation.",
      "registryDependencies": [
        "@loomui/ticket-stub"
      ],
      "files": [
        {
          "path": "registry/example/ticket-stub-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "compare-slider-demo",
      "type": "registry:example",
      "title": "Compare Slider Demo",
      "description": "A draft and a shipped page split by a divider you drag.",
      "registryDependencies": [
        "@loomui/compare-slider"
      ],
      "files": [
        {
          "path": "registry/example/compare-slider-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "sticker-peel-demo",
      "type": "registry:example",
      "title": "Sticker Peel Demo",
      "description": "Three stickers whose corners lift as the pointer crosses them.",
      "registryDependencies": [
        "@loomui/sticker-peel"
      ],
      "files": [
        {
          "path": "registry/example/sticker-peel-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "magnetic-demo",
      "type": "registry:example",
      "title": "Magnetic Demo",
      "description": "A button that leans toward the pointer.",
      "registryDependencies": [
        "@loomui/magnetic"
      ],
      "files": [
        {
          "path": "registry/example/magnetic-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "marquee-demo",
      "type": "registry:example",
      "title": "Marquee Demo",
      "description": "A row of quote cards scrolling on a seamless loop.",
      "registryDependencies": [
        "@loomui/marquee"
      ],
      "files": [
        {
          "path": "registry/example/marquee-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "reading-progress-demo",
      "type": "registry:example",
      "title": "Reading Progress Demo",
      "description": "The page-level progress bar, live at the top of the screen.",
      "registryDependencies": [
        "@loomui/reading-progress"
      ],
      "files": [
        {
          "path": "registry/example/reading-progress-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "testimonial-wall-demo",
      "type": "registry:example",
      "title": "Testimonial Wall Demo",
      "description": "Nine quotes dealt across three columns going opposite ways.",
      "registryDependencies": [
        "@loomui/testimonial-wall"
      ],
      "files": [
        {
          "path": "registry/example/testimonial-wall-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "logo-loom-demo",
      "type": "registry:example",
      "title": "Logo Loom Demo",
      "description": "Five wordmarks woven onto a thread as the row comes into view.",
      "registryDependencies": [
        "@loomui/logo-loom"
      ],
      "files": [
        {
          "path": "registry/example/logo-loom-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "iphone-demo",
      "type": "registry:example",
      "title": "iPhone Demo",
      "description": "A device frame with a screen built out of live markup.",
      "registryDependencies": [
        "@loomui/iphone"
      ],
      "files": [
        {
          "path": "registry/example/iphone-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "ipad-demo",
      "type": "registry:example",
      "title": "iPad Demo",
      "description": "A blank tablet held upright.",
      "registryDependencies": [
        "@loomui/ipad"
      ],
      "files": [
        {
          "path": "registry/example/ipad-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "macbook-demo",
      "type": "registry:example",
      "title": "MacBook Demo",
      "description": "A blank laptop standing on its base.",
      "registryDependencies": [
        "@loomui/macbook"
      ],
      "files": [
        {
          "path": "registry/example/macbook-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "thread-timeline-demo",
      "type": "registry:example",
      "title": "Thread Timeline Demo",
      "description": "Four entries sewn together as the page scrolls past them.",
      "registryDependencies": [
        "@loomui/thread-timeline"
      ],
      "files": [
        {
          "path": "registry/example/thread-timeline-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "loom-loader-demo",
      "type": "registry:example",
      "title": "Loom Loader Demo",
      "description": "The loader at three sizes, with a wider frame on the last.",
      "registryDependencies": [
        "@loomui/loom-loader"
      ],
      "files": [
        {
          "path": "registry/example/loom-loader-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "loom-slider-demo",
      "type": "registry:example",
      "title": "Loom Slider Demo",
      "description": "A tension control read off the dash standing tallest.",
      "registryDependencies": [
        "@loomui/loom-slider"
      ],
      "files": [
        {
          "path": "registry/example/loom-slider-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "progress-ring-demo",
      "type": "registry:example",
      "title": "Progress Ring Demo",
      "description": "A ring stepping through five values without ever settling.",
      "registryDependencies": [
        "@loomui/progress-ring"
      ],
      "files": [
        {
          "path": "registry/example/progress-ring-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "spool-demo",
      "type": "registry:example",
      "title": "Spool Demo",
      "description": "A pill that changes shape to fit three different states, and can be interrupted part way.",
      "registryDependencies": [
        "@loomui/spool"
      ],
      "files": [
        {
          "path": "registry/example/spool-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "icon-morph-demo",
      "type": "registry:example",
      "title": "Icon Morph Demo",
      "description": "Five icon pairs, each one shape travelling rather than two shapes trading places.",
      "registryDependencies": [
        "@loomui/icon-morph"
      ],
      "files": [
        {
          "path": "registry/example/icon-morph-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "photo-stamp-demo",
      "type": "registry:example",
      "title": "Photo Stamp Demo",
      "description": "A stamp that lifts its photo out of the frame at full size over a blurred page.",
      "registryDependencies": [
        "@loomui/photo-stamp"
      ],
      "files": [
        {
          "path": "registry/example/photo-stamp-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "trend-stack-demo",
      "type": "registry:example",
      "title": "Trend Stack Demo",
      "description": "A year of visitors split three ways. Point at a month and the card follows.",
      "registryDependencies": [
        "@loomui/trend-stack"
      ],
      "files": [
        {
          "path": "registry/example/trend-stack-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "gauge-arc-demo",
      "type": "registry:example",
      "title": "Gauge Arc Demo",
      "description": "Sessions split four ways across half a ring, with the leading share in the middle.",
      "registryDependencies": [
        "@loomui/gauge-arc"
      ],
      "files": [
        {
          "path": "registry/example/gauge-arc-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "funnel-rows-demo",
      "type": "registry:example",
      "title": "Funnel Rows Demo",
      "description": "A six stage pipeline, each bar as long as its share of the first.",
      "registryDependencies": [
        "@loomui/funnel-rows"
      ],
      "files": [
        {
          "path": "registry/example/funnel-rows-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "drawer-demo",
      "type": "registry:example",
      "title": "Drawer Demo",
      "description": "A drawer from the bottom edge, pulled open or swiped away by its notch.",
      "registryDependencies": [
        "@loomui/drawer"
      ],
      "files": [
        {
          "path": "registry/example/drawer-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "shimmer-skeleton-demo",
      "type": "registry:example",
      "title": "Shimmer Skeleton Demo",
      "description": "A card placeholder with the sweep running down it.",
      "registryDependencies": [
        "@loomui/shimmer-skeleton"
      ],
      "files": [
        {
          "path": "registry/example/shimmer-skeleton-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "card-stack-demo",
      "type": "registry:example",
      "title": "Card Stack Demo",
      "description": "Four cards pinning one behind another inside a panel.",
      "registryDependencies": [
        "@loomui/card-stack"
      ],
      "files": [
        {
          "path": "registry/example/card-stack-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "image-trail-demo",
      "type": "registry:example",
      "title": "Image Trail Demo",
      "description": "Swatches dropped behind the pointer as it crosses a panel.",
      "registryDependencies": [
        "@loomui/image-trail"
      ],
      "files": [
        {
          "path": "registry/example/image-trail-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "bento-grid-demo",
      "type": "registry:example",
      "title": "Bento Grid Demo",
      "description": "Four tiles of two sizes arriving one after another.",
      "registryDependencies": [
        "@loomui/bento-grid"
      ],
      "files": [
        {
          "path": "registry/example/bento-grid-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "terminal-demo",
      "type": "registry:example",
      "title": "Terminal Demo",
      "description": "An install session typed out one command at a time.",
      "registryDependencies": [
        "@loomui/terminal"
      ],
      "files": [
        {
          "path": "registry/example/terminal-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "unfold-list-demo",
      "type": "registry:example",
      "title": "Unfold List Demo",
      "description": "Three questions, one panel open at a time.",
      "registryDependencies": [
        "@loomui/unfold-list"
      ],
      "files": [
        {
          "path": "registry/example/unfold-list-demo.tsx",
          "type": "registry:example"
        }
      ]
    },
    {
      "name": "utils",
      "type": "registry:lib",
      "title": "Utils",
      "description": "The cn() class merge helper every loom component depends on.",
      "dependencies": [
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "registry/lib/utils.ts",
          "type": "registry:lib"
        }
      ]
    },
    {
      "name": "use-spring",
      "type": "registry:lib",
      "title": "useSpring",
      "description": "A spring over named numbers, driven onto a callback rather than through state, that carries velocity across every retarget.",
      "files": [
        {
          "path": "registry/lib/use-spring.ts",
          "type": "registry:lib"
        }
      ]
    },
    {
      "name": "chart-frame",
      "type": "registry:lib",
      "title": "Chart Frame",
      "description": "The card every loom chart sits in: label, headline, delta, the plot, and a named tile per series.",
      "registryDependencies": [
        "utils"
      ],
      "files": [
        {
          "path": "registry/lib/chart-frame.tsx",
          "type": "registry:lib"
        }
      ],
      "cssVars": {
        "theme": {
          "ease-out-quart": "cubic-bezier(0.165, 0.84, 0.44, 1)",
          "color-chart-1": "var(--chart-1)",
          "color-chart-2": "var(--chart-2)",
          "color-chart-3": "var(--chart-3)",
          "color-chart-4": "var(--chart-4)",
          "color-chart-5": "var(--chart-5)",
          "color-chart-6": "var(--chart-6)",
          "color-chart-up": "var(--chart-up)",
          "color-chart-down": "var(--chart-down)"
        },
        "light": {
          "chart-1": "#ff375f",
          "chart-2": "#00c7be",
          "chart-3": "#ff9500",
          "chart-4": "#af52de",
          "chart-5": "#34c759",
          "chart-6": "#0a84ff",
          "chart-up": "oklch(0.62 0.15 145)",
          "chart-down": "oklch(0.6 0.19 25)"
        },
        "dark": {
          "chart-1": "#f0526e",
          "chart-2": "#00a199",
          "chart-3": "#c06400",
          "chart-4": "#b166e0",
          "chart-5": "#00a63b",
          "chart-6": "#3b8ef0",
          "chart-up": "oklch(0.72 0.16 145)",
          "chart-down": "oklch(0.68 0.18 25)"
        }
      }
    },
    {
      "name": "use-in-viewport",
      "type": "registry:lib",
      "title": "useInViewport",
      "description": "Tells a component whether it is on screen, so a looping animation can stop while nobody is watching it.",
      "files": [
        {
          "path": "registry/lib/use-in-viewport.ts",
          "type": "registry:lib"
        }
      ]
    }
  ]
}
