# AGENTS.md Guidance for AI agents (and humans) working in this repository. For the user-facing overview see [`README.md`](README.md); for the full design see [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md). ## What this is **wimp** is a fully client-side web image editor: crop, transform, color adjust, and export to JPEG/WebP/PNG/AVIF. Images never leave the browser. React 19 + React Compiler on the main thread; all pixel work and encoding run in a Web Worker. ## Commands Requires Node 22+ and npm. ```bash npm install npm run dev # Vite dev server npm run typecheck # tsc, no emit — run this after changes npm run build # tsc + production build npm run preview # serve the production build ``` There is no test runner or linter configured. The verification bar is: `npm run typecheck` passes and `npm run build` succeeds. For behavioral changes, verify in the browser (load an image, exercise the affected path, export). ## Layout ``` index.html entry + inline SVG favicon vite.config.ts react + react-compiler (babel) + tailwind; COOP/COEP headers src/ main.tsx React root index.css Tailwind import + @theme tokens types.ts Template, Adjustments, ExportRequest/Result, worker msgs templates.ts preset data + helpers hooks/useEditor.ts reducer: ALL editor state + actions lib/ image.ts load, filename, download, formatting exportClient.ts main-thread handle to the worker filter.ts shared CSS/canvas filter builder vips.ts guarded lazy wasm-vips loader cn.ts classnames helper workers/export.worker.ts decode -> transform -> encode components/ App.tsx, TopBar, Dropzone, EditorCanvas, TemplatePicker, panels, ui, Slider, icons docs/ ARCHITECTURE / WORKLOG / VERIFICATION + deferred/ ``` ## Conventions and invariants - **State lives in one reducer.** All editor state and actions are in `src/hooks/useEditor.ts`. Add new editor state there, not in scattered component `useState`. - **Preview must match export.** The filter string in `src/lib/filter.ts` is the single source of truth used both as react-easy-crop's `mediaStyle.filter` and the worker's `ctx.filter`. The crop/rotate/flip coordinate math mirrors react-easy-crop's `getCroppedImg` recipe (see ARCHITECTURE.md "Coordinate model"). If you touch one side, touch the other and keep them identical. - **Heavy work stays in the worker.** Decoding, transforming, resampling, and encoding belong in `src/workers/export.worker.ts`, reached via `src/lib/exportClient.ts`. Don't move pixel/encoding work onto the main thread. - **Templates are plain data.** Add presets by appending rows to `TEMPLATES` in `src/templates.ts`; no code changes needed for a new preset. - **React Compiler is on.** Don't hand-add `useMemo`/`useCallback` for performance; let the compiler handle memoization. Write idiomatic components. - **Tailwind v4, no config file.** Design tokens live in `@theme` in `src/index.css`. Use the existing token utilities (e.g. `bg-surface`, `text-muted`, `ring-accent-strong`). ## Cross-origin isolation (read before adding network assets) The app sets `Cross-Origin-Embedder-Policy: require-corp` so `SharedArrayBuffer` is available for threaded WASM (wasm-vips, jSquash). Under `require-corp`, any cross-origin subresource (e.g. an ML model from a CDN) is **blocked** unless it carries a `Cross-Origin-Resource-Policy` header. Self-host model/wasm assets same-origin rather than fetching from a CDN. See `docs/deferred/README.md`. The wasm-vips fast path also requires cross-origin isolation; `src/lib/vips.ts` guards the loader and the worker falls back to canvas otherwise. Keep both paths working. ## Scope discipline Make the change requested and nothing more — no drive-by refactors, no speculative abstractions, no comments that restate the code. Match the existing style of nearby files. Deferred/future work is tracked in `docs/deferred/`; don't start it unless asked. ## Git Develop on the branch you were assigned, commit with clear messages, and do not open a pull request unless explicitly asked.