Dark mode
For creators: maps and routines
Make places for Hana to live in and routines for her day, then share them on the Steam Workshop. Nothing in a map or routine runs as code: they're data only (settings files, a 3D model, pictures and audio), checked again every time they load.
Routines (routine.json)
The easiest way is the editor in ⚙️ Settings → World → Her day → + New routine. Export gives you the file. It looks like this:
json
{
"format": "okaeri-routine",
"version": 1,
"name": "Lazy Sunday",
"author": "Mika",
"description": "Sleeps in, reads all afternoon on the veranda.",
"days": ["sat", "sun"],
"blocks": [
{ "start": "00:00", "activity": "sleep" },
{ "start": "09:30", "activity": "wake" },
{ "start": "10:00", "activity": "breakfast" },
{ "start": "11:00", "activity": "read", "place": "veranda" },
{ "start": "13:00", "activity": "lunch" },
{ "start": "14:00", "activity": "read", "place": "veranda" },
{ "start": "18:30", "activity": "dinner" },
{ "start": "21:00", "activity": "stargaze" },
{ "start": "23:00", "activity": "sleep" }
]
}| Field | Meaning |
|---|---|
format, version | Always "okaeri-routine" and 1. |
name | Shown in the list (max 60 characters). author (60) and description (500) are optional. |
days | Which weekdays it covers: sun mon tue wed thu fri sat (full names like "Sunday" work too). Empty or missing: every day. On other days she lives her own day. |
blocks | Up to 48 rows, sorted by start (24-hour "HH:MM"). Each lasts until the next one starts; the last one runs until midnight, and the time before the first one continues the last one. |
activity | One of the activities below. |
place | Optional: do it somewhere other than usual (any place word from the map places). |
Activities and where she does them by default:
| Activity | What she does | Usual place |
|---|---|---|
sleep | sleeps | bed |
wake | stretches | yard |
breakfast, lunch, dinner | eats (sitting) | table |
cookLunch, cookDinner | cooks | kitchen |
garden | waters the flowers | garden |
read | reads (on the swing on her island) | swing |
readLamp | reads by the lamp (sitting) | lamp |
paint | paints | easel |
koi | feeds the fish | pond |
tea | has tea (sitting) | veranda |
nap | naps (lying down) | tree |
stroll | walks a loop | walk |
sweep | sweeps | sweep |
campfire | roasts marshmallows (sitting) | campfire |
stargaze | lies on a blanket and looks at the stars | stars |
piano | plays the piano (on her island; on a map she just sits there) | piano |
guitar | plays the guitar (sitting) | guitar, else campfire |
ukulele | plays the ukulele (sitting; on her island on the swing) | ukulele, else swing |
kalimba | plays the kalimba (sitting) | kalimba, else veranda |
bedtime | brushes her hair next to the bed | bed |
If something is wrong, Okaeri tells you what and where (for example "blocks[3].start" isn't a real time.).
Maps
A map is a folder (or a .zip of it):
cozy-room/
map.json what the map is and where her places are
room.glb the 3D model (one self-contained .glb, textures embedded)
music.ogg optional: the map's own music (loops while she's there)
preview.jpg optional: a picture for the Workshop (under 1 MB)Import it with ⚙️ Settings → World → + Import a map (the .zip) or + From a folder.
map.json
json
{
"format": "okaeri-map",
"version": 1,
"name": "Cozy Room",
"author": "Okaeri",
"description": "A small room with a bed, a table and a reading nook.",
"model": "room.glb",
"scale": 1,
"indoor": true,
"music": "music.ogg",
"preview": "preview.jpg",
"ground": ["floor"],
"spawn": { "pos": [0, 0, 3.5], "yaw": 3.14 },
"places": {
"bed": { "pos": [-4.4, 0, -3.6], "yaw": 1.57, "seat": 0.45 },
"table": { "pos": [2.8, 0, 2.5], "yaw": 3.14, "seat": 0.45 },
"kitchen": { "pos": [4.6, 0, 0.2], "yaw": 1.57 },
"lamp": { "pos": [-4.2, 0, 2.6], "yaw": 0.4 },
"veranda": { "pos": [3.6, 0.3, -3.2], "yaw": 0 },
"yard": { "pos": [0, 0, 3.5], "yaw": 3.14 }
},
"walk": [[0, 0, 3.5], [4, 0, 3.8], [4.2, 0, -1], [-3.5, 0, 0.6]],
"waypoints": {
"nodes": { "door": [0, 0, 3.5], "middle": [0, 0, 1.2], "east": [3.6, 0, 0], "west": [-3.6, 0, 1.2] },
"edges": [["door", "middle"], ["middle", "east"], ["middle", "west"]]
}
}| Field | Meaning |
|---|---|
format, version | Always "okaeri-map" and 1. |
name | Required, max 60 characters. author and description are optional. |
model | The .glb file name in the same folder. |
scale | Optional (default 1). Multiplies the model and every position, if your model isn't in meters. |
indoor | true if she's inside (her lamp turns on in the evening). |
music, preview | Optional file names in the same folder. |
ground | Optional: names (or the start of names) of the objects she walks on, like ["floor", "stairs"]. Without it, any upward-facing surface counts. Set it when tables or beds would otherwise count as floor. |
spawn | Where she starts and where you look from first. |
places | Where she does things (see Places). Each has pos [x, y, z], yaw, and optionally seat. |
walk | Optional loop of points for her walks. Without it, she tours the places. |
waypoints | Optional paths (up to 128 points and 512 connections) so she walks around walls: she walks to the nearest point, follows the connections, then goes straight to the place. Without them she walks in straight lines. |
Places
The place words are: bed table kitchen lamp veranda garden swing easel pond tree campfire stars yard sweep walk piano guitar ukulele kalimba. Places a map doesn't have fall back to the activity's usual place, then yard, then spawn. guitar, ukulele and kalimba mark where she sits to play them (otherwise she uses campfire, swing and veranda).
- Positions are in meters, glTF style:
xright,yup,ztoward the viewer. Stand her on the floor (y= floor height there); Okaeri finds the floor under her anyway. yawis the direction she faces, in radians:0faces +z,1.57faces +x,3.14faces −z,-1.57faces −x. Forbed, point it from the pillow toward her feet.seatis how high the seat (or mattress) is abovepos, for sitting and lying activities (table,veranda,lamp,bed,campfire…). Leave it out and she sits on the floor.
Making a map in Blender
- Model in meters (Blender's default). Keep the floor at height 0 if you can, and make her room a few meters wide (the built-in Hana is about 1.3 m tall; imported models are usually 1.5–1.7 m).
- Name the floor objects
floor…(for examplefloor,floor_kitchen) and list"ground": ["floor"]inmap.json. - To read a position for
map.json, put the 3D cursor where she should stand and look at its location in the sidebar (N → View → 3D Cursor). Blender is Z-up, so Blender (X, Y, Z) becomes[X, Z, -Y]inmap.json. Example: Blender X 2.8, Y −2.5, Z 0 →[2.8, 0, 2.5]. - Facing: in Blender's top view,
yaw 0faces down the screen (Blender −Y),1.57faces right (+X). - File → Export → glTF 2.0: Format glTF Binary (.glb), optionally Include → Limit to visible objects, Transform +Y Up (the default), Mesh → Apply Modifiers, and leave Compression (Draco) off. Textures are packed into the
.glbautomatically. - Write
map.json, put both in a folder and import the folder. Fix whatever Okaeri tells you, then zip the folder to share it.
What a model may contain: meshes, materials and embedded textures (PNG, JPEG or WebP; up to 64 textures, each at most 8192 px), up to 2 million triangles, at most 150 MB. Not supported: Draco or Meshopt compression, KTX2 textures, files that point to separate .bin or image files, and animations (ignored). Lights in the file are ignored too; the map gets the normal day and night light.
Before you share
- Use only what you made or have the right to share (see the upload rules).
- Music in a map must be yours or properly licensed (for example CC0, or CC BY with credit in the description).
- Add a
preview.jpgunder 1 MB so people can see your map on the Workshop.