shimmer-ui

A practical guide to magic.mov's UI component system and how to use it in your spells.

Interactive Component Tour

Explore our components interactively using the Component Tour:

<script>
  import { ComponentTour } from '$lib/components/ui';
</script>

<ComponentTour
  component="Button"
  variants={['primary', 'secondary', 'ghost']}
  showCode={true}
  initialProps={{
    size: 'lg',
    disabled: false
  }}
/>

The tour provides:

  • Live component demonstrations
  • Real-time prop customization
  • Code snippets with TypeScript hints
  • Visual state management
  • Variant switching

Component Structure

Our UI components are organized in $lib/components/ui following the shadcn-svelte pattern.

Core Components

$lib/components/ui/
├── button/
├── card/
├── dialog/
├── sheet/
├── input/
├── form/
├── ... (and more standard shadcn components)

Custom Film-Inspired Components

These are unique to magic.mov and add cinematic flair to our UI:

  • FilmGrainBackground.svelte: Adds subtle film grain texture to backgrounds
  • Spotlight.svelte: Creates a spotlight effect that follows cursor movement
  • ShinyText.svelte: Text with a subtle shimmer effect
  • DotBackground.svelte: Creates a dot matrix background pattern

Using Components

Import components directly from the UI folder:

<script>
  import { Button } from '$lib/components/ui/button';
  import { Card } from '$lib/components/ui/card';
  import { FilmGrainBackground } from '$lib/components/ui';
</script>

Basic Example

<script>
  import { Button } from '$lib/components/ui/button';
  import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '$lib/components/ui/card';
</script>

<Card>
  <CardHeader>
    <CardTitle>Card Title</CardTitle>
  </CardHeader>
  <CardContent>
    <p>This is a basic card component with a button.</p>
  </CardContent>
  <CardFooter>
    <Button>Action</Button>
  </CardFooter>
</Card>

Film-Inspired Effects

FilmGrainBackground

Adds a subtle film grain texture to create a cinematic atmosphere.

<script>
  import { FilmGrainBackground } from '$lib/components/ui';
</script>

<div class="relative h-screen">
  <FilmGrainBackground grainOpacity={0.05} />
  <div class="relative z-10">
    <!-- Your content here -->
  </div>
</div>

Spotlight

Creates a spotlight effect that follows the cursor.

<script>
  import { Spotlight } from '$lib/components/ui';
</script>

<div class="relative h-screen">
  <Spotlight size={300} opacity={0.15} />
  <div class="relative z-10">
    <!-- Your content here -->
  </div>
</div>

ShinyText

Text with a subtle shimmer effect.

<script>
  import { ShinyText } from '$lib/components/ui';
</script>

<ShinyText>magic.mov</ShinyText>

Component Architecture

All components follow a consistent pattern:

  1. Index files - Each component folder has an index.ts that exports the component
  2. Variants - Components use the cn utility for variants through Tailwind classes
  3. Accessibility - ARIA attributes are properly implemented
  4. Dark mode - Components automatically adapt to light/dark mode

Component Categories

Our components are organized into three main categories:

  1. Core UI Components

    • Basic elements (buttons, inputs, etc.)
    • Layout components
    • Navigation elements
  2. Cinematic Components

    • Visual effects (FilmGrain, Spotlight)
    • Animation components
    • Text effects (ShinyText, CinematicText)
  3. Spell-Specific Components

    • Custom components for each spell
    • Specialized UI elements
    • Interactive tools

Best Practices

  • Use Svelte 5 Runes ($state, $derived, $effect, $props) for state management
  • Keep components small and focused on a single responsibility
  • Leverage Tailwind's utility classes for styling
  • Ensure components are fully keyboard accessible
  • Test components across browsers and screen sizes
  • Use the Component Tour to explore and understand components before implementation

Creating New Components

When creating new components for a spell:

  1. Start by looking for existing components in $lib/components/ui
  2. Create spell-specific components in src/spells/[spell-name]/components
  3. Use the cn utility for conditional class names
  4. Add your component to the Component Tour for documentation
<script lang="ts">
  import { cn } from '$lib/utils';
  
  let { class: className } = $props<{ class?: string }>();
</script>

<div class={cn("base-styles", className)}>
  <slot />
</div>

For detailed styling information, see the Styles page.