Static browser-based image editor built with plain HTML, CSS, and JavaScript.
- Crop & Resize: Interactive selection with aspect-ratio lock.
- Rotate: Rotate by 90 degrees or fine-tune with a custom angle.
- Convert: Seamlessly switch between PNG, JPEG, and WebP formats.
- Compress: Optimize JPEG and WebP images with a quality slider.
- Privacy-First BG Remove: Remove backgrounds locally in the browser with IMG.LY's on-device AI.
- Text Behind Object: Layer text behind a foreground object for cinematic compositing (powered by Fabric.js).
- No Uploads: Images stay on your machine—zero latency, enhanced security.
This project is fully static and GitHub Pages friendly. Current core runtime files are:
index.html(landing route)editor.html(editor route)editor-app.js(editor bootstrap)app.js(app init)styles.cssmodules/**ui/**
- Dependencies:
CropperJS,Pica, andFabric.jsare loaded via CDN for powerful editing capabilities. - AI Integration: Background removal uses
@imgly/background-removalvia CDN, downloading model files to the browser cache on first use. - Layer Compositing: Text Behind Object uses Fabric.js for draggable layers, font controls, and real-time preview.
- Data Privacy: All processing happens client-side. Your images are never uploaded to any server.
OpenLens uses two static HTML routes:
index.html
- Landing page only.
- Contains tool cards and project marketing sections.
- Tool cards navigate to editor route using query params:
- Example:
editor.html?tool=glitch
- Example:
editor.html
- Editor shell only.
- Contains topbar, canvas/dropzone, and tool switcher.
- Sidebar panel markup is mounted by JS at startup.
Editor route behavior:
- Tool selection is encoded in
?tool=.... - Changing tools updates URL with
history.pushState/replaceState. - No full page reload on tool switch.
- In-memory image + history state remains intact.
Back navigation behavior:
- Editor back button navigates to
index.html.
file:// behavior:
- Gracefully handled with a visible note.
- Primary supported usage is static hosting (
GitHub Pagesor local HTTP server).
Editor startup sequence:
editor.htmlloadseditor-app.jseditor-app.jsmounts sidebar panels into.sidebar-panelseditor-app.jsimportsapp.jsapp.jsinitializes file handlers, tool listeners, routing, and UI sync
.
├─ index.html # Landing route
├─ editor.html # Editor route shell
├─ editor-app.js # Mount panels, then load app.js
├─ app.js # Main app initialization
├─ styles.css # Shared/global CSS
├─ modules/
│ ├─ core/
│ │ ├─ state.js # Shared runtime state
│ │ ├─ dom.js # Central DOM refs
│ │ ├─ utils.js # Helper utilities
│ │ └─ messages.js # Status/help messages
│ ├─ tools/ # Tool logic implementations
│ │ ├─ crop.js
│ │ ├─ resize.js
│ │ ├─ rotate.js
│ │ ├─ convert.js
│ │ ├─ ...
│ │ ├─ curvedtext.js # Curved text effect logic
│ │ ├─ stroketext.js # Stroke text effect logic
│ │ ├─ stickers.js # Stickers logic
│ │ ├─ svg-stickers.js # Sticker SVG dataset
│ │ ├─ tool-runtime.js # Facade for tool runtime orchestration
│ │ └─ runtime/
│ │ ├─ activate-runtime.js # Tool activation/deactivation lifecycle
│ │ ├─ render-runtime.js # Tool render-time lifecycle after image updates
│ │ └─ shared.js # Shared runtime helpers
│ ├─ editor-panels/
│ │ ├─ index.js # Registry: tool -> panel markup module
│ │ └─ mount.js # Injects panel markup into editor shell
│ ├─ file-handler.js # File load/commit/undo/reset/download
│ └─ ui-controller.js # Route/view sync and runtime delegation
├─ ui/
│ ├─ <tool-folder>/panel.js # Panel markup module for that tool
│ ├─ <tool-folder>/*.css # Tool-specific styles
│ └─ ...
└─ backups/ # Local snapshots before major refactors
Each tool folder in ui/ has a panel.js file.
Purpose:
- Exports the sidebar UI markup for that tool.
- Used by
modules/editor-panels/index.jsfor panel mounting.
It does not contain tool behavior logic.
Tool behavior lives in modules/tools/*.js.
ui/*/panel.js: Tool panel markupui/*/*.css: Tool panel visual stylingmodules/tools/*.js: Effect logic and processingmodules/tools/runtime/*.js: Tool lifecycle orchestration (activate/render/deactivate)modules/tools/tool-runtime.js: Stable facade imported by UI controllermodules/ui-controller.js: Tool switch UI + route syncing + runtime delegationmodules/file-handler.js: File operations + history changes
- Add logic in
modules/tools/<tool>.js - Add panel markup in
ui/<tool>/panel.js - Add panel CSS in
ui/<tool>/<tool>.cssif needed - Register panel in
modules/editor-panels/index.js - Add switch option in
editor.html - Hook listener init in
app.js - Hook tool lifecycle in
modules/tools/runtime/activate-runtime.jsandmodules/tools/runtime/render-runtime.js - Update
modules/ui-controller.jsonly if route or tool switch UX behavior changes
Run a static server:
python3 -m http.server 4173Open:
http://127.0.0.1:4173/index.htmlhttp://127.0.0.1:4173/editor.html?tool=crop
- Designed for GitHub Pages and local HTTP static servers.
- No build step required.
- Keep relative paths and avoid server-side routing assumptions.
This project is licensed under the AGPLv3. See the LICENSE file for details.
