feat(frontend): ImageVariant component and WASM encoder workers

Add client-side multi-format image encoding via Web Workers using @jsquash and @discourse/jxl libraries. ImageVariant Svelte component renders <picture> elements with format-aware fallback. Vite configured for WASM asset inclusion and encoder dependency exclusion. Portfolio page updated to use multi-format URLs.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-06-04 01:07:00 +01:00
co-authored by Sisyphus
parent 0da7498ad7
commit 584c02ac6c
16 changed files with 178 additions and 60 deletions
@@ -0,0 +1,41 @@
<script lang="ts">
interface ThumbURLs {
avif: string;
webp: string;
jpg: string;
}
interface FullURLs {
avif: string;
webp: string;
jpg: string;
jxl?: string;
}
let { urls, type = "thumb", alt = "", class: className = "", ...imgProps }: {
urls: ThumbURLs | FullURLs;
type?: "thumb" | "full";
alt?: string;
class?: string;
[key: string]: unknown;
} = $props();
const fallbackSrc = $derived(urls.jpg || urls.webp || urls.avif || "");
const hasJxl = $derived(type === "full" && "jxl" in urls && (urls as FullURLs).jxl);
</script>
<picture>
{#if urls.avif}
<source srcset={urls.avif} type="image/avif" />
{/if}
{#if urls.webp}
<source srcset={urls.webp} type="image/webp" />
{/if}
{#if urls.jpg}
<source srcset={urls.jpg} type="image/jpeg" />
{/if}
{#if hasJxl}
<source srcset={(urls as FullURLs).jxl} type="image/jxl" />
{/if}
<img src={fallbackSrc} {alt} class={className} {...imgProps} />
</picture>