add-feature
Guide for implementing a new feature in ProAnimate. Covers types, store, service, panel, canvas layer, Remotion layer, server route, and tab registration.
SKILL.mdAutoAnimation/.claude/skills/add-feature/SKILL.md
GitHubAdd Feature to ProAnimate
Implement a complete feature end-to-end in the ProAnimate animation studio. This skill walks through every layer from types to UI to export.
Steps
Define types in
src/types/<featureName>.ts- Export interfaces for the feature's data model
- Follow the pattern in
src/types/artCurves.ts(simple interfaces with id, position, scale, opacity, rotation, zIndex, visible, startFrame, endFrame) - Re-export from
src/types/index.tsif the types are used broadly
Create Zustand store in
src/stores/use<FeatureName>Store.ts- Use
createfromzustandwithimmermiddleware - Define state interface with data arrays and CRUD actions
- Use
Date.now()for unique IDs (e.g.,feature-${Date.now()}) - Read timeline state via
useTimelineStore.getState()for frame ranges - Add barrel export in
src/stores/index.ts:export { use<FeatureName>Store } from './use<FeatureName>Store'
- Use
Create service in
src/services/<featureName>.ts- Business logic, generation, processing, or API calls
- Keep pure functions separate from store mutations
- For AI features, call server endpoints via fetch to
/api/<feature-name>
Create panel in
src/components/panels/<FeatureName>Panel.tsx- React component that connects to the store
- Use Tailwind CSS for styling (dark theme:
bg-zinc-900,text-zinc-100) - Import store with
use<FeatureName>Store - Follow GlassPanel pattern if applicable
Create canvas layer in
src/components/canvas/<FeatureName>Layer.tsx- Render feature data on the main VideoCanvas
- Read from store, filter by
visibleand frame range (startFrame/endFrame) - Use
usePlaybackStorefor current frame - Position with
position: 'absolute'and layer's position/zIndex
Create Remotion export layer in
src/remotion/Remotion<FeatureName>Layer.tsx- Use
useFrame()from@/engine(NOT from 'remotion' directly) - Accept data as props (not from stores -- stores are read in VideoComposition and passed down)
- Filter items by
visible,startFrame,endFramevs current frame - Register in
src/remotion/VideoComposition.tsx:import { Remotion<FeatureName>Layer } from './Remotion<FeatureName>Layer' // Then render inside the composition JSX <Remotion<FeatureName>Layer data={props.<featureName>Data} />
- Use
Add server route (if needed) in
server/routes/<featureName>.ts- Create Express Router
- Import
requireAuthfrom../middleware/supabaseAuth.js - Mount in
server/index.ts:import <featureName>Routes from './routes/<featureName>' app.use('/api/<feature-name>', requireAuth, <featureName>Routes) - Add
aiRateLimitermiddleware for AI/expensive endpoints
Register tab in left panel
- Add tab ID to
LeftPanelBottomTabunion insrc/types/editor.ts - Add sub-tab entry in
src/constants/tabGroups.tsunder the appropriate group:{ id: '<tab-id>', label: 'Label', icon: 'IconName', description: 'Description' } - The panel component is rendered via lazy loading in the left panel layout based on the active tab ID
- Add tab ID to
Key Files
| Purpose | Path |
|---|---|
| Types | src/types/<featureName>.ts |
| Store | src/stores/use<FeatureName>Store.ts |
| Store barrel | src/stores/index.ts |
| Service | src/services/<featureName>.ts |
| Panel | src/components/panels/<FeatureName>Panel.tsx |
| Canvas layer | src/components/canvas/<FeatureName>Layer.tsx |
| Remotion layer | src/remotion/Remotion<FeatureName>Layer.tsx |
| VideoComposition | src/remotion/VideoComposition.tsx |
| Server route | server/routes/<featureName>.ts |
| Server mount | server/index.ts |
| Tab registration | src/constants/tabGroups.ts |
| Tab types | src/types/editor.ts |
Common Issues
- Store not updating UI: Ensure you use
immermiddleware and mutatestateinsideset()callbacks, not return new objects. - Canvas layer not visible: Check that
zIndexis set on the layer and does not conflict with other layers. - Remotion export blank: Verify the data is passed as props through
VideoComposition.tsx, not read from stores directly in the Remotion layer. - Tab not appearing: Must add the tab ID to both
LeftPanelBottomTabinsrc/types/editor.tsAND as a sub-tab insrc/constants/tabGroups.ts. - Server route 404: Ensure the route is mounted in
server/index.tsand the Vite proxy (/api->localhost:3001) is active.
Example
See ArtCurves as a complete reference implementation:
- Types:
src/types/artCurves.ts - Store:
src/stores/useArtCurveStore.ts - Service:
src/services/artCurveGenerator.ts - Panel:
src/components/panels/ArtCurvesPanel.tsx - Canvas:
src/components/canvas/ArtCurveLayer.tsx - Remotion:
src/remotion/RemotionArtCurveLayer.tsx