Commit Graph

10 Commits

Author SHA1 Message Date
3dtours cc88471256 Offer the three proposed font groups in Themes
The theme menu now carries a fourth choice beside light/dark and the accent:
the font pairing. All three pairings are free for commercial use (SIL OFL),
have a Vietnamese subset, and are self-hosted — the landing still makes no
CDN request.

- styles/fonts.css: 22 @font-face blocks for Plus Jakarta Sans, Inter,
  JetBrains Mono, Fraunces, Be Vietnam Pro, Courier Prime and Space Mono,
  vietnamese/latin-ext/latin subsets only, under public/assets/fonts.
- styles/tokens.css: [data-fonts="studio|editorial|native"] sets --font,
  --font-heading and --mono. Studio (Plus Jakarta Sans + Inter + JetBrains
  Mono) is the default.
- theme/: FontSetId + FONT_SETS, persisted as rc.fonts, applied as
  <html data-fonts> next to data-theme and data-accent.
- TopBar and the landing nav both get the picker; on the landing the theme
  tool now opens a small popover (light/dark + font group) instead of
  toggling on click.
- landing.css: --lp-display/--lp-mono now resolve to the chosen group, so the
  picker retypes the whole page. Syne.woff2 goes with its @font-face.
2026-09-17 19:20:23 +07:00
3dtours 51e572b9ce Persist the studio session across reloads
The working photo and every knob the workspace holds now survive a reload,
for guests as much as for signed-in users:

- engine/session.ts: the knobs go to localStorage (rc.studio.v1) as small
  JSON; the photo goes to IndexedDB, because a 12MP JPEG does not fit in
  localStorage. Both fail soft (private mode, quota) — the studio still works,
  it just forgets.
- App.tsx: state seeds from the stored snapshot synchronously, so the first
  paint already holds the user's settings; the boot effect pulls the photo
  back and adopts it with keepGeo, so the restored params are not clobbered
  by the photo's own EXIF.

Recipes a guest creates with SAVE RECIPE stay session-only, as asked — they
are still gone on reload (create-test asserts it).
2026-09-17 19:12:29 +07:00
3dtours 1446e852b1 Apply the CREATE form's knobs to the photo in realtime
Every row now feeds the open render as it is typed, so a recipe's effect is
visible before it is saved. The draft is not an undo step: SAVE/EXPORT stays the
only thing that commits it, and merely opening the tab changes nothing.
2026-09-17 19:05:59 +07:00
3dtours a684b178b6 Use the app icon as the web favicon and landing logo
RecipesCamIcon.png (scaled to 256px) becomes favicon + apple-touch-icon and
replaces the drawn camera svg in front of the landing wordmark, which now sits
a touch closer to it.
2026-09-17 18:59:41 +07:00
3dtours d31d945827 Add the CREATE RECIPES tab to the web app
The phone's RecipeCreateModal becomes a rail tab with the same rows, seeding
from the look on screen and clamping the same way. SAVE RECIPE applies the new
look, lists it under RECIPES and, when signed in, stores it on the account; a
guest's copy stays in memory and goes away with the page. Signed-in users can
also export the recipe as the app's encrypted .recipe file (shared/utils
/recipeShare.ts vendored byte-identical from the RN project).
2026-09-17 18:56:17 +07:00
3dtours f2e5e9abc9 Give the landing the app's theme and language switches
The blueprint page was dark-only and English-only. It now carries the same
two controls the workspace TopBar has, in the nav's top-right cluster: ◐ flips
light/dark (a paper palette for the same funnel — surfaces and ink flip, the
amber/red accents stay) and VI/EN flips the language, with the whole page of
copy, the FAQ, the pricing tables and the VIP badge all following it. Amber
text switches to a darker #a16207 on the light theme so it keeps ~4.9:1 on
white.

The register account is back as the old landing had it: a "ĐĂNG KÝ" button
pointing at /app?auth=1, and that URL now actually opens the auth dialog on
its sign-up tab (AuthModal takes an initialMode). The nav also collapses to
the hamburger below 1160px now, and the logo/tools shrink below 680px, so the
row still fits a 360px phone.
2026-09-17 18:40:05 +07:00
3dtours 340f0374fc Rebuild the web landing page to the blueprint spec
Ten dark cinematic sections: fixed glass nav with a hamburger sheet, hero
with the badge/dual CTA/stats bar, a pausable 35mm film-strip marquee, the
live preset tester (5 stocks, HUD, spec bars), the three-knob custom recipe
simulator, the 6-card feature grid, the QR sharing showcase, free-vs-Pro
pricing, reviews + FAQ accordion and the final CTA/footer.

The page owns its palette and its .lp-* styles, so it renders the same in
either workspace theme, and it pulls no CDN: Syne is bundled and the six
sample negatives are vendored (see docker/README.md). Store buttons raise a
toast instead of the old alert(). The now-dead landing CSS and the unused
land.* dictionary keys are gone.
2026-09-17 18:26:18 +07:00
3dtours dace19aec4 Match the phone's chip-strip panel on the web
The chips column was a stack of labelled sections; the phone opens one row at
a time. Port that shape: tapping a tool tab shows the tab's chips, tapping a
param chip opens its ruler above them, tapping a group chip opens its options
strip, and either closes the other. RESET leads the row (amber while dirty)
and PHOTO STYLE / RECIPES / WATERMARK are strips instead of inline chips.
2026-09-17 18:11:18 +07:00
3dtours c00c605dd7 Fix header popover hanging off-screen on narrow viewports
The header wraps under 860px, so a menu-wrap can land at the start of a row.
`.popover` is right-anchored to its button, so the theme/language/account menu
rendered at x=-280 of a 390px screen — half of it off the left edge and its
buttons unclickable. Anchor the popover to the full-width header on narrow
screens instead.

Measured at 390x844 before/after: popover x=-280 → x=56, w=326, fully inside.
2026-09-17 17:50:50 +07:00
3dtours 8c6e7930db Add self-contained docker/ stack for the web UI
`docker/` now holds the whole web build — frontend (Vite + React + CanvasKit),
backend (Fastify + SQLite) and the compose file — so the folder can be moved to
another machine and run without the React Native project:

    cd docker && cp .env.example .env && docker compose up -d --build

Only `${WEB_PORT:-8090}` is published; nginx serves the SPA and proxies /api to
the `api` container over Docker's DNS. Photos never reach the server.

The shared render code is vendored into `docker/frontend/shared/` and aliased to
a CanvasKit shim, so the app's own frameUtils/toneShader/jpegDpi run unchanged.

Fix the all-black render on GPU surfaces: `MakeWebGLCanvasSurface` creates a
separate WebGL context per call, and a texture from one context cannot be
sampled by a surface on another — so any pass that drew a snapshot onto a second
surface (output sharpen, screen sharpen, polaroid/wallframe cards) came out
solid black, while the raster fallback was correct. Use one shared
GrDirectContext + MakeRenderTarget instead.

Verified in headless Chromium against the running stack: 12MP JPEG in, preview
mean=120.5 sd=60.5, export 2048x1536 mean=107.2 sd=62.1, JFIF density 300/300,
EXIF present, no console errors; health/signup/login/me/recipes all 2xx through
the nginx proxy.
2026-09-17 17:43:03 +07:00