Theming, i18n, accessibility
Theme
Set theme="dark" | "light" | "auto" and override tokens on the element:
sealpixel-editor {
--sealpixel-color-accent: #d94f8a;
--sealpixel-radius: 12px;
--sealpixel-font: 'Inter', system-ui, sans-serif;
--sealpixel-toolbar-size: 64px;
}
sealpixel-editor::part(nav) { background: transparent; }Parts: root, nav, stage, panel, toolbar, undo, redo, history, export, download, dimensions, tool, button, viewport, canvas, overlay, status, toast, empty. All of them are reachable from the host page through nested shadow roots, so sealpixel-editor::part(export) { display: none } hides the Export button.
See Customize the look for a live pane that prints the CSS for any combination of these tokens.
Locale
<sealpixel-editor locale="de"></sealpixel-editor>Shipped locales (en, de, fr, es, pt, ja) resolve from the locale attribute; a region suffix such as de-AT falls back to de. Pass your own dictionary to add a language or to change single strings:
import de from '@sealpixel/ui/locales/de';
editor.locale = 'de';
editor.dictionary = { ...de, 'nav.download': 'Speichern' };Dictionaries are flat { key: 'text with {placeholders}' }. Missing keys fall back to English and warn in development.
Phone layout
The editor switches layouts on its own container width, not on the viewport. Below 768 px the toolbar moves to the bottom, the tool panel sits above it and the stage takes the rest. Nothing to configure: a narrow sidebar or a phone both get this layout. Pinch zooms, drag pans, and a single finger moves crop handles, redaction boxes and annotations. The image never leaves the view: panning stops at the edges, a plain scroll only pans while the image is larger than the stage, and a double tap or the zoom badge fits it again. Switching tools keeps the view steady: when a tool shows the uncropped image, the same source pixels stay where they were, at the same size. Tapping an element selects it and shows a trash handle above it, so nothing needs a list in the panel. Safe-area insets are respected, so the toolbar clears a home indicator.
On a small screen every control counts. show-history="buttons" keeps undo and redo but drops the timeline, show-export="never" hides Export (see Download and export).

Under the hood the host element is a size container (container-type: inline-size) and a ResizeObserver flips the layout. Tool controls always sit in a bar under the stage; above 48rem only the tool rail moves to the left edge. A panel puts its choice of what to work with on the bottom row, marked class="choice", and the settings for that choice above it. Tools receive ctx.layout ('wide' or 'narrow') and may lay out their panel accordingly; the built-in panels compact themselves into the bar, for example finetune shows one dial with a strip of parameter chips under it and crop offers the aspect ratios in a select. Annotate goes further and shows the controls the selected shape actually has: a rectangle gets a stroke width and a fill, a text box gets a font, size, line height and alignment instead.
A number gets the control its range deserves. A value with a neutral in the middle — the finetune parameters, a rotation — gets the dial, where a scale travelling under a fixed needle shows direction and distance from zero. A magnitude that counts up from a floor — a font size, a line width, a corner radius, a margin — gets a stepper, which reads, types and nudges by one in a fifth of the width. Resize binds its two dimensions with a link: closed, typing either one writes both at the source's ratio and the fit mode steps aside, because nothing is being squeezed.
Crop writes its rectangle to the log the moment a handle is released, but the stage keeps showing the whole image, because a corner cannot be pulled outwards through an edge that is off screen. So that releasing does not look like doing nothing, the crop settles: half a second after the pointer rests, the preview is clipped to the crop and the gizmo fades, leaving the picture that will come out with the stage's own backdrop around it. Clipping rather than painting over is what carries the checker through without a seam; a tool asks for it with ctx.clipPreview(shape).
Redact and annotate use the same clip. Their shapes live in image space, so they render the image before crop and resize — but the user still sees the picture they are working on, because the preview is clipped to what the crop keeps. Before, it was the whole source with the removed part dimmed. Touching the frame is adjusting again. Leaving the tool glides the result into place rather than cutting to it — the one tool switch that moves the image, and only when that visit changed the crop. A tool can ask for the same through ctx.animateNextView().
Accessibility
Every tool is keyboard-operable: the toolbar uses roving tabindex, a dial is a native range input with aria-valuetext behind its scale and a stepper a native number field, arrow keys nudge (Shift for 10 steps), status changes announce through an aria-live region, and a control is 44 px under a finger (pointer: coarse) and 32 px under a mouse, both above the 24 px the WCAG 2.2 target-size rule asks for. Every panel passes an axe scan in Chromium and WebKit in the repository's tests.