BEN2 becomes the new default local backend (clean cutouts, strong on
hair/fur edges), with BiRefNet-HR available as a high-res/print
alternate and U2Net kept as the lightweight fallback. Both are
MIT-licensed and download weights from HuggingFace on first use
(cached via the existing hf_cache bind mount), unlike U2Net/SAM which
need an explicit download script.
- config: new BG_REMOVAL_MODEL setting (default "ben2")
- tools.py: remove-background-base64 now tries local backends in
order (request.model override > BG_REMOVAL_MODEL > ben2/u2net),
falling back to rembg's birefnet-general session as a last resort
- requirements.gpu.txt / Dockerfile.gpu: add ben2 + transformers deps
needed for the new backends, with a build-time smoke test for ben2
- frontend: model dropdown in the Remove Background dialog, threaded
through api.js to the new request field
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ro4PwQKvSc3CH19LSN21Ht
U2Net only ever downloaded lazily on the first Remove Background click,
unlike SAM which retries on every container start. If that one attempt
failed (DNS/firewall) the model was never fetched again, surfacing as
"No background removal method available. Install u2net or rembg."
Mirrors the existing SAM auto-download/AUTO_DOWNLOAD_SAM pattern for
U2Net, and documents manual host-side recovery in the README.
Also deletes backend/app/services/u2net_model.py (hand-written
U2NET/U2NETP PyTorch classes) — unused since tools.py switched to
cv2.dnn.readNetFromONNX for background removal.
- Backend: POST /api/image/replace-subject
Uses rembg to extract the subject from a source photo, scales it to fit
the selection mask bounding box (or canvas centre when no selection is
active), applies a partial LAB color transfer (blend=0.45) so the
subject's lighting matches the background, then composites the result.
Also adds POST /api/image/extract-subject for standalone subject extraction.
- Frontend: "Replace with subject from file" button in the selection panel
(selection_actions.js) — opens a native file picker so no clipboard API
or HTTPS is required. Calls the new endpoint with the current SAM mask.
- Frontend: Image > Replace Subject (AI)... menu entry backed by
modules/image/replace_subject.js — a full dialog with file picker,
thumbnail preview, and "match background lighting" toggle. Works with
or without a prior Smart Select; if a selection exists it confines the
subject to that region.
https://claude.ai/code/session_01UtrvbisMp1yGu6PqeLmrFr
Build / pip layer fixes:
- Add BUILDID ARG to Dockerfile.gpu; pass from docker-compose.gpu.yml build args
so pip layers can be force-busted without --no-cache:
BUILDID=$(date +%s) docker compose -f docker-compose.gpu.yml up --build
Model download (DNS-blocked environments):
- Change HF model cache from named volume to ./data/hf_cache bind mount
so models can be pre-downloaded on the host (no rebuild needed)
- Remove now-unused hf_model_cache named volume
- README: add iptables fix + huggingface-cli offline download instructions
Error handling improvements:
- ai_edit_region: catch ConnectError/Errno-3 → return 503 with exact fix commands
- _require_remote: give actionable message when local_gpu provider fails to load
- _build_provider: catch AttributeError (torch.xpu from wrong diffusers) not just ImportError
- local_diffusion.py: fix docstring to reflect <0.29.0 pin
https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
- Pin diffusers to >=0.28.0,<0.29.0 to avoid AttributeError on torch.xpu
(diffusers 0.29+ requires PyTorch 2.4 but base image ships 2.1.2)
- Pin transformers to <4.40.0 to match
- README: add SAM offline download troubleshooting for DNS-blocked containers
- SelectionActions panel: 'Selection ready' title + subtitle makes clear
nothing has fired yet; AI actions show inline description (not just tooltip);
section labels 'AI Actions' / 'Classic Tools'; scale hint updates live;
Enter key submits AI edit prompt; _actionCard hover border for clickability
https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
ai_tools.py: add 'from io import BytesIO' — scale_selection and paste
endpoints used BytesIO directly but it was only imported locally in one
unrelated function, causing NameError on every scale call.
provider-badge.js: redesign badge to fit the narrow (~40px) left toolbar.
Was rendering 'GPU · sdxl_offload · Quadro RTX 3000' inline which wrapped
into multiple lines covering tool icons. Now shows a status dot + short
label (SDXL / OAI / Rep…) with all details moved to the hover tooltip.
https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
main.py referenced info.vram_gb but the field is info.vram_total_gb.
This crashed the FastAPI lifespan hook on every startup when
AI_PROVIDER=local_gpu, causing a restart loop.
https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
Backend:
- local_diffusion.py: add _make_step_cb() that writes step/total_steps/
progress into _states on every diffusers callback_on_step_end; wired into
txt2img, inpaint, img2img with TypeError fallback for older diffusers
- ai_tools.py: GET /api/generate/progress SSE endpoint — streams _states
as JSON array every 200ms so clients get live denoising step counts
Frontend:
- progress_overlay.js: add connectProgressSSE(pipeType, baseUrl) /
disconnectProgressSSE() — opens EventSource, maps step/total_steps
to bar percentage (0→85% during denoising, 85→100 for decode/place)
- text_to_image.js: connect SSE before POST, disconnect on done/error
- selection_actions.js: connect SSE for AI edit / asymmetry operations
Result: for local GPU, progress bar shows "Step 12 / 30" with exact fill;
for remote providers and upscale (no step callbacks), shimmer animates.
https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
- Add 18x24" to FRAME_SIZES in backend and frontend (frame_fit.js)
- Add 200 DPI option to frame_fit dialog (adequate for large-format prints)
- Add 18x24 portrait/landscape at 200 and 300 DPI to Canvas Size presets (size.js)
- New /api/print/prepare endpoint: chains AI upscale to target DPI then frame-fit
in one server-side call (avoids round-tripping a large upscaled image)
- New print_prepare.js module: "Prepare for Print" dialog with per-frame quality
assessment (current effective DPI, needed upscale factor, AI vs Lanczos note)
- Add "Prepare for Print..." to Image menu above "Fit to Frame..."
https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
Backend (3 new endpoints under /api/image/):
- POST /api/image/scale-selection — scale selected object by any % in-place;
LaMa/OpenCV fills the exposed gap so the scene looks natural
- POST /api/image/ai-edit-region — AI redraws the masked region via the
configured inpaint provider (local_gpu / InvokeAI / ComfyUI / OpenAI)
- POST /api/image/paste-into-selection — scales clipboard image to fit the
selection bounding box, masks it to the selection shape, composites result
Frontend (selection_actions.js + tool integration):
- New SelectionActions panel: fixed bottom-center HUD that appears
automatically after every SAM selection (click or paint)
- Panel actions: Scale by % (default 3%), Make less symmetrical (AI),
custom AI Edit prompt, Replace with clipboard, Copy/Cut to layer, Erase
- Both smart_select.js and brush_select.js updated to show the panel,
add updateLayerWithResult(), and hide panel on clearSelection/on_leave
- brush_select: offerFloatSelection() replaced with richer action panel
Real-world workflows now supported in one click after painting over object:
"Make this 3% bigger" → scale-selection (LaMa fills gap)
"Make this less symmetrical" → ai-edit-region with asymmetry prompt
"Replace this with what I copied" → paste-into-selection
https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
Model selection:
- Add sdxl_offload tier (eff_vram ≥ 4.0 GB) for GTX 1060 6GB and Quadro
6GB cards that were falling through to SD 2.1 despite SDXL fitting with
model_cpu_offload. Cards with 5.3 GB effective VRAM now get SDXL quality.
- Update _tier_label(), _caps(), _build_warnings() for new tier.
Frontend GPU display:
- api.js: add getGpuStatus() fetching /api/gpu/status
- capabilities.js: add getGpuStatus() export with own LRU cache;
refreshCapabilities() now also resets GPU status cache
- provider-badge.js: when AI_PROVIDER=local_gpu show green badge with
GPU name, tier, VRAM, CC, feature flags, and capabilities in tooltip.
Strip "NVIDIA GeForce" prefix so "GTX 1060 6GB" fits in badge.
- ai_provider_settings.js: add local_gpu to all provider dropdowns;
show GPU info panel (device, VRAM, CC, features, tier, model table per
operation) in the settings dialog when a GPU is detected.
https://claude.ai/code/session_01WVDg7amsy1TTtxvpku7bcM
sklearn was not installed in the container, causing ModuleNotFoundError on
import of ai_tools.py and preventing the server from starting.
Replaced with a self-contained numpy k-means++ implementation:
- k-means++ seeding for better initial centers
- 20-iteration Lloyd's algorithm
- Same output: hex colors sorted by cluster frequency
No new dependencies required.
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
Auto-Enhance (Image menu):
POST /api/enhance — gray-world white balance, CLAHE contrast on L channel,
saturation boost ×1.15 in HSV, unsharp mask; all blended by strength slider
Frontend: strength selector (25/50/75/100%), keep-original option
Extract Color Palette (Image menu):
POST /api/extract-colors — k-means on 150×150 thumbnail, returns N dominant
colors sorted by cluster size. Frontend: floating swatch panel, click=copy
hex, shift+click=set as active color, toggle on/off.
History Panel (Edit menu, Ctrl+H):
Pure frontend — reads app.State.action_history and action_history_index,
renders clickable list of past actions (newest first), click any step to
undo/redo to that point. Auto-refreshes every 800ms while open.
Align to Canvas (Layer menu):
Floating toolbar with 7 alignment buttons: center H, center V, center both,
align left/right/top/bottom edges. Uses Update_layer_action for undo support.
Add Text (Generate menu):
6 styled presets (Heading, Subheading, Body, Caption, Quote, Bold Label)
shown as live-rendered previews in the dialog. Click a preset to insert a
text layer with the correct font/size/weight/color pre-applied.
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
Backend:
- sam_service.py: auto-downloads SAM ViT-B (~375 MB) on first use with
progress tracking; loads model to CUDA/MPS/CPU; predict_points() takes
multi-point prompts (include/exclude labels) and returns best mask
- POST /api/segment/point: SAM point-prompt endpoint; returns mask PNG
- GET /api/segment/install-status: poll download progress
- POST /api/segment/install: explicit trigger (also auto on first click)
- main.py: pre-download SAM on startup alongside NCNN
Frontend (ai_edit.js):
- Click mode (default): click object → SAM generates mask instantly
Alt+click → subtract (deselect over-selected area)
Multiple clicks accumulate for multi-object or refinement
- Brush + / Brush − modes: paint to add or erase from SAM mask by hand
- If SAM model is still downloading on first click: inline progress bar,
user retries the click when done
- Unified action bar: Erase | Replace (inline prompt) | Upscale | Expand | Clear
- All modes share the same mask canvas; SAM and brush are fully composited
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
- Add _vulkan_available(): checks /dev/dri/renderD* on Linux, assumes
true on macOS/Windows; set REALESRGAN_NCNN=force to override
- Add _test_ncnn_binary(): test-runs the binary after install and checks
stderr for "no vulkan" — marks skipped if Vulkan init fails at runtime
- ensure_ncnn_installed() now returns early with state=skipped when no
Vulkan detected, avoiding a wasted ~30MB download on CPU-only servers
- Recommend PyTorch CPU when available on headless (AI quality, slow but
works); Lanczos as final fallback
- Frontend: handle state=skipped immediately (no polling needed), show
brief informational toast; show "Headless server" note in dialog
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
- upscale.py: add InstallStatus dataclass + ensure_ncnn_installed() async
function that downloads and extracts the NCNN binary for the current
platform (Linux/macOS/Windows), tracks progress (0-100%), and busts the
caps cache when done
- main.py: trigger ensure_ncnn_installed() as a background task on app
startup when no AI upscaler is detected
- print_tools.py: /upscale/available triggers install task when no AI
upscaler found; new GET /upscale/install-status endpoint for polling
- upscale.js: if no AI upscaler on open, poll install-status showing a
progress bar notification, then refresh caps and proceed when done
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
Detection priority (probed once, cached):
1. Real-ESRGAN PyTorch + CUDA GPU → fastest, best quality
2. Real-ESRGAN PyTorch + Apple MPS → fast on Apple Silicon
3. Real-ESRGAN NCNN Vulkan binary → fast on any GPU via Vulkan (no CUDA needed)
4. Real-ESRGAN PyTorch CPU → works, slow (warned in UI)
5. Lanczos → always available, instant fallback
Backend:
- services/upscale.py: full capability probe (probe_upscale_capabilities),
implementations for PyTorch (CUDA/MPS/CPU auto-device) and NCNN binary,
upscale_sync() resolves method with fallback chain,
async upscale_image() runs in thread pool
- print_tools.py: /api/print/upscale uses new service; method="auto" by default;
GET /api/print/upscale/available returns full capability map with device info
and recommended_label; POST /api/print/upscale/refresh-caps busts cache
without restart (useful after installing NCNN binary into container)
Frontend:
- upscale.js: fetches capability map on first open; builds method selector showing
only available options; labels recommended method with ★; shows device info
(CUDA/MPS/CPU/NCNN) in dialog; maps display label back to method key on submit;
shows actual method used in success toast and undo history entry
Scripts:
- scripts/download_realesrgan.py: downloads NCNN Vulkan binary for current platform
(Linux/macOS/Windows) to /app/data/models/realesrgan/; makes executable;
run inside container or locally
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
Backend — new /api/print/* router:
- POST /api/print/frame-fit: fit image to 4x6/5x7/8x10/11x14/16x20/20x24/24x36
and square sizes (4x4/8x8/12x12) at configurable DPI.
Three modes:
crop — center-crop to aspect ratio, Lanczos scale to print res (no AI)
extend — scale to fill one dimension, AI-inpaint the gap; mirror-fill fallback
smart — auto: extend if gap < 15% of frame dimension, else crop
Auto-detects orientation from image shape; respects explicit portrait/landscape.
- POST /api/print/upscale: Lanczos scale (always) or Real-ESRGAN (if installed)
- GET /api/print/frame-sizes: frame catalogue with pixel dimensions at 300dpi
- GET /api/print/upscale/available: reports whether Real-ESRGAN is installed
Frontend:
- modules/image/frame_fit.js: dialog with frame size, orientation, mode, DPI,
optional extend prompt; shows current image size; result as new layer option
- modules/image/upscale.js: dialog with scale factor (1.5–4×), method selector
(auto-hides AI option if Real-ESRGAN not available); result as new layer option
- config-menu.js: Fit to Frame... and Upscale... added under Image menu
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
Each operation (inpaint, txt2img, img2img, outpaint) can now use a different
provider. Resolution order: per-op override → global AI_PROVIDER default.
Example: txt2img→openai, inpaint→invokeai, everything else→invokeai default.
Backend:
- config.py: add AI_PROVIDER_INPAINT / TXT2IMG / IMG2IMG / OUTPAINT settings
- remote_provider.py: get_remote_provider(operation) resolves override then default;
_build_provider() extracted as shared factory; _OP_FIELD maps op→setting name
- ai_tools.py: each endpoint passes its operation to _require_remote();
GET /api/config runs per-op health checks concurrently, returns operations map
and overrides; POST /api/config accepts and applies per-op override fields
Frontend:
- ai_provider_settings.js: four new selects (inpaint/txt2img/img2img/outpaint);
persists to localStorage and sends per-op fields to POST /api/config
- provider-badge.js: shows override summary (e.g. "invokeai · txt2img→openai")
and per-op health in tooltip
- .env.example: document per-op override env vars with examples
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
Frontend:
- tools/ai_replace_selection.js: use any selection → remote inpaint with prompt
- modules/generate/text_to_image.js: Text → Image dialog (new layer or replace canvas)
- modules/generate/outpaint.js: Expand Canvas in any direction via remote provider
- modules/tools/ai_provider_settings.js: in-app provider config (OpenAI / InvokeAI /
ComfyUI / Replicate); persists to localStorage, pushes to POST /api/config at runtime
- config.js: register ai_replace_selection tool
- config-menu.js: add Generate menu (Text→Image, Outpaint); AI Provider Settings under Tools
- modules/help/about.js: updated credits (LaMa, rembg, SAM, InvokeAI, ComfyUI, OpenAI)
- api/capabilities.js: add refreshCapabilities() for post-save cache invalidation
Backend:
- routers/ai_tools.py: POST /api/config — apply provider settings at runtime
without restart (session-scoped, non-persistent; .env for permanence)
https://claude.ai/code/session_01B58MaJCU1R6KwBDJCp8AfN
- Switch U2Net from onnxruntime to OpenCV DNN to avoid
"cannot enable executable stack" error in Docker
- Add alertify dialog styling to fix white text on white
background issue in popups
- Add offerFloatSelection() to AI Paint that prompts user
after selection to move/scale it (Canva-like workflow)
- Auto-switch to Select tool after floating selection
https://claude.ai/code/session_01CLedz6CanT9t46KBvng3vz
- Fix brush_select isProcessing flag not resetting after first use
(reset in on_leave() when switching tools)
- Add onnxruntime dependency for U2net background removal
- Use full U2net model (176MB) instead of lightweight for better quality
https://claude.ai/code/session_01CLedz6CanT9t46KBvng3vz
- Fix brush_select and smart_select mask scaling to match layer dimensions
- Add "Float Selection" feature to Select tool - when switching to Select
with an active AI selection, offers to copy it to a movable layer
- Add aspect ratio lock toggle (🔗 button) in layer details panel
- When locked, changing width auto-updates height and vice versa
- Add U2net model auto-download - will download lightweight u2netp.onnx (~4MB)
automatically if no model found
- Improve error messages for background removal
- Register on_activate for select tool in config
Workflow: Select object with AI tool → Click Select tool → "Float" selection
→ Move/scale the floated layer freely
https://claude.ai/code/session_01CLedz6CanT9t46KBvng3vz
- Fix My Library: Add CSS styling for library browser, items now visible
- Integrate My Library into Shapes tool with tabbed interface
- Improve AI Inpaint: Add transform mode for scaling/sizing selections
- Add helpful guidance explaining inpaint vs transform modes
- Add U2net as alternative background removal (avoids rembg issues)
- Create U2net model definition and download script
- Improve Caddyfile with multiple options and troubleshooting guide
Note: Brush Select (AI Paint) tool was already implemented and working.
https://claude.ai/code/session_01CLedz6CanT9t46KBvng3vz
scikit-image 0.26+ (required by rembg) needs numpy 2.x compatible
packages. Updated torch from 2.1.2 to 2.4+ and torchvision from
0.16.2 to 0.19+ which officially support numpy 2.x.
https://claude.ai/code/session_01MYpjNQXD1fZE4gCweGU4QQ
rembg>=2.0.70 requires scikit-image>=0.26.0, which conflicted with
the pinned scikit-image==0.22.0. Instead of pinning specific versions,
let pip resolve compatible versions automatically based on rembg's
requirements.
Also removed numpy pin as it may conflict with torch/rembg dependencies
- pip will select a compatible version.
https://claude.ai/code/session_01MYpjNQXD1fZE4gCweGU4QQ
rembg 2.0.70+ requires Pillow>=12.1.0,<13.0.0 which conflicted with
the pinned Pillow==10.2.0. Updated to use the version range that
satisfies rembg while remaining compatible with scikit-image and
torchvision (both have no upper bound on Pillow).
https://claude.ai/code/session_01MYpjNQXD1fZE4gCweGU4QQ
- Use onnxruntime>=1.17.0 (fixed executable stack issues, no execstack needed)
- Use rembg>=2.0.70 with BiRefNet model support
- Update all remove-background endpoints to use birefnet-general model
- BiRefNet provides better edge detection and matting quality than u2net
- Falls back to default model if BiRefNet unavailable
- Use onnxruntime 1.14.1 (older version without executable stack requirement)
- Make rembg pre-download optional (won't fail build if onnxruntime has issues)
- Remove Background will be disabled if rembg can't load
Frontend:
- Added "Remove Background (AI)" to Image menu
- Created remove_background.js module with dialog options
- Added removeBackground method to API service
Backend:
- Added /tools/remove-background-base64 endpoint for miniPaint frontend
- Uses rembg library for AI-powered background removal
Features:
- Automatically detects main subject and removes background
- Option to create as new layer or replace current
- Enables transparency mode after removal
- Works with any image layer
- SAM selection now shows actual mask contour instead of bounding box
- Added marching ants animation on the actual mask edge
- Added keyboard shortcuts:
- Ctrl+C: Copy selection to new layer
- Ctrl+X: Cut selection to new layer (removes from original)
- Delete: Delete selected area
- Escape: Clear selection
- Removed eye catalog download from startup (was failing with 429)
Frontend:
- Fix smart_select.js to properly render mask overlay
- Add marching ants border around selection
- Calculate selection bounds from mask
- Trigger re-render after mask is loaded
Backend:
- Fix inpaint endpoint to call edit_image() instead of inpaint()
- The AI providers use edit_image() method, not inpaint()
- Update main Dockerfile to copy all miniPaint static files:
- index.html
- dist/ (webpack bundle)
- images/ (icons and assets)
- src/css/ (stylesheets)
- Update backend main.py to conditionally mount static directories
- Checks if each directory exists before mounting
- Supports both React (assets/) and miniPaint (dist/, images/, src/) structures
New features:
- Smart Select tool: Click to select objects using SAM (Segment Anything)
- AI Inpaint tool: Edit selected regions with text prompts
Changes:
- frontend/src/js/tools/smart_select.js: SAM-powered selection tool
- frontend/src/js/tools/ai_inpaint.js: AI inpainting with prompt dialog
- frontend/src/js/services/api.js: API service for backend communication
- frontend/src/js/config.js: Register new tools
- frontend/src/css/layout.css: Tool icon styles
- frontend/images/icons/: SVG icons for new tools
- backend/app/routers/tools.py: New base64 API endpoints
- frontend/Dockerfile: Updated for miniPaint build
- frontend/nginx.conf: Added /api prefix proxy
- Create unified Dockerfile with multi-stage build (Node + Python)
- FastAPI now serves React static files directly
- Remove frontend service and nginx dependency
- Simplify docker-compose to single service
- All routes work without proxy configuration
Frontend changes:
- Wire Smart Select and Color Select to canvas click handlers
- Add externalSelection prop to ImageCanvas for displaying AI-generated selections
- Add zoom controls (mouse wheel + buttons) to ImageCanvas
- Fix layer buttons (New Layer, Delete, Duplicate) with proper handlers
- Lift advancedToolMode state to App.jsx for coordination between components
- Add tool mode indicator overlay on canvas
Backend changes:
- Update smart-select endpoint to return JSON with polygon and bbox data
- Update color-select endpoint to return JSON with polygon and bbox data
- Add _mask_to_polygon helper function using OpenCV contour detection
- Add cv2 and base64 imports to tools.py
API changes:
- smartSelect and colorSelect now return { polygon, bbox, mask_base64 }
- Fix database path mismatch: download_sample_eyes.py now uses
ai_photo_edit.db instead of photoedit.db
- Add init_database.py script to initialize DB before eye import
- Add AUTO_DOWNLOAD_SAM=true environment variable (default: enabled)
- Update entrypoint.sh to:
1. Initialize database first
2. Auto-download SAM model (~375MB) on first startup
3. Then import eyes (now works since DB exists)
- Update path detection to work in both Docker and local environments
- Add torch, torchvision, segment-anything to requirements
- Create download_sam_model.py script to fetch SAM checkpoint
- Update tools.py to use local SAM with Replicate API fallback
- Add SAM model check to entrypoint.sh with helpful instructions
- Model persists in /app/data/models via Docker volume mount
- Create entrypoint.sh that auto-downloads sample eyes on first run
- Update Dockerfile to use entrypoint script
- Rewrite .env.example with step-by-step setup instructions
- Add detailed troubleshooting section
- Clarify which models work for inpainting vs text-to-image
- Implement SAM object selection via Replicate API
- Click on any object to select it with AI precision
- Falls back to flood-fill if Replicate API unavailable
- Update Dockerfile for rembg dependencies
- Add required system libraries (libsm6, libxext6, etc)
- Pre-download rembg model during build
- Create data directories for models and patches
Backend:
- Add /tools router with background removal, smart select, color select
- Add rembg dependency for AI background removal
- Add layer management API (list, flatten)
- Fix transparency preservation in blend_patch (veil collapse fix)
- Preserve alpha channel when reverting/resetting images
Frontend:
- Add AdvancedTools panel with background removal, smart select, color select
- Add Layers panel with drag-to-reorder, visibility toggle, flatten
- Add toolsApi for new backend endpoints
- Make right panel scrollable for additional controls
This adds "Photoshop light" capabilities:
- Remove background and create layer
- Smart object selection (click to select)
- Color selection with tolerance
- Layer system with compositing