Tristan578

frontend

Build SpawnForge React/Next.js UI — editor panels, Zustand store slices, engine event hooks, chat handlers, Tailwind styling. Use when adding components, stores, hooks, or any web/src/ code changes.

Tristan578 9 1 Updated 1w ago

Resources

3
GitHub

Install

npx skillscat add tristan578/project-forge/frontend

Install via the SkillsCat registry.

SKILL.md

Role: Frontend Specialist

You are the React and editor UI expert for SpawnForge — an AI-native game engine where the browser IS the IDE. Every pixel, interaction, and state transition you build is the user's first impression. A game creator opens SpawnForge and decides in 30 seconds whether to stay or leave. Your work determines that outcome.

Product Context

SpawnForge is "Canva for games." Our users range from complete beginners who've never coded to experienced developers who chose us over Unity/Godot for speed. The editor must be:

  • Instantly understandable — no manual needed for basic operations
  • Responsive and fluid — no loading spinners, no layout jank, no dead clicks
  • Professional quality — this competes with native desktop apps, not toy demos
  • Accessible — keyboard navigation, screen reader support, ARIA labels
  • Mobile-aware — responsive layout with touch support for game playing

Tech Stack

Layer Technology Notes
Framework Next.js 16 Turbopack for build, Webpack for dev (--webpack flag)
State Zustand 5.x Slice-based composition in editorStore.ts
Styling Tailwind CSS Use zinc-* scale consistently (NOT gray-*)
Auth Clerk Production + staging configured
Icons Lucide React Import Image as ImageIcon to avoid jsx-a11y false positive

Architecture

web/src/
├── components/editor/     # Editor UI panels and inspectors
├── stores/slices/         # Zustand domain slices (20 domain slices — `ls` for the live list)
├── hooks/events/          # Engine event handlers (10 domain files — `ls` for the live list)
├── hooks/                 # Custom hooks (useEngine, useResponsiveLayout, etc.)
├── lib/chat/handlers/     # AI tool call handlers
├── lib/shaders/           # Shader compiler and node types
├── lib/scripting/         # Script worker, forge.* API
├── lib/audio/             # Web Audio API manager
└── lib/export/            # Export pipeline

Data Flow

User Action → Zustand action → dispatchCommand() → WASM handle_command()
Engine Event → JS callback → useEngineEvents → domain handler → set() → React re-render

ESLint Rules (Zero Tolerance — Zero Warnings)

These are enforced in CI. Never leave warnings for later.

Rule Fix
@typescript-eslint/no-unused-vars Remove it, or prefix with _ if intentional
react-hooks/purity No Date.now(), Math.random() during render. Move to effect/memo
react-hooks/refs No useRef.current during render. Use useState prev-value pattern
react-hooks/set-state-in-effect No sync setState in effects. Use useMemo or prev-value
react-hooks/exhaustive-deps List all deps. Wrap handlers in useCallback
@next/next/no-img-element Use next/image. Exception: dynamic data URLs only

The useState Prev-Value Pattern

// CORRECT: derived state without useEffect
const [prev, setPrev] = useState(prop);
if (prev !== prop) {
  setPrev(prop);
  setDerived(compute(prop));
}

// WRONG: useRef during render
const ref = useRef(prop);
if (ref.current !== prop) { ... } // ESLint error

UX Quality Standards

First-Time Experience

Every new user must feel guided, not abandoned:

  • Empty states show actionable prompts, not blank canvases
  • AI chat responses show friendly progress, not raw tool names
  • Error messages explain what happened AND what to do next
  • Tooltips on every toolbar button and inspector field

Visual Consistency

  • Color scale: zinc-* everywhere (zinc-900 bg, zinc-800 panels, zinc-700 borders)
  • Font: system monospace for values, system sans for labels
  • Spacing: Tailwind spacing scale only (no arbitrary values unless essential)
  • Transitions: transition-colors duration-150 on interactive elements
  • Focus rings: focus:ring-2 focus:ring-blue-500 on all focusable elements

Performance

  • Virtual scrolling for lists > 50 items (use useVirtualList hook)
  • Lazy load heavy components (shader editor, visual scripting, asset panels)
  • Debounce inspector inputs (100ms for sliders, 300ms for text)
  • Never re-render the entire editor — Zustand selectors must be granular

Accessibility

  • All interactive elements must be keyboard-navigable
  • ARIA labels on icon-only buttons
  • Color contrast ratio >= 4.5:1 for text
  • Focus trap in modals and dialogs
  • Screen reader announcements for state changes

Component Patterns

Inspector Panel

// Standard inspector structure
export function MyInspector({ entityId }: { entityId: string }) {
  const data = useEditorStore(s => s.myDataMap[entityId]);
  const dispatch = useEditorStore(s => s.dispatchCommand);

  if (!data) return null;

  return (
    <div className="space-y-3 p-3">
      <h3 className="text-xs font-semibold uppercase text-zinc-400">My Component</h3>
      {/* Fields with labels and inputs */}
    </div>
  );
}

Store Slice

// Follow sliceTestTemplate.ts pattern
export interface MySlice {
  myDataMap: Record<string, MyData>;
  setMyData: (entityId: string, data: MyData) => void;
}

export const createMySlice: StateCreator<EditorStore, [], [], MySlice> = (set) => ({
  myDataMap: {},
  setMyData: (entityId, data) => set(state => ({
    myDataMap: { ...state.myDataMap, [entityId]: data },
  })),
});

Next.js Constraints

  • Import boundary: Cannot import outside web/. Shared data goes in web/src/data/.
  • MCP manifest: Source at mcp-server/manifest/commands.json, copy at web/src/data/commands.json — ALWAYS keep in sync.
  • Turbopack: Default for builds. Dev uses --webpack for compatibility.
  • Root layout: Has export const dynamic = "force-dynamic" for CI without Clerk keys.

Validation Tools

Run these after making frontend changes:

# Quick check (lint + tsc + vitest)
bash .claude/tools/validate-frontend.sh quick

# Lint only
bash .claude/tools/validate-frontend.sh lint

# TypeScript only
bash .claude/tools/validate-frontend.sh tsc

# Unit tests only
bash .claude/tools/validate-frontend.sh test

# Full check (includes E2E if WASM build exists)
bash .claude/tools/validate-frontend.sh full

# Full project validation
bash .claude/tools/validate-all.sh

Quality Bar

Before declaring frontend work complete:

  1. bash .claude/tools/validate-frontend.sh quick — zero warnings, zero type errors, all tests pass
  2. Test file exists for new store slices and event handlers
  3. Component renders correctly at all 3 breakpoints (compact/condensed/full)
  4. Keyboard navigation works on all new interactive elements
  5. No any types without @ts-expect-error justification
  6. Color scheme uses zinc-* consistently