Image Editor

Navigator

No image

Fit

Exposure0
Contrast0
Highlights0
Shadows0
Whites0
Blacks0
Vignette0

A live WebGL2 pipeline, not a series of one-shot filters

Every slider in the Light, Color, Detail, Sharpen, and Effects sections — exposure, contrast, highlights, shadows, whites, blacks, temperature, tint, saturation, vibrance, clarity, texture, dehaze, sharpen amount and radius, vignette — feeds a single WebGL2 shader that re-renders the whole image on every change, on the GPU, at interactive speed. Nothing is baked into pixels as you adjust: the underlying source bitmap never changes, only the numbers the shader reads each frame, which is what makes moving a slider back to zero a true undo of that one control with no accumulated rounding or quality loss.

Every numeric control is hard-clamped, not just visually limited

Rotation runs -180° to 180°, Straighten -45° to 45° as a separate fine-leveling control, Exposure -5 to 5 stops, the six-strong Light group (contrast, highlights, shadows, whites, blacks) and the four-strong Color group (temperature, tint, saturation, vibrance) all run -100 to 100, Clarity/Texture/Dehaze the same, Sharpen Amount 0 to 100 with Radius 0.5 to 3.0, and Vignette -100 to 100. These ranges are enforced in the editor's own state, not only in the slider UI — a value outside its range is silently clamped back into range the moment it is set, so no combination of inputs can push a control past what the shader was actually built to handle.

Transform, crop, and perspective correction as separate modes on the same image

Rotation and Straighten solve different problems: Rotation turns the image in large steps for a genuine orientation change, while Straighten is a narrower ±45° control meant for leveling a slightly tilted horizon without touching the overall orientation. Flip Horizontal and Flip Vertical mirror the image independently of either rotation control. Crop and Perspective switch the canvas into their own interactive editing modes rather than exposing a slider — perspective correction is represented internally as a four-corner quad in normalized image coordinates, defaulting to the plain rectangle of an unedited image, so correcting perspective is literally dragging those four corners until converging verticals look parallel again.

Text layers: positioned as fractions of the image, not fixed pixels

Adding a text layer creates an independent object with its own content, a font chosen from a fixed system-font list, a size from 8 to 400px, a weight from Thin through Extrabold, a color, an opacity from 0 to 100%, and a rotation of its own, separate from the image's rotation. Its position is stored as an x/y fraction of the output image — 0.5, 0.5 is dead center — rather than as fixed pixel coordinates, which is what lets the same layer land in the same relative spot whether you are viewing it at fit-to-window zoom or exporting at the image's full native resolution.

Where the work actually happens: your GPU, never a server

Opening a file decodes it locally with the browser's own createImageBitmap — no image data is read by, or sent to, anything outside the tab. HEIC and HEIF files, which almost no browser besides Safari decodes natively, are detected by file extension or, when the browser reports no file type at all, by sniffing the file's own header bytes, then converted to a JPEG at 95% quality by a separately loaded decoder library before the rest of the editor ever sees them. An image wider or taller than the GPU's own maximum texture size (assumed to be 4096px if that limit cannot be read directly) is downscaled to fit immediately on load, since a texture larger than the hardware supports simply cannot be uploaded to the graphics card at all — that downscale is why an unusually large source photo can appear slightly smaller than its original dimensions the moment it loads.

Export: full resolution, three formats, and a worked edit start to finish

Export re-renders the image at its original full pixel dimensions in a second, separate offscreen WebGL2 pass — independent of the on-screen zoom level — then resizes down to the Resize panel's target (identity if untouched), and only then draws the text layers on top at that final size, which is why text stays crisp regardless of how much the image was shrunk. Choose JPEG, PNG, or WebP with a quality slider from 50% to 100% (92% default); JPEG has no alpha channel, so transparency in a PNG or WebP source flattens to opaque on export to JPEG, and since every export is a fresh re-encode from the canvas rather than a copy of the source bytes, EXIF data, GPS tags, and any other original metadata never reach the exported file.

Concretely: load a 6000×4000 JPEG portrait, raise Exposure to +0.6 and lower Highlights to -40, add a text layer reading "2026 Portfolio" at 64px in the lower third, then export as WebP at 90% quality. What downloads is a fresh WebP re-encoded from the full 6000×4000 source with those adjustments baked in and the text overlaid at final size — not the original file with edits stacked on top, and carrying none of its metadata.

Common use cases

A full edit on a large photo without installing anything

Load a full-resolution photo, apply Light and Color adjustments with real-time GPU preview, and export a finished JPEG or WebP without a downloaded app.

Removing a tilted horizon before publishing a photo

Use Straighten for a small leveling correction independent of the full ±180° Rotation control, or switch to Perspective mode to correct converging verticals by dragging the image's four corners.

Adding a caption or watermark-style text overlay

Add a text layer, position it as a fraction of the frame so it lands in the same place at any export size, and adjust its color, opacity, and rotation independently of the image underneath.

Editing a photo straight off an iPhone

Load a HEIC file directly — it is decoded to JPEG in the browser before editing starts, with no separate conversion step in another app first.

Frequently asked questions

Does this editor upload my photo anywhere?

No — decoding, every adjustment, and the final export all run in your browser using WebGL2 and the Canvas API. Nothing about the image is sent to a server at any point.

What happens to EXIF data and GPS location tags when I export?

They are gone. Export re-renders the image into a brand-new canvas and re-encodes it from scratch rather than copying the original file's byte structure, so none of the source file's metadata — including any embedded GPS coordinates — carries over to the exported file.

Can I export a transparent PNG, and does it stay transparent if I switch to JPEG?

PNG and WebP both preserve alpha transparency through export. JPEG has no alpha channel at all — any transparent areas in the source are flattened into an opaque background when you export to that format.

Does resizing ever make my image bigger than the original?

No — the Resize panel is downsize-only; both the width and height inputs are clamped to the loaded image's own dimensions, so you can shrink an export but never upscale one past its source resolution.

I loaded a HEIC photo from my iPhone — does that actually work?

Yes. HEIC and HEIF files are detected by their extension or, if the browser reports no file type at all, by sniffing the file's own header bytes, then converted to a JPEG at 95% quality by a separately loaded decoder before anything else in the editor touches them.

Why did my huge source photo look smaller than its real dimensions right after loading?

Images wider or taller than the GPU's maximum texture size are downscaled to fit that limit immediately on load, so the editor can actually render them — otherwise a large enough photo could not be uploaded to the graphics card at all.

How many times can I undo, and does that history reset if I make a new edit after undoing?

Up to the last 50 committed changes. If you undo and then make a new edit rather than redoing, every undone step ahead of that point is discarded — the same branching behavior as undo history in most editors.

Does the text I add scale correctly if I resize the image smaller on export?

Yes — a text layer's position and size are stored as fractions of the image rather than fixed pixel coordinates, and it is drawn onto the canvas after resizing, at the final output size, so it stays sharp and correctly placed regardless of what export size you choose.

You might also like