Skip to content

Astro ​

@sealpixel/astro is two things: an integration that sets the Vite options the wasm and the worker need, and a .astro component that renders <sealpixel-editor> with plain-data props as attributes. Astro 5 and later.

Install ​

sh
npx astro add @sealpixel/astro

That adds the package and the integration to astro.config. By hand, it is:

mjs
import sealpixel from '@sealpixel/astro';
import { defineConfig } from 'astro/config';

export default defineConfig({ integrations: [sealpixel()] });

The integration keeps the Sealpixel packages out of Vite's dependency pre-bundling, so new URL(…, import.meta.url) for the wasm and the worker keeps working, and sets worker.format to es.

The starter ​

examples/starters/astro. Open it on StackBlitz. The page, quoted from the starter:

astro
---
import SealpixelEditor from '@sealpixel/astro/SealpixelEditor.astro';

const editLog = {
  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 },
  ],
};
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Sealpixel · Astro</title>
    <style>
      body { margin: 0; font-family: system-ui, sans-serif; background: #0f1117; color: #eef0f6; display: grid; gap: 12px; padding: 16px; }
      sealpixel-editor { height: min(70vh, 640px); border-radius: 12px; overflow: hidden; }
      output { font: 13px ui-monospace, monospace; color: #a3a9b8; }
    </style>
  </head>
  <body>
    <SealpixelEditor src="/landscape.png" theme="dark" editLog={editLog} />
    <output data-testid="processed">Press Download: the file name carries the SHA-256 of the result.</output>
    <script>
      import type { ExportResult } from '@sealpixel/core';
      document.querySelector('sealpixel-editor')?.addEventListener('sealpixel:process', (e) => {
        const r = (e as CustomEvent<ExportResult>).detail;
        const out = document.querySelector('output');
        if (out) out.textContent = `exported ${r.width}x${r.height} sha256 ${r.hash}`;
      });
    </script>
  </body>
</html>

The component takes what travels as attributes: src as a URL, theme, locale, editLog and pluginOptions (serialised to JSON), the show… switches and downloadLabel. Events are the element's, listened to from a <script> as above. Anything that is not plain data — a File as the source, a renderer, a custom plugin list, a controlled log — belongs in an island built with @sealpixel/react, @sealpixel/vue or @sealpixel/svelte, with the client directive of your choice.

Server-side rendering ​

The .astro component is server-rendered by nature: it emits the tag and a client script that imports @sealpixel/element. Nothing else is needed; the editor comes alive when that script runs. With the <ClientRouter />, the script also hydrates the editors of every page that a client-side navigation brings in, on astro:page-load, and leaves editors it already hydrated alone. An island around a framework binding needs client:only for the framework, because the bindings are browser-only.

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. With an SSR adapter it runs in an Astro endpoint that you write.

TypeScript ​

The component's props are typed in the .astro file. In the client script, the event details are the element's:

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