World Explorer: design principles
Rules the game keeps everywhere. A new feature follows them, and a change that breaks one changes this file first.
What a shot hits, a ship crashes into
A thing in space is either solid or background, and you can tell which at a glance.
- Solid: asteroids and ore rocks, Dustfall's cliffs and their rubble (arcade), drifting debris and wrecks, built outposts and platforms, the convoy's freighter, every hull (yours and the raiders'). Shots stop on them, and ships collide with them: a hit pushes the ship off, and above cruising speed it costs hull.
- Background: scenery rocks, wrecks and satellites drawn dim (8%) behind the world. Shots and ships pass through them, and they never look like the solid things.
- Everyone follows it: raiders collide with the same things you do, and with each other, and steer round what lies ahead. No two hulls overlap.
- A cliff is a rock of
ore_nodes(typecliff), drawn in full colour with a dark outline and a cast shadow, larger than any rock, so it can never pass for the dim scenery; its fall zone is drawn on the ground, not as a body. - Where it lives:
src/js/bodies.js(what is solid, the separation),resolve_solid_oreinsrc/js/flight.js(your ship against rocks),block_hostile_ore(enemy shots on rocks),src/js/evasion.js(the Evasive thrusters module, which steers round all of it).
What a ship can crash into, a shot can damage; what can be destroyed shows its health
The author's rule, in three parts: what a shot hits, a ship can crash into; what a ship can crash into, a shot can damage; whatever can be destroyed shows a health bar (its armour or energy, and how much is left as it is hit).
- The first part is the section above.
- The bar shows what is left of the thing's hull; a shield shows as a ring round it.
- Today, where the code keeps it and where it does not:
- Raiders: solid, damaged by shots, a bar over the hull once hit, a
shield ring while they have shields. A flagship has the bar at the top
of the screen instead (
#bossbar). The Leviathan of the lure mission is the one hull guns cannot hurt (damage_enemyinsrc/js/operations.js); only a black hole's core takes it. - Ore rocks: solid in both modes. In the arcade your shots break them
(
damage_ore) and a broken rock drops salvage. In the campaign your shots stop on them and do no damage: rocks are the drones' work, and a drone takes units from a reserve (ore_chipinsrc/js/deposits.js), not from the rock's hp. In Dustfall and Obsidian (world rulesolid) raiders' shots take hp off a rock (block_hostile_oreinsrc/js/flight.js). The bar (ore_hp_barinsrc/js/surfaces.js) shows the rock's hp once it is below full, so in the campaign it shows only after raider fire; what a rock still holds shows as the field's label (field_reserves_text). - Dustfall's cliffs (arcade): solid; your shots, the pulse and your
missiles wear one down to its crack (a quarter left: primed), and the
crack gives only to the guns aimed at it, so a cliff falls when you mean
it to. Raiders' shots stop on a cliff and do not wear it, unlike
Dustfall's ore rocks. A bar over it once hit, orange once primed.
Broken, it rumbles 0.6 s and falls along its zone; its rubble are ore
rocks with their own bars (
src/js/arcade_cliffs.js). - Drifting asteroids and wrecks: they hurt your ship when you hit them,
and your shots break them (
drifting_debris_hitinsrc/js/expedition.js), but they have no bar. Raiders and raiders' shots pass through them: they are not among the solid bodies ofsrc/js/bodies.js. - Outposts and defense platforms (campaign): solid, a bar always shown. Raiders' shots and rams damage them; your own shots pass through.
- The convoy's freighter (campaign): solid, 300 hull, shown as a label ("FREIGHTER · n hull"), not a bar. Raiders damage it; your shots pass through.
- The transport line's ship (campaign): a bar always shown; raiders damage it; it is not solid, and your shots pass through.
- The survey robot (campaign): a bar always shown; raiders damage it.
- A ring race's rivals (campaign and the Races mode): solid (they
bounce off rocks and bump you and each other), raiders' shots and rams
damage them, a bar once hit; your shots pass through them, and they never
shoot (
src/js/race.js).
- Raiders: solid, damaged by shots, a bar over the hull once hit, a
shield ring while they have shields. A flagship has the bar at the top
of the screen instead (
- Open question: should ore rocks be shot apart in the campaign as they are in the arcade, and if a rock both holds ore and can break, does it show two bars (hull and reserve) or one? Not decided yet.
- Where it lives:
src/js/update.js(your shots against raiders, rocks and drifting debris),src/js/surfaces.js(raiders' and rocks' bars),src/js/structures.js,src/js/transports.js,src/js/survey.js(their bars and damage),update_escortinsrc/js/operations.js.
Every action is a button that shows its key
A key is a shortcut, never the only way. Whatever a key does, a button on the screen does too, and the button shows the key.
- The HUD has a button for each flight key: R dock or jump, J map, Q E F supplies, H drones, K build, G formation, B brake, Space pulse, Shift turbo.
- A button made in code takes its key as a chip:
ui_button({label, key})insrc/js/ui.js, e.g. Collect reward [C] on a station contract. - The pause screen lists every key with what it does.
- Today the inventory (Tab), pause (P, Esc) and zoom (+, −) buttons name their key only in the tooltip, and M (sound on or off) has no button that shows it.
- Where it lives:
src/html/hud.html(the buttons),src/js/controls.js(the keys),src/html/pause.html(the key list).
A world's map is the same every visit
Where things are in a world is fixed, so a pilot can learn it.
- The map of a world is drawn from a generator seeded by the world's threat
level (
wave): scenery, black holes, mining fields and rocks land in the same places every time. Drifting debris starts from a seed of its own per world. - What the player changes is kept: rocks mined and caches left are saved per
world in
campaign.maps(store_worldinsrc/js/campaign.js). - Where it lives:
base_generate_mapinsrc/js/map.js,generate_drifting_debrisinsrc/js/expedition.js.
Effects have their own dice
An explosion never changes what the game decides.
- Explosions take their randomness from a generator of their own
(
explosion_randominsrc/js/explosions.js), so a bigger or a smaller effect leaves drops, spawns and raider types as they were. - The arcade finale's stars and fireworks come from a seeded generator too,
so they are the same every time (
finale_randominsrc/js/arcade_finale.js). - Today the particle bursts (
burstinsrc/js/combat.js) and the screen shake (renderinsrc/js/render.js) still draw fromMath.random. - Where it lives:
src/js/explosions.js.
An area effect travels
A wave you release touches each thing when its front arrives, never before, so the eye sees the wave do the work.
- The pulse (Space), the EMP (E) and stasis (F) are rings that run out from the ship to their reach. A raider, rock or shot is hit, cleared or slowed as the front reaches it, and a raider it kills blows up a moment after.
- Each keeps its own numbers and colour: the pulse is weaker with range and chains through its kills, the EMP deals the same all the way out, stasis only slows.
- A missile's blast travels too: its wave hurts each hull as the front
reaches it, less toward the rim, and sets off the missiles it reaches
(
missile_waves_updateinsrc/js/missiles.js). Today the arcade's dying-ship blasts (arcade_blast_from_kill) still land at once. - A cliff's fall (arcade Dustfall) runs down its zone from the cliff's foot at
2 km/s: each raider, you and each piece of rubble are hit or land as the
front gets there (
cliff_fall_updateinsrc/js/arcade_cliffs.js). - Where it lives:
src/js/pulse.js(pulse_fire,emp_fire,stasis_fire,stasis_scale),use_supplyinsrc/js/upgrades.js.
The arcade is tuned on its own; the campaign stays as it is
The arcade gets the extra feel (shake, slow motion, chain blasts) and its own difficulty; none of that changes the campaign's rules.
- Every arcade number is read through
arcade_mode()and applies only whilearcade.active; the campaign never readsarcade_modes. - An arcade run starts from a checkpoint made up on the spot and puts the
campaign's checkpoint back after (
arcade_start); an arcade save is a slot of its own (arcade_snapshot,src/js/saves.js). - In the arcade a fight's numbers follow the run's step (
arcade_level, the worlds flown before), not the world's index: the worlds come in an order the player chooses (src/js/arcade_route.js), and a world keeps only what makes it itself (map, rules, its raiders' gun, flagship's attacks). Outside the arcadearcade_level()is the world's index, and a card's factors (arcade_card_k) are all 1. - Arcade-only effects: a kill shakes the screen by the size of what died
(
arcade_kill_shake), a flagship's death plays at 30% speed for a moment (arcade_time_step), and a ship that explodes hurts what is close to it (arcade_blast_from_kill). - A world of the arcade plays its own way, not only by its numbers: Eclipse
is the gravity world. Its hole bends every shot's way, yours and the
raiders', but a shot fired along a line shown first (a flagship's lanes, a
marksman's aim) keeps to it, so a tell never lies; a close pass slings your
ship past cruise for a moment; raiders steer out of its pull, but one
closing on you forgets it and is pulled harder, and one the core takes is
your kill (
src/js/arcade_gravity.js). The campaign's holes pull as before. - The pulse's chain rings are the pulse's own, in both modes; their score
(×(1 + 0.5 × depth)) is arcade-only, and like your shots the pulse and its
chains break ore rocks only in the arcade (
src/js/pulse.js). - Where it lives:
src/js/arcade.js.
A station is a shelter
In the campaign, the space round a station is safe, so a pilot always has a place to fall back to.
- Within
station_shelter(the station's half size plus 400 m): no radiation, no new patrols while you are inside, no mining fields, and raiders are pushed out. A defense platform stands at least 200 m beyond it. - Docking repairs the hull, restores the shield, refills the turbo, clears
the radiation dose and saves the flight (
dock_stationinsrc/js/station.js). - The arcade has no shelter. Its depot raises a shield while raiders are near
and opens only once they are cleared (
src/js/depot_shield.js). - Where it lives:
station_shelterinsrc/js/worlds.js; its uses insrc/js/navigation.js,src/js/expedition.js,src/js/mining.js,src/js/structures.js.
One scene, one camera
The game is one view of one world.
render()insrc/js/render.jsdraws the world once a frame on one canvas (#arena) through one camera and one zoom; there is no second camera or split view.- Ships are drawn from one set of drawings,
src/sprites/3d/. - The map (J) and the minimap are charts of the same objects, not another scene.
- Where it lives:
src/js/render.js,src/js/sprites.js.
The middle of the screen is for flying
The ship and the way ahead are in the middle of the screen; the HUD keeps to its edges and says each thing once, in the least room and for the least time.
- News (
show_toast) is one line under the readouts, one message at a time: a burst waits its turn, danger first; the same title again joins the one shown (×2, amounts added); a newer word on the same subject replaces an older one. A message stays long enough to read, 1.6 to 3.5 s, shorter while others wait. Danger is red, its dot blinks. - Banners (a world's arrival, a goal's step) come under the news line, smaller and for 3 s; the news waits while one shows, all but danger.
- The mission card is two lines: the step, then its distance, arrow and a word on it, with the step's key ([T], [R]) as a button. ⓘ (I) unfolds the world, the step's kind, the buttons, the contract and goal tracks.
- Nothing says twice what the HUD already shows: no toast for a wave's start or end (the card says it), no threat chip (the card's distance turns red with the raiders near), no EMP or Repair on the card (the quick bar has them).
- The minimap is small and see-through, fainter still while a raider flies under it; Hide folds it. Near a ring race it shows the course.
- A race's standings are a small board under the minimap (in its place when it is hidden, under the one-line card on a narrow window): place, name and rings, your row lit; the news line leaves it room.
- Text in the world (
labelinsrc/js/combat.js) does not pile up: the same text close by starts again, amounts of the same thing add up (+6 and +4 make +10), another text stands a line above. - No setting for any of it: one HUD, as clear as it can be.
- Where it lives:
src/js/hud.js,src/css/hud-ui.css, the layout section ofsrc/css/ui-kit.css;bin/layout-checkholds the crowded screen (crowded: an arrival in a fight with a burst of news) to it.