@agentdeck/bridge 0.1.0 → 0.2.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 +21 -0
- package/dist/adapters/claude-code.d.ts +11 -27
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +29 -123
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/codex-cli.d.ts +21 -0
- package/dist/adapters/codex-cli.d.ts.map +1 -0
- package/dist/adapters/codex-cli.js +53 -0
- package/dist/adapters/codex-cli.js.map +1 -0
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +13 -0
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/monitor.d.ts +34 -0
- package/dist/adapters/monitor.d.ts.map +1 -0
- package/dist/adapters/monitor.js +86 -0
- package/dist/adapters/monitor.js.map +1 -0
- package/dist/adapters/openclaw.d.ts +36 -2
- package/dist/adapters/openclaw.d.ts.map +1 -1
- package/dist/adapters/openclaw.js +329 -59
- package/dist/adapters/openclaw.js.map +1 -1
- package/dist/adapters/opencode-adapter.d.ts +48 -0
- package/dist/adapters/opencode-adapter.d.ts.map +1 -0
- package/dist/adapters/opencode-adapter.js +345 -0
- package/dist/adapters/opencode-adapter.js.map +1 -0
- package/dist/adapters/pty-adapter.d.ts +56 -0
- package/dist/adapters/pty-adapter.d.ts.map +1 -0
- package/dist/adapters/pty-adapter.js +143 -0
- package/dist/adapters/pty-adapter.js.map +1 -0
- package/dist/adb-reverse.d.ts +25 -0
- package/dist/adb-reverse.d.ts.map +1 -0
- package/dist/adb-reverse.js +129 -0
- package/dist/adb-reverse.js.map +1 -0
- package/dist/antigravity-local.d.ts +7 -0
- package/dist/antigravity-local.d.ts.map +1 -0
- package/dist/antigravity-local.js +153 -0
- package/dist/antigravity-local.js.map +1 -0
- package/dist/apme/adapters/claude-hook.d.ts +15 -0
- package/dist/apme/adapters/claude-hook.d.ts.map +1 -0
- package/dist/apme/adapters/claude-hook.js +85 -0
- package/dist/apme/adapters/claude-hook.js.map +1 -0
- package/dist/apme/adapters/claude-pty.d.ts +28 -0
- package/dist/apme/adapters/claude-pty.d.ts.map +1 -0
- package/dist/apme/adapters/claude-pty.js +88 -0
- package/dist/apme/adapters/claude-pty.js.map +1 -0
- package/dist/apme/adapters/timeline.d.ts +16 -0
- package/dist/apme/adapters/timeline.d.ts.map +1 -0
- package/dist/apme/adapters/timeline.js +66 -0
- package/dist/apme/adapters/timeline.js.map +1 -0
- package/dist/apme/classifier.d.ts +53 -0
- package/dist/apme/classifier.d.ts.map +1 -0
- package/dist/apme/classifier.js +266 -0
- package/dist/apme/classifier.js.map +1 -0
- package/dist/apme/claude-transcript-reader.d.ts +38 -0
- package/dist/apme/claude-transcript-reader.d.ts.map +1 -0
- package/dist/apme/claude-transcript-reader.js +127 -0
- package/dist/apme/claude-transcript-reader.js.map +1 -0
- package/dist/apme/collector.d.ts +108 -0
- package/dist/apme/collector.d.ts.map +1 -0
- package/dist/apme/collector.js +659 -0
- package/dist/apme/collector.js.map +1 -0
- package/dist/apme/dashboard-html.d.ts +9 -0
- package/dist/apme/dashboard-html.d.ts.map +1 -0
- package/dist/apme/dashboard-html.js +416 -0
- package/dist/apme/dashboard-html.js.map +1 -0
- package/dist/apme/http.d.ts +19 -0
- package/dist/apme/http.d.ts.map +1 -0
- package/dist/apme/http.js +210 -0
- package/dist/apme/http.js.map +1 -0
- package/dist/apme/hw-sampler.d.ts +30 -0
- package/dist/apme/hw-sampler.d.ts.map +1 -0
- package/dist/apme/hw-sampler.js +106 -0
- package/dist/apme/hw-sampler.js.map +1 -0
- package/dist/apme/index.d.ts +43 -0
- package/dist/apme/index.d.ts.map +1 -0
- package/dist/apme/index.js +75 -0
- package/dist/apme/index.js.map +1 -0
- package/dist/apme/outcome.d.ts +48 -0
- package/dist/apme/outcome.d.ts.map +1 -0
- package/dist/apme/outcome.js +232 -0
- package/dist/apme/outcome.js.map +1 -0
- package/dist/apme/recommend.d.ts +32 -0
- package/dist/apme/recommend.d.ts.map +1 -0
- package/dist/apme/recommend.js +41 -0
- package/dist/apme/recommend.js.map +1 -0
- package/dist/apme/runner.d.ts +94 -0
- package/dist/apme/runner.d.ts.map +1 -0
- package/dist/apme/runner.js +812 -0
- package/dist/apme/runner.js.map +1 -0
- package/dist/apme/settings.d.ts +65 -0
- package/dist/apme/settings.d.ts.map +1 -0
- package/dist/apme/settings.js +97 -0
- package/dist/apme/settings.js.map +1 -0
- package/dist/apme/store.d.ts +99 -0
- package/dist/apme/store.d.ts.map +1 -0
- package/dist/apme/store.js +911 -0
- package/dist/apme/store.js.map +1 -0
- package/dist/apme/tuner.d.ts +64 -0
- package/dist/apme/tuner.d.ts.map +1 -0
- package/dist/apme/tuner.js +297 -0
- package/dist/apme/tuner.js.map +1 -0
- package/dist/apme/types.d.ts +11 -0
- package/dist/apme/types.d.ts.map +1 -0
- package/dist/apme/types.js +10 -0
- package/dist/apme/types.js.map +1 -0
- package/dist/auth.d.ts +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +15 -5
- package/dist/auth.js.map +1 -1
- package/dist/bridge-core.d.ts +162 -0
- package/dist/bridge-core.d.ts.map +1 -0
- package/dist/bridge-core.js +627 -0
- package/dist/bridge-core.js.map +1 -0
- package/dist/check-deps.d.ts +3 -1
- package/dist/check-deps.d.ts.map +1 -1
- package/dist/check-deps.js +34 -13
- package/dist/check-deps.js.map +1 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1235 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex-auth.d.ts +10 -0
- package/dist/codex-auth.d.ts.map +1 -0
- package/dist/codex-auth.js +63 -0
- package/dist/codex-auth.js.map +1 -0
- package/dist/codex-output-parser.d.ts +21 -0
- package/dist/codex-output-parser.d.ts.map +1 -0
- package/dist/codex-output-parser.js +253 -0
- package/dist/codex-output-parser.js.map +1 -0
- package/dist/d200h/hid-protocol.d.ts +62 -0
- package/dist/d200h/hid-protocol.d.ts.map +1 -0
- package/dist/d200h/hid-protocol.js +124 -0
- package/dist/d200h/hid-protocol.js.map +1 -0
- package/dist/d200h/image-renderer.d.ts +36 -0
- package/dist/d200h/image-renderer.d.ts.map +1 -0
- package/dist/d200h/image-renderer.js +487 -0
- package/dist/d200h/image-renderer.js.map +1 -0
- package/dist/daemon-server.d.ts +19 -0
- package/dist/daemon-server.d.ts.map +1 -0
- package/dist/daemon-server.js +1168 -0
- package/dist/daemon-server.js.map +1 -0
- package/dist/daemon-ws-client.d.ts +82 -0
- package/dist/daemon-ws-client.d.ts.map +1 -0
- package/dist/daemon-ws-client.js +179 -0
- package/dist/daemon-ws-client.js.map +1 -0
- package/dist/daemon.d.ts +10 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +56 -0
- package/dist/daemon.js.map +1 -0
- package/dist/display-monitor.d.ts +25 -0
- package/dist/display-monitor.d.ts.map +1 -0
- package/dist/display-monitor.js +143 -0
- package/dist/display-monitor.js.map +1 -0
- package/dist/esp32-serial.d.ts +112 -0
- package/dist/esp32-serial.d.ts.map +1 -0
- package/dist/esp32-serial.js +502 -0
- package/dist/esp32-serial.js.map +1 -0
- package/dist/gateway-probe.d.ts +12 -0
- package/dist/gateway-probe.d.ts.map +1 -0
- package/dist/gateway-probe.js +39 -0
- package/dist/gateway-probe.js.map +1 -0
- package/dist/hook-migration.d.ts +2 -0
- package/dist/hook-migration.d.ts.map +1 -0
- package/dist/hook-migration.js +104 -0
- package/dist/hook-migration.js.map +1 -0
- package/dist/hook-server.d.ts +29 -0
- package/dist/hook-server.d.ts.map +1 -1
- package/dist/hook-server.js +366 -8
- package/dist/hook-server.js.map +1 -1
- package/dist/index.d.ts +20 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1304 -562
- package/dist/index.js.map +1 -1
- package/dist/log-stream.d.ts +26 -0
- package/dist/log-stream.d.ts.map +1 -0
- package/dist/log-stream.js +111 -0
- package/dist/log-stream.js.map +1 -0
- package/dist/logger.d.ts +9 -2
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +36 -5
- package/dist/logger.js.map +1 -1
- package/dist/mdns.d.ts +15 -1
- package/dist/mdns.d.ts.map +1 -1
- package/dist/mdns.js +143 -28
- package/dist/mdns.js.map +1 -1
- package/dist/mlx-probe.d.ts +14 -0
- package/dist/mlx-probe.d.ts.map +1 -0
- package/dist/mlx-probe.js +44 -0
- package/dist/mlx-probe.js.map +1 -0
- package/dist/model-catalog.d.ts +5 -3
- package/dist/model-catalog.d.ts.map +1 -1
- package/dist/model-catalog.js +45 -29
- package/dist/model-catalog.js.map +1 -1
- package/dist/modules/adb-module.d.ts +14 -0
- package/dist/modules/adb-module.d.ts.map +1 -0
- package/dist/modules/adb-module.js +36 -0
- package/dist/modules/adb-module.js.map +1 -0
- package/dist/modules/d200h-module.d.ts +43 -0
- package/dist/modules/d200h-module.d.ts.map +1 -0
- package/dist/modules/d200h-module.js +360 -0
- package/dist/modules/d200h-module.js.map +1 -0
- package/dist/modules/d200h-renderer.d.ts +7 -0
- package/dist/modules/d200h-renderer.d.ts.map +1 -0
- package/dist/modules/d200h-renderer.js +321 -0
- package/dist/modules/d200h-renderer.js.map +1 -0
- package/dist/modules/index.d.ts +23 -0
- package/dist/modules/index.d.ts.map +1 -0
- package/dist/modules/index.js +65 -0
- package/dist/modules/index.js.map +1 -0
- package/dist/modules/mdns-module.d.ts +12 -0
- package/dist/modules/mdns-module.d.ts.map +1 -0
- package/dist/modules/mdns-module.js +21 -0
- package/dist/modules/mdns-module.js.map +1 -0
- package/dist/modules/pixoo-module.d.ts +8 -0
- package/dist/modules/pixoo-module.d.ts.map +1 -0
- package/dist/modules/pixoo-module.js +24 -0
- package/dist/modules/pixoo-module.js.map +1 -0
- package/dist/modules/serial-module.d.ts +18 -0
- package/dist/modules/serial-module.d.ts.map +1 -0
- package/dist/modules/serial-module.js +47 -0
- package/dist/modules/serial-module.js.map +1 -0
- package/dist/modules/types.d.ts +39 -0
- package/dist/modules/types.d.ts.map +1 -0
- package/dist/modules/types.js +2 -0
- package/dist/modules/types.js.map +1 -0
- package/dist/ollama-probe.d.ts +13 -0
- package/dist/ollama-probe.d.ts.map +1 -0
- package/dist/ollama-probe.js +46 -0
- package/dist/ollama-probe.js.map +1 -0
- package/dist/opencode-client.d.ts +126 -0
- package/dist/opencode-client.d.ts.map +1 -0
- package/dist/opencode-client.js +181 -0
- package/dist/opencode-client.js.map +1 -0
- package/dist/output-parser.d.ts +3 -0
- package/dist/output-parser.d.ts.map +1 -1
- package/dist/output-parser.js +29 -3
- package/dist/output-parser.js.map +1 -1
- package/dist/passive-observer.d.ts +38 -0
- package/dist/passive-observer.d.ts.map +1 -0
- package/dist/passive-observer.js +632 -0
- package/dist/passive-observer.js.map +1 -0
- package/dist/pixoo/pixoo-bridge.d.ts +50 -0
- package/dist/pixoo/pixoo-bridge.d.ts.map +1 -0
- package/dist/pixoo/pixoo-bridge.js +280 -0
- package/dist/pixoo/pixoo-bridge.js.map +1 -0
- package/dist/pixoo/pixoo-camera.d.ts +80 -0
- package/dist/pixoo/pixoo-camera.d.ts.map +1 -0
- package/dist/pixoo/pixoo-camera.js +271 -0
- package/dist/pixoo/pixoo-camera.js.map +1 -0
- package/dist/pixoo/pixoo-client.d.ts +67 -0
- package/dist/pixoo/pixoo-client.d.ts.map +1 -0
- package/dist/pixoo/pixoo-client.js +335 -0
- package/dist/pixoo/pixoo-client.js.map +1 -0
- package/dist/pixoo/pixoo-font.d.ts +24 -0
- package/dist/pixoo/pixoo-font.d.ts.map +1 -0
- package/dist/pixoo/pixoo-font.js +121 -0
- package/dist/pixoo/pixoo-font.js.map +1 -0
- package/dist/pixoo/pixoo-renderer.d.ts +32 -0
- package/dist/pixoo/pixoo-renderer.d.ts.map +1 -0
- package/dist/pixoo/pixoo-renderer.js +696 -0
- package/dist/pixoo/pixoo-renderer.js.map +1 -0
- package/dist/pixoo/pixoo-settings.d.ts +10 -0
- package/dist/pixoo/pixoo-settings.d.ts.map +1 -0
- package/dist/pixoo/pixoo-settings.js +47 -0
- package/dist/pixoo/pixoo-settings.js.map +1 -0
- package/dist/pixoo/pixoo-sprites.d.ts +187 -0
- package/dist/pixoo/pixoo-sprites.d.ts.map +1 -0
- package/dist/pixoo/pixoo-sprites.js +926 -0
- package/dist/pixoo/pixoo-sprites.js.map +1 -0
- package/dist/pty-manager.d.ts +1 -1
- package/dist/pty-manager.d.ts.map +1 -1
- package/dist/pty-manager.js +36 -15
- package/dist/pty-manager.js.map +1 -1
- package/dist/session-aggregator.d.ts +41 -0
- package/dist/session-aggregator.d.ts.map +1 -0
- package/dist/session-aggregator.js +76 -0
- package/dist/session-aggregator.js.map +1 -0
- package/dist/session-focus-relay.d.ts +35 -0
- package/dist/session-focus-relay.d.ts.map +1 -0
- package/dist/session-focus-relay.js +127 -0
- package/dist/session-focus-relay.js.map +1 -0
- package/dist/session-registry.d.ts +88 -1
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/session-registry.js +222 -15
- package/dist/session-registry.js.map +1 -1
- package/dist/session-timeline-relay.d.ts +27 -0
- package/dist/session-timeline-relay.d.ts.map +1 -0
- package/dist/session-timeline-relay.js +124 -0
- package/dist/session-timeline-relay.js.map +1 -0
- package/dist/state-machine.d.ts +1 -0
- package/dist/state-machine.d.ts.map +1 -1
- package/dist/state-machine.js +14 -0
- package/dist/state-machine.js.map +1 -1
- package/dist/terminal-status.d.ts +28 -0
- package/dist/terminal-status.d.ts.map +1 -0
- package/dist/terminal-status.js +152 -0
- package/dist/terminal-status.js.map +1 -0
- package/dist/timeline-store.d.ts +22 -0
- package/dist/timeline-store.d.ts.map +1 -0
- package/dist/timeline-store.js +79 -0
- package/dist/timeline-store.js.map +1 -0
- package/dist/timeline-summarizer.d.ts +14 -0
- package/dist/timeline-summarizer.d.ts.map +1 -0
- package/dist/timeline-summarizer.js +154 -0
- package/dist/timeline-summarizer.js.map +1 -0
- package/dist/tts.d.ts +25 -0
- package/dist/tts.d.ts.map +1 -0
- package/dist/tts.js +99 -0
- package/dist/tts.js.map +1 -0
- package/dist/tui/ansi.d.ts +92 -0
- package/dist/tui/ansi.d.ts.map +1 -0
- package/dist/tui/ansi.js +181 -0
- package/dist/tui/ansi.js.map +1 -0
- package/dist/tui/dashboard.d.ts +35 -0
- package/dist/tui/dashboard.d.ts.map +1 -0
- package/dist/tui/dashboard.js +436 -0
- package/dist/tui/dashboard.js.map +1 -0
- package/dist/tui/gauge.d.ts +15 -0
- package/dist/tui/gauge.d.ts.map +1 -0
- package/dist/tui/gauge.js +82 -0
- package/dist/tui/gauge.js.map +1 -0
- package/dist/tui/renderer.d.ts +15 -0
- package/dist/tui/renderer.d.ts.map +1 -0
- package/dist/tui/renderer.js +758 -0
- package/dist/tui/renderer.js.map +1 -0
- package/dist/tui/screen.d.ts +27 -0
- package/dist/tui/screen.d.ts.map +1 -0
- package/dist/tui/screen.js +109 -0
- package/dist/tui/screen.js.map +1 -0
- package/dist/tui/terrarium.d.ts +96 -0
- package/dist/tui/terrarium.d.ts.map +1 -0
- package/dist/tui/terrarium.js +912 -0
- package/dist/tui/terrarium.js.map +1 -0
- package/dist/types.d.ts +4 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -2
- package/dist/types.js.map +1 -1
- package/dist/usage-api.d.ts +9 -2
- package/dist/usage-api.d.ts.map +1 -1
- package/dist/usage-api.js +224 -42
- package/dist/usage-api.js.map +1 -1
- package/dist/usage-event.d.ts +12 -0
- package/dist/usage-event.d.ts.map +1 -0
- package/dist/usage-event.js +78 -0
- package/dist/usage-event.js.map +1 -0
- package/dist/usage-tracker.d.ts +4 -0
- package/dist/usage-tracker.d.ts.map +1 -1
- package/dist/usage-tracker.js +17 -0
- package/dist/usage-tracker.js.map +1 -1
- package/dist/utility-proxy.d.ts +30 -0
- package/dist/utility-proxy.d.ts.map +1 -0
- package/dist/utility-proxy.js +217 -0
- package/dist/utility-proxy.js.map +1 -0
- package/dist/utils/project-name.d.ts +22 -0
- package/dist/utils/project-name.d.ts.map +1 -0
- package/dist/utils/project-name.js +72 -0
- package/dist/utils/project-name.js.map +1 -0
- package/dist/version-check.d.ts +26 -0
- package/dist/version-check.d.ts.map +1 -0
- package/dist/version-check.js +225 -0
- package/dist/version-check.js.map +1 -0
- package/dist/voice-assistant.d.ts +63 -0
- package/dist/voice-assistant.d.ts.map +1 -0
- package/dist/voice-assistant.js +406 -0
- package/dist/voice-assistant.js.map +1 -0
- package/dist/voice.d.ts +2 -0
- package/dist/voice.d.ts.map +1 -1
- package/dist/voice.js +26 -1
- package/dist/voice.js.map +1 -1
- package/dist/wake-word.d.ts +35 -0
- package/dist/wake-word.d.ts.map +1 -0
- package/dist/wake-word.js +225 -0
- package/dist/wake-word.js.map +1 -0
- package/dist/whisper-server-manager.d.ts +1 -1
- package/dist/whisper-server-manager.js +1 -1
- package/dist/wifi-config.d.ts +24 -0
- package/dist/wifi-config.d.ts.map +1 -0
- package/dist/wifi-config.js +84 -0
- package/dist/wifi-config.js.map +1 -0
- package/dist/ws-server.d.ts +12 -0
- package/dist/ws-server.d.ts.map +1 -1
- package/dist/ws-server.js +81 -3
- package/dist/ws-server.js.map +1 -1
- package/package.json +21 -13
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pixoo64 HTTP Client — direct REST API for Divoom Pixoo64 LED matrix.
|
|
3
|
+
*
|
|
4
|
+
* Zero dependencies: uses Node 18+ native fetch().
|
|
5
|
+
* All requests have 2s timeout and fail silently (display is non-critical).
|
|
6
|
+
*
|
|
7
|
+
* Frame format: 64×64 RGB = 12,288 bytes → base64 encoded.
|
|
8
|
+
*
|
|
9
|
+
* CRITICAL: PicID must be strictly incrementing — device silently ignores
|
|
10
|
+
* frames with non-sequential IDs (returns error_code:0 but doesn't update display).
|
|
11
|
+
* GetHttpGifId syncs counter; ResetHttpGifId resets to 0 (use sparingly — may crash firmware).
|
|
12
|
+
*/
|
|
13
|
+
import http from 'node:http';
|
|
14
|
+
import { debug } from '../logger.js';
|
|
15
|
+
// Pixoo's embedded HTTP server can't handle keep-alive connections properly
|
|
16
|
+
// (Node 19+ defaults to keepAlive:true). Force fresh TCP per request.
|
|
17
|
+
const pixooAgent = new http.Agent({ keepAlive: false, maxSockets: 1 });
|
|
18
|
+
const TAG = 'Pixoo';
|
|
19
|
+
const REQUEST_TIMEOUT_MS = 2000;
|
|
20
|
+
const PIC_ID_RESYNC_THRESHOLD = 250; // Re-sync before ~300 overflow
|
|
21
|
+
// Per-device static PicID — synced once and held forever (allows real-time streaming without loading screen)
|
|
22
|
+
const devicePicId = new Map();
|
|
23
|
+
/** Clear cached static PicID for a device (call when device reboots to re-sync). */
|
|
24
|
+
export function clearStaticPicId(ip) {
|
|
25
|
+
devicePicId.delete(ip);
|
|
26
|
+
debug(TAG, `Static PicID cleared for ${ip} — will re-sync on next push`);
|
|
27
|
+
}
|
|
28
|
+
// Gamma correction LUT: pow(v/255, 0.7) * 255 — boosts dark values for LED display
|
|
29
|
+
const gammaLUT = new Uint8Array(256);
|
|
30
|
+
for (let i = 0; i < 256; i++) {
|
|
31
|
+
gammaLUT[i] = Math.round(Math.pow(i / 255, 0.7) * 255);
|
|
32
|
+
}
|
|
33
|
+
// ===== Circuit Breaker (per-device exponential backoff + auto-probe) =====
|
|
34
|
+
const deviceBackoff = new Map();
|
|
35
|
+
const BACKOFF_THRESHOLD = 6; // failures before backing off (ESP32 has transient drops)
|
|
36
|
+
const BACKOFF_INITIAL_MS = 5_000; // 5s initial backoff (quick recovery)
|
|
37
|
+
const BACKOFF_MAX_MS = 60_000; // 1m max cap
|
|
38
|
+
const PROBE_INTERVAL_MS = 5_000; // Probe every 5s during backoff
|
|
39
|
+
let probeTimer = null;
|
|
40
|
+
let statusCallback = null;
|
|
41
|
+
/** Register a callback for device online/offline transitions. */
|
|
42
|
+
export function onDeviceStatusChange(cb) {
|
|
43
|
+
statusCallback = cb;
|
|
44
|
+
}
|
|
45
|
+
function isBackedOff(ip) {
|
|
46
|
+
const entry = deviceBackoff.get(ip);
|
|
47
|
+
if (!entry || entry.failures < BACKOFF_THRESHOLD)
|
|
48
|
+
return false;
|
|
49
|
+
return Date.now() < entry.backoffUntil;
|
|
50
|
+
}
|
|
51
|
+
function recordSuccess(ip) {
|
|
52
|
+
const wasBackedOff = isBackedOff(ip);
|
|
53
|
+
deviceBackoff.delete(ip);
|
|
54
|
+
if (wasBackedOff) {
|
|
55
|
+
debug(TAG, `Device ${ip} recovered — backoff cleared, re-syncing PicID`);
|
|
56
|
+
clearStaticPicId(ip); // Device may have rebooted — force fresh PicID sync
|
|
57
|
+
statusCallback?.(ip, true);
|
|
58
|
+
updateProbeTimer();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function recordFailure(ip) {
|
|
62
|
+
const wasBackedOff = isBackedOff(ip);
|
|
63
|
+
const entry = deviceBackoff.get(ip) ?? { failures: 0, backoffUntil: 0 };
|
|
64
|
+
entry.failures++;
|
|
65
|
+
if (entry.failures >= BACKOFF_THRESHOLD) {
|
|
66
|
+
const delay = Math.min(BACKOFF_INITIAL_MS * Math.pow(2, entry.failures - BACKOFF_THRESHOLD), BACKOFF_MAX_MS);
|
|
67
|
+
entry.backoffUntil = Date.now() + delay;
|
|
68
|
+
debug(TAG, `Backoff ${ip}: ${Math.round(delay / 1000)}s (${entry.failures} failures)`);
|
|
69
|
+
if (!wasBackedOff) {
|
|
70
|
+
statusCallback?.(ip, false);
|
|
71
|
+
updateProbeTimer();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
deviceBackoff.set(ip, entry);
|
|
75
|
+
}
|
|
76
|
+
/** Start/stop the probe timer based on whether any device is backed off. */
|
|
77
|
+
function updateProbeTimer() {
|
|
78
|
+
const anyBackedOff = [...deviceBackoff.values()].some(e => e.failures >= BACKOFF_THRESHOLD && Date.now() < e.backoffUntil);
|
|
79
|
+
if (anyBackedOff && !probeTimer) {
|
|
80
|
+
probeTimer = setInterval(probeBackedOffDevices, PROBE_INTERVAL_MS);
|
|
81
|
+
debug(TAG, 'Probe timer started (30s interval)');
|
|
82
|
+
}
|
|
83
|
+
else if (!anyBackedOff && probeTimer) {
|
|
84
|
+
clearInterval(probeTimer);
|
|
85
|
+
probeTimer = null;
|
|
86
|
+
debug(TAG, 'Probe timer stopped — all devices online');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Probe backed-off devices to detect recovery. */
|
|
90
|
+
async function probeBackedOffDevices() {
|
|
91
|
+
const ipsToProbe = [...deviceBackoff.entries()]
|
|
92
|
+
.filter(([, e]) => e.failures >= BACKOFF_THRESHOLD)
|
|
93
|
+
.map(([ip]) => ip);
|
|
94
|
+
for (const ip of ipsToProbe) {
|
|
95
|
+
debug(TAG, `Probing backed-off device ${ip}...`);
|
|
96
|
+
const config = await getDeviceConfig(ip);
|
|
97
|
+
if (config) {
|
|
98
|
+
debug(TAG, `Probe success for ${ip} — restoring connection`);
|
|
99
|
+
recordSuccess(ip);
|
|
100
|
+
// Re-initialize: switch to custom channel
|
|
101
|
+
switchToCustomChannel(ip).catch(() => { });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/** Clean up probe timer. Call on shutdown. */
|
|
106
|
+
export function stopProbeTimer() {
|
|
107
|
+
if (probeTimer) {
|
|
108
|
+
clearInterval(probeTimer);
|
|
109
|
+
probeTimer = null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Wake recovery — clear all PicID caches and circuit breaker state.
|
|
114
|
+
* Devices may have rebooted during sleep, so all cached state is stale.
|
|
115
|
+
*/
|
|
116
|
+
export function handlePixooWake() {
|
|
117
|
+
debug(TAG, `Wake recovery — clearing ${devicePicId.size} PicID(s) and ${deviceBackoff.size} backoff(s)`);
|
|
118
|
+
for (const ip of devicePicId.keys()) {
|
|
119
|
+
clearStaticPicId(ip);
|
|
120
|
+
}
|
|
121
|
+
deviceBackoff.clear();
|
|
122
|
+
if (probeTimer) {
|
|
123
|
+
clearInterval(probeTimer);
|
|
124
|
+
probeTimer = null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/** Get circuit breaker status for a device. */
|
|
128
|
+
export function getDeviceBackoffStatus(ip) {
|
|
129
|
+
const entry = deviceBackoff.get(ip);
|
|
130
|
+
if (!entry)
|
|
131
|
+
return { failures: 0, backedOff: false, nextProbeMs: 0 };
|
|
132
|
+
const now = Date.now();
|
|
133
|
+
const backedOff = entry.failures >= BACKOFF_THRESHOLD && now < entry.backoffUntil;
|
|
134
|
+
return {
|
|
135
|
+
failures: entry.failures,
|
|
136
|
+
backedOff,
|
|
137
|
+
nextProbeMs: backedOff ? entry.backoffUntil - now : 0,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* POST a command to the Pixoo device using node:http (not fetch).
|
|
142
|
+
* Pixoo's embedded HTTP server can't handle keep-alive connections —
|
|
143
|
+
* Node 19+ fetch uses keepAlive:true by default, causing timeouts after 2-3 requests.
|
|
144
|
+
*/
|
|
145
|
+
async function postCommand(ip, command) {
|
|
146
|
+
if (isBackedOff(ip))
|
|
147
|
+
return false;
|
|
148
|
+
try {
|
|
149
|
+
const result = await httpPost(ip, command);
|
|
150
|
+
if (!result) {
|
|
151
|
+
recordFailure(ip);
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
recordSuccess(ip);
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
debug(TAG, `Request failed to ${ip}: ${err.message}`);
|
|
159
|
+
recordFailure(ip);
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/** Low-level HTTP POST with keepAlive:false agent. */
|
|
164
|
+
function httpPost(ip, body) {
|
|
165
|
+
return new Promise((resolve, reject) => {
|
|
166
|
+
const data = JSON.stringify(body);
|
|
167
|
+
const req = http.request({
|
|
168
|
+
hostname: ip,
|
|
169
|
+
port: 80,
|
|
170
|
+
path: '/post',
|
|
171
|
+
method: 'POST',
|
|
172
|
+
agent: pixooAgent,
|
|
173
|
+
headers: {
|
|
174
|
+
'Content-Type': 'application/json',
|
|
175
|
+
'Content-Length': Buffer.byteLength(data),
|
|
176
|
+
},
|
|
177
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
178
|
+
}, res => {
|
|
179
|
+
const chunks = [];
|
|
180
|
+
res.on('data', (c) => chunks.push(c));
|
|
181
|
+
res.on('end', () => {
|
|
182
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
183
|
+
debug(TAG, `HTTP ${res.statusCode} from ${ip}`);
|
|
184
|
+
resolve(null);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
resolve(JSON.parse(Buffer.concat(chunks).toString()));
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
resolve({});
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
req.on('error', reject);
|
|
196
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
|
|
197
|
+
req.end(data);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Push a single 64×64 RGB frame to the device.
|
|
202
|
+
* PicID increments per frame so the device renders each new image.
|
|
203
|
+
* @param buffer - 12,288 bytes (64 * 64 * 3) raw RGB
|
|
204
|
+
*/
|
|
205
|
+
export async function pushFrame(ip, buffer) {
|
|
206
|
+
if (buffer.length !== 64 * 64 * 3) {
|
|
207
|
+
debug(TAG, `Invalid frame size: ${buffer.length} (expected 12288)`);
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
// Get or initialize PicID for this device
|
|
211
|
+
let picId = devicePicId.get(ip);
|
|
212
|
+
if (picId === undefined) {
|
|
213
|
+
// First push — sync with device's current counter + 1 to ensure freshness
|
|
214
|
+
picId = await getHttpGifId(ip);
|
|
215
|
+
debug(TAG, `Synced PicID for ${ip}: ${picId}`);
|
|
216
|
+
}
|
|
217
|
+
// Increment PicID per frame (device renders new image only on new sequential ID)
|
|
218
|
+
picId++;
|
|
219
|
+
// Prevent counter overflow (~300 causes device lockup) — reset gracefully
|
|
220
|
+
if (picId >= PIC_ID_RESYNC_THRESHOLD) {
|
|
221
|
+
debug(TAG, `PicID ${picId} near overflow for ${ip}, resetting`);
|
|
222
|
+
await resetPicId(ip);
|
|
223
|
+
picId = 1;
|
|
224
|
+
}
|
|
225
|
+
devicePicId.set(ip, picId);
|
|
226
|
+
// Apply gamma boost for LED display
|
|
227
|
+
const boosted = new Uint8Array(buffer.length);
|
|
228
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
229
|
+
boosted[i] = gammaLUT[buffer[i]];
|
|
230
|
+
}
|
|
231
|
+
const base64 = Buffer.from(boosted).toString('base64');
|
|
232
|
+
return postCommand(ip, {
|
|
233
|
+
Command: 'Draw/SendHttpGif',
|
|
234
|
+
PicNum: 1, // Always 1 (single image, bypasses loading screen)
|
|
235
|
+
PicWidth: 64,
|
|
236
|
+
PicOffset: 0,
|
|
237
|
+
PicID: picId, // INCREMENTS each push so device renders every frame
|
|
238
|
+
PicSpeed: 1000,
|
|
239
|
+
PicData: base64,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Send scrolling text overlay (device-native font, supports long text).
|
|
244
|
+
* Up to 20 simultaneous text items supported by device.
|
|
245
|
+
* @param textId - 0-19, used to update/remove specific text
|
|
246
|
+
* @param color - hex color string e.g. "#22c55e"
|
|
247
|
+
* @param speed - scroll speed 0-100 (default 50)
|
|
248
|
+
*/
|
|
249
|
+
export async function sendScrollText(ip, textId, text, color, speed = 50) {
|
|
250
|
+
const r = parseInt(color.slice(1, 3), 16);
|
|
251
|
+
const g = parseInt(color.slice(3, 5), 16);
|
|
252
|
+
const b = parseInt(color.slice(5, 7), 16);
|
|
253
|
+
return postCommand(ip, {
|
|
254
|
+
Command: 'Draw/SendHttpText',
|
|
255
|
+
TextId: textId,
|
|
256
|
+
x: 0,
|
|
257
|
+
y: 0,
|
|
258
|
+
dir: 0, // 0=left scroll
|
|
259
|
+
font: 2, // small built-in font
|
|
260
|
+
TextWidth: 64,
|
|
261
|
+
speed,
|
|
262
|
+
TextString: text,
|
|
263
|
+
color: `#${color.slice(1)}`,
|
|
264
|
+
align: 1,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/** Clear all text overlays. */
|
|
268
|
+
export async function clearText(ip) {
|
|
269
|
+
return postCommand(ip, { Command: 'Draw/ClearHttpText' });
|
|
270
|
+
}
|
|
271
|
+
/** Set display brightness (0-100). */
|
|
272
|
+
export async function setBrightness(ip, value) {
|
|
273
|
+
return postCommand(ip, {
|
|
274
|
+
Command: 'Channel/SetBrightness',
|
|
275
|
+
Brightness: Math.max(0, Math.min(100, value)),
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
/** Query the device's current PicID counter. Returns 0 on failure. */
|
|
279
|
+
export async function getHttpGifId(ip) {
|
|
280
|
+
try {
|
|
281
|
+
const data = await httpPost(ip, { Command: 'Draw/GetHttpGifId' });
|
|
282
|
+
return data?.PicId ?? 0;
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
return 0;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/** Reset the PicID counter to prevent device lockup. */
|
|
289
|
+
export async function resetPicId(ip) {
|
|
290
|
+
return postCommand(ip, { Command: 'Draw/ResetHttpGifId' });
|
|
291
|
+
}
|
|
292
|
+
/** Switch device to the custom channel that shows SendHttpGif content. */
|
|
293
|
+
export async function switchToCustomChannel(ip) {
|
|
294
|
+
// SelectIndex: 0=Faces, 1=Cloud, 2=Visualizer, 3=Custom
|
|
295
|
+
return postCommand(ip, { Command: 'Channel/SetIndex', SelectIndex: 3 });
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Get device configuration (also serves as a connectivity test).
|
|
299
|
+
* Returns null on failure.
|
|
300
|
+
*/
|
|
301
|
+
export async function getDeviceConfig(ip) {
|
|
302
|
+
try {
|
|
303
|
+
return await httpPost(ip, { Command: 'Channel/GetAllConf' });
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Discover Pixoo devices via Divoom cloud API.
|
|
311
|
+
* Falls back gracefully if cloud is unreachable.
|
|
312
|
+
*/
|
|
313
|
+
export async function discoverDevices() {
|
|
314
|
+
try {
|
|
315
|
+
const response = await fetch('https://app.divoom-gz.com/Device/ReturnSameLANDevice', {
|
|
316
|
+
method: 'POST',
|
|
317
|
+
headers: { 'Content-Type': 'application/json' },
|
|
318
|
+
body: JSON.stringify({}),
|
|
319
|
+
signal: AbortSignal.timeout(3000),
|
|
320
|
+
});
|
|
321
|
+
if (!response.ok)
|
|
322
|
+
return [];
|
|
323
|
+
const data = await response.json();
|
|
324
|
+
if (!data?.DeviceList)
|
|
325
|
+
return [];
|
|
326
|
+
return data.DeviceList.map((d) => ({
|
|
327
|
+
name: d.DeviceName || 'Pixoo',
|
|
328
|
+
ip: d.DevicePrivateIP,
|
|
329
|
+
}));
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
return [];
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
//# sourceMappingURL=pixoo-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pixoo-client.js","sourceRoot":"","sources":["../../src/pixoo/pixoo-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pixoo64 Bitmap Font — 3×5 pixel font for 64×64 LED matrix.
|
|
3
|
+
*
|
|
4
|
+
* Supports ASCII uppercase A-Z, digits 0-9, and basic symbols.
|
|
5
|
+
* At 3px + 1px gap per character, a 64px line fits ~16 characters.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Draw text onto a 64×64 RGB buffer.
|
|
9
|
+
* @param buf - 12,288 byte RGB buffer (mutated in place)
|
|
10
|
+
* @param x - starting X pixel
|
|
11
|
+
* @param y - starting Y pixel
|
|
12
|
+
* @param text - string to draw (auto-uppercased, unknown chars → space)
|
|
13
|
+
* @param color - hex color "#RRGGBB"
|
|
14
|
+
*/
|
|
15
|
+
export declare function drawText(buf: Uint8Array, x: number, y: number, text: string, color: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Measure text width in pixels.
|
|
18
|
+
*/
|
|
19
|
+
export declare function measureText(text: string): number;
|
|
20
|
+
/**
|
|
21
|
+
* Draw text centered horizontally on the 64px canvas.
|
|
22
|
+
*/
|
|
23
|
+
export declare function drawTextCentered(buf: Uint8Array, y: number, text: string, color: string): void;
|
|
24
|
+
//# sourceMappingURL=pixoo-font.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pixoo-font.d.ts","sourceRoot":"","sources":["../../src/pixoo/pixoo-font.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAmEH;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GACjE,IAAI,CA2BN;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GACtD,IAAI,CAIN"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pixoo64 Bitmap Font — 3×5 pixel font for 64×64 LED matrix.
|
|
3
|
+
*
|
|
4
|
+
* Supports ASCII uppercase A-Z, digits 0-9, and basic symbols.
|
|
5
|
+
* At 3px + 1px gap per character, a 64px line fits ~16 characters.
|
|
6
|
+
*/
|
|
7
|
+
// 3×5 bitmap font data. Each glyph is 5 rows of 3 bits (MSB left).
|
|
8
|
+
// Format: [row0, row1, row2, row3, row4] where each row is 0b___ (3 bits)
|
|
9
|
+
const GLYPHS = {
|
|
10
|
+
'A': [0b010, 0b101, 0b111, 0b101, 0b101],
|
|
11
|
+
'B': [0b110, 0b101, 0b110, 0b101, 0b110],
|
|
12
|
+
'C': [0b011, 0b100, 0b100, 0b100, 0b011],
|
|
13
|
+
'D': [0b110, 0b101, 0b101, 0b101, 0b110],
|
|
14
|
+
'E': [0b111, 0b100, 0b110, 0b100, 0b111],
|
|
15
|
+
'F': [0b111, 0b100, 0b110, 0b100, 0b100],
|
|
16
|
+
'G': [0b011, 0b100, 0b101, 0b101, 0b011],
|
|
17
|
+
'H': [0b101, 0b101, 0b111, 0b101, 0b101],
|
|
18
|
+
'I': [0b111, 0b010, 0b010, 0b010, 0b111],
|
|
19
|
+
'J': [0b001, 0b001, 0b001, 0b101, 0b010],
|
|
20
|
+
'K': [0b101, 0b110, 0b100, 0b110, 0b101],
|
|
21
|
+
'L': [0b100, 0b100, 0b100, 0b100, 0b111],
|
|
22
|
+
'M': [0b101, 0b111, 0b111, 0b101, 0b101],
|
|
23
|
+
'N': [0b101, 0b111, 0b111, 0b101, 0b101],
|
|
24
|
+
'O': [0b010, 0b101, 0b101, 0b101, 0b010],
|
|
25
|
+
'P': [0b110, 0b101, 0b110, 0b100, 0b100],
|
|
26
|
+
'Q': [0b010, 0b101, 0b101, 0b110, 0b011],
|
|
27
|
+
'R': [0b110, 0b101, 0b110, 0b101, 0b101],
|
|
28
|
+
'S': [0b011, 0b100, 0b010, 0b001, 0b110],
|
|
29
|
+
'T': [0b111, 0b010, 0b010, 0b010, 0b010],
|
|
30
|
+
'U': [0b101, 0b101, 0b101, 0b101, 0b010],
|
|
31
|
+
'V': [0b101, 0b101, 0b101, 0b010, 0b010],
|
|
32
|
+
'W': [0b101, 0b101, 0b111, 0b111, 0b101],
|
|
33
|
+
'X': [0b101, 0b101, 0b010, 0b101, 0b101],
|
|
34
|
+
'Y': [0b101, 0b101, 0b010, 0b010, 0b010],
|
|
35
|
+
'Z': [0b111, 0b001, 0b010, 0b100, 0b111],
|
|
36
|
+
'0': [0b010, 0b101, 0b101, 0b101, 0b010],
|
|
37
|
+
'1': [0b010, 0b110, 0b010, 0b010, 0b111],
|
|
38
|
+
'2': [0b110, 0b001, 0b010, 0b100, 0b111],
|
|
39
|
+
'3': [0b110, 0b001, 0b010, 0b001, 0b110],
|
|
40
|
+
'4': [0b101, 0b101, 0b111, 0b001, 0b001],
|
|
41
|
+
'5': [0b111, 0b100, 0b110, 0b001, 0b110],
|
|
42
|
+
'6': [0b011, 0b100, 0b110, 0b101, 0b010],
|
|
43
|
+
'7': [0b111, 0b001, 0b010, 0b010, 0b010],
|
|
44
|
+
'8': [0b010, 0b101, 0b010, 0b101, 0b010],
|
|
45
|
+
'9': [0b010, 0b101, 0b011, 0b001, 0b110],
|
|
46
|
+
'.': [0b000, 0b000, 0b000, 0b000, 0b010],
|
|
47
|
+
':': [0b000, 0b010, 0b000, 0b010, 0b000],
|
|
48
|
+
'%': [0b101, 0b001, 0b010, 0b100, 0b101],
|
|
49
|
+
'/': [0b001, 0b001, 0b010, 0b100, 0b100],
|
|
50
|
+
'-': [0b000, 0b000, 0b111, 0b000, 0b000],
|
|
51
|
+
'+': [0b000, 0b010, 0b111, 0b010, 0b000],
|
|
52
|
+
'$': [0b011, 0b110, 0b010, 0b011, 0b110],
|
|
53
|
+
'!': [0b010, 0b010, 0b010, 0b000, 0b010],
|
|
54
|
+
'?': [0b110, 0b001, 0b010, 0b000, 0b010],
|
|
55
|
+
' ': [0b000, 0b000, 0b000, 0b000, 0b000],
|
|
56
|
+
'_': [0b000, 0b000, 0b000, 0b000, 0b111],
|
|
57
|
+
'(': [0b010, 0b100, 0b100, 0b100, 0b010],
|
|
58
|
+
')': [0b010, 0b001, 0b001, 0b001, 0b010],
|
|
59
|
+
'>': [0b100, 0b010, 0b001, 0b010, 0b100],
|
|
60
|
+
'<': [0b001, 0b010, 0b100, 0b010, 0b001],
|
|
61
|
+
};
|
|
62
|
+
/** Parse "#RRGGBB" hex color to [r, g, b]. */
|
|
63
|
+
function parseColor(hex) {
|
|
64
|
+
return [
|
|
65
|
+
parseInt(hex.slice(1, 3), 16),
|
|
66
|
+
parseInt(hex.slice(3, 5), 16),
|
|
67
|
+
parseInt(hex.slice(5, 7), 16),
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Draw text onto a 64×64 RGB buffer.
|
|
72
|
+
* @param buf - 12,288 byte RGB buffer (mutated in place)
|
|
73
|
+
* @param x - starting X pixel
|
|
74
|
+
* @param y - starting Y pixel
|
|
75
|
+
* @param text - string to draw (auto-uppercased, unknown chars → space)
|
|
76
|
+
* @param color - hex color "#RRGGBB"
|
|
77
|
+
*/
|
|
78
|
+
export function drawText(buf, x, y, text, color) {
|
|
79
|
+
const [r, g, b] = parseColor(color);
|
|
80
|
+
const upper = text.toUpperCase();
|
|
81
|
+
let cx = x;
|
|
82
|
+
for (const ch of upper) {
|
|
83
|
+
const glyph = GLYPHS[ch];
|
|
84
|
+
if (!glyph) {
|
|
85
|
+
cx += 4; // unknown char → space
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
for (let row = 0; row < 5; row++) {
|
|
89
|
+
for (let col = 0; col < 3; col++) {
|
|
90
|
+
if (glyph[row] & (0b100 >> col)) {
|
|
91
|
+
const px = cx + col;
|
|
92
|
+
const py = y + row;
|
|
93
|
+
if (px >= 0 && px < 64 && py >= 0 && py < 64) {
|
|
94
|
+
const idx = (py * 64 + px) * 3;
|
|
95
|
+
buf[idx] = r;
|
|
96
|
+
buf[idx + 1] = g;
|
|
97
|
+
buf[idx + 2] = b;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
cx += 4; // 3px glyph + 1px gap
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Measure text width in pixels.
|
|
107
|
+
*/
|
|
108
|
+
export function measureText(text) {
|
|
109
|
+
if (text.length === 0)
|
|
110
|
+
return 0;
|
|
111
|
+
return text.length * 4 - 1; // each char 3px + 1px gap, minus trailing gap
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Draw text centered horizontally on the 64px canvas.
|
|
115
|
+
*/
|
|
116
|
+
export function drawTextCentered(buf, y, text, color) {
|
|
117
|
+
const width = measureText(text);
|
|
118
|
+
const x = Math.max(0, Math.floor((64 - width) / 2));
|
|
119
|
+
drawText(buf, x, y, text, color);
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=pixoo-font.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pixoo-font.js","sourceRoot":"","sources":["../../src/pixoo/pixoo-font.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,mEAAmE;AACnE,0EAA0E;AAC1E,MAAM,MAAM,GAA6B;IACvC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IACxC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;CACzC,CAAC;AAEF,8CAA8C;AAC9C,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO;QACL,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QAC7B,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;QAC7B,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;KAC9B,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CACtB,GAAe,EAAE,CAAS,EAAE,CAAS,EAAE,IAAY,EAAE,KAAa;IAElE,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAEjC,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,EAAE,IAAI,CAAC,CAAC,CAAC,uBAAuB;YAChC,SAAS;QACX,CAAC;QACD,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;YACjC,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;gBACjC,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,EAAE,CAAC;oBAChC,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;oBACpB,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC;oBACnB,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;wBAC7C,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;wBAC/B,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;wBACb,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;wBACjB,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;oBACnB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QACD,EAAE,IAAI,CAAC,CAAC,CAAC,sBAAsB;IACjC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAChC,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,8CAA8C;AAC5E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAe,EAAE,CAAS,EAAE,IAAY,EAAE,KAAa;IAEvD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pixoo64 Frame Renderer — camera-based animated terrarium.
|
|
3
|
+
*
|
|
4
|
+
* No text. All information encoded visually:
|
|
5
|
+
*
|
|
6
|
+
* Water color ↔ usage zone (blue → teal → amber → red)
|
|
7
|
+
* Waves ↔ agent state (calm=IDLE, choppy=PROC, golden pulse=AWAITING)
|
|
8
|
+
* Bubbles ↔ activity density
|
|
9
|
+
* Creatures ↔ sessions + gateway
|
|
10
|
+
* Particles ↔ data flow during processing
|
|
11
|
+
* Surface glow ↔ state color (green / blue / amber)
|
|
12
|
+
* Camera zoom ↔ state-driven focus (wide, octopus close-up, crayfish, school, surface)
|
|
13
|
+
*
|
|
14
|
+
* Rendering pipeline:
|
|
15
|
+
* 1. Environment → 64×64 world buffer (water, terrain, effects)
|
|
16
|
+
* 2. blitWithCamera() → output buffer (crop + scale by camera zoom/pan)
|
|
17
|
+
* 3. Scaled creatures → output buffer (HD grid sprites with camera-aware sizing)
|
|
18
|
+
* 4. Screen-space overlays (danger flash) → output buffer
|
|
19
|
+
*/
|
|
20
|
+
import type { StateUpdateEvent, UsageEvent } from '../types.js';
|
|
21
|
+
import type { SessionInfo } from '@agentdeck/shared/protocol';
|
|
22
|
+
/**
|
|
23
|
+
* Render a complete 64×64 frame with camera system.
|
|
24
|
+
* Returns 12,288-byte RGB buffer.
|
|
25
|
+
*/
|
|
26
|
+
export declare function renderFrame(stateEvent: StateUpdateEvent | null, usageEvent: UsageEvent | null, sessions: SessionInfo[] | null, timeOverrideMs?: number): Uint8Array;
|
|
27
|
+
/** Render a static black frame with centered grey "OFFLINE" text. */
|
|
28
|
+
export declare function renderDisconnectedFrame(): Uint8Array;
|
|
29
|
+
export { setZone, setOverride, resetDirector } from './pixoo-camera.js';
|
|
30
|
+
export type { Camera } from './pixoo-camera.js';
|
|
31
|
+
export { ZONES } from './pixoo-camera.js';
|
|
32
|
+
//# sourceMappingURL=pixoo-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pixoo-renderer.d.ts","sourceRoot":"","sources":["../../src/pixoo/pixoo-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAkmB9D;;;GAGG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,gBAAgB,GAAG,IAAI,EACnC,UAAU,EAAE,UAAU,GAAG,IAAI,EAC7B,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI,EAC9B,cAAc,CAAC,EAAE,MAAM,GACtB,UAAU,CA0MZ;AAID,qEAAqE;AACrE,wBAAgB,uBAAuB,IAAI,UAAU,CAIpD;AAGD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACxE,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC"}
|