web-duo
v0.1.0
Published
Whole-page hinge glass effects and optional MacBook WebHID input
Readme
web-duo
WebGL glass effects driven by an opening angle: perspective, distance-based frost, and reflection. Framework-independent ESM with TypeScript types.
Install
npm install web-duoImage or canvas
import { createDuo } from 'web-duo';
const image = new Image();
image.src = '/scene.png';
await image.decode();
const effect = createDuo({
canvas: document.querySelector('#output'),
source: image,
openAngle: 120,
});
effect.setAngle(90);
// effect.updateSource(sourceCanvas); // Refresh changed source pixels.
// effect.calibrate(125); // Set the fully open angle.
// effect.destroy(); // Clean up on unmount.Sources: decoded images, HTMLCanvasElement, OffscreenCanvas, or ImageBitmap. Requires WebGL 2 and same-origin or CORS-enabled images. Output pixel dimensions follow the source; preserve its aspect ratio in CSS. Modules can be imported during SSR, but create instances in the browser.
Experimental DOM adapter
import { createDuoPage } from 'web-duo/dom';
const effect = createDuoPage({
source: document.querySelector('#content'),
canvas: document.querySelector('#output'),
openAngle: 120,
onError: console.error,
});
effect.start();
effect.setAngle(75);
// effect.refresh(); effect.scrollBy(200);
// effect.stop(); effect.start(); effect.destroy();Renders a viewport-sized snapshot of self-contained HTML/CSS. Keep the output canvas and interactive controls outside the source element. Rendered content is not interactive DOM.
Video, canvas pixels, iframes, Shadow DOM, external assets, and complex forms or CSS animations may not be reproduced. For inaccessible stylesheets, supply self-contained cssText. Optional settings: background, maxPixelRatio (default 2), and captureIntervalMs (default 100).
Optional MacBook input
import { createMacBookSensor } from 'web-duo/sensor';
const sensor = createMacBookSensor({
onSample: sample => effect.setAngle(sample.angle),
onError: console.error,
});
button.disabled = !sensor.supported;
button.onclick = async () => {
try { await sensor.connect(); } catch (error) { console.error(error); }
};
// await sensor.disconnect();
// On unmount: await sensor.destroy(); effect.destroy();Requires a compatible MacBook, WebHID, HTTPS or localhost, and a user gesture for authorization. Only the validated Apple 05AC:8104 protocol is decoded. No device configuration is written. Input reports on tested devices arrive at about 1 Hz; this library does not remove that limitation. Manual angle input works without a sensor.
Optional callbacks include onPacket, onDevice, onState, onPath, onNotice, and onDisconnect. Connection errors reject connect(); read errors invoke onError. Callbacks should not throw. On WebGL context loss, destroy and recreate the effect.
License and references
UNLICENSED. See NOTICE.md for implementation references.
