Skip to main content

Asset manifest

Only files actually copied into the project are recorded here. This is not a full asset-pack listing. It is a source record of files inside res://assets/.

Each entry follows this format as-is.

## <use>
Source: <asset pack name>
Creator: <author>
License: <license>
Original path: <path inside the original pack>
Project path: <res:// path>
Used: <what is actually used>
Modification: <rename / dropped frames / crop, etc.>

Icon (project · iOS app icon)​

Source: painted art generated and edited from an original character
Creator: Moonlit Beacon · OpenAI image generation
License: follows the project license
Project path: res://assets/custom/ui/app_icon_master.png
Used: Godot editor and window icon, iOS AppIcon generation source
Modification: the approved 1254×1254 of the final Moonlit Warden holding
a glowing beacon flame in both hands, scaled to 1024×1024,
with Android background and figure separated

Generation and edit sources are kept in notes/release/store-assets/source/. The approved art is app-icon-approved.png. Android splits are app-icon-night-crescent.png and app-icon-warden-moonlight.png. Face, gold crescent, and beacon flame are meant to read large. Type, weapons, and platform rounded corners are not in the source.

The docs site shows the painted launcher art: static/img/logo.png is app_icon_main.png bytes and static/img/favicon.png its exact 6x nearest decimation to 32×32, both written deterministically by tools/build_app_icon_assets.py. The archive copy apps/game/icon.svg still comes from the 108×108 fixed-shape definition. None of these are used for the app launcher or store icon.

Icon (Android launcher icon)​

Source: original
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/ui/
Used: app_icon_main.png (192, opaque legacy)
app_icon_foreground.png (432, graded-alpha adaptive foreground)
app_icon_background.png (432, opaque adaptive background)
boot_splash.png (2048×1152, opaque splash)
Modification: the new launcher icon uses the same Moonlit Warden · beacon
flame composition as app_icon_master.png. Foreground is
figure and flame only, fitted to a center-radius 132px
safe circle; farthest visible pixel is 128.55px. Background
is crescent and navy-violet night sky; main composites both
and scales to 192. The splash keeps the existing 2048×1152
production art. Size, alpha, and safe circle are contract-
enforced.
docs favicon.png · logo.png are derived from
app_icon_main.png in tools/build_app_icon_assets.py —
only the editor icon.svg still comes from the 108×108
shape definition
Where the art moved from pixels to a painting

Before 2.0.0 these files were drawn at fixed integer coordinates. The new app icon is painted art so the character's face, crescent ornament, and beacon flame still read together at 48–60px.

The three vectors stayed. Favicon and logo are used by the docs site at mixed sizes, so coming from one definition deterministically is better. That is why the docs favicon and the app icon have different looks — intentional.

Android still keeps separate foreground and background paths

An Android adaptive icon has the launcher apply a mask (circle, squircle, and so on), and only the center 66dp safe area is uncropped under any OEM mask. On the 432px production files that is diameter 264px, radius 132px. Center 72dp (radius 144px) is the actual mask viewport; the outer 18dp of the 108dp canvas is for parallax and masking.

If launcher_icons/* is empty in export_presets.cfg, Godot can use icon.svg as the foreground as-is. Then the opaque background is merged into the foreground layer and adaptive mask and parallax break. Both the Android and Android Play presets name the custom foreground and background above, and the generator's --check inspects both preset paths and the safe circle together.


Fonts (UI body / titles)​

Source: Nexon MapleStory Font
Creator: Nexon Korea Co., Ltd.
License: free use (commercial use allowed, embedding allowed, sale and modification forbidden)
Original path: Maplestory Light.ttf, Maplestory Bold.ttf
Project path: res://assets/third_party/fonts/MaplestoryLight.ttf
res://assets/third_party/fonts/MaplestoryBold.ttf
Used: Light = body, Bold = titles/buttons
Modification: none. distribution as-is (spaces stripped from filenames only)
Download: https://maplestory.nexon.com/Media/Font

The license forbids modifying or editing, so we do not touch the font files themselves. We no longer use the old synthetic bold that thickened Noto with variation_embolden — MapleStory ships Bold separately, so we layer the real Bold.

The two .tres files keep the old filenames — res://assets/third_party/fonts/Galmuri11-Multilingual.tres and res://assets/third_party/fonts/Galmuri11-Bold-Multilingual.tres. The original Galmuri .ttf files are no longer used, so they were removed from the repo. About 40 scenes reference these paths; renaming would mean fixing every reference, and all you gain is a name. Only the face they point at inside changed.

Font file list​

Every font resource the game actually loads.

The manifest checker only reads Project path: lines. Declaring the whole fonts folder in one line means new files are not missed.

Project path: res://assets/third_party/fonts/
FileWhat
MaplestoryLight.ttfbody face · (c) NEXON Korea
MaplestoryBold.ttftitle and button face · (c) NEXON Korea
NotoSansCJKsc-Regular.otfJapanese, Chinese, and player-name fallback · SIL OFL 1.1
Galmuri11-Multilingual.tresbody = MapleStory Light + CJK fallback (old name kept)
Galmuri11-Bold-Multilingual.trestitles and buttons = MapleStory Bold + CJK fallback
NotoSansCJKsc-SyntheticBold.tresCJK bold fallback (Noto synthetic bold)
GoogleSans[GRAD,opsz,wght].ttfGoogle door title face, used at weight 500 · SIL OFL 1.1
OFL.txtlicense text accompanying the Google Sans face

Why we left the pixel font​

Galmuri11 is an 11px-grid font, so it is sharp only at multiples of 11. UI used non-multiple sizes at 53 places, including 9, 10, 12, 13, 14, 15, 16, and those glyphs were all resampled and mushy. Matching every size to a multiple would mean redoing layout per panel.

The 2026-08 graphics renewal moved characters and spirits to soft cell shading, and the pixel font started to clash with the paintings too. An outline font does not care about size, so the 53 places stay and get sharp.

Import settings:

ItemValueWhy
antialiasing1 (grayscale)outline fonts are easier to read with the stairs removed
subpixel_positioning0 (disabled)half-pixel placement jitters glyphs at low resolution (808×360)

CJK fallback​

Source: Noto Sans CJK SC
Creator: Google, Adobe and Noto CJK contributors
License: SIL Open Font License 1.1
Original path: Sans/OTF/SimplifiedChinese/NotoSansCJKsc-Regular.otf
Project path: res://assets/third_party/fonts/NotoSansCJKsc-Regular.otf
Used: Japanese, simplified, and traditional glyphs Galmuri lacks, plus ladder player names
Modification: none. original SHA-256 2c76254f6fc379fddfce0a7e84fb5385bb135d3e399294f6eeb6680d0365b74b

We include one original OTF from the official notofonts/noto-cjk repo as-is. A partial subset is small when you only display fixed translations, but it cannot guarantee Korean, Chinese, and Japanese characters a player types on the ladder, so we do not use one. Bold UI shows the same original with synthetic bold from res://assets/third_party/fonts/NotoSansCJKsc-SyntheticBold.tres (Noto is OFL so synthetic bold is allowed — MapleStory uses the Bold original). res://assets/third_party/fonts/MaplestoryBold.ttf owns Korean and English bold faces; this fallback only fills Japanese and Chinese bold glyphs. The license text is kept as apps/game/docs/licenses/NOTO-OFL-1.1.txt.

MapleStory's system fallback is off, so Noto is always hit first. The Noto original draws Korean, Chinese, and Japanese UI and player names directly; OS fallback after Noto is allowed only for emoji or extra characters a player can type. Fixed UI glyph checks do not count system fallback; they only check has_char() on Galmuri and the Noto original.

The original's GSUB/GPOS hani script has JAN, ZHS, and ZHT language systems. We also confirmed that shaping 骨直返令 with HarfBuzz picks different regional glyph IDs for ja, zh-cn, and zh-tw. The game passes the TranslationServer locale as each Control's language, so even one SC original uses locl substitutions for Japanese and Taiwan forms.


Player (Ninja Green)​

Source: Ninja Adventure Asset Pack
Creator: Pixel-Boy and AAA
License: CC0
Original path: Actor/CharacterAnimated/NinjaGreen/Separate/
Project path: res://assets/third_party/ninja_adventure/actors/player/
Used: currently unused at runtime. kept to compare with pre-course versions
Modification: filenames changed to lowercase snake_case. pixels untouched

The current six heroes all use the dedicated custom sheets below. These five frames remain to compare frame specs with earlier lessons. Attack / Jump / Swim / Climb / Push / Item / Pickup in the same folder were not copied.

The frame spec is a 32x32 cell. A 16x16 character sits in the middle of the cell. The whole pack is unified at 32x32 so it matches sheets whose attack effects leave the cell.

FileImage sizehframes x vframesFrames per facing
idle.png128x1284 x 44
walk.png128x1284 x 44
roll.png128x964 x 33
hit.png128x644 x 22
dead.png32x641 x 22 (no facing)

Columns are facing, rows are animation frames. In Sprite2D.frame_coords that is frame_coords.x = facing, frame_coords.y = frame number.

Column (x)Facing
0Down
1Up
2Left
3Right

Tileset (night-forest arena)​

Source: Ninja Adventure Asset Pack
Creator: Pixel-Boy and AAA
License: CC0
Original path: Backgrounds/Tilesets/
Project path: res://assets/third_party/ninja_adventure/tilesets/
Used: tileset_nature.png, tileset_field.png, tileset_floor.png, tileset_camp.png
Modification: filenames changed to lowercase snake_case

Tile size is 16x16.

FileImage size16px gridTile countUse
tileset_nature.png384x33624 x 21504trees, brush, rocks
tileset_field.png80x2405 x 1575grass, flowers, floor decoration
tileset_floor.png352x41722 x 26572dirt/grass floor
tileset_camp.png368x14423 x 9207camp props. beacon hearth

Only tileset_floor.png is 417px tall, not a multiple of 16. The last 1px row is leftover margin, so a TileSet uses 26 rows only.

A tile boundary is not a sprite boundary. Large objects span several tiles with no empty cell between, so without looking you crop the neighboring tree. region_rect values actually used on the title screen are below. (units: px, relative to tileset_nature.png)

Nameregion_rectNotes
Round tree0,0,32,32 / 256,0,32,32 / 288,0,32,3232x32 broadleaf
Conifer32,0,32,3232x32. night-forest mainstay
Dead tree64,0,32,3232x32. cursed-forest mood
Root tree96,0,32,3232x32
Large conifer0,32,48,4848x48
Large broadleaf64,32,48,48 / 256,32,48,48 / 320,32,48,4848x48
Tall dead tree0,80,32,48 / 32,80,32,4832x48
Small tree96,128,32,3232x32
Stump0,128,32,3232x32
Rock208,128,32,32 (brown) / 256,128,32,32 (gray)32x32
Brush, grass, fern0..176,160,16,16row 10 is brush and grass
Pebbles240,144,16,16 / 288,144,16,1616x16

The beacon hearth in tileset_camp.png is 192,80,32,30. Grab 32x32 and 1px of the neighboring tile comes in at the bottom.


Combat terrain structures (Night Forest · Moonlit Field · Abandoned Camp)​

Source: original painted masters (built-in image generation, 4.0.0),
packed deterministically
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/world/terrain/
Used: nature.png, field_nature.png, camp_nature.png,
forest_floor.png, ground_field.png, ground_camp.png,
field.png, camp.png, floor.png,
forest_props.png, field_props.png, camp_props.png
Modification: tools/pack_painted_world.py packs the biome atlases into 3x
runtime sheets (--check keeps them current; source mapping in
notes/plans/4-0-0-art-build-log.md). World rects are unchanged:
Room scales regions by RoomKind.art_zoom and draws at 1/3 with
a smooth filter, so pivots, feet and collision never move.
floor.png stays with tools/build_world_assets.py

Floors are seamless painted 512×512 panels that repeat across the 1720x1000 play area; the pack check fails on any visible edge step. Scatter sheets are 1152×1008 (Room.KIND world rects times three): the shared nature.png plus one sheet per place, with every tree above sheet row 384 and rocks, logs and stumps below it so the sway shader only moves crowns. Prop sheets keep their logical coords times three — field.png 240×720, camp.png 1104×432 — including the beacon-hearth canvas at world 192,80,32,30. Each *_props sheet holds four 192×192 blocking structures with feet at world y=50; collision still comes from Room.OBSTACLE_RADII, never from the art. Forest is birch, standing stone, thorn brush, moonstone; field is wind standing-stone, cairn, silver grass, observation ring; camp is palisade, crate, cart, lantern stone. The same seed makes the same coordinates and variants, and player, spirits, beacons, and loot all compute safe positions from the same structure list.


Later terrain (Frost Pass · Mirewood Marsh · Moonlit Ruins)​

Source: original painted masters (built-in image generation, 4.0.0),
packed deterministically
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/world/terrain/
Used: frost_props.png, marsh_props.png, ruins_props.png,
ground_frost.png, ground_marsh.png, ground_ruins.png,
frost_nature.png, marsh_nature.png, ruins_nature.png
Modification: tools/pack_painted_world.py packs the biome atlases into 3x
runtime sheets (--check keeps them current; source mapping in
notes/plans/4-0-0-art-build-log.md). World rects are unchanged:
Room scales regions by RoomKind.art_zoom and draws at 1/3 with
a smooth filter, so pivots, feet and collision never move
PlaceFloorTrees and stonesThe four structures
Frost Passwindblown snow with all its streaks leaning one way, snow-capped pebbles, six ice glintsicy-blue pines with a near-white tipice-crystal cluster, scarfed snowman, snow-capped stone lantern with a warm glow, frozen log with icicles
Mirewood Marshdark bog water with moss banks, lily pads and broken ripplesolive and moss pines, bare willows, wet dark woodglowing mushroom cluster, mossy log with reeds, wisp jar on a post, mossy frog statue
Moonlit Ruinsweathered flagstones in running bond, cracked, mossed at the jointsdusk-indigo growth and violet-grey rubblebroken pillar, moon altar, crumbling arch, glowing menhir

Floors are seamless painted 512×512 panels; scatter sheets are 1152×1008 per place. The four structures of each place keep the world shape Room already reads: four 192×192 cells on one row, feet at world y=50, collision from Room.OBSTACLE_RADII. Each drawing keeps its baked contact shadow, like the structures it stands beside.


Place memories (Lantern Hollow motifs + settlement window)​

Source: original (deterministic pixel production)
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/world/places/
Used: motifs.png, window.png
Modification: tools/build_place_motifs.py draws both sheets from integer
coords and a fixed palette (--check keeps them current)
SheetSizeCells
motifs.png192x64six 32x32 terrain columns (forest, field, camp, frost, marsh, ruins), dim row then lit row
window.png64x32two 32x32 cells, dim then lit

The six motifs stand beside their beacon clearings: trail ribbons, wind chimes, the camp kettle, a signal bell, a paper boat, a signal lens. The window answers Nari's opening message on the result screen: lit on an official win, dim on an early return, hidden on defeat.


UI theme (Theme Wood)​

Source: Ninja Adventure Asset Pack
Creator: Pixel-Boy and AAA
License: CC0
Original path: Ui/Theme/Theme Wood/
Project path: res://assets/third_party/ninja_adventure/ui/
Used: panel_wood.png, nine_path_panel.png
currently unused at runtime, kept only to compare theme specs
Modification: copied flat, no folder hierarchy. ThemePreview.gif excluded

ThemePreview.gif is a preview document image and Godot cannot import it as a texture. The 12 unfinished themes under Ui/Theme/Wip/ are not copied either.

The current screen does not reference Theme Wood. The table below is a spec record for when the course-compatibility files are reused, not a claim that they are used now.

These are margin values for stretching as 9-slice. They were taken at the point where border decoration ends and pixels become fully uniform. Smaller than this and the border mush when stretched; larger is still safe.

FileSizelefttoprightbottom
nine_path_bg.png, nine_path_bg_2.png16x162222
nine_path_panel*.png16x166666
nine_path_panel_interior.png16x163322
nine_path_focus.png8x83333
button_normal/hover/disabled.png16x82222
button_pressed.png16x82321
inventory_cell.png16x163311
slider_progress*.png16x163343
tab*.png16x124460

nine_path_panel family has a thick decorative border, so margin needs to go to 6. On a 16px original the stretchable center is only 4px, so use this panel at 12x12 or larger.

button_pressed and tab families are asymmetric top to bottom. A pressed button is a picture sunk 1px; tabs are open at the bottom so bottom is 0. Lump them into symmetric values and the shape goes wrong.


Music (title screen)​

Source: Ninja Adventure Asset Pack
Creator: Pixel-Boy and AAA
License: CC0
Original path: Audio/Musics/13 - Mystical.ogg
Project path: res://assets/third_party/ninja_adventure/audio/music/title_theme.ogg
Used: title-screen BGM
Modification: renamed to title_theme.ogg. audio not re-encoded

Length 60.000s, 1.19MB, 44.1kHz stereo.

Grounds for comparing candidates:

TrackLengthSpectral centroid4kHz+last 3s / bodySizeCall
13 - Mystical60.0s531Hz0.1%1.051.16MBchosen
22 - Dream96.0s389Hz0.6%0.682.23MB96s is long for a title
30 - Ruins48.0s356Hz0.3%0.371.11MBfade-out at the end, cannot loop
37 - Dark Forest153.6s176Hz0.2%0.774.31MB4.3MB, too much for a title

Three reasons we picked 13 - Mystical.

  1. Length is exactly 60.000s. That means it was written to the bar, so the loop does not drift. 30 - Ruins drops to 37% of the body in the last 3 seconds, a fade-out you cannot loop (last 8s −35.6dB, body −25.7dB).
  2. Highs are only 0.1%. No cymbals or hi-hat, so it sounds low and warm. Spectral centroid itself is lower on 37 - Dark Forest, but that track is 4.3MB, too much for a title.
  3. The first 12 seconds sit quiet at −22.1dB then rise to the body (−15.4dB). You can use that as-is for entering the title, and the loop coming back also sounds like taking a breath.

Import default is loop=false, so we changed .import to loop=true.


Music (arena)​

Source: Ninja Adventure Asset Pack
Creator: Pixel-Boy and AAA
License: CC0
Original path: Audio/Musics/27 - Chill.ogg
Project path: res://assets/third_party/ninja_adventure/audio/music/arena_theme.ogg
Used: formerly arena BGM; combat now runs the original arena_kinetic.wav loop.
kept because course lessons reference this track
Modification: renamed to arena_theme.ogg. audio not re-encoded

Length 48.000s, 1.11MB. Measured again the same way as the title track to make the table below.

TrackLengthSpectral centroid4kHz+last 3s / bodySizeCall
27 - Chill48.0s579Hz0.4%0.721.11MBchosen
11 - Clearing69.1s570Hz0.0%0.361.32MBfade-out at the end
29 - Lament48.0s473Hz0.2%0.571.12MBfade-out hint
26 - Lost Village36.0s367Hz0.3%1.430.84MB36s makes the repeat obvious
2 - The Cave44.0s356Hz1.1%0.820.85MBsee below
16 - Melancholia40.0s682Hz1.7%0.790.93MBmost highs
37 - Dark Forest153.6s176Hz0.2%0.774.31MB4.3MB, too much
13 - Mystical60.0s531Hz0.1%1.051.16MBalready used on the title

Filter order:

  1. Throw out broken loops first. If the last 3 seconds drop below 70% of the body, splicing makes the sound die then pop back every time. 11 - Clearing (0.36) and 29 - Lament (0.57) leave here.
  2. Length and size. 36s makes the repeat obvious; 153.6s 4.3MB is too much. 26 - Lost Village and 37 - Dark Forest leave.
  3. Of the remaining three, pick the one with the smallest swings. Arena music has to sit under play, so a big wave is in the way. 1-second-window RMS:
TrackCoefficient of variationloudest / quietest
27 - Chill0.28110.6dB
16 - Melancholia0.29818.4dB
2 - The Cave0.32313.3dB
Picking by name is wrong

By name alone 11 - Clearing looks like the answer. The stage we are making is a forest clearing. Measure it and the last 3 seconds drop to 36% of the body, a fade-out. Loop it and the sound dies then pops back every time.

Do not pick on spectral centroid alone

2 - The Cave is 356Hz, lower than 27 - Chill (579Hz). Lower does sink into the background, but that track also has the most highs at 1.1% and large swings. Decide on one column and you miss that.

Same as the title track, .import was changed to loop=true. Default is loop=false.

How we measured

Both tables use the same method. Decode to 44.1kHz mono, walk the whole track with a 4096-sample Hann window at 50% overlap, compute each window's power-spectrum centroid, and energy-weighted average. Near-silent windows (under 1/10000 of max power) have a meaningless centroid, so they were dropped.

We once measured the two tables with different methods and wrote "same criterion." The same track 37 - Dark Forest came out with different values in the two tables and we were caught. We measured again.


Enemy (spirit)​

Source: Ninja Adventure Asset Pack
Creator: Pixel-Boy and AAA
License: CC0
Original path: Actor/Monster/Spirit/SpriteSheet.png
Project path: res://assets/third_party/ninja_adventure/actor/spirit.png
Used: currently unused at runtime. kept to compare pre-course versions and frame specs
Modification: filename lowercased. pixels untouched

64×64, columns = facing, rows = frames (16px cells 4×4). Same layout as the ninja sheet.

Early lessons picked Spirit over Spirit2. Spirit2 is an orange flame shape, so it collides with the beacon. In the night forest, orange is the beacon's color. Spirit is pale blue, so it matches the night tint and separates from the beacon. Current combat uses the seven original spirits below.


Enemy (three spirit kinds + guardian)​

Source: Ninja Adventure Asset Pack
Creator: Pixel-Boy and AAA
License: CC0
Original path: Actor/Monster/Spirit2/SpriteSheet.png, Actor/Monster/BlueBat/SpriteSheet.png,
Actor/Boss/GiantSpirit/Idle.png, Audio/Musics/17 - Fight.ogg
Project path: res://assets/third_party/ninja_adventure/actor/, res://assets/third_party/ninja_adventure/audio/music/guardian_theme.ogg
Used: guardian_theme.ogg was boss music; combat now runs the original
guardian_assault.wav loop. kept because course lessons reference this track.
spirit_ember.png, spirit_bat.png, guardian.png are currently unused at runtime
Modification: filenames lowercased. audio not re-encoded
FileSizeCellLayout
spirit_ember.png64×6416columns=facing 4, rows=frames 4
spirit_bat.png64×6416columns=facing 4, rows=frames 4
guardian.png250×5050columns=frames 5, no facing

Only the old guardian sheet had a different layout. No facing, so the picture is the same from every side. To absorb that spec difference, SpiritKind got separate cell · facings · frames, and the current original 64px guardians use the same data structure.

guardian_theme.ogg is 17 - Fight. Opposite of the arena track (27 - Chill): big swings and fast — the ear has to know first that this is the last stretch. loop=true in .import.


SFX (beacon ignite)​

Source: Ninja Adventure Asset Pack
Creator: Pixel-Boy and AAA
License: CC0
Original path: Audio/Sounds/Elemental/Fire2.wav
Project path: res://assets/third_party/ninja_adventure/audio/sfx/beacon_ignite.ogg
Used: the instant a beacon lights
Modification: wav -> ogg (q4). 216KB -> 20KB

Of Fire (0.89s) · Fire2 (1.25s) · Fire3 (0.65s) we picked Fire2. A beacon takes 0.45s to light (Beacon.IGNITE_SECONDS), so the sound has to last longer than that and continue while the fire settles. Fire3 is too short and ends before it lights.

The original is a 216KB wav. No reason to put that in the APK, so we changed it to ogg — 20KB. Unlike music it is a short one-shot, so lowering quality does not show.


UI (moonlit hearts · Moon Lantern kit)​

Source: original (deterministic pixel production) · relic emblems drawn as
ChatGPT grid drops
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/ui/
Used: heart.png, kit/*.png (36 files), icons/*.png (22 relic emblems)
Modification: tools/build_world_assets.py builds the 5-step moonlight heart;
tools/build_ui_kit.py generates the whole nine-patch kit, the two
beacon icons, the shared style resources under
resources/ui/, and their asset-contract entries;
the first sixteen icons/*.png are ChatGPT grid drops (batch 3 of the
abandoned 2.5D re-art pass), cut into 48x48 cells on branch
feat/guardian-presentation (closed PR #6); only these emblems
were carried over, and the cutting tools were not.
The nine skill emblems (lantern_familiar, moon_ward, comet_call,
star_magnet, thorn_bloom, second_light, moon_burst, winter_bell,
comet_trail) were drawn with ChatGPT's image generator on 2026-09-29,
the first six as one 3 x 2 grid and the last three as one row, each
shown the existing emblems for style, cut apart with
tools/cut_lineup.py (tools/skill_icons/), and fitted to 48x48 by
tools/build_skill_icons.py

3.0.0 replaced the old ink-navy, moon-silver panels and their teal-edged buttons. Those were flat rectangles with cut corners, drawn a little differently in every scene, and read as a prototype. The new kit is one set of chunky, rounded "sticker" nine-patches: a cream border on deep indigo, lantern-gold and lavender accents, and a berry for danger. Every button label in the game was authored as light text on a dark box, so buttons keep a dark face and say primary, secondary or danger with the colour of the rim.

FileSizeUse
heart.png80×16five 16px cells. empty heart (0) through full heart (4)
kit/panel.png24×24modal and large-surface frame. 8px margin
kit/chip.png · chip_gold.png16×16small readout pill and list row. 6px margin. gold marks the row to look at
kit/button_<variant>_<state>.png16×16 ×20gold · lav · berry · ghost, each in normal / hover / pressed / disabled / focus. 6px margin
kit/card_<state>.png32×32 ×5relic card frame. 12px margin
kit/bar_back.png · bar_fill_<tone>.png12×10progress track and fills (mint · gold · berry · white). white is tinted at runtime, as the boss bar is
kit/banner.png40×24title ribbon. 14px horizontal, 9px vertical margin
kit/icon_beacon_on.png · icon_beacon_off.png16×16the objective on the HUD: a lit and a cold brazier
icons/<relic>.png48×48 ×25one emblem per relic, named by relic id (sixteen at the start, nine skills that unlock as cycles pass)

Every nine-patch keeps its stretched centre one solid colour, and every stretched edge strip uniform along its axis, so a panel of any size never shows a stripe or a seam. tools/build_ui_kit.py refuses to write a sheet that breaks that rule, and it keeps each nine-patch's margin next to its art: --styles writes the shared resources/ui/**/*.tres that scenes point at, and --sync-contract rewrites the ui.kit.* entries in the asset contract.

Why textures and not rounded StyleBoxFlat: with canvas_items stretch a StyleBoxFlat is tessellated at the device resolution, so its corners come out smooth-vector next to pixel-art sprites. A StyleBoxTexture is scaled with nearest filtering and stays chunky.

The heart has 5 steps but we only use the one full frame. Empty slots lower that one frame's opacity to 0.24. Swapping two pictures makes the slot jitter a little.

The relic emblems are 48px art. The relic picker shows them at 48; the HUD strip shows them at 22 with a filtered downscale, because the project's default nearest filter would drop every other pixel into noise at that ratio.


UI (world kit · cut-bronze vector frames)​

Source: original hand-authored SVG (no generator, no pack)
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/ui/world/
Used: 34 .svg sources (22 nine-patch faces, 12 ornaments)
Modification: edited directly as vector originals; tools/build_world_ui_kit.py
validates sizes and determinism (--check) but generates no art

4.0.0 replaces the 3.x sticker kit on the production screens with one set of cut-corner bronze frames: beveled octagon silhouettes, narrow polished rims, a dark groove, deep-ink inset faces, etched moon diamonds at the bevels, and three button roads — ember (primary), steel (quiet), coral (painful). Every source keeps 4 texels per logical unit (a 36-unit frame is 144px of vector art) and every control samples it with an explicit Linear filter; the locked global Nearest never touches this kit.

Godot 4.7 StyleBoxTexture passes its margins through as destination fixed edges, so a 48px margin corner would draw 48 logical pixels wide. The kit is therefore painted by four tiny classes — WorldPanel, WorldFrame, WorldButton, WorldLabel — whose _draw maps source texels to logical units explicitly through WorldChrome.slices: 48 → 12, 32 → 8, 56 → 14, 16 → 4. Native text, icons, focus, signals and hitboxes stay native; invisible margin styles preserve the old kit's content margins, so no layout moves.

FileSizeUse
frame_panel.svg144×144modal frame. 48px src → 12u corners
frame_chip.svg · frame_chip_lit.svg80×80 ×2pills and list rows. 32px → 8u. lit marks owned/found
frame_card.svg · card_focus.svg176×176 ×2relic/hero card + focus halo. 56px → 14u
btn_<ember·steel·coral>_<state>.svg80×80 ×15three roads × normal/hover/pressed/disabled/focus. 32px → 8u
bar_back.svg · bar_fill.svg48×48 ×2progress slot + neutral-white fill the HUD tints. 16px → 4u
bead_moon.svg48×48divider bead and title flanks
seal_win.svg · seal_lose.svg256×256 ×2journey stamps: unbroken gold / broken ash + fallen ember
crest_<motif>.svg80×80 ×6header/tab glyphs: moon · beacon · relic · book · coin · gate
dash_base.svg · dash_fill.svg208 · 104dash dial ring + crescent bolt
dais.svg384×96hero stage ellipse

Stretched edges carry only smooth axial gradients and full-width bands, so a panel of any size stretches them without a seam; all ornament sits inside the fixed corners. test_run_choice_panel proves the 48 → 12 / 32 → 8 mapping and that labels, focus and hitboxes are unaffected.


Objectives · projectiles (moonlight gate · Moon Disc · enemy moonshot)​

Source: original (deterministic pixel production)
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/world/gate/
Project path: res://assets/custom/items/projectiles/
Used: moonlight gate that opens when every beacon is lit, player Moon Disc, enemy moonshot
Modification: tools/build_gate_projectile_assets.py generates with a limited
palette and integer coordinates while preserving existing
runtime cell size and frame consumption

The gate is a 34×52 single image: teal threshold and vermilion runes between ink-navy stone pillars. Moon Disc is a 128×32 sheet of four 32×32 frames; each rotation changes crescent direction and star shards. Enemy moonshot is a 40×40 single image with a magenta eclipse core and vermilion thorns so it separates immediately from the cyan-white player attack.

The hand-generated gate picture from earlier lessons is not referenced at runtime, but is kept for comparison.

Source: past original derivative
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/derived/objectives/moon_gate.png
Used: currently unused at runtime, kept for course compatibility
Modification: 34×52 arch and vertical light pillar

FX (moonlight slash)​

Source: derived (generated)
License: n/a (we made it)
Project path: res://assets/derived/fx/moon_slash.png
Used: crescent mark that appears when swinging the moonlight blade
Modification: 128x32 (four 32x32 cells). tools/build_slash.py bakes it

Make only one frame facing right (+x) and rotate it in the game. Draw all four facings and you have four places to fix.

The fan angle must be the same value as ATTACK_ARC in player.gd. If visible range and actual hit range differ you get "I clearly hit it and it did not die." So we do not draw by hand. Code bakes it — change the angle and the picture follows.


UI (filling ring)​

Source: derived (generated)
License: n/a (we made it)
Project path: res://assets/derived/ui/charge_ring.png
Used: ring that fills at your feet when you stand by a beacon
Modification: 40x40. ellipse ring squashed to 0.45 vertically

Top-down, so a foot ring has to be flat. Draw a true circle and it looks stood in front of the character, not lying on the floor.


UI (virtual stick)​

Source: derived (generated)
License: n/a (we made it)
Project path: res://assets/derived/ui/
Used: stick_base.png, stick_knob.png
Modification: white circles with numpy alpha only. color is given in the scene with modulate
FileSizeShape
stick_base.png48×48thin ring of diameter 46 (3px border)
stick_knob.png22×22slightly filled circle + border

Draw white only and give color in the scene. Then a later dash stick is the same picture with a different color. No reason to make two files.


Player (six heroes)​

Source: original painted masters (built-in image generation, 4.0.0),
packed deterministically
Creator: Moonlit Beacon
License: follows the project license
Original path: notes/workflow/muse/art/4-0-0/<hero>-turnaround.png,
notes/workflow/muse/art/4-0-0/gait/<hero>-sidewalk-v2.png
(side-walk donors, kept)
Project path: res://assets/custom/actors/heroes/warden/, res://assets/custom/actors/heroes/dancer/, res://assets/custom/actors/heroes/keeper/, res://assets/custom/actors/heroes/knight/, res://assets/custom/actors/heroes/eclipse/, res://assets/custom/actors/heroes/sage/
Used: each hero's walk.png, idle.png, portrait.png
Modification: tools/pack_painted_world.py fits each turnaround's four true
facings into 144×192 cells as graded-alpha RGBA (--check keeps
them current; source mapping in
notes/plans/4-0-0-art-build-log.md). Walk side columns instead
come from the registered gait donors: the left column holds
the donor's contact / recover / opposite-contact / recover
stride at one scale with the torso registered, and the right
column mirrors it exactly (crop and registration table in
notes/workflow/muse/gait-131-implementation.md). Idle,
portraits and down/up walk columns are byte-identical to the
turnaround bake. Hero.visual_scale (0.255) renders the legacy
world body with a smooth filter
HeroDesign
Moonlit Wardenviolet hood with a crescent pin, a lit beacon candle held in front
Shadow Dancerpink bob with a mint ribbon, crescent blades at both hands
Beacon Keepergreen hooded cloak, a glowing lantern held in front
Silver Moon Knightsilver helmet with a crescent crest, white cape, sword
Eclipse Mageblack hood with a red rim, a red orb held in front
Constellation Sageteal star-hood, gold staff and two floating orbs
FileSizeLayoutPlayback
walk.png576×768144×192 cells, columns=down·up·left·right, rows=4 frames12fps
idle.png576×768144×192 cells, columns=4 facings, rows=4 breath frames4fps
portrait.png96×96single full-body portraitstatic

All three files use graded alpha and put the feet on the bottom of the cell. A hero is about 36 world px tall, drawn as a shaded chibi with a big head and a bold silhouette, and every facing keeps that height and foot origin, so turning does not change the size. The walk is four source poses per facing; the idle breathes feet-planted about the soles. Down, up and idle facings are true turnaround art; the walk sides are the donor stride on the left with its exact mirror on the right, so the same legs alternate on both sides.

A 0.16s casting cue plays after each shot, so a hero needs no separate attack sheet.

Shrine buy/select cards and the five individual-hero IAP cards press each Hero's 48×48 icon, the 72×72 preview_crop of the idle sheet scaled smooth, to open a full-body detail even before purchase. The detail shows the hero's 96×96 portrait 1:1, and looking does not change buy, unlock, or equip state. All six hero resources and the Player safety fallback use these custom sheets.


Player (six held weapons)​

Source: built-in image generation (one transparent 2×3 weapon atlas,
1536×1024, right-facing, generous alpha padding), separated
and packed deterministically
Creator: Moonlit Beacon
License: follows the project license
Original path: notes/workflow/muse/art/4-0-0/painted-weapons.png (master, kept)
Project path: res://assets/custom/items/weapons/
Used: warden.png, dancer.png, keeper.png, knight.png, eclipse.png, sage.png
Modification: tools/pack_painted_weapons.py separates the atlas by alpha
components (the grid is approximate: two blades cross the
middle column and the reaper curl crosses the row line),
floors dust alpha, scrubs matte RGB, crops each core exactly,
downscales to four texels per logical pixel, and expands a 4px
transparent margin. No repainting: the tool never draws.

Author note: these are the original shaded equipment for the 4.0.0 painted heroes — the bright primitive bars WeaponRig used to draw are gone, but every attack number, muzzle seat, and timing is untouched. Each sheet holds four texels per logical pixel and draws at quarter scale through per-item Linear filtering, so the paint stays smooth at real device output. Guns align by barrel axis so each painted tip lands exactly on its muzzle seat; melee weapons align by grip with the blade following the aim. The dancer sheet holds both fang daggers straddling one hand point. Calibration (tips, grips, axis rows) is measured from the master alpha by the pack tool and frozen in WeaponRig logical constants, guarded by tests/test_painted_weapons.gd.

Atlas cellRuntime fileSizePaint
row 1 left, Warden swordwarden.png68×20curved moon-silver blade, blue guard, navy grip
row 1 right, Dancer fangsdancer.png60×36matched pair, parallel, violet guard accents
row 2 left, Keeper pistolkeeper.png60×36brass lantern pistol, bell barrel, glass chamber
row 2 right, Knight cannonknight.png60×28stout ring cannon, circular aperture, blue accent
row 3 left, Eclipse reapereclipse.png68×32haft with silver crescent curling around the tip
row 3 right, Sage riflesage.png88×28slim needle rifle, star sight, teal stock

Enemies · bosses (Moonlit spirit bestiary)​

Source: original painted masters (built-in image generation, 4.0.0),
packed deterministically
Creator: Moonlit Beacon
License: follows the project license
Original path: notes/workflow/muse/art/4-0-0/spirit-turnarounds.png,
notes/workflow/muse/art/4-0-0/guardian-states.png
Project path: res://assets/custom/actors/spirits/, res://assets/custom/actors/guardians/
Used: 4-facing float motion for 7 normal enemies
idle, wind-up, charge, recover motion for all 12 guardians
Modification: tools/pack_painted_world.py packs the turnaround atlases into
3x runtime sheets as graded-alpha RGBA (--check keeps them
current; source mapping in notes/plans/4-0-0-art-build-log.md).
Every facing is true turnaround art. SpiritKind.visual_scale
(1/3) renders the legacy world body with a smooth filter
Normal enemyDesignBehavior cue
Wispcloud puff with a curl on topdefault chase
Driftersleepy leaf moth with folded wingshigh-inertia float
Emberround flame spiritfast chase
Castermushroom-cap mage with a lantern staffkeep-distance fire
Weaverjellyfish trailing glowing threadsorbit around the player
Stalkershy cat-bat with big earsstraight charge
Swarmfluffy dandelion-puff pupweak and fast cluster

Normal-enemy sheets are all 576×576 with 144×144 cells in four columns down·up·left·right and four frame rows. They are not recolors: each creature has its own silhouette, and asset regression checks that all 7 alpha silhouettes and all 7 full-image hashes differ. Every column is a true turnaround view; the four frames breathe feet-planted with a small bob.

GuardianIdleState sheetsDesign
Forestforest.png 6 frameswind-up, charge, recover 4 frames eachmossy golem with leaf wings and a glowing core; the thorn form is cracked with red veins and horned
Fieldfield.png 6 framescross wind-up, radial wind-up, recover 4 frames eachblue moth sprite with big wings holding a glowing orb; the storm form is purple with lightning wings
Campcamp.png 6 frameswind-up, recover 4 frames eachstone furnace golem with a lit hatch; the siege form is riveted iron with cannons on its flanks
Frost (owl)frost.png 6 frameswind-up, charge, recover 4 frames eachsnowy owl with crystal crown and big blue wings holding an ice gem; the Rimecrown form has antlers of ice and icicle feathers
Marsh (toad)marsh.png 6 frameswind-up, charge, recover 4 frames eachround toad with a lily-pad hat holding a glowing orb; the Glowcap form wears a crown of glowing mushrooms and cattails
Ruins (sentinel)ruins.png 6 frameswind-up, recover 4 frames eachstone cat with a gold crescent on its brow and floating stones round it; the Halo form has a ring of stones and gold plating

Guardian cells are 192×192. Idle is 1152×192 (6 frames), state sheets 768×192 (4 frames), horizontal layout with no facing. Variant forms keep the base silhouette with restrained channel grades and shifted breathing so they stay distinct. Every SpiritKind state slot is filled with a custom sheet so mid-states do not fall back to the old free boss picture.


Player VFX (dedicated moonlight slash)​

Source: original (deterministic pixel production)
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/items/fx/moon_slash.png
Used: default slash and Full Moon front/back blades in player.tscn
Modification: tools/build_moon_slash_asset.py generates four 48×48 frames.
3,640 runtime states combining center 13px, hand-height
pivot (0, -6), pixel four-corners, and upgrade scale
independently were checked.
default visible tip 28.023/34px, upgrade-combo min radius
slack 0.323px, fan min slack 0.768°, fitting inside the
actual hit

The sheet is 192×48, four frames across; a right-facing picture is rotated at runtime. A small thick cyan-white S-ribbon curves the other way into a crescent trail and fades as shard afterglow. Range, fan, and damage can upgrade separately without crossing the screen, and alpha uses at most 5 steps including transparent.

The existing res://assets/derived/fx/moon_slash.png remains for course compatibility only. Moon Arrow was also replaced with a dedicated assets/custom/items/projectiles/moon_arrow.png, so player slash, ranged Moon Disc, and enemy moonshot use different textures and silhouettes.


Combat loot (Moonfire core)​

Source: original (deterministic pixel production)
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/items/pickups/power_gem.png
Used: spirit-kill missile upgrade, pop-out and reclaim core on hit
Modification: tools/build_missile_core_asset.py generates four 24×24
frames directly with fixed integer coordinates and a
10-color palette

The sheet is 96×24, four frames across. A small ember inside a cyan-white octagon crystal and four clockwise vanes are separated so it reads as a weapon part, not moon-embers or currency. Idle cores last 12 seconds; cores popped by a hit last 9.


Player (ninja compatibility sheet)​

Source: Ninja Adventure Asset Pack
Creator: Pixel-Boy and AAA
License: CC0
Original path: Actor/Character/NinjaBlue/SeparateAnim/Walk.png, Idle.png
Project path: res://assets/third_party/ninja_adventure/actor/
Used: ninja_walk.png, ninja_idle.png
currently unused at runtime. kept for course compatibility and frame-spec comparison
Modification: filenames lowercased. pixels untouched
FileSizeLayoutUse
ninja_walk.png64x64columns = facing, rows = frames (16px cells 4x4)walk 4 facings × 4 frames
ninja_idle.png64x16columns = facing (16px cells 4x1)idle 4 facings × 1 frame

Column order is down · up · left · right. Confirmed by enlarging the sprite sheet — column 0 shows the face, column 1 the back of the head, columns 2 and 3 left and right profiles.

Idle is only one frame

Idle.png has one frame per facing. Leave it and you get a fully frozen picture. AnimationPlayer lifts the sprite 1px and drops it so it looks like breathing (1.8s period). Solved without making more frames.

Source: derived (generated)
License: n/a (we made it)
Project path: res://assets/derived/player/shadow.png
Used: shadow at the player's feet
Modification: 24x10 soft ellipse. numpy drew alpha only

The shadow has light_mask = 0. Light hitting a shadow brightens it, so beside a beacon the shadow thins. A shadow is not something that receives light. It is something that blocks light.


FX (custom beacon flame / smoke / moonlight shafts)​

Source: original (deterministic pixel production)
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/world/beacon/
Project path: res://assets/custom/world/atmosphere/
Used: flame.png, spark.png, smoke.png, raylight.png
Modification: tools/build_world_assets.py preserves existing frame and
region specs and generates new RGBA sheets with a limited
palette and fixed integer coordinates

The first three are frame sheets laid out horizontally. CanvasItemMaterial particles_animation plays them once over a particle lifetime.

FileDesignSizeFramesFrame sizeUse
flame.pngvermilion wick and moon-white core96x12812x12beacon flame body
spark.pngmoon-white cross sparks70x8710x8sparks, forest-spirit light
smoke.pngblue-gray stacked clouds192x32632x32beacon smoke column
raylight.pngcyan-white shafts of different thickness216x102-72x102 x 3moonlight falling between canopies

flame.png is drawn to shrink as frames advance. Lay that on particle lifetime and you get a flame that rises then dies. raylight.png is not an animation; three shafts of different thickness, so we crop one at a time with region_rect.

Existing Ninja Adventure FX files are kept for course compatibility and license records but are not referenced at runtime now.

Source: Ninja Adventure Asset Pack
Creator: Pixel-Boy and AAA
License: CC0
Project path: res://assets/third_party/ninja_adventure/fx/
Used: currently unused at runtime, kept for course compatibility and frame comparison

Custom textures (title · beacon background)​

Source: original (deterministic pixel production)
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/world/terrain/forest_floor.png
res://assets/custom/world/beacon/clearing.png
res://assets/custom/world/atmosphere/night_mist.png
Used: forest_floor.png, clearing.png, night_mist.png
Modification: tools/build_world_assets.py generates with a fixed palette and integer coordinates
FileSizeSource tileHow it was made
forest_floor.png256x256nonelow-contrast moon-teal clusters on a tileable opaque floor
clearing.png288x160noneoval clearing with moonstone rim and beacon-vermilion traces
night_mist.png1024x420none (procedural)low-frequency noise dithered to 4 alpha steps. tiles on a 1024px horizontal period

The forest floor hides repeat seams with opaque low-contrast clusters; the clearing keeps combat readability with a binary-alpha moonstone rim. Only mist uses large four-step-alpha cloud masses so it does not cover actors and projectiles while drifting slowly.

The floor is one Sprite2D with region_rect larger than the screen and texture_repeat = 2. You do not need a node per tile, and you do not need a TileSet resource.

night_mist.png tiles horizontally, so shifting position by exactly 1024px hides the loop point. We drift it that way over 48 seconds.

Existing CC0 derivatives also stay in the repo to reproduce the course- era screen, but are not referenced at runtime.

Source: past derivative of Ninja Adventure Asset Pack tiles
Creator: Pixel-Boy and AAA (original), Moonlit Beacon (layout)
License: CC0
Project path: res://assets/derived/title/
Used: currently unused at runtime, kept for course compatibility

UI SFX​

Source: Kenney UI Audio
Creator: Kenney
License: CC0
Original path: Audio/click1.ogg, Audio/rollover2.ogg
Project path: res://assets/third_party/kenney/ui_audio/
Used: ui_confirm.ogg = button confirm, ui_focus.ogg = focus move
Modification: rename only. audio as-is

We picked two of 51. Length and pitch were spread so the two sounds do not overlap.

FileOriginalLengthFundamentalRole
ui_confirm.oggclick1.ogg0.091s88Hzlow and thick, so it reads as "decide"
ui_focus.oggrollover2.ogg0.054s1396Hzshort and high, so fast scrolling does not mush

rollover1.ogg is 0.224s, long enough that fast menu scrolling overlaps the sound. So we excluded it.


Original combat music loops​

Source: original (deterministic synthesis)
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/audio/music/
Used: arena_kinetic/ember/watch.wav = three night-motif arena loops;
guardian_assault/hunt/storm.wav = three faster guardian loops
Modification: n/a. apps/game/tools/build_combat_audio.py bakes them

Same rule as the dialogue blip below: bake, do not fetch. All six share one A-minor lantern motif over driving drums and bass, so the guardian escalation sounds like the same night turning dangerous. The arena draws one of three tracks per region and each guardian entrance draws one of three faster tracks; defeating the guardian returns to a fresh arena draw, and a shuffled no-repeat bag tours each pool without restarting a track mid-fight. Musically exact whole bars with short raised-cosine edge fades, so each loop starts and ends at exact zero and the boundary cannot click.

FileLengthPeakRole
arena_kinetic.wav14.55s0.620kinetic arena ground, 132 BPM × 8, motif lead
arena_ember.wav15.24s0.620shuffling triplets, 126 BPM × 8, motif in thirds
arena_watch.wav13.91s0.620half-time watch, 138 BPM × 8, eighth-note arps
guardian_assault.wav17.14s0.620same motif doubling as the loop heats, 140 BPM × 10
guardian_hunt.wav12.63s0.620four-on-the-floor pursuit, 152 BPM × 8, motif stabs
guardian_storm.wav15.00s0.620double-kick storm, 160 BPM × 10, racing 8ths

Dialogue-window letter sound​

Source: original (deterministic synthesis)
Creator: Moonlit Beacon
License: follows the project license
Project path: res://assets/custom/audio/sfx/
Used: dialogue_blip.wav = the sound of letters printing in a visual-novel dialogue window;
weapon_sword/twin/rifle/shotgun/cannon/scythe.wav = the six heroes' attack voices;
impact_hit.wav = crisp contact knock; kill_pop.wav = kill tick;
level_up.wav = growth surge; core_pickup.wav = core chime;
overcharge_win.wav = overcharge triumph
Modification: n/a. apps/game/tools/build_dialogue_sfx.py bakes the blip,
apps/game/tools/build_combat_audio.py bakes the combat cues

We do not download it. We bake it. Pictures are all made with build_*_assets.py; this sound follows the same rule, so the license- notice set does not grow. 40ms · 1,808 bytes.

ValueWhy
40msletter speed is 42 per second. longer than this overlaps the next sound and mushes
1180Hz + 2nd harmonica pure tone is a grating "beep." add a harmonic and it is closer to a wooden xylophone
2ms attacka sudden start clicks

dialogue_scene.gd plays once every three letters and wobbles pitch ±14% each play. The same sound on every character sounds like a machine talking.


Title (moon gate entry background)​

Source: original title master approved for the 4.0.0 entry surface
Creator: Moonlit Beacon
License: follows the project license
Original path: notes/workflow/muse/art/4-0-0/moon-gate-title.png
Project path: res://assets/gate/moon_gate_title.png
Used: full-screen background of the new moon gate entry surface
(GateEntry); the shaded navy/teal/amber moon gate sits right,
the traveler lower left, control space stays quiet left
Modification: byte copy of the approved master, no repaint and no resize;
runtime framing crops with TextureRect cover at 808x360,
wide-phone and tablet viewports

Author note: the runtime file is the approved master copied byte for byte (1672x941 RGB, about 2.5MB). Nothing here is generated or repainted, so a later art refresh replaces one file and this row. The entry scene draws it with a per-item linear filter while the project keeps its global nearest filter, and all light, mist and dust above it are small procedural layers so the painting stays the single art source on this screen.


UI (moon gate entry frames · forecourt lineup — drawn from code)​

Source: original (vector geometry drawn at runtime, no image files)
Creator: Moonlit Beacon
License: follows the project license
Project path: res://scripts/ui/gate_frame_style.gd
res://scripts/ui/gate_beacon_mark.gd
res://scripts/ui/gate_hero_forecourt.gd
Used: every button face, dialog card, ID field, progress bar and
Hall row on the moon gate entry/account/Hall/conflict/exit/
loading surfaces; the crescent-and-beacon title mark; the
six-hero forecourt lineup behind the interaction layer
Modification: none — these scripts are the editable source. No PNG, SVG or
.tres was added for this look. The lineup reuses the shipped
144x192 hero idle sheets and the six painted weapon sheets
already recorded under the Player rows; no new hero,
weapon or bitmap art was introduced.

Author note: the entry screen is the smooth-shaded surface — painting, hero sheets and MapleStory type all render linear — so its frames are drawn as smooth vector chamfers at runtime instead of chunky nine-patch pixels. That keeps one look per surface: the pixel UI kit stays the in-game voice, these frames stay the gate voice. gate_frame_style.gd also pins the entry minimum-size rule (content margins only): any extra floor clamps the 420px Hall card wider and off-center, and the layout suite guards that width.

Round 082 hardened both pieces. The lineup grounds on measured opaque bounds (alpha >= 32): every down/left idle cell carries 110px of paint tall (cell y 82..191, feet at the cell bottom), 57-82px wide depending on hero and facing. Those numbers live as constants in gate_hero_forecourt.gd and the state suite re-measures them from the source sheets, so an art refresh fails loudly instead of drifting the footing. The gate-mouth keep-clear rect is read off the committed master (painting pixels 1140,220-1450,500) and mapped through aspect-cover framing per viewport. The accent language is fixed: gold for the one gate-entry action, mint for provider/guest passage, coral for destructive choices, steel blue for navigation.


UI (official Google sign-in tiles)​

Source: Google Identity branding kit (gradient Super G tiles)
Creator: Google LLC
License: Google brand use as permitted by the sign-in branding
guidelines; the mark itself is unmodified
Original path: signin-assets.zip from
https://developers.google.com/identity/branding-guidelines
(kit updated 2026-07-07)
Project path: res://assets/third_party/signin/
Used: the Google door's mark on the moon gate entry chooser;
the Android tile on Android/desktop, the iOS tile on iOS
Modification: none to the bytes. SHA-256 android
2bc2ae8e4c67de66d74bf1deed12cd8f22981270266a487576b671b0b4df361c
ios
085692d68716db0e621635128407cb0f0a8db058b1dbfebe3f57a2c9d625d145
(donor record notes/workflow/muse/donors/official-signin-110/
donor-sha256.json). Runtime draws an AtlasTexture crop of
the measured 79x80 glyph alone (android x40-118 y40-119,
iOS x48-126 y48-127); every colorful pixel is kept and no
stroke, corner, or baked padding pixel reaches the button.

Author note: both tiles hold the same 79x80 gradient G with platform padding baked in (40px Android, 48px iOS) on a white rounded tile with the 1px #747775 stroke. An earlier ring-only crop kept the tiles' rounded-corner stroke pixels and is not used: the button draws its own spec face (white fill, inside 1px stroke) with the glyph alone at an explicit 20px logical height and exact spec edge/gap padding, so no tile edge can double-draw or leave corner dirt. Import keeps the pixels lossless with mipmaps on, minified with a mipmapped linear filter. The reference's older four-solid-color G was measured and not shipped.


UI (official Apple sign-in artwork)​

Source: Apple Design Resources, Logo Sign in with Apple
Creator: Apple Inc.
License: Apple Design Resources license EA1677, approved by the
user before extraction; artwork unmodified
Original path: Logo-Sign-in-with-Apple.dmg from
https://developer.apple.com/design/resources/
Project path: res://assets/third_party/signin/apple-left-white-medium.svg
Used: the Apple door's mark on the moon gate entry chooser,
drawn whole at button height on the black brand face
Modification: none to the bytes. SHA-256
f43d1ed5be59bcffdf4c20b5e29f8de041858678f549515377d0ba4f5ebd115e
(donor record notes/workflow/muse/donors/official-signin-110/
donor-sha256.json). Import rasterizes the 31x44 file at
4x with mipmaps for the 3x device scale; the file's own
padding is preserved and the glyph is never cropped out.

Author note: the shipped file is the padded medium white-on-black artwork (31x44, glyph about 15x19), so its apparent size balances the Google G at the shared 44px door height. The license RTF stays with the donor record and is not shipped at runtime. The square logo-only variant was kept as reference only and not shipped.


Fonts (Google Sans for the Google door)​

Source: Google Sans official font repo (ofl/googlesans)
Creator: Google LLC
License: SIL Open Font License 1.1
Original path: GoogleSans[GRAD,opsz,wght].ttf + OFL.txt from
https://github.com/google/fonts/tree/main/ofl/googlesans
Project path: res://assets/third_party/fonts/GoogleSans[GRAD,opsz,wght].ttf
res://assets/third_party/fonts/OFL.txt
Used: Google door titles through a FontVariation at weight 500
with the bundled Noto Sans CJK fallback for localized
glyphs; no other surface uses this face
Modification: none to the bytes. SHA-256 font
d0a87d835a944b8b40d0e82a5651bb59ab97b936a2aeed5946eb57e7b2a3a90a
license
2b75ef20f13d83a7514aee452c4782c20cdc9ff2dee17600f44d37a06d4fb958
(donor record notes/workflow/muse/donors/official-signin-110/
donor-sha256.json)

Author note: the variable face keeps its original bracketed filename so the shipped bytes map to the donor record with no renaming step.