kluuu mascot
90 moods, one spec.
The mascot is a pure function of numbers. An app sets a mood; the transition, the breathing and the blinks happen in the runtime.
How the spec reaches an app
- 1
Ship it embedded
The runtime and the spec sit in the app bundle. The first launch renders without a network.
- 2
Check occasionally
Once a day, jittered per install, never on every launch and never on a metered connection. A check that finds nothing costs one 304 with no body.
- 3
Swap atomically
Verify the signature and hash, then replace. If the new spec fails on the next launch, the client falls back to the embedded copy.
Endpoints
Every path below is relative to this. Set with NUXT_PUBLIC_SPEC_BASE_URL; unset means origin-relative.
Spec
What an app fetches to stay current. Content-hash ETags throughout, so a poll that finds nothing new costs a 304.
- GET
/spec/v1/index.jsonPointer to the current version, with its sha256 and channels. - GET
/spec/v1/releases/1.9.0/bundle.jsonAn immutable release: geometry, rig, motion and every mood. - GET
/spec/v1/schema.jsonJSON Schema, generated from the same rig descriptors.
Rendering
A mood as a self-animating SVG, with its idle loop baked into CSS keyframes. No script, no runtime — it works in an <img> tag, a README or a CMS.
- GET
/api/mascot/{mood}One mood, animated. CORS open. Unknown mood ids 404 rather than falling back.- size=512 (16–2048)
- bg=ffffff (hex, no #)
- colour=mood|brand
- idle=off|subtle|lively
- frames=24 (6–60)
- duration=4000 (500–20000)
- seed=1 (1–9999)
- GET
/api/cloudsA drifting cloud band. Every scenery parameter is a query key of the same name; out-of-range values are clamped. Also served at /api/clouds.svg.- preset=soft|banner|outlined|launchpad|dusk|night|fill
- frameW=402 · frameH=872 · cover=0.32 · zoom=0.57
- depth=3 · layerGap=0.08 · scale=1.35 · softness=0.75
- haze=1.17 · seed=0 · rocket=0 · launch=0
- items=0 · drift=49 · cloudL=0.985 · cloudC=0.014
- cloudHue=236 · outlineDL=-0.09 · outlineW=0 · innerDL=-0.038
- innerSize=7 · accentDL=0.02 · accentW=0 · skyL=0.93
- skyC=0.06 · skyHue=236 · skyOpacity=0
- t=4200 (a still frame)
Sources and docs
Served from the repo files themselves, so what you download is what is running here.
- GET
/api/download/{target}package → the npm tarball (302 to the versioned file) · swiftui → zipped Swift package · react-native → all four adapters (SVG and Skia) and everything they import · parity → PARITY.md - GET
/api/docs/{doc}integration | research — rendered HTML plus the extracted heading tree.
Embeddable bundle
Static files, not endpoints. Two of them go into an app: the runtime is code, the spec is data — which is what lets a new mood ship without a store release.
- GET
/embed/kluuu-mascot-1.9.0.jsThe runtime: rig, scene builder, spring integrator, idle layer. ESM, no dependencies. - GET
/embed/kluuu-spec-1.9.0.jsonThe offline baseline the runtime reads before any update lands. - GET
/embed/kluuu-mascot-1.9.0.tgzThe npm package, pinned to a version. This is the URL to put in a package.json — npm keys its integrity hash by URL, so an unversioned one breaks `npm ci` the day the bytes change. - GET
/embed/manifest.jsonVersions, integrity hashes and sizes for the files above.
Integrate
A framework-free tag for plain HTML, a CMS template or a page you do not control the build of.
<script type="module">
// The embed bundle is one self-contained ESM file with no imports at all, so
// it works from a plain HTML page with no build step. It exports the element
// classes rather than registering them, which is what lets you pick the tag.
import { KluuuMascotElement, KluuuCloudsElement }
from 'https://kluuuapi.glade.studio/embed/kluuu-mascot-1.9.0.js'
customElements.define('kluuu-mascot', KluuuMascotElement)
customElements.define('kluuu-clouds', KluuuCloudsElement)
// With the package installed, one side-effect import does the same thing:
// import '@kluuu/mascot/define'
</script>
<kluuu-mascot mood="happy" size="160"></kluuu-mascot>
<script type="module">
const el = document.querySelector('kluuu-mascot')
el.mood = 'celebrating' // springs across, never cuts
el.setAttribute('idle', 'lively')
el.setAttribute('colour-mode', 'brand') // any mood in the original green
</script>Full guide, including versioning, signing and the native targets: integration guide.