{"$schema":"https://ui.logic2b.com/schema/registry-item.json","name":"parallax","type":"registry:ui","title":"Parallax","description":"A scroll-linked parallax layer for marketing sections: the inner layer drifts as the section passes through the viewport, driven entirely by CSS scroll-driven animations (animation-timeline: view()). Zero JS on the scroll path, zero runtime deps, and guarded by @supports so unsupported browsers render it static. Give the container a height and put an oversized object-cover image or gradient inside.","registryDependencies":["utils"],"files":[{"path":"ui/parallax.tsx","type":"registry:ui","content":"\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/**\n * A scroll-linked parallax layer for marketing sections: the inner layer drifts\n * as the section passes through the viewport, driven entirely by CSS\n * scroll-driven animations (`animation-timeline: view()`). Zero JS on the scroll\n * path and zero runtime deps.\n *\n * Guarded by `@supports (animation-timeline: view())`, so browsers without\n * scroll-driven animations render the layer static — the content is always\n * visible, the motion is pure progressive enhancement.\n *\n * The container is position-relative with `overflow-clip`; give it a height\n * (e.g. `className=\"h-72\"`). Put an oversized, `object-cover` image or a\n * gradient inside — the layer is intentionally taller than the container so the\n * drift never reveals an edge.\n */\nconst PARALLAX_CSS = `\n@supports (animation-timeline: view()) {\n  @keyframes l2b-parallax {\n    from { transform: translateY(calc(var(--l2b-parallax-range, 12%) * -1)); }\n    to { transform: translateY(var(--l2b-parallax-range, 12%)); }\n  }\n  [data-slot=\"parallax-layer\"] {\n    animation: l2b-parallax linear both;\n    animation-timeline: view(block);\n    will-change: transform;\n  }\n  @media (prefers-reduced-motion: reduce) {\n    [data-slot=\"parallax-layer\"] { animation: none; }\n  }\n}\n`\n\nexport interface ParallaxProps extends React.ComponentProps<\"div\"> {\n  /** How far the layer drifts, any CSS length/percentage. Default `\"12%\"`. */\n  range?: string\n}\n\nfunction Parallax({ className, range = \"12%\", children, ...props }: ParallaxProps) {\n  const layerStyle = {\n    \"--l2b-parallax-range\": range,\n    top: `calc(${range} * -1)`,\n    bottom: `calc(${range} * -1)`,\n  } as React.CSSProperties\n\n  return (\n    <div className={cn(\"relative overflow-clip\", className)} {...props}>\n      <style>{PARALLAX_CSS}</style>\n      <div\n        data-slot=\"parallax-layer\"\n        className=\"absolute inset-x-0\"\n        style={layerStyle}\n      >\n        {children}\n      </div>\n    </div>\n  )\n}\n\nexport { Parallax }\n"}],"categories":["motion"],"accessibility":{"support":"consumer","pattern":"decorative parallax","primitive":"Motion scroll transforms","keyboard":[],"aria":["Preserves the semantics of the rendered layer; decorative layers can be hidden from assistive technology."],"consumer":["Use empty alt/aria-hidden for decorative imagery, retain a static layout and disable the transform for reduced-motion users."],"limitations":["Parallax movement can cause vestibular discomfort unless reduced-motion preferences are honored."]},"api":{"source":"src/ui/parallax.tsx","exports":[{"name":"ParallaxProps","kind":"type","definition":"interface ParallaxProps extends React.ComponentProps<\"div\"> { /** How far the layer drifts, any CSS length/percentage. Default `\"12%\"`. */ range?: string }"},{"name":"Parallax","kind":"component","propsType":"ParallaxProps","props":[{"name":"range","type":"string","required":false,"default":"\"12%\"","description":"How far the layer drifts, any CSS length/percentage. Default `\"12%\"`."}]}]}}