Saltar al contenido principal

Sprite

Un personaje pixel armado con partes intercambiables, que camina, se sienta y programa.

1'use client';
2
3import { Sprite } from '@/components/ui/sprite';
4
5export function Default() {
6 return <Sprite seed="nachui" size={72} />;
7}
Cada sprite son cinco ranuras — piel, pelo, ojos, ropa y accesorio — dibujadas sobre un mismo esqueleto fijo: la caja de la cara, la línea de ojos, los hombros y la cadera. Como el esqueleto no se mueve, cualquier combinación de partes hereda las animaciones sin trabajo extra.

Instalación

pnpm dlx nachui add sprite
Instalarlo a mano funciona como con cualquier otro componente: copiá el archivo de la pestaña Manual y ajustá los imports. Las animaciones viajan adentro del archivo como SPRITE_CSS, así que no hay nada más que copiar — renderizá con withStyles o inyectá el string una sola vez:
1<style>{SPRITE_CSS}</style>

Anatomía

1import { Sprite } from '@/components/ui/sprite';
1<Sprite seed="nachui" />

Semillas

Cualquier string arma un sprite, y el mismo string arma siempre el mismo — así que un usuario o un email sirven de avatar sin guardar nada.
nachui
figueroaignacio
mate
bit
vera
lupe
1'use client';
2
3import { Sprite } from '@/components/ui/sprite';
4
5const seeds = ['nachui', 'figueroaignacio', 'mate', 'bit', 'vera', 'lupe'];
6
7export function Seeds() {
8 return (
9 <div className="flex flex-wrap items-end gap-8">
10 {seeds.map((seed) => (
11 <div key={seed} className="flex flex-col items-center gap-3">
12 <Sprite seed={seed} size={64} />
13 <span className="text-muted-foreground font-mono text-xs">{seed}</span>
14 </div>
15 ))}
16 </div>
17 );
18}

Estados

idle respira y parpadea, walk corre el ciclo de caminata de dos cuadros, work saca la laptop, y loop juega todo: llega caminando, se sienta, laburea y se levanta.
idle
walk
work
loop
1'use client';
2
3import { Sprite } from '@/components/ui/sprite';
4
5const states = [
6 { state: 'idle', label: 'idle' },
7 { state: 'walk', label: 'walk' },
8 { state: 'work', label: 'work' },
9 { state: 'loop', label: 'loop' },
10] as const;
11
12export function States() {
13 return (
14 <div className="flex flex-wrap items-end gap-8">
15 {states.map(({ state, label }) => (
16 <div key={state} className="flex flex-col items-center gap-3">
17 <Sprite seed="nachui" state={state} size={72} />
18 <span className="text-muted-foreground font-mono text-xs">{label}</span>
19 </div>
20 ))}
21 </div>
22 );
23}

Partes

Pasá parts para pisar lo que eligió la semilla, ranura por ranura. El color es un eje aparte de la forma: seis peinados y cinco colores son treinta cabezas.
1'use client';
2
3import { Sprite } from '@/components/ui/sprite';
4
5export function Parts() {
6 return (
7 <div className="flex flex-wrap items-end gap-8">
8 <Sprite
9 seed="nachui"
10 size={64}
11 parts={{ hair: 'bun', hairColor: 'copper', eyes: 'wide', accessory: 'glasses' }}
12 />
13 <Sprite
14 seed="nachui"
15 size={64}
16 parts={{ skin: 'umber', outfit: 'overalls', outfitMain: '#4E6E58', accessory: 'none' }}
17 />
18 <Sprite
19 seed="nachui"
20 size={64}
21 parts={{ eyes: 'visor', eyeFill: '#A8E6D7', hair: 'buzz', hairColor: 'ash' }}
22 />
23 </div>
24 );
25}

Suelto

spriteToSvg devuelve el sprite entero como un string SVG, animaciones incluidas, así que funciona donde la hoja de estilos de una página no llega — una respuesta de servidor, un archivo guardado, un README. En este sitio, además, cada sprite es una URL:
1/api/sprite/{semilla}.svg?state=loop&size=96
La misma semilla responde siempre la misma imagen, así que la respuesta se cachea como inmutable.

Props

PropTipoDefaultDescripción
seedstringnachuiCualquier string. El mismo string da el mismo sprite.
partsPartial<SpriteParts>Pisa la semilla, ranura por ranura.
statebust | idle | walk | work | loopidleQué está haciendo.
sizenumber48Ancho en píxeles; el alto sale de la grilla.

Accesibilidad

El sprite es decorativo y no lleva etiqueta propia. Cuando represente a una persona, poné el nombre al lado en texto y no adentro del dibujo.
¿Encontraste algo que mejorar?

¿Notaste un error, tipografía o detalle faltante en esta página? Ayúdanos a mejorar la documentación abriendo un issue en GitHub.

Crear un Issue
Ctrl+I