Precision Image Orchestrator β Compose subjects over backgrounds, generate N Γ A combinations and batch-export high-resolution packs in PNG, JPG or WEBP up to 4K.
- πΌοΈ Multi-layer composition β Upload subjects (PNG with alpha) and backgrounds separately
- π― Fabric.js canvas β Drag, resize, rotate and position layers with precision
- ποΈ Per-layer visibility β Toggle which subjects/backgrounds appear in each export
- π Aspect ratio presets β
1:1,3:4,9:16,4:3,16:9 - π¨ 100% client-side β Zero API calls, zero backend, zero data leaves your browser
- β‘ Instant preview β Real-time composition with live canvas rendering
- π’ Cartesian Export β Generates
BGs(visible) Γ SUBs(visible)combinations automatically - π¦ Batch ZIP β Up to 156 frames per pack (12Γ13 limit)
- π« No-merge invariant β Each frame contains exactly 1 BG + 1 SUB (never combined)
- π₯ Resolution scaling β Export in 1K, 2K or 4K
- π Multiple formats β PNG (lossless), JPG (q=0.95), WEBP (lossless with alpha) β v0.5.0
- β‘ Web Worker β ZIP generation runs off the main thread (UI never freezes)
- π Cancelable export β Stop mid-pack with one click
- β Toggle Grid Mode β Activate a 20Γ20 reference grid based on the canvas's smaller side
- π― Centered & locked β SUBs auto-center geometrically, lock position/rotation/manual scaling
- ββ Discrete scale β Adjust SUB size in steps of
1/20of the canvas (per-SUB) - π’ Visual indicator β
[N/20]badge on each subject card - πΏ Clean export β Grid lines visible only in the preview, never written to PNG/JPG/WEBP
- βΏ Accessibility β
aria-label,aria-pressed,aria-live, focus rings on all controls - π Toast notifications β Replaces native
alert()with smooth Motion-powered toasts - ποΈ Up to 25 images β Total cap (BG + SUB combined, any combination)
- π Strict TypeScript β
strict: trueenabled, zeroas anyin source - π‘οΈ Sanitized filenames β Removes illegal characters for Windows/macOS/Linux
Prerequisites: Node.js 18+
git clone https://github.com/vandre-sales/Alpha-Compose.git
cd Alpha-Compose
npm install
npm run devOpen http://localhost:3000 in your browser.
flowchart LR
subgraph UPLOAD["π₯ Upload (β€ 25 images)"]
A1["Subjects<br/>(PNG with alpha)"]
A2["Backgrounds<br/>(any image)"]
end
subgraph COMPOSE["π¨ Canvas Editor"]
B1["Free mode:<br/>Drag, Resize, Rotate"]
B2["Grid mode:<br/>Centered + 1..20 slices"]
B3["Toggle Visibility<br/>Hide/Show"]
B4["Aspect Ratio"]
end
subgraph EXPORT["π¦ Cartesian Export"]
C1["For each visible SUB:"]
C2["For each visible BG:"]
C3["Render at multiplier<br/>+ format encode"]
C4["ZIP via Web Worker"]
end
A1 --> B1
A2 --> B1
B1 --> B3
B2 --> B3
B3 --> B4
B4 --> C1 --> C2 --> C3 --> C4
| Step | Action | Result |
|---|---|---|
| 1 | Upload subjects (transparent PNGs) | Cards added to Subjects panel |
| 2 | Upload backgrounds (any images) | Cards added to Backgrounds panel |
| 3 | (Optional) Toggle β Grid ON | SUBs auto-center; use +/- to resize discretely |
| 4 | Choose aspect ratio, quality (1K/2K/4K), format (PNG/JPG/WEBP) | UI updates live |
| 5 | (Optional) Hide SUBs/BGs you don't want in this batch | They're silently skipped |
| 6 | Click Generate Pack | Downloaded ZIP: alpha_compose_{res}_{format}_pack.zip |
Formula:
RENDERED_IMAGES = BGs(show) Γ SUBs(show)
| Setup | Output |
|---|---|
| 3 BG visible + 1 SUB visible | 3 frames |
| 3 BG visible + 2 SUB visible | 6 frames (each SUB Γ each BG) |
| 5 BG visible + 4 SUB visible | 20 frames |
| 12 BG visible + 13 SUB visible (max) | 156 frames |
| 25 BG visible + 0 SUB | 25 frames (legacy compat, no subjects) |
| 0 BG visible + N SUB | β error: "select at least one visible background" |
compose_S{subIdx}_B{bgIdx}_{subName}__{bgName}_{1K|2K|4K}.{png|jpg|webp}
Examples:
compose_S1_B1_person__beach_4K.pngcompose_S2_B3_logo__city_2K.jpg
| Quality | Total Pixels | Equivalent (1:1) | Best For |
|---|---|---|---|
| 1K | 1 MP | 1024 Γ 1024 | Social media, thumbnails |
| 2K | 4 MP | 2048 Γ 2048 | Web, presentations, e-commerce |
| 4K | 16 MP | 4096 Γ 4096 | Print, high-res marketing assets |
Resolution scales proportionally to the selected aspect ratio:
targetWidth = β(totalPixels Γ aspectRatio)
multiplier = targetWidth / canvasWidth
β οΈ Browser canvas limit: most browsers cap at 16384 Γ 16384 px. Alpha Compose checks this before rendering and shows an error toast if exceeded.
| Format | Quality | Lossless | Alpha | Typical Size | Best For |
|---|---|---|---|---|---|
| PNG | β | β Yes | β Yes | 100% | Default, maximum compatibility |
| JPG | 0.95 | β No | β No | ~30% | Smallest size, web/sharing |
| WEBP | 1.0 | β Yes | β Yes | ~70% | Best compression with alpha |
π‘ JPG note: JPG doesn't support alpha; the canvas's black background fills any transparent region. π‘ WEBP note: lossless mode with alpha preserved is the best modern choice when supported (97%+ browsers in 2026).
When Grid ON is activated:
sliceSize = min(canvasWidth, canvasHeight) / 20
The canvas is divided into a 20Γ20 grid (on the smaller side; longer side may have more slices). Each subject:
- π Auto-centers geometrically (vertically + horizontally)
- π Locks all manual transforms (drag, resize, rotate)
- π Resizes only via discrete
+/-buttons (1 to 20 slices) - π¦ Bounding box is square (
N Γ Nslices), preserving the subject's aspect ratio inside
| Canvas | Slice (px) | Grid |
|---|---|---|
| 1080 Γ 1080 (1:1) | 54 | 20 Γ 20 |
| 1920 Γ 1080 (16:9) | 54 | 35 Γ 20 |
| 1080 Γ 1440 (3:4) | 54 | 20 Γ 26 |
The grid lines are an SVG overlay outside the Fabric canvas β they appear only in the preview and are never written to exported PNG/JPG/WEBP.
graph TB
subgraph UI["React 19 + Tailwind CSS 4"]
sidebar_l["Left Sidebar<br/>Subjects + Backgrounds"]
header["Header<br/>Grid Toggle + Aspect Ratio + Progress"]
sidebar_r["Right Sidebar<br/>Workflow + Quality + Format + Generate"]
end
subgraph HOOKS["Custom Hooks"]
useImageLib["useImageLibrary<br/>state + actions"]
useExp["useExporter<br/>cartesian loop + Worker"]
useToast["useToast<br/>notifications"]
end
subgraph CANVAS["Fabric.js Engine"]
fabricCanvas["fabric.Canvas"]
bgLayer["BG Layer<br/>cover-fit, sendToBack"]
subLayer["SUB Layer<br/>center-fit, bringToFront"]
gridOverlay["Grid SVG Overlay<br/>(preview only)"]
end
subgraph WORKER["Web Worker"]
zipWorker["zipWorker.ts<br/>JSZip generateAsync"]
end
subgraph EXPORT["Export Pipeline"]
toggle["Toggle visibility:<br/>1 BG + 0|1 SUB per frame"]
render["canvas.toDataURL<br/>(format + quality + multiplier)"]
bytes["base64 β Uint8Array"]
download["alpha_compose_{res}_{format}_pack.zip"]
end
sidebar_l --> useImageLib
sidebar_r --> useExp
useImageLib --> fabricCanvas
useExp --> toggle --> render --> bytes --> zipWorker --> download
fabricCanvas --> bgLayer
fabricCanvas --> subLayer
fabricCanvas -.preview.-> gridOverlay
| Technology | Version | Purpose |
|---|---|---|
| React | 19 | UI framework with hooks |
| TypeScript | 5.8 (strict) | Type safety across the codebase |
| Vite | 6 | Build tool with HMR + Web Worker support |
| Fabric.js | 7 | Canvas manipulation engine |
| Tailwind CSS | 4 | Utility-first styling |
| JSZip | 3 | Client-side ZIP generation (in Worker) |
| Motion | 12 | UI animations + toasts |
| Lucide React | β | Icon library |
Alpha-Compose/
βββ index.html # Entry point
βββ package.json # Dependencies & scripts
βββ vite.config.ts # Vite + Tailwind + React config
βββ tsconfig.json # TypeScript config (strict: true)
βββ LICENSE # MIT
βββ README.md # This file
βββ metadata.json # Project metadata
β
βββ plans/ # Sprint dossiers (audit + plans)
β βββ auditoria-alpha-compose.md
β βββ refatoracao-alpha-compose.md
β βββ sprint-iteracao-sub.md
β βββ sprint-grid-mode.md
β βββ sprint-export-format.md
β
βββ src/
βββ main.tsx # React DOM entry
βββ App.tsx # Root component (composition only)
βββ index.css # Tailwind imports + font config
βββ types.ts # All shared types + constants
β
βββ hooks/
β βββ useImageLibrary.ts # Image state + upload + role mgmt
β βββ useExporter.ts # Cartesian export pipeline
β
βββ components/
β βββ CanvasEditor.tsx # Fabric.js wrapper + grid overlay
β βββ Section.tsx # Sidebar panels (subjects/backgrounds)
β βββ Toast.tsx # Toast notifications system
β
βββ lib/
β βββ utils.ts # cn(), sanitizeFilename, formatFrameName, grid helpers
β
βββ types/
β βββ fabric-augment.d.ts # Custom metadata typing for Fabric objects
β
βββ workers/
βββ zipWorker.ts # ZIP generation off-main-thread
| Command | Description |
|---|---|
npm run dev |
Start dev server on port 3000 |
npm run build |
Build for production (dist/) |
npm run preview |
Preview production build |
npm run lint |
TypeScript type checking (strict mode) |
npm run clean |
Remove dist/ folder |
| Version | Highlights |
|---|---|
| 0.5.0 | Multiple export formats: PNG, JPG, WEBP |
| 0.4.0 | Grid Mode with discrete scaling (20Γ20) |
| 0.3.0 | Cartesian export N Γ A (each SUB Γ each BG) |
| 0.2.0 | Refactor: strict TypeScript, toasts, Web Worker, a11y |
| 0.1.1 | Initial public release |
Detailed dossiers (audit + plans + smoke tests) available under plans/.
Contributions are welcome! Feel free to open issues or submit PRs.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
π‘ Each sprint follows a structured workflow with safeguards: backups in
backups/, dry-run gates (lint + build), and smoke tests (low + high pass). Seeplans/refatoracao-alpha-compose.mdfor the methodology.
MIT β Vandre Sales 2026
Built with β€οΈ using React 19, Fabric.js & Vite