Design System
Cerne v0.1

Um design system completo, do zero, sem dependências externas

Cerne é um framework CSS + JS autocontido — sem CDNs, sem jQuery, sem builds obrigatórios em produção. Foi desenhado para servir múltiplos domínios com o mesmo sistema de tokens e componentes: dashboards administrativos, ambientes de aprendizagem, sistemas de gestão, agendamento de salas e blogs.

ITCSS + CUBE CSS Utility-first + componentes Dark mode nativo Acessível por padrão Zero dependências
Por que o Cerne existe

Uma ferramenta potente para os tempos modernos de desenvolvimento web

O Cerne está na versão 0.1 — um design system inteiro, construído do zero, com um propósito simples: dar a qualquer pessoa uma base rápida, robusta e gratuita para tirar sistemas do papel e colocá-los na internet, sem depender de CDN, sem licença, sem vendor lock-in e sem paywall. Código aberto, acessível a todo mundo, para sempre.

O que já vem pronto na v0.1

  • 40+ componentes de produção — app shell, datatable, calendário, gráficos, chat, video player, modais, formulários avançados e muito mais.
  • 43 exemplos completos prontos para copiar: dashboards, e-commerce, streaming, webmail, rede social, portal de notícias, LLM chat, smart TV...
  • Zero dependências externas — sem jQuery, sem CDN, sem build obrigatório em produção. Abre com um duplo clique no HTML.
  • Dark mode nativo e prefers-reduced-motion/prefers-color-scheme respeitados automaticamente.
  • RTL de verdade via propriedades lógicas — não é um hack de espelhamento.
  • Acessibilidade WCAG 2.1 AA por padrão em todo componente interativo.
  • Internacionalização real — 168 páginas de exemplo traduzidas em CJK, árabe, hindi e russo, não só a interface.
  • CSS moderno de verdade — container queries, cascade layers, color-mix(), clamp(), densidade configurável por data-density.

É uma v0.1 por escolha, não por limitação: o núcleo já está sólido e em uso real nos 43 exemplos acima, mas o projeto segue evoluindo em público — cada versão nova adiciona mais primitivos, mais idiomas, mais componentes, sem quebrar o que já existe.

RV
Ricardo Cezar Volert Curitiba, Paraná, Brasil

Criador e mantenedor do Cerne. Todo o framework — tokens, componentes, os 43 exemplos e as variantes regionais — foi desenhado por Ricardo e construído em colaboração com IA (Claude, da Anthropic), com o objetivo de deixar uma ferramenta boa, aberta e gratuita para quem está construindo a próxima geração de sistemas na web.

Instalação

Copie os arquivos compilados de dist/ para o seu projeto e referencie-os diretamente. Nenhuma etapa de build é necessária para consumir o framework.

<link rel="stylesheet" href="dist/css/cerne.css">

<!-- No fim do body: script clássico (não type="module") para expor window.Cerne -->
<script src="dist/js/cerne.js"></script>

Para evitar o "flash" do tema errado antes do JS carregar, inclua este trecho no <head>, antes do CSS:

<script>
  var t = localStorage.getItem('cerne-theme');
  if (t) document.documentElement.setAttribute('data-theme', t);
</script>

Cores

Paletas primitivas de 11 tons + camada semântica (--cerne-color-primary, -hover, -active, -subtle...) que troca de valor automaticamente entre os temas claro e escuro. Os valores abaixo são lidos ao vivo do CSS compilado — nunca ficam dessincronizados desta documentação.

Espaçamento

Escala de 4px, exposta como --cerne-space-* e como utilitários p-*, m-*, gap-*.

Tipografia

Escala modular (~1.25), fonte padrão = stack de sistema (zero requisições de rede). Troque --cerne-font-sans para usar uma fonte própria self-hosted.

Radius & Sombra

Elevação com receitas distintas para claro/escuro — sombras escuras não desaparecem sobre fundo escuro.

Radius

Sombra

Grid

API clássica .row/.col-* sobre CSS Grid, mais utilitários .grid-cols-* / .col-span-* com prefixos responsivos md:, lg:.

<div class="row">
  <div class="col-12 col-md-4">...</div>
  <div class="col-12 col-md-4">...</div>
  <div class="col-12 col-md-4">...</div>
</div>

App Shell

O primitivo central para dashboards: sidebar + topbar + main via grid-template-areas, com colapso para off-canvas abaixo de lg. Esta própria página usa .app-shell.

<div class="app-shell" id="app-shell">
  <div class="app-shell__backdrop"></div>
  <aside class="app-shell__sidebar">...</aside>
  <header class="app-shell__topbar">...</header>
  <main class="app-shell__main">...</main>
</div>

Botões

Variantes sólida, contornada e fantasma para cada cor semântica, mais tamanhos e estado de carregamento.

<button class="btn btn-primary">Primário</button>
<button class="btn btn-outline-primary">Contornado</button>
<button class="btn btn-ghost-primary">Fantasma</button>

Formulários

Controles nativos estilizados, validação via data-cerne-validate (Constraint Validation API) e mensagens de erro customizáveis por atributo.

<form data-cerne-validate novalidate>
  <div class="form-group">
    <label class="form-label" for="email">E-mail</label>
    <input class="form-control" type="email" id="email" required
      data-error-required="Informe seu e-mail.">
    <span class="form-error"></span>
  </div>
</form>

Mais formulários

Label flutuante, senha com força e visibilidade, código OTP, busca com limpar, slider, tags, combobox, cards selecionáveis, seletor segmentado, upload por arraste e contador de caracteres — para cobrir qualquer fluxo, de login a checkout.

Força:
Setas para navegar, Enter para selecionar, Esc para fechar. Termo buscado aparece em <mark>.
0/140
Arraste arquivos aqui ou clique para escolher
<div class="form-floating">
  <input class="form-control" placeholder=" " id="name">
  <label for="name">Nome completo</label>
</div>

<div class="otp-input" data-cerne-otp>
  <input class="otp-digit"> <input class="otp-digit"> ...
</div>

<div class="tags-input" data-cerne-tags-input>
  <input type="text" placeholder="Adicionar tag...">
</div>

<div class="segmented" role="tablist" data-cerne-segmented>
  <button type="button" class="segmented-item is-active" role="tab">30 dias</button>
  <!-- ... -->
</div>

<div class="file-drop" data-cerne-file-upload data-cerne-file-list="#file-list">
  <input type="file" multiple>
  <span>Arraste arquivos aqui ou clique para escolher</span>
</div>
<div class="file-list" id="file-list"></div>

Cards

Reservas hoje 24 +12% vs. ontem
Título do card
Conteúdo do card com texto de exemplo.

Mídia

.carousel (um slide por vez, com bolinhas e autoplay opcional) e .shelf (fileira com scroll horizontal, RTL-aware) — para hero de portal institucional e catálogos estilo streaming, respectivamente.

Carrossel (data-cerne-carousel-autoplay)

Prateleira (passe o mouse para revelar as setas)

Ilustração de montanhas ao entardecer
Ilustração abstrata de retrato
Ilustração de montanhas ao entardecer, em preto e branco
Ilustração abstrata de retrato
Ilustração de montanhas ao entardecer
<div class="carousel" data-cerne-carousel data-cerne-carousel-autoplay="5000">
  <div class="carousel-track">
    <div class="carousel-slide">...</div>
  </div>
  <button data-cerne-carousel-prev>‹</button>
  <button data-cerne-carousel-next>›</button>
  <div class="carousel-dots"></div>
</div>

<div class="shelf" data-cerne-shelf>
  <button data-cerne-shelf-prev>‹</button>
  <div class="shelf-track">
    <div class="shelf-item"><img src="poster.jpg" alt="..." /></div>
  </div>
  <button data-cerne-shelf-next>›</button>
</div>

Vídeo

Cerne.VideoPlayer — progressive enhancement sobre a marcação de vídeo existente (não impõe HTML próprio): play/pause, seek por clique, volume, controle de velocidade. Roda em "relógio simulado" quando não há um <video> real (como abaixo), ou espelha um <video> nativo (MP4, HLS via hls.js...) quando você passa [data-video-element] — a entrega real por streaming adaptativo é responsabilidade de quem implementa, fora do escopo de um framework de CSS/JS.

0:00 / 0:00
<div class="player" id="player" data-duration="196">
  <button data-video-toggle>▶</button>
  <div class="player-controls">
    <div class="progress" data-video-seek><div class="progress-bar" data-video-fill></div></div>
    <button data-video-mute-toggle>🔊</button>
    <input type="range" data-video-volume min="0" max="1" step="0.05" value="1">
    <span data-video-time>0:00 / 0:00</span>
    <button data-video-speed="1.5">1.5x</button>
  </div>
</div>

<script>
  new Cerne.VideoPlayer(document.getElementById("player"), { duration: 196 });
</script>

Exemplos completos: vídeo com legendas WebVTT, streaming com "próximo episódio", transmissão live: true e smart TV com navegação por D-pad.

Tabelas & Datatable

.table para tabelas estáticas; [data-cerne-datatable] adiciona ordenação, busca e paginação client-side sem nenhuma dependência.

Nome Curso Progresso
Marina SilvaRedes de Computadores92%
Diego SouzaBanco de Dados78%
Ana BeatrizAlgoritmos65%
Lucas PereiraRedes de Computadores40%
Juliana MeloSistemas Operacionais88%
Rafael CostaBanco de Dados55%

Conteúdo editorial

Colunas, quadros de destaque, marca-texto com nota explicativa e barra de progresso de leitura — para blog, portal de notícias ou qualquer texto longo dentro de .prose. Aliás, olhe o topo da tela: a barra fina colorida acima do menu é .reading-progress rastreando o scroll desta própria página de documentação.

Quadros (.callout)

Leia também
Um link para outra matéria relacionada.
Aviso ou correção destacada no meio do texto.
Nota explicativa de um termo marcado com <mark> no parágrafo acima — estilo "glossário"/"IA explica" de portais de notícias.

Marca-texto (<mark data-cerne-reveal="mark">) + quadro de glossário — a cor do destaque "pinta" da esquerda para a direita (ou o inverso em dir="rtl") quando o termo entra na tela, em vez de aparecer pronto.

O relator destacou que o novo marco regulatório muda o rito de aprovação no plenário.

Marco regulatório é o conjunto de regras que rege um setor específico, criado ou alterado por lei ou decreto.

Colunas de texto (.columns-2 / .columns-3, dentro de .prose)

Primeira coluna: o texto flui verticalmente e quebra para a coluna seguinte.

Segunda coluna: útil para listas curtas de destaques, glossários ou citações — colapsa para 1 coluna abaixo de md.

<p>O novo <mark data-cerne-reveal="mark">marco regulatório</mark> muda o rito de aprovação.</p>
<div class="callout callout-glossary">
  <svg class="callout-icon"><use href="sprite.svg#icon-search"></use></svg>
  <div class="callout-body"><strong>Marco regulatório</strong> é...</div>
</div>

<div class="columns-2"><p>...</p><p>...</p></div>

<div class="reading-progress"><div class="reading-progress-bar"></div></div>

Veja um exemplo completo em contexto no post do blog ou na matéria do portal de notícias.

Modais & Offcanvas

Painel lateral

Usado para filtros, carrinhos ou detalhes rápidos sem sair da página.

Alertas & Toasts

Sucesso
Sua reserva foi confirmada.
Atenção
Este horário está quase lotado.

Calendário & Agendamento

Grade semanal de horários para reserva de salas — veja o exemplo completo em Agendamento.

Confirmado Pendente Minha reserva

Gráficos

Mini gráficos SVG sem dependências (Cerne.Chart.bar/line/donut).

Mais componentes

List group, spinner, rating, hero e pricing — para lojas, portais institucionais, páginas de marketing e catálogos.

4.2 (128)
<div class="rating">
  <svg class="is-filled"><use href="sprite.svg#icon-star"></use></svg>
  <!-- ... -->
  <span class="rating-count">4.2 (128)</span>
</div>

Imagens

Recorte (object-fit/aspect-ratio), filtros CSS (grayscale, blur-*, brightness-*...) e receitas de tratamento (zoom no hover, scrim para legenda, duotone, recorte orgânico) — tudo CSS puro, sem biblioteca de processamento de imagem. As fotos desta página são ilustrações SVG autorais, para a doc continuar 100% autocontida.

Recorte & proporção

.aspect-video/.aspect-square/.aspect-portrait fixam a proporção do contêiner; .object-cover preenche sem distorcer.

Ilustração de montanhas ao entardecer aspect-video
Ilustração abstrata de retrato aspect-square
Ilustração de montanhas ao entardecer aspect-portrait
<img class="aspect-video object-cover rounded-md" src="foto.jpg" alt="..." />

Filtros

Classes atômicas, combináveis (class="grayscale contrast-125") — cada uma controla uma única propriedade filter.

Sem filtro sem filtro
Filtro grayscale grayscale
Filtro sepia sepia
Filtro blur-sm blur-sm
Filtro brightness-50 brightness-50
Filtro brightness-150 brightness-150
Filtro contrast-150 contrast-150
Filtro saturate-0 saturate-0
Filtro saturate-200 saturate-200
Filtro hue-rotate-90 hue-rotate-90
Filtro invert invert
Filtros combinados grayscale e contrast-125 grayscale contrast-125
<img class="grayscale" src="foto.jpg" alt="..." />
<img class="sepia" src="foto.jpg" alt="..." />
<img class="blur-sm" src="foto.jpg" alt="..." />
<img class="brightness-150 contrast-125" src="foto.jpg" alt="..." />

Tratamentos

Classes de receita (várias propriedades cada, como .bg-aurora) para padrões comuns de card com foto.

Ilustração de montanhas ao entardecer
.img-hover-zoom — passe o mouse
Ilustração de montanhas ao entardecer
Trilha do Vale
.img-scrim — legenda legível sobre a foto
Ilustração abstrata de retrato
.img-duotone
Ilustração abstrata de retrato
.img-blob — recorte orgânico
<div class="img-hover-zoom rounded-lg aspect-video">
  <img src="foto.jpg" alt="..." />
</div>

<div class="img-scrim rounded-lg aspect-video">
  <img src="foto.jpg" alt="..." />
  <div class="img-scrim-caption"><strong>Trilha do Vale</strong></div>
</div>

<div class="img-duotone aspect-square"><img src="foto.jpg" alt="..." /></div>
<div class="img-blob aspect-square"><img src="foto.jpg" alt="..." /></div>

Tendências modernas

Bento grid, spotlight card, borda em gradiente, glow, grão/ruído, aurora, marquee, FAB e barra de progresso de leitura — técnicas visuais atuais, prontas para qualquer aplicação.

Bento grid Grade assimétrica estilo Apple, com spotlight no hover.
Item simples
Borda em gradiente
Card com borda gradiente

Marquee (pausa no hover)

Design System Acessibilidade Dark mode RTL Design System Acessibilidade Dark mode RTL
Este bloco usa data-cerne-reveal — role a página para vê-lo animar.
<div class="bento-grid">
  <div class="bento-item bento-span-2 card-spotlight">...</div>
  <div class="bento-item">...</div>
</div>

<div data-cerne-reveal="up">Aparece ao rolar a página</div>
<span data-cerne-count-up="1284" data-cerne-count-up-format>0</span>

Variantes de utilitário & adaptação regional

hover:, focus:, focus-visible:, active:, disabled:, focus-within: e dark: na frente de qualquer utilitário de cor/sombra/opacidade, mais group-hover:/peer-checked: em CSS puro (sem JS — .group/.peer são só marcadores), container queries (.cq + cq-md:) e os primitivos que tornam o framework adaptável a padrões de UI de qualquer região — não só ocidental.

Passe o mouse neste card

O botão ao lado usa group-hover:opacity-100 — só aparece quando o pai (.group) está em hover.

data-density="compact" na <html> multiplica toda a escala de espaçamento de uma vez — aproxima o resultado do padrão de alta densidade de informação comum em portais/e-commerce do Leste Asiático. .break-keep e .write-vertical cobrem quebra de texto e escrita vertical em CJK; --cerne-line-height-base fica automaticamente mais generoso em :lang(ar|he|hi|bn|ta|te|th). Veja as 9 páginas de exemplo (loja/notícias/painel × CJK/RTL/Sul da Ásia) em Ver exemplos.

<div class="group card">
  <button class="opacity-25 group-hover:opacity-100 hover:bg-primary">...</button>
</div>

<div class="cq">
  <div class="flex-col cq-md:flex-row">...</div> <!-- reage ao espaço do .cq, não do viewport -->
</div>

<html data-density="compact"> <!-- ou "spacious" -->

Ícones

87 ícones em sprite SVG único (dist/icons/sprite.svg), autorais, referenciados via <use>.

Acessibilidade

O alvo é WCAG 2.1 nível AA — o padrão internacional, independente de país ou idioma — não uma ferramenta ou selo específico de uma jurisdição.

  • Todo componente interativo tem estado :focus-visible visível e navegação por teclado (setas em tabs/menus, Esc para fechar, Tab preso em modais, roving tabindex em tabs).
  • prefers-reduced-motion e prefers-color-scheme são respeitados automaticamente, sem nenhuma configuração extra.
  • Cores de texto sobre fundo sólido foram escolhidas para AA — atenção especial em warning/info, que usam texto escuro em vez de branco por não atingirem contraste suficiente.
  • Formulários associam rótulo (for/id), erro e aria-invalid; o estado de erro nunca depende só de cor.
  • Links de navegação ativos recebem aria-current="page"; landmarks (main, nav, aside) e um <h1> único por página estruturam o documento para leitores de tela.
  • Texto alternativo descritivo em imagens/gráficos é responsabilidade de quem usa o framework — o Cerne não consegue gerar isso por você. A convenção brasileira #PraCegoVer (descrever a imagem no própria legenda/alt) é um bom hábito, mas a prática que importa — escrever um alt que descreva a imagem, não repita o óbvio — vale em qualquer idioma.
  • Sobre VLibras e ferramentas de tradução para língua de sinais: propositalmente não vêm embutidas, pois dependem de um script externo (CDN de terceiros) e são específicas de uma língua/país — o que contradiria tanto "zero dependências externas" quanto "framework internacional". A base correta e universal é HTML semântico + ARIA bem feitos, que qualquer tecnologia assistiva do mundo já sabe interpretar; um widget de tradução específico pode ser adicionado por cima, projeto a projeto, quando fizer sentido.
  • RTL de verdade: os componentes usam propriedades lógicas (inset-inline-start, margin-inline-end, text-align: start...) em vez de left/right fixos, então basta dir="rtl" no <html> para espelhar sidebar, dropdown, tabs, formulários e navegação — sem CSS extra. Veja ao vivo:
Card com acento lateral

A borda acompanha o início do texto, não um lado fixo.

<html lang="ar" dir="rtl">
  <!-- sidebar, dropdown, tabs, formulários... tudo espelha automaticamente -->

Privacidade & consentimento

Banner de cookies/consentimento genérico — o mesmo padrão de "essencial / análise / marketing" usado por GDPR (UE), LGPD (Brasil) e CCPA (Califórnia), sem depender de nenhuma plataforma de terceiros de gestão de consentimento.

<div class="consent-banner" data-cerne-consent hidden role="region" aria-label="Aviso de cookies">
  <p class="consent-banner-text">Usamos cookies essenciais...</p>
  <div class="consent-banner-actions">
    <button data-cerne-consent-customize
      data-cerne-toggle="modal" data-cerne-target="#consent-preferences">Personalizar</button>
    <button data-cerne-consent-reject>Rejeitar não essenciais</button>
    <button data-cerne-consent-accept>Aceitar tudo</button>
  </div>
</div>

<!-- Cerne.Consent.get() / .set({analytics, marketing}) / .reset() -->

A escolha fica em localStorage (chave cerne-consent), nunca em um cookie de terceiros, e nunca é enviada a lugar nenhum — o que o seu backend faz com Cerne.Consent.get() é decisão sua. O banner só aparece automaticamente quando a página contém um elemento [data-cerne-consent]; nesta documentação ele foi omitido de propósito para não ser intrusivo — veja o exemplo completo em Blog, Loja ou Portal institucional.

Exemplos completos

42 páginas construídas inteiramente com o Cerne, cobrindo painel administrativo, ensino, gestão, agendamento, conteúdo, portal de notícias, e-commerce, sites institucionais, vídeo, rede social, streaming, assistente conversacional e portfólio — e cada uma delas com uma variante CJK, RTL, Sul da Ásia e Rússia própria, com tradução completa da interface (168 páginas regionais, ~210 no total), acessível pela barrinha "Variante regional" no topo de qualquer exemplo.

Variantes regionais (CJK, RTL, Sul da Ásia, Rússia)

Toda página de todo exemplo acima tem uma variante CJK, RTL, Sul da Ásia e Rússia — 168 páginas regionais no total — abra qualquer uma e use a barrinha "Variante regional" no topo para navegar entre elas. CJK, RTL e Sul da Ásia usam os primitivos descritos em Variantes & regionaldata-density, .break-keep/.write-vertical, dir="rtl" e --cerne-line-height-base por idioma; a variante Rússia usa lang="ru" com texto em russo sobre a mesma estrutura LTR do exemplo original (sem propriedades lógicas adicionais, já que o russo se comporta como o português nesse sentido). As 168 páginas têm tradução completa — não só a interface (navegação, botões, formulários, rótulos, estados vazios), mas também o conteúdo dinâmico: nomes e descrições de produtos, e-mails de exemplo (assunto e corpo), resultados de busca, títulos e sinopses de vídeo/série, a conversa de exemplo do assistente e o corpo de artigos e posts longos, cada domínio com sua própria cópia dos dados de exemplo por idioma (ex. store-data.cjk.browser.js / store-data.ru.browser.js). O banner de cookies também foi traduzido; só pequenas notas de rodapé descrevendo a própria variante (e nomes próprios de pessoas) permanecem em português, por serem texto de documentação para quem está lendo o código-fonte, não conteúdo do app.

Exemplo CJK RTL Sul da Ásia Rússia
Painel administrativoAbrirAbrirAbrirAbrir
Ambiente de aprendizagemAbrirAbrirAbrirAbrir
Página de professorAbrirAbrirAbrirAbrir
Gestão / CRUDAbrirAbrirAbrirAbrir
Agendamento de salasAbrirAbrirAbrirAbrir
BlogAbrirAbrirAbrirAbrir
Blog — postAbrirAbrirAbrirAbrir
Portal de notíciasAbrirAbrirAbrirAbrir
Portal de notícias — artigoAbrirAbrirAbrirAbrir
Loja e-commerceAbrirAbrirAbrirAbrir
Loja e-commerce — produtoAbrirAbrirAbrirAbrir
Site de laboratórioAbrirAbrirAbrirAbrir
Portal institucionalAbrirAbrirAbrirAbrir
Site de grupo de pesquisaAbrirAbrirAbrirAbrir
Autenticação — loginAbrirAbrirAbrirAbrir
Autenticação — cadastroAbrirAbrirAbrirAbrir
Autenticação — verificação OTPAbrirAbrirAbrirAbrir
Erro 404AbrirAbrirAbrirAbrir
Erro 500AbrirAbrirAbrirAbrir
Plataforma de vídeosAbrirAbrirAbrirAbrir
Vídeos — assistirAbrirAbrirAbrirAbrir
Vídeos — playlistAbrirAbrirAbrirAbrir
Rede social (feed)AbrirAbrirAbrirAbrir
Rede social (perfil)AbrirAbrirAbrirAbrir
Streaming — loginAbrirAbrirAbrirAbrir
Streaming — perfisAbrirAbrirAbrirAbrir
Streaming de vídeoAbrirAbrirAbrirAbrir
Streaming — títuloAbrirAbrirAbrirAbrir
Streaming — assistirAbrirAbrirAbrirAbrir
Streaming — explorarAbrirAbrirAbrirAbrir
Streaming — ao vivoAbrirAbrirAbrirAbrir
Assistente conversacional (LLM)AbrirAbrirAbrirAbrir
Portfólio (grade bento)AbrirAbrirAbrirAbrir
Painel de analyticsAbrirAbrirAbrirAbrir
Webmail (estilo Gmail)AbrirAbrirAbrirAbrir
Webmail (estilo Outlook)AbrirAbrirAbrirAbrir
Buscador (minimalista)AbrirAbrirAbrirAbrir
Buscador (minimalista) — resultadosAbrirAbrirAbrirAbrir
Buscador (portal denso)AbrirAbrirAbrirAbrir
Buscador (portal denso) — resultadosAbrirAbrirAbrirAbrir
Interface de smart TVAbrirAbrirAbrirAbrir
Smart TV — playerAbrirAbrirAbrirAbrir
Cadastro internacional adaptativo (já adapta por país via JS — sem variantes estáticas)