| adapters | ||
| auth | ||
| controllers | ||
| core | ||
| editor | ||
| library | ||
| .containerignore | ||
| .gitignore | ||
| app.js | ||
| function-registry.js | ||
| index.html | ||
| init-controls.js | ||
| input-adapter.js | ||
| key.html | ||
| library.html | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| register-functions.js | ||
| register.html | ||
| server.js | ||
| storage.js | ||
| styles.css | ||
pictures
A tool for composing images with blend modes, z-index manipulation, and keyboard controls. Drag images into the canvas, arrange them with gestures, apply blend modes, and export your compositions.
Architecture
Frontend
- index.html - Main workspace interface
- app.js - Core application logic, keyboard controls, image manipulation
- styles.css - Minimal styling (no rounded corners, clean aesthetic)
- library.html - Image management interface with editing capabilities
Backend
- server.js - Express server serving static files and handling image operations
- storage.js - Storage abstraction layer supporting local filesystem or S3-compatible storage
- package.json - Node.js dependencies
Data Storage
- localStorage - Browser-based storage for spaces and image paths
- Storage backend - Supports local filesystem or S3-compatible storage (configured via environment variables)
Setup
-
Install dependencies:
npm install -
Configure storage backend (optional):
- The app defaults to local storage
- For S3 storage, set environment variables for your S3-compatible service
-
Start the server:
npm start -
Open
http://localhost:3030in your browser
Adding Images
Drag and Drop
Simply drag images from your file manager directly into the browser window. You can drag multiple images at once! They'll be automatically uploaded and available for use.
The app automatically loads available images on startup and whenever you refresh the page.
Usage
Workspace Controls
Image Loading
- n - Load random collection of images (based on photo count set in space)
Image Manipulation
- Click an image to focus it (black border appears)
- Drag images to reposition them
- Scroll on focused image - Scale image up/down from center
- Shift + Scroll - Normal page scrolling (when canvas exceeds viewport)
- Shift + + or Shift + = - Scale all images up by 10% (from their centers)
- Shift + - or Shift + _ - Scale all images down by 10% (from their centers)
- r - Randomize positions of all images
Blend Modes
- b - Cycle blend mode on focused image
- shift + b - Randomize blend modes for all images
Available blend modes: normal, multiply, screen, overlay, darken, lighten, color-dodge, color-burn, hard-light, soft-light, difference, exclusion, hue, saturation, color, luminosity
Export
- e - Export workspace as PNG (preserves blend modes and z-index layering)
Timeline
- t - Toggle timeline mode (navigate through state history)
- Scroll (in timeline mode) - Navigate backward/forward through states
- Arrow keys (in timeline mode) - Navigate backward/forward through states
- Visual indicator shows current position (e.g., "TIMELINE 5/23")
The timeline automatically records state changes during your session. Press t to enter timeline mode, then use scroll or arrow keys to navigate through your composition history. The timeline preserves all image positions, sizes, blend modes, and z-index values.
Navigation
- ← / → - Cycle through images (change focus)
- Escape - Unfocus current image
- Click outside workspace to unfocus
Image Management (library.html)
Access via the "library" link in the workspace or navigate directly to /library or library.html. This is the primary interface for managing your image collection.
Grid View
- Instagram-style grid showing all images
- Click any image to open in full-screen modal
Image Editing Modal
- ✎ (pencil icon) - Toggle edit mode
- When enabled: scroll to zoom, click+drag to pan, crop overlay appears
- Crop handles on edges/corners for resizing
- Drag crop area to reposition
- × (close) - Close modal
- save - Save edits (replaces original file with cropped/edited version)
Editing Features
- Scroll - Zoom in/out (centers on cursor position)
- Click + Drag - Pan around zoomed image
- Crop Overlay - Drag edges/corners to resize, drag center to reposition
- All edits are gesture-based (no sliders)
Technical Details
Image Storage
- Supports local filesystem or S3-compatible storage backends
- Image paths are cached in browser localStorage
- Server provides
/api/imagesendpoint to list all images - Server provides
/api/uploadendpoint for drag-and-drop uploads - Server provides
/api/images/:filenamePUT endpoint for updating images - Server provides
/api/images/:filenameDELETE endpoint for deletion - Thumbnails are automatically generated and stored alongside originals
Space Management
- Spaces are stored in browser localStorage as JSON
- Each space contains: id, name, width, height, photoCount, createdAt
- Multiple spaces can be created and switched between
Export Functionality
- Uses manual canvas compositing (not html2canvas) to preserve blend modes
- Maps CSS blend modes to canvas
globalCompositeOperation - Renders images in z-index order
- Exports at exact workspace dimensions
Image Transformations
- Images can be scaled, panned, and cropped
- Transform state is maintained per image
- Crop calculations account for zoom/pan transforms
- Saved edits replace original files
File Structure
blender/
├── index.html # Main workspace interface
├── library.html # Image management interface
├── app.js # Core application logic
├── styles.css # Styling
├── server.js # Express server
├── storage.js # Storage abstraction (local/S3)
├── package.json # Dependencies
└── README.md # This file
Keyboard Shortcuts Summary
Command Palette
| Key | Action |
|---|---|
? or / or Ctrl/Cmd + k |
Open command palette |
Image Loading
| Key | Action |
|---|---|
n |
Load random images (uses photo count from space settings) |
Image Manipulation
| Key | Action |
|---|---|
Click |
Focus an image (black border appears) |
Drag |
Reposition focused image |
Scroll (on focused image) |
Scale image up/down from center |
Shift + Scroll |
Normal page scrolling (when canvas exceeds viewport) |
Shift + + or Shift + = |
Scale all images up by 10% (from their centers) |
Shift + - or Shift + _ |
Scale all images down by 10% (from their centers) |
r |
Randomize positions of all images |
Image Navigation
| Key | Action |
|---|---|
← / → |
Cycle through images (change focus) |
Escape |
Unfocus current image |
| Click outside canvas | Unfocus current image |
Blend Modes
| Key | Action |
|---|---|
b |
Cycle blend mode on focused image |
Shift + b |
Randomize blend modes for all images |
Available blend modes: normal, multiply, screen, overlay, darken, lighten, color-dodge, color-burn, hard-light, soft-light, difference, exclusion, hue, saturation, color, luminosity
Z-Index (Layering)
| Key | Action |
|---|---|
↑ |
Move focused image up on z-axis (bring forward) |
↓ |
Move focused image down on z-axis (send backward) |
Shift + ↑ |
Randomize z-index for all images |
Export
| Key | Action |
|---|---|
e |
Export workspace as PNG (preserves blend modes and z-index layering) |
Timeline
| Key | Action |
|---|---|
t |
Toggle timeline mode (enter/exit state history navigation) |
Scroll (in timeline mode) |
Navigate backward/forward through states |
↑ / ↓ (in timeline mode) |
Navigate backward/forward through states |
← / → (in timeline mode) |
Navigate backward/forward through states |
The timeline automatically records every state change during your session (image additions, deletions, position changes, blend mode changes, etc.). When you enter timeline mode, a visual indicator shows your current position in the timeline. Navigate through states to see how your composition evolved over time.
Control System Architecture
The app uses a modular control system that supports keyboard, MIDI, gamepad, and OSC inputs through a unified architecture:
InputAdapter (normalizes all inputs)
↓
ControlMapper (maps inputs → functions)
↓
FunctionRegistry (executes functions)
MIDI Control (Continuous & Discrete)
Continuous controls (CC knobs, gamepad axes, OSC faders) map to parameters, while discrete controls (notes, buttons, keys) map to functions.
Setup MIDI Mappings
- Open the Control Palette (
?or/orCtrl/Cmd + k) - Switch to the Screensaver tab
- Click any "map" button next to:
- Tempo (BPM) - Maps a MIDI CC knob to control playback speed
- Play/Stop buttons - Maps MIDI notes to start/stop the screensaver
- Function probability sliders - Maps MIDI CC knobs to control how often each function triggers
Mapping Process
- Click a "map" button - it will pulse red and show "learning..."
- For CC mappings: Move the MIDI knob/fader you want to assign
- For Note mappings: Press the MIDI note/pad you want to assign
- The mapping is saved automatically to localStorage
Features
- Universal - Works with any MIDI controller
- Live updates - CC changes update parameters in real-time
- Visual feedback - See all current mappings at the bottom of the Screensaver tab
- Automatic scaling - CC values (0-127) automatically scale to parameter ranges
- Tempo: 40-240 BPM
- Probability: 0-100%
- Extensible - Easy to add new parameter mappings for any feature
How It Works
MIDI CC events flow through InputAdapter → ControlMapper (with value scaling) → FunctionRegistry (with scaled parameter). This means any continuous control (not just MIDI) can map to any parameter, making the system highly modular and reusable.
The screensaver runs on a tempo-based clock and probabilistically triggers functions on each tick. With MIDI control, you can:
- Adjust tempo in real-time for faster/slower chaos
- Control individual function probabilities to shape the behavior
- Start/stop the screensaver with notes/pads instead of clicking buttons
Future Enhancements
- Multiplayer support with shared cursors and workspaces
- Real-time collaboration
- More advanced image editing tools
- OSC support
- Video & text
- Export formats beyond PNG