@wavegrid/canvas 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +7 -0
- package/README.md +39 -0
- package/esm/index.js +1 -0
- package/esm/server.js +68 -0
- package/esm/ui.js +1196 -0
- package/index.d.ts +1 -0
- package/index.js +5 -0
- package/package.json +47 -0
- package/server.d.ts +3 -0
- package/server.js +74 -0
- package/ui.d.ts +1 -0
- package/ui.js +1199 -0
package/LICENSE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @wavegrid/canvas
|
|
2
|
+
|
|
3
|
+
<p align="center" width="100%">
|
|
4
|
+
<img height="250" src="https://raw.githubusercontent.com/constructive-io/constructive/refs/heads/main/assets/outline-logo.svg" />
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center" width="100%">
|
|
8
|
+
<a href="https://github.com/constructive-io/Illuminate/actions/workflows/ci.yml">
|
|
9
|
+
<img height="20" src="https://github.com/constructive-io/Illuminate/actions/workflows/ci.yml/badge.svg" />
|
|
10
|
+
</a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
Artist-facing creative canvas for the 7×7 Illuminate installation. This is a creative instrument for **painting the sky with light** — not a technical control panel.
|
|
14
|
+
|
|
15
|
+
## Design Philosophy
|
|
16
|
+
|
|
17
|
+
- No technical language, no projector numbers, no OSC concepts
|
|
18
|
+
- Everything is fluid, playful, and expressive
|
|
19
|
+
- Feels like Procreate or TouchDesigner, not a lighting console
|
|
20
|
+
- Optimized for iPad touch interaction
|
|
21
|
+
|
|
22
|
+
## Modes
|
|
23
|
+
|
|
24
|
+
- **Paint** — Choose a color, touch/drag cannons to paint them
|
|
25
|
+
- **Gradient** — Pick colors, drag to create live gradients
|
|
26
|
+
- **Brush** — Adjustable size with soft falloff
|
|
27
|
+
- **Energy** — Single intensity slider for live performance
|
|
28
|
+
- **Scenes** — Visual color swatches, tap to apply
|
|
29
|
+
- **Motion** — Draw paths, light animates along them
|
|
30
|
+
- **Symmetry** — Mirror, radial, and kaleidoscope tools
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
pnpm dev
|
|
36
|
+
# → http://localhost:3001
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Connects to the simulator backend via WebSocket for state synchronization.
|
package/esm/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getCanvasHTML } from './ui';
|
package/esm/server.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import { WebSocket, WebSocketServer } from 'ws';
|
|
3
|
+
import { getCanvasHTML } from './ui';
|
|
4
|
+
const PORT = parseInt(process.env.PORT || '3001', 10);
|
|
5
|
+
const SIMULATOR_URL = process.env.SIMULATOR_URL || 'ws://localhost:3000';
|
|
6
|
+
const server = http.createServer((_req, res) => {
|
|
7
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
8
|
+
res.end(getCanvasHTML());
|
|
9
|
+
});
|
|
10
|
+
const wss = new WebSocketServer({ server });
|
|
11
|
+
let simulatorWs = null;
|
|
12
|
+
let reconnectTimer = null;
|
|
13
|
+
function connectToSimulator() {
|
|
14
|
+
try {
|
|
15
|
+
simulatorWs = new WebSocket(SIMULATOR_URL);
|
|
16
|
+
simulatorWs.on('open', () => {
|
|
17
|
+
console.log(' ✦ Connected to simulator');
|
|
18
|
+
});
|
|
19
|
+
simulatorWs.on('message', (data) => {
|
|
20
|
+
// Relay state from simulator to all canvas clients
|
|
21
|
+
const msg = data.toString();
|
|
22
|
+
wss.clients.forEach(client => {
|
|
23
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
24
|
+
client.send(msg);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
simulatorWs.on('close', () => {
|
|
29
|
+
console.log(' ✦ Simulator disconnected, reconnecting...');
|
|
30
|
+
scheduleReconnect();
|
|
31
|
+
});
|
|
32
|
+
simulatorWs.on('error', () => {
|
|
33
|
+
scheduleReconnect();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (_e) {
|
|
37
|
+
scheduleReconnect();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function scheduleReconnect() {
|
|
41
|
+
if (reconnectTimer)
|
|
42
|
+
return;
|
|
43
|
+
reconnectTimer = setTimeout(() => {
|
|
44
|
+
reconnectTimer = null;
|
|
45
|
+
connectToSimulator();
|
|
46
|
+
}, 2000);
|
|
47
|
+
}
|
|
48
|
+
wss.on('connection', (ws) => {
|
|
49
|
+
ws.on('message', (raw) => {
|
|
50
|
+
// Relay commands from canvas clients to simulator
|
|
51
|
+
if (simulatorWs && simulatorWs.readyState === WebSocket.OPEN) {
|
|
52
|
+
simulatorWs.send(raw);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
server.listen(PORT, '0.0.0.0', () => {
|
|
57
|
+
console.log('');
|
|
58
|
+
console.log(' ╭──────────────────────────────────────╮');
|
|
59
|
+
console.log(' │ Illuminate · Canvas │');
|
|
60
|
+
console.log(' │ painting the sky with light │');
|
|
61
|
+
console.log(' ╰──────────────────────────────────────╯');
|
|
62
|
+
console.log('');
|
|
63
|
+
console.log(` → http://localhost:${PORT}`);
|
|
64
|
+
console.log(` → Simulator: ${SIMULATOR_URL}`);
|
|
65
|
+
console.log('');
|
|
66
|
+
connectToSimulator();
|
|
67
|
+
});
|
|
68
|
+
export { server };
|