Skip to content

Svelte ​

@sealpixel/svelte is a Svelte 5 component around <sealpixel-editor>, runes-based, with bind:editLog for the log and the element's events as callback props.

Install ​

sh
pnpm add @sealpixel/svelte
sh
npm install @sealpixel/svelte

svelte 5 is a peer dependency.

The starter ​

examples/starters/svelte, a Vite app. Open it on StackBlitz. The component, quoted from the starter:

svelte
<script lang="ts">
import type { ExportResult } from '@sealpixel/core';
import { SealpixelEditor } from '@sealpixel/svelte';

let editLog = $state<unknown>({
  version: 1,
  source: { id: 'landscape', width: 120, height: 80 },
  plugins: { finetune: 1, filter: 1 },
  ops: [
    { type: 'finetune.set', id: 'shared-1', params: { contrast: 0.2, saturation: 0.3 } },
    { type: 'filter.set', id: 'shared-2', preset: 'warm', strength: 0.6 },
  ],
});
let processed = $state('Press Download: the file name carries the SHA-256 of the result.');
const onprocess = (r: ExportResult) => {
  processed = `exported ${r.width}x${r.height} sha256 ${r.hash}`;
};
</script>

<SealpixelEditor src="/landscape.png" theme="dark" bind:editLog {onprocess} />
<output data-testid="processed">{processed}</output>

bind:editLog is controlled use: the state holds { log, index } after the first change and the editor follows it. Without the binding, pass defaultEditLog once and use onchange when you want to save. onprocess gets the ExportResult of a Download.

Build setup ​

Vite with the Svelte plugin and vitePreprocess for TypeScript in components; nothing Sealpixel-specific:

ts
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { defineConfig } from 'vite';

export default defineConfig({ plugins: [svelte()] });
js
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

export default { preprocess: vitePreprocess() };

Server-side rendering ​

The component runs in the browser only. In SvelteKit, render it inside {#if browser} from $app/environment, or import the component in onMount; a +page.ts with export const ssr = false takes the whole page out of server rendering instead. Rendering the tag on the server is harmless, but object props such as editLog only reach the element on the client.

Headless ​

createSealpixelStore returns the session and a store-contract subscribe, so $store auto-subscription and fromStore both work; call dispose in onDestroy:

ts
/**
 * Headless use in Svelte 5: a store-contract object (`subscribe`) plus the
 * session. Works with `$store` auto-subscription and with runes via
 * `fromStore`. Call `dispose()` in `onDestroy`.
 */
export function createSealpixelStore(options: SessionOptions): {
  session: EditorSession;
  subscribe: (run: (state: SessionState) => void) => () => void;
  dispose: () => void;
} {
  const session = createEditorSession(options);
  return {
    session,
    subscribe(run) {
      run(session.getState());
      return session.subscribe(run);
    },
    dispose: () => session.dispose(),
  };
}

Server rendering ​

Above the client limit the browser cannot export, see Working copy. Render the original on your server with @sealpixel/render: it takes the original and the edit log from getEditLog(). See Render on your server and the Node starter. The renderer does not depend on Svelte. In SvelteKit it runs in a +server.ts.

TypeScript ​

ts
import type { SessionState } from '@sealpixel/core';
import type { ExportResult, SealpixelError, SourceDescriptor } from '@sealpixel/core';

The callback props are typed on the component: onchange(state: { log, index }), onprocess(result: ExportResult), onerror(error: SealpixelError), onload(descriptor: SourceDescriptor), onready(). onready also runs for the session that the element creates when it is inserted. The component exports getSession, getEditLog, undo, redo, export and download for use through bind:this.