Files
carvalho-finances/neon-handoff/STYLE_GUIDE.md
T
Mlcavalho1andClaude Sonnet 4.6 acbce4edc0 feat: multi-usuário com autenticação JWT
- Tabela `profiles` + coluna `profile_id` em todas as entidades
  (categories, transactions, recurring_expenses, accounts, player_profile,
   xp_events, player_quests, player_achievements, player_cosmetics)
- Dados existentes migrados para profile_id = 1 (Manoel)
- CLI `./api create-user --name <n> --password <p>` cria perfil com
  seed de categorias e player_profile; faz upsert de senha se já existir
- Auth substituída: cookie+APP_PASSWORD → JWT Bearer 24h (HS256)
- Middleware RequireAuth injeta profile_id no context de todas as rotas
- Todos os repositórios filtram por profile_id do context
- Endpoints: POST /api/auth/login, GET /api/auth/me,
  POST /api/auth/change-password, POST /api/logout
- Frontend: auth store usa localStorage (fc_token/fc_profile),
  api.ts envia Authorization header, LoginView usa campo name
- SettingsView reescrita com troca de senha e logout
- docker-compose.yml: remove APP_USERNAME/APP_PASSWORD, adiciona JWT_SECRET

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-27 20:04:44 -03:00

21 KiB
Raw Blame History

Financeiro Carvalho · Style Guide

Direção: Arcade Neon Stack alvo: Vue 3 + Vite + TypeScript + Pinia Princípio: finanças vestindo roupa de fliperama. Fundo escuro, glow neon nos números que importam, fonte pixel nos labels e mono nos dados. HUD sempre presente.


1. Tokens

Copie tokens.css na raiz do src/styles/ e importe em main.ts. Todas as variáveis CSS abaixo são o contrato — componentes consomem var(--fc-*), nunca hex direto.

1.1 Cores

Token Valor Uso
--fc-bg #0a0418 Fundo base do app
--fc-bg-raised #150827 Card / panel topo do gradiente
--fc-bg-panel #1c0d33 Card / panel base do gradiente
--fc-panel-edge #2d1857 Borda padrão de painéis
--fc-line #3a1f6e Grid de fundo, dividers internos
--fc-text #f4eaff Texto principal (off-white lilás)
--fc-text-dim #8b75b8 Texto secundário, labels
--fc-accent #ff2d95 Magenta · destaques quentes, alertas suaves, "diária"
--fc-accent-2 #00f0ff Ciano · links, navegação, "semanal"
--fc-accent-3 #a855f7 Roxo · CTA padrão, painéis com glow
--fc-gold #ffd84d XP, conquistas, "mensal"
--fc-green #39ff7a Meta atingida, valores positivos
--fc-red #ff3b6b Meta falhou, alerta crítico, recorrência ausente

Regra de uso:

  • Magenta é a cor do "agora" — botões primários secundários, status do dia.
  • Ciano é a cor da informação fria — XP, links, navegação ativa.
  • Roxo é estrutura — painel em destaque, hover, foco. Quase sempre tem box-shadow: 0 0 24px rgba(168,85,247,.25).
  • Dourado é recompensa — qualquer coisa relacionada a XP, nível, conquista.
  • Verde/vermelho ficam reservados pro binário "meta sim/meta não".

1.2 Tipografia

Importe via Google Fonts no <head>:

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&family=JetBrains+Mono:wght@400;500;700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
Família Uso Tamanhos comuns
Press Start 2P Labels, títulos de painel, números heroicos (47%), nav 7px, 8px, 9px, 14px, 22px, 40px, 56px
JetBrains Mono Valores numéricos (R$), datas, IDs 10px, 11px, 12px, 16px
Inter Fallback para corpo de texto longo (descrições de quest, etc.) 13px, 14px

Classes utilitárias:

.fc-pixel { font-family: 'Press Start 2P', monospace; letter-spacing: .02em; }
.fc-mono  { font-family: 'JetBrains Mono', monospace; }
.fc-body  { font-family: 'Inter', system-ui, sans-serif; }

Regra: nunca usar Inter pra número. Nunca usar Press Start 2P pra parágrafo (>2 linhas). Press Start 2P em maiúscula sempre.

1.3 Tamanhos e espaçamento

Token Valor Uso
--fc-radius-sm 2px Botões, chips
--fc-radius 4px Painéis
--fc-space-1 4px Gap minúsculo
--fc-space-2 8px Gap entre chips
--fc-space-3 12px Padding interno de card pequeno
--fc-space-4 16px Padding/gap padrão
--fc-space-5 24px Padding de painel grande

Página tem padding: 24px nas bordas. Grids usam gap: 16px entre cards.

1.4 Sombras e glow

Sombra padrão de painel:

box-shadow:
  inset 0 1px 0 rgba(255,255,255,.05),
  0 0 0 1px rgba(0,0,0,.4),
  0 8px 24px rgba(0,0,0,.4);

Painel com glow (destaque do hero):

box-shadow:
  inset 0 1px 0 rgba(255,255,255,.05),
  0 0 0 1px var(--fc-accent-3),
  0 0 24px rgba(168,85,247,.25),
  0 8px 24px rgba(0,0,0,.5);
border-color: var(--fc-accent-3);

Glow em texto (números heroicos):

text-shadow: 0 0 8px rgba(var-rgb, .53);
/* ex: text-shadow: 0 0 8px #39ff7a88; */

Glow em ícone/cor:

box-shadow: 0 0 8px <cor>88;

Sempre que o app exibir um número grande de "vitória", ele recebe um glow do tom correspondente. Use com parcimônia — só nos pontos focais.


2. Layout

2.1 Estrutura geral

Toda tela do app tem essa estrutura vertical:

┌─────────────────────────────────────────┐
│  HUD (Top Bar)                          │  ← persistente, navegação + stats RPG
├─────────────────────────────────────────┤
│  Sub-header (título da rota + ações)    │
├─────────────────────────────────────────┤
│  Conteúdo                               │  ← grid de painéis
│                                         │
└─────────────────────────────────────────┘

HUD é elemento de identidade — não dispensar em nenhuma rota.

2.2 Grid de painéis

Dashboard usa grid 1.6fr 1fr (coluna principal mais larga que a lateral). Cards empilhados com gap: 16px.

Personagem usa grid 1fr 1.4fr (personagem à esquerda, quests/conquistas à direita).

2.3 Fundo do app

O fundo tem 3 camadas (em ordem, do mais ao fundo):

  1. Cor sólida #0a0418
  2. Dois gradientes radiais sutis (roxo no topo, magenta no canto inferior direito)
  3. Grid pontilhado fino (32×32px linhas, opacidade 12%) sobre tudo
  4. Scanlines horizontais finas (CRT vibe) com opacidade 2,5%

CSS do body/root do app:

.fc-app {
  background:
    radial-gradient(ellipse 80% 50% at 50% 0%, rgba(168,85,247,.18), transparent 70%),
    radial-gradient(ellipse 60% 40% at 80% 100%, rgba(255,45,149,.12), transparent 60%),
    var(--fc-bg);
  position: relative;
  min-height: 100vh;
}
.fc-app::before { /* scanlines */
  content: '';
  position: absolute; inset: 0;
  background-image: repeating-linear-gradient(0deg, rgba(255,255,255,.025) 0 1px, transparent 1px 3px);
  pointer-events: none;
  z-index: 2;
}
.fc-app::after { /* grid */
  content: '';
  position: absolute; inset: 0;
  background-image:
    linear-gradient(var(--fc-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--fc-line) 1px, transparent 1px);
  background-size: 32px 32px;
  opacity: .12;
  pointer-events: none;
}
.fc-app > * { position: relative; z-index: 1; }

3. Componentes

3.1 Panel

Wrapper para qualquer conteúdo. Tem cantos em "L" (corner brackets) opcionais — a estética HUD do Arcade Neon.

<!-- NeonPanel.vue -->
<template>
  <div class="fc-panel" :class="{ 'fc-panel--glow': glow, [`fc-panel--${variant}`]: variant }">
    <span v-if="corners" class="fc-corner fc-corner--tl" />
    <span v-if="corners" class="fc-corner fc-corner--tr" />
    <span v-if="corners" class="fc-corner fc-corner--bl" />
    <span v-if="corners" class="fc-corner fc-corner--br" />
    <slot />
  </div>
</template>

<script setup lang="ts">
defineProps<{
  glow?: boolean
  corners?: boolean
  variant?: 'danger' | 'success'
}>()
</script>

CSS:

.fc-panel {
  position: relative;
  background: linear-gradient(180deg, var(--fc-bg-raised), var(--fc-bg-panel));
  border: 2px solid var(--fc-panel-edge);
  border-radius: var(--fc-radius);
  padding: 16px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.05),
    0 0 0 1px rgba(0,0,0,.4),
    0 8px 24px rgba(0,0,0,.4);
}
.fc-panel--glow {
  border-color: var(--fc-accent-3);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.05),
    0 0 0 1px var(--fc-accent-3),
    0 0 24px rgba(168,85,247,.25),
    0 8px 24px rgba(0,0,0,.5);
}
.fc-panel--danger { border-color: var(--fc-red); box-shadow: 0 0 0 1px var(--fc-red), 0 0 16px rgba(255,59,107,.3); }
.fc-corner {
  position: absolute; width: 8px; height: 8px;
  border: 2px solid var(--fc-accent-2);
}
.fc-corner--tl { top: -2px; left: -2px;  border-right: none; border-bottom: none; }
.fc-corner--tr { top: -2px; right: -2px; border-left:  none; border-bottom: none; }
.fc-corner--bl { bottom: -2px; left: -2px;  border-right: none; border-top: none; }
.fc-corner--br { bottom: -2px; right: -2px; border-left:  none; border-top: none; }

Quando usar corners: somente no painel principal de cada coluna ou no hero. Eles são "decoração de HUD", não devem aparecer em cada card.

Quando usar glow: apenas no painel de status mais importante da rota — o de meta de poupança no dashboard, o card do personagem na tela RPG.

3.2 Título de painel

Todo painel começa com um título no padrão :: NOME:

<div class="fc-panel-title">:: GASTOS · CATEGORIA</div>
.fc-panel-title {
  font-family: 'Press Start 2P', monospace;
  font-size: 9px;
  color: var(--fc-accent-2);
  margin-bottom: 14px;
  letter-spacing: .04em;
}

O :: prefix é assinatura visual da direção. Mantém.

3.3 Button

Botão padrão é "neon outline":

.fc-btn {
  font-family: 'Press Start 2P', monospace;
  font-size: 9px;
  padding: 9px 12px;
  background: var(--fc-bg-raised);
  border: 2px solid var(--fc-accent-3);
  color: var(--fc-text);
  cursor: pointer;
  border-radius: 2px;
  letter-spacing: .05em;
  text-transform: uppercase;
  transition: all .12s;
}
.fc-btn:hover {
  background: var(--fc-accent-3);
  color: white;
  box-shadow: 0 0 16px rgba(168,85,247,.6);
}
.fc-btn--pink { border-color: var(--fc-accent); }
.fc-btn--pink:hover { background: var(--fc-accent); box-shadow: 0 0 16px rgba(255,45,149,.6); }
.fc-btn--cyan { border-color: var(--fc-accent-2); color: var(--fc-accent-2); }
.fc-btn--cyan:hover { background: var(--fc-accent-2); color: var(--fc-bg); box-shadow: 0 0 16px rgba(0,240,255,.6); }

Hierarquia:

  • Roxo (padrão): ação primária genérica.
  • Magenta: ação destrutiva ou de "agora" (registrar transação, atingir quest).
  • Ciano: ação secundária, ver detalhes.

3.4 Chip

.fc-chip {
  display: inline-block;
  font-family: 'Press Start 2P', monospace;
  font-size: 7px;
  padding: 4px 6px;
  border-radius: 2px;
  letter-spacing: .05em;
  text-transform: uppercase;
}

Cores dependem do contexto:

  • Quest "Diária" → background: var(--fc-accent)
  • Quest "Semanal" → background: var(--fc-accent-2)
  • Quest "Mensal" → background: var(--fc-gold)
  • Categoria de transação → color: var(--fc-text-dim) apenas (sem fundo)

3.5 Bar (XP, progresso de quest, gauge)

<template>
  <div class="fc-bar" :class="{ 'fc-bar--success': success }">
    <div class="fc-bar__fill" :style="{ width: pct + '%' }" />
  </div>
</template>

<script setup lang="ts">
defineProps<{ pct: number; success?: boolean }>()
</script>
.fc-bar {
  height: 14px;
  background: var(--fc-bg);
  border: 2px solid var(--fc-panel-edge);
  position: relative;
  overflow: hidden;
}
.fc-bar__fill {
  height: 100%;
  background: linear-gradient(90deg, var(--fc-accent-2), var(--fc-accent-3), var(--fc-accent));
  position: relative;
}
.fc-bar__fill::after {
  content:''; position: absolute; inset: 0;
  background-image: repeating-linear-gradient(90deg, rgba(0,0,0,.2) 0 2px, transparent 2px 6px);
}
.fc-bar--success { border-color: var(--fc-green); }
.fc-bar--success .fc-bar__fill { background: linear-gradient(90deg, var(--fc-green), var(--fc-accent-2)); }

Tamanhos:

  • XP geral (dashboard widget): 8px
  • Quest mini: 6px
  • Hero (poupado %): 14px
  • Personagem (XP grande): 14px

3.6 HUD (top bar)

Persistente em todas as rotas. Contém: logo, separator, stats RPG (LV/XP/STREAK/META), nav.

Stats são essenciais — mesmo em telas que não são /personagem, o usuário tem que ver seu progresso o tempo todo. Esse é o ponto da direção.

<header class="fc-hud">
  <div class="fc-hud__logo">
    <span class="fc-hud__logo-mark" />
    <div>
      <div class="fc-pixel" style="font-size: 10px; color: var(--fc-accent-2)">CARVALHO</div>
      <div class="fc-pixel" style="font-size: 7px; color: var(--fc-text-dim)">FIN.SYS v1.4</div>
    </div>
  </div>
  <div class="fc-hud__sep" />
  <div class="fc-hud__stats">
    <HUDStat label="LV"     :value="user.level"        color="var(--fc-gold)" />
    <HUDStat label="XP"     :value="user.xp"           :sub="`/${user.xpNext}`" color="var(--fc-accent-2)" />
    <HUDStat label="STREAK" :value="`${user.streak}d`" color="var(--fc-accent)" />
    <HUDStat label="META"   value="47%"                 sub="/40%" color="var(--fc-green)" />
  </div>
  <nav class="fc-hud__nav">
    <!-- chip-shaped buttons, one per route -->
  </nav>
</header>
.fc-hud {
  display: flex; align-items: center; gap: 16px;
  padding: 12px 20px;
  border-bottom: 2px solid var(--fc-panel-edge);
  background: linear-gradient(180deg, var(--fc-bg-panel), var(--fc-bg));
  position: relative; z-index: 3;
}
.fc-hud__logo-mark {
  display: inline-block;
  width: 28px; height: 28px;
  background: var(--fc-accent);
  box-shadow: 0 0 12px var(--fc-accent);
  position: relative;
}
.fc-hud__logo-mark::before, .fc-hud__logo-mark::after { content: ''; position: absolute; }
.fc-hud__logo-mark::before { inset: 5px; background: var(--fc-bg); }
.fc-hud__logo-mark::after { top: 9px; left: 9px; width: 10px; height: 10px; background: var(--fc-accent-2); }

Nav items são chips com borda. Item ativo: fundo --fc-accent-3 + glow.

.fc-link {
  color: var(--fc-accent-2);
  font-family: 'Press Start 2P', monospace;
  font-size: 8px;
  cursor: pointer;
  text-decoration: none;
  letter-spacing: .04em;
}
.fc-link:hover {
  text-decoration: underline;
  text-shadow: 0 0 8px var(--fc-accent-2);
}

Use sempre VER+, ABRIR &gt;, REGISTRAR &gt; — verbo curto + seta. Toda navegação textual usa esse padrão pra reforçar o "menu de jogo".

3.8 Alerta pulsante (recorrência ausente)

@keyframes fc-blink { 0%,49% { opacity: 1; } 50%,100% { opacity: 0.2; } }
.fc-blink { animation: fc-blink 1.2s steps(1) infinite; }

Use no triângulo ⚠ que precede o título do alerta. Pisca em vermelho.


4. Tabelas / listas

Padrão de tabela de transações:

[ data ][ descrição ......... ][ CATEGORIA ][ -R$ X,XX ]
 mono10   mono11 ellipsis      pixel7 dim   mono11 right
  • Linhas usam border-bottom: 1px dashed var(--fc-panel-edge) (a última, não).
  • Padding vertical de 8px por linha.
  • Valor positivo → cor --fc-green.
  • Valor negativo → cor --fc-text (não vermelho — o vermelho é só pra alerta crítico).

5. Pixel Sprite (Character)

O personagem é desenhado a partir de uma grade 17×24 de células. Cores são parametrizáveis por slot de cosmético.

5.1 Slots de cor

Slot Token CSS sugerido Cosmético que altera
outline --fc-sprite-outline (#10131c) nunca muda
skin --fc-sprite-skin (#f3c79b) nunca muda
skinShade --fc-sprite-skin-shade (#c98863) nunca muda
hat --fc-sprite-hat cosmético hat
band --fc-sprite-band faixa do chapéu
shirt --fc-sprite-shirt cosmético shirt
shirtShade --fc-sprite-shirt-shade shadow do shirt
pants --fc-sprite-pants cosmético pants
pantsShade --fc-sprite-pants-shade shadow do pants
boots --fc-sprite-boots cosmético shoes

5.2 Render (Vue)

A grade vem do arquivo sprites/sprite-data.json (incluído). Componente:

<!-- CharacterSprite.vue -->
<template>
  <svg :width="cols * scale" :height="rows * scale"
       :viewBox="`0 0 ${cols * scale} ${rows * scale}`"
       shape-rendering="crispEdges"
       :class="['fc-sprite', { 'fc-sprite--bob': bob, 'fc-sprite--celebrate': celebrate }]">
    <rect v-for="px in pixels" :key="`${px.x}-${px.y}`"
          :x="px.x * scale" :y="px.y * scale" :width="scale" :height="scale"
          :fill="colors[px.k]" />
  </svg>
</template>

<script setup lang="ts">
import spriteData from '@/assets/sprite-data.json'
import { computed } from 'vue'

const props = withDefaults(defineProps<{
  scale?: number
  theme?: Partial<Record<string,string>>
  bob?: boolean
  celebrate?: boolean
}>(), { scale: 4, bob: true })

const rows = spriteData.rows
const cols = spriteData.cols

const defaults: Record<string,string> = {
  L: '#10131c', s: '#f3c79b', S: '#c98863', e: '#10131c', m: '#80484b',
  h: '#ffd84d', w: '#fde68a',
  c: '#00f0ff', C: '#0369a1',
  p: '#7c5a2e', P: '#4f3a1e',
  b: '#0f172a',
}

const colors = computed(() => ({ ...defaults, ...(props.theme || {}) }))

const pixels = computed(() => {
  const out: { x: number, y: number, k: string }[] = []
  spriteData.grid.forEach((row: string, y: number) => {
    for (let x = 0; x < row.length; x++) {
      const k = row[x]
      if (k === '.' || !colors.value[k]) continue
      out.push({ x, y, k })
    }
  })
  return out
})
</script>

<style scoped>
.fc-sprite { image-rendering: pixelated; line-height: 0; }
@keyframes fc-bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
.fc-sprite--bob { animation: fc-bob 2.2s steps(2) infinite; }
@keyframes fc-celebrate { 0%,100% { transform: translateY(0) rotate(0); } 25% { transform: translateY(-6px) rotate(-3deg); } 75% { transform: translateY(-6px) rotate(3deg); } }
.fc-sprite--celebrate { animation: fc-celebrate 1s ease-in-out infinite; }
</style>

5.3 Tamanhos canônicos

  • Dashboard widget: scale={3} → 51×72px no SVG
  • Mobile inline: scale={2} → 34×48px
  • Personagem hero: scale={6} → 102×144px

Sempre escalas inteiras. Nunca esticar.

5.4 Cosméticos (data)

A loja de cosméticos persiste no banco. Cada cosmético tem:

type Cosmetic = {
  id: string
  name: string
  slot: 'hat' | 'shirt' | 'pants' | 'shoes' | 'cape'
  unlockLv: number          // nível necessário
  colors: Partial<Record<'h'|'w'|'c'|'C'|'p'|'P'|'b', string>>
}

O store (Pinia) tem um getter equippedTheme que faz o merge das cores dos itens equipados. Esse objeto vai como prop theme para <CharacterSprite>.


6. Animações

Trigger Comportamento
Idle (sempre) Sprite bobinha verticalmente (fc-sprite--bob, 2.2s steps(2) infinite)
Quest completa Sprite vira fc-sprite--celebrate por 3s, depois volta
Level up Modal sobrepõe a tela: painel com glow magenta, "+1 LEVEL", som opcional
XP ganho Bar enche com transição width 0.6s ease-out. Numero do XP no HUD soma com tween 1s
Hover em card transform: translateY(-2px) + shadow um pouco mais profundo
Alerta de recorrência Triângulo ⚠ pisca (fc-blink)

Sem motion gratuito. Cada animação tem um significado.


7. Iconografia

Esta direção evita ícones de biblioteca (Lucide, etc.). Em vez disso usa:

  • Símbolos unicode pequenos pra categorias: casa, saúde, mercado, veleiro, board games, transporte, outros.
  • Cantos em "L" (fc-corner-*) pra emoldurar painéis especiais.
  • Triângulo pra alerta, estrela ou pra conquista, diamante pra equipado.
  • Setas > pra navegação textual.

Quando precisar de um ícone novo: SVG inline pixel-art (8×8 ou 12×12), nunca importar ícone vetorial moderno.

Os pixels de PixelHeart e PixelCoin estão em sprites/icons.json.


8. Voz e copywriting

  • Labels em maiúscula com Press Start 2P, curtas. :: GASTOS · CATEGORIA, :: TRANSAÇÕES, :: PERSONAGEM.
  • Botões em maiúscula, verbo + (seta opcional). REGISTRAR >, VER +, ABRIR >, IMPORTAR EXTRATO.
  • Mensagens de sucesso em tom de jogo: QUEST OK, META BATIDA, +200 XP.
  • Mensagens de aviso em tom direto: RECORRÊNCIA AUSENTE, QUEST FAIL.
  • Nome de seção da vida real ganha "stage": :: STAGE 05 :: antes do nome do mês na rota /.

Evite tom motivacional vazio ("você consegue!"). O jogo recompensa com XP, não com frase.


9. Responsivo

  • Desktop ≥ 1024px: grid 1.6fr 1fr (dashboard) ou 1fr 1.4fr (personagem). HUD horizontal completo.
  • Tablet 7681023px: grid colapsa pra 1 coluna. HUD ainda horizontal mas nav vira menu hambúrguer (preserve os stats).
  • Mobile <768px:
    • HUD compacta. Apenas LV + XP-bar visíveis + streak.
    • Nav vira bottom bar fixa, 4 itens: HOME / TX / ADD (+) / PERS.
    • Painéis empilham com gap: 12px, padding interno reduz pra 14px.
    • Hero "47%" ocupa toda a largura, centralizado.

10. Arquivos deste pacote

neon-handoff/
├── STYLE_GUIDE.md              ← este arquivo
├── tokens.css                  ← variáveis CSS prontas pra importar
├── preview.html                ← referência visual interativa
├── components/
│   ├── NeonPanel.vue
│   ├── XPBar.vue
│   ├── HUDStat.vue
│   └── CharacterSprite.vue
├── sprites/
│   ├── sprite-data.json        ← grade raw 17×24 (chave por cor)
│   ├── icons.json              ← heart, coin, achievement
│   ├── manoel-default.png      ← 1× (17×24px) e 4× (68×96px)
│   ├── manoel-default-4x.png
│   ├── manoel-lv01.png
│   ├── manoel-lv03-bone-verolme.png
│   ├── manoel-lv05-wingspan.png
│   ├── manoel-lv07-chapeu-sol.png
│   ├── manoel-lv10-anti-vento.png
│   ├── manoel-lv15-capitao.png
│   └── manoel-sheet-4x.png     ← todos os 7 lado a lado, pra sprite-sheet
└── README.md