Getting Started
@mariojgt/neo-css is a Neo-Brutalist design system with 30+ components, gaming utilities, and a Theme API. Works with React, Vue, Svelte, Next.js, Nuxt, Astro, or plain HTML. No build tool required to get started.
Installation
Option A — CDN (no build tool)
Add one <link> to your HTML. That's it.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mariojgt/neo-css@latest/dist/neo.css">
Option B — npm / pnpm / yarn
# npm npm install @mariojgt/neo-css # pnpm pnpm add @mariojgt/neo-css # yarn yarn add @mariojgt/neo-css
Then import the stylesheet in your entry file:
import '@mariojgt/neo-css/dist/neo.css'
Sub-bundles
Import only what you need to keep bundles small:
import '@mariojgt/neo-css/dist/tokens.css' // CSS variables only import '@mariojgt/neo-css/dist/components.css' // all component classes import '@mariojgt/neo-css/dist/animations.css' // keyframes only
Quick Start — Plain HTML
A complete working page in under 20 lines:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mariojgt/neo-css@latest/dist/neo.css"> </head> <body class="neo-noise" style="padding:2rem;background:var(--neo-body-bg)"> <button class="neo-btn neo-btn-primary">Primary</button> <button class="neo-btn neo-btn-accent">Accent</button> <button class="neo-btn neo-btn-ghost">Ghost</button> <div class="neo-card" style="max-width:320px;padding:1.5rem;margin-top:1.5rem"> <h2 style="margin-bottom:.5rem">Hello Neo</h2> <p class="neo-text-muted">Bold borders. Hard shadows. Zero apologies.</p> </div> </body> </html>
Framework Setup
⚛️ React (Vite)
-
Install the packageShell
npm install @mariojgt/neo-css
-
Import in your entry filemain.jsx
import '@mariojgt/neo-css/dist/neo.css' import { createRoot } from 'react-dom/client' import App from './App' createRoot(document.getElementById('root')).render(<App />)
-
Use classes in any componentApp.jsx
export default function App() { return ( <div className="neo-card" style={{'{'}}padding: '1.5rem'{'}'}> <button className="neo-btn neo-btn-primary">Click me</button> </div> ) }
▲ Next.js (App Router)
import '@mariojgt/neo-css/dist/neo.css' export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body className="neo-noise">{children}</body> </html> ) }
💚 Vue 3
import { createApp } from 'vue' import '@mariojgt/neo-css/dist/neo.css' import App from './App.vue' createApp(App).mount('#app')
💚 Nuxt 3
export default defineNuxtConfig({ css: ['@mariojgt/neo-css/dist/neo.css'], })
🔥 Svelte / SvelteKit
<script> import '@mariojgt/neo-css/dist/neo.css' </script> <slot />
🚀 Astro
--- import '@mariojgt/neo-css/dist/neo.css' --- <html lang="en"> <body class="neo-noise"> <slot /> </body> </html>
Tailwind CSS Preset
Use the built-in Tailwind preset to get all Neo design tokens as Tailwind utilities — no CSS import needed.
module.exports = {
presets: [require('@mariojgt/neo-css/tailwind-preset')],
content: ['./src/**/*.{html,js,ts,jsx,tsx,vue,svelte}'],
}
The preset exposes:
- Color utilities:
bg-brand,text-brand,border-accent,bg-surface,text-muted… - Shadow utilities:
shadow-neo,shadow-neo-sm,shadow-neo-lg,shadow-neo-xl border-3width utility- All Neo animation keyframes as
animate-neo-*
Design Tokens
All values are CSS custom properties on :root. Override any token after the import to customise the theme.
/* After importing neo.css, override any token: */ :root { /* Brand */ --neo-brand: #0d9668; --neo-brand-light: #2bb885; --neo-brand-dark: #047857; /* Surfaces (dark by default) */ --neo-body-bg: #080d19; --neo-surface: #0c1222; --neo-surface-light: #131d33; --neo-surface-lighter: #1a2742; /* Accent & Borders */ --neo-accent: #e6930a; --neo-border-color: #3a506e; --neo-border: 3px solid var(--neo-border-color); --neo-radius: 0.375rem; /* Shadows */ --neo-shadow: 5px 5px 0 #000; --neo-shadow-sm: 4px 4px 0 #000; --neo-shadow-lg: 6px 6px 0 #000; --neo-shadow-xl: 8px 8px 0 #000; /* Typography */ --neo-font-sans: ui-sans-serif, system-ui, sans-serif; --neo-font-mono: ui-monospace, Consolas, monospace; }
Runtime Theming
Switch themes at runtime by calling setNeoTheme() — no page reload required. Persisted in sessionStorage.
// Built-in themes setNeoTheme('emerald') // default green setNeoTheme('violet') // purple brand setNeoTheme('crimson') // red brand
Or define your own by setting CSS variables in a class and calling document.documentElement.className = 'my-theme'.
All Components
Cards
<!-- Basic card (hover lifts) --> <div class="neo-card" style="padding:1.5rem">Content</div> <!-- Brand card (green top border) --> <div class="neo-card-brand" style="padding:1.5rem">Content</div> <!-- Stat card --> <div class="neo-stat-card"> <p class="neo-text-muted">Total Users</p> <p style="font-size:2rem;font-weight:900">12,480</p> </div>
Modal
<button class="neo-btn neo-btn-primary" onclick="neoModalOpen('my-modal')">Open</button> <div class="neo-modal-backdrop" id="my-modal" onclick="if(event.target===this)neoModalClose('my-modal')"> <div class="neo-modal"> <div class="neo-modal-header"> <h2 class="neo-modal-title">Title</h2> <button class="neo-modal-close" onclick="neoModalClose('my-modal')">✕</button> </div> <div class="neo-modal-body">Body text here.</div> <div class="neo-modal-footer"> <button class="neo-btn neo-btn-primary">Confirm</button> </div> </div> </div> <script> function neoModalOpen(id) { document.getElementById(id).classList.add('open') document.body.style.overflow = 'hidden' } function neoModalClose(id) { document.getElementById(id).classList.remove('open') document.body.style.overflow = '' } </script>
Accordion
<div class="neo-accordion"> <div class="neo-accordion-item open"> <button class="neo-accordion-trigger" onclick="neoAccordion(this)"> Question <span class="neo-accordion-chevron">▼</span> </button> <div class="neo-accordion-body">Answer text.</div> </div> </div> <script> function neoAccordion(btn) { const item = btn.closest('.neo-accordion-item') const isOpen = item.classList.contains('open') item.closest('.neo-accordion') .querySelectorAll('.neo-accordion-item.open') .forEach(el => el.classList.remove('open')) if (!isOpen) item.classList.add('open') } </script>
Tooltip — pure CSS, zero JS
<button class="neo-btn neo-btn-primary" data-tip="Creates a new project"> New Project </button> <!-- Works on any element --> <span class="neo-badge neo-badge-success" data-tip="Deployed 2 min ago">Live</span>
Skeleton Loader
<!-- Sizes --> <div class="neo-skeleton neo-skeleton-thumb"></div> <!-- image area --> <div class="neo-skeleton neo-skeleton-title"></div> <!-- heading --> <div class="neo-skeleton neo-skeleton-text"></div> <!-- body line --> <div class="neo-skeleton neo-skeleton-avatar"></div> <!-- circle --> <div class="neo-skeleton neo-skeleton-btn"></div> <!-- button -->
Avatar
<!-- Sizes: sm | md | lg | xl --> <div class="neo-avatar neo-avatar-md">MJ</div> <div class="neo-avatar neo-avatar-md neo-avatar-brand neo-avatar-online">AB</div> <!-- Group (overlapping) --> <div class="neo-avatar-group"> <div class="neo-avatar neo-avatar-md">A</div> <div class="neo-avatar neo-avatar-md">B>C</div> <div class="neo-avatar neo-avatar-md">+3</div> </div>
Keyboard Badges
Press <span class="neo-kbd">⌘ K</span> to search. Save with <span class="neo-kbd">⌃ S</span>. Dismiss with <span class="neo-kbd">Esc</span>.
Gaming Utilities
neo.js. Copy them from the showcase source or the GitHub repo.