Files
flatrender/PROJECT_MEMORY.md
T

359 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FlatRender — Project Memory
> **Rule:** Read this file before starting any task. Update it after every completed feature, bug fix, or architectural decision.
> Both Cursor AI and Claude Code use this as the project brain.
---
## 📌 Project Identity
| Key | Value |
|---|---|
| Project folder | `D:\Projects\flatrender` |
| Brand name | **FlatRender** (package: `flatrender`) — ✅ All UI updated to FlatRender |
| Products | Video Maker · Image Maker |
| Stack | Next.js 14 App Router · TypeScript · Tailwind CSS · shadcn/ui · Framer Motion |
| Canvas | React-Konva (Konva.js) — both Video Studio and Image Editor |
| State | Zustand (`studio-store.ts`, `image-editor-store.ts`) |
| Auth + DB | Supabase (`@supabase/ssr`) |
| Payments | Stripe |
| Video (browser) | ffmpeg.wasm in Web Worker (`src/workers/ffmpeg-trim.worker.ts`) |
| Video (server) | nexrender + Adobe After Effects (`server/render-worker.ts`) |
| Dev server | `npm run dev` → http://localhost:3000 |
| Render worker | `npm run render-worker` → http://localhost:3355 |
---
## ✅ Completed Features
### Landing Page (`/`)
- [x] `Hero` — gradient on “AI” (`from-blue-600 via-violet-500 to-blue-500`), dual CTA, preview cards, blobs
- [x] `HeroPreviewCards` — Mixkit MP4 loops, play overlay fades on hover, Framer Motion stagger
- [x] `ProductsShowcase` — Video Maker + Image Maker cards with glassmorphism style
- [x] `TemplateGallery` — filter tabs, 8-card grid, `scroll-mt-20` for sticky nav anchor
- [x] `TemplateCard` — hover Mixkit video via `previewVideoUrl`, bottom "Use Template" CTA, `AnimatePresence` fade
- [x] `template-gallery-data.ts``previewVideoUrl` on video/social template entries
- [x] `HowItWorks` — 3-step process, alternating layout, scroll-triggered animations
- [x] `Pricing` — monthly/annual toggle, green “Save 20%” yearly badge, 3 tiers, Stripe checkout wired
- [x] `PricingCompareTable` — full feature comparison table, 5 sections, synced billing toggle, Pro column highlight
- [x] `Testimonials` — 6-card grid
- [x] `FAQ` — accordion, 2-column layout
- [x] `Navbar` — FlatRender logo, Video/Image Maker + Learn dropdowns (shadcn), Pricing link, Sign In / Try for Free; mobile sheet (`navbar-menu-data.ts`)
- [x] `Footer` — 4-column, dark background
### Product Pages
- [x] `/video-maker` — Hero, Features, UseCases, TemplateCarousel, CTA
- [x] `/image-maker` — Hero, BeforeAfter, Gallery, Features, UseCases, CTA
### Templates Page (`/templates`)
- [x] Renderforest layout: 260px category sidebar + carousel rows (`VideoTemplatesCategorySidebar`, `VideoTemplatesCarouselRow`)
- [x] Toolbar: search, Premium Only (Switch), All Sizes select (16:9 / 9:16 / 1:1 / 4:5), Sort by (local state)
- [x] Sidebar filters panel (collapsed): Premium + size; `?category=` from navbar
- [x] `VideoTemplatesPageContent` — client-side filtering via `video-templates-catalog.ts`
- [x] Template detail `/templates/[id]``TemplateDetailContent` (preview, styles, Create Now, examples row); `generateStaticParams` from catalog
### Auth (`/auth`)
- [x] Sign In / Sign Up tabs
- [x] Email + password (react-hook-form + zod)
- [x] Google OAuth button
- [x] Supabase auth integration
- [x] OAuth callback route (`/auth/callback`)
- [x] Sign-out route (`/auth/sign-out`)
- [x] `SupabaseSetupNotice` — shown when env vars missing (dev-friendly)
### Dashboard (`/dashboard`)
- [x] `DashboardShell` — layout wrapper
- [x] `DashboardSidebar` — logo, nav links, user avatar + plan badge
- [x] `DashboardTopBar` — search + "New Project" dropdown
- [x] `NewProjectMenu` — Video / Image / Trimmer options
- [x] `DashboardProjectsSection` — projects grid from Supabase; `isLoading` shows 6-card skeleton grid
- [x] `DashboardProjectsContent` — async Supabase fetch (Suspense on `/dashboard`)
- [x] `SkeletonProjectCard` — pulse placeholders matching `ProjectCard` layout
- [x] `DashboardPlanBadge` — async plan fetch; sidebar `Suspense` + `DashboardPlanBadgeSkeleton`
- [x] `DashboardSidebarNav` — client nav (pathname-aware)
- [x] `DashboardEmptyState` — illustration + CTA
- [x] `ProjectCard` — thumbnail, type badge, status, 3-dot menu
- [x] `/dashboard/settings` — settings page
### Video Creation Studio (`/studio/video/[projectId]`)
- [x] `VideoStudioLayout` — icon dock (56px) + fixed 220px tool panel + full-width canvas/timeline (no right `PropertiesPanel`); `StudioMobileGate` below 768px; `useStudioProjectPersistence` (3s debounced save; dev 404 → `localStorage` `flatrender-project-{id}`)
- [x] `StudioSidebarDock` — Audio / TTS / Colors / Transitions / Font / Watermark + Guide + Keyboard (toasts); blue active bar; scenes via timeline strip only
- [x] `WatermarkSidebarContent` — upload placeholder, 3×3 position grid, opacity slider
- [x] Sidebar panels — `AudioSidebarContent`, `ColorsSidebarContent`, `TransitionsSidebarContent` (Random / No Transition tiles, apply all scenes), `FontSidebarContent`, `WatermarkSidebarContent`
- [x] `scene-browser-data.ts`, `SceneBrowserCard`, shadcn `Tabs` for media filter
- [x] `/studio/video/new` — Renderforest-style onboarding (Select Scenes / AI / presets) before editor
- [x] `VideoProjectNewContent`, `TEMPLATE_GALLERY_ITEMS` (picsum thumbnails); preset click → `/templates/[id]`; catalog includes onboarding preset ids
- [x] `SceneBrowserModal` — full-screen library (categories, Video/Photo tabs, search, 28 scenes); onboarding + studio “Browse Scenes”
- [x] `StudioMobileGate` + `useIsMobile` — desktop-only gate for video/image studio (`matchMedia` max-width 767px)
- [x] `ResizableStudioPanel` — drag-to-resize left/right panels
- [x] `StudioTopBar` — breadcrumb (My Projects → name), `StudioTopBarSaveBadge` (Local / Saved ✓ / dot), centered undo/redo + toolbar, `StudioTopBarTextControls` when text layer selected, Export dropdown → `RenderModal` presets
- [x] `PropertiesPanel` — still used by image editor; not mounted in video studio layout
- [x] `dev-project-storage.ts` — dev-only localStorage fallback when Supabase returns 404
- [x] `render-presets.ts` — full / 720p preview / GIF export presets for `RenderModal`
- [x] Scenes managed via timeline `SceneThumbnailStrip` only (no left sidebar scenes panel): 120×80px blocks, rename, browse (`SceneBrowserModal`), duplicate/delete on hover
- [x] `SceneTransitionPicker` — None / Fade / Slide / Zoom popover on outgoing scene
- [x] `scene-transitions.ts` — Framer Motion `animate()` playback (300ms fade, slide-left, zoom)
- [x] `DraggableSceneItem` + `SceneItemActions` — live Konva `thumbnailUrl` previews
- [x] `AddSceneMenu` — blank / from template
- [x] `CanvasEditor` — React-Konva Stage (1280×720), scaled to container
- [x] Text layers (draggable, resizable, rotatable)
- [x] Image layers
- [x] Video clip layers
- [x] Shape layers (rect, circle, line, arrow)
- [x] Transformer (resize handles, rotation, min 8px guard)
- [x] Click empty area → deselect
- [x] Circle drag fix (center-origin correction)
- [x] `CanvasLayerNode` router → `TextLayerNode`, `ImageLayerNode`, `ShapeLayerNode`, `VideoLayerNode`
- [x] `PropertiesPanel` — context-sensitive to selected layer type
- [x] `TextLayerProperties` — font, size, bold/italic, color, align, letter-spacing, line-height, animation style
- [x] `ImageLayerProperties` — opacity, flip H/V, replace, border-radius
- [x] `ShapeLayerProperties` — fill, stroke, stroke-width, border-radius
- [x] `CommonLayerControls` — X/Y/W/H, rotation, z-order, delete
- [x] `PropertyControls` + `useLayerUpdater`
- [x] `Timeline` — 180px Renderforest layout: `TimelineControlBar`, `SceneThumbnailStrip` / `SceneThumbnailBlock`, `TimelineActionRow`; playhead on strip (`STRIP_PX_PER_SECOND` 24); zoom slider 30120
- [x] `TimeRuler` — time markers, click to seek
- [x] `SceneTrack` + `SceneBlock` — color-coded, drag-right-edge to resize duration
- [x] `AudioTrack` — file picker, file name display
- [x] `TimelinePlayhead` — red playhead overlay on thumbnail strip during playback
- [x] Legacy `SceneBlock` / `SceneTrack` / `TimeRuler` / `AudioTrack` — unused by Timeline (kept for reference)
- [x] `StudioToolbar` — add Text / Image / Video / Shape buttons
- [x] `RenderModal` — resolution, FPS, progress bar, download link
- [x] `useCanvasKeyboard` — Delete, Ctrl+C/V/Z/Y
- [x] `useCanvasPreviewPlayback` — scene-by-scene playback with timing
- [x] `useContainerSize` — responsive canvas scaling
- [x] `studio-store.ts` — full Zustand store (scenes, layers, playback, zoom, audio, undo/redo)
- [x] `studio-history.ts` — past/future snapshot undo stack (limit 50)
- [x] `studio-timeline.ts` — duration helpers, zoom levels, scene-at-time
- [x] `studio-types.ts` — Scene, Layer, LayerType, `SceneTransition`, AddLayerInput interfaces
- [x] `studio-snapshot.ts` — Konva stage → PNG download
- [x] `studio-canvas-stage.ts` — global stage ref registry
- [x] `studio-scene-thumbnail.ts``toDataURL({ pixelRatio: 0.2 })` + deferred capture after layer edits
- [x] `studio-scene-data.ts` / `image-scene-data.ts` — parse + serialize `scene_data` for persistence
- [x] `ProjectSaveIndicator` — Saving… / Saved / Local save / Save failed (image editor); video studio uses `StudioTopBarSaveBadge`
- [x] `canvas-transform.ts` — node transform → layer coords
- [x] `studio-layer-props.ts` — typed prop accessors per layer type
- [x] `dev-mock-project.ts` — dev-only mock for testing without Supabase
### Video Trimmer (`/studio/trimmer`)
- [x] `TrimmerUploadZone` — drag-drop + click, accepts video/*
- [x] `TrimmerVideoPreview``<video>` + `react-rnd` crop overlay, aspect ratio buttons
- [x] `TrimmerStrip` — frame thumbnail strip, draggable trim handles
- [x] `TrimmerExportSection` — MP4/WebM toggle, export button, progress, download
- [x] `ffmpeg-trim.worker.ts` — full ffmpeg.wasm Web Worker (init, progress, process, complete)
- [x] `ffmpeg-worker-client.ts` — typed client to communicate with worker
- [x] `trimmer-types.ts` + `trimmer-utils.ts` — types and crop scaling math
### Image Editor (`/studio/image` and `/studio/image/[projectId]`)
- [x] `ImageEditorLayout` — full-viewport, dark theme; mobile gate; `useImageProjectPersistence` auto-save
- [x] `ImageEditorTopBar` — project name, export button
- [x] `ImageEditorToolbar` — Select, Crop, Text, Shape, Draw, AI tools
- [x] `ImageEditorCanvas` — dynamic import (SSR off), Konva stage
- [x] `ImageBaseLayer` — base image rendering with Konva filters
- [x] `ImageEditorLayerNode` — text/shape/draw layer nodes
- [x] `ImageCropOverlay``react-rnd` crop box on canvas (aspect lock)
- [x] `VignetteOverlay` — radial gradient vignette
- [x] `ImageCropControls` — aspect presets (Free, 1:1, 16:9, 4:3, 9:16), Apply/Cancel above canvas
- [x] `image-editor-crop.ts` — aspect math, canvas→source crop, `cropImageDataUrl`
- [x] `ImageEditorRightPanel` — tabbed: Adjust | Filters | Layers
- [x] `AdjustPanel` — brightness, contrast, saturation, hue, blur, sharpen, vignette sliders
- [x] `FiltersPanel` — 12 preset filter thumbnails
- [x] `LayersPanel` — reorder, hide, lock, delete
- [x] `AiRemoveBgModal` — calls `/api/remove-bg`, shows result
- [x] `image-editor-store.ts` — Zustand store for image editor
- [x] `image-editor-filters.ts` — Konva filter pipeline helpers
- [x] `image-editor-konva.ts` — Konva helpers
- [x] `image-editor-types.ts` — ImageLayer, ImageEditorState types
- [x] `image-editor-export.ts` — stage → PNG/JPG/WebP download
- [x] `image-editor-stage-ref.ts` — global stage ref
- [x] `image-editor-transform.ts` — transform helpers
### API Routes
- [x] `POST /api/checkout` — creates Stripe Checkout session
- [x] `POST /api/webhooks/stripe` — updates user plan on checkout.session.completed
- [x] `GET/POST /api/projects` — fetch / create user projects
- [x] `GET/PATCH /api/projects/[projectId]` — load project + auto-save `scene_data`
- [x] `POST /api/remove-bg` — calls remove.bg or rembg service
- [x] `POST /api/render` — queues render job in Supabase
- [x] `GET /api/render/[jobId]/status` — poll render job status
### Server (render worker process)
- [x] `server/render-worker.ts` — HTTP server on port 3355, `/health` + `/process`
- [x] `server/render-job-processor.ts` — fetches job from Supabase, runs nexrender, uploads result
- [x] `server/nexrender-job-builder.ts` — builds nexrender job JSON from scene data
- [x] `server/nexrender.d.ts` — type declarations for @nexrender/core
### Infrastructure
- [x] `supabase/migrations/001_profiles.sql` — profiles table, RLS
- [x] `supabase/migrations/002_render_jobs.sql` — render_jobs table, RLS
- [x] `supabase/migrations/003_projects.sql` — projects table, RLS, updated_at trigger
- [x] `.env.example` — all required env vars documented
- [x] `next.config.mjs` — webpack globalObject fix + COOP/COEP headers (required for ffmpeg.wasm)
- [x] `.cursorrules` — full project rules for Cursor AI
- [x] `tailwind.config.ts` — custom colors, font families
- [x] `components.json` — shadcn/ui config
---
## 🔄 In Progress
_Nothing currently in progress._
### Landing page status (2026-05-21 polish)
- `npx tsc --noEmit` — clean (no TypeScript errors)
- Tailwind `rf.blue` / `rf.blue-light``#2563EB` / `#EFF6FF`
- Remaining pre-launch work is env/migrations/E2E tests (see Must Do backlog), not landing UI
---
## 📋 Backlog (Next Tasks)
### 🔴 Must Do Before Launch
- [ ] Create `.env.local` from `.env.example` and fill in real keys ← NOT DONE YET
- [ ] Run Supabase migrations (`001``002``003`) in SQL Editor ← NOT DONE YET
- [ ] Test full auth flow (sign up → dashboard → create project → open studio)
- [ ] Test ffmpeg.wasm trimmer end-to-end in browser
### 🟡 UI Polish (Cursor screenshot-driven)
- [x] Navbar: Video/Image Maker + Learn dropdowns (Renderforest-style, no mega menu)
- [x] Landing polish pass: `rf-blue` / `rf-blue-light` tokens, Hero AI gradient, pricing Save 20% badge, `#templates` scroll-mt-20
- [x] Hero: animated video thumbnail preview cards (autoplay muted)
- [x] TemplateCard: video preview on hover (autoplay muted loop, AnimatePresence fade)
- [x] Studio: scene thumbnail auto-generated from Konva canvas (toDataURL)
- [x] Studio: transition picker between scenes (fade, slide, zoom)
- [x] Dashboard: skeleton loading states for project cards
- [x] Mobile: studio pages desktop gate (under 768px shows `StudioMobileGate`, not full editor)
### 🟢 Nice to Have
- [ ] Template system: pre-built `.aep` templates for nexrender
- [ ] Image editor: text curved/arc effect
- [ ] Image editor: sticker/icon library (200+ SVGs)
- [ ] Video studio: background color/gradient picker per scene
- [ ] Onboarding flow for new users (first project wizard)
- [ ] Usage limits per plan (enforced server-side)
---
## 🐛 Known Issues
| # | Issue | File | Priority |
|---|---|---|---|
| 1 | Brand name "CreatorStudio" in UI | ✅ Fixed 2026-05-21 — all 4 files updated | — |
| 2 | `next.config.mjs` was missing COOP/COEP headers | ✅ Fixed 2026-05-21 | — |
| 3 | Scene thumbnails are placeholder gray boxes | ✅ Fixed 2026-05-21 — `thumbnailUrl` via `updateSceneThumbnail` | — |
| 4 | No loading/error state in trimmer if ffmpeg CDN is slow | `TrimmerExportSection` | 🟡 Medium |
| 5 | Image editor crop tool not fully implemented | ✅ Fixed 2026-05-21 — `ImageCropControls`, `ImageCropOverlay`, pixel crop in `applyCrop` | — |
---
## 🏗️ Architecture Decisions
| Decision | Rationale |
|---|---|
| React-Konva for all canvas work | Consistent layer model across Video Studio and Image Editor |
| ffmpeg.wasm in Web Worker only | Never block main thread; SharedArrayBuffer requires COOP/COEP headers in `next.config.mjs` |
| Zustand for studio state (not React context) | Avoids re-render cascade on every canvas update |
| nexrender + aerender for final render | AE templates give highest quality output; `RENDER_MOCK=true` skips it in dev |
| Supabase RLS on all tables | Row-level security — users can only access their own data |
| `studio-canvas-stage.ts` global stage ref | Allows snapshot/export from any component without prop-drilling |
| Dynamic import for ImageEditorCanvas | Konva cannot run on server — `ssr: false` prevents SSR crash |
| `dev-mock-project.ts` | Dev POST mock; `dev-project` id skips load/save in studio editors |
---
## 🚀 Production-Ready Checklist
| Item | Status |
|---|---|
| `next.config.mjs``output: 'standalone'` (Docker) | ✅ |
| `app/sitemap.ts``/`, `/video-maker`, `/image-maker`, `/templates`, `/pricing` | ✅ |
| `app/robots.ts` — allow public; disallow `/dashboard`, `/studio`, `/api` | ✅ |
| Page metadata via `createPageMetadata` (public routes + studio layouts) | ✅ |
| `app/pricing/page.tsx` — dedicated pricing route for SEO/sitemap | ✅ |
| `app/error.tsx` — error boundary with reload | ✅ |
| `app/not-found.tsx` — 404 with home CTA | ✅ |
| `npx tsc --noEmit` clean | ✅ (re-run before deploy) |
| `.env.local` + Supabase migrations | ⬜ Operator setup |
| `NEXT_PUBLIC_SITE_URL` set to production domain | ⬜ Required for sitemap/OG URLs |
---
## 🔑 Environment Variables Checklist
| Variable | Status | Where to get it |
|---|---|---|
| `NEXT_PUBLIC_SUPABASE_URL` | ⬜ Not set | Supabase → Settings → API |
| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | ⬜ Not set | Supabase → Settings → API |
| `SUPABASE_SERVICE_ROLE_KEY` | ⬜ Not set | Supabase → Settings → API |
| `STRIPE_SECRET_KEY` | ⬜ Not set | Stripe Dashboard → API Keys |
| `STRIPE_WEBHOOK_SECRET` | ⬜ Not set | Stripe → Webhooks → signing secret |
| `STRIPE_PRICE_PRO_MONTHLY` | ⬜ Not set | Stripe → Products → price ID |
| `STRIPE_PRICE_PRO_ANNUAL` | ⬜ Not set | Stripe → Products → price ID |
| `STRIPE_PRICE_BUSINESS_MONTHLY` | ⬜ Not set | Stripe → Products → price ID |
| `STRIPE_PRICE_BUSINESS_ANNUAL` | ⬜ Not set | Stripe → Products → price ID |
| `REMOVE_BG_API_KEY` | ⬜ Not set | remove.bg → API |
| `RENDER_WORKER_URL` | ✅ Default: `http://localhost:3355` | — |
| `RENDER_MOCK` | ✅ Default: `true` | Set to `false` when AE is configured |
| `NEXRENDER_TEMPLATE_SRC` | ⬜ Not set | Path to your `.aep` template file |
| `NEXRENDER_BINARY` | ⬜ Not set | Path to `aerender` executable |
---
## 📁 Key File Map (Quick Reference)
```
src/
├── app/
│ ├── page.tsx ← Landing page
│ ├── video-maker/page.tsx ← Video Maker product page
│ ├── image-maker/page.tsx ← Image Maker product page
│ ├── templates/page.tsx ← Templates gallery
│ ├── pricing/page.tsx ← Pricing (public SEO route)
│ ├── sitemap.ts / robots.ts ← SEO + crawler rules
│ ├── error.tsx / not-found.tsx ← Global error UI
│ ├── auth/page.tsx ← Sign in / Sign up
│ ├── dashboard/page.tsx ← User dashboard
│ ├── studio/
│ │ ├── video/new/page.tsx ← New video project onboarding
│ │ ├── video/[projectId]/page.tsx ← Video Creation Studio
│ │ ├── image/[projectId]/page.tsx ← Image Editor
│ │ └── trimmer/page.tsx ← Video Trimmer/Cropper
│ └── api/ ← All API routes
├── components/
│ ├── layout/ ← Navbar, Footer, SiteChrome
│ ├── sections/ ← Landing page sections
│ ├── studio/ ← Video Studio components
│ ├── image-editor/ ← Image Editor components
│ ├── trimmer/ ← Video Trimmer components
│ ├── dashboard/ ← Dashboard components
│ └── ui/ ← shadcn/ui (do not edit)
├── lib/
│ ├── studio-store.ts ← Video Studio Zustand store
│ ├── studio-types.ts ← Scene / Layer types
│ ├── image-editor-store.ts ← Image Editor Zustand store
│ └── supabase/ ← Supabase client helpers
├── hooks/ ← useCanvasKeyboard, useContainerSize, useIsMobile, etc.
└── workers/
└── ffmpeg-trim.worker.ts ← ffmpeg.wasm Web Worker
server/
├── render-worker.ts ← HTTP server (port 3355)
├── render-job-processor.ts ← nexrender job runner
└── nexrender-job-builder.ts ← builds AE job from scene JSON
supabase/
└── migrations/ ← SQL files, run in order in Supabase SQL Editor
```
---
## 📅 Session Log
| Date | What was done |
|---|---|
| 2026-05-21 | Full project scaffolded: all pages, studio modules, API routes, Supabase migrations, server render worker |
| 2026-05-21 | Fixed `next.config.mjs` — added COOP/COEP headers required for ffmpeg.wasm SharedArrayBuffer |
| 2026-05-21 | Created `PROJECT_MEMORY.md` — project brain for Cursor + Claude |
| 2026-05-21 | Fixed brand name in 4 files: `metadata.ts`, `DashboardSidebar.tsx`, `ProductsMegaMenu.tsx`, `Navbar.tsx` |
| 2026-05-21 | Discovered `ProductsMegaMenu` already fully built — moved from backlog to done |
| 2026-05-21 | Added `PricingCompareTable` with 5 feature sections matching Renderforest /subscription layout |
| 2026-05-21 | Scene thumbnails: `thumbnailUrl` on Scene, `updateSceneThumbnail`, `DraggableSceneItem` img preview |