game.json — file map
Every game has one game.json in the project folder. Most games set only title, window and a few session keys — everything else has a sensible default.
The whole file
Keys with { … } open below. Linked names jump to that section. Grey notes say what each key does. Under each section, Keys lists type, If omitted, allowed values, and a short note.
{
"title": "My Novel", // game name
"title_key": "game_title", // translated game name
"version": "1.0.0", // your version label
"authors": ["Your Studio"], // credits / company
"icon": "icon.png", // app icon path
"window": { … }, // base screen size; the picture scales to any window
"locale": "en", // starting language
"i18n": { … }, // languages offered in Settings
"typing": { … }, // how dialogue text appears
"sounds": { … }, // title music, voice beeps, button sounds
"transitions": { … }, // default fade between scenes and screens
"notifications": { … }, // short messages like Saved
"session": { … }, // saving, Back, start and end of the story
"layout": { … }, // where choices, name entry and characters go on screen
"cursor": { … }, // custom mouse pointer
"splash": { … }, // boot / loading look before the title on web, Android, and delivered desktop. Draw order: bg_color → background → logo → progress bar. Root keys are shared; web / android / desktop only override that platform
"android": { … }, // Android store identity for builds
"stories": [ { … } ], // several story packs in one game (early)
"extensions": [ { … } ] // advanced: your own code packs
}
Root keys
Top-level keys that are not objects.
title stringstringauthors arraylist of stringsicon pathproject pathLearn more: title · title_key · icon
window
Base screen size; the picture scales to any window.
{
"window": { // base screen size; the picture scales to any window
"width": 1280, // design width (px)
"height": 720 // design height (px)
}
}
Keys
width int1280pixels ≥ 1height int720pixels ≥ 1Learn more: window
i18n
Languages offered in Settings.
{
"i18n": { // languages offered in Settings
"locales": [ { // one entry per language
"id": "en", // language code
"label": "English", // name in Settings
"label_key": "lang_en" // translated language name
} ]
}
}
Keys
locales[].id stringen, uk). Required in each entry.locales[].label stringidlocales[].label_key stringlabellabel.Learn more: i18n
typing
How dialogue text appears.
{
"typing": { // how dialogue text appears
"cps": 30, // letters per second
"cps_fast": -1, // speed while advance held
"delay": 0.07, // seconds per letter
"delay_fast": 0.01, // fast seconds per letter
"instant": false, // always show whole lines
"speed_scale": 1.0, // overall speed multiplier
"auto_advance_default": 0.0, // auto-advance delay
"reveal": "typewriter", // how letters appear
"pending_alpha": 0.0, // untyped letter opacity
"reveal_soft": { // settings for the soft reveal
"fade_chars": 2.5 // soft fade width
},
"reveal_pop": { // settings for the pop reveal
"pop_scale": 1.2, // pop start scale
"fade_chars": 1.5 // pop fade width
},
"reveal_rise": { // settings for the rise reveal
"rise_px": 6.0, // rise distance
"fade_chars": 1.5 // rise fade width
},
"caret": { // a blinking mark where typing is
"enabled": true, // show typing caret
"blink": 0.5, // blink period
"glyph": "▋", // caret character
"color": "#ffffff", // caret colour
"offset_x": 0, // nudge right
"offset_y": 0, // nudge down
"height": "line", // caret height
"scale": 1.0, // extra size
"texture": "ui/caret.png" // caret picture
},
"beep": { // voice beep while text types
"enabled": true, // play typing beep
"sample": "typing_beep", // beep sample id
"volume": 0.5, // beep volume
"pitch_min": 0.9, // beep pitch low
"pitch_max": 1.1 // beep pitch high
},
"start_sfx": { // sound when a line starts typing
"enabled": true, // play start sound
"sample": "msg_in", // start sample id
"volume": 1.0 // start volume
},
"end_sfx": { // sound when a line finishes typing
"enabled": true, // play end sound
"sample": "msg_done", // end sample id
"volume": 1.0 // end volume
}
}
}
Keys
cps numberdelay≥ 0 · 0 = instant0 = whole line at once. Omit to use delay instead.cps_fast number-1-1 means use delay_fast.delay number0.07cps is omitted.delay_fast number0.01cps_fast is unused.instant boolfalsetrue · falsecps).speed_scale number1.0auto_advance_default number0.00 = wait for click.reveal enumtypewritertypewriter · soft · fade_line · pop · risepending_alpha number0.00–10–1). Ignored for fade_line.reveal_soft.fade_chars number2.5soft reveal.reveal_pop.pop_scale number1.2pop reveal.reveal_pop.fade_chars number1.5pop reveal.reveal_rise.rise_px number6.0rise reveal.reveal_rise.fade_chars number1.5rise reveal.caret.enabled booltruetrue · falsecaret.blink number0.50 = solid (no blink).caret.glyph string▋texture is set.caret.color color#ffffff#RRGGBBcaret.offset_x number0caret.offset_y number0caret.height string or numberlineline · pixels"line" (match line height) or a pixel number.caret.scale number1.0caret.texture pathglyph insteadproject pathglyph. Path under the project.beep.enabled booltruetrue · falsebeep.sample stringtyping_beepaudio idaudio/sfx/ played while text types.beep.volume number0.50–10–1), multiplied by master × SFX.beep.pitch_min number0.9beep.pitch_max number1.1start_sfx.enabled booltruetrue · falsestart_sfx.sample stringaudio idaudio/sfx/ played once when the line begins (not on Back/load).start_sfx.volume number1.00–10–1), multiplied by master × SFX. Not gated by Typing Sound.end_sfx.enabled booltruetrue · falseend_sfx.sample stringaudio idaudio/sfx/ played once when the whole line finishes (not each pause, not on Back/load).end_sfx.volume number1.00–10–1), multiplied by master × SFX. Not gated by Typing Sound.Learn more: typing
sounds
Title music, voice beeps, button sounds.
{
"sounds": { // title music, voice beeps, button sounds
"main_bgm": "title_theme", // title music id
"main_bgm_volume": 1.0, // title music volume
"main_bgm_fade_in": 1.5, // fade-in seconds
"main_bgm_fade_in_from": 0.0, // fade-in from volume
"main_bgm_fade_out": 1.5, // fade-out seconds
"main_bgm_fade_out_to": 0.0, // fade-out to volume
"button_click": "click", // button click sound
"button_hover": "hover", // button hover sound
"button_volume": 1.0, // button sound volume
"defaults": { // Settings values on first launch
"master": 1.0, // first-launch master
"bgm": 1.0, // first-launch music
"sfx": 1.0, // first-launch SFX
"typing_enabled": true // first-launch beep on/off
}
}
}
Keys
main_bgm stringaudio idmain_bgm_volume number1.00–10–1).main_bgm_fade_in number1.5main_bgm_fade_in_from number0.00–10–1).main_bgm_fade_out number1.5main_bgm_fade_out_to number0.00–10–1).button_click stringaudio idbutton_hover stringaudio idbutton_volume number1.00–10–1).defaults.master number1.00–10–1).defaults.bgm number1.00–10–1).defaults.sfx number1.00–10–1).defaults.typing_enabled booltruetrue · falseLearn more: sounds
transitions
Default fade between scenes and screens.
{
"transitions": { // default fade between scenes and screens
"fade_default": 0.35 // default fade seconds
}
}
Keys
fade_default number0.35Learn more: transitions
notifications
Short messages like Saved.
{
"notifications": { // short messages like Saved
"duration": 2.0, // toast hold time
"labels": { // text per message: saved · loaded · save_incompatible
"saved": { // any name you choose
"text": "Saved!" // message text
}
}
}
}
Keys
duration number2.0labels.*.text stringsaved, loaded, save_incompatible, …).Learn more: notifications
session
Saving, Back, start and end of the story.
{
"session": { // saving, Back, start and end of the story
"boot": "title", // cold start screen
"allow_back": false, // enable Back
"back_retype": false, // retype when going Back
"back_limit": 0, // Back step limit
"save_slots": 9, // manual save slots
"hud_screen": "hud", // in-game HUD id
"post_story_screen": "credits", // screen after last line
"post_story_return_to_title": true, // return to title after end
"default_story": "main" // New Game story pack
}
}
Keys
boot enumtitletitle · new_game"title" shows the title screen; "new_game" skips it and starts play.allow_back boolfalsetrue · falseback_retype boolfalsetrue · falseback_limit int00 = unlimited · ≥ 10 = no limit.save_slots int91–99hud_screen stringhudscreen id · """" turns the HUD off.post_story_screen string""screen id · ""post_story_return_to_title booltruetrue · falsedefault_story stringmainstory idLearn more: session
layout
Where choices, name entry and characters go on screen.
{
"layout": { // where choices, name entry and characters go on screen
"choices": { // choice menu defaults
"show_numbers": true, // number choices
"shuffle": false, // shuffle choice order
"gap": 10, // space between choices
"style": "choice_button", // choice button pack
"container": {}, // menu placement box
"item": {} // per-choice defaults
},
"text_input": { // name-entry defaults
"style": "input_default", // input look pack
"source": "input_extra", // extra input look
"container": {}, // field placement
"field": {}, // field chrome
"confirm": {"label": "OK"} // confirm button
},
"characters": { // places for characters on stage
"mode": "adaptive", // place layout engine
"base_texture_size": 600, // art height basis
"active_profile": "default", // active arrangement
"adaptive": { // an even row of places
"slot_count": 3, // how many places
"slot_width": 400, // place width
"slot_height": 720, // place height
"side_margin": 20, // side inset
"slot_gap": null, // gap between places
"snap": "bottom", // vertical snap
"margin": 0, // edge margin
"auto_selection_policy": "nearest_center_out", // free-place pick order
"alias_strategy": "canonical", // how places are named
"aliases": ["left", "center", "right"], // custom place names
"z_pattern": "center_front" // draw-order pattern
},
"explicit": { // your own arrangements (same as profiles below)
"active_profile": "default", // active explicit profile
"profiles": {} // named arrangements
},
"profiles": { // arrangements by name
"closeup": { // any name you choose
"aliases": {}, // extra names for places
"auto_selection_policy": "nearest_center_out", // free-place pick order
"transition": {}, // move between arrangements
"slots": [ { // the places
"id": "left", // place id
"x": 320, // x position
"y": 720, // y position
"width": 400, // place width
"height": 720, // place height
"z": 0, // draw order
"order": 0, // auto-pick order
"draw_layer": "behind_panel", // behind or above panel
"modulate": "#ffffff", // tint
"scale": 1.0 // size multiplier
} ]
}
}
}
}
}
Keys
choices.show_numbers booltruetrue · false"1.", "2.", …choices.shuffle boolfalsetrue · falsechoices.gap number-1 (use theme spacing)-1 means use theme spacing.choices.style stringpack nametext_input.style stringpack nametext_input.source stringpack nametext_input.field objecttext_input.confirm object{ "label": "OK" }).characters.mode enumadaptiveadaptive · explicit"adaptive" = even row; "explicit" = your named profiles.characters.base_texture_size number600pixels ≥ 1characters.active_profile stringdefaultcharacters.adaptive.slot_count int32–…characters.adaptive.slot_width numberbase_texture_sizecharacters.adaptive.slot_height numberslot_width, or base_texture_sizecharacters.adaptive.side_margin number20characters.adaptive.slot_gap number or nullnull — auto gap to fit the windownull · pixelsnull = auto gap to fit the window. A number sets an exact gap (negative overlaps).characters.adaptive.snap enumbottombottom · topcharacters.adaptive.margin number0characters.adaptive.auto_selection_policy stringnearest_center_outnearest_center_out · policy namecharacters.adaptive.alias_strategy enumcanonicalcanonical · indexed · customcharacters.adaptive.aliases arrayleft/center/right for 3 slots)list of namescustom.characters.adaptive.z_pattern stringcenter_frontcenter_front · pattern namecenter_front).characters.explicit.active_profile stringdefaultexplicit.profiles is active.characters.explicit.profiles objectcharacters.profiles.*.aliases objectcharacters.profiles.*.auto_selection_policy stringnearest_center_out{"kind":"instant","duration":0}characters.profiles.*.slots[].id stringcharacters.profiles.*.slots[].x numbercharacters.profiles.*.slots[].y numbercharacters.profiles.*.slots[].width numbercharacters.profiles.*.slots[].height numbercharacters.profiles.*.slots[].z number0characters.profiles.*.slots[].order number0characters.profiles.*.slots[].draw_layer enumbehind_panelbehind_panel · above_panelcharacters.profiles.*.slots[].modulate color#ffffff#RRGGBBcharacters.profiles.*.slots[].scale number1.0Learn more: layout
cursor
Custom mouse pointer.
{
"cursor": { // custom mouse pointer
"enabled": true, // use custom pointer
"default": "arrow", // starting pointer profile
"config": "cursors.json", // pointer catalog file
"touch_pointer": false, // show on touch
"idle_hide": { // hide the pointer while reading
"enabled": true, // hide while idle
"delay": 2.5, // idle seconds
"fade": 0, // fade-out seconds
"keep_visible": ["choices", "screens"] // never hide during…
}
}
}
Keys
enabled boolfalsetrue · falsedefault string"default", or the default in cursors.jsoncursors.json to start with.config stringcursors.jsonproject pathtouch_pointer boolfalsetrue · falseidle_hide.enabled boolfalse unless you enable idle-hidetrue · falseidle_hide.delay number2.50.5–30 secondsidle_hide.fade number0idle_hide.keep_visible array["choices","screens"] when idle_hide is setchoices · screens · hotspotsLearn more: cursor
splash
Boot / loading look before the title on web, Android, and delivered desktop. Draw order: bg_color → background → logo → progress bar. Root keys are shared; web / android / desktop only override that platform.
{
"splash": { // boot / loading look before the title on web, Android, and delivered desktop. Draw order: bg_color → background → logo → progress bar. Root keys are shared; web / android / desktop only override that platform
"bg_color": "#1a1a2e", // solid fill behind everything
"background": "ui/splash_bg.png", // full-bleed picture under the logo
"logo": "sprites/logo.png", // centred brand mark (prefer PNG)
"logo_max_width": 300, // max logo width
"logo_offset_x": 0, // nudge logo right (+)
"logo_offset_y": 0, // nudge logo down (+)
"boot": { // logo drawing on the web shell
"fullsize": false, // stretch logo to fill (web)
"use_filter": true // smooth logo scaling (web)
},
"progress_bar": { // loading bar (web + Android; not desktop)
"background": "#2a3060", // track (empty bar) colour
"fill": "#6a75b0", // progress fill colour
"width": "50%", // bar width (px or %)
"height": 6, // bar height
"border_radius": 3, // bar corner radius
"bottom_percent": 10 // distance from bottom (%)
},
"web": { // web-only overrides (merged over root; any splash key may live here)
"notice": { // error plate if the web pack fails
"background": "#5b3943", // error plate fill (web)
"border_color": "#9b3943", // error plate border (web)
"text_color": "#e0e0e0" // error plate text (web)
}
},
"android": {}, // Android-only overrides
"desktop": { // delivered desktop builds only
"min_seconds": 0.6 // min brand hold (desktop builds)
}
}
}
Keys
bg_color colorpanel.default.bg, else colors.background_default; no theme → kit #000000#RRGGBB · nullbackground pathbg_color onlyproject path · nulllogo pathnull also hides it)project path · nullicon is used for the OS splash icon.logo_max_width number or size300; in-engine overlays leave width unconstrainedpx · CSS size"40%".logo_offset_x number0logo_offset_y number0boot.fullsize boolfalseboot.use_filter booltruefalse = sharp / pixel art.progress_bar.background colorpanel bg from theme; no theme → kit #2a3060#RRGGBBprogress_bar.fill colorcolors.speaker_text, else choice_text; no theme → kit #6a75b0#RRGGBBprogress_bar.width number or size"50%"px · CSS sizeprogress_bar.height number or size6progress_bar.border_radius number or size3progress_bar.bottom_percent number100–100 % of screen heightweb.notice.background color#5b3943#RRGGBBweb.notice.border_color color#9b3943#RRGGBBweb.notice.text_color colornotification_text / dialogue_text; no theme → kit #e0e0e0#RRGGBBandroid objectlogo_max_width).desktop.min_seconds number0.60–… seconds0 = dismiss when ready. Not used on web/Android. Author Open does not show this overlay.Learn more: splash
android
Android store identity for builds.
{
"android": { // Android store identity for builds
"package_id": "com.studio.mygame", // Android app id
"version_code": 1 // Play versionCode
}
}
Keys
package_id stringreverse-DNS idcom.studio.game). Required for Android builds. Never change after first Play upload.version_code int11–…Learn more: android
stories
Several story packs in one game (early).
{
"stories": [ { // several story packs in one game (early)
"id": "main", // story pack id
"title": "Chapter One", // display name
"title_key": "ch1_title", // translated title
"path": "story", // story folder
"start": "start", // first scene id
"mode": "anthology", // episode or anthology
"unlock": { // when it becomes available
"always": true, // always unlocked
"flag": "ch1_done" // unlock flag
},
"clear_flag": "ch1_done" // flag set on finish
} ]
}
Keys
id stringtitle stringidtitle_key stringtitlepath stringstoryproject folderscript.txt / story.json.start stringstartstart; if that id is missing, the first moment in the story is used. Script sugar: :: start.mode enumanthologyepisode · anthology"episode" unlocks in order; "anthology" is free pick.unlock.always booltrue when unlock is omitted entirelytrue · falseunlock is omitted.unlock.flag stringflag nameclear_flag stringflag nameepisode mode).Learn more: stories
extensions
Advanced: your own code packs.
{
"extensions": [ { // advanced: your own code packs
"id": "parallax", // extension id
"entry": "extensions/parallax/main.gd", // main script path
"runtime_min": "0.1.0" // oldest player version
} ]
}
Keys
id stringlowercase_id[a-z0-9_]+). Required.entry pathproject pathruntime_min stringsemverLearn more: extensions