A local-first browser controller for Twinkly Squares. It keeps the stock Twinkly firmware and coordinate map, so there is nothing to flash, open, or solder.
- Paint, erase, fill, and preview the entire matrix in real time
- Import still images, animated GIFs, and video with fit, sampling, saturation, contrast, gamma, and playback controls
- Turn a browser microphone into Spectrum, Bass Halo, or 3-Band Field visuals with sensitivity, smoothing, and live frequency meters
- Mirror a screen, window, or browser tab through the same media sampling and color-correction pipeline
- Run sixteen procedural 2D and particle effects with speed, intensity, and optional effect-specific controls
- Select curated palettes, build two-to-eight-stop gradients, and save custom palettes to the controller library
- Compose two effect layers with opacity and five blend modes
- Target the whole wall, a panel, a row, a column, or a custom rectangle; pin up to three additional 2D segments with mirroring, transpose, grouping, spacing, and offset transforms
- Save server-persisted scenes and timed playlists with eight transitions, including cut, crossfade, push, dissolve, wipe, shift, radial, and pixelate
- Capture up to 32 hand-built pixel frames, set each frame's hold time down to 25 ms, preview the loop, and bake it into controller movie storage
- See real scene thumbnails, exact browser-output previews, honest controller-local playback status, active-scene state, and playlist progress
- Organize scenes with folders, tags, favorites, search, filters, duplication, inline metadata editing, and merge-or-replace JSON backups
- Display scrolling text, a clock, and locally loaded fonts
- Schedule sleep, wake, brightness, stock-mode, and off actions
- Choose safe startup and stale-browser-frame behavior; unchanged startup and hold-last-frame remain the non-disruptive defaults
- Rotate the complete display to 0°, 90°, 180°, or 270°
- Control live brightness while custom frames are streaming
- Inspect advertised, measured, target, and delivered frame cadence plus relay gap, repeat, and missed-deadline telemetry
- Bake a finite effect, video clip, or static look into unused controller movie storage for browser-free playback without overwriting existing movies
- Integrate local tools through a versioned JSON API, OpenAPI document, CLI, Server-Sent Events, and a Home Assistant example
- Return to the original Twinkly animation at any time
The layout is read from the Twinkly controller at startup. This project has been physically tested with a 4×3, 768-pixel Twinkly Squares wall: 32×24 at 0°/180° and 24×32 at 90°/270°.
Requires Python 3.11 or newer. Node 18 or newer is optional; npm is only used
as a convenient command runner and test runner.
cp config.example.json config.jsonEdit config.json and set the private IPv4 address of your Twinkly controller:
{
"deviceIp": "192.168.1.100"
}Then start the app:
npm startOr without Node:
python3 server.pyOn macOS, you can also double-click scripts/start.command.
Open http://127.0.0.1:4312. Press Control-C to stop;
a graceful shutdown returns the panel to its saved Twinkly animation.
Scenes, playlists, palettes, automations, and runtime policy are stored in
.squares/ beside the controller. That directory and config.json are
ignored by Git.
The versioned local API is documented in docs/INTEGRATIONS.md. A few examples:
./scripts/squaresctl status
./scripts/squaresctl brightness 25
./scripts/squaresctl rotate 270
./scripts/squaresctl off
./scripts/squaresctl stockThe live OpenAPI document is served at http://127.0.0.1:4312/openapi.json.
Environment variables override the defaults:
| Variable | Purpose | Default |
|---|---|---|
TWINKLY_IP |
Twinkly controller IPv4 address | config.json |
HOST |
Web server bind address | 127.0.0.1 |
PORT |
Web server port | 4312 |
SQUARES_CONFIG |
Alternate configuration file | ./config.json |
SQUARES_LIBRARY |
Alternate scene/playlist file | ./.squares/library.json |
SQUARES_AUTOMATIONS |
Alternate automation file | ./.squares/automations.json |
SQUARES_RUNTIME_POLICY |
Alternate startup/frame-loss policy file | ./.squares/runtime.json |
ALLOW_UNAUTHENTICATED_LAN |
Explicitly allow a non-loopback bind | unset |
From the project directory:
./scripts/install-macos-service.shThis installs a user LaunchAgent, starts the controller at login, and keeps it running after a crash. Remove it with:
./scripts/uninstall-macos-service.shThe server has no authentication and therefore binds only to 127.0.0.1 by
default. A non-loopback bind is refused unless you make the risk explicit:
HOST=0.0.0.0 ALLOW_UNAUTHENTICATED_LAN=1 npm startUse that only on a trusted, firewalled home network. Never port-forward port 4312 or expose it to the internet. The app also rejects public IP addresses as panel targets. See SECURITY.md.
npm testThe current suite contains 49 Python and 67 browser-model tests. It covers device protocol behavior, coordinate mapping, brightness, rotation, state synchronization, persistence, scheduling, API validation, palettes, zones, blending, transitions, effects, audio analysis, live-input rendering, media controls, scene organization, playlists, pixel clips, runtime failure policy, relay telemetry, and safe movie payloads.
The connected controller advertises 40 FPS but reports a measured 38.46 FPS clock. Realtime output therefore runs on an independent, deadline-aligned 37.5 FPS relay clock to leave narrow sampling headroom. The UI reports actual delivery gaps, repeated inputs, and missed deadlines; those host measurements do not claim that every frame lit physically. Controller-local movies use the controller's integer 38 FPS playback path and remove browser, HTTP, Python scheduling, and Wi-Fi cadence from ongoing playback. See docs/PERFORMANCE.md for the measurements.
The browser talks only to the local Python server. The server authenticates directly with the Twinkly controller over HTTP and streams RGB frames over the controller's local realtime protocol on UDP port 7777. The runtime uses the Python standard library and native browser APIs.
WLED is an excellent community-built LED firmware project. Its established product concepts—including presets and playlists, segments, palettes, transitions, effects, scheduling, and a JSON API—helped shape the roadmap for Squares Controller.
Squares Controller is an independent implementation for stock Twinkly hardware. It does not include or modify WLED firmware, source code, web UI assets, or branding, and it is not affiliated with the WLED or Twinkly projects. WLED is licensed under EUPL-1.2; Squares Controller remains MIT licensed. See NOTICE.md for the durable attribution statement.
MIT