Imported from apneduniya/fenon-platform (
AGENTS.md). Install upstream withnpx skills add apneduniya/fenon-platform. Copyright stays with the author.
This is NOT the Next.js you know
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ (resolved from this file's directory; in monorepos the next package may not be visible from the repo root) before writing any code. Heed deprecation notices.
This block is written and re-added by next dev — verify at node_modules/next/dist/server/lib/generate-agent-files.js. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
Fenon platform — agent guide
Marketing site for Fenon (inference infrastructure for robotics), built from the design exports in fenon_full_web_design/. That folder is local reference only and is git-ignored (decision #41). Get it from the team's Figma file if it's missing.
Priority order when guidance conflicts: Next.js docs (node_modules/next/dist/docs/) → this file → user preferences. If you find a conflict, flag it to the user and record the outcome in docs/decisions.md.
Docs you must keep in sync
| File | Holds |
|---|---|
docs/decisions.md |
Every decision, why, alternatives rejected. Append; never silently rewrite. |
docs/design-tokens.md |
Palette, semantic tokens, type scale, radius, spacing, breakpoints. |
docs/components.md |
Component inventory and which design PNG each maps to. |
docs/figma-extract.md |
Raw Figma MCP responses (free plan — never re-fetch what is recorded here). |
Rule: any new or changed decision, convention, dependency, token or folder is written to the relevant doc in the same change. At the end of each step, check the docs against the code.
Stack
- Next.js 16 App Router, React 19, TypeScript strict, bun.
- Tailwind CSS v4 (CSS-first config, no
tailwind.config). - shadcn/ui on Base UI primitives (not Radix), generated into
components/ui/. - Zustand (shared client state), TanStack Form + Zod (forms and validation), Zod (content typing).
- TanStack Query is not installed yet. Add it only when data must be fetched on the client.
- Fonts: Inter (sans/display) + JetBrains Mono via
next/font/google.
Folder structure
app/ is for routing only. Shared project code lives in top-level folders.
app/
layout.tsx, page.tsx, providers.tsx, globals.css
contact/page.tsx
engineering/[slug]/page.tsx
@modal/default.tsx, @modal/[...catchAll], @modal/(.)contact, @modal/(.)engineering/[slug]
(dev)/tokens/page.tsx dev-only token board (404 in production)
components/
ui/ shadcn (generated). Edit only to restyle via tokens.
common/ small reusable building blocks (Container, Eyebrow, SectionHeading, Card, CodeWindow, CtaLink, TextLink, ThemeToggle, ThemeImage, DocumentCard, RouteModal, CloseButton, CopyButton, Lines, icons)
layout/ AnnouncementBar, SiteHeader, MobileMenu, SiteFooter
sections/ one file per homepage section
illustrations/ inline SVG React components
forms/ ContactForm
panels/ ContactPanel, ArticlePanel (shared by full pages and intercepted modals)
providers/ StoreProvider
content/ typed copy and data (site, home, contact, articles, code-samples)
lib/ utils.ts (cn), theme.ts, brand-colors.ts, stores/ (zustand), schemas/ (zod)
styles/ palette.css → tokens.css → theme.css (the only theme source, imported by app/globals.css)
public/images/ local image assets only
scripts/ repo tooling (check-tokens.ts)
docs/ agent docs (see table above)
Components
- Server Components by default. Add
"use client"only to the interactive leaf, never to a whole section. Pass server-rendered children into client components where possible. - One component per file, PascalCase filename, named export (
export function Hero()). Route files (page.tsx,layout.tsx) use default exports, as Next requires. - Sections read copy from
content/and never hardcode strings. Content objects are validated by Zod schemas inlib/schemas/. - Compose primitives rather than duplicating markup. If a pattern appears twice, extract it into
components/common/. - Props are typed with explicit interfaces. Use
cn()fromlib/utils.tsto merge classes. - Add comments only where the intent is not obvious from the code.
State and data
- Server data: fetch in Server Components (async functions or
fetch). Do not add TanStack Query for server-renderable data. - Shared client state: Zustand, with the store created per provider (
createStore+ React context incomponents/providers/StoreProvider.tsx). Never use a module-level singleton store. - Local UI state (menu open, active tab, copied flag):
useState. - Theme: an inline pre-hydration script sets
.darkon<html>from localStorage or the system setting. The Zustand theme store mirrors and updates that class. Do not rely onpersistfor the theme, because it flashes on load. - Forms: TanStack Form + a Zod schema from
lib/schemas/. Types are inferred withz.infer. Any future server submission is a Server Action that re-validates with the same schema.
Theming (strict)
Tokens come in three layers. Only layer 3 utilities appear in components.
styles/palette.css: brand primitives (--fenon-*) in OKLCH. The only file allowed to contain raw colour values.styles/tokens.css: semantic tokens in:rootand.dark, in shadcn surface/-foregroundpairs. They referencevar(--fenon-*)only.styles/theme.css:@theme inlinemaps each semantic token to a--color-*utility. It also holds the type scale, radius, fonts and motion.
Rules:
- Use semantic utilities only:
bg-card,text-muted-foreground,border-border,bg-primary,text-display-hero. - Never write hex, rgb or oklch values, arbitrary colour classes (
bg-[#…]) or Tailwind default palette classes (bg-orange-500) in components.bun run lint:tokensfails on them. - Type sizes are tokens set at the exact Figma values. Never round to a generic scale (don't swap a 15px design size for
text-sm). - Arbitrary values are allowed only for one-off layout measurements (a specific width or offset).
- Need a new colour? Add a semantic token first (and a primitive only if the brand genuinely adds one), then document it in
docs/design-tokens.md. - Hand-built SVGs (icons, charts, logo) use
currentColororvar(--token)fills, so one asset serves both themes. - Exception: complex Figma illustration exports (e.g. the hero) are used unedited, one file per theme, and swapped with
dark:hidden/hidden dark:block(decision #21). They live inpublic/images/and are outsidelint:tokens. - The theme's token files live in root
styles/, notapp/styles/(decision #15).
Images, motion and accessibility
- Use
next/imagewith explicitwidth/height, orfillinside a parent with a fixed aspect ratio, to protect against layout shift. Only the hero's largest visual getspriority. - All images are local, so there are no
images.remotePatterns. If a remote source is ever added, allow-list its exact host innext.config.tsand record the decision. - Alt text describes what the image shows. Decorative SVGs get
aria-hidden="true". - Animate only
transformandopacity, never width, height, margin or top/left. Every animation respectsprefers-reduced-motion. - Keep one
h1per page, with headings in order. Interactive widgets are keyboard operable and have visible focus rings (ringtoken).
Design deviations (intentional)
- Section eyebrows drop the numeric prefix ("THE PLATFORM", not "01 / THE PLATFORM"). All other numbering in the design is kept.
shadcn/ui
- Add components with
bunx --bun shadcn@latest add <name>. If it prompts to overwritebutton.tsx, answer no: it holds the Fenonctavariants. - After adding, run
bun run lint.lint:tokensflags palette colours (e.g.bg-black/10) andimport { cn } from "cn". Replace them with tokens and@/lib/utils. - Known fixes in generated files are listed in decision #31. Re-apply them if you ever overwrite.
Workflow
- Commands:
bun dev,bun run build,bun run lint(includeslint:tokens). - Deployment: Vercel project
apneduniyas-projects/fenon-platform, connected to GitHubapneduniya/fenon-platform. Every push tomaindeploys to production (https://fenon-platform.vercel.app); other branches get previews. Prefer deploying by pushing oververcel deploy;.vercelignorekeeps the local design folder out of CLI uploads. - If newly added Tailwind classes don't apply in dev, restart
bun dev(Turbopack can miss files replaced in place; decision #34). - Design measurements: crop the PNGs at full resolution (4× for 1440) and compare glyph bands and DOM landmarks. Don't eyeball.
- Build order: theme foundation → setup → primitives → sections one by one → routes/modals.
- Verify each section live with the
agent-browserskill at 1440px and 390px, in light and dark, against the matching crop of the design PNG.