blueprintWeb.md

The web blueprint for markdowngames.com, Unity embed, and related UX.

Docs/blueprintWeb.md
Project: markdowngames.com Website

1. Project Thesis
This is the official landing page for the "Markdown Games" studio. The brand’s philosophy remains “Human‑Architected Games.” The current hero now highlights Griddie Golf as the flagship example of Markdown‑first, agent‑enabled development:

> ### Headline: From Spec to Play, Faster.
> ### Subheadline: Meet Griddie Golf: a 2D golf roguelite scripted end‑to‑end with Cursor agents, from Markdown specs to shipping builds.

> ### **AI for Process, Not for Product.**

Core Communication Goal: We must clearly distinguish our process from "AI slop."

- Product (Art): 100% human-crafted. We hire human artists.
- Process (Code): Human-architected and AI-assisted. We use Spec-Driven Development (SDD), where a senior developer designs the blueprints (in markdown) and audits all AI-generated code. Griddie Golf’s codebase is iterated from `Docs/blueprintGame.md` using Cursor agents.

---

2. Current Implementation Status
- Landing hero implemented with IDE-inspired dark theme and gradient CTA.
  - Headline: “From Spec to Play, Faster.”
  - Subheadline: “Meet Griddie Golf: a 2D golf roguelite scripted end‑to‑end with Cursor agents, from Markdown specs to shipping builds.”
  - Primary CTA uses cyan→lime gradient; size/hover affordance slightly increased for a better tap target.
- Metadata set in `app/layout.tsx`:
  - `title`: “Markdown Games”
  - `description`: “From Spec to Play, Faster”
  - Note: `/mdmcp-unity` defines its own `metadata` (route-specific title/description).
- Brand palette in `app/globals.css` using CSS variables:
  - `--bg` #0b0f14, `--panel` #0f172a, `--text` #e6e6e6, `--muted` #94a3b8
  - Accents: `--accent-a` #22d3ee (cyan), `--accent-b` #a3e635 (lime)
- Simple SVG wordmark `public/logo.svg` (games.md badge, cyan→lime gradient).
- `/play` page embeds a Unity Stable (WebGL2) build via `react-unity-webgl`.
- Unity canvas sized to tall‑mobile (iPhone 12 Pro Max) aspect:
  - Aspect: 9 / 19.5
  - Wrapper height: 100svh (no scroll)
  - Width: min(100vw, calc(100svh * 9 / 19.5), 720px)
- Fullscreen controls: removed for now to preserve the designed aspect ratio.
- “How to play” modal: bottom‑left button opens an IDE‑styled `rules.md` overlay using the descriptive rules (`app/components/how-to-play.tsx`). Visible only on the Main Menu and auto‑hides on gameplay scenes.
- Quick Start hint: an inline, dismissible overlay (`app/components/quickstart-hint.tsx`) appears on the Main Menu above the canvas. It summarizes core play in 6 bullets (leaderboard qualification, distance = die ± terrain, tap→drag→release, and nested club rules including Tap‑In under Putter). Dismissal persists via `localStorage` key `gg.quickstart.dismissed`.
- Landing README panel: below the hero, an IDE‑styled `README.md` panel summarizes the thesis:
  - Headline line: **AI for Process, Not for Product.**
  - “Process is Collaboration” paragraph comes first and explains Spec‑Driven Development (SDD).
  - “Product is Human” follows and states that all art and game design are human‑crafted (no mention of music).
  - A Griddie Golf paragraph explains that the Unity 2D golf game’s codebase is iterated from Markdown specs using Cursor agents and that the agent‑enabled workflow is documented in public.
- Landing Open Source panel: an IDE‑styled “Open Source — MDMCP Server (Unity)” panel appears below the README, with CTAs for Get Started (`/mdmcp-unity`) and GitHub.
- Landing modal toggle: a button opens an IDE‑styled modal that switches between:
  - `Contact.md` — Discord “pogchampion” and email `connor@markdowngames.com`
  - `README.md` — mirrors the README panel copy (AI for Process, Process is Collaboration, Product is Human, Griddie Golf paragraph).
- Markdown Docs panel: a `Markdown Docs` IDE panel surfaces links to `/docs/blueprint-game`, `/docs/blueprint-web`, `/docs/changelog`, and the three Cursor command docs (`/docs/new-chat`, `/docs/update-blueprint`, `/docs/git-push`).
- Philosophy section removed from landing; the secondary “Our Philosophy” CTA remains hidden.
- Global footer: `SiteFooter` shows email and X/Twitter links, plus copyright.
  - Email: `connor@markdowngames.com`
  - X/Twitter: `https://x.com/connorleisz`
- Auth (Web, Google):
  - GIS popup button rendered on `/play` (bottom‑right). Unity requests sign‑in via a JS bridge.
  - After Google credential is received, the token is forwarded into Unity and linkage/sign‑in proceeds with UGS.
  - Sign‑out shows a brief toast and re‑renders the Google button without page refresh.
  - “Sticky” linkage: once linked, the host treats the user as linked across scenes and reloads until an explicit sign‑out.
  - Button visibility and rendering are gated to the Main Menu and now wait for a confirmed scene from Unity (`GG_OnSceneChanged` → `sceneKnown=true`). The initial Google button render is also gated by `onMainMenu` to avoid prompting during game load.

---

3. Technical Stack
- Framework: Next.js 16 (App Router)
- Language: TypeScript
- Styling: Tailwind CSS v4, dark theme tuned to feel like an IDE/cursor markdown view
- Fonts: Geist Sans + Geist Mono (Next Font)
- Icons: `lucide-react` for overlay controls and UI glyphs
- Analytics: Vercel Web Analytics (`@vercel/analytics`), mounted in `app/layout.tsx`

Directory highlights:
- `app/page.tsx` — landing hero (CTA to `/play`), mounts `HeroReadme`
- `app/components/unity-canvas.tsx` — client component that embeds Unity
- `app/components/quickstart-hint.tsx` — dismissible Quick Start overlay (Main Menu only; persists dismissal in `localStorage`)
- `app/components/hero-readme.tsx` — landing README panel and Contact/README modal toggle
- `app/docs/page.tsx` — docs index listing blueprints, changelog, and Cursor command docs
- `app/docs/*/page.tsx` — IDE‑styled views that render markdown from `Docs/` and `.cursor/commands`
- `app/components/site-footer.tsx` — global footer (email, X/Twitter, ©)
- `app/layout.tsx` — wraps pages, mounts `SiteFooter`, and renders `<Analytics />` from `@vercel/analytics/next`
- `app/mdmcp-unity/page.tsx` — MDMCP Server (Unity) docs page (Getting Started)
- `app/components/hover-video.tsx` — hover/tap overlay controls for videos (Play/Pause, Fullscreen)
- `app/components/ide-panel.tsx` — reusable IDE‑styled panel (header + mono content)
- `app/components/ide-modal.tsx` — reusable IDE‑styled modal (title + Esc/backdrop close)
- `app/play/page.tsx` — renders `UnityCanvas`, gates the Google button and “How to play” modal to the Main Menu, and mounts `QuickStartHint`
- `app/icon.svg` — favicon (SVG)
- `app/apple-icon.tsx` — Apple touch icon (generated PNG via Next/og)
- `app/globals.css` — theme variables and Tailwind v4 `@theme inline` mapping
- `next.config.ts` — headers for Unity Brotli assets; `no-store` for `Stable/index.html`
- `app/api/unity/stable-manifest/route.ts` — manifest discovery (dev: filesystem, prod: parses `Stable/index.html`)
- `public/builds/griddie/Stable/` — Stable WebGL2 build (hashed filenames)
- `public/builds/griddie/WebGPU/` — Experimental WebGPU build (optional)
 - `public/videos/` — site video assets (prefer `.webm` with `.mp4` fallback)

---

4. Coding Conventions
- All components are React functional components.
- Prefer inline Tailwind utility classes; use `@apply` only for repeated patterns.
- File names: `kebab-case.tsx?`.
- New pages live under `app/<route>/page.tsx`.
- Client components must start with `'use client'`.
 - Server Components cannot receive interactive event handlers (e.g. `onContextMenu`); wrap such needs in a small Client Component.

---

5. Theming and Layout
- Global CSS variables (editable in `app/globals.css`):
  - `--bg`, `--panel`, `--text`, `--muted`, `--accent-a`, `--accent-b`
- Tailwind v4 theme bridge:
  ```
  @theme inline {
    --color-background: var(--bg);
    --color-foreground: var(--text);
    --font-sans: var(--font-geist-sans);
    --font-mono: var(--font-geist-mono);
  }
  ```
- Hero CTA gradient uses `--accent-a` → `--accent-b`.
- SVG logo lives at `/public/logo.svg` and renders in the hero.
- Icons & Favicons:
  - Favicon: `app/icon.svg` (served automatically by Next.js App Router).
  - Apple touch icon: `app/apple-icon.tsx` generates a 180×180 PNG via `next/og` (`ImageResponse`).
  - Optional alternates: `public/md-favicon-solid.svg`, `public/md-favicon-outline.svg`.
  - Palette: cyan → lime gradient using hex `#22d3ee` → `#a3e635` (same as `public/logo.svg`).
- Analytics:
  - Import `{ Analytics }` from `@vercel/analytics/next` and render `<Analytics />` at the end of `<body>` in `app/layout.tsx`.
  - No configuration required for basic pageview analytics on Vercel deployments.

---

6. Unity Web Build Integration (Stable WebGL2)
Folder layout under `public` (keep names as exported by Unity):
- `public/builds/griddie/Stable/Build/`
- `public/builds/griddie/Stable/StreamingAssets/`
- `public/builds/griddie/Stable/index.html` (useful for direct testing)

Embedding:
- `app/components/unity-canvas.tsx` is a client component that embeds Unity via `react-unity-webgl`.
- The four core filenames (loader/data/framework/wasm) are auto‑discovered at runtime by `GET /api/unity/stable-manifest`:
  - In local/dev it scans `Stable/Build` on the filesystem
  - In serverless/prod it fetches and parses `Stable/index.html` over HTTP
  - It returns:
  - `base`, `streamingAssets`, `loader`, `data`, `framework`, `code`, and a `version` (mtime‑based) used as a query cache‑buster on the four core files.
- Important: do not append a query parameter to `streamingAssetsUrl` (Unity concatenates file names onto this base).
- The manifest supports compressed (`.br`/`.unityweb`) and uncompressed builds.

Canvas sizing (portrait, tall phones):
- Outer: `h-[100svh]` on the page (no scroll)
- Inner wrapper: `aspectRatio: '9 / 19.5'`, width clamp `min(100vw, calc(100svh * 9 / 19.5), 720px)`

Headers (Brotli):
`next.config.ts` adds:
  - `Stable/index.html`: `Cache-Control: no-store`
  - Hashed assets: `Content-Encoding: br` (for `.br`/`.unityweb`) and `Cache-Control: public, max-age=31536000, immutable`
  - Also caches `*.loader.js`

LFS & Vercel deploy:
- Large Unity outputs are tracked with Git LFS via `.gitattributes`:
  - `public/builds/**/Build/*.data(.br|.unityweb)`, `*.wasm(.br|.unityweb)`, `*.loader.js`, `*.framework.js`
- Only the latest Stable build is kept (remove older hashed files before committing).
- In Vercel, enable Project Settings → Git → Git LFS so real files (not pointers) are available at build time.
- Build command: `npm run vercel-build` (fetches LFS objects, then `next build`).

7. Web Auth (Google) — Host Bridge + Unity
- Env:
  - `NEXT_PUBLIC_GOOGLE_CLIENT_ID` must be set (local: `.env.local`; prod: Vercel env).
  - Add your exact origins (localhost:3000, apex + www domain, vercel domain) in Google Cloud Console → OAuth client (Web application) → Authorized JavaScript origins.
- Host (`app/play/page.tsx`):
  - Loads GIS script and renders the official “Sign in with Google” button using the popup flow.
  - Exposes JS hooks Unity calls:
    - `GG_RequestGoogleSignIn()` → renders/starts GIS popup.
    - `GG_OnIsGoogleLinked(true/false)` → drives button visibility and “Sign out” UI.
    - `GG_OnSceneChanged(sceneName)` → sets `sceneKnown` and the current scene. UI is gated to the Main Menu only (scene name contains “mainmenu”, case‑insensitive).
    - `GG_OnAuthStateChanged(true/false)` → reflects UGS session; not used to decide Google button visibility.
    - `GG_RequestSignOut()` → host→Unity request (Unity signs out, then notifies host).
  - Sign‑out UX: brief toast (“Signed out”), button re‑rendered proactively on next tick.
  - Sticky linkage:
    - Once linked, host keeps `effectiveLinked=true` across scenes and reloads until an explicit sign‑out.
    - Persisted in `localStorage` (`ggEverLinked=1`) to avoid flicker after reload. Cleared on sign‑out.
  - Button rendering is gated by `onMainMenu`, which now requires `sceneKnown=true` and the scene name to contain “mainmenu”. This prevents the Google prompt from showing before the Unity game reaches the Main Menu.
  - Debug overlay: add `?ui-debug=1` to `/play` to see current scene/auth/link states and recent hook events.
- “How to play” rules: Bottom‑left button opens a markdown‑tab‑styled modal (`rules.md`) with descriptive rules (`app/components/how-to-play.tsx`). Visibility is gated by `onMainMenu`. The modal auto‑closes on scene change away from the Main Menu.
- Quick Start hint: The condensed quick‑start appears as an inline overlay (`app/components/quickstart-hint.tsx`) on the Main Menu. It stores dismissal in `localStorage` as `gg.quickstart.dismissed`. A compact quick modal variant exists at `app/components/how-to-play-quick.tsx` (not wired by default).
- Unity:
  - After init/sign‑in, call `GG_OnAuthStateChanged(signedIn)` and call `GG_OnIsGoogleLinked(true/false)` only when the provider check succeeds.
  - On transient provider‑check errors, do not emit `false` (host keeps sticky true). Emit `false` only on explicit sign‑out.
  - On scene transitions, call `GG_OnSceneChanged("MainMenuScene" | "GameScene" | ...)`.

---

7. MDMCP Server (Unity) — Open Source
- Overview: HTTP‑based automation bridge for the Unity Editor; actions invoked via JSON.
- Landing: featured panel under README with CTAs (Get Started → `/mdmcp-unity`, GitHub).
- Docs: `/mdmcp-unity` includes Install (UPM Git URL), Start the Server, Quickstart (curl), and Extend (IEditorAction).
- Prompting in Cursor:
  - Always attach `@Packages/com.clokk.mdmcp-unity/Documentation/MDMCPServer.md` (or local `@MDMCPServer.md`) to give the agent context.
  - Describe goals in natural language (e.g., “Enter play mode, wait 2s, click /Canvas/MainMenu/PlayButton, then run getContext.”).
  - Ensure the Unity Editor is open, compiled (no pending scripts), and focused before running MCP commands.
- Repo: `https://github.com/clokk/mdmcp-unity`
 - Demo video:
   - Embedded looping, muted, inline video under “Prompting in Cursor” (prefers WebM, falls back to MP4).
   - Container width clamped to avoid upscaling blur; optional `poster` for a crisp first frame.
   - Interactive controls provided by `HoverVideo` (client) with hover/tap overlay:
     - Play/Pause and Fullscreen (standard API + iOS fallback).
     - Icons: `lucide-react` (Play, Pause, Maximize, Minimize).

---

8. Media & Video Assets
- Location: `public/videos/`
- Recommended embed (Server Component safe):
  - `<video autoPlay loop muted playsInline preload="metadata" controls={false} disablePictureInPicture controlsList="nodownload noplaybackrate nofullscreen">`
  - Include both sources (browser picks best):
    - `<source src="/videos/file.webm" type="video/webm" />`
    - `<source src="/videos/file.mp4" type="video/mp4" />`
  - Add `poster="/videos/file-poster.png"` for a crisp first frame.
- Interactive overlay pattern:
  - Use `app/components/hover-video.tsx` for hover/tap‑revealed controls without native UI.
  - Props: `srcWebm`, `srcMp4`, `poster`, `className`.
- Sizing for sharp UI text:
  - Clamp container width (e.g., `max-w-[1024px]`) to avoid blurry upscaling.
  - Ensure the exported width is ≥ the displayed width.
- Encoding (run locally; do not add ffmpeg to project):
  - VP9 WebM (crisp text, preferred):
    ```
    ffmpeg -i input.mp4 -vf "scale=1280:-1:flags=lanczos" -r 30 \
      -c:v libvpx-vp9 -b:v 0 -crf 24 -deadline good -row-mt 1 -an output.webm
    ```
  - H.264 MP4 fallback (high quality):
    ```
    ffmpeg -i input.mp4 -vf "scale=1280:-1:flags=lanczos" -r 30 \
      -c:v libx264 -preset slow -crf 18 -profile:v high -pix_fmt yuv420p \
      -movflags +faststart -an output.mp4
    ```
- Caching:
  - Hard reload to bypass cache during dev; rename files to bust CDN caches if needed (e.g., `file.v2.webm`) and update `<source>` paths.

---

9. Experimental WebGPU Path (paused)
- The WebGPU build currently renders magenta→black with validation errors (bind group).
- Root cause is likely pipeline/shader compatibility; plan:
  1) Ensure URP is active for Web build and materials are URP compatible.
  2) Start with minimal URP scene (Lit cube) and scale features on.
  3) Once stable, add a runtime switch to prefer WebGPU when supported, fallback to Stable.

---

10. Developer Tasks (How‑To)
- Update Stable build:
  1) Export Unity WebGL2 with “Name Files As Hashes” + Brotli ON.
  2) Copy to `public/builds/griddie/Stable/`.
  3) No code changes needed for filenames — the client calls `/api/unity/stable-manifest` to auto‑discover the four hashed files and append a version cache‑buster.
  4) Restart dev server; verify network headers (look for `Content-Encoding: br` on Unity assets).
- Edit landing README content:
  - Update text in `app/components/hero-readme.tsx` (both the inline panel and modal).
  - To change contacts, edit the Contact.md section in `HeroReadme`:
    - Discord label currently “pogchampion”
    - Email `connor@markdowngames.com`
- Edit global footer:
  - Update email/X/Twitter links or copy in `app/components/site-footer.tsx`.
- Edit MDMCP docs page:
  - Update content in `app/mdmcp-unity/page.tsx` (sections: Install, Start, Quickstart, Extend, Prompting).
- Adjust spacing between landing panels:
  - In `app/components/hero-readme.tsx`, wrapper around the MDMCP `IdePanel` adds `mt-6` for breathing room.
- Adjust aspect ratio:
  - In `unity-canvas.tsx`, edit `ASPECT` and width clamp. For phones with dynamic toolbars, 100svh works well; 100dvh is an alternative.
- Testing:
  - Dev: `npm run dev` → `/play`
  - Prod build: `npm run build && npm run start`
  - Lighthouse (desktop + mobile), check a11y and SEO.
 - Production Google Sign‑In:
   - Set `NEXT_PUBLIC_GOOGLE_CLIENT_ID` in Vercel (Production + Preview) and redeploy.
   - Add Authorized JavaScript origins for apex/www and `*.vercel.app` preview in Google Cloud Console (OAuth client: Web application).
   - Verify `/play?ui-debug=1` shows “Rendering Google button (init)” and the button on the Main Menu.

---

11. Future Roadmap (Web)
- Add “Studio / Devlog” section and a Manifesto page using content from `Docs/webStrategy.md`.
-- Steam “Defensive Disclosure” page linking the manifesto.
- Add OG/SEO metadata, sitemap, and robots.
- Implement WebGPU fallback flow once the build is validated.
- Optional: E2E tests (Playwright) for hero, CTA routing, and Unity mount.

--- 

12. Quick File Map
- `app/page.tsx` — Landing (hero; secondary CTA currently hidden)
- `app/play/page.tsx` — Unity entry point
- `app/components/unity-canvas.tsx` — Unity embed and sizing logic
- `app/components/hero-readme.tsx` — Landing README panel and Contact/README modal
- `app/components/site-footer.tsx` — Global footer (email, X/Twitter, ©)
- `app/mdmcp-unity/page.tsx` — MDMCP docs page
- `app/components/ide-panel.tsx` — IDE‑styled panel component
- `app/components/ide-modal.tsx` — IDE‑styled modal component
- `app/components/how-to-play.tsx` — IDE‑styled `rules.md` modal (descriptive How‑to‑Play)
- `app/components/how-to-play-quick.tsx` — condensed How‑to‑Play modal (present; not used by default)
- `app/components/quickstart-hint.tsx` — dismissible Quick Start overlay (Main Menu)
- `app/icon.svg` — Favicon (SVG, brand gradient “.md”)
- `app/apple-icon.tsx` — Apple touch icon (Next/og; 180×180 PNG)
- `app/globals.css` — Theme and Tailwind v4 bridge
- `next.config.ts` — Headers for Unity Brotli assets
- `app/api/unity/stable-manifest/route.ts` — Manifest discovery for hashed Unity filenames
- `public/builds/griddie/Stable/*` — Deployed Stable WebGL2 build
- `public/builds/griddie/WebGPU/*` — Experimental WebGPU build (optional)
- `app/docs/page.tsx` — Docs index (Markdown docs hub)
- `app/docs/blueprint-game/page.tsx` — Renders `Docs/blueprintGame.md`
- `app/docs/blueprint-web/page.tsx` — Renders `Docs/blueprintWeb.md`
- `app/docs/changelog/page.tsx` — Renders `Docs/changelog.md`
- `app/docs/new-chat/page.tsx` — Renders `.cursor/commands/NewChat.md`
- `app/docs/update-blueprint/page.tsx` — Renders `.cursor/commands/UpdateBlueprint.md`
- `app/docs/git-push/page.tsx` — Renders `.cursor/commands/gitPush.md`