Build your own pet pack
Mochi, Byte and Flowy are separate packages containing character definitions and artwork. Importing a pack creates no DOM and starts no animation. The application creates a live instance with createPet.
1. Prepare artwork
Choose PNG, GIF, video, sprite sheets or separate frames. Keep canvas dimensions and the character's pivot consistent across states to prevent jumps. This example needs a still idle.png and a happy.png sheet with 16 equal frames in a 4 × 4 grid.
2. Package structure
Source artwork lives in assets; the build puts it beside the JavaScript in dist/assets:
my-pet/
src/index.ts
assets/idle.png
assets/happy.png
dist/index.js
dist/index.d.ts
dist/assets/idle.png
dist/assets/happy.png
package.json
README.md
LICENSE3. Export the definition
Like Flowy, the pack imports only types from core. new URL(..., import.meta.url) resolves files relative to the module instead of the website root. These paths target the built dist/index.js.
// src/index.ts
import type { PetDefinition } from '@flowscape-ui/mimimo';
export const myPet = {
id: 'my-pet',
name: 'My pet',
width: 128,
height: 128,
initialState: 'idle',
animations: {
idle: {
type: 'image',
path: new URL('./assets/idle.png', import.meta.url).href,
},
happy: {
type: 'sprite',
path: new URL('./assets/happy.png', import.meta.url).href,
columns: 4,
rows: 4,
frameCount: 16,
fps: 12,
loop: false,
},
},
} as const satisfies PetDefinition;4. Build the package and its assets
Replace @your-scope/my-pet with your own name. The example stays private until you choose licenses for code and artwork and decide to publish. Build with TypeScript and tsdown:
{
"name": "@your-scope/my-pet",
"version": "0.1.0",
"private": true,
"type": "module",
"sideEffects": false,
"files": ["dist", "README.md", "LICENSE"],
"exports": {
".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
"./assets/*": "./dist/assets/*"
},
"peerDependencies": { "@flowscape-ui/mimimo": "^0.1.0" },
"scripts": { "build": "tsdown" }
}pnpm add -D typescript tsdown @flowscape-ui/mimimo// tsdown.config.ts
import { defineConfig } from 'tsdown';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
platform: 'browser',
target: 'es2022',
dts: true,
clean: true,
copy: [{ from: 'assets', to: 'dist' }],
});Run pnpm build, then pnpm pack. Check that the tarball includes dist/index.js, declarations and both PNGs in dist/assets. Install the .tgz in a test application and check Network for missing assets. When serving modules directly, preserve the adjacent assets directory.
5. Use the character
definePet validates the definition at runtime. In React create the instance in useEffect; in Vue use onMounted. Call destroy on unmount. See complete framework examples.
import { createPet, definePet } from '@flowscape-ui/mimimo';
import { myPet } from '@your-scope/my-pet';
// Call after the component mounts.
const pet = createPet({
character: definePet(myPet),
draggable: true,
reactions: { click: 'happy' },
});
pet.say('Hello!');
// On unmount: pet.destroy();How our packs work
- Mochi and Byte generate SVG frames and export
frameswithfps. No separate image files are needed. - Flowy ships three PNG sheets,
idle,workingandhappystates, and copies artwork during its build. Use it as the example for external assets.
Core must not import your pet pack. The application chooses the character, messages and reactions; the pack owns only its definition and artwork.