Communitygithub.com

stevembarclay/pencilplaybook

PencilPlaybook é o Skills de UI / Taste-Skill para Pencil.dev + Claude Code — um playbook de design que dá ao Claude verdadeira psicologia perceptual e guardrails de nível sênior para que ele pare de produzir 'AI slop' padronizado.

O que é pencilplaybook?

PencilPlaybook é um skill especializado em design de interface para o Claude Code (Pencil.dev), que atua como um 'playbook de design' ou 'Taste-Skill'. Ele fornece ao Claude um conjunto rigoroso de princípios de psicologia perceptual e guardrails de nível sênior para criar interfaces que fogem do design genérico e 'AI slop' (conteúdo sem personalidade gerado por IA). O skill é configurado através de um assistente de configuração (setup wizard) que define dimensões de tela, paletas de cores e tokens de marca. Durante cada sessão, ele carrega um mapeamento de tokens e nove 'Scaffold Scripts' (esqueletos de layout) para os principais arquétipos de design: dashboards, listas, detalhes, páginas de marketing, modais, wizards, telas mobile, formulários e estados vazios. Plataformas suportadas: Pencil.dev (editor de design) e Claude Code (ferramenta de IA). O fluxo de trabalho inclui arqueologia de canvas (compreensão de arquivos .pen existentes) e construção de componentes com padrões de espaçamento, tipografia e acessibilidade.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add stevembarclay/pencilplaybook

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Pencil Pro

Regra de Resolução Primária

Este skill deve ser configurado antes do primeiro uso.

Se o usuário disser "executar o assistente de configuração do PencilPlaybook" ou pedir para configurar o PencilPlaybook: → Leia .claude/skills/pencilplaybook/setup.md e siga as instruções exatamente.

Se o usuário disser "construir minha primeira tela com o PencilPlaybook" ou pedir para começar a projetar: → Leia .claude/skills/pencilplaybook/onboarding.md e siga as instruções exatamente.

Resolução configurada: (executar configuração para definir isso)

Se a raiz de uma tela em um arquivo .pen existente não corresponder à sua resolução configurada, anote isso antes de editar. Não construa sobre um canvas de tamanho errado sem sinalizar o desvio.

Exceção comum — páginas de marketing: Projete em 1440px independentemente da resolução do seu aplicativo. Páginas de marketing são consumidas em larguras de navegador variáveis — projete em 1440px, verifique em 390px.


Inicialização de Sessão (Toda Sessão Pencil)

1. get_editor_state()                           — verificar documento ativo e seleção
2. open_document("path/to/your-file.pen")       — abrir arquivo de destino
3. get_guidelines(topic="web-app")              — carregar diretrizes de design
4. set_variables(<mapa de tokens abaixo>)        — injetar tokens de marca
5. get_variables()                              — confirmar tokens armazenados
6. snapshot_layout()                            — verificar dimensões do canvas

Seu mapa de tokens — execute set_variables com este objeto no início de cada sessão. As variáveis podem não persistir entre sessões do Claude Code.

{
  "color-primary":        "YOUR_HEX",
  "color-primary-dark":   "YOUR_HEX",
  "color-accent":         "YOUR_HEX",
  "color-background":     "YOUR_HEX",
  "color-surface":        "YOUR_HEX",
  "color-border":         "YOUR_HEX",
  "color-text":           "YOUR_HEX",
  "color-text-muted":     "YOUR_HEX",
  "color-success":        "YOUR_HEX",
  "color-warning":        "YOUR_HEX",
  "color-error":          "YOUR_HEX",
  "font-sans":            "YOUR_FONT",
  "font-mono":            "YOUR_FONT",
  "font-serif":           "YOUR_FONT",
  "spacing-card":         "24",
  "spacing-gap-sm":       "8",
  "spacing-gap-md":       "16",
  "spacing-gap-lg":       "24",
  "spacing-gap-xl":       "32",
  "content-max-width":    "YOUR_VALUE",
  "sidebar-width":        "YOUR_VALUE"
}

Após set_variables, chame get_variables() para confirmar que todos os tokens estão armazenados.


Scripts Scaffold

Nove scripts scaffold cobrindo os arquétipos de layout mais comuns. Execute o assistente de configuração para preencher os valores de dimensão e cor abaixo antes de usar.


Scaffold A — Dashboard do Aplicativo

Métricas, KPIs, feed de atividade, monitoramento

sidebar=I("root", {name:"Sidebar", width:SCAFFOLD_SIDEBAR_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"SIDEBAR_BG", display:"flex", flexDirection:"column"})
pageArea=I("root", {name:"PageArea", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, x:SCAFFOLD_SIDEBAR_WIDTH, bg:"PAGE_BG"})
pageHeader=I("pageArea", {name:"PageHeader", width:SCAFFOLD_PAGE_AREA_WIDTH, height:64, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", px:32})
statsBar=I("pageArea", {name:"StatsBar", y:64, width:SCAFFOLD_PAGE_AREA_WIDTH, height:80, bg:"STATS_BG", display:"flex", alignItems:"center", gap:24, px:32})
contentWrap=I("pageArea", {name:"ContentWrap", y:144, width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CONTENT_HEIGHT_A, display:"flex", justifyContent:"center", p:32})
contentInner=I("contentWrap", {name:"ContentInner", width:SCAFFOLD_CONTENT_MAX, display:"flex", flexDirection:"column", gap:24})

Após scaffold: snapshot_layout() — verifique se pageArea.width e contentInner.width estão corretos.


Scaffold B — Lista / Fila do Aplicativo

Tabelas, bibliotecas de ativos, filas, gerenciamento de usuários

sidebar=I("root", {name:"Sidebar", width:SCAFFOLD_SIDEBAR_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"SIDEBAR_BG"})
pageArea=I("root", {name:"PageArea", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, x:SCAFFOLD_SIDEBAR_WIDTH, bg:"PAGE_BG"})
pageHeader=I("pageArea", {name:"PageHeader", width:SCAFFOLD_PAGE_AREA_WIDTH, height:64, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", px:32})
commandStrip=I("pageArea", {name:"CommandStrip", y:64, width:SCAFFOLD_PAGE_AREA_WIDTH, height:52, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", gap:16, px:32})
tableWrap=I("pageArea", {name:"TableWrap", y:116, width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CONTENT_HEIGHT_B, display:"flex", justifyContent:"center", px:32, pt:24})
tableInner=I("tableWrap", {name:"TableInner", width:SCAFFOLD_CONTENT_MAX, display:"flex", flexDirection:"column", gap:0})
tableHeader=I("tableInner", {name:"TableHeader", width:SCAFFOLD_CONTENT_MAX, height:40, bg:"TABLE_HEADER_BG", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center"})

Scaffold C — Detalhe / Revisão do Aplicativo

Visualizações de detalhe em dois painéis, fluxos de revisão, layouts lado a lado

sidebar=I("root", {name:"Sidebar", width:SCAFFOLD_SIDEBAR_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"SIDEBAR_BG"})
pageArea=I("root", {name:"PageArea", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, x:SCAFFOLD_SIDEBAR_WIDTH, bg:"PAGE_BG"})
pageHeader=I("pageArea", {name:"PageHeader", width:SCAFFOLD_PAGE_AREA_WIDTH, height:64, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR"})
actionBar=I("pageArea", {name:"ActionBar", y:64, width:SCAFFOLD_PAGE_AREA_WIDTH, height:56, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR"})
contentWrap=I("pageArea", {name:"ContentWrap", y:120, width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CONTENT_HEIGHT_C, display:"flex", justifyContent:"center"})
contentInner=I("contentWrap", {name:"ContentInner", width:SCAFFOLD_CONTENT_MAX, height:SCAFFOLD_CONTENT_HEIGHT_C, display:"flex", gap:0})
leftPanel=I("contentInner", {name:"LeftPanel", width:SCAFFOLD_LEFT_PANEL, height:SCAFFOLD_CONTENT_HEIGHT_C, bg:"SURFACE_COLOR", borderRight:"1px solid BORDER_COLOR"})
rightPanel=I("contentInner", {name:"RightPanel", width:SCAFFOLD_RIGHT_PANEL, height:SCAFFOLD_CONTENT_HEIGHT_C, bg:"PAGE_BG", p:24, display:"flex", flexDirection:"column", gap:20})

Nota: A divisão esquerda/direita padrão é ~40/60. Ajuste por funcionalidade — divisões comuns: 40/60, 38/62, 50/50.


Scaffold D — Página de Marketing

Páginas de destino, páginas de produto — sempre com 1440px de largura, independentemente do canvas do aplicativo

navbar=I("root", {name:"Navbar", width:1440, height:72, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", px:80})
heroSection=I("root", {name:"HeroSection", y:72, width:1440, height:600, bg:"HERO_BG", display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center"})
heroContent=I("heroSection", {name:"HeroContent", width:SCAFFOLD_MARKETING_CONTENT_MAX, display:"flex", flexDirection:"column", alignItems:"center", gap:24})
section1=I("root", {name:"Section1", y:672, width:1440, height:480, bg:"SURFACE_COLOR", display:"flex", flexDirection:"column", alignItems:"center", py:80})
section1Content=I("section1", {name:"Section1Content", width:SCAFFOLD_MARKETING_CONTENT_MAX})

Páginas de marketing são mobile-first. Projete em 1440px e verifique o layout em largura de 390px antes da entrega.


Scaffold E — Modal / Diálogo

Confirmações, ações destrutivas, formulários de edição rápida, painéis laterais

Execute o Scaffold A, B ou C primeiro. Em seguida, adicione este modal sobreposto na páginaArea — não insira na raiz.

backdrop=I("pageArea", {name:"ModalBackdrop", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"rgba(0,0,0,0.48)", display:"flex", alignItems:"center", justifyContent:"center"})
modal=I("backdrop", {name:"Modal", width:480, bg:"SURFACE_COLOR", borderRadius:8, border:"1px solid BORDER_COLOR", display:"flex", flexDirection:"column", overflow:"hidden"})
modalHeader=I("modal", {name:"ModalHeader", height:56, px:24, display:"flex", alignItems:"center", justifyContent:"space-between", borderBottom:"1px solid BORDER_COLOR"})
modalBody=I("modal", {name:"ModalBody", px:24, py:20, display:"flex", flexDirection:"column", gap:16})
modalFooter=I("modal", {name:"ModalFooter", height:60, px:24, display:"flex", alignItems:"center", justifyContent:"flex-end", gap:12, borderTop:"1px solid BORDER_COLOR"})

Após scaffold: snapshot_layout() — confirme que o modal está visível e centralizado. Ajuste a largura do modal por caso de uso: 380px (confirmação compacta), 480px (formulário padrão), 600px (formulário amplo), 720px (detalhe/pré-visualização).


Scaffold F — Assistente / Passo a Passo

Formulários de várias etapas, fluxos de integração, sequências de configuração, checkout

sidebar=I("root", {name:"Sidebar", width:SCAFFOLD_SIDEBAR_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"SIDEBAR_BG"})
pageArea=I("root", {name:"PageArea", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, x:SCAFFOLD_SIDEBAR_WIDTH, bg:"PAGE_BG"})
pageHeader=I("pageArea", {name:"PageHeader", width:SCAFFOLD_PAGE_AREA_WIDTH, height:64, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", px:32})
stepperBar=I("pageArea", {name:"StepperBar", y:64, width:SCAFFOLD_PAGE_AREA_WIDTH, height:60, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", justifyContent:"center"})
contentWrap=I("pageArea", {name:"ContentWrap", y:124, width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CONTENT_HEIGHT_F, display:"flex", justifyContent:"center", px:32, pt:32})
contentInner=I("contentWrap", {name:"ContentInner", width:640, display:"flex", flexDirection:"column", gap:24})
actionFooter=I("pageArea", {name:"ActionFooter", y:SCAFFOLD_WIZARD_FOOTER_Y, width:SCAFFOLD_PAGE_AREA_WIDTH, height:72, bg:"SURFACE_COLOR", borderTop:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", justifyContent:"space-between", px:32})

Nota: ContentInner tem 640px de largura por padrão — formulário de coluna única focado. Botão Voltar à esquerda, Próximo/Enviar à direita em ActionFooter (justifyContent:"space-between").


Scaffold G — Tela Mobile

390×844px (padrão iPhone 14). Use para todas as telas mobile — codificado, nenhum valor de configuração necessário.

statusBar=I("root", {name:"StatusBar", width:390, height:44, bg:"PAGE_BG"})
navBar=I("root", {name:"NavBar", y:44, width:390, height:56, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", px:16})
scrollContent=I("root", {name:"ScrollContent", y:100, width:390, height:688, bg:"PAGE_BG", display:"flex", flexDirection:"column", overflow:"hidden"})
contentPad=I("scrollContent", {name:"ContentPad", width:390, display:"flex", flexDirection:"column", gap:16, px:16, pt:16})
bottomNav=I("root", {name:"BottomNav", y:788, width:390, height:56, bg:"SURFACE_COLOR", borderTop:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", justifyContent:"space-around"})

Nota: Remova statusBar e defina navBar.y=0 se não estiver exibindo a interface do sistema. Remova bottomNav para aplicativos sem navegação por abas. Os alvos de toque dentro deste scaffold devem ter ≥44×44px.


Scaffold H — Formulário / Entrada de Dados

Páginas de configurações, edição de perfil, entrada intensa de dados — coluna única, formulário centralizado

sidebar=I("root", {name:"Sidebar", width:SCAFFOLD_SIDEBAR_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"SIDEBAR_BG"})
pageArea=I("root", {name:"PageArea", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, x:SCAFFOLD_SIDEBAR_WIDTH, bg:"PAGE_BG"})
pageHeader=I("pageArea", {name:"PageHeader", width:SCAFFOLD_PAGE_AREA_WIDTH, height:64, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", justifyContent:"space-between", px:32})
formWrap=I("pageArea", {name:"FormWrap", y:64, width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CONTENT_HEIGHT_H, display:"flex", justifyContent:"center", px:32, pt:32})
formInner=I("formWrap", {name:"FormInner", width:600, display:"flex", flexDirection:"column", gap:28})
formSection=I("formInner", {name:"FormSection1", display:"flex", flexDirection:"column", gap:16})
formActions=I("formInner", {name:"FormActions", display:"flex", gap:12, justifyContent:"flex-end"})

Nota: A largura padrão do FormInner é 600px. Use 480px para fluxos simples, 800px para layouts amplos de duas colunas. Adicione mais nós FormSection dentro de formInner para agrupar campos relacionados.


Scaffold I — Estado Vazio / Etapa de Integração

Visualizações sem dados, prompts de primeiro uso, descoberta de funcionalidades, telas em branco

sidebar=I("root", {name:"Sidebar", width:SCAFFOLD_SIDEBAR_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"SIDEBAR_BG"})
pageArea=I("root", {name:"PageArea", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, x:SCAFFOLD_SIDEBAR_WIDTH, bg:"PAGE_BG"})
pageHeader=I("pageArea", {name:"PageHeader", width:SCAFFOLD_PAGE_AREA_WIDTH, height:64, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR"})
emptyCenter=I("pageArea", {name:"EmptyCenter", y:64, width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CONTENT_HEIGHT_H, display:"flex", alignItems:"center", justifyContent:"center"})
emptyContent=I("emptyCenter", {name:"EmptyContent", width:400, display:"flex", flexDirection:"column", alignItems:"center", gap:20})
illustrationArea=I("emptyContent", {name:"IllustrationArea", width:200, height:160, borderRadius:12, bg:"SURFACE_COLOR", border:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", justifyContent:"center"})
textStack=I("emptyContent", {name:"TextStack", width:400, display:"flex", flexDirection:"column", alignItems:"center", gap:8})
emptyActions=I("emptyContent", {name:"EmptyActions", display:"flex", gap:12})

Nota: Substitua IllustrationArea por G("illustrationArea", "ai", "your prompt") para gerar uma ilustração. Mantenha o texto do estado vazio curto: um título (16–18px), uma linha de apoio (14px muted), um CTA primário.


Fluxos de Trabalho Principais

Fluxo 1: Arqueologia de Canvas

Use quando: "o que tem neste arquivo .pen?" ou "descreva o layout atual"

1. open_document("path/to/file.pen")
2. get_editor_state()

Descreva a estrutura retornada — número de elementos, hierarquia de aninhamento, sistema de grade usado, quaisquer anotações. Se o canvas estiver vazio: "Canvas vazio — dimensões {X}x{Y}, nenhum elemento renderizado." Se houver um scaffold reconhecível, nomeie-o ("Parece um scaffold da Dashboard do Aplicativo — sidebar de {N}px, header, barra de estatísticas, wrap de conteúdo").

Fluxo 2: Construção de Componente

Use ao construir qualquer componente de interface: botões, cartões, tabelas, menus dropdown, barras de progresso, etc.

  1. Análise de Contexto: Entenda como o componente se encaixa no layout. Verifique os elementos pais — não construa um botão primário que flutua isoladamente.
  2. Hierarquia Visual: Dê ao componente a profundidade correta usando sombras, elevação, cor de fundo. Botões têm borderRadius:6 por padrão; ajuste para 4 em componentes compactos.
  3. Estado: construa variantes de estado onde for relevante: padrão, hover (se o editor suportar pseudo-estados), ativo, desabilitado.
  4. Escala: O componente preenche seu contêiner por padrão (width:"100%" ou herança) a menos que seja um elemento flutuante (modais, dropdowns, dicas de ferramentas).
  5. Toques Finais: tamanhos de fonte entre 12–16px, pesos de fonte conforme grade tipográfica, altura de linha de 1.4–1.6.

Diretrizes de Design

Estas regras substituem preferências subjetivas. Aplique-as sempre.

Hierarquia Visual

  • Tamanho acima de cor — elementos maiores parecem mais importantes, mesmo sem cor. Ao sinalizar importância, aumente o tamanho primeiro, depois ajuste o peso/contraste. Botões primários são mais altos (40–48px) do que botões secundários (32–36px).
  • Profundidade e Elevação — si. Use sombras para empurrar elementos para frente no espaço. Modais e dropdowns estão sempre acima de tudo.
  • Tipografia Escalonada — títulos: 20–24px, subtítulos: 16–18px, corpo: 14px, suporte: 12px. Não use tamanhos arbitrários.

Espaçamento e Ritmo

  • Use apenas valores da sua grade de espaçamento: 4, 8, 12, 16, 20, 24, 32, 40, 48, 64. Prefira 8 e 16 entre elementos. Use 24 e 32 para separar seções.
  • Elementos de cartão: padding 24px. Espaçamento interno entre grupos: 16px.
  • O espaçamento visual entre um título e seu conteúdo é 8px. Título para próxima seção: 24px.

Contraste e Acessibilidade

  • Contraste de texto: texto principal ≥7:1 contra fundo, texto de suporte ≥4.5:1 contra fundo. Links: ≥3:1 contra texto ao redor, ≥4.5:1 contra fundo.
  • Não coloque texto claro (por exemplo, #FFFFFF ou #F5F5F5) sobre imagens de fundo sem uma sobreposição escura (pelo menos 60% de opacidade).
  • Alvos de toque: mínimo 44×44px em telas mobile. Em telas desktop, 32×32px mínimo, prefira 40×40px.

Cor e Branding

  • Use cores primárias para ações e navegação. Use cores de superfície para fundos de cartão, cabeçalhos de tabela, barras laterais.
  • Nunca use a cor primária como cor de fundo a menos que seja para um herói ou banner promocional onde o contraste é controlado.
  • As cores de estado (sucesso, aviso, erro) devem ser usadas apenas para seus significados pretendidos. Não use cor de erro para decoração.

Organização de Layout

  • As telas de aplicativo sempre têm uma barra lateral à esquerda (largura do scaffold) e uma área de página.
  • As barras laterais contêm navegação. As áreas de página contêm cabeçalho, conteúdo, rodapé de ação.
  • Páginas de marketing não têm barra lateral. Use largura total de 1440px com preenchimento de conteúdo.
  • Telas mobile não têm barra lateral. Use scaffold 390×844. Cabeçalho no topo, navegação inferior na parte inferior.

O Que Não Fazer

  • Não coloque modais na raiz do canvas. Insira-os na pageArea para que a sobreposição funcione corretamente com snapshot_layout().
  • Não crie elementos filho sem um pai — verifique a hierarquia. Botões não flutuam sozinhos; estão dentro de um contêiner.
  • Não adivinhe tokens de marca — sempre execute get_variables() primeiro para verificar valores armazenados. Se estiverem vazios, peça ao usuário para executar o assistente de configuração.
  • Não ultrapasse o canvas — verifique com snapshot_layout() antes de terminar.
  • Não use fontes que não estejam no mapa de tokens. Se o aplicativo não especificar uma fonte, use o font-sans padrão.
  • Não construa scaffolds parciais — se você iniciar um scaffold, renderize todos os elementos definidos nele. Scaffolds parciais produzem layouts quebrados.
  • Não crie barras laterais em aplicativos sem barra lateral (Scaffold I — Estado Vazio) ou em telas mobile.

Habilidades Relacionadas