Imported from shenmareparas/Portfolio_NextJS (
.agents/AGENTS.md). Install upstream withnpx skills add shenmareparas/Portfolio_NextJS --skill .agents. Copyright stays with the author.
Agent Guidelines & Rules
This document outlines the development guidelines, constraints, and conventions for AI agents working on the Paras Shenmare Portfolio codebase.
🛠️ Stack & Architecture Constraints
- Framework: Next.js 16 (App Router), React 19, TypeScript, and Bun as the package manager and runner.
- Styling: Tailwind CSS v4. Ensure configuration is done via CSS variables or standard Tailwind classes. Avoid using deprecated Tailwind v3 config structures or styles.
- Animations: Framer Motion. Keep animations smooth, subtle, and responsive.
- Haptics:
web-haptics(local plugin in.agents/skills/web-haptics) should be used for interactive elements targeting mobile viewports (e.g., buttons, toggles, form submissions). Refer to web-haptics SKILL.md for trigger details. - UI Components: Built using Shadcn UI primitives (
components/ui/) and Radix UI.
📂 Codebase & Folder Conventions
- Pages and Routing: All routing is under
app/using Next.js App Router. - Components:
components/ui/: Low-level reusable UI components (buttons, inputs, tooltips, dialogs,coverflow-carousel.tsx,vertical-gallery.tsx).components/layout/: Global structure components (Header, Footer, Navbar).components/providers/: Client-side provider contexts (Theme, Nav).components/motion/: Framer-motion helper components.- Page-specific components reside in folders like
components/home/,components/projects/,components/experience/, etc.
- Data-Driven Configuration:
- CRITICAL: Do NOT hardcode personal details, experience, education, or project lists directly in the page components. Always read from or modify files in the
data/directory:- config.ts: Site SEO and metadata.
- profile.ts: Bio, contact details, and resume links.
- projects.ts: List of featured and personal projects. Key conventions:
- Cover banners: Standardized to
image: "/project/<slug>/banner.webp". - Gallery layouts: Mobile apps use 3D Coverflow (
galleryLayout: "carousel"); desktop/macOS/CLI apps use vertical scrolling (galleryLayout: "vertical"). - Theme-aware gallery items: Supports
GalleryItem = string | { light: string; dark: string }for automatic theme-switched screenshots. - Screenshot cropping: Window/app captures must have excessive OS transparent drop-shadow borders cropped away (preserving only a subtle 14–15px margin around the window frame) to maintain consistent aspect ratios across the lightbox.
- Cover banners: Standardized to
- Favicons & App Icons: Managed via Next.js metadata file conventions: app/favicon.ico (32x32), app/icon.png (512x512), app/apple-icon.png (180x180), and fallback public/favicon.ico.
- experience.ts & education.ts: Timelines.
- skills.tsx: Categorized developer skills using Lucide and Simple Icons.
- testimonials.ts: User/client feedback.
- expertise.ts: Core domain expertise list.
- CRITICAL: Do NOT hardcode personal details, experience, education, or project lists directly in the page components. Always read from or modify files in the
- Types: All TypeScript interfaces and types must be placed in
types/. Cross-reference types before declaring new ones.
🎨 Styling & Design Guidelines
- Theme Support: The site is light/dark system-aware. Ensure all new components use Tailwind's dark-mode classes (e.g.,
dark:bg-zinc-950). - Typography & Colors:
- Use high-quality curated color palettes (primarily Zinc/Neutral greys, with vibrant, tailored accent gradients).
- Ensure visual excellence, premium aesthetics (glassmorphism/backdrop-filters where appropriate), and high contrast (WCAG standards).
- Responsive Design: Ensure mobile-first designs. Never assume a desktop width.
- Form Validation: Always pair React Hook Form with Zod for contact or input validation.
🚀 Key Commands
- Run Dev Server:
bun dev - Build Production:
bun run build - Lint Code:
bun run lint - Install Dependencies:
bun install
⚡ Performance & Quality Guidelines (React Doctor Audited)
- Avoid Layout Property Animations & Broad Transitions:
- Do not animate layout-affecting properties (like
height,width,top,left, etc.) directly via Framer Motion. Instead use GPU-composited CSS transforms (scaleX,scaleY) and CSS Grid transitions (grid-template-rows: 0fr -> 1fr). - Avoid
transition-all. Always specify targeted transitions (e.g.,transition-colors,transition-opacity,transition-transform, ortransition-[border-color,box-shadow,transform]) to prevent browser layout reflow jank.
- Do not animate layout-affecting properties (like
- Prevent Timer and Event Listener Leaks: Every
setTimeout,setInterval, or DOM event listener registered inside auseEffectmust return a corresponding cleanup function (clearTimeout,clearInterval, orremoveEventListener) to prevent memory leaks and background state updates on unmounted components. - SSR-Safe Mounting without Flicker: Do not use
useState+useEffectmount flags just to detect client-side rendering. Use React 19'suseSyncExternalStorewith stable module-level selectors to ensure client-only mount state syncs in a single commit, eliminating hydration flashes. - Stable Callback Dependencies: When using hooks like
useCallbackoruseMemo, avoid depending on complex/derived variables when only a primitive is needed. Extract the primitive boolean or string in the render scope (e.g.,isDark,themeToSet) and depend on that to prevent redundant hook recreation. - Interactive Element Accessibility: Never attach click, keydown, or drag handlers directly as React props on static elements (
div) or semantic non-interactive elements (section,li). For custom drag-scrollable containers, register listeners dynamically inside auseEffectusing.addEventListener()to bypass static checker violations while ensuring full control over event teardown. - Zod 4 Schema Standards: Use top-level format builders (e.g.,
z.email(),z.uuid(),z.iso.date()) rather than chained methods onz.string()(e.g.,z.string().email()) for forward compatibility. - Immediate Above-the-Fold LCP Delivery: Never wrap above-the-fold hero content (
h1,h2, hero CTA buttons) inside client animation wrappers initialized withopacity: 0(e.g.<FadeIn>). The hero elements must render immediately in the initial SSR commit to prevent artificial LCP and FCP delays. Below-the-fold sections may use scroll-triggered animations. - Font Swap Strategy: Google Fonts configured via
next/font/googlemust explicitly specifydisplay: "swap"to prevent font-blocking delays. - Consistent Canonical URLs: Maintain strict canonical formatting across
app/layout.tsx, individual page routes, andapp/sitemap.tsto prevent Google Search Console duplicate/mismatch warnings. - Pure State Updaters & Zero Cascading Effect Setters: State updater functions passed to
setStatemust be strictly pure and free of side effects. Never callsetStatesynchronously within auseEffectbody to synchronize state with other state variables; derive state during render or update values together in event handlers. - Component Modularity & Low Control Flow Complexity: Keep React functions concise and modular. Extract complex inline conditional render sections (e.g., project action links, custom modal controls, navigation blocks) into focused sub-components.
- Synthetic Mouse Event Debouncing for Touch Gestures: Mobile browsers fire delayed synthetic
click(300ms) anddblclick(350–500ms) events after touch gestures. When handling custom touch double-tap or touch tap gestures inpointerup, record the interaction timestamp (lastTouchDoubleTapTimeRef.current = Date.now()) and guard all synthetic mouse listeners (onDoubleClick,onClick) with a timestamp diff check (if (Date.now() - lastTouchDoubleTapTimeRef.current < 700) return;) to prevent synthetic mouse events from immediately inverting touch-toggled states. - Dynamic GPU Optimization (
willChange) & Module-Level Static Objects: Never apply permanentwill-change: transformorwill-change-transformto idle DOM elements as it wastes dedicated GPU memory compositor layers. DynamicizewillChangeto active interaction state (e.g.willChange: isInteracting ? "transform" : "auto"). Extract static object declarations (e.g.,const SLOT_STYLE = { width: "calc(100% / 3)" } as const;) to module scope to prevent re-instantiation across renders. - Coordinated Component State via
useReducer(react-doctor/prefer-useReducer): When managing multiple interrelated state variables that transition together (such as lightbox zoom scale, pan position, strip offset, animation flags, and dismiss coordinates), consolidate them into a typeduseReducerwith an atomic action dispatch instead of firing disjointuseStatesetters. - Sub-component & Custom Hook Decomposition (
react-doctor/no-giant-component): Maintain concise component boundaries (< 300 lines). Decouple complex gesture/pointer engines and lifecycle listeners into dedicated custom hooks (e.g.useLightboxGestures) and encapsulate multi-slot render strips or control bars into focused sub-components (e.g.LightboxStrip,LightboxControls).