Susano
Susano library by JOYCO Studio.
Asset load orchestration made easy.
pnpm add @joycostudio/susanoQuick Start
import { susano } from '@joycostudio/susano'
// Queue assets
susano.add('/hero.png', { type: 'image' })
susano.add('/intro.mp4', { type: 'video' })
// Start loading
susano.start({
onProgress: ({ value }) => console.log(`${Math.round(value * 100)}%`),
onCompleted: () => console.log('All assets loaded!'),
})API
susano singleton
A pre-configured instance with built-in loaders for image, video, audio, and generic types.
add(url, { type, loaderArgs? })
Queue an asset for batch loading. Returns the loader instance.
const img = susano.add('/photo.png', {
type: 'image',
loaderArgs: { srcSet: '480w.png 480w, 800w.png 800w', sizes: '(max-width: 600px) 480px, 800px' },
})load(url, { type, loaderArgs? })
Load a single asset immediately (standalone, outside the batch queue). Returns the loader instance.
const img = susano.load('/standalone.png', { type: 'image' })start({ onProgress?, onCompleted? })
Start loading all queued assets. Emits start, progress, and completed events.
susano.start({
onProgress: ({ value, item }) => {
// value: 0 to 1
},
onCompleted: (susano) => {
// all assets loaded
},
})registerLoader(type, loader)
Register a custom loader class for a given type.
susano.registerLoader('custom', CustomLoader)Built-in Loaders
image
Loads images via HTMLImageElement.
| Option | Type | Description |
|---|---|---|
srcSet | string | Maps to img.srcset |
sizes | string | Maps to img.sizes |
susano.add('/photo.png', {
type: 'image',
loaderArgs: { srcSet: '/photo-2x.png 2x', sizes: '100vw' },
})video
Loads video via HTMLVideoElement.
| Option | Type | Default | Description |
|---|---|---|---|
video | HTMLVideoElement | new element | Existing video element to load into |
loadEvent | 'canplay' | 'canplaythrough' | 'canplay' | Event that signals load completion |
susano.add('/intro.mp4', {
type: 'video',
loaderArgs: { loadEvent: 'canplaythrough' },
})audio
Loads audio via HTMLAudioElement.
| Option | Type | Default | Description |
|---|---|---|---|
audio | HTMLAudioElement | new element | Existing audio element to load into |
loadEvent | 'canplay' | 'canplaythrough' | 'canplay' | Event that signals load completion |
susano.add('/music.mp3', {
type: 'audio',
loaderArgs: { loadEvent: 'canplaythrough' },
})generic
Fully custom loader. Requires a loadFn callback.
| Option | Type | Description |
|---|---|---|
loadFn | GenericLoadFn | Required. Custom load function |
The loadFn receives { url, done, error, progress }:
susano.add('/data.json', {
type: 'generic',
loaderArgs: {
loadFn: ({ url, done, error, progress }) => {
fetch(url)
.then((res) => res.json())
.then((data) => done(data))
.catch((err) => error(err))
},
},
})Events
The susano instance extends TinyEmitter and emits:
| Event | Payload | Description |
|---|---|---|
start | susano | Batch loading started |
progress | { value: number, item: SusanoLoader, susano } | An asset finished loading |
completed | susano | All assets loaded |
Individual loader instances also emit loaded and progress events.
Batched vs Standalone Loading
Batched — queue multiple assets with add(), then call start() to load them all. Progress is tracked across the entire batch.
susano.add('/a.png', { type: 'image' })
susano.add('/b.mp4', { type: 'video' })
susano.start({ onCompleted: () => console.log('done') })Standalone — use load() to immediately load a single asset without affecting the batch queue.
const item = susano.load('/lazy.png', { type: 'image' })