Toolbox

Susano

See on GitHub

Susano library by JOYCO Studio.

Asset load orchestration made easy.

pnpm add @joycostudio/susano

Quick 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.

OptionTypeDescription
srcSetstringMaps to img.srcset
sizesstringMaps to img.sizes
susano.add('/photo.png', {
  type: 'image',
  loaderArgs: { srcSet: '/photo-2x.png 2x', sizes: '100vw' },
})

video

Loads video via HTMLVideoElement.

OptionTypeDefaultDescription
videoHTMLVideoElementnew elementExisting 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.

OptionTypeDefaultDescription
audioHTMLAudioElementnew elementExisting 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.

OptionTypeDescription
loadFnGenericLoadFnRequired. 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:

EventPayloadDescription
startsusanoBatch loading started
progress{ value: number, item: SusanoLoader, susano }An asset finished loading
completedsusanoAll 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' })

Related Toolboxs