mappy
mappy · utilities · schema v1MAPPY is a multi-surface manual projection mapper. It
spawns up to six surfaces; each surface is fed by a distinct
video input (in1…in6), warped onto its own draggable quad in the output frame, and composited — painter's
order, OVER — into one video output you send to a projector.
model
- One surface — de-skew. Point a projector at an awkwardly-angled wall, then drag a surface's four corners until the projected image lines up square. The homography corrects the keystone / perspective distortion.
- Up to six — map a cube (or a stage set). Give each face of
a white cube its own feed; only ~3-4 faces are ever visible from one
projector angle, so six surfaces cover a rotating object or a multi-panel
set. Composite order (
in1first …in6last) lets a later surface paint over an earlier one where they overlap. - Manual only (v1). You align by hand on the card. The camera-assisted auto-align — point a camera at the projection and solve the homography from detected features — is a later phase. There is no camera input and no CV in v1 by design.
warp + composite
Every surface owns a four-corner quad in normalized [0,1] output
space, corner order TL, TR, BR, BL. A homography (the unit square → that quad) defines the projective warp.
The shader runs per output texel: it takes the output uv,
applies the inverse homography to find the matching source uv, and samples the input there — only where the source
uv is inside [0,1] (outside, the texel is transparent so the layers beneath
show through). The pure 2D projective math (DLT solve · apply · invert ·
column-major-for-GLSL) lives in $lib/video/mappy-homography and is
shared by the shader and the unit tests.
Surfaces composite in input order with an OVER blend. The composite is exposed
on the out port and as the on-card live preview.
Grids-first. A fresh MAPPY shows one surface,
and a live surface with no input connected renders its numbered calibration grid — a per-surface-tinted checker +
bright border + cross-hairs + a big seven-segment digit naming
the input that will feed it. So with nothing patched the output is the
grid(s): set the geometry up on the physical faces first (drag corners; use +/− to add up to six surfaces), then connect video.
The instant inN is connected, surface N swaps grid →
warped video in the quad you already mapped — surface ↔ input is fixed, no
reassignment. The GRID toggle forces the grid back on for
every live surface (a re-alignment override); connecting inN auto-activates surface N even beyond the count.
card & MAP editor
The card has a live composite preview with draggable corner handles + quad
outlines (coloured per surface), a +/− surface
counter, a MAP button, the GRID toggle, and a per-surface
legend (focus · FIT/CROP · reset · a ● video / ○ grid state).
Drag a corner to pin it, or grab the surface's interior and drag to move the whole quad bodily — on the card
preview and in the editor. Precise corner-pin work happens in the MAP editor — a full-window canvas with big handles,
drag-inside-a-surface to move it bodily, surface tabs, a per-surface FIT/CROP
toggle, and snap-to-grid for matching a real edge. All ports live on the
yellow drill-down patch panel — no raw side jacks.
FIT vs CROP (per surface)
Each surface has its own FIT toggle (default ON; surfaces are independent). It is one cheap per-surface shader uniform — no extra render pass, no readback.
- FIT (default) — zoom-fit. The homography squeezes the whole source
[0,1]²into the dragged quad. Resize the box and the entire frame stretches to fill it (the original behaviour). - CROP — window at native scale. The quad becomes a moveable window onto the source, which is pinned 1:1 into output space: moving the box pans across the natively-placed source, and resizing it crops more or less. The quad still provides the shape/mask — only the part of the source under the box shows. Use it to frame a region of a feed onto a physical panel without distorting it.
inputs
| id | cable |
|---|---|
in1 | video |
in2 | video |
in3 | video |
in4 | video |
in5 | video |
in6 | video |
outputs
| id | cable |
|---|---|
out | video |
params
| id | label | range | default |
|---|---|---|---|
showGrid | Grid | 0..1 | 0 |
surfaceCount | Surfaces | 1..6 | 1 |
usage
- Route
out→ OUTPUT (your projector). With nothing patched yet, MAPPY projects surface 1's numbered grid. - Open MAP (or drag on the card) and pull the grid's four corners until it lines up with the physical screen / cube face.
- Hit
+to add surface 2 (it drops in as an inset grid showing the digit “2”), map it onto the next face, and repeat — up to six surfaces. - Connect a video source into
inN— surface N's grid is replaced by that feed, warped into the quad you already mapped. Flip GRID back on any time to re-check alignment.