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.
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import { initSkia, hasGpu } from './skiaShim';
|
||||
import type { RenderAssets } from './exportEngine';
|
||||
|
||||
// One CanvasKit instance per page, one copy of the three render assets. The wasm
|
||||
// file is served from /wasm/ (scripts/copy-wasm.mjs puts it there at build time);
|
||||
// the fonts and the wall-frame artwork are in public/assets.
|
||||
let assets: RenderAssets | null = null;
|
||||
|
||||
async function buf(url: string): Promise<ArrayBuffer> {
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) throw new Error(`fetch ${url}: ${res.status}`);
|
||||
return res.arrayBuffer();
|
||||
}
|
||||
|
||||
// The engine is only usable on a WebGL-backed surface (see skiaShim.ts), so the
|
||||
// app has to know whether it got one: reporting "no WebGL" beats silently
|
||||
// spending minutes per photo on the raster fallback.
|
||||
export function probeGpu(): boolean {
|
||||
return hasGpu();
|
||||
}
|
||||
|
||||
export async function loadEngine(): Promise<{ assets: RenderAssets; gpu: boolean }> {
|
||||
await initSkia({ locateFile: (file) => `/wasm/${file}` });
|
||||
if (!assets) {
|
||||
const [textFont, emojiFont, wallframePng] = await Promise.all([
|
||||
buf('/assets/Cousine-Regular.ttf'),
|
||||
buf('/assets/NotoEmoji-GPS.ttf'),
|
||||
buf('/assets/wallframe.png'),
|
||||
]);
|
||||
assets = { textFont, emojiFont, wallframe: new Uint8Array(wallframePng) };
|
||||
}
|
||||
return { assets, gpu: probeGpu() };
|
||||
}
|
||||
Reference in New Issue
Block a user