Commit Graph

8 Commits

Author SHA1 Message Date
3dtours d52d4c4281 feat(studio): redesign LIGHT tab to Lumetri style and fix mobile inpaint freeze with worker proxy and patch cache 2026-10-14 11:01:52 +07:00
3dtours 8fee6693bf fix(studio): an iPhone keeps the repair off WebGPU, off the worker pool and at 384 pixels, the three things its page did not survive 2026-10-14 09:50:51 +07:00
3dtours 5aa6a5ba23 fix(studio): a repair lands under the brush with no pill over it, and a browser with no device is not asked for one 2026-10-14 08:59:13 +07:00
3dtours 836858c36c fix(studio): the repair keeps to a worker wherever it falls back, so a device that cannot run the graph cannot freeze the page 2026-10-14 00:52:58 +07:00
3dtours 4ff5eca71a fix(studio): the repair model runs in a worker where the phone has no device, so the page keeps answering fingers 2026-10-14 00:18:35 +07:00
3dtours 550e688b3c revert(studio): the repair is drawn once again, and the model's own answer is the only one the stage shows
The two rounds were meant to answer the stroke sooner, but a preview cannot be
half a repair: the blurred fill is what a machine without the runtime gets, and
with it on the stage a spot of dirt came back smeared rather than gone — worst of
all on a run of strokes, where each new one cancels the model's round that was
still on its way and leaves the blur standing longest. The repair that works is
the one that waits for the model, and the wait is worth it.

The worker stays available but is switched off with the rest: this reverts the
runtime's proxy along with the second round, so the stage is exactly what it was
before, lag and all.

Reverts 5489114.
2026-10-12 22:05:45 +07:00
3dtours 54891148a9 fix(studio): the repair runs off the page's own thread, and a stroke is answered twice so the hand is never held
The graph is seconds of solid arithmetic however large the crop is, and it ran
where the pointer lives: the brush lagged behind the hand for exactly as long as
the model took. The runtime's wasm provider now works in a worker of its own, so
the page keeps drawing while the repair is thought through.

The wait itself stays — it is the model's, not the page's — so a preview paints
the blurred fill first and lets the model's version of the same mask replace it.
Filing and export still wait for the model: the faster answer is for the eye
waiting on the brush and for nothing else.

Measured on the same photo and stroke, worst main-thread gap 3703 ms before and
487 ms after; previews land at 1.0 s and 5.3 s, and the model's render is the one
left on the stage.
2026-10-12 21:43:00 +07:00
3dtours 15fb4422dc feat(studio): HEAL invents what was under the brush with MI-GAN, and keeps the blurred fill for the machines that cannot run it
The dust brush filled its hole with a blur of the hole's own rim — the light
beside it, carried in. Right for a speck on a wall, and visibly thin over
anything with structure: a stroke across a shirt came back as the average of a
shirt. The fill is now a learned one.

engine/inpaint.ts runs MI-GAN (andraniksargsyan/migan, the same
`migan_pipeline_v2.onnx` inpaint-web ships) through onnxruntime-web on the
visitor's own machine: 27MB of weights in public/models, WebGPU where the graph
fits the provider, the processor otherwise, one warm-up pass so the first repair
is not the one that pays for the kernels. It is handed the masked crop and
nothing else — the model's mask polarity is 255 KEEP / 0 HOLE, the opposite of
the obvious guess, and the other way round repaints the frame and leaves the
hole (measured).

Step 6e of the renderer cuts the crop at the resolution the model will actually
run at (512 on its longest side — the graph is fully convolutional and would
take a whole frame, and ten seconds over one), builds the mask from the brush's
own circles, and draws the answer into the fill surface at its own place in the
box. The composite, the feathered mask and the untouched frame around it are
unchanged, so nothing outside the mask moves — and when the model cannot be had
the blurred fill is still built first and still stands. The preview gets this
for free: renderPhoto was already async and the preview was already debounced.

Node probe: the model + polarity + read/write path run; heal-check.mjs keeps
measuring the fallback and now asserts the wiring and the polarity. Browser:
engine/inpaint.ts in a real Chromium returns a patch (hole moves, kept pixels
within 0.02 of a level), and the built app renders a 42-spot stroke in 4.7s on
single-threaded wasm with no fallback warning — 1.15s and the warning when the
model is taken away.
2026-10-12 21:07:09 +07:00