3dtours 1f6c97be62 web: let a mask's own edge turn it, and another chip put it down
A mask could only be taken hold of by its pin or by one of the handles, and the
pin of a linear mask sits on the middle of its own line, so the press a hand aims
at "that line" was the press that moved the shape. What it moved by was worse: a
ramp is stored as the two points it falls between, and 'move' measured the hand
against the shape's first point, so the first move of a drag put that end under
the pointer and threw the rest of the ramp sideways by half its length — the
shape landed somewhere off to the side of the hand instead of under it. The move
now takes its delta from the pin the press landed on, which is what the press
wanted, and which for an ellipse was already the centre it moved by.

The drawn outline is the shape's own handle. A press on the line a ramp falls
across — any of the three, anywhere along it — or on an ellipse's rim, turns the
shape; the nodes that resize it sit on that same outline and are drawn over it,
so a press on one of those is still a resize. That is the Lightroom gesture: the
edge is what you drag to aim a gradient, and the ends and the axes are what you
drag to lay it out again. Until now a press on the edge was a press on the layer,
which read it as the start of the next shape and laid a second mask down while
the first was being turned. The band is sixteen screen pixels wide and does not
scale with the zoom, so a finger finds it at any size of photo.

A mask is chosen by pressing it on the picture, so the keys the hand is on are
DELETE, which is what the chip beside the photo already says. And the column the
chosen mask puts up — its name, DELETE, and its knobs as rulers — belongs to the
mask tool: another chip puts that tool down and takes the column with it, because
a photo still armed to draw shapes is not what a hand reaching for a knob is
asking for. The shape stays chosen and stays live in the render; the mask chip
brings its column straight back.

ponytail: Backspace is read as DELETE as well, since that is the key the label
sits under on a Mac keyboard, and is the one shortcut this adds. A mask can still
only be chosen while a mask tool is armed — the shapes answer the pointer through
the layer that only exists then — so the column coming back with the mask chip is
also the way back to a shape drawn a moment ago.

Verified: tsc clean; mask-probe 50/0 on the dev server and again on 8090 — a ramp
lands with its pin on its middle, dragging its own edge turns it (ends at 0.200
and 0.800, one pin, no second shape laid), the same drag on an ellipse's rim turns
that (90deg -> -39deg, one pin), the pin takes the shape with the hand to where
the hand went (0.560,0.560, no sideways throw), another chip leaves 0 mask
columns and the mask chip brings 1 back, and DELETE takes the chosen shape off the
photo with its grade (64 -> 255, then back to 61). brush-edit 33/0, heal-idle
23/0, heal-zoom-drag 28/0, landing/pro-gate/award-column/otp-code/tone-curve/
hsl-panel/grain-controls/chip-edge/chips-desk/slider-reset/temp-swatch all ALL
PASS, backend 180/0. panel-test (4), histogram-wb (1) and studio-save-hl fail
exactly as they do on the build before this one, on their own tabs.
2026-09-24 11:18:59 +07:00
…
…
…
…
…
…
…
…
…

RecipesCam

RecipesCam is a camera and photo-editing app built around recipes — reusable looks that carry a film simulation plus a full set of adjustments. You shoot or open a photo, dial in a look, and keep it as a recipe you can apply again, share as a .recipe file, or save to your account.

It ships twice from one repository: a React Native (Expo) app for iOS and Android, and a self-contained web build under docker/ that runs the same render pipeline in the browser.

What it does

  • Shoot with a recipe applied. Live viewfinder, GPS-tagged captures, and the recipe baked into the saved file.
  • Film simulations. Built-in looks — PROVIPES, VELVIPES, CLASSIC CHRIPES, CLASSIC NEGIPES, ASTIPES, ETERNIPES, ACRIPES, B&W HIGH CONTRAST and the LC STREETLIFE pair — each with its own grain and tone curve.
  • The full adjustment set. Exposure, contrast, highlights and shadows, saturation, colour temperature, clarity, grain, and an HSL mixer with a colour picker that samples straight off the photo.
  • Geometry. Crop to a fixed ratio or free-form, quarter turns, and a straighten ruler, plus printed frames (classic border, retro instant, wall frame portrait/landscape).
  • Finishing. Watermark and GPS stamp, EXIF carried through the export, JPEG written with a proper 300 DPI JFIF header.
  • On-device upscaling. A Real-ESRGAN pass runs locally when an export asks for more pixels than the source has — no server sees the photo.
  • Recipes. Save, favourite, export and import .recipe files; the web build keeps them in your account, the phone build also keeps them on device.

The two builds

Build Where Stack
iOS / Android repo root Expo + React Native, @shopify/react-native-skia for the render pipeline, NativeWind for styling
Web docker/ Vite + React, CanvasKit (canvaskit-wasm) for the same pipeline, Fastify + SQLite API for accounts and recipes

The render engine is shared by design: the web build compiles the app's own src/utils/* and type definitions unchanged, with @shopify/react-native-skia aliased to a CanvasKit shim (docker/frontend/src/engine/skiaShim.ts). A look looks the same on both because it is the same code.

Running the web build

cd docker
cp .env.example .env
docker compose up -d --build
# → http://localhost:8090

Photos never leave the browser: grading, framing, watermarking and JPEG encoding all run in the visitor's tab; the API only stores accounts and recipe JSON. See docker/README.md for the layout and the proxy setup.

Running the app

npm install
npx expo start          # Expo Go / dev client
npx expo run:android    # or run:ios for a native build

Repository layout

App.tsx, src/           the Expo app: screens, tool rail, viewfinder, shaders
docker/                 the web build (frontend + API + compose file)
  frontend/shared/      vendored copies of the app's types and utils
  frontend/src/engine/  CanvasKit shim, export engine, super-resolution
docs/                   privacy policy
THIRD_PARTY_NOTICES.md  licences of the bundled fonts, models and libraries

Licence

See LICENSE and THIRD_PARTY_NOTICES.md.

S
Description
No description provided
Readme 7.8 GiB
Languages
TypeScript 92.9%
Kotlin 5.7%
JavaScript 1.3%