9.5 KiB
Adding real art
Nothing in the code needs to change to swap in real art. src/util/assetManifest.js
lists every image the game expects, with an exact path. PreloadScene tries to
load each one; if the file doesn't exist (or fails to load), it falls back to a
synthesized colored placeholder shape instead. Drop a real PNG at the exact path
below, refresh the page, and it's used automatically.
Where files go
All paths are relative to the project root (/home/brianfertig/git/monsterplex/).
The folders already exist and are currently empty.
| key | path | size used in-game | shape | notes |
|---|---|---|---|---|
bus_chassis |
assets/sprites/bus_chassis.png |
340 x 128 | rectangle | see "Bus" below |
bus_wheel |
assets/sprites/bus_wheel.png |
104 x 104 | circle | one image, used for both wheels |
kid_idle |
assets/sprites/kid_idle.png |
56 x 56 | circle | passenger while aboard the bus |
kid_ejected |
assets/sprites/kid_ejected.png |
56 x 56 | circle | passenger after being thrown off |
bg_far |
assets/backgrounds/bg_far.png |
tiled, 512 x 1080 native | - | slowest-scrolling parallax layer (sky/distant) |
bg_mid |
assets/backgrounds/bg_mid.png |
tiled, 512 x 1080 native | - | mid-speed parallax layer |
bg_near |
assets/backgrounds/bg_near.png |
tiled, 512 x 1080 native | - | fastest-scrolling parallax layer (closest) |
icon_kid |
assets/ui/icon_kid.png |
48 x 48 | - | small HUD "kids aboard" icon, top-left |
favicon |
assets/favicon.png |
32 x 32 | - | browser tab icon - see caveat below |
"Size used in-game" is the size the game actually displays the image at
(setDisplaySize), not a requirement on the source file's resolution - see
"Resolution" below.
These numbers are the game's current 1920x1080 resolution (WORLD_SCALE = 2
in src/config.js) - if that changes again, every size in this table changes
with it (same ratios, just re-derive from that one constant).
Bus
bus_chassis.pngandbus_wheel.png, transparent background (PNG alpha).- The bus always faces right (nose/front toward positive x - the direction it drives at level start) and there's no left/right flip when reversing, so draw the chassis facing right.
- The chassis's rectangle is the physics hitbox (with rounded corners baked in by the physics engine, not the art). Keep the bus's silhouette roughly filling a 340x128 box so the visual matches where it actually collides.
bus_wheel.pngis used for both wheels (front and rear) - same image, no separate left/right variant needed. It's a real physics body, so it visually spins as the bus drives; a plain hubcap/circle reads better at speed than fine detail.- If you want a bus with different proportions (longer, taller, etc.) than
340x128, tell me the size you want art at - that number is also the physics
body size in
src/config.js(BUS.chassisWidth/chassisHeight), so it needs a matching code change, not just a differently-shaped image.
Kids
kid_idle.png(aboard) andkid_ejected.png(mid-air after being thrown off) - two separate images, swapped automatically when a kid is ejected.- Physics shape is a circle, but the image itself renders as a full square at 56x56 - draw the character centered in a square canvas with transparent padding around them rather than filling every corner, or they'll look like they're poking out past their own collision circle.
kid_ejectedis a good place to show some "yikes" energy (arms out, startled face, etc.) since it only appears for the ~2 seconds after a kid gets thrown clear.
Parallax backgrounds
bg_far/bg_mid/bg_nearare rendered as horizontally tiling strips (TileSprite), not single stretched images - whatever you supply repeats sideways as the camera scrolls.- Make the left and right edges match so the seam is invisible when it tiles (or design something patternable, like scattered clouds/hills on a transparent background).
- far/mid/near are layered back-to-front and scroll at different speeds for depth (far moves slowest, near moves fastest) - a plain sky for far, hills or treeline silhouettes for mid, and closer foreground detail for near works well.
- Native resolution isn't locked to 512x1080 the way the bus/kid sprites are - a wider or taller source image just changes how often the tile repeats, so use whatever gives a clean seamless loop.
Level select map
The level select screen is a map per campaign: a themed background with a road ribbon snaking between level nodes, a finish flag past the last node, and a banner plate behind the campaign title. There is one of each of these per campaign, plus the shared node/flag/plate sprites.
Important convention for these sprites: each is displayed at a fixed
display size with origin (0.5, 0.5) at its map position, so keep the
subject centered in its file or it will show up shifted. The node badges
and the flag ship as tight 512x512 images (the badge/flag IS the file);
map_campaign_tag is a full-screen 1920x1080 frame with the plate centered
near the top. Sizes below are the display sizes the game uses (design
units); the source file's own resolution only affects crispness.
| key | path | subject size (design units) | notes |
|---|---|---|---|
campaign01_bg |
assets/backgrounds/campaign01_bg.png |
full frame 960x540 | Campaign 1 "Sunny Suburbs" background |
campaign02_bg |
assets/backgrounds/campaign02_bg.png |
full frame 960x540 | Campaign 2 "Dusk Junction" background |
map_node |
assets/ui/map_node.png |
~58x58 badge (512x512 file) | completed level node |
map_node_current |
assets/ui/map_node_current.png |
~71x71 badge (512x512 file) | the next level to play ("start here" node) |
map_node_locked |
assets/ui/map_node_locked.png |
~58x58 badge (512x512 file) | locked level node |
map_finish |
assets/ui/map_finish.png |
~345x345 (512x512 file) | flag past the last node |
map_campaign_tag |
assets/ui/map_campaign_tag.png |
~1440x300 plate centered near top | banner behind the campaign title text (title is drawn on top at y≈82/540) |
Per-campaign notes:
campaign0X_bg.png- full 960x540 (or 2x) scene, no transparency needed. The top ~150 units are behind the title plate, so keep that area fairly quiet. Node positions are auto-placed in a 2-lane serpentine that sits in the band y ≈ 268-412 (design units) across the full map width (x ≈ 90-870) - both lanes - so keep that horizontal strip fairly open and readable, and leave the bottom ~60 units clear for the< Menu/ hint chrome. The exact lane y-values live insrc/data/levels/positioning.js(LANE_TOP/LANE_BOTTOM) and per-campaign overrides insrc/data/levels/index.js(positions) - check where your nodes will land before you paint.- Node states share one silhouette (same size/placement) in three moods:
map_node(cleared),map_node_current(the one to play next - this one gets a gentle idle pulse),map_node_locked(greyed out, e.g. a padlock). All three ship as 512x512 badge images with no padding frame; their display size and hit area are driven byNODE_ART_FRAMES+BADGE_FILE_FRACper-key insrc/util/mapArt.js, so a different frame size there is fine as long as those tables are updated. If you want the badge to be a different display size than ~58-71 units, adjustBADGE_FRAC_OF_FRAME/ the per-stateBADGE_FILE_FRACentries insrc/util/mapArt.js(the click area follows the art, not these knobs). - Cleared nodes show the player's best score under the badge, as a small
gold pill (the game's
SCORE_PILL_STYLEinsrc/scenes/LevelSelectScene.js) with the number rolling up from 0 on entrance. The pill is drawn by the game, not part of the badge art - themap_nodebadge should stay a plain cleared marker (no digits baked in). The score itself comes frombestScoreinsrc/util/progress.js(localStorage), recorded by the tally scene after each run. map_finish.png- the flag sits just past the last node, so a base/mound that grounds it looks best. Currently ships as a tight 512x512 image (flag ink is ~60% of the width, full height); the scene displays it at 0.18x the game screen, so keep the flag roughly centered in a square frame if you re-export it. The auto-layout circuit ends at the bottom-right, so the flag lands in the bottom-right corner past the final node (with custompositionsthe nudge flips to stay on-screen when the last node is at an edge).map_campaign_tag.png- a plate/banner with empty center space; the game writes"<name> x/y cleared"on top of it in dark ink (#1a1f29), so the middle should be a light, uncluttered fill.
Favicon
favicon.pngis the one asset without a placeholder fallback for its actual purpose - the browser tab icon comes from a plain<link>tag inindex.html, not from Phaser's loader, so until a real file exists atassets/favicon.pngthe browser just shows its default icon (nothing broken, just nothing shown).
Resolution
Supply art at the "size used in-game" from the table above, or a clean multiple of it (2x/3x) for a crisper look on high-DPI screens - everything gets scaled to the table's size regardless of the source file's actual pixel dimensions, so it won't come in stretched or huge, but a very different aspect ratio than the target box will get squashed/stretched to fit.
Testing
Just refresh the browser tab after dropping files into assets/ - no build
step, no server restart needed (unless the static server itself isn't
running yet, in which case see README.md).