A Convex-powered application for designing and controlling LED light displays. Create complex lighting sequences on a 3D mesh visualization before deploying them to your actual hardware.
Effect Sim allows you to:
- Visualize your space - Import a 3D model of your garden, house, or any space (created with tools like Polycam)
- Design light layouts - Place LED strings on your 3D mesh with precise positioning
- Create sequences - Build complex lighting animations using a timeline-based sequencer
- Control hardware - Deploy your sequences to actual LED strings via a headless runtime
- Organize with playlists - Chain multiple sequences together for continuous playback
- π¨ 3D Visualization - View your lighting design in a 3D environment with day/night mode
- π¬ Timeline Sequencer - Create animations using a familiar timeline interface (similar to video editing software)
- π‘ Effect Library - Built-in effects like rainbow, fire, comet, sparkle, fireflies, and more
- π Virtual Strings - Combine multiple strings or select segments to act as a single string
- π Playlists - Chain sequences together for continuous playback
- π Switch Control - Control smart plugs/switches alongside your lights
- π― Real-time Preview - See your effects play out in real-time in the 3D viewer
- π Auto-sync - Changes sync automatically across multiple instances via Convex
- π Hardware Runtime - Headless runtime for deploying to actual hardware
- Frontend: React 19, Vite, TypeScript
- Backend: Convex (serverless backend)
- State Management: MobX (local-first with Convex sync)
- UI: Mantine
- 3D: Three.js, React Three Fiber, Drei
- Layout: FlexLayout (docking panels)
- Package Manager: Bun
- Hardware Runtime: React Nil (headless React)
- Bun (package manager and runtime)
- Convex CLI - Install with
npm install -g convex - Node.js (for Convex CLI if not using Bun)
git clone <repository-url>
cd effect-sim
bun installIf you haven't already, create a Convex account and initialize your project:
convex devThis will:
- Create a new Convex project (or connect to existing one)
- Generate the necessary configuration files
- Start the Convex dev server
Note: The Convex dev server should be kept running. The project rules specify that both Convex dev and Vite dev servers should be running at all times.
The project uses separate commands for frontend and backend. You'll need to run both:
Terminal 1 - Convex Backend:
convex devTerminal 2 - Frontend:
bun run dev:frontendOr use the combined command (runs both in parallel):
bun run devThe frontend will open automatically at http://localhost:5173 (or your configured Vite port).
- When you first load the app, you'll see a welcome screen
- Click "Create New Project" and give it a name
- Start adding strings, creating sequences, and building your lighting display!
effect-sim/
βββ convex/ # Convex backend code
β βββ schema.ts # Database schema definitions
β βββ functions.ts # Server functions (minimal - most logic is client-side)
βββ src/ # Frontend React application
β βββ common/ # Shared frontend code
β β βββ models/ # MobX models (UI-specific)
β βββ ... # React components and UI code
βββ shared/ # Code shared between frontend and backend
β βββ models/ # Shared MobX models (data layer)
βββ hardware-interface-runtime/ # Headless runtime for hardware control
β βββ models/ # Runtime-specific models
β βββ updateAndRestart.ts # Auto-update logic
βββ public/ # Static assets (3D models, etc.)
Effect Sim uses MobX for state management with a custom sync layer to Convex. This provides:
- Instant updates - Changes appear immediately in the UI
- Optimistic updates - No waiting for server round-trips
- Fine-grained reactivity - Only components using changed data re-render
- Automatic syncing - Changes sync to Convex in the background
The architecture uses:
- Shared Models (
shared/models/) - Pure data models with no UI dependencies - UI Models (
src/common/models/) - Models that can contain UI-specific state (mouse positions, element IDs, etc.) - TableSyncer - Automatically syncs MobX models to/from Convex tables
Effects are React components that define lighting animations. They:
- Receive props for configuration (speed, size, intensity, color, etc.)
- Use
useEffectFramehook to receive frame timing information - Can access the current frame ratio (0-1) within their event duration
- Are shared between the UI preview and hardware runtime
Example effects: rainbow, fire, comet, sparkle, fireflies, setColor, twinkle
Nodes represent elements in your lighting setup:
- String Nodes - LED strings with IP address, port, LED count, and 3D path
- Virtual String Nodes - Combinations of string segments that act as one
- Switch Nodes - Smart plugs/switches for controlling power
- Folder Nodes - Organizational containers for grouping nodes
- Sequences - Timeline-based animations with tracks and events
- Tracks - Horizontal rows in the sequencer (like audio/video tracks)
- Events - Effect instances placed on tracks with start/end frames
- Playlists - Ordered lists of sequences that play continuously
The HWIR is a headless process that runs on a separate machine (Mac mini, Raspberry Pi, etc.) to control your actual hardware.
bun run hwirThe CLI will prompt you to select a project and playlist.
# Normal startup (always prompts)
bun run hwir
# Specify project/playlist directly (skips prompts)
bun run hwir -p <projectId> -l <playlistId>Enable automatic updates to keep HWIR up-to-date:
# Enable auto-updates
export HWIR_AUTO_UPDATE=true
bun run hwir
# Or on Windows PowerShell
$env:HWIR_AUTO_UPDATE="true"
bun run hwirWhen enabled:
- Checks git for updates every 1 minute
- Automatically pulls, installs deps, and restarts
- Preserves your project/playlist selection across restarts
- Only updates when working directory is clean
For production use on macOS, you can set up a launch agent:
# Install launch agent
./install-launch-agent.sh
# Uninstall launch agent
./uninstall-launch-agent.shSee hardware-interface-runtime/README.md for more details.
# Development
bun run dev # Run both frontend and backend
bun run dev:frontend # Frontend only (Vite)
bun run dev:backend # Backend only (Convex)
# Hardware Runtime
bun run hwir # Run hardware interface runtime
# Testing
bun run test # Run tests
bun run dev:test # Run tests in watch mode
# Type Checking
bun run typecheck # Type check the entire project
# Linting
bun run lint # Check for linting errors
bun run lint:fix # Auto-fix linting errors- Prefer short, focused functions (β€ 20 lines)
- Use early returns / guard clauses
- Prefer
constby default - Use descriptive naming (booleans prefixed with
is,has,can,should) - Inline event handlers in JSX (avoid hoisting unless reused)
- Push Convex queries/mutations down into leaf components
- Use React Contexts to avoid prop drilling
See .cursor/rules/my-project-rules.mdc and project rules for more details.
- No authentication - Currently open (add auth if deploying publicly)
- Minimal server code - Most logic is client-side with MobX
- Single mutation - All changes go through
applyOperationsmutation - Shared code -
/sharedcontains code used by both frontend and backend - React Nil - Hardware runtime uses React without DOM
The app supports GLB/GLTF 3D models. You can:
- Create models using Polycam (LiDAR scanning on iPhone)
- Optimize in Blender (reduce file size)
- Place them in the
public/directory - Load them in your project
This is a personal project, but contributions and suggestions are welcome! Some areas that could use improvement:
- Authentication/authorization
- Undo/redo functionality
- More effect types
- Better 3D model import/editing
- True local-first with CRDTs/OT
- Client-side Convex IDs
Apache License 2.0 - See LICENSE.txt for details.
Built with:
- Convex - Backend as a service
- MobX - State management
- Mantine - UI components
- React Three Fiber - 3D rendering
- FlexLayout - Docking panels
- React Nil - Headless React
Note: This project was built for controlling Christmas lights displays, but can be adapted for any LED lighting project!
