WO-TF-015 (game-studio / hacker-collective persona, GO-BIG motion). - Overrides: all 49 mandatory builtin keys in templates/overrides/cyberpunk/ (dashed keys), each restyled to neon-HUD chrome preserving builtin field reads + scripts. Legacy button/card/heading/text reconciled to new field names (label/link/style, text/media). Auth surface (auth-form, auth-status, password-reset-form) reproduces the builtin hardcoded HTMX endpoints + Cap widget verbatim. page-suggestions ships themed 404 chrome. - Page templates: 7 (default, full-width, landing, article, blog-index, contact, auth), dual-mode via theme_mode, scanline overlay chrome. - Hero override: dependency-free canvas digital-rain showpiece — lazy-init via IntersectionObserver, prefers-reduced-motion honored, static neon gradient no-JS fallback, token-derived colors only. - Blocks: deleted 6 builtin-duplicating theme blocks (now overrides); kept code_neon (+ copy handler); added persona blocks glitch_hero, roster_grid, patch_notes with schemas + sample data. - Presets: 5 (neon-noir, acid-rain, toxic-bloom, hotline, ghost-protocol), all 19 tokens, light+dark both tuned. - Fonts: bundled OFL woff2 (Orbitron, Share Tech Mono, Inter latin subsets) in assets/fonts + fonts.json + LICENSES; all font-family via CSS vars. - Email: preset-aware email-safe wrapper (tables, inline styles, colors.*). - Master pages + demo seed (home, about, blog+3 posts, contact with data-table + row_inserted email-admins workflow, login). - manifest CSS: hud-frame, clip-cut, cyberpunk-eyebrow, canvas-rain utils. - plugin.mod + manifest required_icon_packs = [lucide, simple-icons]. make build + verify exit 0; check-safety exit 0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
220 lines
11 KiB
JSON
220 lines
11 KiB
JSON
{
|
|
"demo": true,
|
|
"settings": {
|
|
"merge": {
|
|
"companyName": "Neon Forge",
|
|
"tagline": "We build games and the tools that ship them."
|
|
}
|
|
},
|
|
"data_tables": [
|
|
{
|
|
"key": "contact_submissions",
|
|
"name": "Contact Enquiries",
|
|
"description": "Seeded contact-form submissions for the Neon Forge demo. A submission becomes a row here and emails the site admins.",
|
|
"columns": [
|
|
{ "key": "name", "label": "Name", "type": "text", "required": true },
|
|
{ "key": "email", "label": "Email", "type": "email", "required": true },
|
|
{ "key": "studio", "label": "Studio", "type": "text", "required": false },
|
|
{ "key": "message", "label": "Message", "type": "text", "required": true }
|
|
]
|
|
}
|
|
],
|
|
"pages": [
|
|
{
|
|
"slug": "/",
|
|
"title": "Neon Forge",
|
|
"template_key": "landing",
|
|
"blocks": [
|
|
{
|
|
"block_key": "hero",
|
|
"title": "Hero",
|
|
"slot": "main",
|
|
"sort_order": 1,
|
|
"content": {
|
|
"template": "centered",
|
|
"minHeight": "screen",
|
|
"eyebrow": "Build 2.049",
|
|
"headline": "Ship the impossible",
|
|
"subheadline": "A game studio and the tools that ship it.",
|
|
"description": "We build a rendering engine, live ops, and a build farm that never sleeps. Then we make games on top of it.",
|
|
"ctaPrimary": { "text": "Get the SDK", "url": "/contact" },
|
|
"ctaSecondary": { "text": "Read the devlog", "url": "/blog" }
|
|
}
|
|
},
|
|
{
|
|
"block_key": "feature-grid",
|
|
"title": "What we ship",
|
|
"slot": "main",
|
|
"sort_order": 2,
|
|
"content": {
|
|
"eyebrow": "The stack",
|
|
"heading": "One pipeline, end to end",
|
|
"intro": "Engine, tooling, and live service. Built in house, shipped together.",
|
|
"layout": "card",
|
|
"columns": 3,
|
|
"items": [
|
|
{ "icon": "lucide:cpu", "title": "Render engine", "text": "Neon lighting, volumetric fog, and a deferred path tuned for night maps." },
|
|
{ "icon": "lucide:terminal", "title": "Build farm", "text": "Shader caching across branches. Green builds in minutes, not hours." },
|
|
{ "icon": "lucide:radio", "title": "Live ops", "text": "Ship events, patch balance, and roll back without a redeploy." }
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"block_key": "cyberpunk:roster_grid",
|
|
"title": "The crew",
|
|
"slot": "main",
|
|
"sort_order": 3,
|
|
"content": {
|
|
"eyebrow": "The crew",
|
|
"heading": "Who ships this",
|
|
"intro": "A small team that builds the engine, the game, and the pipeline in between.",
|
|
"members": [
|
|
{ "name": "Nova Reyes", "handle": "@nova", "role": "Engine lead", "status": true },
|
|
{ "name": "Kai Okafor", "handle": "@kaisdf", "role": "Graphics", "status": true },
|
|
{ "name": "Sable Lin", "handle": "@sable", "role": "Live ops", "status": false },
|
|
{ "name": "Juno Vale", "handle": "@juno", "role": "Gameplay", "status": true },
|
|
{ "name": "Rin Castellano", "handle": "@rin", "role": "Tools", "status": true },
|
|
{ "name": "Ash Mori", "handle": "@ash", "role": "Netcode", "status": false }
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"block_key": "cyberpunk:patch_notes",
|
|
"title": "Patch notes",
|
|
"slot": "main",
|
|
"sort_order": 4,
|
|
"content": {
|
|
"heading": "Patch notes",
|
|
"intro": "What changed, build by build.",
|
|
"entries": [
|
|
{ "version": "v2.049.0", "date": "2049.04.01", "tag": "FEATURE", "items": [ { "text": "Volumetric neon fog on all night maps." }, { "text": "Build farm caches shaders across branches." } ] },
|
|
{ "version": "v2.048.3", "date": "2049.03.18", "tag": "FIX", "items": [ { "text": "Fixed a stall when hot-reloading materials." }, { "text": "Reduced desync on high-latency links." } ] },
|
|
{ "version": "v2.048.0", "date": "2049.03.02", "tag": "BALANCE", "items": [ { "text": "Tuned dash cooldown from 4s to 3.2s." } ] }
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"block_key": "cta",
|
|
"title": "CTA",
|
|
"slot": "main",
|
|
"sort_order": 5,
|
|
"content": {
|
|
"background": "band",
|
|
"heading": "Start building tonight",
|
|
"text": "Grab the SDK and ship your first build before the coffee runs out.",
|
|
"primaryLabel": "Get the SDK",
|
|
"primaryUrl": "/contact"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"slug": "/about",
|
|
"title": "The studio",
|
|
"template_key": "default",
|
|
"blocks": [
|
|
{ "block_key": "heading", "title": "Heading", "slot": "main", "sort_order": 1, "content": { "text": "The studio", "level": 1 } },
|
|
{ "block_key": "rich-text", "title": "Story", "slot": "main", "sort_order": 2, "content": { "html": "<p>Neon Forge started as a build tool for a game that shipped late. The tool outlived the game. We kept building it, then built more games to prove it out.</p><p>Now we run both. The engine and live service on one side, the games that stress test them on the other. Everything we make, we run in production first.</p>" } },
|
|
{ "block_key": "cyberpunk:code_neon", "title": "Quickstart", "slot": "main", "sort_order": 3, "content": { "language": "bash", "code": "npm install @neon-forge/sdk\nnpx neon-forge init my-game\nnpx neon-forge ship --stage prod", "copy": "on" } },
|
|
{ "block_key": "divider", "title": "Divider", "slot": "main", "sort_order": 4, "content": { "variant": "line", "weight": "medium" } },
|
|
{ "block_key": "quote", "title": "Quote", "slot": "main", "sort_order": 5, "content": { "style": "pull", "quote": "Build the tool. Ship the game. Repeat.", "attribution": "The studio" } }
|
|
]
|
|
},
|
|
{
|
|
"slug": "/blog",
|
|
"title": "Devlog",
|
|
"template_key": "blog-index",
|
|
"blocks": [
|
|
{ "block_key": "card", "title": "Post: Rain", "slot": "main", "sort_order": 1, "content": { "layout": "vertical", "title": "Making it rain", "text": "<p>How we built a dependency-free digital-rain effect that stays smooth at 60 fps.</p>", "link": "/blog/making-it-rain", "linkLabel": "Read on" } },
|
|
{ "block_key": "card", "title": "Post: Shaders", "slot": "main", "sort_order": 2, "content": { "layout": "vertical", "title": "Caching shaders across branches", "text": "<p>Green builds in minutes. What we changed in the build farm and why.</p>", "link": "/blog/caching-shaders", "linkLabel": "Read on" } },
|
|
{ "block_key": "card", "title": "Post: Netcode", "slot": "main", "sort_order": 3, "content": { "layout": "vertical", "title": "Netcode on bad links", "text": "<p>Cutting desync on 200ms connections without rewriting the sim.</p>", "link": "/blog/netcode-bad-links", "linkLabel": "Read on" } }
|
|
]
|
|
},
|
|
{
|
|
"slug": "/blog/making-it-rain",
|
|
"title": "Making it rain",
|
|
"template_key": "article",
|
|
"parent_slug": "/blog",
|
|
"blocks": [
|
|
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Making it rain", "level": 1 } },
|
|
{ "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "<p>The hero on our home page runs a digital-rain canvas. No libraries, no images, just a small script that draws falling glyphs.</p><p>The trick is to fade the last frame instead of clearing it. That leaves a trail. Cap the frame rate and it stays cheap, even on a laptop.</p>" } }
|
|
]
|
|
},
|
|
{
|
|
"slug": "/blog/caching-shaders",
|
|
"title": "Caching shaders across branches",
|
|
"template_key": "article",
|
|
"parent_slug": "/blog",
|
|
"blocks": [
|
|
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Caching shaders across branches", "level": 1 } },
|
|
{ "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "<p>Every branch used to recompile the whole shader set. That is minutes per build, times every push.</p><p>We keyed the cache on the shader source, not the branch. Two branches that share a shader now share the compile. Builds got short again.</p>" } }
|
|
]
|
|
},
|
|
{
|
|
"slug": "/blog/netcode-bad-links",
|
|
"title": "Netcode on bad links",
|
|
"template_key": "article",
|
|
"parent_slug": "/blog",
|
|
"blocks": [
|
|
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Netcode on bad links", "level": 1 } },
|
|
{ "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 2, "content": { "html": "<p>Players on slow connections kept desyncing. Rewriting the simulation was off the table.</p><p>We added client prediction with a short rollback window. The client guesses, the server corrects, and the gap closes before anyone notices.</p>" } }
|
|
]
|
|
},
|
|
{
|
|
"slug": "/contact",
|
|
"title": "Contact",
|
|
"template_key": "contact",
|
|
"blocks": [
|
|
{
|
|
"block_key": "contact-form",
|
|
"title": "Contact form",
|
|
"slot": "main",
|
|
"sort_order": 1,
|
|
"content": {
|
|
"heading": "Request access",
|
|
"description": "Tell us what you are building. We reply within one business day.",
|
|
"submitLabel": "Request access",
|
|
"successMessage": "Message received. We will reply within one business day.",
|
|
"fields": [
|
|
{ "name": "name", "label": "Your name", "type": "text", "required": true, "width": "half" },
|
|
{ "name": "email", "label": "Email", "type": "email", "required": true, "width": "half" },
|
|
{ "name": "studio", "label": "Studio", "type": "text", "required": false, "width": "full" },
|
|
{ "name": "message", "label": "What are you building", "type": "textarea", "required": true, "width": "full" }
|
|
],
|
|
"formConfig": { "enabled": true, "captchaEnabled": false, "targetTable": "contact_submissions" }
|
|
}
|
|
},
|
|
{
|
|
"block_key": "contact-card",
|
|
"title": "Reach us",
|
|
"slot": "main",
|
|
"sort_order": 2,
|
|
"content": {
|
|
"heading": "Other ways in",
|
|
"columns": 3,
|
|
"channels": [
|
|
{ "icon": "lucide:mail", "label": "Email", "value": "crew@neonforge.dev", "link": "mailto:crew@neonforge.dev" },
|
|
{ "icon": "simple-icons:github", "label": "Source", "value": "github.com/neon-forge", "link": "https://github.com/neon-forge" },
|
|
{ "icon": "lucide:message-square", "label": "Discord", "value": "Join the build channel", "link": "#" }
|
|
]
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"slug": "/login",
|
|
"title": "Sign in",
|
|
"template_key": "auth",
|
|
"blocks": [
|
|
{ "block_key": "auth-form", "title": "Sign in", "slot": "main", "sort_order": 1, "content": { "default_tab": "login", "show_social": false } }
|
|
]
|
|
}
|
|
],
|
|
"menu_items": [
|
|
{ "menu": "main", "label": "Home", "page_slug": "/", "sort_order": 1 },
|
|
{ "menu": "main", "label": "Studio", "page_slug": "/about", "sort_order": 2 },
|
|
{ "menu": "main", "label": "Devlog", "page_slug": "/blog", "sort_order": 3 },
|
|
{ "menu": "main", "label": "Contact", "page_slug": "/contact", "sort_order": 4 }
|
|
]
|
|
}
|