CROP chip on the FRAME tab for the library's plain frames: NONE, FREE
(drag the box) and the fixed ratios 1:1, 2:3, 3:2, 3:4, 4:3, 16:9. The
preview draws the keep-rectangle over the photo and the export honours it
pixel-for-pixel, pinching and dragging inside the band to pick the framing.
- Viewfinder: build frameRect from the normalised rect so the Skia canvas
never sees undefined width/height (nothing to commit until now), keep
the watermark drag target across the WATERMARK tab so a zoomed photo
no longer resets, and derive the crop band + export rect from the photo
fit rect.
- exportEngine: crop by fraction rect (or the ratio fallback) before the
frame is composited.
- Leaving a plain frame clears the crop, and the ratio strip closes with
the CROP chip it belongs to.
Three WATERMARK/FRAME behaviours that share the stamp geometry:
* GPS mark: drag it anywhere on the frame/photo area and pinch it bigger or
smaller. The 0..1 anchor plus the size multiplier ride along in the export
options, so a framed file (whose canvas IS the card/frame) burns the mark in
at exactly the fraction the preview showed.
* The photo's own pinch zoom stays available while the WATERMARK editor is
closed, so a two-finger zoom is never swallowed by the mark while its panel
is open.
* WALL FRAME gains a WALL PORTRAIT / WALL LANDSCAPE chip: the artwork hangs
in its own 4000x3117 orientation instead of the default 90-degree rotation.
- FX: new VIGNETTING 0-10 control (chip + slider). Darkens the four
corners of the photo with a radial gradient whose radius is the photo
diagonal/2, so the falloff stays circular on any aspect. Applied in
preview (camera overlay, polaroid/wall window, plain library) and in
exportEngine pass 6b, always on the picture, never on the mat.
- LIGHT: new VIBRANCE -10..+10 (chroma-masked saturation in the tone
shader: vivid pixels move least). Renamed the existing saturation
control chip from COLOR to SATURATION - same param, clearer label.
- Fix: <Shader> takes a RuntimeEffect, not a gradient SkShader; the
preview vignette threw "Object is not a HostObject" when it got one.
Use the declarative <RadialGradient> child on the Rect instead.
- Preview: drop the "AE/AF LOCKED - TAP TO UNLOCK" banner; the lock
reticle is now itself the unlock touch target.
The built-in lens filter, simulated the way it is done in Photoshop: pull the
highlights out with a hard contrast curve (out = 2.5*in - 1.5, black below 0.6),
Gaussian-blur that selection, then Screen it back over the photo at reduced
opacity. Screen against a near-black pixel is a no-op, so areas with no
highlight within the blur radius come back byte-identical while lit areas
spread their light.
One 0..10 knob drives both the radius (4%..1.9% of the width, ~10..50px at
2560 wide) and the opacity (0.15..0.5), matching the recipe's 15-50px radius
range. The extraction composes on top of the recipe colour matrix so a
monochrome look glows white instead of leaking the original colours back.
Runs in the Skia export engine only; the P5 native path is not wired into the
app (dev parity probe only), so it is left alone for now.
Watermark editing no longer covers the photo: the preview letterboxes the
image inside its fit rect while the deck is open, and the idle hint is gone.
The FRAME tab can rotate a library photo 90 degrees clockwise. Rotation
swaps the pixel dimensions instead of the frame, so the polaroid/wall window
keeps its aspect and every consumer (cover crop, watermark area, export) picks
up the new orientation from width()/height() with no extra layout branch. The
rotate surface is CPU-backed on purpose - a GPU snapshot loses its pixels
before the next frame and renders the photo black.
Custom watermark text can now be dragged anywhere on the photo, double-tapped
to re-edit, and is only baked into the file once ACCEPT is pressed; the export
engine takes the same position. It also gained COLOR/SIZE/FONT chips, with the
font list read from the OS via Skia's FontMgr so any installed family can be
used.
- Settings STARTUP MODE chips (AsyncStorage startup_mode): default = clean camera
+ PROVIA neutral 4:3, last = restore full session look.
- initSession: resolve sim-* recipe ids via FILM_SIMS (fix clobber of session
ratio/adjustments to 4:3 canonical); restore via setSelectedRecipe not
applyRecipe so user tweaks (frame/geotag/ratio) survive restore.
- applyDefaultStartup turns GPS watermark OFF (user-requested default).
- Shutter: OFF must not play click on must-play-policy devices. VisionCamera
v5.2.3 HybridPhotoOutput.kt plays MediaActionSound itself gated by
(enableShutterSound ?: true) || mustPlayShutterSound — on Xiaomi mustPlay=true
so OFF still clicked. Both capture paths now gate on enableShutterSound != false.
node_modules patch not trackable -> artifacts/patches/vision-camera-shutter-silent.patch.
Verified on Xiaomi 12S Ultra: log SND user=false -> play=false; cold-start
DEFAULT shows GPS WATERMARK OFF.