# Accessibility URL: https://www.spaceui.one/docs/accessibility *** title: Accessibility description: How is accessibility with Space UI? ------------------------------------------------ Animations can greatly enhance user experience, but they can also create accessibility issues if not handled with care. Some users are sensitive to motion and may experience discomfort, dizziness, or difficulty focusing when faced with strong visual effects. To address this, operating systems and browsers expose a setting called **Reduced Motion** (`prefers-reduced-motion`). When enabled, it communicates that the user prefers simpler or fewer animations. ## Core Principles ## Prefers Reduced Motion `prefers-reduced-motion` is a CSS media query and system-level setting. If a user has enabled it, it usually means: * Avoiding large-scale movement (scale, translate, rotate). * Preferring subtle effects such as opacity fades. * Disabling parallax or auto-scrolling animations. * Turning off looping or auto-playing background motion. The goal isn't to remove animation entirely, but to make it comfortable and safe. ## Space UI & Motion Space UI **is built on top of [Motion](https://motion.dev/)**. This means all Space UI components can leverage Motion’s accessibility features. The recommended way to support Reduced Motion is to wrap your app with `MotionConfig`: ```tsx import { MotionConfig } from 'motion/react' export function App({ children }: { children: React.ReactNode }) { return {children} } ``` With `reducedMotion="user"`, Motion will automatically: * Disable transform and layout animations if the user has Reduced Motion enabled. * Keep helpful transitions like opacity or background-color. As a result, Space UI components will automatically respect user preferences without extra configuration. ## Conclusion Accessible animations help ensure your UI is usable for everyone. By combining Space UI with Motion’s `MotionConfig`, you can provide a smooth, animated experience while adapting gracefully to `prefers-reduced-motion`. **We recommend adding `MotionConfig reducedMotion="user"` at the root of your app.** For more details, see the [Motion documentation](https://motion.dev/docs/react-accessibility). # AI Agents URL: https://www.spaceui.one/docs/agents *** title: AI Agents description: Build faster and cleaner interfaces with autonomous AI coding agents, specialized skills, and MCP tools. --------------------------------------------------------------------------------------------------------------------- import { IconArrowRight } from '@tabler/icons-react' import { Frame, FrameHeader } from '@/registry/primitives/frame' import { Card as CardPrimitives, CardPanel } from '@/registry/primitives/card' import { Badge } from '@/registry/components/spaceui/badge-squircle' Space UI is engineered from the ground up for both human developers and **autonomous AI coding agents** (Claude Code, Cursor, Windsurf, GitHub Copilot, Codex, and Antigravity). Thanks to standard shadcn registry schemas, headless Base UI primitives, and typed Motion animations, AI models can inspect, install, compose, and refactor Space UI components with zero hallucination. *** ## The 3 Pillars of AI Integration Space UI's agent ecosystem is structured into three dedicated layers: *** ## How Agents Work with Space UI When an AI agent operates in your workspace with Space UI:
{/* Top: AI Agent */} AI Agent Workspace Engine

Your AI Assistant

Claude Code, Cursor, Windsurf, GitHub Copilot, Antigravity

1. Query & Install MCP Server

@spaceui MCP Protocol

Autonomous component discovery, typed prop inspection, and CLI installation.

search_components get_component add_component
2. Guide & Refactor Agent Skills

.agents/skills/ Rules

Rules and lessons your agent applies on its own.

space-motion
Output React 19

Your React Workspace

Base UI primitives, Tailwind CSS v4, and tactile motion in src/components/ui

*** ## Best Practices for Agent Prompts To get the highest quality code from your AI assistant: ### 1. Specify Component Handles Always reference the exact `@spaceui/` identifier so the agent fetches the official registry item: ```text Add an interactive notification list using @spaceui/notification-list and @spaceui/badge. ``` ### 2. Combine with Skills Ask your agent to apply one of the [Space UI skills](/docs/skills) while it builds or reviews: ```text Review the transitions of this dialog with space-motion and fix anything slower than it should be. ``` ### 3. Use Copy Markdown for Context If your agent does not have live MCP access, click the **"Copy Markdown"** button at the top of any component page and paste the complete spec into your prompt. # Changelog URL: https://www.spaceui.one/docs/changelog *** title: Changelog description: Latest updates and announcements. ---------------------------------------------- import { Changelog, ChangelogItem, ChangelogChange } from '@/components/docs/mdx/changelog' * Added `LiquidMetalBorder` and `SilkBorder`: liquid metal flow and shimmering silk reactive borders with configurable lighting and angles. * Added procedural WebGPU/WGSL shaders: * `HeatShade`: procedural heat distortion shader with dynamic heat licks. * `SilkGradient`: fluid real-time silk wave gradient shader. * Added fluid physics & morphing components: * `LiquidSwitch`: fluid toggle switch with organic liquid morphing. * `LiquidSortableList`: drag-and-drop sortable list with smooth fluid transitions. * `SloshSlider`: interactive range slider with fluid slosh physics. * `SlideToConfirm`: interactive swipe/slide-to-action confirmation control. * `FrostBlurred`: frosted glass blur with chromatic diffusion and layered depth. * Added animated text & search components: * `MorphingText`: smooth text morphing between words and phrases. * `BlurRevealText`: staged kinetic blur-to-clear text reveal animation. * `MorphingCommandBar`, `MorphingSearchPill` & `MorphingArea`: expandable search pills and morphing command bar controls. * Added utility & layout components: * `AdaptiveDensityGrid`: dynamic layout grid with fluid cell packing. * `ChromaPalette`: interactive color palette previewer and selector. * `InteractiveChecklist`: micro-animated interactive checklist. * `TeamRosterSelector`: interactive team member selection widget. * Added `CommunityWall`: interactive infinite canvas block for community notes, stickers, and social badges. * Added `InteractiveGridHero`: hero block with proximity-reactive cursor mesh grid. * Added dedicated Pricing page with interactive savings calculator and plan comparisons. * Expanded **Emoji Explorer** asset catalog with 30,000+ indexed Unicode assets. * Added quick export drawer to **OG Image Generator**. * Global design polish across landing sections, bento showcases, and navigation. * Enhanced component preview stages and documentation layouts. * Optimized WebGPU/WebGL shader rendering and frame pacing. * Refined typography hierarchy with custom Open Runde font pairings. * Fixed reactive storage synchronization in `useLocalStorage`. * Fixed threshold and trigger edge cases in `useLoadMore`. * Fixed WebGL context cleanup and memory disposal on component unmount. * Added `GitHubActivity`: interactive GitHub contribution heatmap supporting live user and repository commit activity. * Added `FluidCountdown`: fluid countdown timer with smooth slot-machine roll transitions powered by `@number-flow/react`. * Added `Thinking`: AI reasoning/thinking status bubble indicator with subtle pulsating animations. * Added `HandleReel`: animated handle ticker and reel ticker component. * Added `BadgeSquircle` and `ButtonSquircle`: squircle-shaped badges and buttons with tailored curvature. * Added new carousel blocks: Dither Carousel, Lens Carousel, Liquid Gooey Carousel, and Prism Carousel. * Added `Stats` block template featuring GitHub stats, commit graphs, and analytics cards. * Added Interactive Design Tools Suite: * **Flags Explorer**: vector flag asset catalog, playground, and multi-format export. * **Image Split**: multi-row and grid image splitting utility. * **Plush Studio**: interactive 3D plush cushion design playground with real-time settings. * **OG Image Generator**: dynamic OpenGraph preview generator and showcase dashboard. * Overhauled site header into a modular floating island layout with separate brand, navigation, and tools capsules. * Enhanced mega menu geometry with circular arc fillets for seamless ear transitions. * Enhanced `GitHubActivity` with horizontal `ScrollArea`, edge fades, and auto-scroll on mobile while preserving the 100% full-width grid on desktop. * Integrated `NumberFlow` into `GitHubLink` for animated rolling star counts with compact notation. * Refactored squircle borders and visual consistency across Library components and marketing views. * Fixed initial SSR/hydration border-radius flash (FOUC) and spring physics in `BouncyAccordion`. * Fixed sticky positioning and scroll pinning on `DocsSidebar` and `DocsTocSidebar`, preventing sidebars from unsticking on long pages. * Fixed 56px top gap above documentation sidebar in standard layout mode. * Fixed SVG path stroke crossing artifact on mega menu inverse radius ears. * Fixed layout blowout and container width overflow on mobile for `GitHubActivity`. * Reorganized Library documentation structure under `src/content/ui-kit/`. * Added comprehensive MDX documentation and interactive demos for all new components, blocks, and templates. * Refactored application layout and navigation structure. * Streamlined documentation content with direct AI workflow integration. * Polished visual consistency and squircle styling across UI kit views. * Initial release of Space UI component distribution. * Added animated primitives powered by Base UI and Motion. * Integrated shadcn registry support with custom style presets. * Added sensory hooks, sound system, squircle tokens, and AI tooling (`llms.txt`). # Colors URL: https://www.spaceui.one/docs/fundamentals/colors *** title: Colors description: Color palette, semantic tokens, alpha translucent borders, and contrast standards. ----------------------------------------------------------------------------------------------- ## Overview Space UI relies on high-contrast semantic color tokens paired with subtle alpha-translucent borders (`--alpha(...)`) and layered drop shadows to produce visual hierarchy and depth. ## Palette & Semantic Tokens | Token | Light Mode | Dark Mode | Usage | | :------------ | :------------------------------------------------------- | :------------------------------------------------------- | :---------------------------- | | `background` | | | Application canvas background | | `foreground` | | | Default body text | | `card` | | | Cards, panels, surfaces | | `primary` | | | Primary buttons & highlights | | `secondary` | | | Secondary actions & badges | | `muted` | | | Subtle container backgrounds | | `destructive` | | | Errors, delete actions | | `info` | | | Informational callouts | | `success` | | | Completed/success states | | `warning` | | | Cautionary warnings | | `border` | | | Translucent borders | ## CSS Variables Definition ```css title="app/globals.css" :root { --radius: 0.625rem; --background: hsl(0 0% 100%); --foreground: hsl(222 46% 11%); --card: hsl(0 0% 100%); --card-foreground: hsl(0 0% 4%); --popover: hsl(0 0% 100%); --popover-foreground: hsl(0 0% 4%); --primary: hsl(0 0% 4%); --primary-foreground: hsl(0 0% 100%); --secondary: hsl(240 5% 96%); --secondary-foreground: hsl(240 5% 34%); --muted: hsl(0 0% 96%); --muted-foreground: hsl(0 0% 45%); --accent: hsl(240 5% 96%); --accent-foreground: hsl(0 0% 4%); --destructive: var(--color-red-500); --destructive-foreground: var(--color-red-500); --info: var(--color-blue-500); --info-foreground: var(--color-blue-500); --success: var(--color-emerald-500); --success-foreground: var(--color-emerald-500); --warning: var(--color-amber-500); --warning-foreground: var(--color-amber-500); --border: --alpha(var(--color-black) / 8%); --input: --alpha(var(--color-black) / 8%); --ring: transparent; --pill-active-bg: --alpha(var(--color-black) / 10%); } .dark { --background: hsl(0 0% 9%); --foreground: hsl(0 0% 100%); --card: hsl(0 0% 4%); --card-foreground: hsl(0 0% 98%); --popover: hsl(0 0% 4%); --popover-foreground: hsl(0 0% 98%); --primary: hsl(0 0% 98%); --primary-foreground: hsl(0 0% 4%); --secondary: hsl(240 4% 16%); --secondary-foreground: hsl(0 0% 98%); --muted: hsl(240 4% 16%); --muted-foreground: hsl(0 0% 64%); --accent: hsl(0 0% 9%); --accent-foreground: hsl(0 0% 98%); --destructive: var(--color-red-900); --destructive-foreground: var(--color-red-400); --info: var(--color-blue-500); --info-foreground: var(--color-blue-400); --success: var(--color-emerald-500); --success-foreground: var(--color-emerald-400); --warning: var(--color-amber-500); --warning-foreground: var(--color-amber-400); --border: --alpha(var(--color-white) / 8%); --input: --alpha(var(--color-white) / 15%); --ring: transparent; --pill-active-bg: --alpha(var(--color-white) / 14%); } ``` # Iconography URL: https://www.spaceui.one/docs/fundamentals/iconography *** title: Iconography description: Icon standards for Space UI using Tabler Icons for components and Lucide Icons for primitives. ----------------------------------------------------------------------------------------------------------- ## Overview Space UI relies on clean, static vector iconography designed for clarity, visual balance, and performance. We adopt a dual-library approach where each icon set serves a distinct structural role: *** ## Dual Iconography Comparison Explore side-by-side examples of identical icon concepts implemented with **Tabler Icons** versus **Lucide Icons** to understand the design decisions and aesthetic differences: | Icon Concept | Tabler Icons (Components & Blocks) | Lucide Icons (Primitives) | Usage Context | | :-------------------- | :---------------------------------------------------------------- | :-------------------------------------------------------- | :-------------------------------------------- | | **Settings** | | | Administration, user preferences, options | | **Calendar** | | | Date pickers, event scheduling, timelines | | **Notifications** | | | Alert center, bell counters, status tags | | **Search** | | | Command menu, search inputs, filters | | **User / Profile** | | | Account dropdown, avatars, member lists | | **Folder** | | | File tree, directory explorers, project items | | **Mail** | | | Contact forms, inbox rows, email inputs | | **Sparkles / AI** | | | AI assistants, prompt generators, highlights | | **Shield / Security** | | | Security banners, permissions, auth status | | **Layout Grid** | | | Grid views, dashboard switchers, catalogs | | **Sliders / Filters** | | | Filter controls, configuration panels | | **Trash / Delete** | | | Destructive actions, item removal | *** ## Installation Install both libraries to support primitives and compound components in your application: ### Tabler Icons (Components & Blocks) ### Lucide Icons (Primitives) *** ## Usage Guidelines ### 1. Tabler in Components & Blocks When building custom UI sections, feature cards, dashboards, or buttons, import icons from `@tabler/icons-react`: ```tsx import { IconRocket, IconBrandGithub, IconArrowRight } from '@tabler/icons-react' import { Button } from '@/components/ui/button' export function HeroActions() { return (
) } ``` ### 2. Lucide in Headless Primitives Primitives use `lucide-react` for standard UI indicators and state controls: ```tsx import { ChevronDown } from 'lucide-react' import { AccordionPrimitive } from '@/components/ui/accordion' export function AccordionTrigger({ children, ...props }: AccordionPrimitive.Trigger.Props) { return ( {children} ) } ``` *** ## Icon Sizing Standards To maintain consistent vertical rhythm across your application, adhere to the standard Space UI icon scale: | Context | Tailwind Class | Pixel Size | Stroke Width | | :------------------------------- | :--------------------- | :---------- | :------------- | | **Badges & Micro tags** | `size-3` or `size-3.5` | 12px – 14px | `1.5` – `1.75` | | **Buttons & Form Controls** | `size-4` | 16px | `1.75` – `2.0` | | **Section & Card Headers** | `size-4.5` or `size-5` | 18px – 20px | `1.5` – `2.0` | | **Empty States & Feature Tiles** | `size-8` or `size-10` | 32px – 40px | `1.25` – `1.5` | *** ## Optical Alignment When pairing icons with text inside buttons or badges: * Always apply `shrink-0` to prevent icon distortion inside flex containers. * Use `pointer-events-none` on decorative icons to ensure click events pass cleanly to the parent trigger. * Keep icon colors inherited or muted with `text-muted-foreground` to preserve high visual hierarchy on the label text. # Typography URL: https://www.spaceui.one/docs/fundamentals/typography *** title: Typography description: Responsive type scale, font variables, heading hierarchy, optical line-heights, and interactive typography specs. ------------------------------------------------------------------------------------------------------------------------------ ## Overview Space UI typography is built on the principles of **restraint, precision, and responsive scalability**. Rather than arbitrary one-off font sizes, the system uses a mathematically grounded type scale with descending heading levels, optical line-heights, and dedicated tokens for body and interface controls. The design system is powered by three primary font families: *** ## Text Playground Test how headings, body paragraphs, blockquotes, lists, and interactive accordion widgets respond across different screen sizes and typeface configurations. *** ## Heading Font Specs Headings feature tight, optical line-heights (`1.10–1.35`) and proportional negative letter-spacing (tracking) to produce dense, punchy titles that balance neatly across lines. *** ## Body & UI Font Specs Body and interface typography is calibrated for maximum legibility at high reading speeds. Line-heights are relaxed (`1.40–1.60`) to provide comfortable vertical rhythm. *** ## Type Scale Reference A quick-reference matrix mapping typographic roles to rem/pixel sizes, line-heights, weights, tracking, and Tailwind CSS v4 utility classes: | Role | Size (Desktop) | Line Height | Weight | Tracking | Tailwind v4 | Description | | :---------------------- | :--------------- | :---------- | :---------------------------- | :------- | :--------------------- | :--------------------------------------------- | | **H1 Title** | 64px / 4.0rem | 72px / 1.12 | SemiBold / 600 | -0.025em | `text-5xl lg:text-6xl` | Display hero headlines & major page titles | | **H2 Section** | 48px / 3.0rem | 56px / 1.16 | SemiBold / 600 | -0.020em | `text-4xl lg:text-5xl` | Main content sections & feature headings | | **H3 Subsection** | 36px / 2.25rem | 44px / 1.22 | SemiBold / 600 | -0.015em | `text-3xl` | Subsections & card headers | | **H4 Card Title** | 28px / 1.75rem | 36px / 1.28 | SemiBold / 600 | -0.010em | `text-2xl` | Panel titles, dialog headers, modal titles | | **H5 Subhead** | 22px / 1.375rem | 30px / 1.36 | SemiBold / 600 | -0.005em | `text-xl` | Feature group titles & small card headings | | **H6 Group Header** | 18px / 1.125rem | 26px / 1.44 | SemiBold / 600 | 0em | `text-lg` | List section titles & sub-labels | | **Body Large** | 18px / 1.125rem | 28px / 1.55 | Regular / 400 • Medium / 500 | -0.005em | `text-lg` | Lead paragraphs & hero descriptions | | **Body Base** | 16px / 1.0rem | 24px / 1.50 | Regular / 400 • Medium / 500 | -0.005em | `text-base` | Default documentation copy & blog paragraphs | | **UI Small / Controls** | 14px / 0.875rem | 20px / 1.43 | Regular / 400 • Medium / 500 | 0em | `text-sm` | Buttons, form controls, table cells, dropdowns | | **Subtext / Caption** | 13px / 0.8125rem | 18px / 1.38 | Regular / 400 • Medium / 500 | 0em | `text-[13px]` | Helper texts, breadcrumbs, timestamp strings | | **Badge / Micro** | 12px / 0.75rem | 16px / 1.33 | Medium / 500 • SemiBold / 600 | +0.010em | `text-xs` | Keyboard shortcuts, status badges, micro tags | *** ## Typographic Principles When styling components or long-form documentation, follow these core guidelines: ### 1. Line-Height by Role * **Headings**: Keep line-height tight (around `1.10–1.25`) so multiline headlines read as cohesive units. * **Body & Paragraphs**: Use generous line-height (`1.50–1.60`) so the eye easily transitions to the next line. * **Single-line Controls**: Use `leading-none` or `leading-normal` with centered flex alignment. ### 2. Cap the Measure (Line Length) Unbounded paragraph widths fatigue the reader. Cap long-form reading copy around **60–75 characters per line** using `max-w-[65ch]` or `max-w-2xl`. ### 3. Deliberate Text Wrapping * Apply `text-wrap: balance` on headings and card titles to distribute line lengths evenly. * Apply `text-wrap: pretty` on lead paragraphs and descriptions to prevent single-word orphans on the final line. ### 4. Tabular Numbers on Changing Values Proportional digits have variable widths, causing layout jitter when counters, prices, or timers tick. Use `font-variant-numeric: tabular-nums` (Tailwind `tabular-nums`) for dynamic numeric values: ```tsx ${price.toFixed(2)} ``` ### 5. iOS Mobile Input 16px Rule iOS Safari automatically zooms the viewport if a form input has a font size smaller than `16px`. Always start mobile inputs at `16px` and scale down on larger viewports: ```tsx ``` *** ## Configuration & Custom Fonts ### 1. Setup with `next/font` (Next.js) Configure Google Fonts or local variable fonts in your root layout: ```tsx title="app/layout.tsx" import { Inter, Geist, JetBrains_Mono } from 'next/font/google' import '@/styles/globals.css' const fontSans = Inter({ subsets: ['latin'], variable: '--font-sans', display: 'swap', }) const fontHeading = Geist({ subsets: ['latin'], variable: '--font-heading', display: 'swap', }) const fontMono = JetBrains_Mono({ subsets: ['latin'], variable: '--font-mono', display: 'swap', }) export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ) } ``` ### 2. Tailwind CSS v4 Theme Integration In Tailwind CSS v4, map your font variables inside `@theme` in `globals.css`: ```css title="app/globals.css" @import 'tailwindcss'; @theme { --font-sans: var(--font-sans), system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; --font-heading: var(--font-heading), var(--font-sans), system-ui, sans-serif; --font-mono: var(--font-mono), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; } @layer base { body { font-family: var(--font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } h1, h2, h3, h4, h5, h6 { font-family: var(--font-heading); text-wrap: balance; } } ``` # Introduction URL: https://www.spaceui.one/docs *** title: Introduction description: An open-source design library built for humans and AI to create expressive, polished, and high-quality interfaces. ------------------------------------------------------------------------------------------------------------------------------- **Space UI is a distribution of React components** built with [Tailwind CSS](https://tailwindcss.com/), [Motion](https://motion.dev/), and [Base UI](https://base-ui.com/), based on the shadcn registry format. Our goal is to help anyone build tasteful, accessible, Motion‑powered interfaces while keeping sites ultra-fast, sensory, and maintainable. ## Not a library—an open component distribution Like [shadcn/ui](https://ui.shadcn.com/), **Space UI is not a typical install‑from‑NPM library**. It’s an open collection you can **copy, modify, and customize** directly in your codebase. This “open code” approach gives you maximum flexibility without wrapper overhead or styling workarounds. ## What’s included ## Why Space UI? 1. **Open source & copy‑first**: Direct access to source so you can adapt components at their core to your design system. 2. **Sensory & Animation‑first**: Consistent, composable physics and micro-interactions that make interfaces feel alive. 3. **Performance & accessibility**: Sensible defaults, WCAG compliance, and reduced-motion safety. 4. **Base UI & Radix support**: Built on headless primitives while keeping source open and fully customizable. ## AI-Enhanced Workflow Space UI is designed from the ground up to be **AI-friendly**, making it easier for language models to understand and modify your UI. # Installation URL: https://www.spaceui.one/docs/installation *** title: Installation description: How to install dependencies, configure registries, and add Space UI components to your project. ------------------------------------------------------------------------------------------------------------ Space UI is an open distribution of React components built on top of **React 19**, **Base UI**, **Tailwind CSS v4**, and **Motion**. It works seamlessly with the official `shadcn` CLI through custom registries. **Zero-lockin open code:** Space UI components are not a heavy NPM dependency. They install directly into your codebase, giving you full ownership to inspect, edit, and style every line of code. ## Choose Your Integration Select your framework or development workflow to get started: Next.js 15/16 App Router, React 19 Server Components, and Tailwind CSS v4 setup. Client-side React 19 SPA with Vite, `@tailwindcss/vite`, and TypeScript aliases. Prompting rules, custom registries, and `llms.txt` integration for Lovable, Bolt.new, v0, Cursor & Windsurf. Step-by-step manual setup, components.json configuration, and custom registry reference. Connect Claude Code, Cursor, Windsurf, and VS Code directly to Space UI's registry. Browse all animated Base UI primitives, interactive demos, and component sources. *** ## Prerequisites & Compatibility Ensure your project environment meets the minimum version requirements: | Technology | Minimum Version | Notes | | :--------------- | :-------------- | :-------------------------------------------------------------------- | | **React** | `≥ 19.0.0` | Full support for React 19 Actions, Server Components, and Transitions | | **Tailwind CSS** | `≥ 4.0.0` | Built natively for CSS-first `@import "tailwindcss";` architecture | | **Motion** | `≥ 12.0.0` | Fluid physics, layout animations, and gesture interactions | | **Base UI** | `≥ 1.7.0` | Headless, accessible primitives powering menus, dialogs, and popovers | *** ## Quick Start (CLI) If you already have a React project with Tailwind CSS configured, integrate Space UI in three simple steps: ### Initialize the Space UI Preset Run the `init` command to automatically configure your `components.json`, color variables, and squircle utility classes: ### Add Components Install any primitive or component directly from the `@spaceui` registry: Shared dependencies like `@base-ui/react`, `motion`, and `@spaceui/*` primitives are resolved and downloaded automatically by the CLI. ### Import and Use Import the installed component into your layout or page: ```tsx title="app/page.tsx" import { Dialog, DialogTrigger, DialogPopup, DialogTitle, DialogDescription, DialogClose } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' export default function Page() { return ( Open Dialog} /> Welcome to Space UI State of the art animations, accessible Base UI primitives, and sensory micro-interactions.
Dismiss} />
) } ```
*** ## Next Steps Explore the core foundations and available component categories: * [Explore Primitives](/ui-kit/primitives) — Base UI animated primitives (Dialog, Menu, Tooltip, Tabs, Popover). * [Explore Components](/ui-kit/components) — High-level UI components, charts, and interactive tables. * [Sensory Hooks & Sounds](/ui-kit/hooks) — Haptic audio feedback and interaction utilities. * [Fundamentals & Theming](/docs/fundamentals/colors) — Color palettes, typography scales, and token systems. # Lovable, Bolt & AI Builders URL: https://www.spaceui.one/docs/installation/lovable *** title: Lovable, Bolt & AI Builders description: Build faster with Space UI in Lovable, Bolt.new, v0, Cursor, Windsurf, and Claude Code. ---------------------------------------------------------------------------------------------------- Space UI is engineered from the ground up for the AI-assisted development era. Thanks to standard **shadcn registry** formatting, strict **React 19** typing, and a dedicated **`llms.txt`** index, language models and AI IDEs understand and generate Space UI components effortlessly. *** ## Lovable.dev **Lovable** natively supports custom shadcn registries. You can add the Space UI registry directly in your project settings: ### Configure the Registry Endpoint In your Lovable project, open **Settings → Registries** (or in `components.json`) and add: ```json title="components.json" { "registries": { "@spaceui": "https://www.spaceui.one/r/{name}.json" } } ``` ### Prompt Lovable with Space UI Primitives Use specific component handles in your prompt instructions: ```text Build a modern dashboard settings view with: - Tabs using @spaceui/tabs - Modal dialog for user invitations using @spaceui/dialog - Button controls from @spaceui/button with squircle radius - Follow the design tokens and dark mode styling from Space UI ``` *** ## Bolt.new **Bolt.new** runs in-browser WebContainer environments. To use Space UI inside Bolt: ### Initialize Space UI in WebContainer Terminal Run the standard initialization in the Bolt terminal: ```bash npx shadcn@latest init https://www.spaceui.one/r/lib-style.json -y ``` ### Add Space UI Components Install any required primitives directly: ```bash npx shadcn@latest add https://www.spaceui.one/r/primitives-dialog.json https://www.spaceui.one/r/primitives-button.json -y ``` *** ## v0.dev (by Vercel) When generating UI blocks with **v0**, pass Space UI's documentation context or ask v0 to use Base UI primitives: ```text Generate a multi-step checkout dialog using Base UI (@base-ui/react) and Motion. Use Space UI semantic tokens (--background, --foreground, --card, --primary). Ensure dialogs use Base UI Portal and Backdrop with smooth scale-in animations. ``` *** ## Cursor & Windsurf Rules (`.cursorrules`) Save a `.cursorrules` (or `.windsurfrules`) file in the root of your repository to ensure your AI assistant always recommends and writes Space UI code: ```markdown title=".cursorrules" # Space UI Project Guidelines You are an expert React 19 & Tailwind CSS v4 developer working with Space UI. ## Core Stack - React 19 (Server & Client Components) - Base UI headless primitives (@base-ui/react) - Motion for fluid physics and micro-interactions (motion) - Tailwind CSS v4 (@import "tailwindcss") ## Component Installation When asked to add or use new UI components: 1. Always check if the component exists in the Space UI registry (@spaceui). 2. Install via shadcn CLI: npx shadcn@latest add @spaceui/ 3. Import from `@/components/ui/` ## Theming & Styling Rules - Use semantic color tokens: `bg-background`, `text-foreground`, `border-border`, `bg-muted`, `text-muted-foreground`. - Use squircle corner classes (`rounded-sm`, `rounded-md`, `rounded-lg`) for cards and dialogs. - Use `relative isolate` on page wrappers to prevent portal z-index collisions. - Reference documentation schemas from: https://www.spaceui.one/llms.txt ``` *** ## Direct `llms.txt` Context Feed our structured AI documentation directly into **Claude Projects**, **ChatGPT Custom GPTs**, or **OpenAI Assistant API**: * **Structured Map**: [https://www.spaceui.one/llms.txt](https://www.spaceui.one/llms.txt) * **Full Documentation**: Every page on Space UI includes a **Copy Markdown** action in the header to instantly grab the raw source for your LLM prompts. # Manual Installation URL: https://www.spaceui.one/docs/installation/manual *** title: Manual Installation description: Step-by-step manual setup, components.json configuration, and custom registry reference. ----------------------------------------------------------------------------------------------------- This guide covers setting up Space UI manually—from configuring **`components.json`** for registry resolution to zero-CLI copy-pasting for custom stacks and monorepos. **Full Code Ownership:** Space UI components are open and unbundled. You have complete freedom to customize, tweak styles, and adapt them directly in your codebase. ### Install Core Dependencies Install Base UI, Motion, and class utility dependencies: ### Configure `components.json` Create or update `components.json` at the root of your project to connect the `@spaceui` registry namespace: ```json title="components.json" { "$schema": "https://ui.shadcn.com/schema.json", "style": "base-nova", "rsc": true, "tsx": true, "tailwind": { "config": "", "css": "app/globals.css", "baseColor": "neutral", "cssVariables": true }, "aliases": { "components": "@/components", "ui": "@/components/ui", "blocks": "@/components/blocks", "lib": "@/lib", "utils": "@/lib/utils", "hooks": "@/hooks" }, "registries": { "@spaceui": "https://www.spaceui.one/r/{name}.json" } } ``` ### Add Class Merging Utility (`lib/utils.ts`) Create `lib/utils.ts` to provide the `cn()` helper used throughout all Space UI primitives: ```ts title="lib/utils.ts" export { cn, type ClassValue } from 'cn' ``` ### Configure Theme & CSS Variables (`globals.css`) Add the standard design tokens to your global CSS stylesheet (`app/globals.css` or `src/index.css`): ```css title="globals.css" @import 'tailwindcss'; @layer base { :root { --background: 0 0% 100%; --foreground: 240 10% 3.9%; --card: 0 0% 100%; --card-foreground: 240 10% 3.9%; --popover: 0 0% 100%; --popover-foreground: 240 10% 3.9%; --primary: 240 5.9% 10%; --primary-foreground: 0 0% 98%; --secondary: 240 4.8% 95.9%; --secondary-foreground: 240 5.9% 10%; --muted: 240 4.8% 95.9%; --muted-foreground: 240 3.8% 46.1%; --accent: 240 4.8% 95.9%; --accent-foreground: 240 5.9% 10%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; --border: 240 5.9% 90%; --input: 240 5.9% 90%; --ring: 240 5.9% 10%; --radius: 0.75rem; } .dark { --background: 240 10% 3.9%; --foreground: 0 0% 98%; --card: 240 10% 3.9%; --card-foreground: 0 0% 98%; --popover: 240 10% 3.9%; --popover-foreground: 0 0% 98%; --primary: 0 0% 98%; --primary-foreground: 240 5.9% 10%; --secondary: 240 3.7% 15.9%; --secondary-foreground: 0 0% 98%; --muted: 240 3.7% 15.9%; --muted-foreground: 240 5% 64.9%; --accent: 240 3.7% 15.9%; --accent-foreground: 0 0% 98%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; --border: 240 3.7% 15.9%; --input: 240 3.7% 15.9%; --ring: 240 4.9% 83.9%; } } ``` ### Add Components Install via shadcn CLI or copy the primitive code directly: *(Or click the **Code** tab on any component documentation page and copy the source into your `components/ui/` directory).* ### Render and Verify Import your component and verify its behavior: ```tsx title="app/page.tsx" import { Button } from '@/components/ui/button' export default function Page() { return (
) } ```
*** ## `components.json` Schema Reference | Property | Type | Description | | :-------------------------- | :-------- | :------------------------------------------------------------------------------------------------------- | | **`style`** | `string` | Style preset. Set to `"base-nova"` for Base UI and squircle token support. | | **`rsc`** | `boolean` | Set to `true` for Next.js App Router (React Server Components). When `false`, all files are client-only. | | **`tsx`** | `boolean` | Set to `true` to generate `.tsx`/`.ts` files, or `false` for `.jsx`/`.js`. | | **`tailwind.css`** | `string` | Relative path to your global CSS stylesheet (e.g. `app/globals.css` or `src/index.css`). | | **`tailwind.baseColor`** | `string` | Base palette color (`neutral`, `zinc`, `slate`, `gray`, `stone`). | | **`tailwind.cssVariables`** | `boolean` | Set to `true` to enable CSS variables (`--background`, `--foreground`). | | **`aliases`** | `object` | Mapping between logical imports and your project directory structure. | | **`registries`** | `object` | Remote registry namespace mapping (e.g. `"@spaceui": "https://www.spaceui.one/r/{name}.json"`). | *** ## Multi-Registry Namespaces With the `@spaceui` registry configured, you can install any component with: ```bash npx shadcn@latest add @spaceui/dialog @spaceui/button ``` The CLI queries `https://www.spaceui.one/r/{name}.json`, resolves the component code and sub-dependencies, rewrites imports according to your local `aliases`, and places files into your `components/ui/` directory. *** ## Custom Path Aliases & Monorepos For monorepo structures (e.g. Turborepo, Nx) or custom folder hierarchies, adjust the `aliases` block: ```json title="components.json" { "aliases": { "components": "@/shared/components", "ui": "@/shared/components/ui", "blocks": "@/shared/components/blocks", "lib": "@/shared/lib", "utils": "@/shared/utils", "hooks": "@/shared/hooks" } } ``` # Next.js URL: https://www.spaceui.one/docs/installation/nextjs *** title: Next.js description: Complete step-by-step integration for Next.js 15/16 App Router, React 19, and Tailwind CSS v4. ----------------------------------------------------------------------------------------------------------- This guide walks you through setting up Space UI in a modern **Next.js** application with the **App Router**, **React 19**, and **Tailwind CSS v4**. Space UI components are fully compatible with Next.js Server Components. Interactive primitives automatically contain the `'use client'` directive where necessary. ### Create a Next.js Project Initialize a new Next.js application with TypeScript, Tailwind CSS, and App Router: ### Initialize Space UI Preset Run the official initialization command to configure the Space UI design tokens, Base UI dependencies, and squircle utilities: ### Configure `components.json` Ensure your `components.json` includes the `@spaceui` registry namespace alongside your project path aliases: ```json title="components.json" { "$schema": "https://ui.shadcn.com/schema.json", "style": "base-nova", "rsc": true, "tsx": true, "tailwind": { "config": "", "css": "app/globals.css", "baseColor": "neutral", "cssVariables": true }, "aliases": { "components": "@/components", "ui": "@/components/ui", "blocks": "@/components/blocks", "lib": "@/lib", "utils": "@/lib/utils", "hooks": "@/hooks" }, "registries": { "@spaceui": "https://www.spaceui.one/r/{name}.json" } } ``` ### Configure Tailwind CSS v4 in `globals.css` Tailwind CSS v4 uses CSS-first configuration. Verify that `app/globals.css` imports Tailwind and defines the Space UI theme tokens: ```css title="app/globals.css" @import 'tailwindcss'; @layer base { :root { --background: 0 0% 100%; --foreground: 240 10% 3.9%; --card: 0 0% 100%; --card-foreground: 240 10% 3.9%; --popover: 0 0% 100%; --popover-foreground: 240 10% 3.9%; --primary: 240 5.9% 10%; --primary-foreground: 0 0% 98%; --secondary: 240 4.8% 95.9%; --secondary-foreground: 240 5.9% 10%; --muted: 240 4.8% 95.9%; --muted-foreground: 240 3.8% 46.1%; --accent: 240 4.8% 95.9%; --accent-foreground: 240 5.9% 10%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; --border: 240 5.9% 90%; --input: 240 5.9% 90%; --ring: 240 5.9% 10%; --radius: 0.75rem; } .dark { --background: 240 10% 3.9%; --foreground: 0 0% 98%; --card: 240 10% 3.9%; --card-foreground: 0 0% 98%; --popover: 240 10% 3.9%; --popover-foreground: 0 0% 98%; --primary: 0 0% 98%; --primary-foreground: 240 5.9% 10%; --secondary: 240 3.7% 15.9%; --secondary-foreground: 0 0% 98%; --muted: 240 3.7% 15.9%; --muted-foreground: 240 5% 64.9%; --accent: 240 3.7% 15.9%; --accent-foreground: 0 0% 98%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; --border: 240 3.7% 15.9%; --input: 240 3.7% 15.9%; --ring: 240 4.9% 83.9%; } } ``` ### Setup Stacking Context in `app/layout.tsx` Add the `relative isolate` utility class to your application wrapper. This ensures portaled elements (dialogs, tooltips, select menus) layer above sticky headers without `z-index` conflicts: ```tsx title="app/layout.tsx" import type { Metadata } from 'next' import { Inter } from 'next/font/google' import './globals.css' const inter = Inter({ subsets: ['latin'] }) export const metadata: Metadata = { title: 'My App', description: 'Built with Space UI and Next.js', } export default function RootLayout({ children }: { children: React.ReactNode }) { return (
{children}
) } ```
### Add Components Install any component from the catalog: ### Test in Your Page Create a test page to verify smooth animations and styling: ```tsx title="app/page.tsx" import { Dialog, DialogTrigger, DialogPopup, DialogTitle, DialogDescription, DialogClose } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' export default function HomePage() { return (

Space UI + Next.js

Sensory interactions, accessible Base UI primitives, and fluid Motion physics.

Open Interactive Dialog } /> Hello from Space UI This dialog uses Base UI portal management and fluid Motion physics.
Cancel} />
) } ```
*** ## Tips & Best Practices **React 19 Server Components:** You can import and render Space UI primitives in Server Components without adding `'use client'` to your page file, because the internal primitives encapsulate client boundaries directly. # Vite + React URL: https://www.spaceui.one/docs/installation/vite *** title: Vite + React description: Setup Space UI in a modern Vite React SPA with Tailwind CSS v4 and TypeScript path aliases. -------------------------------------------------------------------------------------------------------- This guide walks you through setting up Space UI in a **Vite + React 19** Single Page Application using **Tailwind CSS v4** and the official `@tailwindcss/vite` plugin. **Path Aliases:** Vite requires configuring path resolution in `vite.config.ts` and `tsconfig.json` so that the `@/components` aliases work seamlessly with the `shadcn` CLI. ### Create a Vite Project Scaffold a new Vite React application with TypeScript: ### Install Tailwind CSS v4 & Core Dependencies Install `@tailwindcss/vite`, Tailwind CSS v4, Base UI, Motion, and utility libraries: ### Configure Path Aliases in `vite.config.ts` Update `vite.config.ts` to add the `@` path alias and load the Tailwind CSS plugin: ```ts title="vite.config.ts" import path from 'path' import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import tailwindcss from '@tailwindcss/vite' export default defineConfig({ plugins: [react(), tailwindcss()], resolve: { alias: { '@': path.resolve(__dirname, './src'), }, }, }) ``` ### Update `tsconfig.json` and `tsconfig.app.json` Add path mappings to `tsconfig.app.json` (or `tsconfig.json`): ```json title="tsconfig.app.json" { "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] } } } ``` ### Configure `src/index.css` Import Tailwind CSS and declare the theme variables in `src/index.css`: ```css title="src/index.css" @import 'tailwindcss'; @layer base { :root { --background: 0 0% 100%; --foreground: 240 10% 3.9%; --card: 0 0% 100%; --card-foreground: 240 10% 3.9%; --popover: 0 0% 100%; --popover-foreground: 240 10% 3.9%; --primary: 240 5.9% 10%; --primary-foreground: 0 0% 98%; --secondary: 240 4.8% 95.9%; --secondary-foreground: 240 5.9% 10%; --muted: 240 4.8% 95.9%; --muted-foreground: 240 3.8% 46.1%; --accent: 240 4.8% 95.9%; --accent-foreground: 240 5.9% 10%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; --border: 240 5.9% 90%; --input: 240 5.9% 90%; --ring: 240 5.9% 10%; --radius: 0.75rem; } .dark { --background: 240 10% 3.9%; --foreground: 0 0% 98%; --card: 240 10% 3.9%; --card-foreground: 0 0% 98%; --popover: 240 10% 3.9%; --popover-foreground: 0 0% 98%; --primary: 0 0% 98%; --primary-foreground: 240 5.9% 10%; --secondary: 240 3.7% 15.9%; --secondary-foreground: 0 0% 98%; --muted: 240 3.7% 15.9%; --muted-foreground: 240 5% 64.9%; --accent: 240 3.7% 15.9%; --accent-foreground: 0 0% 98%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; --border: 240 3.7% 15.9%; --input: 240 3.7% 15.9%; --ring: 240 4.9% 83.9%; } } ``` ### Initialize Space UI Preset Run the preset initializer to create `components.json`: ### Add Components Install components into your Vite project: ### Test in `src/App.tsx` Import and test your component: ```tsx title="src/App.tsx" import { Dialog, DialogTrigger, DialogPopup, DialogTitle, DialogDescription, DialogClose } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' export default function App() { return (

Space UI + Vite

Ultra-fast development with React 19, Tailwind v4, and Motion primitives.

Open Dialog} /> Vite Integration Active Space UI components are rendered with native physics and Base UI accessibility.
Close} />
) } ```
# LLMs & AI Context URL: https://www.spaceui.one/docs/llms *** title: LLMs & AI Context description: Access full LLM context, global documentation dumps, and per-component markdown endpoints. ------------------------------------------------------------------------------------------------------- ## Overview Space UI is engineered to be **machine-readable and AI-friendly**. We provide dedicated endpoints that output clean, LLM-optimized markdown without HTML noise or navigation clutter. ## Endpoints ### How Per-Component Markdown Works Every documentation page and primitive can be fetched directly as clean Markdown by prefixing the route with `/llms.mdx/`: * Example: `https://www.spaceui.one/llms.mdx/ui-kit/primitives/dialog` * Example: `https://www.spaceui.one/llms.mdx/ui-kit/primitives/tabs` * Example: `https://www.spaceui.one/llms.mdx/docs/fundamentals/colors` ## Copy Markdown Feature Every component page in the web UI includes an instant **"Copy Markdown"** button in the header, allowing you to copy the entire page's prompt-ready context into your clipboard in one click. # Model Context Protocol (MCP) URL: https://www.spaceui.one/docs/mcp *** title: Model Context Protocol (MCP) description: Connect Claude Code, Cursor, VS Code, and Windsurf to Space UI's component registry using MCP. ----------------------------------------------------------------------------------------------------------- The **Model Context Protocol (MCP)** allows AI assistants to query the Space UI registry directly inside your editor. When enabled, your AI coding agent can search components, inspect TypeScript signatures, and install primitives without leaving the chat. Space UI leverages the official **shadcn MCP server**. Once configured, any `@spaceui` primitive can be discovered and installed autonomously by your AI tools. *** ## Automatic Configuration (Recommended) Run the initialization command for your preferred editor to automatically write the MCP configuration file: Claude Code Cursor VS Code *** ## Manual Configuration If you prefer adding the MCP server manually, save the corresponding JSON snippet in your project or global configuration directory: Claude Code Cursor VS Code Windsurf ```json title=".mcp.json" { "mcpServers": { "shadcn": { "command": "npx", "args": ["shadcn@latest", "mcp"] } } } ``` ```json title=".cursor/mcp.json" { "mcpServers": { "shadcn": { "command": "npx", "args": ["shadcn@latest", "mcp"] } } } ``` ```json title=".vscode/mcp.json" { "mcpServers": { "shadcn": { "command": "npx", "args": ["shadcn@latest", "mcp"] } } } ``` ```json title=".codeium/windsurf/mcp_config.json" { "mcpServers": { "shadcn": { "command": "npx", "args": ["shadcn@latest", "mcp"] } } } ``` *** ## Available MCP Capabilities When the MCP server is active, your AI agent has access to these capabilities: *** ## Example Prompts with MCP Try prompting your AI assistant with natural language instructions: ```text 1. Search Space UI for animated tab primitives and install @spaceui/tabs. 2. Build a project settings view with 3 tabs: General, Members, and Billing. 3. Add a delete confirmation dialog using @spaceui/dialog with destructive styling. ``` # Registry URL: https://www.spaceui.one/docs/registry *** title: Registry description: Learn how to use the Space UI Registry with shadcn/ui. ------------------------------------------------------------------- The catalog uses the `@spaceui` namespace. The shadcn CLI resolves the full alias suffix into the registry URL, so you can install everything from one namespace. ## Setup Space UI Registry Add the Space UI registry namespace to your `components.json`. Learn more about registry config from [shadcn registry docs](https://ui.shadcn.com/docs/registry). ```json { "registries": { "@spaceui": "https://www.spaceui.one/r/{name}.json" } } ``` ## Installing Components Component examples use the `c-*` naming pattern and install with no license key or account: ```bash npx shadcn@latest add @spaceui/components-spaceui-c-alert-1 ``` Some `c-*` items pull shared `@spaceui/*` primitives as registry dependencies. Those supporting files are resolved automatically, so installs keep working out of the box. # Roadmap URL: https://www.spaceui.one/docs/roadmap *** title: Roadmap description: Roadmap for Space UI. ---------------------------------- import { Roadmap, RoadmapGroup, RoadmapItem } from '@/components/docs/mdx/roadmap' This roadmap provides a high-level overview of our current objectives and what's coming next for Space UI. # Skills URL: https://www.spaceui.one/docs/skills *** title: Skills description: Agent skills that teach your AI assistant how Space UI builds, animates and ships interfaces. ---------------------------------------------------------------------------------------------------------- Your agent can already write code. Space UI skills give it the judgement: the rules, values and hard-won lessons behind our components, written down so Claude Code, Cursor, Windsurf, Codex or Antigravity apply them on their own. Each skill installs through the shadcn CLI into `.agents/skills/`, where agents discover it automatically. No Space UI code is required: the rules work with any stack and any design system. *** ## Available Skills More skills are on the way. *** ## Space Motion Teaches your agent how things should move: arrivals in 350ms, text that comes into focus, scenes that arrive over the last frame instead of fading out, sound only on key actions, and exports rendered frame by frame instead of screen-recorded. ```bash npx shadcn@latest add @spaceui/motion ``` * **Timing**: exact durations, easings, distances, blur and stagger, and when each one applies. * **Films**: scrubbable timelines, transitions, pre-mounting, driving live components, sound cues. * **Storytelling**: beat order, copy that sells, emoji as punctuation, layout per scene. * **Rendering**: 4K 60fps exports with zero dropped frames on a virtual clock. It also points your agent to [`@usespaceui/emoji`](https://www.npmjs.com/package/@usespaceui/emoji), [`@usespaceui/sounds`](https://www.npmjs.com/package/@usespaceui/sounds) and these docs for components to film. ### Prompt to start Paste this into your agent, swap the brackets, and it installs the skill before it starts: ```text Hey! I want to make a [10-second] opener for my product [Product name]: [one line on what it does and who it's for]. First install the Space Motion skill and follow it for everything that moves: npx shadcn@latest add https://www.spaceui.one/r/motion.json Then: 1. Propose the beats and the copy, one line per scene, and wait for my OK before animating. 2. Build it as a scrubbable page with one clock (?t= jumps to a moment). 3. Use animated emoji from @usespaceui/emoji and sounds from @usespaceui/sounds on key actions only. 4. When I approve it, export it frame by frame in 4K 60fps, not by recording the screen. ``` ### System prompt For agents and tools that take standing instructions (Claude Projects, custom GPTs, Cursor rules, `CLAUDE.md`): ```text You are a motion designer who ships in code. For any animation, transition, product video or opener, follow the Space Motion skill: read .agents/skills/space-motion/SKILL.md, or fetch https://www.spaceui.one/r/motion.json and read its files if it isn't installed. - Arrivals take ~350ms with a smooth ease-out; close faster than you open; never fade a scene out, let the next one arrive over it. - Reveal text by focus: word by word, 12px rise, 8px blur, 40ms stagger. Swap words with a blur swap, never a jump. - One idea per scene, two lines max, no dead air past 0.4s. Copy sells a concrete benefit, no filler adjectives. - Film the real product and drive it; don't mock it up. Fit each component to its frame. - No borders or shadows for depth; two tones and soft continuous corners. - Sound only on key actions. At most one animated emoji per line. - Everything is a function of one clock, so playback, scrubbing and export match. Warm heavy scenes up before they appear. - Agree on the beats and copy before animating. Check your work frame by frame at specific timestamps. - Export by rendering frames on a virtual clock, never by screen recording. ``` *** ## Using Skills Skills in `.agents/skills/` are picked up automatically. Describe the job and the matching skill kicks in: ```text Make a 45-second launch video of our landing page, then export it in 4K. ``` To call one explicitly, name it: ```text Review the transitions of this dialog with space-motion. ``` In editors that don't discover skills on their own, point to the file: ```markdown Follow the rules in .agents/skills/space-motion/SKILL.md for every animation in this PR. ``` # Card Info URL: https://www.spaceui.one/blocks/card-info *** title: Card Info description: Responsive feature and philosophy cards with gradient icons, clean typography, and layered container aesthetics. preview: block-card-info-1 -------------------------- ## Installation ## Examples ### Philosophy & Values A variation tailored for core principles and philosophical tenets with balanced gradient icon accents. # Community Wall URL: https://www.spaceui.one/blocks/community-wall *** title: Community Wall description: An interactive 2D draggable infinite canvas community board featuring radial bloom distribution, tilt controls, card pattern styles, and real-time note pinning. preview: name: block-community-wall-1 contained: false ---------------- ## Installation ## Features * **Draggable Infinite Canvas**: Smooth 2D drag-to-pan physics with boundary clamping and recenter GPS trigger. * **Radial Bloom Distribution**: Newly added notes automatically find empty coordinates via logarithmic spiral placement, avoiding overlapping cards. * **Geometric Card Patterns**: Choose between 6 bespoke SVGs (waves, dots, circuit, isometric grid, rings, radial bursts) styled with subtle OKLCH accents. * **Micro-Interactions & Audio**: Hover elevations, card tilt angles (-12° to +12°), and audio feedback powered by `@usespaceui/sounds`. * **Responsive Layout**: Infinite canvas on desktop and seamless vertical list/masonry on mobile devices. * **Flexible Backend**: Ready to connect to Supabase, PostgreSQL, or any REST/GraphQL backend with support for verified creator badges and guest postings. ## Structure The block includes: * `CommunityWall`: Main wrapper combining the canvas, floating action bar, stats counter, and submission dialog. * `InfiniteCanvas`: Draggable 2D viewport handling panning, collision avoidance, and card rendering. * `CommunityWallCard`: The memo note card with rotation, background patterns, and author avatar. * `LeaveNoteDialog`: Modal form with live real-time card preview, angle slider, and pattern picker. * `WALL_PATTERNS`: Array of 6 decorative SVGs for card backgrounds. ## Supabase Schema If you want to persist notes to Supabase with mixed guest and authenticated postings, use the following SQL schema: ```sql create table if not exists public.community_wall ( id uuid primary key default gen_random_uuid(), user_id uuid references auth.users(id) on delete set null, creator_name text not null, creator_avatar_url text, message text not null check (char_length(message) <= 140), pattern_index int default 0, rotation int default 0, is_verified boolean default false, created_at timestamptz default now() ); alter table public.community_wall enable row level security; create policy "Anyone can read community notes" on public.community_wall for select using (true); create policy "Anyone can insert community notes" on public.community_wall for insert with check (char_length(message) <= 140); ``` # Dither Carousel URL: https://www.spaceui.one/blocks/dither-carousel *** title: Dither Carousel description: A 3D cylindrical spiral column of cards in WebGL2 with curved perspective, directional blur, and matrix dither grain. preview: name: block-dither-carousel contained: false ---------------- Cards mapped onto the surface of an orbital cylinder. As cards travel away, they pass through an axial blur and dissolve into an ordered threshold dither pattern. ## Installation ## Usage ```tsx import BlockDitherCarousel from '@/components/blocks/dither-carousel' export default function Showcase() { return } ``` # Eleven Labs Landing URL: https://www.spaceui.one/blocks/eleven-labs *** title: Eleven Labs Landing description: ElevenLabs-inspired landing page block with a live Smooth Orb hero, product families, audio player, and voice cards. preview: block-eleven-labs -------------------------- ## Installation ## Files | File | Role | | ------------------------------------------------------------ | ------------------------------------------ | | `components/blocks/eleven-labs/index.tsx` | Main landing page & hero orb carousel | | `components/blocks/eleven-labs/data/flags.ts` | Language codes, flag mappings & SVG assets | | `components/blocks/eleven-labs/data/index.ts` | Voices, products, agents & initial data | | `components/blocks/eleven-labs/components/shared.tsx` | Shared icons, buttons & layout primitives | | `components/blocks/eleven-labs/components/speech-select.tsx` | Accessible portal-based dropdown select | | `components/blocks/eleven-labs/components/code-controls.tsx` | All-in-one AI editor code controls | | `components/blocks/eleven-labs/sections/creative-platform/` | ElevenCreative section & feature cards | | `components/blocks/eleven-labs/sections/product-tabs/` | Product tabs (Agents, API, Creative) | | `components/orb/smooth` | Hero orb (registry dependency) | | `components/shader/silk-gradient` | Silk gradient shader (registry dependency) | | `public/mastermind/` | Product and voice artwork | The orb in the hero uses ambient audio. Point `textureUrl` at another image if you replace the creative stills. # Blocks URL: https://www.spaceui.one/blocks *** title: Blocks description: Complete UI sections and page blocks ready to drop into a product. ------------------------------------------------------------------------------- # Interactive Fun Facts URL: https://www.spaceui.one/blocks/interactive-fun-facts *** title: Interactive Fun Facts description: Interactive 3D stacked quiz game block with True/False feedback, live score counter, progression indicators, and flip-to-reveal grid. preview: block-interactive-fun-facts ------------------------------------ ## Installation # Interactive Grid Hero URL: https://www.spaceui.one/blocks/interactive-grid-hero *** title: Interactive Grid Hero description: Interactive proximity-reactive square cell grid canvas that softly rounds and insets cells within a focused radius around the cursor. preview: block-interactive-grid-hero-1 -------------------------------------- ## Installation ## Features * **Dynamic Proximity Physics**: Cells smoothly adjust border-radius and inset within a configurable radius around the pointer. * **Shape Controls**: Switch seamlessly between `square`, `rounded`, and `full` (circle) corner styles. * **Responsive Layout**: Automatically calculates rows and columns to fill 100% of container width and height. # Lens Carousel URL: https://www.spaceui.one/blocks/lens-carousel *** title: Lens Carousel description: Vertical WebGL lens gallery from the Immersive Lens template. Scroll-linked planes, not a horizontal card strip. isPro: true preview: name: block-lens-carousel contained: false ---------------- ## Installation ## Usage ```tsx import BlockLensCarousel from '@/components/blocks/lens-carousel' export default function Showcase() { return } ``` # Liquid Gooey Carousel URL: https://www.spaceui.one/blocks/liquid-gooey-carousel *** title: Liquid Gooey Carousel description: A WebGL2 signed distance field carousel where cards behave like drops of liquid held on glass, fusing together and stretching organic strands. isPro: true preview: name: block-liquid-gooey-carousel contained: false ---------------- Each card is a rounded-box distance field. A fullscreen pass evaluates a smooth minimum (smin) across all cards, allowing them to fuse seamlessly like drops of liquid metal. ## Installation ## Usage ```tsx import BlockLiquidGooeyCarousel from '@/components/blocks/liquid-gooey-carousel' export default function Showcase() { return } ``` # Prism Carousel URL: https://www.spaceui.one/blocks/prism-carousel *** title: Prism Carousel description: A looping image strip viewed through a thick optical glass element with radial zoom, refraction, and chromatic RGB aberration. isPro: true preview: name: block-prism-carousel contained: false ---------------- The image strip renders to an offscreen texture, then a fullscreen WebGL pass samples it through an optical lens shader with dispersion and refraction. ## Installation ## Usage ```tsx import BlockPrismCarousel from '@/components/blocks/prism-carousel' export default function Showcase() { return } ``` # Showcase Gallery URL: https://www.spaceui.one/blocks/showcase-gallery *** title: Showcase Gallery description: Justified gallery of stills and looping videos. Point at a piece, tap it or tab to it and it steps forward on a spring while the rest makes room. isPro: true preview: name: block-showcase-gallery contained: false ---------------- ## Installation ## Usage ```tsx import { ShowcaseGallery } from '@/components/blocks/showcase-gallery' const rows = [ [ { title: 'Launch film', category: 'Motion', image: '/work/launch.webp', video: '/work/launch.mp4', aspect: 16 / 9 }, { title: 'Watch face', category: 'Product', image: '/work/watch.webp', video: '/work/watch.mp4', aspect: 0.8 }, ], [ { title: 'Dashboard', category: 'Product', image: '/work/dashboard.webp', aspect: 16 / 9 }, { title: 'Mobile app', category: 'Product', image: '/work/app.webp', aspect: 1 }, ], ] export default function Work() { return } ``` Each row is justified to the full width, with tiles sized by their `aspect` (width / height). In a narrow container the same items regroup two per row and keep their real proportions. Focus a tile and it steps forward on a spring: it widens, its row grows taller, its neighbours give way without changing the gallery's height, the media pans slightly toward the focus point and a caption with its `title` and `category` comes into focus. Only the focused tile's video plays; with nothing focused, videos play while they're on screen. * **Mouse**: the focus follows the pointer. * **Touch**: tap a tile to focus it, tap it again or anywhere else to let go. * **Keyboard**: tab through the tiles; Escape lets go. With reduced motion the focus still works, without the animation. Videos only load their metadata once they're about to scroll into view. Remote images go through `next/image`, so add their host to `images.remotePatterns` in `next.config`. # Sign In Page URL: https://www.spaceui.one/blocks/sign-in *** title: Sign In Page description: A complete sign in page block using our space components and primitives. preview: name: block-sign-in iframe: false ------------- ## Installation # Stats URL: https://www.spaceui.one/blocks/stats *** title: Stats description: Comprehensive portfolio statistics and analytics blocks featuring KPI cards, GitHub activity heatmap, publication analytics, Lighthouse benchmarks, and reader engagement. preview: block-stats-general ---------------------------- ## Installation ## Blocks ### GitHub Activity & Heatmap GitHub ecosystem metrics (stars, forks, commits) with floating particle shapes and an interactive 52-week contribution heatmap matrix. ### Blog & Writing Analytics Publication statistics tracking published articles, cumulative word counts, community messages, and reading time estimates. ### Lighthouse Performance Audit Mobile and desktop performance scorecards featuring SVG concentric radar charts and animated category benchmark progress bars. ### Reader Engagement Audience interaction dashboard featuring most-viewed articles, top community reactions, interactive emoji counters, topic distribution tags, and recent changelog milestones. # Velocity Hover Preview URL: https://www.spaceui.one/blocks/velocity-hover-preview *** title: Velocity Hover Preview description: Interactive kinetic list and hover carousel projecting a floating WebGL preview with inertial momentum mesh-warping and pixel block entry/exit wave crossfading. isPro: true preview: name: demo-c-velocity-hover-preview-01 contained: false ---------------- Interactive kinetic hover carousel. Hovering list items projects an orthographic WebGL preview that trails pointer velocity with inertia, vertex momentum distortion, and pixel wave entrance and exit dissolves. ## Installation ## Usage ```tsx import { VelocityHoverPreview } from '@/components/spaceui/velocity-hover-preview' const sampleServices = [ { id: '01', num: '01', title: 'Space UI Twilight Ring', subtitle: 'Luminous Coastal Horizon & Twilight Shaders', mediaUrl: 'https://cdn.spaceui.one/atom/samples/image-1.png', }, { id: '02', num: '02', title: 'Flora Kinetic Portrait', subtitle: 'Botanical Florals & Reactive Micro-interactions', mediaUrl: 'https://cdn.spaceui.one/atom/samples/image-2.png', }, ] export default function Example() { return } ``` ## Props | Prop | Type | Default | Description | | --------------- | ----------------------------- | ----------- | --------------------------------------------------------------- | | `items` | `PreviewItem[]` | `[]` | Array of items with title, subtitle, mediaUrl, and num. | | `accentColor` | `string` | `'#ffe9a8'` | Accent color of pixel wave transition bands (Aurum by default). | | `gridDensity` | `number` | `32` | Density of matrix blocks in transition waves. | | `warpIntensity` | `number` | `0.45` | Inertial momentum mesh distortion scale. | | `onItemSelect` | `(item: PreviewItem) => void` | — | Callback when a list item is clicked. | # Adaptive Density Grid URL: https://www.spaceui.one/components/adaptive-density-grid *** title: Adaptive Density Grid description: A fluid polymorphic grid featuring velocity-driven spring pill tabs, staggered layout reflow animations, and built-in memory optimization. preview: name: demo-c-adaptive-density-grid-01 contained: false ---------------- ## Installation ## Usage ```tsx import { AdaptiveDensityGrid } from '@/components/spaceui/adaptive-density-grid' ``` ```tsx
{item.title}
} /> ``` ## API Reference ### AdaptiveDensityGrid Props | Prop | Type | Default | Description | | ----------------- | -------------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------ | | `items` | `T[]` | `undefined` | Array of data items to render | | `renderItem` | `(item: T, index: number, state: { isRearranging: boolean }) => ReactNode` | `undefined` | Custom item render function | | `children` | `ReactNode` | `undefined` | Direct children components (alternative to `items`) | | `options` | `DensityOption[]` | `DEFAULT_OPTIONS` | Array of layout density or category filter options | | `activeId` | `string \| number` | `undefined` | Controlled active option id | | `defaultActiveId` | `string \| number` | `options[0]?.id` | Default active option id | | `onOptionChange` | `(id: string \| number) => void` | `undefined` | Callback fired when option selection changes | | `showControls` | `boolean` | `true` | Show or hide the top selector bar | | `controlsExtra` | `ReactNode` | `undefined` | Extra elements rendered alongside the controls (e.g. search input) | | `staggerDelay` | `number` | `0.012` | Stagger delay in seconds between tile animations | | `duration` | `number` | `0.55` | Layout reflow transition duration in seconds | | `memoryOptimized` | `boolean` | `true` | Enables `content-visibility: auto` to prevent memory saturation | *** ### Category Filter & Cards Reflow Use the adaptive density grid as an animated tab reflow system with search integration and interactive cards. # Textmoji Animated URL: https://www.spaceui.one/components/animoji *** title: Textmoji Animated description: Renders every Unicode emoji in a string as an animated image sized to the surrounding text. preview: name: demo-c-animoji-01 contained: false ---------------- ## Installation ## Usage ```tsx import { Animoji } from '@/components/spaceui/animoji' export default function Example() { return (

Ship your ideas faster 🚀

) } ``` For static emoji, use [Textmoji](/components/textmoji) instead — same API, different provider list. ## Examples ### Sources ### Unicode escapes & flags ### With Blur Reveal Text ## Props | Prop | Type | Default | Description | | ---------------- | ---------------------------------- | ---------- | --------------------------------------------------------- | | `children` | `string` | — | The text to scan | | `source` | `'fluent' \| 'telegram' \| 'noto'` | `'fluent'` | Provider to render — only the ones with an animated style | | `className` | `string` | — | Class on the outer wrapper | | `emojiClassName` | `string` | — | Class applied to each rendered emoji image | # Aurora Glow Button URL: https://www.spaceui.one/components/aurora-glow-button *** title: Aurora Glow Button description: A button with a hover-reactive radial aurora gradient, an animated conic-gradient border, and a rotating shine sweep. preview: name: demo-c-aurora-glow-button-01 ---------------------------------- ## Installation # Autoscale Input URL: https://www.spaceui.one/components/autoscale-input *** title: Autoscale Input description: Input that binary-searches a font size so the value always fills the available width, with locale number formats. preview: demo-c-autoscale-input-01 ---------------------------------- ## Installation ## Usage ```tsx import { AutoscaleInput } from '@/components/spaceui/autoscale-input' export default function SpaceUI() { return } ``` ## Files | File | Role | | --------------------------- | ------------------------------------------------ | | `autoscale-input/index.tsx` | Format helpers, `useAutoscale`, `AutoscaleInput` | ## API Reference | Prop | Type | Default | Description | | -------------------- | --------------------------------------------------------------- | ------- | --------------------------------------- | | `numberFormat` | `'us' \| 'eu' \| 'space' \| 'ch' \| 'in' \| 'none' \| 'string'` | `'us'` | Grouping / decimal style | | `prefix` | `string` | `'$'` | Leading glyph, scales with the value | | `suffix` | `string` | `''` | Trailing glyph | | `minSize` | `number` | `18` | Minimum font size in px | | `maxSize` | `number` | `100` | Maximum font size in px | | `containerClassName` | `string` | — | Outer width wrapper | | `wrapperClassName` | `string` | — | Flex row around prefix / input / suffix | All native `` props are forwarded. Mobile text stays `text-base`. # Avatar Extended URL: https://www.spaceui.one/components/avatar-extended *** title: Avatar Extended description: Extended Avatar components with rings, status badges, indicators, icons, and a built-in procedural fallback powered by the SpaceUI Avatars API. preview: demo-p-avatar-05 ------------------------- ## Installation ## Anatomy ```tsx import { Avatar, AvatarImage } from '@/components/ui/avatar' import { AvatarExtended, AvatarFallback, AvatarRing, AvatarBadge, AvatarIndicator, AvatarIcon, } from '@/components/spaceui/avatar-extended' export default () => ( U +6 ) ``` ## Features ### Verified Icon & Company Logo Use the `AvatarIcon` component to display small status indicators, verified badges, or company logos at the corner of the avatar. ### Avatar Rings Apply custom selection states or decorative borders using the `AvatarRing` component with standard utility classes. ### AvatarFallback Generates a procedural avatar image from a name via the [SpaceUI Avatars API](https://avatars.spaceui.one). It replaces the primitive `` with a rich, generated image instead of initials. #### AvatarFallback Variants Pass a `variant` prop to choose a specific style family. Defaults to `'all'` which lets the API pick a random style. ### Avatar Badges (Counts) Display unread notifications or counters cleanly over the avatar using the `AvatarBadge` component. ## API Reference ### AvatarFallback Generates a procedural avatar image from the SpaceUI Avatars API. Extends `React.ImgHTMLAttributes`. | Prop | Type | Default | Description | | :-------- | :-------------- | :------ | :---------------------------------------------------------------------- | | `name` | `string` | - | The name used to seed the avatar. Falls back to `children` if a string. | | `variant` | `AvatarVariant` | `'all'` | The visual style family. `'all'` picks a random variant. | **`AvatarVariant`** values: | Family | Variants | | :---------- | :--------------------------------------------------------------------- | | Gradient | `lumina` `shaula` `singularity` `triton` `solar-flare` `titan` `glass` | | Fluid | `splash` `astronaut` `ghost` `bot` `glitch` `animals` | | Classic | `pebble` `invader` `grunge` `bored` `doodle` `squiggle` | | Paletteless | `critter` `kendo` | | All | `all` (random — default) | *** ### AvatarExtended The root wrapper component that establishes the relative positioning context. Extends `React.HTMLAttributes`. | Prop | Type | Default | Description | | :--------- | :---------- | :------ | :------------------------------------------------------------ | | `children` | `ReactNode` | - | Must contain an `Avatar` and any of the extension components. | *** ### AvatarRing An absolute overlay that applies a decorative ring or focus outline around the avatar. Extends `React.HTMLAttributes`. *No specific props. Use `className` to pass Tailwind ring utility classes (e.g. `ring-primary ring-offset-2`).* *** ### AvatarIndicator A small status dot positioned at the bottom right by default, used for online/offline states. Extends `React.HTMLAttributes`. *No specific props. Use `className` to set the color (e.g. `bg-emerald-500`).* *** ### AvatarBadge A notification counter or badge positioned at the top right. It wraps the standard `Badge` primitive. Extends `BadgeProps`. | Prop | Type | Default | Description | | :-------- | :------------------------------------------------------------------------------------------------------ | :---------- | :-------------------------------------------------- | | `variant` | `"default" \| "destructive" \| "error" \| "info" \| "outline" \| "secondary" \| "success" \| "warning"` | `"default"` | The visual variant of the badge. | | `size` | `"default" \| "sm" \| "lg"` | `"sm"` | The size of the badge. | | `square` | `boolean` | `true` | Forces a square ratio for numbers. Fixed to `true`. | *** ### AvatarIcon A wrapper used to absolutely position small icons, logos, or verified checkmarks at the bottom right. Extends `React.HTMLAttributes`. | Prop | Type | Default | Description | | :--------- | :---------- | :------ | :----------------------------------- | | `children` | `ReactNode` | - | The icon or logo element to display. | # Avatar Group URL: https://www.spaceui.one/components/avatar-group *** title: Avatar Group description: A component for rendering a group of avatars, supporting different stacking directions and action buttons. preview: demo-p-avatar-07 ------------------------- ## Installation ## Usage ```tsx import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { AvatarGroup, AvatarGroupAction } from '@/components/spaceui/avatar-group' ``` ```tsx U1 U2 +4 ``` ## Features ### With Actions Use the `AvatarGroupAction` component to add an interactive trailing element. It can contain text indicating remaining users or an icon for interaction (e.g., a plus button to add members). ## API Reference ### AvatarGroup Props | Prop | Type | Default | Description | | ---------- | ------------------- | --------- | -------------------------------------------------- | | `stacking` | `"left" \| "right"` | `"right"` | Controls the visual z-index overlap of the avatars | # Badge Squircle URL: https://www.spaceui.one/components/badge-squircle *** title: Badge Squircle description: Tactile squircle badge components featuring dynamic curvature morphing on hover with polymorphic Base UI render support. preview: name: demo-c-badge-squircle-01 ------------------------------ ## Installation ## Anatomy ```tsx import { Badge } from '@/components/spaceui/badge-squircle' export default function Example() { return ( Badge label ) } ``` ## Features ### Sizes ### Icons & Polymorphic Links ## Props ### BadgeSquircle | Prop | Type | Default | Description | | ---------- | ----------------------------------------------------------------------------------------------- | ----------- | -------------------------------------------------------------------- | | `variant` | `'default' \| 'primary' \| 'secondary' \| 'outline' \| 'destructive' \| 'inverted' \| 'accent'` | `'default'` | Visual styling variant | | `size` | `'xs' \| 'sm' \| 'default' \| 'md' \| 'lg'` | `'default'` | Dimensions and font scaling scale | | `squircle` | `boolean` | `true` | Enables continuous curvature corner squircle mask | | `circle` | `boolean` | `false` | Aspect ratio square modifier | | `render` | `React.ReactElement \| ((props: any) => React.ReactNode)` | - | Polymorphic Base UI render element (e.g. Next.js Link or ` ) } ``` ## Features ### Sizes ### Icon Sizes ## Props ### ButtonSquircle | Prop | Type | Default | Description | | ---------- | --------------------------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------- | | `variant` | `'primary' \| 'secondary' \| 'destructive' \| 'outline' \| 'ghost' \| 'icon' \| 'link'` | `'primary'` | Visual styling variant | | `size` | `'xs' \| 'sm' \| 'default' \| 'lg' \| 'icon-xs' \| 'icon-sm' \| 'icon' \| 'icon-lg'` | `'default'` | Dimensions and padding | | `squircle` | `boolean` | `true` | Enables continuous curvature corner squircle mask | | `render` | `React.ReactElement \| ((props: any) => React.ReactNode)` | - | Polymorphic Base UI render element (e.g. Next.js Link or ``) | | `full` | `boolean` | `false` | Stretches button to 100% width (supports legacy `asFull`) | | `icon` | `boolean` | `false` | Adjusts svg sizing behavior for pure icon content (supports legacy `asIcon`) | | `pointer` | `boolean` | `false` | Applies explicit cursor-pointer styling (supports legacy `asPointer`) | | `hover` | `boolean` | `false` | Subtle hover scale tactile feedback (supports legacy `whileTap`) | # Chroma Palette URL: https://www.spaceui.one/components/chroma-palette *** title: Chroma Palette description: Perceptually uniform color generator and interactive swatch palette with organic gooey fluid morph and one-click copy. preview: demo-c-chroma-palette-01 --------------------------------- ## Installation ## Usage ```tsx import { ChromaPalette } from '@/components/spaceui/chroma-palette' export default function Example() { return } ``` ## Props | Prop | Type | Default | Description | | ----------------- | ---------------------------- | ----------- | ----------------------------------------------- | | `count` | `number` | `5` | Number of color swatches (min 2, max 5) | | `corner` | `number` | `14` | Swatch corner radius | | `morph` | `number` | `50` | Morphing animation speed / intensity (0-100) | | `palettes` | `string[][]` | `undefined` | Optional array of preset color palettes | | `onGenerate` | `() => string[]` | `undefined` | Custom palette generation callback | | `onPaletteChange` | `(colors: string[]) => void` | `undefined` | Callback invoked when a new palette is selected | # Cloud URL: https://www.spaceui.one/components/cloud *** title: Cloud description: Volumetric cloud material. Color the sky, sun, and shadows, then fly the camera with mouse or touch. preview: demo-c-cloud-01 defaultMode: split ------------------ Volumetric Vanta CLOUDS math in WGSL (`vgpu`). The canvas renders at `devicePixelRatio / 3` (desktop) like the original Vanta runtime — full retina would raymarch \~115 steps per pixel and stall the page. ## Installation Depends on `vgpu`. WebGPU required. ## Files | File | Role | | ---------------------- | ----------------------------------------------- | | `cloud/index.tsx` | vgpu surface, mouse ease, low-DPR backing store | | `cloud/clouds.wgsl.ts` | Raymarched fbm clouds (map2–map5) | ## Usage ```tsx import { Cloud } from '@/components/shader/cloud' export default function SpaceUI() { return } ``` ## API Reference ### Cloud | Prop | Type | Default | Description | | ------------ | -------- | --------- | ---------------- | | `bg` | `string` | `#ffffff` | Scene background | | `sky` | `string` | `#68b8d7` | Sky tint | | `cloudColor` | `string` | `#adc1de` | Cloud volume | | `shadow` | `string` | `#183550` | Cloud shadow | | `sun` | `string` | `#ff9919` | Sun disc | | `glare` | `string` | `#ff6633` | Sun glare | | `sunlight` | `string` | `#ff9933` | Direct light | | `speed` | `number` | `1` | Drift speed | | `className` | `string` | — | Wrapper class | # Data Grid URL: https://www.spaceui.one/components/data-grid *** title: Data Grid description: Displays large datasets in an interactive table where users can sort, filter, paginate, and resize columns to analyze data efficiently. component: true base: base links: api: [https://tanstack.com/table/latest](https://tanstack.com/table/latest) preview: name: demo-c-data-grid-01 align: start className: '\*\*:\[.preview]:h-auto' ------------------------------------ The current `data-grid` package ships the shared grid context, table renderers, pagination, column controls, drag-and-drop helpers, virtualization, infinite scroll, footer helpers, and row-pinning support. Footer components (`DataGridTableFoot`, `DataGridTableFootRow`, `DataGridTableFootRowCell`) and the `DataGridTableRowPin` toggle are exported from `data-grid-table.tsx`. In the base build, `data-grid-scroll-area.tsx` is also included and exports `DataGridScrollArea` for dedicated scroll handling around sticky-header or wide tables. ## Installation ## React Compiler TanStack Table v8 returns a stable table instance whose state mutates internally (the reference itself never changes). React Compiler memoizes reads against that stable reference, so state updates can be skipped. In practice that shows up as stale row-selection checkboxes, frozen sort arrows, and unresponsive pin or pagination controls. The fix is the `"use no memo"` directive, which opts a file out of the compiler. It is an inert no-op when React Compiler is not enabled, and is the recommended interim until TanStack Table v9's compiler-native API lands. **Already handled for you.** Every Space UI data-grid file you install (the primitive and the examples) already ships with `"use no memo"`, so installed Space UI code is safe out of the box. **What you must do.** If you enable React Compiler, add `"use no memo"` to your own component that calls `useReactTable`, the one file Space UI cannot reach: ```tsx 'use client' 'use no memo' // required only when React Compiler is enabled export function MyTable() { const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel(), }) return ( {/* ... */} ) } ``` Prefer excluding a whole directory over a per-file directive? Configure it in your compiler setup instead (Vite example): ```ts babel({ presets: [reactCompilerPreset()], exclude: ['**/components/spaceui/data-grid/**', '**/your-tables/**'], }) ``` On Next.js, prefer the per-file `"use no memo"` directive, since its SWC compiler exclusion is more limited. ## Usage ```tsx import { DataGrid, DataGridContainer, DataGridPagination, DataGridTable, DataGridTableFootRow, DataGridTableFootRowCell, } from '@/components/spaceui/data-grid' export default function SpaceUI() { const footer = ( Showing {data.length} rows ) const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel(), }) return ( ) } ``` Use `DataGridTableRowPin` inside a column definition to let users pin rows, swap in `DataGridTableVirtual` when you need virtualization or infinite scroll, and wrap sticky-header tables with `DataGridScrollArea` when you want the dedicated base scroll wrapper. When rows can be pinned or virtualized, provide a stable `getRowId` so row identity stays intact across reordering. ## Examples ### Cell Border ### Dense Table ### Light Table ### Striped Table ### Auto Width ### Row Selection For the full set of variations — expandable rows, sub-grids, sortable / movable / draggable / resizable / pinnable columns, sticky header, column controls and visibility, loading skeleton, CRUD in frame, footer totals / summary / aggregates, infinite scroll, and row pinning — browse the [Data Grid components](/ui-kit/components/spaceui/data-grid). ## API Reference ### DataGrid The root component that provides the table context. | Prop | Type | Default | Description | | :--------------------- | :------------------------ | :--------------------- | :--------------------------------------------------------------------- | | `table` | `Table` | - | `Required`. The TanStack Table instance. | | `recordCount` | `number` | - | `Required`. Total number of records. | | `isLoading` | `boolean` | `false` | Whether the table is in a loading state. | | `loadingMode` | `"skeleton" \| "spinner"` | `"skeleton"` | The visual style of the loading state. | | `loadingMessage` | `ReactNode \| string` | `"Loading..."` | Message to display when `loadingMode` is `"spinner"`. | | `fetchingMoreMessage` | `ReactNode \| string` | `loadingMessage` | Message to display while `DataGridTableVirtual` is fetching more rows. | | `allRowsLoadedMessage` | `ReactNode \| string` | `"All records loaded"` | Message to display when virtual infinite scroll reaches the end. | | `emptyMessage` | `ReactNode \| string` | `"No data available"` | Message to display when the table is empty. | | `onRowClick` | `(row: TData) => void` | - | Callback function triggered when a row is clicked. | | `tableLayout` | `DataGridTableLayout` | - | Configuration for table layout and features. | | `tableClassNames` | `DataGridTableClassNames` | - | Custom CSS classes for various table parts. | | `className` | `string` | - | Additional CSS classes for the root grid component. | *** ### DataGridTableLayout Configuration object for the table's behavior and appearance. | Property | Type | Default | Description | | :------------------ | :------------------ | :-------- | :---------------------------------------------------------- | | `dense` | `boolean` | `false` | Whether to use dense padding for cells. | | `cellBorder` | `boolean` | `false` | Whether to show vertical borders between cells. | | `rowBorder` | `boolean` | `true` | Whether to show horizontal borders between rows. | | `rowRounded` | `boolean` | `false` | Whether to add rounded corners to rows. | | `stripped` | `boolean` | `false` | Whether to use zebra-striping for rows. | | `headerBackground` | `boolean` | `true` | Whether to show a background color for the header. | | `headerBorder` | `boolean` | `true` | Whether to show a border below the header. | | `headerSticky` | `boolean` | `false` | Whether the header should be sticky during scroll. | | `width` | `"auto" \| "fixed"` | `"fixed"` | The table layout algorithm (`table-auto` vs `table-fixed`). | | `columnsVisibility` | `boolean` | `false` | Enables column visibility toggling. | | `columnsResizable` | `boolean` | `false` | Enables column resizing. | | `columnsPinnable` | `boolean` | `false` | Enables column pinning. | | `columnsMovable` | `boolean` | `false` | Enables moving columns via menu. | | `columnsDraggable` | `boolean` | `false` | Enables drag-and-drop for columns. | | `rowsDraggable` | `boolean` | `false` | Enables drag-and-drop for rows. | | `rowsPinnable` | `boolean` | `false` | Enables row pinning (top/bottom). | *** ### DataGridTableClassNames Custom CSS classes for different parts of the table. | Property | Type | Default | Description | | :------------- | :------- | :------ | :------------------------------------------------- | | `base` | `string` | - | CSS classes for the `` element. | | `header` | `string` | - | CSS classes for the `` element. | | `headerRow` | `string` | - | CSS classes for header rows. | | `headerSticky` | `string` | - | CSS classes for sticky header state. | | `body` | `string` | - | CSS classes for the `` element. | | `bodyRow` | `string` | - | CSS classes for body rows. | | `footer` | `string` | - | CSS classes for the `` element. | | `edgeCell` | `string` | - | CSS classes for the first and last cells in a row. | *** ### DataGridContainer A scrollable container for the table. | Prop | Type | Default | Description | | :---------- | :-------- | :------ | :--------------------------------------------- | | `border` | `boolean` | `true` | Whether to show a border around the container. | | `className` | `string` | - | Additional CSS classes for the container. | *** ### DataGridScrollArea Dedicated scroll wrapper for wide grids and sticky headers. | Prop | Type | Default | Description | | :------------ | :------------------------------------- | :------- | :-------------------------------------- | | `children` | `ReactNode` | - | `Required`. The grid content to wrap. | | `orientation` | `"horizontal" \| "vertical" \| "both"` | `"both"` | Which scrollbars to render. | | `className` | `string` | - | Additional CSS classes for the wrapper. | *** ### DataGridTable The component that renders the actual HTML table. It automatically handles data rendering, loading states (skeletons/spinners), empty states, footer rows, and pinned rows when `rowsPinnable` is enabled on the parent `DataGrid`. | Prop | Type | Default | Description | | :-------------- | :---------- | :------ | :------------------------------------------------- | | `footerContent` | `ReactNode` | - | Optional footer content rendered inside ``. | | `renderHeader` | `boolean` | `true` | Whether to render the table header. | *** ### DataGridPagination The component for table pagination controls. | Prop | Type | Default | Description | | :------------------ | :--------- | :--------------------------- | :---------------------------------------------------- | | `sizes` | `number[]` | `[5, 10, 25, 50, 100]` | Array of available page sizes. | | `sizesLabel` | `string` | `"Show"` | Label for the page size selector. | | `sizesDescription` | `string` | `"per page"` | Description following the page size selector. | | `rowsPerPageLabel` | `string` | `"Rows per page"` | Accessible label for the rows per page selector. | | `info` | `string` | `"{from} - {to} of {count}"` | Template for displaying record info. | | `more` | `boolean` | `false` | Whether to show ellipsis for more pages. | | `moreLimit` | `number` | `5` | The number of page buttons to show before truncating. | | `previousPageLabel` | `string` | `"Go to previous page"` | Accessible label for the previous page button. | | `nextPageLabel` | `string` | `"Go to next page"` | Accessible label for the next page button. | | `ellipsisText` | `string` | `"..."` | Text to display for the ellipsis button. | | `className` | `string` | - | Additional CSS classes for the pagination container. | *** ### DataGridColumnHeader A flexible column header component with built-in support for sorting, pinning, and moving columns. | Prop | Type | Default | Description | | :----------- | :---------------------- | :------ | :--------------------------------------------------------- | | `column` | `Column` | - | `Required`. The TanStack Column instance. | | `title` | `string` | - | The title to display in the header. | | `icon` | `ReactNode` | - | Optional icon to display next to the title. | | `filter` | `ReactNode` | - | Optional filter component to display in the header menu. | | `visibility` | `boolean` | `false` | Whether to include column visibility controls in the menu. | *** ### DataGridColumnFilter A popover-based multi-select filter for columns. | Prop | Type | Default | Description | | :-------- | :-------------------------------------------------------------- | :------ | :------------------------------------------------ | | `column` | `Column` | - | The TanStack Column instance to filter. | | `title` | `string` | - | The title for the filter trigger and placeholder. | | `options` | `Array<{ label: string, value: string, icon?: ComponentType }>` | - | `Required`. The list of options to filter by. | *** ### DataGridColumnVisibility A dropdown component to toggle column visibility. | Prop | Type | Default | Description | | :-------- | :------------- | :------ | :------------------------------------------------------- | | `table` | `Table` | - | `Required`. The TanStack Table instance. | | `trigger` | `ReactElement` | - | `Required`. The trigger element for the visibility menu. | *** ### DataGridTableDnd Used for enabling column drag-and-drop reordering with optional footer rendering. | Prop | Type | Default | Description | | :-------------- | :------------------------------ | :------ | :---------------------------------------------------------------- | | `handleDragEnd` | `(event: DragEndEvent) => void` | - | `Required`. Callback triggered when a column drag operation ends. | | `footerContent` | `ReactNode` | - | Optional footer content rendered inside ``. | *** ### DataGridTableDndRows Used for enabling row drag-and-drop reordering with optional footer rendering. | Prop | Type | Default | Description | | :-------------- | :------------------------------ | :------ | :----------------------------------------------------------------- | | `dataIds` | `UniqueIdentifier[]` | - | `Required`. Array of unique identifiers for the current page data. | | `handleDragEnd` | `(event: DragEndEvent) => void` | - | `Required`. Callback triggered when a row drag operation ends. | | `footerContent` | `ReactNode` | - | Optional footer content rendered inside ``. | *** ### DataGridTableVirtual A virtualized table renderer using `@tanstack/react-virtual` for row virtualization, infinite scroll, optional footer rows, and pinned rows when `rowsPinnable` is enabled. The wrapper manages row count and the scroll element for you, while `virtualizerOptions` lets you customize the underlying TanStack Virtual instance. Set `scrollToRowIndex` to reveal a controlled center row; `"auto"` alignment keeps already-visible rows in place and accounts for sticky headers. | Prop | Type | Default | Description | | :------------------- | :--------------------------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------- | | `height` | `number \| string` | - | Optional fixed height when not using an outer scroll container. | | `estimateSize` | `number` | `48` | Estimated row height in pixels for the virtualizer. | | `overscan` | `number` | `10` | Number of rows to render outside the visible area. | | `scrollBehavior` | `ScrollBehavior` | `"auto"` | Scroll animation used when revealing `scrollToRowIndex`. | | `scrollToRowAlign` | `"auto" \| "center" \| "start" \| "end"` | `"auto"` | Alignment used when revealing the target row. `"auto"` only scrolls when the row is outside the visible area. | | `scrollToRowIndex` | `number` | - | Index within the center (non-pinned) row section to reveal. Supports custom scroll elements and disabled virtualization. | | `footerContent` | `ReactNode` | - | Optional footer content rendered inside ``. | | `renderHeader` | `boolean` | `true` | Whether to render the table header. | | `onFetchMore` | `() => void` | - | Callback triggered when user scrolls near the bottom. | | `isFetchingMore` | `boolean` | - | Whether additional data is currently being loaded. | | `hasMore` | `boolean` | - | Whether there are more records available to fetch. | | `fetchMoreOffset` | `number` | `0` | How many rows before the end should trigger `onFetchMore`. | | `virtualizerOptions` | `DataGridTableVirtualizerOptions` | - | Optional passthrough for TanStack Virtual settings like `enabled`, `getItemKey`, `measureElement`, `rangeExtractor`, and `onChange`. | *** ### DataGridTableRowPin A pin/unpin toggle button for use in column definitions to enable row pinning. | Prop | Type | Default | Description | | :---- | :----------- | :------ | :------------------------------------------- | | `row` | `Row` | - | `Required`. The TanStack Table row instance. | *** ### DataGridTableFoot Wrapper component for the table footer (``). *** ### DataGridTableFootRow A row inside the table footer. *** ### DataGridTableFootRowCell A cell inside a footer row. | Prop | Type | Default | Description | | :---------- | :---------- | :------ | :------------------------------- | | `colSpan` | `number` | - | Column span for the footer cell. | | `className` | `string` | - | Additional CSS classes. | | `children` | `ReactNode` | - | Content of the footer cell. | *** ### DOM Attributes Data rows carry these attributes so you can target them from queries, tests, and styles. They are applied by the shared row renderer, so they appear on standard, virtualized, pinned, and draggable rows alike. Spacer, skeleton, empty, and expanded-detail rows are rendered separately and carry none of them. | Attribute | Value | Description | | :---------------- | :------------------ | :------------------------------------------------------------------------------------------------------------------------------------- | | `data-row-id` | `string` | The resolved TanStack Table row id, respecting any `getRowId` configuration. Stable across sorting and pagination. | | `data-index` | `number` | Position of the row within the rendered rows, used for virtual measurement and striping. Omitted when the renderer does not supply it. | | `data-row-pinned` | `"top" \| "bottom"` | Which edge the row is pinned to. Omitted entirely when the row is not pinned. | ## All 29 variations ### Data grid with expandable rows ### Data grid with sub table ### Data grid with column icons ### Data grid with sortable columns ### Data grid with movable columns ### Data grid with draggable columns ### Data grid with draggable rows ### Data grid with column resizing ### Data grid with pinnable columns ### Data grid with sticky header ### Data grid with column controls ### Data grid with card container ### Data grid with column visibility controls ### Data grid with loading skeleton ### Data grid with CRUD features ### Data grid with CRUD in frame container ### Data grid with column totals footer ### Data grid with summary stats footer ### Data grid with per-column aggregate footer ### Data grid with local infinite scroll ### Data grid with remote infinite scroll ### Data grid with row pinning support # Date Selector URL: https://www.spaceui.one/components/date-selector *** title: Date Selector description: Allows users to quickly choose single dates or time ranges using interactive timeline scrubbers and preset shortcut buttons. component: true base: base preview: name: demo-c-date-selector-01 align: start className: '\*\*:\[.preview]:h-auto!' ------------------------------------- ## Installation ## Usage ```tsx import * as React from 'react' import { DateSelector, type DateSelectorValue } from '@/components/spaceui/date-selector' export default function SpaceUI() { const [value, setValue] = React.useState() return } ``` ## Examples ### With Popover ### With Dialog ### With i18n Support ## API Reference ### DateSelector The main component for selecting dates and time periods. | Prop | Type | Default | Description | | :------------------ | :----------------------------------- | :------------------------- | :----------------------------------------------------------------------- | | `value` | `DateSelectorValue` | - | The current value of the selector. | | `onChange` | `(value: DateSelectorValue) => void` | - | Callback fired when the value changes. | | `allowRange` | `boolean` | `true` | Whether to allow selecting date ranges (using "between" operator). | | `periodTypes` | `DateSelectorPeriodType[]` | - | List of available period types (day, month, etc.). | | `defaultPeriodType` | `DateSelectorPeriodType` | `"day"` | The initial period type. | | `defaultFilterType` | `DateSelectorFilterType` | `"is"` | The initial filter operator. | | `presetMode` | `DateSelectorFilterType` | - | If set, locks the selector to this specific filter mode. | | `showInput` | `boolean` | `true` | Whether to show the text input field above the selector. | | `showTwoMonths` | `boolean` | `true` | Whether to show two months in the calendar view (desktop only). | | `label` | `string` | - | Optional label to display above the filter toggle. | | `yearRange` | `number` | `10` | The number of years to show in the year/month/quarter list. | | `baseYear` | `number` | `new Date().getFullYear()` | The reference year for the year selection list. | | `minYear` | `number` | `2015` | The minimum selectable year. | | `maxYear` | `number` | `2026` | The maximum selectable year. | | `i18n` | `Partial` | - | Custom labels and operators for internationalization. | | `inputHint` | `string` | - | Optional hint text to display in the input field when empty and focused. | | `dayDateFormat` | `string` | `"MM/dd/yyyy"` | The format used to display single days. | | `className` | `string` | - | Additional CSS classes for the container. | *** ### Interfaces #### DateSelectorValue The structure of the value returned by the `onChange` callback. | Property | Type | Description | | :----------- | :-------------------------------- | :------------------------------------------------------------------------- | | `period` | `DateSelectorPeriodType` | The selected period type (`day`, `month`, `quarter`, `half-year`, `year`). | | `operator` | `DateSelectorFilterType` | The selected operator (`is`, `before`, `after`, `between`). | | `startDate` | `Date` | The selected start date (for `day` period). | | `endDate` | `Date` | The selected end date (for `day` period range). | | `year` | `number` | The selected year. | | `month` | `number` | The selected month (0-11). | | `quarter` | `number` | The selected quarter (0-3). | | `halfYear` | `number` | The selected half-year (0-1). | | `rangeStart` | `{ year: number; value: number }` | The start of a period range. | | `rangeEnd` | `{ year: number; value: number }` | The end of a period range. | # Detachable Accordion URL: https://www.spaceui.one/components/detachable-accordion *** title: Detachable Accordion description: An interactive accordion with spring motion where the expanded item physically detaches with animated gaps and rounded corners. preview: name: demo-c-detachable-accordion-01 contained: false ---------------- ## Installation ## Usage ```tsx import { DetachableAccordion } from '@/components/spaceui/detachable-accordion' ``` ```tsx ``` ## API Reference ### DetachableAccordion Props | Prop | Type | Default | Description | | --------------- | -------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------- | | `items` | `DetachableAccordionItem[]` | `DEFAULT_ITEMS` | List of items containing `value`, `title`, `content`, and optional `icon` | | `value` | `string` | - | Controlled expanded item value | | `defaultValue` | `string` | `""` | Initial expanded item value | | `onValueChange` | `(value: string \| undefined) => void` | - | Callback triggered when the expanded item changes | | `detachGap` | `number` | `16` | Spacing in pixels created above and below the active item | | `cornerRadius` | `number` | `24` | Border radius in pixels applied to the active item and neighboring edges | | `spring` | `Transition` | `mass: 10, stiffness: 900, damping: 80` | Motion spring configuration for detachment and icon rotation | | `className` | `string` | - | Additional class name applied to outer container | # Dirt Carousel URL: https://www.spaceui.one/components/dirt-carousel *** title: Dirt Carousel description: 3D ring of video worlds. Drag, wheel, or snap. Open the gear panel to change radius, tilt, and auto-rotate. preview: demo-c-dirt-carousel-01 -------------------------------- Interactive 3D cylindrical ring carousel. Drag, wheel, or snap between cards. Items, dimensions, and motion physics are configurable via props. ## Installation ## Usage ```tsx import { DirtCarousel, type DirtCarouselItem } from '@/components/spaceui/dirt-carousel' const items: DirtCarouselItem[] = [ { name: 'Brand', mediaType: 'video', videoLink: 'https://...', thumbnail: 'https://...', }, { name: 'Showcase', mediaType: 'image', imageLink: 'https://...', }, ] export default function Example() { return } ``` ## Props | Prop | Type | Default | Description | | ----------------- | -------------------------- | -------- | --------------------------------------------- | | `items` | `DirtCarouselItem[]` | `[]` | Array of media items (video or image). | | `direction` | `'flat' \| 'up' \| 'down'` | `'flat'` | Orbital tilt angle of the 3D ring. | | `radius` | `number` | `800` | Radius of the circular orbit in pixels. | | `perspective` | `number` | `800` | 3D CSS perspective camera distance. | | `ballSize` | `number` | `800` | Size of each carousel item container. | | `dragSensitivity` | `number` | `0.5` | Drag speed multiplier. | | `bounce` | `boolean` | `false` | Floating / bounce animation up and down. | | `mouseTilt` | `boolean` | `false` | Tilts carousel towards the mouse pointer. | | `snap` | `boolean` | `true` | Snaps smoothly to nearest item when released. | | `autoRotate` | `boolean` | `false` | Enables continuous automatic rotation. | | `autoRotateSpeed` | `number` | `0.3` | Speed of auto rotation (items/second). | # Doodle Callout URL: https://www.spaceui.one/components/doodle-callout *** title: Doodle Callout description: A hand-drawn arrow that draws itself next to a handwritten label, replaying on a loop. preview: demo-c-doodle-callout-01 --------------------------------- ## Installation ## Usage ```tsx import { DoodleCallout } from '@/components/spaceui/doodle-callout' export default function PricingCard() { return (
Complete plan
) } ``` The stroke draws from start to end, then the label blur-reveals in place above it. The whole sequence replays every `loopInterval`. ## Props | Prop | Type | Default | Description | | ----------------- | -------- | --------------------- | ------------------------------------------------------------------------- | | `label` | `string` | — | The handwritten annotation text | | `path` | `string` | the hand-drawn stroke | SVG path `d`, animated from start to end | | `viewBox` | `string` | `'0 0 457 101'` | viewBox matching the path's coordinate space | | `width` | `number` | `280` | SVG width | | `height` | `number` | `62` | SVG height | | `strokeWidth` | `number` | `5` | Stroke width | | `revealGap` | `number` | `400` | Delay in ms between the stroke finishing and the label revealing | | `loopInterval` | `number` | `8000` | How often the sequence replays once settled, in ms — `0` disables looping | | `className` | `string` | — | Class on the outer wrapper | | `labelClassName` | `string` | — | Class on the label — pass your own script/cursive font here | | `strokeClassName` | `string` | — | Class on the SVG | # Event Calendar URL: https://www.spaceui.one/components/event-calendar *** title: Event Calendar description: Displays scheduled events across day, week, and month views, making it easy for users to create and manage appointments. component: true base: base preview: name: demo-c-event-calendar-01 align: start ------------ The demo above is the whole feature surface in one example: every view (month, week, day, N-days, agenda, and the resource time grid), a multi-day all-day bar, custom chips via `renderEvent`, and a tabbed Settings panel driving view settings, time-grid options, and interactions as controlled props - with a reset back to defaults. The `event-calendar` package separates the calendar engine from the calendar UI. A subscribable store (`useEventCalendarState`) owns events, view, date, selection, and interactions with controlled and uncontrolled modes for every state pair; the shipped view components (month, week, day, N-days, agenda, and a resource day grid) render from that store through fine-grained selector hooks. Events are yours: the calendar never persists anything, it proposes changes through `onEventUpdate` and you accept, adjust, or reject them. The composition contract is a provider plus slots: `` wraps ``, an optional ``, and ``. Recurrence (an RFC 5545 subset, structured rules or raw `RRULE` strings), display time zones via `@date-fns/tz`, pointer-based drag, resize, and drag-create, and per-key i18n overrides are built in. ## Installation ## Usage ```tsx import * as React from 'react' import { EventCalendar } from '@/components/spaceui/event-calendar/event-calendar' import { EventCalendarContent } from '@/components/spaceui/event-calendar/event-calendar-content' import { EventCalendarNav } from '@/components/spaceui/event-calendar/event-calendar-nav' import type { CalendarEvent } from '@/components/spaceui/event-calendar/event-calendar-types' export default function SpaceUI() { const [events, setEvents] = React.useState(initialEvents) return ( ) } ``` Pass `defaultEvents` for uncontrolled state or `events` + `onEventsChange` for controlled state; the same pairing exists for `view`, `date`, `dayCount`, `selection`, `interactions`, and `viewSettings`. In the default `scrollMode="contained"` the calendar fills its container and scrolls internally, so give the root an explicit height (the examples use `h-[560px]`). Every timing change, whether from a drag, a resize, or `api.updateEvent`, funnels through `onEventUpdate`: return `false` to reject and revert, return nothing (or `true`) to accept, or return `{ start, end, allDay }` to accept with an adjustment, then persist to your backend from `onEventsChange` or inside `onEventUpdate` itself. Use `onRangeChange` to fetch remote events for the visible range, and `apiRef` (or a hoisted `useEventCalendarState` instance passed as `calendar`) for imperative control from outside the tree. For more variations, browse the [Event Calendar components](/ui-kit/components/spaceui/event-calendar). ## API Reference ### EventCalendar The root provider and container. It creates (or adopts) the calendar instance, provides it via context, and renders a flex-column `div` (customizable through `render`). Besides the props below, it accepts every option and callback listed under [State options](#state-options) and [Callbacks](#callbacks), and every display prop listed under [View configuration](#view-configuration). | Prop | Type | Default | Description | | :---------- | :------------------------------------------- | :------ | :------------------------------------------------------------------------------------------------------------------------ | | `calendar` | `EventCalendarInstance` | - | Adopt a hoisted `useEventCalendarState` instance; option props are then ignored (a dev warning fires if both are passed). | | `apiRef` | `RefObject \| null>` | - | Imperative escape hatch; receives the instance API for use outside the tree. | | `children` | `ReactNode` | - | Composed slots, typically `EventCalendarNav`, `EventCalendarToolbar`, and `EventCalendarContent`. | | `className` | `string` | - | Additional CSS classes for the root element. | | `render` | `useRender` render prop | - | Replace the rendered root element. | *** ### EventCalendarNav Default composed navigation: Today, view switcher, prev/next, title, and a trailing spacer. Pass `children` to use it as a pure layout shell and compose the nav parts yourself. Renders as a `div` with `useRender` support. | Prop | Type | Default | Description | | :----------------- | :---------- | :------ | :------------------------------------------------------------------------------- | | `showViewSwitcher` | `boolean` | `true` | Render the view switcher in the composed layout; turn off for fixed-view embeds. | | `children` | `ReactNode` | - | Replaces the default composed layout entirely. | | `className` | `string` | - | Additional CSS classes for the nav container. | *** ### EventCalendarNavToday The "Today" navigation button; resets the calendar to now. It follows the configured `navButtonVariant` / `navButtonSize` and the `classNames.navButton` hook, and gets `data-active` while the anchor period contains now. `EventCalendarNavPrev` and `EventCalendarNavNext` share the same props. | Prop | Type | Default | Description | | :--------- | :---------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------- | | `tooltip` | `ReactNode \| null` | - | Hover/focus-visible hint. Today defaults to the current date; Prev/Next default to their i18n labels. Pass `null` to disable this one button. | | `children` | `ReactNode` | - | Replaces the default label or chevron icon. | | `render` | `useRender` render prop | - | Replace the rendered button element. | *** ### EventCalendarNavPrev The previous-period navigation button; steps the anchor date one period back for the current view. Same props as [`EventCalendarNavToday`](#eventcalendarnavtoday), except `tooltip` defaults to the i18n "previous" label and `children` replaces the default chevron icon. *** ### EventCalendarNavNext The next-period navigation button; steps the anchor date one period forward for the current view. Same props as [`EventCalendarNavToday`](#eventcalendarnavtoday), except `tooltip` defaults to the i18n "next" label and `children` replaces the default chevron icon. *** ### EventCalendarTitle The current period title (from `i18n.functions.formatTitle`), marked `aria-live="polite"`. | Prop | Type | Default | Description | | :------- | :-------------------------------------- | :------ | :----------------------------------------- | | `format` | `(ctx: { title: string }) => ReactNode` | - | Wrap or transform the computed title text. | *** ### EventCalendarViewSwitcher Dropdown listing the available views (the resolved `views` option) with optional keyboard-shortcut hints; when the `days` view is enabled, one item per `dayCountPresets` entry is offered. | Prop | Type | Default | Description | | :--------- | :------------------ | :------ | :------------------------------------------------------------------------------------------ | | `tooltip` | `ReactNode \| null` | - | Hover-only hint (force-closed while the menu is open); defaults to the "Select view" label. | | `children` | `ReactNode` | - | Replaces the default trigger content (current view name + chevron). | *** ### EventCalendarDatePicker Optional go-to-date popover (shadcn Calendar), not part of the default nav; compose it yourself. It is view-aware: week, N-days, and agenda highlight the whole active range, other views select a single date. | Prop | Type | Default | Description | | :--------- | :------------------------------ | :------- | :------------------------------------------------------------------------------ | | `mode` | `"auto" \| "single" \| "range"` | `"auto"` | `"auto"` resolves to `"range"` for week/N-days/agenda and `"single"` otherwise. | | `tooltip` | `ReactNode \| null` | `null` | No tooltip by default (the button opens an overlay); pass a node to opt in. | | `children` | `ReactNode` | - | Replaces the default calendar icon. | *** ### EventCalendarToolbar Free slot for consumer toolbar buttons; a pure layout shell (`flex items-center gap-2`) with `useRender` support and the `classNames.toolbar` hook. No props beyond standard `div` props. *** ### EventCalendarContent Active-view switchboard: renders the component registered for the current view and exposes `data-view` / `data-loading` attributes. While `loading` is true it dims and disables pointer events. | Prop | Type | Default | Description | | :----------- | :--------------------------------------------- | :------ | :----------------------------------------------------------------------------- | | `components` | `Partial>` | - | Swap individual view implementations (merged over the root `components` prop). | | `children` | `ReactNode` | - | Replaces the switchboard entirely; read `useEventCalendarView()` inside. | *** ### EventCalendarMonthView ARIA-grid month view: week rows, day cells, continuous multi-day bars in a lane overlay, "+N more" overflow, week numbers, and the day add affordance. | Prop | Type | Default | Description | | :----------------- | :----------------- | :------ | :------------------------------------------------------------------------- | | `maxEventsPerCell` | `number \| "auto"` | - | Per-view override of the `maxEventsPerCell` view config (bars plus chips). | *** ### EventCalendarTimeGrid The shared week/day/N-days engine: hour gutter, minute-positioned event blocks with overlap packing, the all-day row, drag ghosts, and the now indicator. You usually render one of the wrappers below instead. | Prop | Type | Default | Description | | :------------- | :-------------------------- | :------ | :---------------------------------------------------------------------------------------------- | | `view` | `"week" \| "day" \| "days"` | - | `Required`. Which time-based view this grid renders. | | `dayStartHour` | `number` | - | Per-view override of the `dayStartHour` option. | | `dayEndHour` | `number` | - | Per-view override of the `dayEndHour` option. | | `showAllDay` | `boolean` | `true` | Render the all-day row above the time track. | | `interval` | `number` | - | Gutter/gridline interval in minutes (clamped 5 to 240); defaults to the `interval` view config. | *** ### EventCalendarWeekView Thin wrapper around [`EventCalendarTimeGrid`](#eventcalendartimegrid) with `view` preset to `"week"`. Accepts every `EventCalendarTimeGrid` prop except `view`. *** ### EventCalendarDayView Thin wrapper around [`EventCalendarTimeGrid`](#eventcalendartimegrid) with `view` preset to `"day"`. Accepts every `EventCalendarTimeGrid` prop except `view`. *** ### EventCalendarDaysView Thin wrapper around [`EventCalendarTimeGrid`](#eventcalendartimegrid) with `view` preset to `"days"`. Accepts every `EventCalendarTimeGrid` prop except `view`. *** ### EventCalendarAgendaView Chronological list grouped by day: sticky date gutters, collapsible days with a color-dot summary row, expandable per-event details (via `renderAgendaEventDetails`), and a compact empty state. The agenda window length comes from the `agendaDayCount` option, so the view has no props beyond standard `div` props. *** ### EventCalendarResourceView Resource-columns day grid for booking scenarios: one time axis, one column per leaf resource (from the `resources` option, flattened depth-first), with full drag, resize, and drag-create across columns. | Prop | Type | Default | Description | | :------------- | :-------- | :------ | :---------------------------------------------------------------------------------------------- | | `dayStartHour` | `number` | - | Per-view override of the `dayStartHour` option. | | `dayEndHour` | `number` | - | Per-view override of the `dayEndHour` option. | | `showAllDay` | `boolean` | `true` | Render the all-day row above the time track. | | `interval` | `number` | - | Gutter/gridline interval in minutes (clamped 5 to 240); defaults to the `interval` view config. | *** ### EventCalendarApi The imperative API, available as `instance.api`, through `apiRef`, or from any hook's instance. Reading methods reflect the current snapshot; writing methods respect controlled props (they call the matching `on*Change` callback and only mutate internal state for uncontrolled fields). | Method | Signature | Description | | :--------------------- | :----------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------- | | `next` / `prev` | `() => void` | Step the anchor date one period forward or backward for the current view. | | `today` | `() => void` | Jump to now. | | `goTo` | `(date: Date) => void` | Jump to a date. | | `setView` | `(view: CalendarView, opts?: { dayCount?: number }) => void` | Switch view; unknown views fall back to the first enabled view with a dev warning. | | `setDayCount` | `(count: number) => void` | Set the N-day count (min 1). | | `getEvents` | `() => CalendarEvent[]` | Current events array. | | `getEvent` | `(id: string) => CalendarEvent \| undefined` | Find one event by id. | | `setEvents` | `(events: CalendarEvent[]) => void` | Replace the events array. | | `addEvent` | `(event: CalendarEvent) => void` | Append an event. | | `updateEvent` | `(id: string, patch: Partial>) => void` | Patch an event; timing patches route through `onEventUpdate` with `source: "api"`. | | `removeEvent` | `(id: string) => void` | Remove an event. | | `getOccurrences` | `(range?: EventCalendarDateRange) => EventCalendarOccurrence[]` | Expanded, sorted occurrences; defaults to the visible range. | | `getOccurrencesForDay` | `(day: Date) => EventCalendarOccurrence[]` | Deduplicated occurrences touching one day. | | `findOverlapping` | `(candidate: { start: Date; end: Date; excludeEventId?: string }) => EventCalendarOccurrence[]` | Occurrences overlapping a candidate range. | | `select` | `(selection: Partial) => void` | Patch the selection. | | `selectEvent` | `(key: string, opts?: { additive?: boolean }) => void` | Select an occurrence key; `additive` toggles it within the current set. | | `clearSelection` | `() => void` | Clear event keys and the committed slot. | | `setInteractions` | `(patch: Partial) => void` | Toggle drag, resize, or slot selection. | | `setViewSettings` | `(patch: EventCalendarViewSettings) => void` | Patch the user display toggles. | | `getVisibleRange` | `() => EventCalendarDateRange` | The full rendered grid range (including outside days); fetch remote data for this. | | `getActiveRange` | `() => EventCalendarDateRange` | The logical period (the month or week itself). | | `toZoned` | `(date: Date) => Date` | The instant re-expressed in the calendar's display time zone (a `TZDate`). | | `scrollToTime` | `(time: Date \| number) => void` | Scroll a time grid to an instant or minutes-from-day-start; no-op outside time-grid views. | *** ### CalendarEvent Your event objects. `TData` is a fully generic consumer payload. | Property | Type | Default | Description | | :----------------- | :-------------------------------------- | :------ | :----------------------------------------------------------------------------- | | `id` | `string` | - | `Required`. Stable event id. | | `title` | `string` | - | `Required`. Display title. | | `start` | `Date` | - | `Required`. Start instant (consumers parse ISO strings themselves). | | `end` | `Date` | - | `Required`. Exclusive end instant; must be greater than or equal to `start`. | | `allDay` | `boolean` | - | Render as an all-day bar; date comparison is day-granular in the display zone. | | `recurrence` | `EventCalendarRecurrenceRule \| string` | - | Structured rule or a raw `"RRULE:..."` line. | | `recurringEventId` | `string` | - | Marks this event as an edited single occurrence of that series. | | `originalStart` | `Date` | - | Which occurrence it replaces (RECURRENCE-ID semantics). | | `color` | `string` | - | Token or CSS color; flows to the `--ec-event-color` CSS variable. | | `readOnly` | `boolean` | - | Excluded from drag and resize regardless of the interactions state. | | `draggable` | `boolean` | - | Per-event override; the default comes from `interactions.drag`. | | `resizable` | `boolean` | - | Per-event override; the default comes from `interactions.resize`. | | `priority` | `number` | - | Packing prominence; feeds the `getEventPriority` ordering. | | `zIndex` | `number` | - | Explicit stacking override; wins over the computed z-index. | | `resourceId` | `string` | - | Bookable resource this event belongs to (resource view). | | `data` | `TData` | - | Consumer payload, fully generic. | *** ### EventCalendarResource A bookable resource (room, person, equipment). Nested resources render their leaves as booking columns in the resource view. | Property | Type | Default | Description | | :--------- | :------------------------ | :------ | :---------------------------------------------------------- | | `id` | `string` | - | `Required`. Stable resource id. | | `title` | `string` | - | `Required`. Column header text (or `renderResourceHeader`). | | `color` | `string` | - | Token or CSS color for subtle row/column accents. | | `children` | `EventCalendarResource[]` | - | Child resources; only leaves become booking columns. | *** ### EventCalendarRecurrenceRule The structured RFC 5545 subset. A raw `RRULE` string with the same parts is equally accepted on `event.recurrence`. | Property | Type | Default | Description | | :----------- | :------------------------------------------------------------------------------ | :------ | :------------------------------------------------------------------------------------------- | | `freq` | `"daily" \| "weekly" \| "monthly" \| "yearly"` | - | `Required`. Recurrence frequency. | | `interval` | `number` | `1` | Every N periods. | | `count` | `number` | - | Total number of occurrences. | | `until` | `Date` | - | Inclusive end instant. | | `byWeekday` | `Array` | - | Weekdays; ordinals (`2TU`, `-1FR`) apply to monthly/yearly rules. | | `byMonthDay` | `number[]` | - | Days of the month; negative values count back from month end. | | `byMonth` | `number[]` | - | Months (1 to 12) for yearly rules. | | `weekStart` | `EventCalendarWeekday` | - | WKST equivalent. | | `exDates` | `Date[]` | - | Excluded instants; matching occurrences are removed (they still consume their `count` slot). | | `rDates` | `Date[]` | - | Extra instants added to the series, each with the event's own duration. | `EventCalendarWeekday` is `"MO" \| "TU" \| "WE" \| "TH" \| "FR" \| "SA" \| "SU"`. For rule parts outside this subset, plug a full RRULE engine through the `getOccurrences` option; unsupported parts throw `EventCalendarRecurrenceError`. *** ### EventCalendarOccurrence One expanded instance of an event, as passed to click callbacks and returned by `api.getOccurrences`. | Property | Type | Description | | :---------------- | :--------------------- | :----------------------------------------------------- | | `key` | `string` | Stable per instance: `` `${event.id}::${startISO}` ``. | | `eventId` | `string` | The source event id. | | `event` | `CalendarEvent` | The source event. | | `start` / `end` | `Date` | This instance's instants (end exclusive). | | `allDay` | `boolean` | Resolved all-day flag. | | `isRecurring` | `boolean` | Whether it came from a recurrence expansion. | | `recurrenceIndex` | `number` | Series ordinal, when recurring. | *** ### EventCalendarSegment A per-day slice of an occurrence, produced by the event index and consumed by `EventCalendarEvent` and the layout hooks. Positional fields are filled per surface: `startMin` / `endMin` for timed blocks, `lane` / `column` / `columnCount` / `columnSpan` for packing, and `rowIndex` / `colStart` / `colSpan` for month/all-day bars. `isStart` / `isEnd` and `continuesBefore` / `continuesAfter` mark cross-day edges. *** ### EventCalendarProposedUpdate The payload of `onEventUpdate` and `canDropEvent`: a proposed timing (and optionally resource) change. | Property | Type | Description | | :----------- | :---------------------------------------------------------------- | :----------------------------------------------------------- | | `event` | `CalendarEvent` | The event being changed. | | `occurrence` | `EventCalendarOccurrence \| null` | The dragged occurrence; `null` when `source` is `"api"`. | | `start` | `Date` | Proposed start. | | `end` | `Date` | Proposed exclusive end. | | `allDay` | `boolean` | Proposed all-day flag. | | `resourceId` | `string` | Proposed resource when the gesture crossed resource columns. | | `source` | `"drag" \| "resize-start" \| "resize-end" \| "keyboard" \| "api"` | What produced the proposal. | The `onEventUpdate` return type is `EventCalendarUpdateResult`: `false` rejects and reverts, `void` or `true` accepts, and `{ start?, end?, allDay? }` accepts with an adjustment. *** ### EventCalendarSlotInfo The payload of `onSlotClick`. A click is a point, not a range. | Property | Type | Description | | :----------- | :------------- | :---------------------------------------------------------------------- | | `date` | `Date` | Clicked instant (snapped in time grids) or day (day-granular surfaces). | | `end` | `Date` | Present for timed slots: `date` plus `slotDuration`. | | `allDay` | `boolean` | Whether the click landed on a day-granular surface. | | `view` | `CalendarView` | The view the click happened in. | | `resourceId` | `string` | Present when the click happened inside a resource column. | *** ### EventCalendarSlotDraft The drag-create rectangle, passed to `onSelectSlot` and `canSelectSlot`. The in-progress draft lives in state as `slotDraft` and is cleared on commit or cancel; the committed slot selection lives in `selection.slot`. | Property | Type | Description | | :----------- | :------------- | :----------------------------------------------------------- | | `start` | `Date` | Draft start. | | `end` | `Date` | Draft exclusive end. | | `allDay` | `boolean` | Whether the draft was drawn on a day-granular surface. | | `view` | `CalendarView` | The view the draft was drawn in. | | `resourceId` | `string` | Present when the slot was selected inside a resource column. | *** ### EventCalendarState The store snapshot, as received by `useEventCalendarSelector` selectors and `instance.getState()`. | Property | Type | Description | | :------------- | :-------------------------------------- | :----------------------------------------------------------------------------------- | | `view` | `CalendarView` | Active view (`"month" \| "week" \| "day" \| "days" \| "agenda" \| "resource"`). | | `date` | `Date` | Anchor date. | | `dayCount` | `number` | Day count for the `days` view. | | `visibleRange` | `EventCalendarDateRange` | Full rendered grid range including outside days; fetch remote data for this. | | `activeRange` | `EventCalendarDateRange` | The logical period (the month or week itself). | | `events` | `CalendarEvent[]` | Current events. | | `selection` | `EventCalendarSelection` | Selected occurrence keys plus the committed slot. | | `interactions` | `EventCalendarInteractions` | Effective interaction toggles. | | `loading` | `boolean` | The `loading` prop. | | `drag` | `EventCalendarDragState \| null` | Live move/resize gesture (kind, occurrence, proposed instants, validity), or `null`. | | `slotDraft` | `EventCalendarSlotDraft \| null` | Live drag-create rectangle, or `null`. | | `viewSettings` | `EventCalendarViewSettings` | User display toggles. | `EventCalendarDateRange` is `{ start: Date; end: Date }` with an inclusive start and an exclusive end. The exported `EventCalendarDataAdapter` type (`getEvents(range, signal?)`) describes the shape of an external data source; wiring it to a backend is application territory. ## Hooks Most hooks require an `` ancestor. The exceptions: `useEventCalendarState` creates the instance itself, `useNow` is standalone, `useEventCalendarSettingsVersion` takes the instance as an argument, and hooks that accept an explicit `calendar` option work outside the tree. | Hook | Signature | Description | | :-------------------------------- | :-------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `useEventCalendarState` | `(options?: UseEventCalendarStateOptions) => EventCalendarInstance` | Headless root hook: the full engine without markup. Pass the instance to `` or drive fully custom UI from `getState` / `subscribe` / `api`. | | `useEventCalendar` | `() => EventCalendarInstance` | The stable calendar instance from context; throws outside ``. | | `useEventCalendarSelector` | `(selector: (state: EventCalendarState) => T, options?: { calendar?, isEqual? }) => T` | Fine-grained subscription with equality memoization (`Object.is` default). | | `useEventCalendarView` | `() => { view, dayCount, availableViews, setView }` | Active view state plus the resolved `views` option. | | `useEventCalendarNavigation` | `() => { date, title, visibleRange, activeRange, next, prev, today, goTo, isToday }` | Navigation state and actions; `title` is the formatted period title. | | `useEventCalendarSelection` | `() => { selection, select, selectEvent, clearSelection }` | Selection state and actions. | | `useEventCalendarInteractions` | `() => { interactions, setInteractions }` | Interaction toggles. | | `useEventCalendarOccurrences` | `(range?: EventCalendarDateRange) => EventCalendarOccurrence[]` | Expanded, sorted occurrences; defaults to the visible range. | | `useEventCalendarDay` | `(day: Date) => { segments: { allDay, timed }, isToday, isOutside }` | Per-cell subscription; only cells whose segments changed re-render. | | `useEventCalendarWeek` | `(day: Date) => { bars, laneCount, rowStart }` | Per-week-row subscription for the month view's laned multi-day bars. | | `useEventCalendarViewSettings` | `() => { viewSettings, setViewSettings, effective }` | User display toggles plus the effective values after view-config fallback. | | `useEventCalendarSettings` | `() => EventCalendarSettings` | Resolved settings including merged i18n; re-renders only when settings change. | | `useEventCalendarSettingsVersion` | `(instance: EventCalendarInstance) => number` | Subscribes to settings changes only (version counter, not state). | | `useEventCalendarViewConfig` | `() => EventCalendarViewConfig` | Root-level display props and render overrides, for view components. | | `useEventCalendarViewContext` | `() => { view: CalendarView }` | The rendering view of the nearest view component; throws outside a view. | | `useEventCalendarGestures` | `() => { beginMove, beginResize, beginCreate, canDrag, canResize }` | Per-chip / per-surface pointer gesture wiring for custom views and cells. | | `useEventCalendarEventChip` | `() => { occurrence, segment, isDragging, isSelected }` | The chip's subject; usable inside `renderEvent` content and chip children. | | `useNow` | `(intervalMs?: number) => Date` | Current time, refreshed on an interval (default 30000 ms) and on tab focus. | An `EventCalendarInstance` is `{ getState, subscribe, api, settings, internals }`; `internals` is cross-file plumbing for sibling view modules and not public API. ## Helpers Pure, React-free helpers exported from `event-calendar-lib.tsx` (plus the gesture flags from `event-calendar-dnd.tsx`). `event-calendar-lib.tsx` also exports the advanced types `EventCalendarIndex`, `EventCalendarDayBucket`, and `EventCalendarWeekRow` used in these signatures, and `event-calendar.tsx` exports the `EventCalendarContext`, `EventCalendarViewConfigContext`, and `EventCalendarViewContext` context objects for advanced composition. | Function | Signature | Description | | :------------------- | :--------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------- | | `flattenResources` | `(resources: EventCalendarResource[], depth?: number) => Array<{ resource, depth }>` | Depth-first flatten of the resource tree, parents included. | | `buildEventIndex` | `(events, visibleRange, opts) => EventCalendarIndex` | Expand, segment, and pack all events for a range into `{ occurrences, byDay, weekRows }`. | | `segmentOccurrence` | `(occurrence, range, timeZone) => EventCalendarSegment[]` | The canonical multi-day segmentation (exclusive end, zero-duration safe). | | `packTimedSegments` | `(segments) => void` | Google-style overlap packing for one day's timed segments (mutates `column` fields in place). | | `packWeekRowLanes` | `(segments, rowIndex, rowStart, timeZone) => EventCalendarSegment[]` | Greedy lane packing of bar segments within one week row; returns new merged bar segments. | | `defaultEventOrder` | `(a, b: EventCalendarOccurrence) => number` | Default sort: earlier start, then longer duration, then key. | | `getViewDateRange` | `(view, date, opts) => { visibleRange, activeRange }` | The rendered and logical ranges for a view and anchor date. | | `stepDate` | `(view, date, direction, opts) => Date` | The anchor date stepped one period forward or backward. | | `toZoned` | `(date: Date, timeZone: string) => TZDate` | The instant re-expressed in the display time zone. | | `zonedStartOfDay` | `(date: Date, timeZone: string) => TZDate` | Zoned midnight of the day containing the instant. | | `getDayKey` | `(date: Date, timeZone: string) => string` | Stable per-day key (`yyyy-MM-dd`) in the display time zone. | | `getDayTotalMinutes` | `(dayStart: Date, timeZone: string) => number` | Day length in minutes; 1380/1500 on DST transition days. | | `getRangeKey` | `(range: EventCalendarDateRange) => string` | Cheap string cache key for a range. | | `snapMinutes` | `(minutes: number, snap: number) => number` | Round minutes to the nearest snap step. | | `rangesIntersect` | `(a, b: EventCalendarDateRange) => boolean` | Half-open range intersection. | | `eventsOverlap` | `(a, b: { start: Date; end: Date }) => boolean` | Half-open overlap test. | | `isBarOccurrence` | `(occurrence: EventCalendarOccurrence) => boolean` | True when the occurrence renders as a bar (all-day or multi-day). | | `spansMultipleDays` | `(occ: { start: Date; end: Date }) => boolean` | Longer than 24 hours (an event ending exactly at midnight is single-day). | | `resolveOffDay` | `(day, timeZone, config: boolean \| EventCalendarOffDaysConfig \| undefined) => boolean` | Whether a day is an off day in the display zone. | | `minuteBlockStyle` | `(startMin, endMin, boundsStartMin) => CSSProperties` | Absolute top/height for a minute-positioned overlay block (from `event-calendar-time-grid.tsx`). | | `wasRecentDrag` | `() => boolean` | True shortly after a gesture ended; lets click handlers ignore the click that ends a drag. | | `wasRecentChipPress` | `() => boolean` | True shortly after a press started on an event chip; guards slot-create clicks. | | `markChipPress` | `() => void` | Flag a chip press (called by `EventCalendarEvent`); needed when building custom chips. | Useful exported constants: `BASE_VIEWS` and `ALL_VIEWS` (the view lists), `DEFAULT_VIEW_CONFIG`, `DEFAULT_VIEW_COMPONENTS` (the view switchboard map), `EVENT_CALENDAR_ACTIVATION` (gesture defaults), `EVENT_CALENDAR_COLORS` (ten Tailwind palette presets for `event.color`), `EVENT_CALENDAR_GHOST` (the standardized drag-ghost classes), `EVENT_CALENDAR_FADE_TRUNCATE` (the fade-out truncation classes, reusable in `renderEvent` content), `MIN_PACK_SLOT` (packing-effective minimum of 30 minutes), and `MAX_OCCURRENCES` (recurrence expansion cap of 1000 per event). *** ### Recurrence helpers Exported from `event-calendar-recurrence.tsx`. The supported `RRULE` subset is `FREQ` (daily, weekly, monthly, yearly), `INTERVAL`, `COUNT`, `UNTIL`, `BYDAY` (with ordinals for monthly/yearly), `BYMONTHDAY`, `BYMONTH`, and `WKST`; anything else throws `EventCalendarRecurrenceError`, whose message points at the `getOccurrences` escape hatch. | Function | Signature | Description | | :------------------ | :---------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | | `expandRecurrence` | `(event, range, ctx: { timeZone }) => EventCalendarOccurrence[]` | Expand one event into its occurrences intersecting the range; wall-time iteration in the display zone (DST-safe). | | `parseRRuleString` | `(input: string, timeZone?: string) => EventCalendarRecurrenceRule` | Parse a raw `RRULE` line (with or without the prefix); Z-less `UNTIL` values are wall time in the given zone. | | `formatRRuleString` | `(rule: EventCalendarRecurrenceRule) => string` | Serialize the structured subset back to an `RRULE` line (without prefix). | ## Config ### State options Option props accepted by `EventCalendar` and `useEventCalendarState`. Controlled/uncontrolled pairs follow the standard convention: pass the controlled prop plus its `on*Change` callback, or the `default*` prop for internal state. | Prop | Type | Default | Description | | :------------------------------------- | :------------------------------------------------------------------------------- | :------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `events` / `defaultEvents` | `CalendarEvent[]` | `[]` | The events (controlled / uncontrolled). | | `view` / `defaultView` | `CalendarView` | `"month"` | Active view. | | `date` / `defaultDate` | `Date` | `new Date()` | Anchor date. | | `dayCount` / `defaultDayCount` | `number` | `3` | Day count for the `days` view (min 1). | | `selection` / `defaultSelection` | `EventCalendarSelection` | `{ eventKeys: [], slot: null }` | Selection state. | | `interactions` / `defaultInteractions` | `Partial` | all `true` | Interaction toggles, merged over the defaults. | | `viewSettings` / `defaultViewSettings` | `EventCalendarViewSettings` | `{}` | User display toggles. | | `loading` | `boolean` | `false` | Dims the content area and disables pointer events. | | `views` | `CalendarView[]` | base views | Enabled views; defaults to `["month", "week", "day", "days", "agenda"]`, plus `"resource"` when `resources` is non-empty. | | `timeZone` | `string` | system time zone | IANA display time zone; all day math and rendering happen in it. | | `locale` | `Locale` | - | date-fns locale for every formatted string. | | `weekStartsOn` | `0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6` | `locale` | First day of the week (0 = Sunday). Defaults to the `locale`'s own first day when one is set, so a German or French calendar starts on Monday; an explicit value always wins. | | `dayStartHour` | `number` | `0` | First rendered hour in time grids. | | `dayEndHour` | `number` | `24` | Last rendered hour in time grids. | | `slotDuration` | `number` | `30` | Duration in minutes of a click-created slot (`onSlotClick` end). | | `snapDuration` | `number` | `15` | Snap granularity in minutes for drag, resize, and drag-create. | | `agendaDayCount` | `number` | `30` | Days covered by the agenda view window. | | `fixedWeeks` | `boolean` | `true` | Month view always renders 6 weeks. | | `showOutsideDays` | `boolean` | `true` | Show leading/trailing outside days in the month view. | | `i18n` | `Partial` | - | Per-key overrides of labels, view names, formats, and formatter functions. | | `resources` | `EventCalendarResource[]` | `[]` | Bookable resources for the resource view. | | `getEventPriority` | `(event: CalendarEvent) => number` | `event.priority ?? 0` | Packing prominence resolver. | | `eventOrder` | `(a, b: EventCalendarOccurrence) => number` | `defaultEventOrder` | Occurrence sort comparator (default: earlier start, then longer duration, then key). | | `getOccurrences` | `(event, range, ctx: { timeZone }) => Array<{ start: Date; end: Date }> \| null` | - | Custom recurrence expansion per event (plug a full RRULE engine); return `null` for the built-in one. | | `weekendDays` | `number[]` | `[0, 6]` | Weekday numbers treated as the weekend by the "weekends" view toggle. | | `activation` | `Partial` | see below | Pointer-gesture tuning. | `EventCalendarActivationConfig` defaults: `moveDistancePx: 5`, `createDistancePx: 4`, `touchDelayMs: 250`, `touchTolerancePx: 5`, `autoScrollEdgePx: 48`, `autoScrollMaxStepPx: 15` (exported as `EVENT_CALENDAR_ACTIVATION`). *** ### Callbacks Callback props accepted by `EventCalendar` and `useEventCalendarState`, alongside the options above. | Prop | Signature | Description | | :--------------------- | :-------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- | | `onEventClick` | `(occurrence, e: React.MouseEvent) => void` | Chip click; call `e.preventDefault()` to opt out of the built-in selection. | | `onEventDoubleClick` | `(occurrence, e: React.MouseEvent) => void` | Chip double click. | | `onEventUpdate` | `(update: EventCalendarProposedUpdate) => EventCalendarUpdateResult` | The one validation funnel for drags, resizes, and API timing changes; `false` rejects, an object adjusts. | | `canDropEvent` | `(update: EventCalendarProposedUpdate) => boolean` | Live validation during a gesture; drives the `data-drop-invalid` styling and the not-allowed cursor. | | `onDragBlocked` | `(occurrence, info: { gesture: "move" \| "resize"; reason: "readOnly" \| "disabled" \| "interactions-off" }) => void` | A gesture was attempted on a locked event; fires once per gesture so you can surface a message. | | `onSlotClick` | `(slot: EventCalendarSlotInfo, e: React.MouseEvent) => void` | Click on an empty slot or day cell (also fired by the day add button). | | `onSelectSlot` | `(slot: EventCalendarSlotDraft) => void` | A drag-create selection was committed. | | `canSelectSlot` | `(slot: EventCalendarSlotDraft) => boolean` | Live validation of the drag-create rectangle. | | `onRangeChange` | `(info: EventCalendarRangeInfo) => void` | Visible range changed (view, date, or time zone); fires once for the initial range. `info` carries `range`, `activeRange`, `view`, `date`, and `timeZone`. | | `onViewChange` | `(view: CalendarView) => void` | View changed. | | `onDateChange` | `(date: Date) => void` | Anchor date changed. | | `onDayCountChange` | `(count: number) => void` | N-day count changed. | | `onSelectionChange` | `(selection: EventCalendarSelection) => void` | Selection changed. | | `onInteractionsChange` | `(interactions: EventCalendarInteractions) => void` | Interaction toggles changed. | | `onViewSettingsChange` | `(viewSettings: EventCalendarViewSettings) => void` | User display toggles changed. | | `onEventsChange` | `(events: CalendarEvent[]) => void` | Events array changed (drag commit, resize, API mutation). | | `onMoreClick` | `(day: Date, occurrences: EventCalendarOccurrence[], e: React.MouseEvent) => void \| false` | "+N more" clicked; return `false` to suppress the built-in popover and open your own UI. | *** ### View configuration Display props and render overrides, accepted directly on `EventCalendar` (they live in the view layer, never in the headless options). Defaults come from `DEFAULT_VIEW_CONFIG`. | Prop | Type | Default | Description | | :--------------------- | :-------------------------------------------------- | :------------------------------------------------------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `scrollToHour` | `number` | `7` | Hour the time grids scroll to on mount. | | `nowIndicator` | `boolean` | `true` | Show the current-time line in time grids. | | `interval` | `number` | `60` | Grid interval in minutes for time-based views; gutter slots and gridlines follow it. Also accepted per view component. | | `maxEventsPerCell` | `number \| "auto"` | `"auto"` | Max bars plus chips per month cell before "+N more". | | `showWeekNumbers` | `boolean` | `false` | Week-number gutter in the month view. | | `enableShortcuts` | `boolean` | `true` | View-switcher keyboard shortcuts and their `kbd` hints. | | `shortcutsScope` | `"focus-within" \| "global"` | `"focus-within"` | Where the shortcuts listen. | | `scrollMode` | `"contained" \| "page"` | `"contained"` | Contained: the calendar fills its container and views scroll internally. Page: content flows with the document and day headers stick below `--ec-sticky-offset`. | | `stickyNav` | `boolean` | `false` | Stick the default nav to the top while the page scrolls. | | `dayClassName` | `(day: Date) => string \| undefined` | - | Custom per-day indication on month cells, day columns, and all-day cells. | | `todayClassName` | `string` | - | Extra classes for the current day, appended after the built-in highlight. | | `showDayAddButton` | `boolean` | `false` | Hover "+" affordance on month cells; fires the same `onSlotClick` as clicking the day. | | `scrollbars` | `"custom" \| "native"` | `"custom"` | Scroll implementation for every internally scrolling surface (shadcn ScrollArea vs browser scrollbars). | | `navButtonVariant` | `"ghost" \| "outline" \| "secondary" \| "default"` | `"ghost"` | Variant applied to all nav buttons. | | `navButtonSize` | `"sm" \| "default"` | `"sm"` | Size applied to all nav buttons (icon buttons use the icon twin). | | `offDays` | `boolean \| EventCalendarOffDaysConfig` | - | Off-day (non-working day) marking; `true` = weekends with a muted background. | | `classNames` | `EventCalendarClassNames` | - | Per-element class hooks; see below. | | `components` | `Partial>` | - | Swap individual view implementations. | | `dayCountPresets` | `number[]` | `[5]` | N-day presets offered by the view switcher when the `days` view is enabled. | | `navTooltips` | `false \| { side?, delay?, closeDelay?, timeout? }` | `{ side: "bottom", delay: 600, closeDelay: 0, timeout: 300 }` | Nav tooltips: `false` disables them all; the object tunes placement and timings. | | `eventTooltip` | `boolean \| { side?, delay? }` | `false` | Styled tooltip on event hover / focus; `true` shows the event label, an object tunes side and delay. Content via `renderEventTooltip`. | | `compactEventMinutes` | `number` | `45` | Timed events shorter than this render the compact single-row chip layout. | | `morePopoverAlign` | `"start" \| "center" \| "end"` | `"start"` | "+N more" popover alignment against its trigger. | | `nowIndicatorInterval` | `number` | `30000` | Now-indicator refresh cadence in milliseconds. | | `agendaSummaryMaxDots` | `number` | `6` | Max color dots in a collapsed agenda day summary. | Render overrides, all optional and all part of the same view config: | Prop | Signature | Description | | :-------------------------- | :------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------ | | `renderEvent` | `(props: EventCalendarRenderEventProps) => ReactNode` | Replace the chip content in grid views; receives `occurrence`, `segment`, `view`, `isDragging`, `isSelected`. | | `renderAgendaEvent` | `(props: EventCalendarRenderEventProps) => ReactNode` | Replace the agenda row content. | | `renderEventTooltip` | `(props: { occurrence, segment, view, label }) => ReactNode` | Content for the styled hover tooltip (`eventTooltip`); a falsy return falls back to the default label. | | `renderDragPreview` | `(props: { drag: EventCalendarDragState }) => ReactNode` | Custom drag preview content. | | `renderMonthCell` | `(props: { day, segments, isToday, isOutside, overflowCount, defaultContent }) => ReactNode` | Replace a month cell's body; `defaultContent` lets you wrap instead of rebuild. | | `renderDayColumnBackground` | `(props: { day, boundsStartMin, boundsEndMin, totalMinutes }) => ReactNode` | Business-logic layer rendered pointer-events-none behind event segments in each day column. | | `renderDayHeader` | `(props: { day, view, isToday }) => ReactNode` | Replace day header cells (month header row and time-grid headers). | | `renderTimeGutterSlot` | `(props: { time, hour, minute }) => ReactNode` | Replace hour gutter labels. | | `renderAllDaySection` | `(props: { days, segments }) => ReactNode` | Replace the entire all-day row of time grids. | | `renderMoreIndicator` | `(props: { day, count, segments }) => ReactNode` | Replace the "+N more" trigger content. | | `renderMoreContent` | `(props: { day, segments, close }) => ReactNode` | Replace the entire body of the built-in "+N more" popover while keeping its trigger and positioning. | | `renderAgendaEventDetails` | `(occurrence: EventCalendarOccurrence) => ReactNode` | Agenda-only expandable details; returning a node gives the row an expand/collapse toggle. | | `renderNowIndicator` | `(props: { time: Date }) => ReactNode` | Replace the current-time line. | | `renderNoEvents` | `() => ReactNode` | Replace the agenda empty state. | | `renderResourceHeader` | `(props: { resource: EventCalendarResource }) => ReactNode` | Resource column header content; default is `resource.title`. | | `renderAgendaDayHeader` | `(props: { day, collapsed, count, toggle, defaultContent }) => ReactNode` | Replace the agenda date gutter (day badge, weekday, collapse toggle). | | `renderAgendaDaySummary` | `(props: { day, occurrences, count, expand, defaultContent }) => ReactNode` | Replace the collapsed agenda day summary row content. | The `classNames` object (`EventCalendarClassNames`) offers one string hook per element, cn-merged after the built-in classes so Tailwind variants and `!` overrides win. Available keys: `nav`, `toolbar`, `content`, `monthView`, `monthCell`, `timeGrid`, `timeGutter`, `dayColumn`, `allDaySection`, `agendaView`, `event`, `eventTooltip`, `moreIndicator`, `morePopover`, `morePopoverHeader`; nav family `navButton`, `title`, `navTooltip`, `viewSwitcherContent`, `viewSwitcherLabel`, `viewShortcut`, `datePickerContent`; month view `monthHeader`, `monthDayHeader`, `monthBody`, `monthRow`, `weekNumber`, `monthBarOverlay`, `monthBar`, `monthCellContent`, `monthCellFooter`, `monthDayNumber`, `dayAddButton`; time grid and resource `timeGridHeader`, `timeGutterLabel`, `allDayLabel`, `allDayCell`, `timedChip`, `resourceHeader`; interaction surfaces `dragGhost`, `dragCarry`, `dragCarryInvalid`, `dropHint`, `dropIndicator`, `slotDraft`, `resizeHandle`, `resizeGrip`; agenda `noEvents`, `agendaDay`, `agendaDayGutter`, `agendaDate`, `agendaDayToggle`, `agendaDayContent`, `agendaItem`, `agendaItemSurface`, `agendaItemToggle`, `agendaDaySummary`, `agendaSummaryDot`. Metric CSS variables can ride on any parent key, for example `classNames.timeGrid: "[--ec-gutter-width:4rem]"` or `classNames.morePopover: "[--ec-more-max-height:20rem]"`. *** ### EventCalendarInteractions Interaction toggles, controllable via the `interactions` prop or `api.setInteractions`. All three default to `true`. | Property | Type | Default | Description | | :----------- | :-------- | :------ | :---------------------------- | | `drag` | `boolean` | `true` | Move events by dragging. | | `resize` | `boolean` | `true` | Resize events at their edges. | | `selectSlot` | `boolean` | `true` | Drag-create slot selection. | *** ### EventCalendarViewSettings User-adjustable display toggles (the "view settings" state), controllable via `viewSettings` / `onViewSettingsChange` or `api.setViewSettings`. Every field is optional; `undefined` defers to the matching view-config prop (see `useEventCalendarViewSettings().effective`). | Property | Type | Default | Description | | :------------- | :-------- | :------ | :--------------------------------------------------------------------------------------- | | `weekends` | `boolean` | - | Show Saturday/Sunday columns in month, week, and N-day grids (effective default `true`). | | `weekNumbers` | `boolean` | - | Week-number gutter in the month view (defers to `showWeekNumbers`). | | `nowIndicator` | `boolean` | - | Current-time line (defers to the `nowIndicator` view config). | | `offDays` | `boolean` | - | Off-day background marking (defers to the `offDays` view config). | *** ### EventCalendarOffDaysConfig Configuration for non-working-day marking, passed as the `offDays` view config. `true` uses the defaults (weekends with a muted background); marked cells carry `data-off` for CSS-selector customization. | Property | Type | Default | Description | | :------------ | :----------------------- | :-------------- | :------------------------------------------------------------------- | | `weekendDays` | `number[]` | `[0, 6]` | Weekday numbers treated as off (0 = Sunday). | | `dates` | `Date[]` | - | Additional explicit off dates (compared by day in the display zone). | | `isOffDay` | `(day: Date) => boolean` | - | Full custom predicate; runs in addition to `weekendDays` / `dates`. | | `className` | `string` | `"bg-muted/40"` | Marker classes. | *** ### Internationalization The `i18n` option accepts a `Partial` with four sections, shallow-merged per nested object so a partial override replaces individual keys, never whole sections: * `labels`: UI strings and label functions (`today`, `previous`, `next`, `addEvent`, `allDay`, `more(count)`, `noEvents`, `loading`, `event`, `events(count)`, `selectView`, `week(weekNumber)`, `resources`, `goToDate`, `dropNotAllowed`, `continues`, `timeFrom(time)`, `timeUntil(time)`, `viewShortcuts`, `toggleDayEvents(count, expanded)`, `eventDetails(title)`, `moreCompact(count)`, `timeRange(from, to)`). * `viewNames`: display names per view (`month`, `week`, `day`, `days(count)`, `agenda`, `resource`). * `formats`: date-fns format strings applied with the calendar `locale` (`monthTitle`, `weekTitle`, `dayTitle`, `agendaTitle`, `monthDayHeader`, `monthDayHeaderNarrow`, `timeGridDayHeader`, `agendaDayHeader`, `agendaDayNumber`, `agendaWeekday`, `moreDayHeader`, `monthCellAriaLabel`, `dayAria`, `resourceTitle`, `timeGutter`, `timeGutterMinute`, `eventTime`, `monthCellDay`). Leaving `weekTitle` / `agendaTitle` undefined keeps the smart cross-month range title. * `functions`: formatter functions (`formatTitle`, `formatEventTime`, `formatDayRange`, `formatEventLabel`, `formatEventAriaLabel`). The defaults are re-bound to the merged labels and formats, so overriding `formats.monthTitle` flows into the default `formatTitle` without replacing it. `mergeEventCalendarI18n(overrides?)` performs this merge and `DEFAULT_EVENT_CALENDAR_I18N` holds the defaults; both are exported from `event-calendar-i18n.tsx` for standalone use. ## All 5 variations ### Event calendar with resource view for room bookings ### Event calendar with create and edit dialog ### Event calendar with custom event chips ### Event calendar with drag-to-book appointments # Filters URL: https://www.spaceui.one/components/filters *** title: Filters description: Provides a filter bar with badges and active tags, allowing users to narrow down search results by multiple criteria simultaneously. component: true base: base preview: name: demo-c-filters-01 align: start className: '\*\*:\[.preview]:h-auto' ------------------------------------ ## Installation ## Usage ```tsx import * as React from 'react' import { createFilter, Filters, type Filter, type FilterFieldConfig } from '@/components/spaceui/filters' export default function SpaceUI() { const [filters, setFilters] = React.useState([createFilter('priority', 'is_any_of', ['low', 'medium'])]) const fields: FilterFieldConfig[] = [ { key: 'priority', label: 'Priority', type: 'multiselect', options: [ { value: 'low', label: 'Low' }, { value: 'medium', label: 'Medium' }, { value: 'high', label: 'High' }, ], }, ] return } ``` ## Examples ### Validation ### Trigger Button ### Small Size ### Large Size ### Custom Controls ### Data Grid ### Nuqs ### With i18n Support ### Virtualized Large Lists ### Prefetched Async Options ### Async Server-side Search ## API Reference ### Filters The main component for displaying and managing a collection of active filters. | Prop | Type | Default | Description | | :------------------- | :------------------------------- | :---------- | :---------------------------------------------------------------------- | | `filters` | `Filter[]` | - | `Required`. The array of active filters. | | `fields` | `FilterFieldsConfig` | - | `Required`. The configuration for available filter fields. | | `onChange` | `(filters: Filter[]) => void` | - | `Required`. Callback fired when filters are added, updated, or removed. | | `size` | `"sm" \| "default" \| "lg"` | `"default"` | The size of the filter items and controls. | | `trigger` | `ReactNode` | - | Custom element to trigger the "Add Filter" menu. | | `showSearchInput` | `boolean` | `true` | Whether to show the search input in the "Add Filter" menu. | | `allowMultiple` | `boolean` | `true` | Whether to allow multiple filters for the same field. | | `enableShortcut` | `boolean` | `false` | Whether to enable the keyboard shortcut to open the filter menu. | | `shortcutKey` | `string` | `"f"` | The key used for the shortcut (e.g., "f"). | | `shortcutLabel` | `string` | `"F"` | The label to display in the shortcut indicator. | | `i18n` | `Partial` | - | Custom labels and operators for internationalization. | | `className` | `string` | - | Additional CSS classes for the container. | | `menuPopupClassName` | `string` | - | Additional CSS classes for the filter dropdown menu. | *** ### FilterFieldConfig Configuration for an individual filterable field. | Property | Type | Description | | :-------------------- | :------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `key` | `string` | `Required`. Unique identifier for the field. | | `label` | `string` | `Required`. Human-readable label for the field. | | `type` | `"text" \| "select" \| "multiselect" \| "custom" \| "separator"` | The type of filter input to use. | | `icon` | `ReactNode` | Optional icon to display next to the field label. | | `options` | `FilterOption[]` | List of options for `select` and `multiselect` fields. | | `loadOptions` | `(query: string) => FilterOption[] \| Promise[]>` | Async options loader for large or remote lists. Called with the current search query - return a prefetched list (ignore the query) or server-side search results. Debounced, with loading/error states and a value-to-label cache. `options` still seeds the initial view. | | `renderOptionList` | `(props: FilterOptionListRenderProps) => ReactNode` | Bring-your-own rendering for the options list, e.g. virtualization with a windowing library of your choice. Receives `{ options, highlightedIndex, renderOption }`; render the scrollable list and call `renderOption` for each row. Omit for the default plain list. | | `operators` | `FilterOperator[]` | Custom operators for this specific field. | | `defaultOperator` | `string` | The operator to select by default when adding this field. | | `placeholder` | `string` | Placeholder text for text inputs. | | `searchable` | `boolean` | Whether the options list should be searchable. | | `maxSelections` | `number` | Maximum number of items allowed in `multiselect`. | | `prefix` | `ReactNode \| string` | Prefix element for the input field. | | `suffix` | `ReactNode \| string` | Suffix element for the input field. | | `pattern` | `string` | Regex pattern for text input validation. | | `validation` | `(value) => boolean \| object` | Custom validation function. | | `customRenderer` | `(props) => ReactNode` | Custom renderer for the filter value selector. | | `customValueRenderer` | `(values, options) => ReactNode` | Custom renderer for the active filter value display. | | `fields` | `FilterFieldConfig[]` | Nested fields if this is a group configuration. | | `group` | `string` | Group label if this is a group configuration. | | `className` | `string` | Additional CSS classes for the field components. | *** ### FilterOption Structure for options in `select` and `multiselect` fields. | Property | Type | Description | | :---------- | :---------- | :----------------------------------------------- | | `value` | `T` | `Required`. The internal value of the option. | | `label` | `string` | `Required`. Human-readable label for the option. | | `icon` | `ReactNode` | Optional icon to display next to the option. | | `className` | `string` | Additional CSS classes for the option item. | *** ### Filter The structure of an active filter object. | Property | Type | Description | | :--------- | :------- | :----------------------------------------------- | | `id` | `string` | Unique identifier for the filter instance. | | `field` | `string` | The `key` of the associated field configuration. | | `operator` | `string` | The selected operator (e.g., "is", "contains"). | | `values` | `T[]` | The current value(s) of the filter. | *** ### FilterI18nConfig Configuration for internationalization and custom labels. | Property | Type | Description | | :------------- | :------- | :----------------------------------------- | | `addFilter` | `string` | Label for the "Add Filter" button. | | `searchFields` | `string` | Placeholder for the field search input. | | `operators` | `object` | Map of operator keys to localized strings. | | `validation` | `object` | Map of validation error messages. | | `placeholders` | `object` | Map of dynamic placeholder templates. | *** ### Helpers | Function | Signature | Description | | :------------------ | :---------------------------------------------------- | :-------------------------------------------- | | `createFilter` | `(field, operator?, values?) => Filter` | Creates a new filter object with a unique ID. | | `createFilterGroup` | `(id, label, fields, initialFilters?) => FilterGroup` | Creates a filter group configuration. | # Flip Text URL: https://www.spaceui.one/components/flip-text *** title: Flip Text description: Per-character 3D flip animation with a sine-eased stagger wave across the text. preview: name: demo-c-flip-text-01 ------------------------- ## Installation # Fluid Countdown URL: https://www.spaceui.one/components/fluid-countdown *** title: Fluid Countdown description: A countdown timer with fluid rolling digits, play/pause and reset controls, and auto-loop built with NumberFlow and Motion. preview: name: demo-c-fluid-countdown-01 contained: false ---------------- Full-screen countdown with fluid rolling numerals, interactive controls, and accessible motion. ## Installation ## Usage ```tsx import { FluidCountdown } from '@/components/spaceui/fluid-countdown' export default function Timer() { return } ``` # Fluid Crossfade URL: https://www.spaceui.one/components/fluid-crossfade *** title: Fluid Crossfade description: Dual-pass WebGL fluid simulation with chromatic wave refraction and Bayer 4x4 matrix ordered dither crossfading. isPro: true preview: name: demo-c-fluid-crossfade-01 contained: false ---------------- ## Installation ## Usage ```tsx import { FluidCrossfade } from '@/components/spaceui/fluid-crossfade' import { FluidCrossfade } from '@/components/shader/fluid-crossfade' export default function Example() { return ( ) } ``` ## API Reference | Prop | Type | Default | Description | | -------------------- | -------- | -------- | ------------------------------------------- | | `imageA` | `string` | — | Initial default texture URL | | `imageB` | `string` | — | Hover/transition texture URL | | `ditherGrid` | `number` | `3.0` | Scale of the Bayer 4x4 dithering pattern | | `pixelGridSize` | `number` | `240` | Resolution of pixel quantization | | `refractionStrength` | `number` | `0.85` | Power of fluid wave refraction on the image | | `aspectRatio` | `number` | `16 / 9` | Aspect ratio of the canvas | # Fluid Distortion Image URL: https://www.spaceui.one/components/fluid-distortion-image *** title: Fluid Distortion Image description: An interactive WebGL image component with cover UV mapping and dynamic cursor fluid-distortion ripples using data textures. preview: name: demo-c-fluid-distortion-image-01 contained: false ---------------- ## Installation ## Usage ```tsx import { FluidDistortionImage } from '@/components/spaceui/fluid-distortion-image' import { FluidDistortionImage } from '@/components/shader/fluid-distortion-image' export default function Example() { return ( ) } ``` ## API Reference | Prop | Type | Default | Description | | --------------------- | -------- | --------------------------- | -------------------------------------------- | | `src` | `string` | — | Image source URL | | `alt` | `string` | `'Distorted surface image'` | Accessible image label | | `aspectRatio` | `number` | `16 / 10` | Fixed aspect ratio with object-cover mapping | | `distortionIntensity` | `number` | `0.03` | Strength of cursor ripple displacement | | `relaxationSpeed` | `number` | `0.94` | Decay rate of fluid velocity (0 to 1) | | `radius` | `number` | `0.18` | Radius of cursor impact area | # Fluid Dither Crossfade URL: https://www.spaceui.one/components/fluid-dither-crossfade *** title: Fluid Dither Crossfade description: A dual-pass WebGL shader component featuring real-time Navier-Stokes fluid pressure simulation and Bayer 4x4 matrix ordered dithering crossfade. preview: name: demo-c-fluid-dither-crossfade-01 contained: false ---------------- ## Installation ## Usage ```tsx import { FluidDitherCrossfade } from '@/components/spaceui/fluid-dither-crossfade' import { FluidDitherCrossfade } from '@/components/shader/fluid-dither-crossfade' export default function Example() { return ( ) } ``` ## API Reference | Prop | Type | Default | Description | | -------------------- | --------- | ------------------------------------------------------ | ------------------------------------------------ | | `imageA` | `string` | `'https://cdn.spaceui.one/atom/samples/image-0-f.png'` | Initial base texture URL | | `imageB` | `string` | `'https://cdn.spaceui.one/atom/samples/image-0-b.png'` | Revealed target texture URL | | `bgColor` | `string` | `'#0e0e0e'` | Canvas background color | | `pixelRes` | `number` | `150` | Pixelation resolution for revealed texture | | `pixelEdgeRes` | `number` | `80` | Chunky pixel resolution for fluid ink boundary | | `ditherGrid` | `number` | `20` | Bayer 4x4 matrix grid sampling size | | `ditherEnabled` | `boolean` | `true` | Whether ordered dithering is active | | `brushSize` | `number` | `0.64` | Radius of cursor fluid wave & ink stroke | | `distortionStrength` | `number` | `9.18` | Intensity of wave chromatic refraction | | `inkDissipation` | `number` | `0.926` | Speed at which revealed ink mask fades back | | `edgeThreshold` | `number` | `0.08` | Ink density threshold required to reveal image B | # Frost Blurred URL: https://www.spaceui.one/components/frost-blurred *** title: Frost Blurred description: Stacked, masked backdrop-filter layers that frost content along an edge. preview: name: demo-c-frost-blurred-01 contained: false ---------------- ## Installation ## Usage ```tsx import { FrostBlurred } from '@/components/spaceui/frost-blurred' export default function Hero() { return (

UImaxxing

) } ``` Without children, render it as an overlay on a relative parent: ```tsx
``` ## Props | Prop | Type | Default | Description | | ---------- | ---------------------------------------- | ---------- | ------------------------------------------------- | | `layers` | `number` | `7` | Stacked progressive blur layers. | | `strength` | `number` | `1` | Multiplier on each layer's blur radius. | | `height` | `string \| number` | `'62%'` | Overlay height (or width if left/right). | | `side` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'bottom'` | Edge the frost grows from. | | `tint` | `number` | `0` | Optional theme background mix (0 for pure glass). | | `opacity` | `number` | `0.9` | Layer opacity. | | `children` | `React.ReactNode` | — | Content to frost. Omit to use as a pure overlay. | # GitHub Activity URL: https://www.spaceui.one/components/github-activity *** title: GitHub Activity description: An interactive GitHub ecosystem showcase featuring pure 52-week contribution heatmap matrix content with live fetch for users and repositories. preview: name: demo-c-github-activity-01 contained: false ---------------- ## Installation ## Anatomy ```tsx import { GitHubActivity } from '@/components/spaceui/github-activity' export default function Example() { return } ``` ## Features ### Repository Activity with Stats on Top Layout demonstrating repository commit activity with KPI metric cards positioned above the graph. ### User Activity with Stats at Bottom Layout demonstrating user contribution activity with KPI metric cards positioned below the graph. ## Props ### GitHubActivity | Prop | Type | Default | Description | | --------------- | ----------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | `user` | `string` | - | Target GitHub identifier: user handle (`'shadcn'`), profile URL, repository slug (`'facebook/react'`), or repo URL. Auto-detects user vs repository. | | `repo` | `string` | - | Explicit alias for `user` when targeting a repository (`'owner/repo'` or GitHub URL) | | `target` | `string` | - | Unified alias for `user` | | `username` | `string` | - | Alias for `user` for backwards compatibility | | `shape` | `'square' \| 'rounded' \| 'circle'` | `'rounded'` | Corner geometry style for inner elements (no squircle) | | `contributions` | `ContributionData` | - | 52-week contribution heatmap calendar data (skips live fetch if provided) | | `showHeader` | `boolean` | `true` | Toggles the top summary header | | `showLegend` | `boolean` | `true` | Toggles the bottom color level legend | | `title` | `string` | `'Contributions'` | Custom header title (displayed if no user/repo is given) | | `subtitle` | `string` | `'Past 52 weeks'` | Custom header subtitle (defaults to `'Repository commit activity'` for repos) | # Glass Button URL: https://www.spaceui.one/components/glass-button *** title: Glass Button description: A glassmorphic extension of Button Squircle — backdrop blur, layered highlights and a hover shine sweep. --------------------------------------------------------------------------------------------------------------------- ## Icon Icon-only glass buttons, sized for a toolbar or a social row. ## Text A pill CTA with an icon and a label. ## Blur Reveal An icon button that widens and blur-reveals a text label on hover. # Gooey Experiments URL: https://www.spaceui.one/components/gooey-experiments *** title: Gooey Experiments description: A gallery of drag-to-merge and hover-morph gooey micro-interactions built with SVG filters. -------------------------------------------------------------------------------------------------------- ## Gooey Tooltip A tooltip bubble that follows the cursor and gooey-connects to its trigger button on hover. ## Gooey Info Popover A round trigger that morphs into an info panel on hover — pass any content as children. ## Gooey Slots Tooltip A round trigger that expands upward into a rich content card on hover. ## Gooey Blobs Two draggable blobs — drag them close together to see them merge into one liquid shape. # Gooey Text Reveal URL: https://www.spaceui.one/components/gooey-text-reveal *** title: Gooey Text Reveal description: Line-by-line blur reveal with a gooey SVG edge filter, driven by GSAP SplitText — plays immediately, on scroll, or scrubbed to scroll position. preview: name: demo-c-gooey-text-reveal-01 contained: false align: start previewClassName: items-start ----------------------------- ## Installation # Gradient File Upload URL: https://www.spaceui.one/components/gradient-file-upload *** title: Gradient File Upload description: A refined upload surface with an animated glowing beam border, dynamic radial feedback, file extension badges, and multi-state progress indicators. preview: name: demo-c-gradient-file-upload-01 contained: false ---------------- ## Installation ## Usage ```tsx import { GradientFileUpload } from '@/components/spaceui/gradient-file-upload' ``` ```tsx console.log('Selected:', file.name)} /> ``` ## API Reference ### GradientFileUpload Props | Prop | Type | Default | Description | | ------------------ | ------------------------------ | ------------ | ------------------------------------------------------------------- | | `variant` | `'original' \| 'glow'` | `'original'` | Visual border animation engine (`original` conic shader or `glow`) | | `accept` | `string` | `"*"` | Accepted file types (e.g. `image/*,application/pdf`) | | `maxSizeMb` | `number` | `50` | Maximum file size in megabytes before rejecting | | `uploadDurationMs` | `number` | `2400` | Simulated upload duration in milliseconds | | `onFileAccepted` | `(file: File) => void` | - | Callback fired immediately when a valid file is dropped or selected | | `onUpload` | `(file: File) => Promise<...>` | - | Custom async upload handler returning `{ status, message }` | | `className` | `string` | - | Additional class name applied to outer container | # Gradient Background URL: https://www.spaceui.one/components/gradient *** title: Gradient Background description: Creates a smoothly animating multi-color gradient background that shifts colors gently behind your page content. preview: demo-c-backgrounds-gradient-01 --------------------------------------- ## Installation ## Usage ```tsx ``` ## API Reference ### GradientBackground ', required: false, }, }} /> # Handle Reel URL: https://www.spaceui.one/components/handle-reel *** title: Handle Reel description: Kinetic tumbler reel that spins a vertical reel of names past a prefix, highlighting the centered handle as it decelerates and settles with momentum. preview: name: demo-c-handle-reel-01 contained: false ---------------- A slot-machine handle reel inspired by tactile momentum wheels. It spins past a fixed prefix (such as `ryna.me/`), highlights the landed name, and eases gracefully. Built with Motion. ## Installation ## Variants ### With custom reset button ## Usage ```tsx import { HandleReel } from '@/components/spaceui/handle-reel' export default function HeroSection() { return } ``` ## Props | Prop | Type | Default | Description | | ---------------- | ----------- | --------------------------- | --------------------------------------------------------- | | `prefix` | `ReactNode` | `"ryna.me/"` | Static prefix displayed before the rolling handles. | | `suffix` | `ReactNode` | `undefined` | Optional suffix displayed after the rolling handles. | | `names` | `string[]` | Default names | Array of candidate names or handles to cycle through. | | `finalName` | `string` | `"ryna"` | The final handle the reel lands on. | | `rows` | `number` | `7` | Number of visible rows in the viewport. | | `cycles` | `number` | `3` | Number of scroll cycles before settling. | | `spinDuration` | `number` | `4` | Duration of the spin animation in seconds. | | `highlightColor` | `string` | `"var(--primary, #6366f1)"` | Accent color pulsed when landed. | | `loop` | `boolean` | `false` | Replay the reel automatically. | | `loopDelay` | `number` | `2200` | Pause duration before replaying when `loop` is true. | | `trigger` | `number` | `0` | Increment to restart the roll programmatically. | | `onLand` | `function` | `undefined` | Callback fired when the reel settles on the final handle. | # Heat Shade URL: https://www.spaceui.one/components/heat-shade *** title: Heat Shade description: WebGPU heat field or climbing licks. Logo cyan on a navy ember. preview: demo-c-heat-shade-01 defaultMode: split ------------------ ## Installation Depends on `vgpu`. WebGPU required. ## Files | File | Role | | ------------------------------- | ------------------------------ | | `heat-shade/index.tsx` | vgpu surface, clock, low-power | | `heat-shade/heat-shade.wgsl.ts` | Field boundary | | `heat-shade/heat-licks.wgsl.ts` | Climbing tongues | ## Usage ```tsx import { HeatShade } from '@/components/shader/heat-shade' export default function SpaceUI() { return } ``` ## Variants ### Field Drifting boundary. Same colors, different silhouette. ## API Reference ### HeatShade | Prop | Type | Default | Description | | ----------- | -------------------- | ---------- | --------------- | | `variant` | `'field' \| 'licks'` | `'licks'` | Silhouette | | `from` | `'top' \| 'bottom'` | `'bottom'` | Origin edge | | `base` | `string` | `#2a7bba` | Navy (logo) | | `hot` | `string` | `#43c8ff` | Cyan rim (logo) | | `speed` | `number` | `1` | Drift speed | | `className` | `string` | — | Canvas class | # Icon Stack URL: https://www.spaceui.one/components/icon-stack *** title: Icon Stack description: Displays an overlapping cluster of icons or avatars that expands smoothly when hovered to reveal every individual item. component: true base: base preview: demo-c-icon-stack-01 ----------------------------- ## Installation ## Usage ```tsx import { InboxIcon } from 'lucide-react' import { IconStack } from '@/components/spaceui/icon-stack' ``` ```tsx ``` `IconStack` is a shadcn-compatible Space UI primitive for building layered isometric icons and compact isometric illustrations. Use it for empty states, onboarding steps, feature cards, dashboard status panels, and small UI moments that need more depth than a flat icon. The main preview above shows the basic shadcn icon stack pattern: a layered SVG stack with one centered icon. Style the inner icon or custom content directly with its own `className`; the stack only provides the isometric artwork and overlay position. Keep meaningful labels in surrounding copy and mark purely decorative stacks with `aria-hidden="true"`. ## Examples ### Sizes ### Colors ### Icon Badge ### Empty State Illustration ### Item Media ## API Reference ### IconStack | Prop | Type | Default | Description | | :---------- | :---------------- | :------ | :---------------------------------------------------- | | `className` | `string` | - | Controls the outer wrapper size, color, and layout. | | `children` | `React.ReactNode` | - | Renders optional decorative content inside the stack. | All native `div` props are supported. # Image Dark URL: https://www.spaceui.one/components/image-dark *** title: Image Dark description: An adaptive image component that dynamically switches between light and dark mode sources using standard HTML img elements with zero layout shift and no hydration mismatch. preview: demo-c-image-dark-01 ----------------------------- ## Installation ## Usage ```tsx import { ImageDark } from '@/components/spaceui/image-dark' ``` ```tsx ``` ## API Reference ### ImageDark Props `ImageDark` accepts all standard HTML `` element attributes (`width`, `height`, `loading`, `decoding`, `alt`, `className`, etc.) along with the following: | Prop | Type | Default | Description | | ----------- | -------- | ------------ | ----------------------------------------------------------------------------------------- | | `src` | `string` | **Required** | The primary/light mode image source URL or path. | | `darkSrc` | `string` | `undefined` | The dark mode image source URL or path. Swapped automatically in dark theme. | | `alt` | `string` | `""` | Alternative text description for accessibility. | | `className` | `string` | `undefined` | Additional classes merged onto both image elements (`dark:hidden` / `hidden dark:block`). | *** ### Card Integration Use standard image sizing and container styling inside cards, hero banners, or device mockups. # Components URL: https://www.spaceui.one/components *** title: Components description: Composed Space UI components styled with Tailwind CSS. ------------------------------------------------------------------- # Interactive Checklist URL: https://www.spaceui.one/components/interactive-checklist *** title: Interactive Checklist description: Tactile checklist with spring checkmarks, animated strike-through lines, and completion progress. preview: demo-c-interactive-checklist-01 ---------------------------------------- ## Installation ## Usage ```tsx import { InteractiveChecklist } from '@/components/spaceui/interactive-checklist' export default function Example() { return } ``` ## Props | Prop | Type | Default | Description | | --------------- | ----------------- | ---------------- | --------------------------------- | | `initialItems` | `ChecklistItem[]` | `DEFAULT_TASKS` | Initial checklist tasks | | `title` | `string` | `'Sprint Tasks'` | Checklist title | | `corner` | `number` | `24` | Corner radius in px | | `onCompleteAll` | `() => void` | `—` | Triggered when all items are done | # Interest Picker URL: https://www.spaceui.one/components/interest-picker *** title: Interest Picker description: A draggable row-packed interest picker with an emoji burst on select and a shake-to-explode clear action. preview: name: demo-c-interest-picker-01 contained: false ---------------- ## Installation # Kanban URL: https://www.spaceui.one/components/kanban *** title: Kanban description: Displays tasks across draggable columns, allowing users to organize projects, track progress stages, and reorder cards intuitively. component: true base: base preview: name: demo-c-kanban-01 align: start className: '\*\*:\[.preview]:h-auto' ------------------------------------ ## Installation ## Usage ```tsx import { Kanban, KanbanBoard, KanbanColumn, KanbanColumnContent, KanbanColumnHandle, KanbanItem, KanbanItemHandle, KanbanOverlay, } from '@/components/spaceui/kanban' ``` ```tsx item.id}> {Object.entries(columns).map(([id, items]) => (

{id}

{items.map((item) => ( {item.content} ))}
))}
``` ## Examples ### Overlay ### Persist to a backend ## Persisting moves Keep `value` and `onValueChange` so the board reshuffles live while dragging, and use `onValueCommit` to save. It fires once per completed drag (never during the hover preview) with the final board and a `previousValue` snapshot, so you can update optimistically and roll back on error. Its `meta.kind` tells you whether a card moved (`"item"`) or a column was reordered (`"column"`). ```tsx const moveCard = api.board.moveCard.useMutation() const reorderColumns = api.board.reorderColumns.useMutation() task.id} onValueCommit={(next, meta) => { if (meta.kind === "column") { reorderColumns.mutate({ order: Object.keys(next) }) return } moveCard.mutate( { id: String(meta.event.active.id), to: meta.overContainer, index: meta.overIndex, }, { onError: () => { setColumns(meta.previousValue) // roll back toast.error("Could not move the card. Your board was restored.") }, }, ) }} > {/* ... */} ``` If a user might start another drag before the mutation settles, prefer a refetch in `onError` instead of restoring the snapshot, so a newer arrangement is not clobbered. If you do not need the live cross-column preview, `onMove` is a simpler alternative: it fires once on drop for item moves and lets you apply the move yourself. Column reorders still arrive through `onValueChange`. ## API Reference ### Kanban The root component that provides the kanban context and manages the items state. | Prop | Type | Default | Description | | :---------------- | :---------------------------------------------------------------- | :------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `value` | `Record` | - | `Required`. The current state of columns and their items. | | `onValueChange` | `(value: Record) => void` | - | `Required`. Fired when items move within or between columns. In the default mode it also fires during the drag to render the live preview, so avoid persisting from here directly. | | `getItemValue` | `(item: T) => string` | - | `Required`. Function to get a unique identifier for an item. | | `onValueCommit` | `(value: Record, meta: KanbanCommitMeta) => void` | - | Fired once per completed drag with the final board and a `previousValue` snapshot. Use it to persist moves to a backend. See [Persisting moves](#persisting-moves). | | `onMove` | `(event: KanbanMoveEvent) => void` | - | Opt-in single commit point for item moves. When set, the live preview is disabled and you apply the move yourself. | | `restoreOnCancel` | `boolean` | `false` | When `true`, cancelling a drag (for example pressing Escape) restores the board to its pre-drag arrangement. | | `onDragStart` | `(event: DragStartEvent) => void` | - | Raw dnd-kit passthrough, fired when a drag starts. | | `onDragEnd` | `(event: DragEndEvent) => void` | - | Raw dnd-kit passthrough, fired after internal cleanup and before the final `onValueChange`/`onMove` call. In the default mode, `onValueChange` has already fired during dragOver. | | `onDragCancel` | `(event: DragCancelEvent) => void` | - | Raw dnd-kit passthrough, fired when a drag is cancelled. | | `accessibility` | `DndContextProps["accessibility"]` | - | dnd-kit accessibility options (announcements and screen reader instructions). | | `modifiers` | `Modifiers` | - | dnd-kit modifiers applied to the drag. | | `className` | `string` | - | Additional CSS classes for the container. | `KanbanCommitMeta` is `{ kind: "item" | "column"; event: DragEndEvent; activeContainer: string; activeIndex: number; overContainer: string; overIndex: number; previousValue: Record }`. *** ### KanbanBoard The horizontal container for kanban columns. | Prop | Type | Default | Description | | :---------- | :------- | :------ | :------------------------------------ | | `className` | `string` | - | Additional CSS classes for the board. | *** ### KanbanColumn An individual column within the kanban board. | Prop | Type | Default | Description | | :---------- | :------- | :------ | :------------------------------------------------ | | `value` | `string` | - | `Required`. The unique identifier for the column. | | `className` | `string` | - | Additional CSS classes for the column. | *** ### KanbanColumnHandle The drag handle for a column (if columns are sortable). | Prop | Type | Default | Description | | :---------- | :------- | :------ | :------------------------------------- | | `className` | `string` | - | Additional CSS classes for the handle. | *** ### KanbanColumnContent The scrollable area within a column that holds the items. | Prop | Type | Default | Description | | :---------- | :------- | :------ | :---------------------------------------------------------------- | | `value` | `string` | - | `Required`. The identifier of the column this content belongs to. | | `className` | `string` | - | Additional CSS classes for the content area. | *** ### KanbanItem An individual draggable item within a column. | Prop | Type | Default | Description | | :---------- | :-------- | :------ | :---------------------------------------------- | | `value` | `string` | - | `Required`. The unique identifier for the item. | | `disabled` | `boolean` | `false` | Whether the item is draggable. | | `className` | `string` | - | Additional CSS classes for the item. | *** ### KanbanItemHandle The drag handle for an individual item. | Prop | Type | Default | Description | | :---------- | :------- | :------ | :------------------------------------- | | `className` | `string` | - | Additional CSS classes for the handle. | *** ### KanbanOverlay The ghost element displayed during a drag operation. | Prop | Type | Default | Description | | :---------- | :------- | :------ | :-------------------------------------- | | `className` | `string` | - | Additional CSS classes for the overlay. | ## All 6 variations ### Kanban board with frame columns ### Minimal kanban with stacked frame ### Feature roadmap kanban with progress # Like Button URL: https://www.spaceui.one/components/like-button *** title: Like Button description: A like button with burst particles, a ripple ring, a spring-animated heart, and a smooth NumberFlow count transition. preview: name: demo-c-like-button-01 --------------------------- ## Installation # Liquid Mask Crossfade URL: https://www.spaceui.one/components/liquid-mask-crossfade *** title: Liquid Mask Crossfade description: A WebGL shader component featuring interactive liquid cursor mask crossfade with dynamic trail, refraction, and parallax effects. preview: name: demo-c-liquid-mask-crossfade-01 contained: false ---------------- ## Installation ## Usage ```tsx import { LiquidMaskCrossfade } from '@/components/shader/liquid-mask-crossfade' export default function Example() { return ( ) } ``` ## API Reference | Prop | Type | Default | Description | | ------------------ | -------- | ----------- | --------------------------------------------- | | `imageA` | `string` | `-` | Outer base texture URL | | `imageB` | `string` | `-` | Inner revealed texture URL | | `radius` | `number` | `0.15` | Base radius of the liquid cursor droplet | | `distortion` | `number` | `0.18` | Liquid noise distortion intensity | | `noiseScale` | `number` | `5.7` | Scale of the FBM procedural noise | | `speed` | `number` | `0.1` | Animation speed of procedural liquid noise | | `edgeSoftness` | `number` | `0.06` | Softness and blur width of the mask boundary | | `refraction` | `number` | `0.14` | Strength of the chromatic refraction effect | | `parallax` | `number` | `0.05` | Depth parallax movement of the inner image | | `mouseSmoothness` | `number` | `0.06` | Cursor lerp smoothing factor | | `trailLength` | `number` | `1.08` | Length spacing of the cursor droplet trail | | `trailPersistence` | `number` | `0.65` | Persistence and drag memory of the trail | | `trailTaper` | `number` | `0.86` | Taper ratio from cursor head to trail tail | | `idleDelay` | `number` | `2.0` | Seconds of inactivity before fade out begins | | `fadeDuration` | `number` | `0.35` | Fade-in duration when pointer enters or moves | | `fadeOutDuration` | `number` | `0.7` | Fade-out duration when cursor goes idle | | `aspectRatio` | `number` | `undefined` | Optional aspect ratio override | | `className` | `string` | `undefined` | Additional Tailwind CSS classes | # Liquid Mesh Blur URL: https://www.spaceui.one/components/liquid-mesh-blur *** title: Liquid Mesh Blur description: Organic liquid mesh gradient shader background blending orbiting particle clusters through a high-radius Gaussian blur diffusion filter. preview: demo-c-liquid-mesh-blur-01 defaultMode: split isPro: true ----------- ## Installation ## Usage ```tsx import { LiquidMeshBlur } from '@/components/shader/liquid-mesh-blur' export default function SpaceUI() { return (
) } ``` ## Examples ### Top Ambient Glow ## API Reference | Prop | Type | Default | Description | | -------------------- | --------------------- | -------------------------------------------------------------------- | ---------------------------------------------------- | | `colors` | `string[]` | `['#7C5CFC', '#0EA5E9', '#FF6F59', '#B8EE3A', '#E040FB', '#06B6D4']` | Array of hex color strings for fluid clusters | | `color1` .. `color6` | `string` | — | Direct overrides for individual cluster colors | | `blur` | `number` | `60` | Gaussian blur diffusion radius in pixels | | `speed` | `number` | `1` | Orbit & drift velocity multiplier | | `particleCount` | `number` | `70` | Total number of animated fluid particles | | `minSize` | `number` | `130` | Minimum particle radius in pixels | | `maxSize` | `number` | `230` | Maximum particle radius in pixels | | `contrast` | `number` | `1.1` | Color contrast multiplier applied with blur filter | | `interactive` | `boolean` | `true` | Enables pointer tracking attraction & repulsion | | `className` | `string` | — | Optional container CSS class name | | `style` | `React.CSSProperties` | — | Inline styles for wrapper container | | `children` | `React.ReactNode` | — | Content overlaid cleanly on top of the liquid canvas | # Liquid Metal Border URL: https://www.spaceui.one/components/liquid-metal-border *** title: Liquid Metal Border description: Liquid metal shader as a border wrap. Put any registry component inside. preview: name: demo-c-liquid-metal-border-01 className: mb-4 --------------- ## Installation ## Usage ```tsx import { LiquidBorder } from '@/components/spaceui/liquid-metal-border' import { Avatar } from '@/components/ui/avatar' import { AvatarFallback } from '@/components/spaceui/avatar-extended' ; ``` `rounded-*` and `p-0.75` on `LiquidBorder` are the metal ring. ## Variants ### Button ### Card ### Presets ## Props | Prop | Type | Default | Description | | ------------------- | -------------------------------------------------------------------- | ---------- | ---------------------------------------------- | | `children` | `node` | — | Any registry component | | `preset` | `'chrome' \| 'gold' \| 'ocean' \| 'sunset' \| 'emerald' \| 'violet'` | `'chrome'` | Built-in metal tint and fallback palette | | `colorBack` | `string` | — | Custom base metal color (overrides preset) | | `colorTint` | `string` | — | Custom highlight tint color (overrides preset) | | `fallbackClassName` | `string` | — | CSS linear gradient classes for fallback layer | | `innerClassName` | `string` | — | Class names for the relative content wrapper | | `speed` | `number` | `0.6` | Animation speed | | `repetition` | `number` | `4` | Pattern repeats | | `softness` | `number` | `0.5` | Highlight softness | | `shiftRed` | `number` | `0.3` | Red shift | | `shiftBlue` | `number` | `0.3` | Blue shift | | `distortion` | `number` | `0` | Distortion | | `contour` | `number` | `0` | Contour | | `angle` | `number` | `45` | Pattern angle | | `scale` | `number` | `8` | Pattern scale | | `offsetX` | `number` | `0.1` | X offset | | `offsetY` | `number` | `-0.1` | Y offset | # Liquid Sortable List URL: https://www.spaceui.one/components/liquid-sortable-list *** title: Liquid Sortable List description: Smooth drag-and-drop sortable team list with generative avatars and spring reordering. preview: demo-c-liquid-sortable-list-01 --------------------------------------- ## Installation ## Usage ```tsx import { LiquidSortableList } from '@/components/spaceui/liquid-sortable-list' export default function Example() { return } ``` ## Props | Prop | Type | Default | Description | | --------------- | ----------------------------------- | -------------------- | ---------------------------- | | `items` | `SortableMember[]` | `DEFAULT_MEMBERS` | Items with avatars and roles | | `onOrderChange` | `(items: SortableMember[]) => void` | `—` | Callback when order changes | | `title` | `string` | `'Reorder Priority'` | Header title | | `corner` | `number` | `20` | Card corner radius | # Liquid Switch URL: https://www.spaceui.one/components/liquid-switch *** title: Liquid Switch description: Elastic toggle switch with velocity-based organic stretch and spring return physics. preview: demo-c-liquid-switch-01 -------------------------------- ## Installation ## Usage ```tsx import { LiquidSwitch } from '@/components/spaceui/liquid-switch' export default function Example() { return } ``` ## Props | Prop | Type | Default | Description | | ----------------- | ---------------------------- | ------- | --------------------------------- | | `checked` | `boolean` | `—` | Controlled checked state | | `defaultChecked` | `boolean` | `false` | Default checked state | | `onCheckedChange` | `(checked: boolean) => void` | `—` | Toggle change callback | | `stretch` | `number` | `36` | Dynamic elongation factor (0-100) | | `label` | `string` | `—` | Optional companion label | | `disabled` | `boolean` | `false` | Disabled interaction | # Loading Orb URL: https://www.spaceui.one/components/loading *** title: Loading Orb description: Matrix pixel grid loader with Tailwind color support, spring motion presets, and assistant status cards. preview: demo-c-orb-loading-01 ------------------------------ ## Installation ## Usage ```tsx import { LoadingOrb, BuildingLoader } from '@/components/orb/loading' export default function App() { return (
{/* Standard loader cycling states with Tailwind color */} {/* Specific pattern locked */} {/* Companion assistant status card */}
) } ``` ## Features ### All States Overview All 6 geometric matrix patterns (`diamond`, `corners`, `bands`, `scatter`, `diagonal`, `glyph`) displayed simultaneously on a single line: ### Tailwind Colors Style with standard Tailwind text or background utilities (`text-primary`, `text-emerald-500`, `text-indigo-500`, etc.). Tonal depth is automatically calculated across opacities: ### Assistant Status Banner Agentic workflow status card with reactive states and real-time shimmer progress: ## API Reference ### LoadingOrb | Prop | Type | Default | Description | | -------------- | ----------------------------------------------------------------------------------- | -------------- | ----------------------------------------------------------------------------- | | `size` | `number` | `56` | Pixel size of the 4x4 matrix container | | `speed` | `number` | `750` | Interval in milliseconds between pattern steps | | `pattern` | `'diamond' \| 'corners' \| 'bands' \| 'scatter' \| 'diagonal' \| 'glyph' \| number` | `undefined` | Specific pattern to display, or omitted to auto-cycle | | `motionPreset` | `'morph' \| 'fade' \| 'scale' \| 'blur' \| 'flip'` | `'morph'` | Spring animation curve applied on cell transitions | | `className` | `string` | — | Tailwind classes (e.g. `text-foreground`, `text-primary`, `text-emerald-500`) | | `dotClassName` | `string` | `'bg-current'` | Custom Tailwind utility applied to every cell | | `radius` | `number` | `3` | Border radius in pixels for each matrix dot | | `gap` | `number` | `3` | Spacing between dots in pixels | | `showGhost` | `boolean` | `false` | When true, renders inactive dots with subtle ghost opacity | ### BuildingLoader | Prop | Type | Default | Description | | ------------- | ----------------------------------------------------------------------------------- | ----------------------------------- | -------------------------------------------------------------- | | `state` | `string` | `'Building'` | Primary state label (e.g. "Building", "Thinking", "Searching") | | `detail` | `string` | `'Composing response from context'` | Secondary explanatory caption | | `showShimmer` | `boolean` | `true` | Whether to display the bottom shimmer progress bar | | `size` | `number` | `38` | Size of the embedded `LoadingOrb` | | `pattern` | `'diamond' \| 'corners' \| 'bands' \| 'scatter' \| 'diagonal' \| 'glyph' \| number` | `undefined` | Specific pattern for the embedded orb | | `className` | `string` | — | Classes for the container card | # Member Selector URL: https://www.spaceui.one/components/member-selector *** title: Member Selector description: An interactive participant and member avatar selector with dynamic row layout, animated selection badges, quick-add button, and searchable popover. preview: name: demo-c-member-selector-01 contained: false ---------------- ## Installation ## Usage ```tsx import { MemberSelector } from '@/components/spaceui/member-selector' ``` ```tsx const [selected, setSelected] = useState(['1', '2']) ``` ## API Reference ### MemberSelector Props | Prop | Type | Default | Description | | ------------ | ------------------------------ | ------------ | ------------------------------------------------------------- | | `members` | `Member[]` | **required** | List of available members (`id`, `name`, `email?`, `avatar?`) | | `selected` | `string[]` | **required** | Array of currently selected member IDs | | `onChange` | `(selected: string[]) => void` | **required** | Callback when selection changes | | `max` | `number` | - | Optional maximum number of selectable members | | `maxVisible` | `number` | `5` | Maximum number of avatars displayed in horizontal row | | `label` | `string` | - | Optional header label (e.g. "Participants") | | `className` | `string` | - | Additional class names applied to the container | # Mesh Gradient URL: https://www.spaceui.one/components/mesh-gradient *** title: Mesh Gradient description: Dynamic WebGL mesh gradient shader background featuring fluid swirls, configurable color stops, distortion turbulence, and film grain overlay. preview: demo-c-mesh-gradient-01 defaultMode: split ------------------ ## Installation Depends on `@paper-design/shaders-react`. WebGL required. ## Usage ```tsx import { MeshGradient } from '@/components/shader/mesh-gradient' export default function SpaceUI() { return (
) } ``` ## API Reference | Prop | Type | Default | Description | | ----------------- | ------------------------------ | ----------------------------------- | ----------------------------------------- | | `colors` | `string[]` | `['#085b96', '#51a0f6', '#cfe5f2']` | Array of color stops for the gradient | | `speed` | `number` | `1` | Time progression multiplier for animation | | `distortion` | `number` | `1` | Turbulence wave amplitude | | `swirl` | `number` | `0.57` | Rotational vortex intensity | | `swirlIterations` | `number` | `7.4` | Depth of swirl fractal iterations | | `softness` | `number` | `1` | Blur and color blend smoothness | | `proportion` | `number` | `0` | Center color distribution bias | | `shape` | `'edge' \| 'wave' \| 'circle'` | `'edge'` | Primary gradient geometry type | | `shapeScale` | `number` | `0.59` | Geometric scale factor | | `scale` | `number` | `1.45` | Global mesh magnification | | `rotation` | `number` | `120` | Initial angular orientation in degrees | | `grain` | `boolean` | `true` | Organic film grain overlay texture | | `className` | `string` | — | Wrapper CSS class name | | `style` | `React.CSSProperties` | — | Inline style object | # Morph Icon URL: https://www.spaceui.one/components/morph-icon *** title: Morph Icon description: Transforms one vector icon smoothly into another with fluid shape morphing animations when state changes. preview: demo-c-morph-icon-01 ----------------------------- ## Installation ## Usage ```tsx import { MorphIcon } from '@/components/spaceui/morph-icon' import { IconSun, IconMoon } from '@tabler/icons-react' ``` ```tsx ``` ## API Reference ### MorphIcon Props | Prop | Type | Default | Description | | ----------- | ------------------------------------------------------ | -------------- | ----------------------------------------------------------------------- | | `activeKey` | `React.Key` | **Required** | Unique key identifying current active icon/state to trigger transitions | | `children` | `React.ReactNode` | **Required** | The icon element to render | | `variant` | `"blur-scale" \| "rotate-scale" \| "flip" \| "spring"` | `"blur-scale"` | Motion transition preset style | | `duration` | `number` | `0.22` | Transition duration in seconds | | `className` | `string` | `undefined` | Additional classes applied to the motion wrapper | *** ### Theme Switcher Transition Smooth morphing between sun, moon, and system desktop icons. ### Action & Status Toggles Common UI action buttons (like/heart, volume/mute, play/pause, upvote) with instant morphing transitions. ### Animation Presets Side-by-side comparison of all 4 motion presets: `blur-scale`, `rotate-scale`, `flip`, and `spring`. ### Multi-State Status Indicator Morphing through multi-stage state transitions (pending, loading, success, error). ### Accordion & Visibility Toggles Password reveal and accordion expand/collapse transitions using `MorphIcon`. ## Examples # Morphing Area URL: https://www.spaceui.one/components/morphing-area *** title: Morphing Area description: Adaptive aspect ratio surface with constant-area morphing for any child element, card, or media. preview: demo-c-morphing-area-01 -------------------------------- ## Installation ## Usage ```tsx import { MorphingArea } from '@/components/spaceui/morphing-area' export default function Example() { return ( ) } ``` You can pass any content as `children`, including custom UI cards, gradients, or media: ```tsx

Dynamic Card

Morphs smoothly across aspect ratios.

``` ## Props | Prop | Type | Default | Description | | ----------- | ------------------------------------------------------------------- | ------- | ----------------------------------------------------------------- | | `children` | `React.ReactNode` | `—` | Child elements (images, cards, media) to morph. | | `ratio` | `'4:3' \| '1:1' \| '3:4' \| '16:9' \| 'land' \| 'square' \| 'tall'` | `'1:1'` | Target aspect ratio for constant-area surface morphing. | | `width` | `string \| number` | `—` | Optional explicit width override. | | `height` | `string \| number` | `—` | Optional explicit height override. | | `rounded` | `number` | `8` | Corner radius in pixels (min 0). | | `squircle` | `boolean` | `false` | Enables continuous squircle curvature via `@usespaceui/squircle`. | | `morph` | `number` | `50` | Morph transition spring duration modifier (0–100). | | `className` | `string` | `—` | Additional class names. | # Morphing Command Bar URL: https://www.spaceui.one/components/morphing-command-bar *** title: Morphing Command Bar description: Elastic command bar that expands seamlessly from passive state to active input with action trigger. preview: demo-c-morphing-command-bar-01 --------------------------------------- ## Installation ## Usage ```tsx import { MorphingCommandBar } from '@/components/spaceui/morphing-command-bar' export default function Example() { return } ``` ## Props | Prop | Type | Default | Description | | ------------- | ------------------------- | ----------------------------------------- | ---------------------- | | `placeholder` | `string` | `'Search components, actions or docs...'` | Input placeholder text | | `onSubmit` | `(query: string) => void` | `—` | Submit callback | | `corner` | `number` | `28` | Corner radius in px | # Morphing Search Pill URL: https://www.spaceui.one/components/morphing-search-pill *** title: Morphing Search Pill description: Adaptive search pill that expands smoothly from a compact button into a full input field. preview: demo-c-morphing-search-pill-01 --------------------------------------- ## Installation ## Usage ```tsx import { MorphingSearchPill } from '@/components/spaceui/morphing-search-pill' export default function Example() { return } ``` ## Props | Prop | Type | Default | Description | | ---------------- | ------------------------- | ------------------- | -------------------------- | | `placeholder` | `string` | `'Quick search...'` | Search field placeholder | | `onSearch` | `(query: string) => void` | `—` | Search query callback | | `collapsedWidth` | `number` | `64` | Width when collapsed in px | | `expandedWidth` | `number` | `280` | Width when expanded in px | | `corner` | `number` | `20` | Pill corner radius | # Morphing Text URL: https://www.spaceui.one/components/morphing-text *** title: Morphing Text description: Seamless character-level FLIP morphing animation between words or phrases with pause-on-hover capability. preview: name: demo-c-morphing-text-01 contained: false ---------------- A fluid character-morphing typography component that rearranges matching letters into their next positions using shared layout IDs and blur transitions. ## Installation ## Examples ### Full Phrases & Sentences Morph seamlessly across full multi-word sentences and headlines with fluid character travel. ## Usage ```tsx import { MorphingText } from '@/components/spaceui/morphing-text' const words = ['Morphing', 'Motion', 'Animation', 'Dimension', 'Precision'] export default function RotatingHeadline() { return ( ) } ``` ## Props ### MorphingText | Prop | Type | Default | Description | | --------------- | ----------------------------- | ------------ | --------------------------------------------------------------------------------------------------------- | | `texts` | `string[]` | **required** | The list of words or phrases to cycle through sequentially. | | `interval` | `number` | `2400` | Time in milliseconds before advancing to the next phrase. | | `pauseOnHover` | `boolean` | `true` | When true, pauses timer when cursor is hovered over the text. | | `blurAmount` | `string` | `'10px'` | Blur radius applied to entering and exiting characters. | | `springBounce` | `number` | `0.14` | Spring bounce factor (0 to 1) for layout transitions. | | `className` | `string` | `undefined` | Custom styling for the wrapper container. | | `textClassName` | `string` | `undefined` | Custom styling for the text component. | | `renderChar` | `(char: string) => ReactNode` | `undefined` | Overrides how each character token renders — e.g. through Textmoji so emoji stay styled across the morph. | ### TextMorph (Single Morph) You can also use `` directly for fine-grained control when morphing between custom state values: ```tsx import { TextMorph } from '@/components/spaceui/morphing-text' export function DynamicStatus({ status }: { status: string }) { return {status} } ``` # Notification List URL: https://www.spaceui.one/components/notification-list *** title: Notification List description: Displays an interactive feed of incoming notifications with unread indicators, timestamps, and swipe-to-dismiss actions. author: name: arhamkhnz url: [https://github.com/arhamkhnz](https://github.com/arhamkhnz) preview: demo-c-notification-list-01 ------------------------------------ ## Installation ## Usage ```tsx ``` ## Credits * Credits to [Alexander Avdeev](https://x.com/privetavdey) for [this X post](https://x.com/privetavdey/status/1932774726889586780) as inspiration # Paper Shader URL: https://www.spaceui.one/components/paper-shader *** title: Paper Shader description: Paper Shaders WebGL2 canvas. Pass a fragment shader and uniforms; the mount compiles, resizes, and ticks time. preview: demo-c-paper-shader-01 defaultMode: split ------------------ The canvas is `registry/components/shader/paper-shader/index.tsx` (default export `PaperShader`). The demo fragment lives in `demo/components/shader/paper-shader/c-paper-shader-1/shader-source.tsx`. ## Installation ## Usage ```tsx import PaperShader from '@/components/shader/paper-shader' export default function SpaceUI() { return ( ) } ``` ## Files | File | Role | | ------------------------------------ | ---------------------------------------- | | `paper-shader/index.tsx` | WebGL2 mount, compile, uniforms, dispose | | `c-paper-shader-1/index.tsx` | Demo wrapper | | `c-paper-shader-1/shader-source.tsx` | Example GLSL 300 es fragment | ## API Reference | Prop | Type | Default | Description | | ------------------------ | ------------------------- | ------------ | ------------------------------------------------- | | `fragmentShader` | `string` | **required** | GLSL 300 es fragment source | | `uniforms` | `Record` | `{}` | Values uploaded each frame (`u_time` is injected) | | `speed` | `number` | `0` | Time multiplier | | `webGlContextAttributes` | `WebGLContextAttributes` | — | Context flags | | `minPixelRatio` | `number` | — | DPR floor | | `maxPixelCount` | `number` | — | Pixel cap for large canvases | | `style` | `CSSProperties` | — | Outer div style | The parent must be positioned; the canvas is `absolute inset-0`. # Phone Input URL: https://www.spaceui.one/components/phone-input *** title: Phone Input description: Allows users to enter international phone numbers with automatic country flag detection, dial codes, and formatted digits. component: true base: base links: api: [https://gitlab.com/catamphetamine/react-phone-number-input](https://gitlab.com/catamphetamine/react-phone-number-input) preview: name: demo-c-phone-input-01 className: '\[&*.preview>\*]:w-full \[&*.preview>\*]:max-w-xs' -------------------------------------------------------------- We used the [react-phone-number-input](https://gitlab.com/catamphetamine/react-phone-number-input) library to create this component. ## Installation ## Usage ```tsx import { PhoneInput } from '@/components/spaceui/phone-input' ``` ```tsx ``` ## Examples ### Size ## API Reference ### PhoneInput The main component for entering phone numbers with country selection. | Prop | Type | Default | Description | | :--------------- | :-------------------------- | :---------- | :--------------------------------------------------------- | | `value` | `string` | - | The current phone number value in E.164 format. | | `onChange` | `(value: string) => void` | - | Callback fired when the value changes. | | `variant` | `"sm" \| "default" \| "lg"` | `"default"` | The vertical size of the input and country selector. | | `popupClassName` | `string` | - | Additional CSS classes for the country selection dropdown. | | `defaultCountry` | `Country` | - | The default country selected if no value is provided. | | `placeholder` | `string` | - | Placeholder text for the phone number input. | | `className` | `string` | - | Additional CSS classes for the root container. | | `disabled` | `boolean` | `false` | Whether the input and country selector are disabled. | *** ### Utilities The component re-exports essential phone number utilities: ```tsx import { PhoneInput, isValidPhoneNumber, formatPhoneNumber, formatPhoneNumberIntl, isPossiblePhoneNumber, getCountryCallingCode, } from '@/components/spaceui/phone-input' ``` * **`isValidPhoneNumber(value)`**: Checks if the phone number is valid according to international metadata. * **`formatPhoneNumber(value)`**: Formats the phone number in national format. * **`formatPhoneNumberIntl(value)`**: Formats the phone number in international format (e.g. `+1 213 373 4253`). * **`isPossiblePhoneNumber(value)`**: Quick length check to see if the number could be possible. * **`getCountryCallingCode(country)`**: Returns the calling code for a given ISO country code (e.g. `'FR'` -> `'33'`). *** ### External Props This component also accepts all props from the [react-phone-number-input](https://gitlab.com/catamphetamine/react-phone-number-input#props) library. ## Examples ### Large phone input ### Disabled phone input ### Phone input with preset value ### Phone input with error state ### Phone input with specific default country ### Read-only phone input ### Real-time validation ### With Field, Label and Description # Pin List URL: https://www.spaceui.one/components/pin-list *** title: Pin List description: Provides a quick-access bar where users can pin, organize, and reorder favorite items, documents, or shortcuts. author: name: arhamkhnz url: [https://github.com/arhamkhnz](https://github.com/arhamkhnz) preview: demo-c-pin-list-01 --------------------------- ## Installation ## Usage ```tsx ``` ## API Reference ### PinList ## Credits * Credits to [Nitish Khagwal](https://x.com/nitishkmrk) for [this X post](https://x.com/nitishkmrk/status/1933050634594660800) as inspiration # Pixel Fill Button URL: https://www.spaceui.one/components/pixel-fill-button *** title: Pixel Fill Button description: An interactive button whose background fills with square matrix pixels radiating from the cursor entry point on hover. preview: name: demo-c-pixel-fill-button-01 contained: false ---------------- ## Installation ## Usage ```tsx import { PixelFillButton } from '@/components/spaceui/pixel-fill-button' export default function Example() { return (
{/* Classic */} Classic Button {/* Silk Border */} Silk Edition {/* Metal Border */} Metal Edition
) } ``` ## API Reference | Prop | Type | Default | Description | | ------------------ | ------------------------------------------ | ------------ | ------------------------------------------------------------- | | `children` | `ReactNode` | — | Button label / icons | | `borderEffect` | `'default' \| 'silk' \| 'metal' \| 'none'` | `'default'` | Active border styling wrapper (Silk shader or Liquid Metal) | | `silkPreset` | `SilkPreset` | `'twilight'` | Preset palette for the Silk Border ('aurora', 'sunset', etc.) | | `metalPreset` | `LiquidPreset` | `'chrome'` | Preset finish for the Metal Border ('gold', 'violet', etc.) | | `pixelColor` | `string` | `'#ffe9a8'` | Color of the expanding matrix pixels | | `textColorOnHover` | `string` | `'#000000'` | Color applied to the text when pixel-filled | | `pixelSize` | `number` | `4` | Size in pixels of each square grain | | `blurAmount` | `string` | `'8px'` | Text transition blur amount | | `squircle` | `boolean` | `true` | Smooth squircle curvature styling | | `href` | `string` | — | Optional URL (renders an `` tag when provided) | | `borderClassName` | `string` | — | Custom class names for the outer border container | | `className` | `string` | — | Custom class names for the button element | # Pixel Reveal Image URL: https://www.spaceui.one/components/pixel-reveal-image *** title: Pixel Reveal Image description: A WebGL image component with dynamic pixel matrix wave and customizable neon accent border on scroll. preview: name: demo-c-pixel-reveal-image-01 contained: false ---------------- ## Installation ## Usage ```tsx import { PixelRevealImage } from '@/components/shader/pixel-reveal-image' export default function Example() { return } ``` ## API Reference | Prop | Type | Default | Description | | ---------------- | ------------------------------------ | ----------------------- | ---------------------------------------------------------- | | `src` | `string` | — | Path or URL to the source image | | `alt` | `string` | `'Pixel reveal visual'` | Accessible image label | | `accentColor` | `string` | `'#ffe9a8'` | Accent color for transition edge pixels (Aurum by default) | | `gridDensity` | `number` | `40` | Number of pixel blocks across the matrix grid | | `bandWidth` | `number` | `3.5` | Thickness of the glowing pixel transition wave | | `noiseIntensity` | `number` | `0.16` | Procedural jitter noise dispersion | | `direction` | `'top-to-bottom' \| 'bottom-to-top'` | `'bottom-to-top'` | Wavefront sweep direction | | `progress` | `number` | — | Optional controlled progress value (0 to 1) | | `aspectRatio` | `number` | `3 / 4` | Aspect ratio of the canvas container | # Pixel Reveal Text URL: https://www.spaceui.one/components/pixel-reveal-text *** title: Pixel Reveal Text description: A typography shader component that materializes text out of pixel matrix noise with neon contour highlights on scroll. preview: name: demo-c-pixel-reveal-text-01 contained: false ---------------- ## Animoji Phrases The same loop effect cycling through a rotating set of phrases, in top of the Animoji component. ## Installation ## Usage ```tsx import { PixelRevealText } from '@/components/spaceui/pixel-reveal-text' export default function Example() { return } ``` ## API Reference | Prop | Type | Default | Description | | --------------- | ------------------ | ----------- | ---------------------------------------------------------- | | `text` | `string` | — | Text content to reveal | | `fontSize` | `number` | `44` | Font size in pixels | | `fontFamily` | `string` | `'inherit'` | CSS font family | | `fontWeight` | `string \| number` | `600` | Font weight | | `color` | `string` | — | Base text color (inherits from theme if omitted) | | `edgeColor` | `string` | `'#ffe9a8'` | Accent color of the advancing wavefront (Aurum by default) | | `pixelSize` | `number` | `4` | Resolution of pixel blocks | | `noiseStrength` | `number` | `0.35` | Degree of matrix randomness during reveal | | `progress` | `number` | — | Optional controlled reveal progress (0 to 1) | # Rainbow Glow Border URL: https://www.spaceui.one/components/rainbow-glow-border *** title: Rainbow Glow Border description: Smooth animated rainbow glow border wrap with drifting color orbs. Put any registry component inside. isPro: true preview: name: demo-c-rainbow-glow-border-01 className: mb-4 --------------- ## Installation ## Usage ```tsx import { RainbowGlowBorder } from '@/components/spaceui/rainbow-glow-border' import { Avatar } from '@/components/ui/avatar' import { AvatarFallback } from '@/components/spaceui/avatar-extended' ; ``` `rounded-*` and `p-0.75` on `RainbowGlowBorder` control the glow ring shape and thickness. ## Variants ### Button ### Card ### Presets ## Props | Prop | Type | Default | Description | | ---------------- | -------------------------------------------------------------------- | ----------- | -------------------------------------------------------------- | | `children` | `React.ReactNode` | — | Any registry component | | `preset` | `'rainbow' \| 'aurora' \| 'sunset' \| 'neon' \| 'cyber' \| 'chrome'` | `'rainbow'` | Built-in animated palette presets | | `orbs` | `OrbConfig[]` | — | Custom array of orb colors and trajectories (overrides preset) | | `innerClassName` | `string` | — | Class names for the relative content wrapper | | `blur` | `number` | `6` | Gaussian blur radius applied to drifting orbs in pixels | | `duration` | `number` | `3` | Loop duration in seconds for each cycle | # Rainbow Glow Button URL: https://www.spaceui.one/components/rainbow-glow-button *** title: Rainbow Glow Button description: An interactive dark pill button featuring 6 orbiting colorful blurred orbs and a blur reveal transition on hover. preview: name: demo-c-rainbow-glow-button-01 contained: false ---------------- ## Installation ## Usage ```tsx import { RainbowGlowButton } from '@/components/spaceui/rainbow-glow-button' ``` ```tsx export default function Example() { return ( Get pro ) } ``` ## API Reference ### RainbowGlowButton Props | Prop | Type | Default | Description | | ----------- | ----------------- | -------------- | ----------------------------------------------------------- | | `as` | `'button' \| 'a'` | `'button'` | Render as a button or an anchor link. | | `href` | `string` | — | Target link URL when `as="a"`. | | `orbs` | `OrbConfig[]` | `DEFAULT_ORBS` | Custom array of orb colors and coordinate motion keyframes. | | `className` | `string` | — | Additional CSS class names. | | `children` | `React.ReactNode` | — | Content displayed within the button label. | # Rating URL: https://www.spaceui.one/components/rating *** title: Rating description: Allows users to submit ratings or view average customer scores using interactive star icons with half-star precision. component: true base: base preview: demo-c-rating-01 ------------------------- ## Installation ## Usage ```tsx import { Rating } from '@/components/spaceui/rating' ``` ```tsx ``` ## Examples ### Decimal ### Show Value ### Editable ### Size ## API Reference ### Rating The main component for displaying and editing star ratings. | Prop | Type | Default | Description | | :--------------- | :-------------------------- | :------ | :--------------------------------------------------------------------------------- | | `rating` | `number` | - | **Required**. The current rating value. Supports decimal values for partial stars. | | `maxRating` | `number` | `5` | Total number of stars to display. | | `size` | `"sm" \| "default" \| "lg"` | `"md"` | The size of the stars and spacing. | | `showValue` | `boolean` | `false` | Whether to show the numeric rating value next to the stars. | | `editable` | `boolean` | `false` | Whether the rating can be changed by clicking on stars. | | `onRatingChange` | `(rating: number) => void` | - | Callback fired when a star is clicked (if `editable` is true). | | `starClassName` | `string` | - | Additional CSS classes for the numeric value container. | | `className` | `string` | - | Additional CSS classes for the root container. | ## All 9 variations ### Rating with review summary ### Interactive half-star rating ### Emoji reaction rating ### Rating with review text input # Resizable URL: https://www.spaceui.one/components/resizable *** title: 'Resizable' description: Allows users to adjust side-by-side workspace panels by dragging divider handles to fit their screen needs. preview: demo-c-resizable-01 ---------------------------- ## Installation # Examples ## Horizontal resizable layout ## Vertical resizable layout. ## Nested mixed-direction resizable layout. ## Nested resizable ## Handle with animated pill indicator ## Handle pill with spring scale on drag ## Handle with large capsule expansion on drag ## Nested layout with animated pill handles ## Three-panel layout with animated pill handles ## State-tracked resizable layout. # Scatter Text URL: https://www.spaceui.one/components/scatter-text *** title: Scatter Text description: A text input whose content scatters into drifting canvas grains on submit. preview: name: demo-c-scatter-text-01 contained: false ---------------- ## Installation ## Usage ```tsx import { ScatterText } from '@/components/spaceui/scatter-text' export default function SpaceUI() { return console.log(value)} /> } ``` ## Files | File | Role | | ------------------------ | ------------------------------------------ | | `scatter-text/index.tsx` | Canvas rasterizing, scatter loop, the form | ## API Reference | Prop | Type | Default | Description | | ---------------- | -------------------------------------------- | ------- | ----------------------------------------- | | `placeholder` | `string` | — | Empty-state hint | | `value` | `string` | — | Controlled value | | `defaultValue` | `string` | `''` | Initial value when uncontrolled | | `onChange` | `(e: ChangeEvent) => void` | — | Fires on every keystroke | | `onSubmit` | `(value: string) => void` | — | Fires once the scatter animation finishes | | `className` | `string` | — | Outer form wrapper | | `inputClassName` | `string` | — | The `` element | Submit either by pressing Enter or clicking the trailing button. Grain color is sampled from the input's own computed text color, so it follows light/dark theme automatically. # Scroll Manifesto URL: https://www.spaceui.one/components/scroll-manifesto *** title: Scroll Manifesto description: A pinned statement that comes into focus word by word as you scroll. Each word rises, sharpens from a blur and lights up in reading order. isPro: true preview: name: demo-c-scroll-manifesto-01 contained: false align: start previewClassName: items-start ----------------------------- ## Installation ## Usage ```tsx import { ScrollManifesto } from '@/components/spaceui/scroll-manifesto' export default function Mission() { return ( ) } ``` The statement stays pinned while the reader scrolls through `scrollLength` viewport heights, then lets the page continue. It pins inside the nearest scrolling ancestor (a preview pane, a modal) or the window, and shows the text fully revealed when the reader prefers reduced motion. # Scroll Text Reveal URL: https://www.spaceui.one/components/scroll-text-reveal *** title: Scroll Text Reveal description: Progressive character-by-character and word-by-word text reveal driven by scroll progress. preview: name: demo-c-scroll-text-reveal-01 contained: false align: start previewClassName: items-start ----------------------------- ## Installation # Scrollspy URL: https://www.spaceui.one/components/scrollspy *** title: Scrollspy description: Tracks the user’s scroll position on the page and automatically highlights the corresponding link in the table of contents. component: true base: base preview: name: demo-c-scrollspy-01 align: start className: '\[&\_.preview>\[data-orientation=vertical]]:sm:max-w-\[80%] \*\*:\[.preview]:min-h-\[580px]' -------------------------------------------------------------------------------------------------------- ## Installation ## Usage ```tsx import { Scrollspy } from '@/components/spaceui/scrollspy' ``` ```tsx Section 1 Section 2
Content 1
Content 2
``` ## Examples ### Horizontal ## API Reference ### Scrollspy The main component that wraps the navigation links and manages the scroll spying logic. | Prop | Type | Default | Description | | :-------------- | :----------------------------------- | :------------ | :----------------------------------------------------------------- | | `targetRef` | `RefObject` | `window` | The scrollable container to monitor. | | `onUpdate` | `(id: string) => void` | - | Callback fired when the active section changes. | | `offset` | `number` | `0` | Global pixel offset from the top when calculating active sections. | | `smooth` | `boolean` | `true` | Whether to use smooth scrolling when clicking on anchors. | | `history` | `boolean` | `true` | Whether to update the URL hash when the active section changes. | | `dataAttribute` | `string` | `"scrollspy"` | The prefix for data attributes (e.g., `data-scrollspy-anchor`). | | `className` | `string` | - | Additional CSS classes for the wrapper. | *** ### Data Attributes Navigation links within `Scrollspy` should use these attributes to connect to sections: | Attribute | Description | | :---------------------- | :-------------------------------------------------------------- | | `data-scrollspy-anchor` | **Required**. The ID of the target section (without the `#`). | | `data-scrollspy-offset` | Optional. Overrides the global `offset` for this specific link. | The component adds `data-active="true"` to the link element when its corresponding section is active. # Section Scrollspy URL: https://www.spaceui.one/components/section-scrollspy *** title: Section Scrollspy description: Floating section scrollbar that tracks the active heading as you scroll. preview: name: demo-c-section-scrollspy-01 contained: false ---------------- Mark each block with `data-page-section` and an `h2`. The bar reads the heading (and an optional badge) then follows scroll. ## Installation ## Usage ```tsx import * as React from 'react' import { SectionScrollspy } from '@/components/spaceui/section-scrollspy' export default function SpaceUI() { const scrollRef = React.useRef(null) return (

Installation

) } ``` Pass `portal` to pin it to the viewport. Omit `containerRef` to track `window` scroll. ## API Reference | Prop | Type | Default | Description | | -------------- | ------------------------ | --------------------- | ------------------------------ | | `containerRef` | `RefObject` | — | Scroll root. Window if omitted | | `selector` | `string` | `[data-page-section]` | Section query | | `portal` | `boolean` | `false` | Render into `document.body` | | `className` | `string` | — | Root class | # Silk Border URL: https://www.spaceui.one/components/silk-border *** title: Silk Border description: Fluid WebGPU silk mesh gradient wrapper. Wrap avatars, badges, buttons, and cards with theme presets and CSS fallback. preview: name: demo-c-silk-border-01 className: mb-4 --------------- ## Installation ## Usage ```tsx import { SilkBorder } from '@/components/spaceui/silk-border' import { Avatar } from '@/components/ui/avatar' import { AvatarFallback } from '@/components/spaceui/avatar-extended' ; ``` `rounded-*` and `p-0.75` on `SilkBorder` form the silk outline ring with an automatic CSS gradient fallback if WebGPU is unsupported. ## Variants ### Button & Badge ### Card ### Presets ## Props | Prop | Type | Default | Description | | ------------------- | ---------------------------------------------------------------------------------------------- | --------- | ---------------------------------------------- | | `children` | `React.ReactNode` | — | Any component wrapped inside the border | | `preset` | `'aurora' \| 'ember' \| 'twilight' \| 'ocean' \| 'sunset' \| 'emerald' \| 'amber' \| 'violet'` | `'ember'` | Built-in silk color and fallback palette | | `color1` | `string` | — | Custom primary hex color | | `color2` | `string` | — | Custom secondary hex color | | `color3` | `string` | — | Custom tertiary hex color | | `speed` | `number` | `0.65` | Animation speed multiplier | | `animate` | `boolean` | `true` | Whether the silk mesh flows smoothly | | `grain` | `boolean` | `false` | Film grain texture overlay | | `fallbackClassName` | `string` | — | CSS linear gradient classes for fallback layer | | `innerClassName` | `string` | — | Class names for the relative content wrapper | # Silk Flare URL: https://www.spaceui.one/components/silk-flare *** title: Silk Flare description: WebGPU single-pass composite shader fusing silky mesh warp gradients and rising thermodynamic heat flares. preview: demo-c-silk-flare-01 defaultMode: split ------------------ ## Installation Depends on `vgpu`. WebGPU required. ## Usage ```tsx import { SilkFlare } from '@/components/shader/silk-flare' export default function SpaceUI() { return ( ) } ``` ## API Reference | Prop | Type | Default | Description | | ------------- | ------------------- | ------------------ | -------------------------------------------------- | | `color1` | `string` | required | First silk mesh base color | | `color2` | `string` | required | Mid warp mesh color | | `color3` | `string` | required | Dark silk blend color | | `hotColor` | `string` | `color3` | Peak flame/flare heat color | | `heatOpacity` | `number` | `0.5` | Intensity/opacity of the thermodynamic flare layer | | `from` | `'bottom' \| 'top'` | `'bottom'` | Direction of rising heat licks | | `speed` | `number` | `0.8` | Animation velocity | | `animate` | `boolean` | `true` | Play / pause animation | | `grain` | `boolean` | `true` | Film grain overlay | | `dpr` | `number` | `devicePixelRatio` | Target device pixel ratio cap | | `className` | `string` | — | Canvas class name | # Silk Gradient URL: https://www.spaceui.one/components/silk-gradient *** title: Silk Gradient description: WebGPU silk mesh. Three colors, warp, grain. Animation on by default. preview: demo-c-silk-gradient-01 defaultMode: split ------------------ ## Installation Depends on `vgpu`. WebGPU required. ## Usage ```tsx import { SilkGradient } from '@/components/shader/silk-gradient' export default function SpaceUI() { return } ``` ## API Reference | Prop | Type | Default | Description | | ----------- | --------- | -------- | --------------- | | `color1` | `string` | required | Light silk | | `color2` | `string` | required | Mid warp | | `color3` | `string` | required | Dark blend | | `speed` | `number` | `1` | Animation speed | | `animate` | `boolean` | `true` | Play / pause | | `grain` | `boolean` | `true` | Film grain | | `className` | `string` | — | Canvas class | # Slide To Confirm URL: https://www.spaceui.one/components/slide-to-confirm *** title: Slide To Confirm description: Tactile slide-to-confirm action slider with inertia spring physics. preview: demo-c-slide-to-confirm-01 ----------------------------------- ## Installation ## Usage ```tsx import { SlideToConfirm } from '@/components/spaceui/slide-to-confirm' export default function Example() { return } ``` ## Props | Prop | Type | Default | Description | | ---------------- | ------------ | -------------------- | ---------------------------- | | `label` | `string` | `'Slide to confirm'` | Track placeholder label | | `confirmedLabel` | `string` | `'Confirmed'` | Confirmed state label | | `onConfirm` | `() => void` | `—` | Callback on successful slide | | `resetDelay` | `number` | `2400` | Auto reset duration in ms | | `width` | `number` | `320` | Track width in px | | `speed` | `number` | `50` | Spring return speed (0-100) | | `corner` | `number` | `28` | Corner border radius | | `disabled` | `boolean` | `false` | Disabled state | # Slosh Slider URL: https://www.spaceui.one/components/slosh-slider *** title: Slosh Slider description: Liquid fill slider. Corner, viscosity, momentum, tilt. preview: demo-c-slosh-slider-01 ------------------------------- ## Installation ## Usage ```tsx import { SloshSlider } from '@/components/spaceui/slosh-slider' export default function Example() { const [value, setValue] = React.useState(42) return } ``` ## Props | Prop | Type | Default | Description | | --------------- | ------------------------- | ------- | ------------------------------------- | | `value` | `number` | — | Controlled value | | `min` | `number` | `0` | Minimum | | `max` | `number` | `100` | Maximum | | `step` | `number` | `1` | Snap | | `height` | `number \| string` | `40` | Slider track height in px or CSS unit | | `ring` | `boolean` | `true` | Inner offset frame ring around track | | `onValueChange` | `(value: number) => void` | — | Change handler | | `corner` | `number` | `13` | Fill radius, 0–20 | | `viscosity` | `number` | `15` | 0 rigid, 100 loose | | `momentum` | `number` | `55` | Coast after release | | `tilt` | `number` | `45` | Lean on the leading edge | # Smooth Slider URL: https://www.spaceui.one/components/smooth-slider *** title: Smooth Slider description: A continuous slider with a filled track, tick dots, and a draggable thumb. preview: demo-c-smooth-slider-01 -------------------------------- ## Installation ## Usage ```tsx import { SmoothSlider } from '@/components/spaceui/smooth-slider' export default function Example() { const [value, setValue] = React.useState(50) return } ``` ## Props | Prop | Type | Default | Description | | ---------------- | ------------------------- | ---------- | ----------------------------------------------------------------------------------------------- | | `value` | `number` | — | Controlled value | | `defaultValue` | `number` | `50` | Initial value when uncontrolled | | `min` | `number` | `0` | Floor on the reachable value — positions stay anchored to `[0, max]`, `min` never rescales them | | `max` | `number` | `100` | Maximum | | `step` | `number` | `1` | Snap | | `height` | `number` | `32` | Thumb/fill diameter, in px — dots and the track's own height scale with it | | `showTicks` | `boolean` | `true` | Dots marking each reachable step along the track | | `onValueChange` | `(value: number) => void` | — | Change handler | | `label` | `string` | `'Slider'` | Accessible name — the control carries no visible one | | `disabled` | `boolean` | `false` | Disables the control | | `className` | `string` | — | Class on the outer track | | `fillClassName` | `string` | — | Overrides the fill bar's background — the default is a gradient | | `thumbClassName` | `string` | — | Overrides the thumb's background | # Smooth Orb URL: https://www.spaceui.one/components/smooth *** title: Smooth Orb description: Audio-reactive fluid WebGL orb. Swap ambient, microphone, or file input, change the texture, and toggle grain. preview: demo-c-orb-smooth-01 ----------------------------- ## Installation ## Usage ```tsx import { OrbSmooth } from '@/components/orb/smooth' export function HeroOrb() { return } ``` ## Files | File | Role | | -------------------------- | ------------------------------------------ | | `smooth/index.tsx` | `OrbSmooth` WebGPU fluid sim + display | | `smooth/sim.wgsl.ts` | Splat, advect, pressure, blur passes | | `smooth/display.wgsl.ts` | Sphere shading, grain, texture mapping | | `smooth/audio-analyzer.ts` | Mic / `