Some checks failed
CI / build-and-deploy (push) Has been cancelled
Replaces the gPhoto2 demo UI (live view beside the raw config tree) with a timelapse intervalometer. The home screen carries only what changes between runs - interval, frame count, start delay, start/stop, countdown, progress and a log - while every camera setting moves into a settings drawer. - intervalometer.js: schedules frames on an absolute grid (start + n * interval) so transfer time doesn't accumulate as drift over a long run. An overrun logs and fires as soon as the camera is free rather than dropping a frame; three consecutive failures abort. - storage.js: frames stream into a folder via the File System Access API, named for capture time (20260801-172713_00001.JPG) so sorting by name is sorting by time. Falls back to downloads. Also holds the screen wake lock, since background tabs get their timers throttled. - config-utils.js: config tree lookups, shutter speed parsing, and bulb capability detection (bulb toggle or Canon eosremoterelease). - home.js: sequence controls plus a read-only exposure readout and pre-flight warnings when the interval can't fit the exposure and transfer. - settings.js / index.js: app prefs and the full config tree behind a drawer. Config polling now only runs while that drawer is open, leaving the USB link to the captures during a sequence. Live view stays up between frames and steps aside only while the shutter fires, which is what the EOS driver requires; it recovers afterwards with backoff instead of hammering a busy camera. Deployed as an assets-only Cloudflare Worker. The WASM is built with pthreads and allocates a shared WebAssembly.Memory, so _headers reproduces the COOP/COEP pair from serve.json - without cross-origin isolation the app fails to start. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QK7PKpRVoy69Fpa32R8abb
21 lines
536 B
TypeScript
21 lines
536 B
TypeScript
type LogEntry = {
|
|
id: number;
|
|
message: string;
|
|
kind: 'info' | 'warn' | 'error';
|
|
at: number;
|
|
};
|
|
|
|
type AppState = {
|
|
/** Which top-level screen is showing. */
|
|
view: 'status' | 'picker' | 'ready';
|
|
/** Shown while `view` is 'status'. */
|
|
message?: string;
|
|
config?: import('web-gphoto2').Config;
|
|
supportedOps?: import('web-gphoto2').SupportedOps;
|
|
prefs: import('./settings.js').Prefs;
|
|
seq: import('./intervalometer.js').SequenceState;
|
|
log: LogEntry[];
|
|
settingsOpen: boolean;
|
|
singleShotStatus: 'idle' | 'busy';
|
|
};
|