An interactive art installation where visitors can customize and plant virtual flowers that appear in real-time on a large display screen.
This project creates an immersive digital garden experience for art shows and exhibitions. Visitors scan a QR code, customize a flower on their mobile device, and watch it bloom instantly in the shared virtual garden displayed on a projector or large screen.
- Real-time synchronization between mobile devices and display screen via WebSockets
- Persistent garden state - flowers survive server restarts (PostgreSQL database)
- 6 flower types with full customization (color, leaves, petals)
- High performance - handles thousands of flowers at 60fps using PixiJS WebGL
- Flat/minimalist design - modern aesthetic optimized for projection
- Mobile-first UI - smooth touch interactions with arrow navigation
- Rate limiting - prevents spam (1 flower per user every 5 seconds)
wallflower/
├── packages/
│ ├── shared/ # TypeScript types, Zod schemas, constants
│ ├── backend/ # Node.js + Express + Socket.io + Prisma
│ ├── display/ # React + PixiJS garden renderer
│ └── mobile/ # React + Tailwind customizer
- Package Manager: pnpm
- Language: TypeScript
- Backend: Express, Socket.io, Prisma, PostgreSQL
- Display: React, PixiJS v8 (WebGL), Zustand, Socket.io-client
- Mobile: React, Tailwind CSS, Framer Motion, Socket.io-client
🐳 Option 1: Docker (Recommended - Easiest)
Quick deployment with everything included:
# 1. Configure environment
cp .env.docker .env
# Edit .env with your IP/domain
# 2. Deploy with one command
./scripts/docker-deploy.sh
# Or manually:
docker-compose up -dSee Docker Deployment Guide for details.
💻 Option 2: Local Development
- Node.js 20+
- pnpm 8+
- PostgreSQL 15+ (local or cloud instance)
- Docker (for Option 1)
- Clone and install dependencies:
cd wallflower
pnpm install- Set up environment variables:
# Backend
cp packages/backend/.env.example packages/backend/.env
# Edit packages/backend/.env with your PostgreSQL connection string
# Display
cp packages/display/.env.example packages/display/.env
# Mobile
cp packages/mobile/.env.example packages/mobile/.env- Set up the database:
pnpm db:migrateThis creates the PostgreSQL database schema using Prisma migrations.
Run all services in parallel:
pnpm devOr run individually:
# Backend server (port 3001)
pnpm backend:dev
# Display screen (port 5173)
pnpm display:dev
# Mobile customizer (port 5174)
pnpm mobile:dev- Open display at
http://localhost:5173on your projector/large screen - Scan the QR code with your phone, or open
http://localhost:5174 - Customize your flower (type, color, leaves, petals)
- Click "Plant Flower"
- Watch it appear on the display screen with a growing animation!
-
Backend: Railway or Render ($7-10/month)
- Automatic WebSocket support
- Built-in PostgreSQL
- Environment variables management
-
Frontends: Vercel (free tier)
- Deploy display and mobile as separate projects
- Automatic deployments from GitHub
- Global CDN included
# Build all packages
pnpm build
# Backend
cd packages/backend && pnpm build && pnpm start
# Display
cd packages/display && pnpm build
# Mobile
cd packages/mobile && pnpm build# Backend
DATABASE_URL=postgresql://...
PORT=3001
CORS_ORIGIN=https://display.yourapp.com,https://customize.yourapp.com
MAX_FLOWERS=10000
# Display
VITE_BACKEND_URL=wss://api.yourapp.com
VITE_MOBILE_URL=https://customize.yourapp.com
# Mobile
VITE_BACKEND_URL=wss://api.yourapp.com# Create a new migration
cd packages/backend
npx prisma migrate dev --name your_migration_name
# Push schema changes without migration
pnpm db:push
# Open Prisma Studio (database GUI)
pnpm db:studio
# Generate Prisma client (after schema changes)
cd packages/backend
npx prisma generateContains TypeScript types, Zod validation schemas, and constants used across all packages:
types/- FlowerData, SocketEvents, Garden typesschemas/- Zod validation schemasconstants/- Flower types, colors, garden config
Node.js server with WebSocket support:
services/garden-placement.ts- Poisson disc placement algorithmservices/flower-service.ts- Database CRUD operationssocket/socket-manager.ts- WebSocket orchestrationsocket/handlers/- Mobile and display event handlers
React + PixiJS garden renderer:
pixi/GardenRenderer.ts- Main WebGL rendering enginepixi/layers/- Background, Flower, and Particle layerspixi/FlowerSprite.ts- Individual flower spritecomponents/Garden.tsx- React wrapper for PixiJScomponents/QRCodeDisplay.tsx- QR code overlay
React + Tailwind customizer:
components/Customizer.tsx- Main wizard containercomponents/steps/- Individual customization stepshooks/useCustomizer.ts- Customization state managementsocket/mobile-socket.ts- WebSocket client
- Concurrent users: 200+
- Total flowers: 10,000 (configurable limit)
- Display FPS: Stable 60fps with 2,000+ flowers
- Latency: <200ms from mobile submit to display render
- PixiJS WebGL - Hardware-accelerated rendering
- Spatial hashing - O(1) collision detection
- Texture atlasing - Single draw call for all flowers
- Object pooling - Reuse sprite instances
- Rate limiting - Prevent server overload
- Check PostgreSQL is running
- Verify DATABASE_URL in
.env - Run
pnpm db:migrateto create schema
- Check WebSocket connection (green indicator in top-right)
- Verify VITE_BACKEND_URL in
.env - Check browser console for errors
- Ensure backend is running
- Check VITE_BACKEND_URL matches backend address
- Verify CORS_ORIGIN includes mobile URL
- Adjust PLACEMENT_MIN_DISTANCE in backend
.env - Reduce MAX_FLOWERS if garden is too crowded
All packages support HMR - changes reflect instantly without refresh.
# WARNING: Deletes all data
cd packages/backend
npx prisma migrate resetOpen browser DevTools → Network → WS → Click connection → Messages
Display FPS shown in browser DevTools Performance tab.
- Add to
packages/shared/src/constants/flower-types.ts - Create texture in
packages/display/public/textures/ - Update TextureManager to load new texture
Edit packages/shared/src/constants/customization.ts - PRESET_COLORS array
Modify packages/shared/src/constants/garden.ts - GARDEN_CONFIG values
MIT
Built for interactive art installations. Designed to handle large crowds at exhibitions and public displays.
Need help? Check the /docs folder for detailed API documentation and deployment guides.