Files
djaudiovisualizer/preload.js
T
lucianoandClaude Opus 5.5 ab1ab89127 Phone remote: LAN web page + WebSocket, QR pairing, blackout/freeze
remote-server.js: http + ws server (off by default, started from the panel,
port 8787 or next free), every request gated by a secret key embedded in a
QR code; the key persists in userData/remote.json so a phone's home-screen
shortcut survives restarts, 'Nuovo codice' revokes it. Phones send commands
that the panel executes through its own functions (transport, track pick,
effect next/prev/random/family/sequence, Auto VJ, pads, mapping on + visible
zones, blackout, freeze) and the panel pushes a compact live state at ~6 Hz
while a phone is connected (track + progress, effect, sequence, pads,
zones, meters, BPM). New panic controls in output and aux windows: blackout
(fade to black above every layer) and freeze (hold the last frame); also
available as panel buttons. src/remote.{html,css,js} is the touch UI in the
Neon Grid style, installable to the home screen, auto-reconnecting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XVMQ2JhsJ77pGKqcvvFHqc
2026-10-02 13:39:28 +02:00

62 lines
3.3 KiB
JavaScript

const { contextBridge, ipcRenderer, webUtils } = require('electron');
// Each window is launched with --role=control, --role=output or --role=aux.
const roleArg = process.argv.find(a => a.startsWith('--role='));
const role = roleArg ? roleArg.split('=')[1] : 'control';
// Aux outputs also get the id of the display they live on.
const dispArg = process.argv.find(a => a.startsWith('--display='));
const displayId = dispArg ? parseInt(dispArg.split('=')[1], 10) : -1;
contextBridge.exposeInMainWorld('djv', {
role,
displayId,
// Audio analysis relay: main output -> aux outputs (~30 Hz).
sendAudio: (data) => ipcRenderer.send('afr', data),
onAudio: (cb) => ipcRenderer.on('afr', (_e, d) => cb(d)),
// Create/close aux output windows to match the given display-id list.
auxSync: (ids) => ipcRenderer.invoke('aux:sync', ids),
// Control -> Output commands.
send: (msg) => ipcRenderer.send('ctl', msg),
onControl: (cb) => ipcRenderer.on('ctl', (_e, m) => cb(m)),
// Output -> Control reports.
report: (msg) => ipcRenderer.send('rpt', msg),
onReport: (cb) => ipcRenderer.on('rpt', (_e, m) => cb(m)),
// Display management (control window).
// Bundled svg/ folder, read in the main process, as same-origin data URLs.
listBuiltinSvgs: () => ipcRenderer.invoke('svg:listBuiltin'),
// Resolve a dropped/picked File to its absolute filesystem path.
pathForFile: (file) => {
try { return webUtils.getPathForFile(file); }
catch (e) { return file && file.path ? file.path : null; }
},
listDisplays: () => ipcRenderer.invoke('displays:list'),
moveOutputTo: (id) => ipcRenderer.invoke('output:moveTo', id),
toggleOutputFullscreen: () => ipcRenderer.invoke('output:toggleFullscreen'),
// Recording (output streams chunks to main, which muxes/transcodes to MP4).
recStart: () => ipcRenderer.invoke('rec:start'),
recChunk: (bytes) => ipcRenderer.send('rec:chunk', bytes),
recStop: (opts) => ipcRenderer.invoke('rec:stop', opts),
openRecordingsFolder: () => ipcRenderer.invoke('rec:openFolder'),
// Pad bank persistence.
loadPads: () => ipcRenderer.invoke('pads:load'),
savePads: (data) => ipcRenderer.invoke('pads:save', data),
loadPlaylist: () => ipcRenderer.invoke('playlist:load'),
savePlaylist: (data) => ipcRenderer.invoke('playlist:save', data),
exportPlaylist: (data) => ipcRenderer.invoke('playlist:export', data),
importPlaylist: () => ipcRenderer.invoke('playlist:import'),
peaks: (path, buckets) => ipcRenderer.invoke('audio:peaks', path, buckets),
// Ask macOS for camera permission (interactive family) right before use.
camAccess: () => ipcRenderer.invoke('cam:ensure'),
// Convert Mixamo FBX files via Blender: animation clips / character models.
convertAnim: (p) => ipcRenderer.invoke('anim:convert', p),
convertModel: (p) => ipcRenderer.invoke('model:convert', p),
readFile: (path) => ipcRenderer.invoke('file:read', path),
// Phone remote: LAN server control, incoming commands, outgoing state.
remoteStart: () => ipcRenderer.invoke('remote:start'),
remoteStop: () => ipcRenderer.invoke('remote:stop'),
remoteNewKey: () => ipcRenderer.invoke('remote:newKey'),
remoteInfo: () => ipcRenderer.invoke('remote:info'),
remoteState: (state) => ipcRenderer.send('remote:state', state),
onRemote: (cb) => ipcRenderer.on('remote', (_e, m) => cb(m))
});