@nanonomad/core
v1.0.3
Published
Framework-agnostic digital pet engine (movement, behavior, capabilities, renderer)
Maintainers
Readme
@nanonomad/core
The framework-agnostic engine that powers the NanoNomad digital pet. It handles physics, behavior, animation, and rendering — with no dependencies on React, Vue, or any other UI library.
Use this package directly when working with vanilla JavaScript, or as the foundation when integrating into any framework.
For a single install that includes characters helpers and assets metadata, use @nanonomad/web. For React / Next.js, use @nanonomad/react (it depends on core + characters).
Installation
npm install @nanonomad/core @nanonomad/characters@nanonomad/characters supplies the SVG assets, CSS, and character.json files the engine loads at runtime (or install @nanonomad/web / @nanonomad/react instead).
Quick start
The engine needs three things to run: a host (an abstraction over window and document), a runtime config that tells it which character to display and where to find its assets, and a call to start().
import NanoNomad, { createBrowserHost } from '@nanonomad/core'
const pet = new NanoNomad({
host: createBrowserHost(window),
runtimeConfig: {
character: 'default',
characterBaseUrl: '/nanonomad-characters/default/',
characterConfigUrl: '/nanonomad-characters/default/character.json',
},
})
await pet.start()The pet will appear immediately and begin walking, jumping, and idling across the browser window. It sits on a fixed overlay with pointer-events: none, so it never blocks clicks or form inputs.
Loading character assets
The engine fetches character.json at startup to learn which poses, capabilities, and physics settings the character uses. All SVG and CSS files are loaded relative to characterBaseUrl.
There are two ways to serve these assets.
Self-hosted (recommended for production)
Copy the character files into your project's static folder using the CLI tool from @nanonomad/characters:
npx nanonomad-characters-copy ./public/nanonomad-charactersThen point the engine at the copied files:
runtimeConfig: {
character: 'default',
characterBaseUrl: '/nanonomad-characters/default/',
characterConfigUrl: '/nanonomad-characters/default/character.json',
}CDN (zero-setup)
Use the jsDelivr CDN, which mirrors the npm package automatically. No server configuration is needed.
import { getCharacterUrls } from '@nanonomad/characters'
const urls = getCharacterUrls('default', { version: '1.0.0' })
const pet = new NanoNomad({
host: createBrowserHost(window),
runtimeConfig: {
...urls,
// urls provides: character, characterBaseUrl, characterConfigUrl
},
})The page must be served over HTTP or HTTPS — fetch() does not work on file:// URLs.
Constructor options
const pet = new NanoNomad(options)| Option | Type | Default | Description |
|---|---|---|---|
| host | object | — | A host object created by createBrowserHost(window). Required before calling start(). |
| runtimeConfig | object | {} | Configuration passed to the engine. See Runtime configuration below. |
| mountTarget | HTMLElement | null | A DOM element to mount the pet inside. When omitted the engine creates its own full-screen overlay appended to <body>. |
| capabilityRegistry | CapabilityRegistry | auto | Supply a custom registry if you want to add or replace capabilities before startup. |
| registerBuiltin | boolean | true | Set to false to skip loading the built-in capabilities (idle, walk, jump, sit, fall, run, sleep, pee). Useful when you want to provide your own capability set. |
| fetch | function | globalThis.fetch | Override the fetch function used to load character.json. Useful in environments where fetch is not global. |
Runtime configuration
The runtimeConfig object controls every aspect of the pet's behavior and appearance.
Asset loading
| Parameter | Type | Default | Description |
|---|---|---|---|
| character | string | 'default' | The character identifier to load. Must match a folder name in your characters directory (e.g. 'dog', 'default'). |
| characterBaseUrl | string | '' | Base URL for the character's asset folder. All SVG and CSS files are fetched relative to this path. Must end with /. |
| characterConfigUrl | string | '' | Full URL to the character's character.json file. |
| characterProvider | object | null | An alternative to characterBaseUrl / characterConfigUrl. Supply an object with a getCharacter(id) async method. See Character providers. |
Behavior
| Parameter | Type | Default | Description |
|---|---|---|---|
| enabledCapabilities | string[] | [] | List of capabilities the pet is allowed to use. An empty array means all capabilities defined in character.json are enabled. Valid values: 'idle', 'walk', 'run', 'jump', 'sit', 'sleep', 'pee', 'fall'. Note: idle and fall are always included regardless of this list. |
| movementSpeed | number | 50 | Overall movement speed on a scale of 1 to 100. Affects walk and run velocity. Higher values make the pet visibly faster. |
| behaviorFrequency | number | 50 | How often the behavior engine considers changing state, on a scale of 1 to 100. Higher values produce more active, restless behavior. Lower values make the pet calmer and more likely to idle. |
| mobileEnabled | boolean | false | When false, the pet does not start on screens narrower than 768 px. Set to true to enable it on mobile devices. |
| persistenceEnabled | boolean | true | Saves the pet's position to localStorage every 5 seconds and on page unload. On the next page load the pet resumes from where it was. |
Appearance
| Parameter | Type | Default | Description |
|---|---|---|---|
| customColors | object | {} | Override the character's default color palette. Keys must match the palette keys defined in character.json. Values are CSS color strings. |
Lifecycle methods
await pet.start()
Fetches character.json, mounts the pet into the DOM, initializes the physics and behavior engines, and begins the animation loop. This is the only async step. Safe to call once per instance.
pet.pause()
Stops the animation loop and pauses both the behavior and movement engines. The pet remains visible in the DOM at its last position. Use this when the pet should temporarily stop (e.g. during a modal or video).
pet.resume()
Resumes a paused pet. Restarts the animation loop and engines. Has no effect if the pet was not previously paused.
pet.destroy()
Stops the loop, removes all event listeners, clears all timers, and removes the pet's DOM elements. After calling destroy(), the instance cannot be restarted — create a new one if needed.
pet.getConfig()
Returns the fully merged configuration object that was resolved at start() time, including values loaded from character.json. Useful for inspecting what the engine is actually running with.
Automatic behaviors
Once running, the engine manages several behaviors automatically without any configuration.
Tab visibility — the animation loop stops when the browser tab is hidden (via the Page Visibility API) and resumes when the tab regains focus. This prevents unnecessary CPU usage on inactive tabs.
Idle detection — if the user has not moved the mouse, pressed a key, or touched the screen for 60 seconds, the pet pauses. It resumes as soon as the user interacts again.
Scroll fading — the pet's opacity drops to 30% while the page is being scrolled and returns to full opacity 400 ms after scrolling stops.
Platform detection — the engine scans the page for DOM elements (header, nav, footer, section, article, .card, .widget, and others) and treats their top edges as platforms. The pet can land on and walk across these surfaces.
Capabilities
Capabilities are the individual behaviors the pet can perform. Each capability is a state the pet transitions into and out of over time.
| Capability | Description | Characters that include it |
|---|---|---|
| idle | The pet stands still facing forward. Always active. | All |
| walk | The pet walks left or right across the screen or platform. | All |
| fall | The pet falls when it steps off a platform or edge. Always active. | All |
| jump | The pet launches upward and falls back down. | All |
| sit | The pet sits and rests for a random duration. | All |
| run | The pet moves at 2.2× walk speed. | Dog |
| sleep | The pet lies down and sleeps for an extended period. | Dog |
| pee | The pet walks toward a nearby text element and marks it. | Dog |
The idle and fall capabilities are always included even if omitted from enabledCapabilities. Other capabilities must be listed in the character's character.json AND present in enabledCapabilities (or enabledCapabilities must be empty) to activate.
Color customization
Each character defines a color palette in its character.json. You can override any or all palette keys by passing customColors in your runtime config.
// Default character palette keys: body, head, legs, blush, eyes, detail
runtimeConfig: {
character: 'default',
customColors: {
body: '#2563eb',
head: '#1d4ed8',
legs: '#1e3a8a',
},
}// Dog character palette keys: body, belly, ears, detail, eyes, tongue
runtimeConfig: {
character: 'dog',
customColors: {
body: '#8b4513',
belly: '#d2691e',
tongue: '#ff4444',
},
}Color keys not provided in customColors retain their defaults from character.json. Any valid CSS color string is accepted (#hex, rgb(), hsl(), named colors).
Character providers
For advanced setups — such as loading characters from a custom API or a private CDN — you can supply a characterProvider instead of characterBaseUrl and characterConfigUrl.
A character provider is any object with a getCharacter(id) async method that returns { config, baseUrl, configUrl }.
import { createUrlCharacterProvider } from '@nanonomad/core'
// Built-in provider: resolves characters from a static root URL
const provider = createUrlCharacterProvider('https://example.com/pets/')
const pet = new NanoNomad({
host: createBrowserHost(window),
runtimeConfig: {
character: 'dog',
characterProvider: provider,
},
})To write a custom provider:
const myProvider = {
async getCharacter(id) {
const res = await fetch(`/api/characters/${id}`)
const data = await res.json()
return {
config: data.characterConfig, // the character.json contents
baseUrl: data.assetBaseUrl, // e.g. 'https://assets.example.com/dog/'
configUrl: data.assetBaseUrl + 'character.json',
}
},
}Custom capabilities
You can extend the engine with your own behavior states. Register a custom capability on a CapabilityRegistry before passing it to NanoNomad.
import NanoNomad, { createBrowserHost, CapabilityRegistry, registerBuiltinCapabilities } from '@nanonomad/core'
const registry = new CapabilityRegistry()
registerBuiltinCapabilities(registry)
// Add a custom 'spin' capability
registry.register('spin', {
id: 'spin',
state: 'spin',
system: false,
enter(ctx) {
ctx.movement.stopWalk()
ctx.stateTimer = ctx.getStateDuration('spin') || 2000
},
update(ctx, dt) {
ctx.stateTimer -= dt
if (ctx.stateTimer <= 0) ctx.transitionToNext()
},
exit(ctx) {},
})
const pet = new NanoNomad({
host: createBrowserHost(window),
capabilityRegistry: registry,
runtimeConfig: {
character: 'default',
characterBaseUrl: '/nanonomad-characters/default/',
characterConfigUrl: '/nanonomad-characters/default/character.json',
enabledCapabilities: ['idle', 'walk', 'jump', 'sit', 'fall', 'spin'],
},
})
await pet.start()Named exports
import NanoNomad, {
createBrowserHost,
CapabilityRegistry,
registerBuiltinCapabilities,
createUrlCharacterProvider,
mergeRuntimeConfig,
Environment,
MovementEngine,
BehaviorEngine,
Renderer,
} from '@nanonomad/core'| Export | Description |
|---|---|
| NanoNomad (default) | The main orchestrator class. |
| createBrowserHost | Creates the host object required by the engine. Pass window. |
| CapabilityRegistry | Registry for registering and resolving behavior capabilities. |
| registerBuiltinCapabilities | Registers all built-in capabilities on a registry instance. |
| createUrlCharacterProvider | Factory for a URL-based character provider. |
| mergeRuntimeConfig | Merges runtime options with character JSON. Used internally; exposed for advanced use. |
| Environment | Scans the DOM for platforms and text targets. |
| MovementEngine | Velocity-based physics engine. |
| BehaviorEngine | State machine that drives capability transitions. |
| Renderer | Loads SVG assets and applies CSS transforms and color overrides. |
Formats
The package ships three build formats.
| Format | File | Use case |
|---|---|---|
| ESM | dist/nanonomad.esm.js | Bundlers (webpack, Vite, Rollup), modern import |
| CJS | dist/nanonomad.cjs | Node.js require() |
| UMD | dist/nanonomad.umd.js | <script> tags, CDN, vanilla JS |
Requirements
- Node.js 18 or later (for tooling)
- Modern browser with
fetch,requestAnimationFrame, andlocalStorage - Pages must be served over HTTP or HTTPS (not
file://)
License
GPL-2.0-or-later
