themes-cyberpunk/manifest.yaml
Alex Dunmow 644a8083f7 fix(cyberpunk): rain first-paint density, seed depth, HUD bracket inset, sized icon SVGs
- hero rain canvas: seed drops across full height so the digital-rain reads
  dense from the first painted frame (was starting all drops above the
  viewport -> near-blank within a short capture settle).
- seed: expand the About story + give the pull-quote a real attribution
  (was the two-word 'The studio' stub); expand all three devlog articles,
  making-it-rain to ~10 paragraphs, so no article strands a void above the
  footer.
- manifest CSS: inset the HUD corner brackets 5px so they clear rounded /
  overflow-hidden panels (fixes the clipped cyan tick on the code_neon block).
- SVG geometry guard: explicit width/height on all 37 icon <use>/inline SVGs
  (px = tailwind unit x4) so a purged utility can't balloon them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 16:10:38 +08:00

393 lines
14 KiB
YAML

# Cyberpunk theme — codeless .bnp manifest (WO-TF-015, Wave A).
# Synthesized into manifest.pb by `ninja plugin build` (no plugin.wasm).
theme_presets: presets.json
bundled_fonts: fonts.json
master_pages: master_pages.json
required_icon_packs: ["lucide", "simple-icons"]
system_templates:
- key: cyberpunk
title: Cyberpunk
description: "Neon-on-black game-studio / hacker-collective theme — RGB-split glitch, CRT scanlines, HUD brackets, angled clip cuts, and a canvas digital-rain hero."
page_templates:
- system: cyberpunk
key: default
title: Default
description: "Standard dark page with scanline overlay and a sticky terminal-style header"
slots: [header, main, footer]
- system: cyberpunk
key: full-width
title: Full Width
description: "Edge-to-edge dashboard / showcase layout, no max-width"
slots: [header, main, footer]
- system: cyberpunk
key: landing
title: Landing
description: "Canvas digital-rain hero, neon feature grid, glowing CTA, footer"
slots: [header, main, footer]
- system: cyberpunk
key: article
title: Article
description: "Mono-metadata header, prose column, HUD-framed aside"
slots: [header, main, aside, footer]
- system: cyberpunk
key: blog-index
title: Blog Index
description: "Patch-notes feed layout with neon post cards and sidebar"
slots: [header, main, footer]
- system: cyberpunk
key: contact
title: Contact
description: "Terminal contact console — form panel plus HUD contact card"
slots: [header, main, footer]
- system: cyberpunk
key: auth
title: Auth
description: "Centered neon auth console for login / register / reset"
slots: [header, main, footer]
# All 49 mandatory-tier builtin overrides (OVERRIDE-CONTRACT §1), dashed keys.
template_overrides:
# Chrome (4)
- { template: cyberpunk, block: navbar }
- { template: cyberpunk, block: footer }
- { template: cyberpunk, block: utility-bar }
- { template: cyberpunk, block: announcement-bar }
# Marketing (12)
- { template: cyberpunk, block: hero }
- { template: cyberpunk, block: feature-grid }
- { template: cyberpunk, block: rich-section }
- { template: cyberpunk, block: stats }
- { template: cyberpunk, block: testimonial }
- { template: cyberpunk, block: logo-strip }
- { template: cyberpunk, block: pricing }
- { template: cyberpunk, block: team }
- { template: cyberpunk, block: faq }
- { template: cyberpunk, block: timeline }
- { template: cyberpunk, block: cta }
- { template: cyberpunk, block: countdown }
# Primitives (11)
- { template: cyberpunk, block: heading }
- { template: cyberpunk, block: text }
- { template: cyberpunk, block: rich-text }
- { template: cyberpunk, block: image }
- { template: cyberpunk, block: quote }
- { template: cyberpunk, block: divider }
- { template: cyberpunk, block: button }
- { template: cyberpunk, block: card }
- { template: cyberpunk, block: gallery }
- { template: cyberpunk, block: video-embed }
- { template: cyberpunk, block: audio-embed }
# Commerce / local (6)
- { template: cyberpunk, block: menu-list }
- { template: cyberpunk, block: event-list }
- { template: cyberpunk, block: contact-form }
- { template: cyberpunk, block: contact-card }
- { template: cyberpunk, block: hours-location }
- { template: cyberpunk, block: social-links }
# Blog family (12)
- { template: cyberpunk, block: blog-hero }
- { template: cyberpunk, block: featured-posts }
- { template: cyberpunk, block: related-posts }
- { template: cyberpunk, block: popular-posts }
- { template: cyberpunk, block: category-list }
- { template: cyberpunk, block: post-hero }
- { template: cyberpunk, block: post-metadata }
- { template: cyberpunk, block: author-bio }
- { template: cyberpunk, block: author-bio-hero }
- { template: cyberpunk, block: newsletter-signup }
- { template: cyberpunk, block: breadcrumbs }
- { template: cyberpunk, block: sidebar-nav }
# Auth surface (3)
- { template: cyberpunk, block: auth-form }
- { template: cyberpunk, block: password-reset-form }
- { template: cyberpunk, block: auth-status }
# System (1)
- { template: cyberpunk, block: page-suggestions }
email_wrappers:
- cyberpunk
css:
input_css_append: |
/* ============================================================
Cyberpunk — Neon-on-black game-studio / hacker-collective theme
(WO-TF-015). Scanlines / glitch / RGB-split / caret-blink /
neon-edge / HUD-bracket / clip-cut / digital-rain utilities.
All colours consume the host shadcn HSL tokens via hsl(var(--token)).
No hardcoded hex / rgb / named colours.
============================================================ */
/* --- Typography ------------------------------------------- */
/* Families flow through the admin-bound CSS variables; the fallback
leads with the bundled OFL family so the intended look survives
before the admin assigns a slot. @font-face for the bundled
families is auto-emitted from fonts.json (source=template rows). */
.cyberpunk-body {
font-family: var(--font-body, "Inter", system-ui, -apple-system, "Segoe UI", sans-serif);
}
.cyberpunk-mono,
.cyberpunk-mono code,
pre.cyberpunk-mono,
code.cyberpunk-mono {
font-family: var(--font-mono, "Share Tech Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, monospace);
}
.cyberpunk-display {
font-family: var(--font-heading, "Orbitron", system-ui, -apple-system, "Segoe UI", sans-serif);
letter-spacing: 0.01em;
}
.cyberpunk-prose,
.cyberpunk-prose p,
.cyberpunk-prose li {
font-family: var(--font-body, "Inter", system-ui, sans-serif);
line-height: 1.75;
}
/* Eyebrow / kicker: mono, uppercase, wide-tracked accent readout. Carries
enough on its own that it is never a silent no-op when used alone. */
.cyberpunk-eyebrow {
font-family: var(--font-mono, "Share Tech Mono", ui-monospace, monospace);
text-transform: uppercase;
letter-spacing: 0.2em;
font-size: 0.75rem;
color: hsl(var(--accent));
}
.cyberpunk-prose code {
color: hsl(var(--accent));
background-color: hsl(var(--muted));
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
font-family: var(--font-mono, "Share Tech Mono", ui-monospace, monospace);
font-size: 0.875em;
}
/* --- Scanlines -------------------------------------------- */
.scanlines {
opacity: 0.05;
background-image: linear-gradient(
to bottom,
hsl(var(--foreground)) 0px,
hsl(var(--foreground)) 1px,
transparent 1px,
transparent 3px
);
background-size: 100% 3px;
animation: scanline-drift 6s linear infinite;
}
@keyframes scanline-drift {
0% { background-position: 0 0; }
100% { background-position: 0 3px; }
}
/* --- Glitch (RGB-split text-shadow) on big headings ------- */
.glitch {
position: relative;
text-shadow:
-2px 0 hsl(var(--primary)),
2px 0 hsl(var(--accent));
animation: glitch-x 3.6s steps(1, end) infinite;
}
@keyframes glitch-x {
0%, 92%, 100% {
text-shadow: -2px 0 hsl(var(--primary)), 2px 0 hsl(var(--accent));
}
93% {
text-shadow: -3px 0 hsl(var(--primary)), 3px 0 hsl(var(--accent)), 0 1px hsl(var(--accent));
}
95% {
text-shadow: -1px 0 hsl(var(--accent)), 4px 0 hsl(var(--primary));
}
97% {
text-shadow: -2px 0 hsl(var(--primary)), 2px 0 hsl(var(--accent));
}
}
/* --- RGB-split hover/focus/active on primary buttons ------ */
.rgb-split {
transition: transform 120ms ease, box-shadow 120ms ease;
}
.rgb-split:hover,
.rgb-split:focus-visible {
box-shadow: -2px 0 0 hsl(var(--primary)), 2px 0 0 hsl(var(--accent));
transform: translateY(-1px);
}
.cyberpunk-btn:active,
.rgb-split:active,
button.cyberpunk-btn:active {
box-shadow: -2px 0 0 hsl(var(--primary)), 2px 0 0 hsl(var(--accent));
}
.cyberpunk-btn:focus-visible,
.cyberpunk-btn-ghost:focus-visible,
button:focus-visible,
a:focus-visible {
outline: 2px solid hsl(var(--ring));
outline-offset: 2px;
}
/* --- Caret blink ------------------------------------------ */
.caret-blink {
display: inline-block;
animation: caret 1.05s steps(2, end) infinite;
}
@keyframes caret {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
/* --- Neon edge utilities (magenta / cyan / lime channels) - */
/* --primary is the lead accent, --accent the secondary, --ring
the third neon channel (present in every preset). */
.neon-edge-magenta {
box-shadow: 0 0 0 1px hsl(var(--primary) / 0.4), 0 0 18px hsl(var(--primary) / 0.22);
transition: box-shadow 180ms ease, transform 180ms ease;
}
.neon-edge-magenta:hover,
.neon-edge-magenta:focus-within {
box-shadow: 0 0 0 1px hsl(var(--primary) / 0.85), 0 0 28px hsl(var(--primary) / 0.42);
transform: translateY(-1px);
}
.neon-edge-cyan {
box-shadow: 0 0 0 1px hsl(var(--accent) / 0.4), 0 0 18px hsl(var(--accent) / 0.22);
transition: box-shadow 180ms ease, transform 180ms ease;
}
.neon-edge-cyan:hover,
.neon-edge-cyan:focus-within {
box-shadow: 0 0 0 1px hsl(var(--accent) / 0.85), 0 0 28px hsl(var(--accent) / 0.42);
transform: translateY(-1px);
}
.neon-edge-lime {
box-shadow: 0 0 0 1px hsl(var(--ring) / 0.4), 0 0 18px hsl(var(--ring) / 0.22);
transition: box-shadow 180ms ease, transform 180ms ease;
}
.neon-edge-lime:hover,
.neon-edge-lime:focus-within {
box-shadow: 0 0 0 1px hsl(var(--ring) / 0.85), 0 0 28px hsl(var(--ring) / 0.42);
transform: translateY(-1px);
}
/* --- HUD corner brackets ---------------------------------- */
/* Draw two L-brackets (top-left, bottom-right) around any panel. */
.hud-frame {
position: relative;
}
.hud-frame::before,
.hud-frame::after {
content: "";
position: absolute;
width: 14px;
height: 14px;
pointer-events: none;
z-index: 1;
}
/* Inset 5px so the L-brackets clear any rounded / overflow-hidden panel
corner (e.g. the code_neon figure) instead of being sliced by it. */
.hud-frame::before {
top: 5px;
left: 5px;
border-top: 2px solid hsl(var(--primary));
border-left: 2px solid hsl(var(--primary));
}
.hud-frame::after {
bottom: 5px;
right: 5px;
border-bottom: 2px solid hsl(var(--accent));
border-right: 2px solid hsl(var(--accent));
}
/* --- Angled clip-path cut (arcade panel silhouette) ------- */
.clip-cut {
clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 10px, 100% 100%, 10px 100%, 0 calc(100% - 10px));
}
/* --- Status pill / dot pulse ------------------------------ */
.cyberpunk-status-dot {
animation: cyberpunk-pulse 2.2s ease-in-out infinite;
}
@keyframes cyberpunk-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
/* --- Digital-rain canvas showpiece (hero override only) --- */
/* The <canvas> lazy-inits from the hero's inline script. This block
styles the container + the static no-JS neon fallback layer. */
.cyberpunk-rain-wrap {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
}
.cyberpunk-rain-canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
display: block;
opacity: 0.5;
}
/* Static fallback: a neon vertical-gradient wash shown until (or instead
of) the canvas. Tokens only. */
.cyberpunk-rain-fallback {
position: absolute;
inset: 0;
background:
radial-gradient(120% 80% at 50% 0%, hsl(var(--primary) / 0.18), transparent 60%),
radial-gradient(120% 80% at 100% 100%, hsl(var(--accent) / 0.16), transparent 55%),
linear-gradient(to bottom, transparent, hsl(var(--background) / 0.6));
}
/* --- Hero heights (bespoke bounded clamp — anti-balloon) -------------- */
/* Responsive grids/columns/spans/splits are plain Tailwind utilities in the
templates (grid-cols-*, columns-*, col-span-*, gap-*) — the host build
scans theme .ninjatpl, so no CSS reimplementation of those.
These hero min-heights stay CSS: a bespoke clamp() that caps a sparse
hero so it never balloons into an empty neon void while a populated hero
still reads full-bleed — not a stock min-h-* utility. */
.cp-hero-tall { min-height: clamp(32rem, 82vh, 50rem); }
.cp-hero-mid { min-height: clamp(28rem, 70vh, 44rem); }
.cp-hero-short { min-height: clamp(20rem, 50vh, 30rem); }
.cp-hero-auto { min-height: 22rem; }
.cp-hero-split { min-height: clamp(20rem, 46vh, 28rem); }
/* --- Reduced motion: kill all motion --------------------- */
@media (prefers-reduced-motion: reduce) {
.glitch,
.caret-blink,
.scanlines,
.cyberpunk-status-dot,
.cyberpunk-rain-canvas {
animation: none !important;
animation-duration: 0.01ms !important;
}
.glitch { text-shadow: none; }
.scanlines { opacity: 0; }
.cyberpunk-rain-canvas { display: none; }
.rgb-split:hover,
.rgb-split:focus-visible { transform: none; }
}
/* --- High-contrast: kill scanlines + rain ---------------- */
@media (prefers-contrast: more) {
.scanlines,
.cyberpunk-rain-canvas { display: none; }
}