Repository navigation
EN Create Characters
Français · Type: reference · Audience: author · Context: engine repository, created project · Status: ready · Applies from: 4.3.0
A character is declared once, in game.ts (characters, usually from cast.ts), and placed in a room as an actor.
This page lists a character's fields, its poses and mouths, the variants its state selects, palette swaps, and
characters that are seen but not acted on.
characters: {
grandma: {
name: 'Grandma', color: '#f0c040', height: 124, kind: ['person'],
portrait: 'grandma/r1c2',
sprites: { idle: ['grandma/r3c3'], talk: ['grandma/r3c4', 'grandma/r3c3'], walk: ['grandma/r2c1', 'grandma/r2c2', …] },
refuse: 'That is sweet, dear. But keep it, you will need it for your errand.',
hug: 'Always. Even with a basket in my arms.',
},
talkie: { name: 'the walkie-talkie', color: '#ff6fb5', offscreen: true }, // speaks in a frame, no body
},| Field | What |
|---|---|
name |
The display name. |
color |
The colour of their lines. Make each character's distinct (dialogues). |
height |
On-screen height in logical units, in the foreground (default skin.heights: actor 110, hero 84). |
sprites |
Poses: pose name → list of images, played in a loop (at least idle). |
fps |
Animation frames per second (default 8). |
mouths |
Mouth images per pose (below). |
portrait |
For the map, calls and conversation menus. |
kind |
Kinds, for the reactions by kind (['person'], ['cat']; reactions). |
refuse |
The answer to any Give that has no rule. |
hug |
The answer to the global "hug" topic (globalTalk.hug); without it, "♥". |
offscreen |
Speaks in a frame at the top of the screen, no body (narrator, plush toy, phone). |
glow |
A soft glow around the character (a CSS colour), e.g. an apparition. |
room |
Starting room of a character that moves between rooms (moving characters). |
variants, palette, paletteTolerance
|
Looks that depend on state (below). |
description |
What they look like, in words, for the art prompts (npm run prompts). Not shown in the game. |
The hero is a character too (hero in game.ts); several playable characters and choosing the hero are on
heroes. A character speaks in a room only through an actor, except in a phone call
(commands).
By convention: idle, talk, walk (profile, facing right; the engine flips the image for left), walk_front,
walk_back, point, use, plus any special pose you want (sleep, sit, celebrate…). A pose is a list of images
played in a loop. A missing pose falls back to idle (validate warns about an actor whose pose is missing). The
template's cast.ts has helpers for the standard sheets: human(id) and cat(id) map a 6 × 4 sheet to these poses
(images). { pose: ['cat', 'sleep'] } sets a lasting pose; { anim: ['hero', 'use'], ms: 600 }
plays one for a while (commands).
A character with a talking sheet declares their mouths per pose. During a line the body never changes: the open-mouth images cycle at random (160 to 220 ms), and a blink passes by now and then at rest. The "mouth closed" image replaces the pose's rest image, so rest and speech come from the same drawing.
import { human, mouths } from './cast';
grandpa: { …, mouths: mouths('talk_grandpa', { idle: 'profile', front: 'face', seated: 'seated' }) },mouths(folder, { pose: row }) reads <folder>/<row>/t1…t6 (t1 closed, t2 to t4 open, t5 blink, t6 smile), the
frames tools/talk-apply.py produces. With no mouths for a pose, the character keeps the same image and bounces a
pixel while talking; a long line starts with a gesture (the talk pose) played once.
import { cat } from './cast';
hero: { …, sprites: cat('hero'), variants: [{ if: { has: 'bucket' }, sprites: cat('hero_bucket'), mouths: … }] },The first variant whose condition is true replaces sprites, mouths and portrait, and name when it has one
(4.3.0: the hero the player chose, a character renamed after a reveal; heroes). The change shows
right away (e.g. as soon as the bucket is picked up).
One sheet, several looks: palette maps source colours to target colours, both #rrggbb. The room view recolours
every sprite and mouth frame of the character once, in an offscreen canvas (cached, alpha kept). A variant's palette
replaces the character's while its condition holds (a variant without one keeps the character's).
biscuit: { …, sprites: cat('cat'),
palette: { '#2c1818': '#7a3416', '#492a25': '#b0592a', '#543329': '#c4703a' }, paletteTolerance: 14,
variants: [{ if: 'muddy', palette: { '#492a25': '#5a4a3a' } }] },Matches are exact RGB by default: this suits the pixel art style, whose cutter gives every material one exact
value. Painted (cel) sheets and lossy WebP have many neighbouring tones: paletteTolerance (an RGB distance; 10 to
16 is a good start, below the distance to the outline colour) recolours every pixel near a source colour, keeping its
offset from it; the nearest source colour wins. Pick the source colours from the cut PNG (the most frequent opaque
colours of a cell). The demo's Biscuit uses this to become a ginger tabby.
Limit ·
portraits-not-recolouredPortraits in menus and calls are not recoloured.npm run validatewarns about a palette key or value that is not#rrggbb.
A seagull that watches or snaps, an old dog that sleeps, sulks or yawns, a cat's eye glowing on a screen: a hotspot has only a name and a zone, so for a drawn thing that changes, use a stateful prop:
props: { seagull: { name: 'seagull', states: { watch: 'obj_yard/r2c4', snap: 'obj_yard/r2c5' }, initial: 'watch' } }with a position per state in the layout (props.seagull.states.snap); the clickable zone follows the image. Change
the state with { prop: ['seagull', 'snap'] } and react to it with if: { prop: ['seagull', 'snap'] }. For a zone of
the background that changes name or shape, use two hotspots with opposite visible conditions (visible: 'x' /
visible: '!x'), each with its own zone; a rule can target both (a: ['h1', 'h2']).
actors: { ghost: { char: 'ghost', interactive: false, visible: 'ghost_seen' } }: visible, but neither clickable nor
named. Combine with { show: 'ghost', fade: 1500 } / { hide: 'ghost', fade: 1500 } and glow on the character's
sheet.
-
CharacterDef,ActorDef,MouthSetinsrc/engine/core/types/content.ts. - Rooms: actors, dialogues, heroes, images, voices.
Generated publication · publication générée — current documentation · documentation courante: quest'n'click 4.4.0 r1, documentation revision · révision de la documentation 8dc717c69acb62c4742b69c54a7e7dfb620f75d8.
Earlier versions and permalinks · versions précédentes et liens permanents: https://wanoo.github.io/quest-n-click/docs/
An edit made in this wiki is overwritten at the next publication · une modification faite dans ce wiki est écrasée à la publication suivante.
Edit the source · Modifier la source · Report an error · Signaler une erreur
Index (6)
Start (6)
Play (9)
Install (17)
- Requirements
- Install from the release archive
- Install from npm, once published
- Install from the repository to work on the engine
- doctor: checking your machine
- Image toolchain
- Audio toolchain: ffmpeg, fluidsynth, Furnace, uv
- Upgrade
- Upgrade notes: 4.4
- Upgrade notes: 4.3
- Upgrade notes: 4.2
- Upgrade notes: 4.1
- Upgrade notes: v3
- Upgrade notes: v2 to v3
- Coming from web-scumm
- Package reference
- Install troubleshooting
Create a game (55)
- Your first game
- Layout of a created project and of the engine repository
- The working loop
- Content principles and the identity contract
- Rooms
- Geometry: placement, walk zones, masks, layers, camera
- Something is visible but unreachable
- Reactions
- Game commands
- Conditions
- Flags, variables and events: which to use
- Custom code
- Characters
- Items and inventory
- World map
- Dialogues
- Scripts and events
- Moving characters: patrols and walks
- Exits
- Chapters and objectives
- State and saves: persistent or temporary, renaming an id, migrations
- Staging: wide rooms and animations
- The stage: lights, particles, floors
- Skin and fonts
- Title and credits
- Heroes: several characters and hero choice
- Built-in minigames
- A custom minigame
- Translations
- Music in stems
- Sound effects
- Voices: per language and per hero
- Images: prompts, cutting sheets, transparency, scale
- Asset provenance
- The storyboard, source of truth
- Puzzle design
- Classic mechanics
- Review pages
- DSL reference
- Checking your game
- What the solver proves
- Solver options
- Playtests
- Remix
- Speedrun for authors
- The sealed ending
- Production template
- Example games
- Working with an AI
- Build and release a game
- Publish on GitHub Pages
- The static game on Clever Cloud
- Other static hosts
- Sub-path, cache and service worker, incomplete deploys, going back
- Testing on a phone over the LAN
Local Studio (24)
- The local Studio: overview and launch
- Edit a room
- Placement and stage
- Preview, apply, undo
- Storyboard
- Assets and cutting
- Check: validator, solver, critical path, heat, health, coverage
- Before and after captures
- Semantic diff
- Play and replay a session
- Rule explainer
- Language and objectives
- Voices and the heroes × languages matrix
- Map
- Notes
- Remix in the Studio
- Music
- The Assistant: bring your own key
- Demo mode and studio-apply
- Local and LAN security
- Studio API
- Local MCP: setting up each client
- MCP tools
- Studio troubleshooting
Team Studio (21)
- What runs where
- Concepts: revision, transaction, span, lease, preview, build
- Starting as an invited dev
- Working together day to day
- Roles and actions: the full matrix
- Invitations
- Managing members
- Write refused on the hosted Studio: stale base revision (409)
- Write refused on the hosted Studio: span locked (423)
- Recovering after a lost lease, a disconnection or a stale preview
- Comments
- Map and semantic diff
- Publishing builds
- Remote MCP
- The game in Git
- Upgrading the engine of a hosted game
- Hosted assets
- The server's command line
- Health and metrics routes
- Trying it locally with compose.yml
- Known limits
Clever Cloud (23)
- Clever Cloud: overview, cost and prerequisites
- Apps and add-ons
- Domains and TLS
- Keycloak
- Generic OIDC and GitLab
- Configuration
- First deployment
- Backups
- RPO and RTO
- Restore the Studio on a fresh installation
- Redeploys
- Upgrading the server and checking state after a migration
- Limits of going back
- Monitoring
- Security
- Rotating keys
- Recovering admin access
- Changing domain or OIDC provider
- Worker, PostgreSQL or Cellar down
- Exporting the game and leaving the installation
- Retention
- Clever Cloud troubleshooting
- Costs and teardown
Reality Bridge and connectors (16)
- The Reality Bridge: what it is
- Quick start
- Guarantees
- Install and run the Bridge
- Backup and restore
- Several tenants
- Signals and the manifest
- The Bridge's command line
- Connectors overview
- Email connector
- Telnet connector
- SSH connector
- Open Badges connector
- The connector SDK
- Security: Biscuit and signatures
- Bridge and connector troubleshooting
Contribute (25)
- Welcome
- Developer setup
- The dev loop
- Before a pull request
- Conventions
- Writing documentation
- Architecture
- Code tour
- Import boundaries
- Which tests run when
- Mutation testing
- The coverage ratchet
- The quality baseline
- CI explained
- Field passes
- Benchmarks
- Releasing
- npm packages
- Decisions and ADRs
- Governance
- Bot pull requests
- Contributing with AI agents
- Security policy
- Code of conduct
- Licences and credits