# AnySurface API Reference

All exports are available from the main bundle entry point:

```js
import { Surface, CameraInterface, ... } from 'anysurface'
```

---

## Core

### Surface

Main orchestrator class that initializes and coordinates all subsystems.

**Extends:** `Evented`

```js
const surface = new Surface()
await surface.init(canvases, opts)
```

#### Methods

| Method | Description |
|--------|-------------|
| `init(canvases, opts?)` | Initialize all subsystems. `canvases`: `{pointerCanvas, scanCanvas, alignCanvas, shutterCanvas}`. `opts`: `{trackingOn: boolean}` |
| `detectCamera(cameraLabel, cameraURL?)` | Detect and configure a camera. Returns `Promise<boolean>` |
| `findAndSetShutterValue(successCb, failureCb)` | Auto-detect optimal exposure value |
| `cameraServerIsUp(itsUpCb, itsDownCb, waitTime?)` | Check if camera server is running |
| `serverVersion()` | Get camera server version string |
| `setCameraRaster(cameraRaster)` | Set camera-to-projector mapping |
| `setDimensions(dataWidth, dataHeight)` | Set grid dimensions |
| `getCameraRaster()` | Returns `CameraRaster` or `null` |
| `getProjectorRaster()` | Returns `ProjectorRaster` or `null` |
| `getAllRasters()` | Returns `{cameraRaster, projectorRaster, flatRaster, moundRaster, diffRaster}` |
| `getProjectorDimensions()` | Returns `{width, height}` or `null` |

#### Properties

| Property | Type | Description |
|----------|------|-------------|
| `cameraParameters` | `object` (get/set) | Camera parameters including shutter, gain, trigger values, laser threshold |
| `backgroundSubtract` | `boolean` (get/set) | Enable/disable background subtraction |

#### Events

| Event | Payload | Description |
|-------|---------|-------------|
| `'initialized'` | `{from: 'Surface'}` | All subsystems ready |
| `'status'` | varies | Status updates from subsystems |

---

### GrayScan

Gray code pattern projection and camera correspondence mapping.

```js
const grayScan = new GrayScan(canvas, inputSimulator, cameraInterface, pictureDelay)
```

#### Constructor

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `canvas` | `HTMLCanvasElement` | | Canvas for displaying scan patterns |
| `inputSimulator` | `InputSimulator` | | Input simulator instance |
| `cameraInterface` | `CameraInterface` | | Camera interface instance |
| `pictureDelay` | `number` | `120` | Delay between frames in ms |

#### Methods

| Method | Description |
|--------|-------------|
| `flatScan(callback?, errorCallback?)` | Scan a flat surface to establish baseline correspondence |
| `calibrationMoundScan(sx0, sy0, sx1, sy1, callback?, errorCallback?)` | Scan with a known mound at bounding box `(sx0,sy0)-(sx1,sy1)` for height calibration |
| `moundScan(callback?, errorCallback?)` | Scan current surface to generate height map |
| `getCameraRaster()` | Returns `CameraRaster` |
| `getProjectorRaster()` | Returns `ProjectorRaster` |
| `getFlatRaster()` | Returns baseline `CameraRaster` |
| `getMoundRaster()` | Returns current surface `CameraRaster` |
| `getDiffRaster()` | Returns height `DiffRaster` |
| `getAllRasters()` | Returns all rasters as an object |
| `getProjectorDimensions()` | Returns `{width, height}` |

---

### Align

Live camera alignment visualization.

```js
const align = new Align(canvas, inputSimulator, cameraInterface)
```

#### Methods

| Method | Description |
|--------|-------------|
| `start()` | Start live camera display with alignment border |
| `stop(cb?)` | Stop alignment and resume tracking |

---

### ShutterEstimate

Automatic camera exposure optimization.

**Extends:** `Evented`

```js
const shutter = new ShutterEstimate(canvas, inputSimulator, cameraInterface)
await shutter.estimate(callback, errorCallback)
```

#### Properties

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `searchIncrement` | `number` (get/set) | `3` | Search step size |
| `brightnessThreshold` | `number` (get/set) | `400` | Pixel brightness threshold |
| `searchHigh` | `number` (get/set) | `100` | Maximum shutter value to search |

#### Events

| Event | Payload |
|-------|---------|
| `'status'` | `{from: 'ShutterEstimate', found: boolean, value?: number, searching: boolean, error?: Error}` |

---

### CameraInterface

Polymorphic camera abstraction combining image loading and settings control.

**Extends:** `Evented`

```js
const camera = new CameraInterface(imageLoader?, settings?)
await camera.detectCamera('USB Camera')
```

#### Methods

| Method | Description |
|--------|-------------|
| `detectCamera(cameraLabel, cameraURL?, options?)` | Auto-detect camera type and initialize. `options`: `{URLArguments?, proxyURL?}`. Returns `Promise<boolean>` |
| `setCameraParameters(camParams)` | Set camera parameters object |
| `goToDarkMode()` | Switch to dark mode for laser detection |
| `goToBrightMode()` | Switch to bright mode for scanning |
| `setBrightShutter(shutter)` | Set bright exposure value |
| `getBrightShutter()` | Get bright exposure value |

#### Events

| Event | Description |
|-------|-------------|
| `'imageLoader ready'` | Image loader initialized |
| `'settings ready'` | Settings interface initialized |
| `'camera failed'` | Camera stream failed |

### makeDummyInterface()

```js
const dummy = makeDummyInterface()
```

Returns a `CameraInterface` with no-op dummy loader and settings. Useful for testing.

---

## Laser Detection

### InputSimulator

Converts laser positions to synthetic DOM mouse events.

```js
const sim = new InputSimulator(canvas, cameraInterface, {trackingOn: true})
await sim.start()
```

#### Methods

| Method | Description |
|--------|-------------|
| `start()` | Start pointer detection loop |
| `stop()` | Stop pointer detection |
| `setTrackingOn(on)` | Enable/disable tracking |
| `setCameraRaster(cameraRaster)` | Set camera-to-projector mapping |
| `setDimensions(dataWidth, dataHeight)` | Set grid dimensions |

#### Properties

| Property | Type | Description |
|----------|------|-------------|
| `backgroundSubtract` | `boolean` (get/set) | Background subtraction toggle |
| `laserBrightnessThreshold` | `number` (get/set) | Laser brightness threshold |

#### Generated DOM Events

The InputSimulator fires synthetic mouse events on DOM elements under the laser:

- `mouseover` / `mouseout` - When laser enters/leaves an element
- `mousedown` / `mouseup` - When laser turns on/off
- `mousemove` - When laser moves
- `click` - When laser turns off

---

### PointerDetectorClient

Core laser detection loop. Captures camera frames and detects the brightest point.

**Extends:** `Evented`

```js
const detector = new PointerDetectorClient(
    cameraInterface,
    laserBrightnessThreshold, // default: 100
    pause,                    // default: 0 (ms between frames)
    allowSetCameraParams,     // default: true
    laserExposure,            // default: 16
    laserGain,                // default: 1
    laserColorTemp            // default: 6500
)
await detector.start()
```

#### Properties

| Property | Type | Description |
|----------|------|-------------|
| `running` | `boolean` | Whether detector is active |
| `state` | `'on'\|'off'` | Current laser state |
| `framesToBuffer` | `number` | Frames to buffer before state change (default: 5) |
| `backgroundSubtract` | `boolean` (get/set) | Background subtraction toggle |
| `laserBrightnessThreshold` | `number` (get/set) | Brightness threshold |

#### Events

| Event | Payload | Description |
|-------|---------|-------------|
| `'laser-on'` | `{u, v, x, y, i}` | Laser detected. `u,v`: normalized 0-1. `x,y`: pixel. `i`: intensity 0-255 |
| `'laser-off'` | none | Laser lost |
| `'laser-move'` | `{u, v, x, y, i}` | Laser moved |
| `'server-down'` | none | Camera server unreachable |

---

### findBrightestPoint Functions

Low-level laser detection running in a web worker.

```js
import {
    initWorker,
    findBrightestPointInImageData_usingWorker,
    findBrightestPointInImageData,
    averageRGB,
    sumGreyscale,
} from 'anysurface'
```

| Function | Description |
|----------|-------------|
| `initWorker(path?)` | Initialize the web worker. Default path: `"lib/Laser/brightestPoint_webWorker.js"`. For bundled usage, pass the path to `anysurface.worker.js` |
| `findBrightestPointInImageData_usingWorker(data, width, height, channels?, sumChannels?, backgroundSubtract?)` | Find brightest point using web worker. Falls back to main thread if worker unavailable |
| `findBrightestPointInImageData(data, width, height, channels?, sumChannels?)` | Find brightest point on main thread |
| `averageRGB(r, g, b)` | Average of RGB channels |
| `sumGreyscale(r, g, b)` | Sum of RGB channels |

---

### KalmanFilter

1D Kalman filter for smoothing noisy position data.

```js
const kf = new KalmanFilter()
const filtered = kf.filter(measurement, deltaTime)
```

#### Methods

| Method | Description |
|--------|-------------|
| `init(position?)` | Initialize/reset filter. Default position: `0` |
| `filter(measurement, deltaTime?)` | Combined predict + correct. Returns filtered position |
| `predict(deltaTime)` | Predict next state |
| `correct(measurement, deltaTime)` | Correct with measurement |

### KalmanFilterCoordinates

Wraps two `KalmanFilter` instances for 2D coordinate smoothing.

```js
const kfc = new KalmanFilterCoordinates({x: 0, y: 0}, dtMax)
const filtered = kfc.filter({x: rawX, y: rawY}, deltaTime)
// filtered.x, filtered.y
```

| Param | Default | Description |
|-------|---------|-------------|
| `position` | `{x: 0, y: 0}` | Initial position |
| `dtMax` | `0.2` | Max time delta before resetting filter |

---

### CursorFilter

Moving-window average filter for cursor smoothing.

```js
const cf = new CursorFilter(5) // window length
cf.addPoint([x, y])
const [avgX, avgY] = cf.average()
```

| Method | Description |
|--------|-------------|
| `addPoint(p)` | Add `[x, y]` point to window |
| `reset()` | Clear all points |
| `average(newPoint?)` | Get average position. Optionally add a point first |

---

### simulate(element, type, x, y)

Fire a synthetic mouse event on a DOM element.

```js
simulate(element, 'click', screenX, screenY)
```

---

## Scanning & Rasters

### Correspondence

Manages the full gray code scanning pipeline for camera-projector mapping.

```js
const corr = new Correspondence(cameraInterface, {
    vertFrames: 8,        // 2^8 = 256 columns
    horizFrames: 7,       // 2^7 = 128 rows
    darkStripeColor: '#000',
    lightStripeColor: '#ddd',
    varianceThreshold: 0.4,
    pictureDelay: 600,
})
```

#### Methods

| Method | Description |
|--------|-------------|
| `flatScan(canvas, callback, errorCallback?)` | Scan flat surface for baseline mapping |
| `calibrationMoundScan(canvas, sx0, sy0, sx1, sy1, callback, errorCallback?)` | Calibrate height estimation with known mound |
| `moundScan(canvas, callback, errorCallback?)` | Scan current surface for height map |

#### Properties

| Property | Type | Description |
|----------|------|-------------|
| `dataWidth` | `number` | Projector width (`2^vertFrames`) |
| `dataHeight` | `number` | Projector height (`2^horizFrames`) |
| `flatRaster` | `CameraRaster` | Baseline scan |
| `moundRaster` | `CameraRaster` | Current surface scan |
| `diffRaster` | `DiffRaster` | Height differences |
| `projectorRaster` | `ProjectorRaster` | Reverse mapping |

---

### Raster

Base class for 2D grid data structures.

```js
const raster = new Raster(width, height, initValue)
```

#### Methods

| Method | Description |
|--------|-------------|
| `reset()` | Reset all cells to initial values |
| `renderInCanvas(canvas)` | Render raster to a canvas element |
| `bilinear(x, y, prop, zeroValue?)` | Bilinear interpolation at fractional coordinates |
| `neighbors(x, y)` | Get 8-connected neighbor cells |

#### Properties

| Property | Description |
|----------|-------------|
| `data` | 2D array of cell objects |
| `width` | Grid width |
| `height` | Grid height |

---

### CameraRaster

Camera-space raster mapping each camera pixel to its projector coordinate.

**Extends:** `Raster`

Cell structure: `{x, y, min, max, variance, enabled}`

#### Methods

| Method | Description |
|--------|-------------|
| `disableLowVariancePixels(threshold)` | Disable pixels below variance threshold (uses ckmeans clustering) |

---

### ProjectorRaster

Projector-space raster mapping each projector cell to camera coordinates.

**Extends:** `Raster`

Cell structure: `{x, y, count, sumX, sumY, enabled}`

#### Methods

| Method | Description |
|--------|-------------|
| `ProjectorRaster.fromCameraRaster(cameraRaster)` | **Static.** Build reverse mapping from a `CameraRaster` |
| `lookup(projX, projY)` | Get camera coordinates for a projector position |
| `lookupInterpolated(projX, projY)` | Lookup with bilinear interpolation |
| `renderCoverageMap(canvas)` | Visualize pixel density as a heat map |

---

### DiffRaster

Height difference map between two scans.

**Extends:** `Raster`

Cell structure: `{diffValue, list?}`

#### Methods

| Method | Description |
|--------|-------------|
| `doDiff(flatRaster, moundRaster)` | Compute height differences between flat and mound scans |
| `pruneOutliers(n?, factor?)` | Remove outlier values. `n`: passes (default 1), `factor`: threshold (default 5) |
| `blur(n?)` | Smooth values. `n`: passes (default 1) |
| `upsample(newWidth, newHeight)` | Increase resolution with bilinear interpolation. Returns new `DiffRaster` |
| `clip(left, top, width, height)` | Extract rectangular region. Returns new `DiffRaster` |
| `paintDiff(canvas)` | Visualize heights with HSV color map |

---

### StripeScan

Gray code stripe projection and image capture.

```js
const scan = new StripeScan(cameraInterface, {
    horizFrames, vertFrames, varianceThreshold,
    darkStripeColor, lightStripeColor, pictureDelay
})
```

#### Methods

| Method | Description |
|--------|-------------|
| `init(width, height)` | Initialize working canvases |
| `scan(canvas, doneCallback, errorCallback?)` | Execute full gray code scan sequence |

---

### EpinodeEstimate

Estimates height direction from scan data for 3D surface reconstruction.

```js
const epi = new EpinodeEstimate()
epi.estimateEpinodeDirection(diffRaster, x0, y0, x1, y1)
epi.writeNormalizedHeightsInto(diffRaster)
```

| Method | Description |
|--------|-------------|
| `estimateEpinodeDirection(diffRaster, x0, y0, x1, y1)` | Estimate height angle from known mound bounding box |
| `writeNormalizedHeightsInto(diffRaster)` | Normalize height values to positive range |

---

## Camera Image Loaders

All image loaders extend `Evented` (via `DummyImageLoader`) and share this interface:

| Method | Description |
|--------|-------------|
| `getImage()` | Returns `Promise<HTMLImageElement>` from the camera |

### DummyImageLoader

Base class / no-op loader. Returns a blank 1x1 image.

### IPImageLoader

Loads images from IP cameras via laser-server (port 8080).

```js
const loader = new IPImageLoader(cameraURL, options)
```

### USBImageLoader

Loads images from USB/UVC webcams via browser `getUserMedia`.

```js
const loader = new USBImageLoader(cameraLabel)
```

### AxisLoader

Loads images from Axis IP cameras. Extends `IPImageLoader`.

```js
const loader = new AxisLoader(cameraURL)
```

### WebRTCImageLoader

Loads images via WebRTC connection.

### VideoServer

WebRTC signaling server using Firebase and PeerJS.

**Note:** Requires global `Firebase` and `Peer` objects via `<script>` tags.

### USB Camera Utilities

```js
import {
    fireUpDummyCameraToGetPermissions,
    getVideoDevices,
    getUsableVideoDeviceLabel,
    getDevicesIncludingGeniCam,
} from 'anysurface'
```

| Function | Description |
|----------|-------------|
| `fireUpDummyCameraToGetPermissions()` | Request camera permissions from browser |
| `getVideoDevices()` | List available video input devices |
| `getUsableVideoDeviceLabel()` | Get the first usable camera label |
| `getDevicesIncludingGeniCam(cameraURL?)` | List devices including GeniCam cameras from laser-server |

---

## Camera Settings Interfaces

All settings interfaces extend `Evented` (via `DummyCameraSettingsInterface`) and share:

| Method | Description |
|--------|-------------|
| `setExposure(value)` | Set camera exposure/shutter |
| `setGain(value)` | Set camera gain |
| `getExposure()` | Get current exposure |
| `getGain()` | Get current gain |

### DummyCameraSettingsInterface

No-op base class.

### IPLaserServerSettings

Controls cameras via laser-server REST API (port 8080).

### UVCServerSettings

Controls USB cameras via uvcc-webserver (port 3456). Required on Mac where browsers cannot control camera settings.

### BrowserUSBSettings

Controls USB cameras via browser-native `MediaStreamTrack` capabilities. Works on Windows/Android Chrome and partially on Linux.

### AxisSettings

Controls Axis IP cameras directly.

### detectCorrectUSBSettingsDriver()

```js
const settings = await detectCorrectUSBSettingsDriver(cameraLabel)
```

Auto-detects the correct settings driver for a USB camera based on platform.

### Settings UI Helpers

```js
import { settingsInterfaceToHTMLSnippet, getSliderList, capabilitiesToHtml } from 'anysurface'
```

| Function | Description |
|----------|-------------|
| `settingsInterfaceToHTMLSnippet(settings)` | Generate HTML controls for a settings interface |
| `getSliderList(settings)` | Get a list of slider configurations |
| `capabilitiesToHtml(capabilities)` | Render browser USB capabilities as HTML |

---

## Utilities

### Evented

Pub/sub event emitter base class used throughout AnySurface.

```js
class MyClass extends Evented {
    doSomething() {
        this.fire('done', {result: 42})
    }
}

const obj = new MyClass()
const unsub = obj.on('done', (data) => console.log(data.result))
// later: unsub() or obj.off('done')
```

| Method | Description |
|--------|-------------|
| `on(eventName, callback)` | Subscribe. Returns an unsubscribe function |
| `off(eventName, callback?)` | Unsubscribe. Removes all listeners if callback omitted |
| `fire(eventName, argument?)` | Emit event asynchronously (via `setTimeout`) |
| `fireAll(argument?)` | Fire all registered events |

---

### BlindCanvas

Visualizes projector cells with no camera coverage as a dark overlay.

```js
const blind = new BlindCanvas()
blind.draw(canvas, cameraRaster, dataWidth, dataHeight)
```

---

### projectorsList

Array of preset projector/camera parameter configurations.

```js
import { projectorsList } from 'anysurface'
// [{name: '...', params: {...}}, ...]
```

---

### CameraParameters

**Deprecated.** Throws on construction. Included for reference only.

---

### config

Build-time configuration object modified by the deploy system.

```js
import { config } from 'anysurface'
// {build_number, build_branch, build_time, build_root}
```

---

### Utility Functions

All from `lib/Utils.js`:

| Function | Description |
|----------|-------------|
| `delayPromise(ms?)` | Returns a promise that resolves after `ms` milliseconds (default: 100) |
| `fetchWithTimeout(url, timeout?)` | Fetch with timeout support |
| `generateGUID()` | Generate a random GUID string |
| `debounced(fn, delay)` | Debounce a function |
| `probeForFunctionToReturnTrue(fn, interval?, timeout?)` | Poll until a function returns true |
| `proxiedURL(url)` | Wrap URL through CORS proxy |
| `putTextOnCanvas(canvas, text)` | Draw text on a canvas |
| `logCanvas(canvas, label?)` | Log canvas contents to console |
| `logImg(img, label?)` | Log image to console |
| `imgToCanvas(img)` | Convert image element to canvas |
| `getImageDataFromImage(img)` | Get ImageData from an image element |
| `drawEmoji(canvas, emoji)` | Draw an emoji on a canvas |
| `hsvToRGB(h, s, v)` | Convert HSV to RGB |
| `colorizeDepthImage(imageData)` | Apply depth colorization to image data |
| `extractSquareFromImageData(imageData, x, y, size)` | Extract a square region from image data |
| `imageDataToFile(imageData, filename?)` | Convert ImageData to a File object |

---

## Logging

### ImageUploadQueue

Queued image upload manager.

```js
const queue = new ImageUploadQueue()
```

### signedUpload(imageData, url)

Upload image data with signed URL.

### getThumbnailURL(key)

Get thumbnail URL for an uploaded image.

### getImageURL(key)

Get full-size URL for an uploaded image.

---

## UI Components

### CalibratorWrapper

Custom HTML element that wraps the full calibration UI.

```html
<calibrator-wrapper></calibrator-wrapper>
```

**Note:** Importing `CalibratorWrapper` from the bundle registers `<calibrator-wrapper>` and its child custom elements (`<camera-selector>`, `<laser-calibrator>`, `<align-calibrator>`, `<grayscan-calibrator>`, `<scan-calibrator>`) as side effects.

### calibratorStyles

`CSSStyleSheet` instance with shared calibrator component styles.
