Skills Agentes

Tailwind Design System

Construye sistemas de diseño escalables con Tailwind CSS v4, tokens de diseño, librerías de componentes y patrones responsivos. Úsalo al crear librerías de componentes o estandarizar la interfaz.

Estrellas
49.5k

en todo el repo

Actividad
36

0–100, la ruta de este skill

Actualizado
hace 4 meses

último commit aquí

Commits
0

últimos 90 días

Contexto
5.6k tok

53 tok en reposo

Paquete
1 archivo

22 KB

Instalar

Funciona con cualquier agente que lea SKILL.md

npx -y skills add calesthio/OpenMontage --skill tailwind-design-system --agent claude-code

Se instala solo en este repositorio.

Qué hace

  • Construye sistemas de diseño escalables con Tailwind CSS v4, tokens de diseño y librerías de componentes
  • Explica los cambios clave de la v4 y trae una lista de migración de v3 a v4
  • Cubre la jerarquía de tokens y la arquitectura de componentes
  • Trae seis patrones: componentes con CVA, componentes compuestos en React 19, formularios, rejilla responsiva, animaciones CSS nativas y modo oscuro
  • Documenta patrones avanzados de v4: `@utility`, modificadores de tema, sobrescritura de espacios de nombres, variantes de color semitransparentes y container queries

Úsalo cuando

  • Crear una librería de componentes
  • Implementar un sistema de diseño
  • Estandarizar patrones de interfaz

No lo uses cuando

    Qué lo activa

    Di cualquiera de estas frases y el agente debería cargar este skill.

    • Móntame un sistema de diseño con Tailwind v4
    • Convierte estos componentes a CVA
    • Migra este proyecto de Tailwind v3 a v4
    • Añade modo oscuro con CSS de v4

    SKILL.md

    En inglés

    Tailwind Design System (v4)

    Build production-ready design systems with Tailwind CSS v4, including CSS-first configuration, design tokens, component variants, responsive patterns, and accessibility.

    Note: This skill targets Tailwind CSS v4 (2024+). For v3 projects, refer to the upgrade guide.

    When to Use This Skill

    • Creating a component library with Tailwind v4
    • Implementing design tokens and theming with CSS-first configuration
    • Building responsive and accessible components
    • Standardizing UI patterns across a codebase
    • Migrating from Tailwind v3 to v4
    • Setting up dark mode with native CSS features

    Key v4 Changes

    v3 Pattern v4 Pattern
    tailwind.config.ts @theme in CSS
    @tailwind base/components/utilities @import "tailwindcss"
    darkMode: "class" @custom-variant dark (&:where(.dark, .dark *))
    theme.extend.colors @theme { --color-*: value }
    require("tailwindcss-animate") CSS @keyframes in @theme + @starting-style for entry animations

    Quick Start

    /* app.css - Tailwind v4 CSS-first configuration */
    @import "tailwindcss";
    
    /* Define your theme with @theme */
    @theme {
      /* Semantic color tokens using OKLCH for better color perception */
      --color-background: oklch(100% 0 0);
      --color-foreground: oklch(14.5% 0.025 264);
    
      --color-primary: oklch(14.5% 0.025 264);
      --color-primary-foreground: oklch(98% 0.01 264);
    
      --color-secondary: oklch(96% 0.01 264);
      --color-secondary-foreground: oklch(14.5% 0.025 264);
    
      --color-muted: oklch(96% 0.01 264);
      --color-muted-foreground: oklch(46% 0.02 264);
    
      --color-accent: oklch(96% 0.01 264);
      --color-accent-foreground: oklch(14.5% 0.025 264);
    
      --color-destructive: oklch(53% 0.22 27);
      --color-destructive-foreground: oklch(98% 0.01 264);
    
      --color-border: oklch(91% 0.01 264);
      --color-ring: oklch(14.5% 0.025 264);
    
      --color-card: oklch(100% 0 0);
      --color-card-foreground: oklch(14.5% 0.025 264);
    
      /* Ring offset for focus states */
      --color-ring-offset: oklch(100% 0 0);
    
      /* Radius tokens */
      --radius-sm: 0.25rem;
      --radius-md: 0.375rem;
      --radius-lg: 0.5rem;
      --radius-xl: 0.75rem;
    
      /* Animation tokens - keyframes inside @theme are output when referenced by --animate-* variables */
      --animate-fade-in: fade-in 0.2s ease-out;
      --animate-fade-out: fade-out 0.2s ease-in;
      --animate-slide-in: slide-in 0.3s ease-out;
      --animate-slide-out: slide-out 0.3s ease-in;
    
      @keyframes fade-in {
        from {
          opacity: 0;
        }
        to {
          opacity: 1;
        }
      }
    
      @keyframes fade-out {
        from {
          opacity: 1;
        }
        to {
          opacity: 0;
        }
      }
    
      @keyframes slide-in {
        from {
          transform: translateY(-0.5rem);
          opacity: 0;
        }
        to {
          transform: translateY(0);
          opacity: 1;
        }
      }
    
      @keyframes slide-out {
        from {
          transform: translateY(0);
          opacity: 1;
        }
        to {
          transform: translateY(-0.5rem);
          opacity: 0;
        }
      }
    }
    
    /* Dark mode variant - use @custom-variant for class-based dark mode */
    @custom-variant dark (&:where(.dark, .dark *));
    
    /* Dark mode theme overrides */
    .dark {
      --color-background: oklch(14.5% 0.025 264);
      --color-foreground: oklch(98% 0.01 264);
    
      --color-primary: oklch(98% 0.01 264);
      --color-primary-foreground: oklch(14.5% 0.025 264);
    
      --color-secondary: oklch(22% 0.02 264);
      --color-secondary-foreground: oklch(98% 0.01 264);
    
      --color-muted: oklch(22% 0.02 264);
      --color-muted-foreground: oklch(65% 0.02 264);
    
      --color-accent: oklch(22% 0.02 264);
      --color-accent-foreground: oklch(98% 0.01 264);
    
      --color-destructive: oklch(42% 0.15 27);
      --color-destructive-foreground: oklch(98% 0.01 264);
    
      --color-border: oklch(22% 0.02 264);
      --color-ring: oklch(83% 0.02 264);
    
      --color-card: oklch(14.5% 0.025 264);
      --color-card-foreground: oklch(98% 0.01 264);
    
      --color-ring-offset: oklch(14.5% 0.025 264);
    }
    
    /* Base styles */
    @layer base {
      * {
        @apply border-border;
      }
    
      body {
        @apply bg-background text-foreground antialiased;
      }
    }
    

    Core Concepts

    1. Design Token Hierarchy

    Brand Tokens (abstract)
        └── Semantic Tokens (purpose)
            └── Component Tokens (specific)
    
    Example:
        oklch(45% 0.2 260) → --color-primary → bg-primary
    

    2. Component Architecture

    Base styles → Variants → Sizes → States → Overrides
    

    Patterns

    Pattern 1: CVA (Class Variance Authority) Components

    // components/ui/button.tsx
    import { Slot } from '@radix-ui/react-slot'
    import { cva, type VariantProps } from 'class-variance-authority'
    import { cn } from '@/lib/utils'
    
    const buttonVariants = cva(
      // Base styles - v4 uses native CSS variables
      'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
      {
        variants: {
          variant: {
            default: 'bg-primary text-primary-foreground hover:bg-primary/90',
            destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
            outline: 'border border-border bg-background hover:bg-accent hover:text-accent-foreground',
            secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
            ghost: 'hover:bg-accent hover:text-accent-foreground',
            link: 'text-primary underline-offset-4 hover:underline',
          },
          size: {
            default: 'h-10 px-4 py-2',
            sm: 'h-9 rounded-md px-3',
            lg: 'h-11 rounded-md px-8',
            icon: 'size-10',
          },
        },
        defaultVariants: {
          variant: 'default',
          size: 'default',
        },
      }
    )
    
    export interface ButtonProps
      extends React.ButtonHTMLAttributes<HTMLButtonElement>,
        VariantProps<typeof buttonVariants> {
      asChild?: boolean
    }
    
    // React 19: No forwardRef needed
    export function Button({
      className,
      variant,
      size,
      asChild = false,
      ref,
      ...props
    }: ButtonProps & { ref?: React.Ref<HTMLButtonElement> }) {
      const Comp = asChild ? Slot : 'button'
      return (
        <Comp
          className={cn(buttonVariants({ variant, size, className }))}
          ref={ref}
          {...props}
        />
      )
    }
    
    // Usage
    <Button variant="destructive" size="lg">Delete</Button>
    <Button variant="outline">Cancel</Button>
    <Button asChild><Link href="/home">Home</Link></Button>
    

    Pattern 2: Compound Components (React 19)

    // components/ui/card.tsx
    import { cn } from '@/lib/utils'
    
    // React 19: ref is a regular prop, no forwardRef
    export function Card({
      className,
      ref,
      ...props
    }: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) {
      return (
        <div
          ref={ref}
          className={cn(
            'rounded-lg border border-border bg-card text-card-foreground shadow-sm',
            className
          )}
          {...props}
        />
      )
    }
    
    export function CardHeader({
      className,
      ref,
      ...props
    }: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) {
      return (
        <div
          ref={ref}
          className={cn('flex flex-col space-y-1.5 p-6', className)}
          {...props}
        />
      )
    }
    
    export function CardTitle({
      className,
      ref,
      ...props
    }: React.HTMLAttributes<HTMLHeadingElement> & { ref?: React.Ref<HTMLHeadingElement> }) {
      return (
        <h3
          ref={ref}
          className={cn('text-2xl font-semibold leading-none tracking-tight', className)}
          {...props}
        />
      )
    }
    
    export function CardDescription({
      className,
      ref,
      ...props
    }: React.HTMLAttributes<HTMLParagraphElement> & { ref?: React.Ref<HTMLParagraphElement> }) {
      return (
        <p
          ref={ref}
          className={cn('text-sm text-muted-foreground', className)}
          {...props}
        />
      )
    }
    
    export function CardContent({
      className,
      ref,
      ...props
    }: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) {
      return (
        <div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
      )
    }
    
    export function CardFooter({
      className,
      ref,
      ...props
    }: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) {
      return (
        <div
          ref={ref}
          className={cn('flex items-center p-6 pt-0', className)}
          {...props}
        />
      )
    }
    
    // Usage
    <Card>
      <CardHeader>
        <CardTitle>Account</CardTitle>
        <CardDescription>Manage your account settings</CardDescription>
      </CardHeader>
      <CardContent>
        <form>...</form>
      </CardContent>
      <CardFooter>
        <Button>Save</Button>
      </CardFooter>
    </Card>
    

    Pattern 3: Form Components

    // components/ui/input.tsx
    import { cn } from '@/lib/utils'
    
    export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
      error?: string
      ref?: React.Ref<HTMLInputElement>
    }
    
    export function Input({ className, type, error, ref, ...props }: InputProps) {
      return (
        <div className="relative">
          <input
            type={type}
            className={cn(
              'flex h-10 w-full rounded-md border border-border bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
              error && 'border-destructive focus-visible:ring-destructive',
              className
            )}
            ref={ref}
            aria-invalid={!!error}
            aria-describedby={error ? `${props.id}-error` : undefined}
            {...props}
          />
          {error && (
            <p
              id={`${props.id}-error`}
              className="mt-1 text-sm text-destructive"
              role="alert"
            >
              {error}
            </p>
          )}
        </div>
      )
    }
    
    // components/ui/label.tsx
    import { cva, type VariantProps } from 'class-variance-authority'
    
    const labelVariants = cva(
      'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
    )
    
    export function Label({
      className,
      ref,
      ...props
    }: React.LabelHTMLAttributes<HTMLLabelElement> & { ref?: React.Ref<HTMLLabelElement> }) {
      return (
        <label ref={ref} className={cn(labelVariants(), className)} {...props} />
      )
    }
    
    // Usage with React Hook Form + Zod
    import { useForm } from 'react-hook-form'
    import { zodResolver } from '@hookform/resolvers/zod'
    import { z } from 'zod'
    
    const schema = z.object({
      email: z.string().email('Invalid email address'),
      password: z.string().min(8, 'Password must be at least 8 characters'),
    })
    
    function LoginForm() {
      const { register, handleSubmit, formState: { errors } } = useForm({
        resolver: zodResolver(schema),
      })
    
      return (
        <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
          <div className="space-y-2">
            <Label htmlFor="email">Email</Label>
            <Input
              id="email"
              type="email"
              {...register('email')}
              error={errors.email?.message}
            />
          </div>
          <div className="space-y-2">
            <Label htmlFor="password">Password</Label>
            <Input
              id="password"
              type="password"
              {...register('password')}
              error={errors.password?.message}
            />
          </div>
          <Button type="submit" className="w-full">Sign In</Button>
        </form>
      )
    }
    

    Pattern 4: Responsive Grid System

    // components/ui/grid.tsx
    import { cn } from '@/lib/utils'
    import { cva, type VariantProps } from 'class-variance-authority'
    
    const gridVariants = cva('grid', {
      variants: {
        cols: {
          1: 'grid-cols-1',
          2: 'grid-cols-1 sm:grid-cols-2',
          3: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
          4: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4',
          5: 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-5',
          6: 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-6',
        },
        gap: {
          none: 'gap-0',
          sm: 'gap-2',
          md: 'gap-4',
          lg: 'gap-6',
          xl: 'gap-8',
        },
      },
      defaultVariants: {
        cols: 3,
        gap: 'md',
      },
    })
    
    interface GridProps
      extends React.HTMLAttributes<HTMLDivElement>,
        VariantProps<typeof gridVariants> {}
    
    export function Grid({ className, cols, gap, ...props }: GridProps) {
      return (
        <div className={cn(gridVariants({ cols, gap, className }))} {...props} />
      )
    }
    
    // Container component
    const containerVariants = cva('mx-auto w-full px-4 sm:px-6 lg:px-8', {
      variants: {
        size: {
          sm: 'max-w-screen-sm',
          md: 'max-w-screen-md',
          lg: 'max-w-screen-lg',
          xl: 'max-w-screen-xl',
          '2xl': 'max-w-screen-2xl',
          full: 'max-w-full',
        },
      },
      defaultVariants: {
        size: 'xl',
      },
    })
    
    interface ContainerProps
      extends React.HTMLAttributes<HTMLDivElement>,
        VariantProps<typeof containerVariants> {}
    
    export function Container({ className, size, ...props }: ContainerProps) {
      return (
        <div className={cn(containerVariants({ size, className }))} {...props} />
      )
    }
    
    // Usage
    <Container>
      <Grid cols={4} gap="lg">
        {products.map((product) => (
          <ProductCard key={product.id} product={product} />
        ))}
      </Grid>
    </Container>
    

    Pattern 5: Native CSS Animations (v4)

    /* In your CSS file - native @starting-style for entry animations */
    @theme {
      --animate-dialog-in: dialog-fade-in 0.2s ease-out;
      --animate-dialog-out: dialog-fade-out 0.15s ease-in;
    }
    
    @keyframes dialog-fade-in {
      from {
        opacity: 0;
        transform: scale(0.95) translateY(-0.5rem);
      }
      to {
        opacity: 1;
        transform: scale(1) translateY(0);
      }
    }
    
    @keyframes dialog-fade-out {
      from {
        opacity: 1;
        transform: scale(1) translateY(0);
      }
      to {
        opacity: 0;
        transform: scale(0.95) translateY(-0.5rem);
      }
    }
    
    /* Native popover animations using @starting-style */
    [popover] {
      transition:
        opacity 0.2s,
        transform 0.2s,
        display 0.2s allow-discrete;
      opacity: 0;
      transform: scale(0.95);
    }
    
    [popover]:popover-open {
      opacity: 1;
      transform: scale(1);
    }
    
    @starting-style {
      [popover]:popover-open {
        opacity: 0;
        transform: scale(0.95);
      }
    }
    
    // components/ui/dialog.tsx - Using native popover API
    import * as DialogPrimitive from '@radix-ui/react-dialog'
    import { cn } from '@/lib/utils'
    
    const DialogPortal = DialogPrimitive.Portal
    
    export function DialogOverlay({
      className,
      ref,
      ...props
    }: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> & {
      ref?: React.Ref<HTMLDivElement>
    }) {
      return (
        <DialogPrimitive.Overlay
          ref={ref}
          className={cn(
            'fixed inset-0 z-50 bg-black/80',
            'data-[state=open]:animate-fade-in data-[state=closed]:animate-fade-out',
            className
          )}
          {...props}
        />
      )
    }
    
    export function DialogContent({
      className,
      children,
      ref,
      ...props
    }: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
      ref?: React.Ref<HTMLDivElement>
    }) {
      return (
        <DialogPortal>
          <DialogOverlay />
          <DialogPrimitive.Content
            ref={ref}
            className={cn(
              'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border border-border bg-background p-6 shadow-lg sm:rounded-lg',
              'data-[state=open]:animate-dialog-in data-[state=closed]:animate-dialog-out',
              className
            )}
            {...props}
          >
            {children}
          </DialogPrimitive.Content>
        </DialogPortal>
      )
    }
    

    Pattern 6: Dark Mode with CSS (v4)

    // providers/ThemeProvider.tsx - Simplified for v4
    'use client'
    
    import { createContext, useContext, useEffect, useState } from 'react'
    
    type Theme = 'dark' | 'light' | 'system'
    
    interface ThemeContextType {
      theme: Theme
      setTheme: (theme: Theme) => void
      resolvedTheme: 'dark' | 'light'
    }
    
    const ThemeContext = createContext<ThemeContextType | undefined>(undefined)
    
    export function ThemeProvider({
      children,
      defaultTheme = 'system',
      storageKey = 'theme',
    }: {
      children: React.ReactNode
      defaultTheme?: Theme
      storageKey?: string
    }) {
      const [theme, setTheme] = useState<Theme>(defaultTheme)
      const [resolvedTheme, setResolvedTheme] = useState<'dark' | 'light'>('light')
    
      useEffect(() => {
        const stored = localStorage.getItem(storageKey) as Theme | null
        if (stored) setTheme(stored)
      }, [storageKey])
    
      useEffect(() => {
        const root = document.documentElement
        root.classList.remove('light', 'dark')
    
        const resolved = theme === 'system'
          ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
          : theme
    
        root.classList.add(resolved)
        setResolvedTheme(resolved)
    
        // Update meta theme-color for mobile browsers
        const metaThemeColor = document.querySelector('meta[name="theme-color"]')
        if (metaThemeColor) {
          metaThemeColor.setAttribute('content', resolved === 'dark' ? '#09090b' : '#ffffff')
        }
      }, [theme])
    
      return (
        <ThemeContext.Provider value={{
          theme,
          setTheme: (newTheme) => {
            localStorage.setItem(storageKey, newTheme)
            setTheme(newTheme)
          },
          resolvedTheme,
        }}>
          {children}
        </ThemeContext.Provider>
      )
    }
    
    export const useTheme = () => {
      const context = useContext(ThemeContext)
      if (!context) throw new Error('useTheme must be used within ThemeProvider')
      return context
    }
    
    // components/ThemeToggle.tsx
    import { Moon, Sun } from 'lucide-react'
    import { useTheme } from '@/providers/ThemeProvider'
    
    export function ThemeToggle() {
      const { resolvedTheme, setTheme } = useTheme()
    
      return (
        <Button
          variant="ghost"
          size="icon"
          onClick={() => setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')}
        >
          <Sun className="size-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
          <Moon className="absolute size-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
          <span className="sr-only">Toggle theme</span>
        </Button>
      )
    }
    

    Utility Functions

    // lib/utils.ts
    import { type ClassValue, clsx } from "clsx";
    import { twMerge } from "tailwind-merge";
    
    export function cn(...inputs: ClassValue[]) {
      return twMerge(clsx(inputs));
    }
    
    // Focus ring utility
    export const focusRing = cn(
      "focus-visible:outline-none focus-visible:ring-2",
      "focus-visible:ring-ring focus-visible:ring-offset-2",
    );
    
    // Disabled utility
    export const disabled = "disabled:pointer-events-none disabled:opacity-50";
    

    Advanced v4 Patterns

    Custom Utilities with @utility

    Define reusable custom utilities:

    /* Custom utility for decorative lines */
    @utility line-t {
      @apply relative before:absolute before:top-0 before:-left-[100vw] before:h-px before:w-[200vw] before:bg-gray-950/5 dark:before:bg-white/10;
    }
    
    /* Custom utility for text gradients */
    @utility text-gradient {
      @apply bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent;
    }
    

    Theme Modifiers

    /* Use @theme inline when referencing other CSS variables */
    @theme inline {
      --font-sans: var(--font-inter), system-ui;
    }
    
    /* Use @theme static to always generate CSS variables (even when unused) */
    @theme static {
      --color-brand: oklch(65% 0.15 240);
    }
    
    /* Import with theme options */
    @import "tailwindcss" theme(static);
    

    Namespace Overrides

    @theme {
      /* Clear all default colors and define your own */
      --color-*: initial;
      --color-white: #fff;
      --color-black: #000;
      --color-primary: oklch(45% 0.2 260);
      --color-secondary: oklch(65% 0.15 200);
    
      /* Clear ALL defaults for a minimal setup */
      /* --*: initial; */
    }
    

    Semi-transparent Color Variants

    @theme {
      /* Use color-mix() for alpha variants */
      --color-primary-50: color-mix(in oklab, var(--color-primary) 5%, transparent);
      --color-primary-100: color-mix(
        in oklab,
        var(--color-primary) 10%,
        transparent
      );
      --color-primary-200: color-mix(
        in oklab,
        var(--color-primary) 20%,
        transparent
      );
    }
    

    Container Queries

    @theme {
      --container-xs: 20rem;
      --container-sm: 24rem;
      --container-md: 28rem;
      --container-lg: 32rem;
    }
    

    v3 to v4 Migration Checklist

    • Replace tailwind.config.ts with CSS @theme block
    • Change @tailwind base/components/utilities to @import "tailwindcss"
    • Move color definitions to @theme { --color-*: value }
    • Replace darkMode: "class" with @custom-variant dark
    • Move @keyframes inside @theme blocks (ensures keyframes output with theme)
    • Replace require("tailwindcss-animate") with native CSS animations
    • Update h-10 w-10 to size-10 (new utility)
    • Remove forwardRef (React 19 passes ref as prop)
    • Consider OKLCH colors for better color perception
    • Replace custom plugins with @utility directives

    Best Practices

    Do's

    • Use @theme blocks - CSS-first configuration is v4's core pattern
    • Use OKLCH colors - Better perceptual uniformity than HSL
    • Compose with CVA - Type-safe variants
    • Use semantic tokens - bg-primary not bg-blue-500
    • Use size-* - New shorthand for w-* h-*
    • Add accessibility - ARIA attributes, focus states

    Don'ts

    • Don't use tailwind.config.ts - Use CSS @theme instead
    • Don't use @tailwind directives - Use @import "tailwindcss"
    • Don't use forwardRef - React 19 passes ref as prop
    • Don't use arbitrary values - Extend @theme instead
    • Don't hardcode colors - Use semantic tokens
    • Don't forget dark mode - Test both themes

    Reproducido de calesthio/OpenMontage bajo licencia AGPL-3.0. Leer esta página en markdown.

    Archivos

    1 archivo en el paquete. Solo se lee SKILL.md al activarse — las referencias se cargan si el skill decide que las necesita.

    Antes de instalar

    Está escrito para Tailwind CSS v4; algunos patrones asumen React 19.

    Detalles

    Creador
    calesthio
    Categoría
    Diseño y UI
    Licencia
    AGPL-3.0
    Recursos incluidos
    Solo SKILL.md
    Código fuente
    Ver SKILL.md

    Etiquetas

    Más de calesthio/OpenMontage

    Este repo incluye 89 skills. Si instalas uno, normalmente ya tienes los demás.

    Comfyui

    49.5k

    Úsalo al trabajar con workflows de ComfyUI en OpenMontage: comfyui_image/video/music, workflows propios, selección de output_node, modelos que faltan, LoRAs, poca VRAM e importación de workflows de la comunidad.

    Costo de contexto al activarse
    1.9k tok
    Tamaño del paquete
    1 archivo
    Última actualización
    hace 9 días
    diseno ui

    Genera vídeo cinematográfico de 4-30 s con ByteDance Seedance 2.5 por fal.ai, Volcengine Ark, Runway o ComfyUI. Cubre el contrato de prompt 2.5, cortes duros, locks de continuidad y voz.

    Costo de contexto al activarse
    3.2k tok
    Tamaño del paquete
    2 archivos
    Última actualización
    hace 4 días
    diseno ui

    Genera narración expresiva y multilingüe con fish.audio (modelos S1 / S2) y reutiliza voces clonadas mediante reference_id.

    Costo de contexto al activarse
    1.4k tok
    Tamaño del paquete
    1 archivo
    Última actualización
    hace 9 días
    diseno ui

    Genera y edita conversacionalmente vídeos cortos con Google Gemini Omni Flash: itera con ediciones en lenguaje natural, clips de 3-10s a 720p con audio y texto en pantalla, e imágenes de referencia por etiquetas.

    Costo de contexto al activarse
    2.1k tok
    Tamaño del paquete
    1 archivo
    Última actualización
    hace 9 días
    Permisos
    diseno ui

    Genera vídeo con MiniMax H3 (Hailuo 3.0) por la API oficial v2, fal.ai, Runway, nodos partner de ComfyUI o pesos abiertos locales. Clips de 4-15s a 2K con animación de primer/último fotograma.

    Costo de contexto al activarse
    582 tok
    Tamaño del paquete
    1 archivo
    Última actualización
    hace 9 días
    diseno ui

    Genera, reconstruye, inspecciona y enruta activos 3D de producción para mundos de OpenMontage con Atlas Cloud, fal.ai, catálogos con licencia y Blender.

    Costo de contexto al activarse
    1.2k tok
    Tamaño del paquete
    2 archivos
    Última actualización
    hace 9 días
    diseno ui

    Skills relacionados

    Genera, reconstruye, inspecciona y enruta activos 3D de producción para mundos de OpenMontage con Atlas Cloud, fal.ai, catálogos con licencia y Blender.

    Costo de contexto al activarse
    1.2k tok
    Tamaño del paquete
    2 archivos
    Última actualización
    hace 9 días
    diseno ui

    Acestep

    49.5k

    Generación musical con ACE-Step 1.5: música de fondo, pistas con voz, versiones y extracción de stems para producción de vídeo.

    Costo de contexto al activarse
    2.3k tok
    Tamaño del paquete
    1 archivo
    Última actualización
    hace 4 meses
    diseno ui

    Genera vídeos con IA desde texto usando varias pasarelas — HeyGen, fal.ai, Kling y Gemini — con soporte de imagen a vídeo y comparación entre VEO, Kling, Sora, Runway, Seedance y MiniMax.

    Costo de contexto al activarse
    3k tok
    Tamaño del paquete
    1 archivo
    Última actualización
    el mes pasado
    diseno ui