Big Typing Quiz Game Bible Play

Big Typing Quiz: the Game Bible

Fixed Home tiers and learning new mechanics#

Tier is the only solo difficulty control. Old Cadet/Pilot/Ace/Nightmare damage and salvage modifiers no longer affect fixed missions. Earned checkpoints remain available across those retired settings.

Home has 19 fixed tiers across ten five-wave groups. Tier 1 builds from 10 to 20 WPM; Tier 19 builds from 125 to 130 WPM. At group progress p = clamp((group - 1) / 9, 0, 1), set low = 10 + 10p and high = 125 + 5p. Tier t asks for low * (high / low)^((t - 1) / 18), rounded once to whole WPM. This makes each tier the same percentage harder than the previous tier within a group: about 15.1% at the opening and 11.0% at the finale, before rounding. For example, Tier 2 is 12 to 22 WPM and Tier 10 is 35 to 51 WPM. Regular waves alternate the group budget and a 15% boost; bosses use the group budget. A higher-pressure warning appears on the preceding wave summary and on the opening briefing when starting directly on a boosted wave. Event formations do not multiply it. Home ends after wave 50. The final boss review leads to the run summary; no wave 51 checkpoint is unlocked. Older saves beyond wave 50 return to the last earned valid group without removing rewards or history. Other sectors retain their existing tier scales. Home's displayed pace and tier suggestions use this fixed scale. The boss attack clocks are calibrated in actual starter-equipment fights at 95% accuracy, without charges or consumables, so the block's survival pressure follows the scale as well as its workload. Equipment and more accurate play can help a slower player survive.

home-boss-pace.js contains the 19 by 10 attack-period table. Generate it with node tools/check-home-pace-browser.cjs --calibrate: this drives the production boss mechanics, corrects seeded mistakes, measures resulting WPM, and finds the survivable attack period on two seeded readings at each tier and boss group. The shipped lookup is independent of the player's loadout and pace; it does not inspect WPM during a fight or force a loss below a number. The existing telegraphed volleys, hull damage and core phases enforce the pressure. A 4% timing allowance covers reading variants and errors carried from earlier waves. Ordinary waves allow some missed enemies; the boss is the block's pace checkpoint. Home mini-bosses delay their opening volley until 1.25 times the priced reading duration. A starter player at the tier pace can finish them without a mandatory hull tax that would make the following boss require faster typing. Recalibrate after changing starter stats, boss text costs or combat mechanics.

A fresh Service Repeater has zero charge generation and zero capacity. The first Home boss (wave 5) guarantees a Capacitor Repeater, equips it immediately, and offers a paused, skippable charge playback. It earns 0.2 charge per correct character and holds 20. Normal Space types; Shift+Space explicitly discharges, even at a pending separator. Each fresh press can clear another word while charge lasts. Repeats from holding the key do not fire. Red errors block firing.

Target switching is available from the first wave. Another enemy's first letter can switch targets between words, before or after Space. Switching away waives a pending separator without typing credit or charge; returning always uses the current word's first letter. Starting a word commits aim again. A separate safe practice introduces both switching windows, available through the ↔ control and Ability Guide.

No nuke opportunities appear in the first five waves. Nuke slots and explanations remain hidden until discovery. Its first pickup introduces the shared-charge blast and F5 control on a paused card. Charge training does not introduce nukes.

Teaching rule: every new or item-granted mechanic needs a skippable first-use explanation, playback or safe practice, plus permanent review from the Armory Ability Guide or an equally discoverable place. Review never spends resources. The guide replays Charge and Target Relay and explains discovered powers and equipped items.

Equipment comparisons: A compact owned-item grid opens from fitted gear in the Hangar or pre-flight. Hover or keyboard focus previews an item; click or Enter keeps it selected. The selected item and currently equipped item appear side by side, including on phones, with aligned rows in a fixed order for that slot. All relevant numerical effects stay visible, including unchanged values and signed green gains/red losses. Values are build totals for the active mount, including upgrades, fitted gear and gambits. Descriptions live below the numbers. Only the separate Equip/Move/Unequip or Buy & equip button changes gear.

The complete design and reference document for Big Typing Quiz. It is two things at once, on purpose: the specification a developer works from, and the manual a player reads when they want to know what a Railgun actually does. Every number in it is the number the code uses.

About this document#

Who it is for. A developer changing a system, a designer arguing with a balance decision, and a player who has just been told that splash rolls off plating and wants to know by how much. Those three readers want the same facts at different depths, so each system is described in the same order: what it is for, how it behaves, then the exact parameters in a table.

Where the truth lives. The code is the truth, this document describes it. Every table here was read out of the modules under js/, and the derived figures (XP per minute, level costs, characters to kill a word) were computed by running those modules rather than by hand. When the two disagree the code wins and this file is stale: fix it in the same commit that moved the number.

How to read a parameter table. Anything named as a multiplier is applied to a base value rather than replacing it. Anything in milliseconds is a real clock. Positions and speeds in the arcade are FRACTIONS of the playfield and playfield heights per second, never pixels, because what matters is how long a threat takes to arrive and not how big the screen is.

A note on units. One word is five characters, everywhere, without exception (CHARS_PER_WORD in js/util.js). Words per minute means correct characters divided by five, over the minutes actually spent typing. Every WPM in this document is net WPM unless it says otherwise.

Conventions. File paths point at the module that owns a rule. A number in code style is a constant you can find by that name. Sections are anchored, so any heading in this document can be linked to directly.

The other documents. ART_DIRECTION.md covers the art: how it was made, what each family has to look like, and the compositing contracts this document only summarises. WEAPON_IDENTITY.md carries the projectile identity contract in full, including the archetype recipes no shipped weapon uses yet. CLAUDE.md is the guide for AI editors and carries the same reasoning in a different order. FILE_MANIFEST.md describes every file in the repo. FIREBASE_SETUP.md has the Firestore rules. This file is the one that carries the numbers.

The arcade world: Beacon Nine#

Home Sector is a bright orbital shipyard under attack by the Scrap Armada. Pilot its defense ship through fifty waves, break machine formations and bring back enough salvage to make the hangar crew smile. The setting fits the painted metal hulls, cyan docking lights, engine trails and dark planetary horizon.

Ten operations: Launch Ring, Chrome Swarm, Heavy Metal, Ghost Signal, Solar Run, Salvage Alley, Ion Weather, Night Shift, Redline Orbit and Last Light. Each covers five waves and ends with a command ship. Flight Control gives each wave a short dispatch; later groups continue the orbital sweep rather than replaying earlier events. Clearing wave 50 completes Home Sector.

Where to reread: Operations shows the current flight briefing and earned enemy intel. Pause repeats the current dispatch. Arrival cards announce command ships; victory cards show their scans. Wave summaries preview the next operation beat. These are flavor surfaces: their text does not add modifiers or change rewards.

Enemy reading formats: short ships carry words or coherent phrases, and larger ships carry whole sentences bounded to eight words. The independent reading library supplies varied typing practice. Capitalization, punctuation, keyboard eligibility and seeded selection retain their existing rules.

The arcade world guide below documents the setting and its writing rules.

1. The brief#

A complete beginner and a 130 words per minute typist have to open the same page and both find it worth playing.

That sentence is the whole design problem, and almost every decision in this document is an answer to it. It is harder than it sounds, because the two audiences want opposite things:

Sites that pick one audience are common and they are all the same site. Sites that try to serve both usually do it with a difficulty menu, which fails because a difficulty menu asks a beginner to self-assess before they have any idea what the scale is.

Big Typing Quiz answers it four ways at once, and the four are deliberately different shapes so that no single player can be at the bottom of all of them:

AxisWhat it measuresShapeWho it favours
Level XPReal target WPM and accuracy in Starfall; measured run pace in trainingPer-target work times pace times squared accuracyFaster, accurate typists
MasteryImprovement against your own pastRatio, relative to your own baselineEverybody equally
ScrapEnemies defeated and objectives cleared in StarfallActivity value, with salvage bonuses; no WPM or accuracy factorEvery player who clears combat work
GearCombat survival and salvageReduces failure and can improve scrap, never Starfall performance score or XPAnyone who plays

And two mechanisms remove the need to self-assess at all:

1.1 The rules the design will not break#

These are load bearing. Everything else is negotiable.

  1. Nothing is ever gated. Every game, drill, curriculum node, Academy group, sector and vendor is reachable in the first minute. Progression is shown as a score, a star count or a badge, never as a lock. A sector states a recommended power and lets you in regardless.
  2. Gear buys access, skill buys rate. Gear reduces failure so you survive deeper. It never multiplies XP.
  3. Targeting assistance preserves score. Mistake forgiveness, combo protection and earlier reveals in the targeting slot carry no score penalty. Other slots retain their individual tradeoffs.
  4. Accuracy is paid in time and performance rewards. A word costs its own letters to erase and typing banks charge toward it, so being accurate literally means typing fewer characters. Ordinary targets keep the correct prefix after a mistake, while marked Rewind targets have a capped reset rule. You take the wrong letter back out and the turret holds its shot for a fraction of a second, and the field keeps descending through both.
  5. Only complete runs count. A run walked out of is discarded everywhere except the per-key model, which keeps the keystrokes because they are still real evidence about your fingers.
  6. One funnel. finishRun() in js/run.js is the only thing in the codebase that grants XP, scrap, cores, badges, loot, bests, History entries or leaderboard posts. A game reports what happened; the funnel decides what it was worth.
  7. Difficulty is priced in WPM and accuracy. The selected numbered tier fixes the typing workload. A separate survival estimate uses the fitted loadout, actual task words and declared accuracy assumptions. Bosses repeat attacks rather than imposing a global WPM deadline.
  8. Mistake consequences are visible and bounded. Ordinary targets cost correction time, accuracy, heat and combo retention. Clearly marked Rewind and Brood targets can reset or add enemies at most twice. They never remove already banked score or create paid repeat work. Correction stays available.

2. How to play#

This section is the manual. Everything in it is expanded later.

2.1 The first ten minutes#

  1. The Flight Check offers itself once. One minute of ordinary words. It measures you, grants the level you have already earned, seeds the per-key model with real evidence, and tells the Academy which key groups you have already proved. Declining costs nothing and it never nags again, but the offer stands on the Arcade card and in Progress until you take it.
  2. Open the Arcade and play Starfall Keys. Craft descend carrying one to three words each. Type a word and it is destroyed. Your typing also banks CHARGE, and SPACE spends that to delete a word you have not typed. Mistype and the wrong letter lands in the box over your base until you backspace it out. Every fifth wave a stationary boss broadcasts a paragraph and exchanges fire with your ship. Your hull and equipment determine how many hits you survive.
  3. Spend scrap in the Armory. Scrap accrues from time played, so you will have some. Buy a hull or a coolant first: staying alive longer is what makes everything else pay.
  4. If the keyboard is not yet under your fingers, open Training. The Academy teaches two keys at a time and never scores you on speed.

2.2 Controls#

WhereKeyWhat it does
Arcadeany printable characterLocks the lowest threat whose CURRENT word starts with it, then types into that lock. Typing the word OUT destroys it
ArcadeSpaceDISCHARGES the charge that typing banked: deletes the locked word without typing the rest of it, or the word closest to your base if nothing is locked
ArcadeSpace between the words of a held phraseTYPES THE SEPARATOR. A stack or a line craft is written on screen with spaces between its words and is typed the same way, so the space is a character it ASKS FOR: it counts, it banks charge, it keeps the combo, and it never fires. Skipping it and going straight to the next word is a mistype like any other
ArcadeBackspaceTakes back a mistyped character (nothing else is accepted until it is gone), then the letters you got right, and then the target itself: back it all the way out and you are free to commit to anything on the field
ArcadeTabSwaps to the other weapon hardpoint (only if one is fitted)
ArcadeCtrl + SpaceSpends an emergency flare on whatever is closest to your base
ArcadeEscapePauses during a word, a pending separator, or an error. After Space, it can release the empty target preference
ArcadeEnter or Escape while pausedResumes, through a 3-2-1 countdown
ArcadeF8Opens the run's event timeline, live or paused
Arcadeany key during a wave cardSkips the breather and starts the next wave
Boss transmissionBackspaceRemoves pending errors before editing accepted text. The input line also has a touch Backspace button
Sprint and drillsBackspaceCorrects a character. It restores the text but never refunds the accuracy
Anywherethe tab barSix sections: Arcade, Training, Versus, Progress, Leaderboards, Armory

On a phone the keyboard is raised by a single hidden input (#kbCatch) that the app never rebuilds, so it stays up for the whole run.

2.3 Reading the arcade HUD#

ReadoutMeaning
HullBase health. At zero the run ends and is scored
HeatRises on every mistype, bleeds off over time. Full means the turret jams for just over a second
ComboConsecutive correct characters. Drives combat feedback and streak-sensitive weapons, never a score multiplier
WaveThe wave counter. Every fifth is a boss (every fourth in the Rift)
ScorePerformance points from defeated targets: unique typed work, measured target WPM and squared accuracy
ChargeThe capacitor, in LETTERS, beside what the thing you are aimed at would cost to skip. Green means space will delete it
ScrapCredited combat salvage from kills and cleared objectives, including applicable salvage bonuses
FlaresEmergency flares left, if your module carries any
GunsBoth hardpoints, with the live one lit. A dashed edge or a ring mark means an area discharge
The box over your baseWhat you have typed of the current word, anything mistyped (in red), and what the meter still owes. Its edge and its typed letters wear the equipped weapon's colours
Threat, top centreThe REQUIRED WPM: the pace the field is currently demanding of you. Four pips under it say which severity band that is, and the screen edges carry the same band without being looked at. Section 7.14
Boss attack intentionThe next volley, seconds until launch, damage per hit after armour, and escort launches. Boss fights have no required-WPM deadline
The strip along the bottom edgeThe capacitor again, as pure extent: it fills outward from the centre as charge banks and brightens when a discharge can pay

Everything from the threat pill down is designed to be read WITHOUT looking at it, because during a wave the eyes belong to the word. Section 7.15 is the whole argument.

2.4 A dozen things worth knowing early#

  1. Typing the first letter of a word locks the LOWEST threat carrying it. The lowest one is the one about to land, and no two craft on screen ever offer the same first letter, so that keystroke is never a gamble.
  2. TYPING CHARGES, SPACE FIRES. A word costs its own letters, so the meter has to reach the word before space will take it. Surplus charge carries over. The one place space does not fire is between the words of a craft carrying a PHRASE: that space is part of the phrase, so it is typed like the letters around it. round laugh track is eighteen keystrokes.
  3. A craft can carry one to eight words. The count is its size, its damage and the number of times you have to engage it, and the lock is released after each word so you are free to answer something more urgent.
  4. A wrong key never deducts anything. It lands in the box over your base in red, has to be backspaced out, costs heat and the combo, and stalls the turret for a fraction of a second.
  5. Power-ups are typed like anything else, then fired on. They are the short words in capitals.
  6. A boss alternates prose with generators, guard formations and precision weakpoints that require typing. Its announced volleys exchange damage with your hull; it never descends.
  7. Being accurate with a precision weapon fills the meter half again as fast, so a clean stretch hands you words you never have to type. The letters a discharge saves you are a SNAP SHOT. The kill earns combat salvage; only original characters you actually typed earn performance score and XP.
  8. Fumbling with a precision weapon banks almost nothing, so the same stretch buys you no free words at all. The word you were typing still dies. Nothing is ever deducted.
  9. Gambits are opt-in handicaps that pay a salvage multiplier. They are how you make the game hard again after your gear has made it easy.
  10. Cores only ever drop from bosses and mini-bosses. Nothing else in the game produces one.
  11. The Academy never measures speed. Certifying the whole keyboard is the largest single XP award in the game.
  12. Contracts, the streak and the Salvager's shelf all roll over at your local midnight.
  13. The number at the top of the screen is the WPM the field is asking for right now. You do not have to read it: the edges glow harder as it climbs, and a word with a line struck through it is one that is going to land whatever you do, so spend your typing elsewhere.
  14. Escape with nothing locked pauses, and pausing costs you nothing at all. The clock the run is scored on stops with it.

3. The loops#

A game that only has one reward cycle only holds one kind of player. Five run at once, and each is a different length:

LoopLengthWhat closes it
The keystrokeUnder a secondA correct character: a rising pitch, a beam, damage
The waveAbout a minuteThreats cleared, a wave card, a score milestone, an event banner
The encounterMinutesA boss killed and salvage falling out of it
The sessionTwenty minutes to an hourLevels, certifications, badges, a vendor's stock
The long gameWeeksThe collection, the diploma, the boards, ascension

The middle loop is the one most typing sites do not have at all, and it is why the loot system exists: XP is continuous and predictable, scrap accrues by the second, and a badge fires once. None of those produce the moment where something falls out of a boss and you do not yet know what it is.

4. Progression#

4.1 Axis 1: level XP, absolute skill#

Current Starfall runs use performance-v1. Every enemy and boss objective has its own engagement clock. The first observed consecutive-key interval is also credited to the opening keystroke, avoiding inflated WPM on very short words; it is measured from actual input, never seeded from the baseline. It includes mistakes, correction and thinking while selected. Switching away closes that interval; returning resumes the same sample. A wrong acquisition key and its correction time follow into the next target rather than disappearing from reward accuracy. Pauses and protected reading do not advance it. Measured WPM is real correct characters divided by five, per active minute. It does not use paragraph-equivalent effort, the chosen tier, an entered baseline or a gear multiplier.

Each defeated enemy leaves a 2.2-second receipt at its position: large WPM and accuracy figures above an enlarged amber scrap reward. Nearby receipts spread apart and stay inside the field. A perfect result adds a small star. Untyped charge, splash or nuke kills show an unmeasured dash, never invented speed or 100% accuracy; short speed samples are identified. Reduced motion keeps receipts stationary. The latest result also remains in the existing HUD summary.

Target selection uses four small corner brackets without glow. Affordable charge gently changes their tint. A short underline shows remaining words; neither indicator surrounds the whole ship. Area previews share these quiet corners rather than stacking a second targeting outline.

Rewards count each original requested position only once:

rawWpm        = correctCharacters * 12000 / activeMilliseconds
rewardWpm     = min(260, uniqueCorrectCharacters * 12000 / max(1000, activeMilliseconds))
rewardAccuracy = uniqueCorrectCharacters / (uniqueCorrectCharacters + wrongAttempts)
targetXP      = uniqueCorrectCharacters / 5 * rewardWpm / 40 * rewardAccuracy^2
targetScore   = targetXP * 10

Only a defeated eligible target pays. Zero measured time pays zero. A charge, splash or nuke pays score and XP only for the original positions the player actually typed before the kill. Reset text, retyped prefixes and mistake-born echoes cannot create new paid work. Raw WPM/accuracy remain available as honest feedback even where the one-second reward floor or 260 WPM reward cap applies. The ledger keeps fractional amounts until the run total is rounded for banking. Optional event clean-clear bonuses now help charge acquisition rather than performance score: the listed 2x or 3x clean bonus affects charge only.

For 100 unique characters at perfect accuracy, a 40 WPM target pays 200 points and 20 XP; an 80 WPM target pays 400 points and 40 XP. At 95% reward accuracy, the latter pays 361 points and 36.1 XP before total rounding. Difficulty, challenge tier, equipment, combo, the Zone, FOCUS, events and ascension add no Starfall score or XP multiplier. There are no flat first-run, first-clear, personal-best, boss, day-streak, comeback or badge XP payments on these runs. Badges, contracts and checkpoints can still record the achievement.

Training, sprints and legacy run formats retain the following pace model. XP counts correct characters produced under pressure, which is what typing skill is. The pace half of a run's XP is:

words   = correct characters / 5
paceXp  = words * paceFactor(netWpm) * accFactor(acc) * difficultyMultiplier

with

paceFactor(w) = clamp((w / 40) ^ 1.35, 0.35, 8)
accFactor(a)  = clamp((a / 100) ^ 2, 0, 1)

Accuracy is squared, so speed bought with sloppiness does not pay: 95% keeps 90% of the XP, 85% keeps 72%, 70% keeps 49%.

The reference pace is 40 WPM, where paceFactor is exactly 1. Because a faster typist also produces more words in the same minute, the compounded rate is steeper than the exponent alone suggests:

Net WPMpaceFactorXP per minute at 100%at 95%
150.350 (floor)55
200.39287
250.5301312
300.6782018
401.0004036
501.3526861
601.72910494
702.129149134
802.549204184
902.988269243
1003.445345311
1103.918431389
1204.407529477
1304.910638576
1405.426760686
1606.4981040938

Both clamps matter. The floor of 0.35 keeps a genuine beginner earning something rather than nothing, which would read as broken. The ceiling of 8 stops a freak measurement (a stuck key, a paste, a three character run with a tiny denominator) from minting a level.

Training flat bonuses are the beginner's engine. They do not pay on current Starfall runs. They are fixed amounts, so they dominate the XP of somebody hitting firsts constantly and are a rounding error to an expert:

BonusXPWhen
firstRun250The first completed run of a game
personalBest150A new best for this game and mode
dailyFirst200The first completed run of the day, any game
perfectRun220100% accuracy on a run of at least 60 characters
waveMilestone60Per multiple of 5 waves reached in the arcade
nodeFirstClear200First time a curriculum node is cleared
nodeStar120Each new star on a curriculum node
academyCertified300Each Academy key group certified
academyGraduated3000Certifying all 21 groups. The largest flat award in the game

Defined in BONUS, js/xp.js.

The level curve costs round(60 + 40 * level^1.28) XP for the step from level to level + 1, capped at level 100. The exponent is gentle enough early that a beginner sees levels move in one session, and steep enough later that level 60 means something.

LevelCost of the next levelTotal XP to reach
11000
2157100
5374776
108223,508
201,91116,457
303,17041,115
424,84488,209
506,041131,112
607,613198,527
8010,975382,270
100(capped)635,670

Ranks follow the level, so the number and the word never disagree:

LevelRank
1Cadet
5Recruit
10Ensign
15Pilot
20Lieutenant
30Commander
40Captain
50Ace
65Wing Commander
80Vanguard
95Legend
100Grandmaster

4.2 Axis 2: mastery, relative to yourself#

Curriculum nodes and Academy drills are judged against your OWN rolling baseline, never against a fixed target. That is the mechanism that keeps a beginner progressing, and it is the thing most star-based typing sites get wrong: fixed WPM targets give the beginner who needs encouragement most none at all, and let the expert clear everything on day one.

How a node is starred (scoreNode in js/skill.js):

RuleValue
Accuracy needed to clear the node at all92%
First cleared runEarns one star by definition, and becomes the baseline
Further starsLand at 1.05x, 1.12x and 1.22x of your own baseline for that node
Third star also requires96% accuracy
Stars are never taken awayOnce awarded, permanent
Baseline rise on a better run35% of the gap, immediately
Baseline fall on a worse cleared run6% of the gap
Minimum baseline8 WPM, so nothing divides by nearly zero

Because the steps are RATIOS, 18 to 24 WPM (plus 33%) and 100 to 115 WPM (plus 15%) are the same kind of event, and the beginner's is in fact the larger one. The baseline falls at roughly a sixth of the rate it rises, so it is a floor you have to walk back down to rather than a punishment for one good night.

4.3 Axis 3: scrap, combat activity and consistency#

In current Starfall runs, scrap rewards defeating enemies and clearing objectives. It has no WPM, accuracy, time-idling or personal-best factor. Killing more eligible enemies is a useful alternative objective to maximizing performance score. A charged kill can earn its full salvage value even when little or none of its text was typed.

enemyBaseScrap = max(1, round(1 + originalCarriedCharacters * 0.35))
salvageScale  = difficulty.salvage * clamp(lootMult, 0.5, 6) * clamp(ascension, 1, 7)
enemyScrap    = max(1, round(enemyBaseScrap * salvageScale))
objectiveBase = event: 18; mini-boss: 40; boss: 120 + 40 * completedPhases
objectiveScrap = round(objectiveBase * salvageScale)

The shared helpers in js/xp.js apply the scale when the drop is credited. Combat floaters, the HUD, wave records and the run bank use that exact number; finishRun never multiplies it a second time. Mistake-created enemies and regenerated objectives are not fresh salvage opportunities. Loot conversion, cores and separately settled encounter receipts are itemized separately from the per-wave combat scrap record.

Training and legacy formats keep their older salvageFactor based on measured run speed and accuracy. This rule does not apply to performance-v1 Starfall. Existing currency, items and upgrade levels are preserved.

4.4 Axis 4: gear, access rather than rate#

Stated as one line, because it is the thing to protect if you change anything in js/gear.js:

Gear buys ACCESS. Skill buys RATE.

Almost every stat in the catalogue reduces FAILURE: more health, less damage taken, more heat before a jam, a combo that survives a slip, a charge that swats the thing about to land, a field that descends slower. Good gear lets a 30 WPM player survive to wave 18 in a sector that would have ended them at wave 6, and carries them into the Rift, which is exactly what it is for.

Equipment can increase salvage and change survival. It does not multiply current Starfall score or XP. Former score-only gear bonuses now contribute to salvage instead, preserving those items as meaningful choices. Typing faster and more accurately raises performance rewards directly, while better weapons can clear more enemies and earn more scrap.

The full gear system is section 10.

4.5 The placement#

The Flight Check is the skip-ahead. It runs a 60 second sprint and then grants a lump sum equal to the level that performance deserves.

placementLevel(w, acc) = clamp(round(((w - 18) / 3.6) * (acc / 100) ^ 1.5), 1, 42)
                         (and exactly 1 below 20 WPM)
placementGrant(...)    = max(0, totalXpFor(placementLevel) - currentTotalXp)
Net WPMLevel at 100%at 97%at 92%XP granted to a new account at 97%
201110
30333257
406651,150
509882,149
601211104,330
701414137,400
801716159,973
9020191814,664
10023222020,398
11026242324,822
12028272532,392
13031302741,115
16039383570,275
180+42 (cap)424088,209

Four rules make it safe to re-take:

  1. It only ever raises. The grant is the difference between what you have and what the measurement is worth, floored at zero.
  2. The profile keeps the BEST placement, not the latest. Rewriting "placed at level 22 from 96 WPM" with a slower re-take would replace a true sentence with a misleading one.
  3. It seeds the per-key model, and that seeding also only ever raises. This is what makes the curriculum immediately recommend symbols and code to a proficient typist rather than the home row.
  4. It hands the Academy a head start. Any key group whose keys the measurement already proved (12 or more samples at 90% or better) is marked as evidence rather than starting from zero.

The dialog offers itself once per profile and then never again. placed records a completed check; placeOffered is stamped the moment the dialog opens, because closing it is an answer and re-opening a modal on every load until a one minute test is finished is nagging. The offer itself does not go away: the Arcade's "Start here" card and the Progress re-take button stand for as long as the profile is unplaced. tools/check-app.py guards this.

4.6 Per-game ranks#

Each mini-game keeps its own XP, rank, plays, bests and badges in state.games[<id>], so playing Starfall levels up Starfall AND the account, and being level 40 does not make a game you have never opened look finished.

The per-game curve is flatter than the account one, at round(120 + 70 * rank^1.15) per rank, capped at rank 50. A game rank is a familiarity measure, not a skill measure.

Game rankCost of the nextCumulative
11900
55661,298
101,1095,191
202,31421,602
50(capped)149,110

4.7 Ascension#

At level 100 you may reset the level and XP, keeping EVERYTHING else: gear, cosmetics, badges, the Academy, History, the boards. Each ascension grants a permanent +6 percentage points per ascension to training XP and salvage, a visible mark, and 5 cores. The account multiplier is 1 + 0.06 * ascensions, an additive increase. Starfall combat salvage caps this ascension component at 7x; its performance score and XP are never multiplied.

It is opt-in and never suggested twice. It exists so the ceiling is a door rather than a wall.

5. Measurement#

5.1 Speed and accuracy#

There is exactly one definition of each, in js/util.js, and every surface in the app uses it:

CHARS_PER_WORD = 5
wpm      = (characters / 5) / minutes
netWpm   = (CORRECT characters / 5) / minutes
accuracy = correct / typed * 100

What counts as a minute. Current Starfall performance tracks manual enemy, boss-objective and optional asteroid typing. Pickup-code typing is outside this performance ledger. Selected-target thinking, mistakes and correction time count; pauses and protected cards do not. The first contiguous pair of keys supplies one observed opening interval for that engagement, avoiding short-word inflation without a baseline seed. Unassigned acquisition errors and their time follow the next target; remaining errors stay in an unpaid measurement row. Target switches suspend one sample and returning resumes it. Original positions earn at most once, while raw correct/typed counts remain available for feedback. History retains the actual play duration separately from target engagement time.

Feedback beside the ship. The left segmented meter shows hull percentage, HULL LOW at 50%, and CRITICAL at 25%, with shield points underneath. The right meter shows stored charge, a notch for the next shot's cost, and FIRE READY when the shot is affordable. During transmissions it says AUTO FIRE; overheating says JAMMED. Hull threshold crossings play a short descending warning once per crossing. The existing charge pitch and full-capacity cue continue; the meters remain readable with sound or motion disabled.

Power-up dock. The five fixed F1–F5 slots sit below the playfield beside the lower controls. Filled slots say Ready, active effects show seconds and a draining strip, and overflow drops retain their waiting timer. Collection cues travel toward the matching lower slot. The help button remains beside the slots.

Boss word goals. Each phase forecasts the final full word using the active weapon, current damage modifiers, upcoming combo bonuses and remaining health. The last word is underlined and words beyond it are dimmed. The endpoint updates after mistakes, corrections and weapon changes. In fixed-tier fights, maximum core health stays at its initial text length times sector HP scaling: mistakes never inflate it. Current health clamps at zero, but the current word must be completed before the phase clears. Legacy fights retain upward whole-word health alignment. Retyping already-scored letters still deals no duplicate damage. If the remaining passage cannot finish the phase, its text stays undimmed and the label explains that another passage may be needed.

Asteroid pace. Optional rocks travel at no more than 35% of the slowest solved enemy speed in the wave. Their longer lifetime leaves time for spare-time collection; they still do not hold a cleared wave open.

Backspace. It is allowed everywhere: in the arcade it takes back the red, then the letters you got right, then the lock itself, and in sprints, drills and boss transmissions it corrects the text, because a paragraph you cannot correct is a punishment rather than a test. Everywhere it restores the text and the character counts toward net WPM, but the keystroke that got it wrong stays in the accuracy denominator forever. That is the standard convention and the only one that stops "type garbage and repair it" scoring 100%.

5.2 The plausibility gate#

plausible() in js/run.js drops a run that claims something no human did. The Cloudflare Worker holds the same line independently on the leaderboard side.

RuleValue
Must be completecomplete: false is discarded everywhere
Minimum duration2,000 ms
Must have typed somethingtyped > 0
Correct cannot exceed typedenforced
Maximum net WPM260

5.3 The per-key model#

One record per character and per typed pair, holding how often it was hit, how often it was right, and how long the finger took. This is what makes the site personal: the arcade builds asteroid chunks from your worst keys, the drills target them by name, and the Progress heat map is a picture of your own hands.

ParameterValueWhy
MIN_KEY_MS40 msFaster than this is a paste or a stuck key, not a finger
MAX_KEY_MS3,000 msSlower is somebody answering the door
KEY_INERTIA0.25Old evidence is discounted, so the model notices improvement
KEY_ALPHA_MIN0.1A veteran's record stays movable
KEY_CAP140 charactersThe blob syncs and has to stay small
BIGRAM_CAP400 pairsSame
MIN_KEY_SAMPLE12 pressesBefore a key may be called weak
ACC_FLOOR70%As bad as the accuracy scale goes for one key
LAT_SLOW / LAT_FAST1.8x / 0.6xOf your own average pace, scoring 0 and 100
DEFAULT_REF_MS320 msStand-in pace before you have been measured

Timing is keyed by the character that was EXPECTED, not the one that was pressed: knowing you typed k when l was wanted says something about l.

Account-level skill is an exponential moving average of recent runs rather than a best, because a best is a story about one lucky minute and this number has to decide what to put in front of you next. The first run is adopted whole (a new player should see a real number, not a fifth of one), then the weight falls off as runs accumulate and settles at a floor of 0.12 for a veteran. Run length weighs in as well: a 15 second burst is not the same evidence as a five minute haul (RUN_FULL_MS is 30 seconds).

5.4 Word tiers#

The lexicon is ten tiers of hand-written real words, each staying strictly inside its own character set, plus a prose tier for sentences and paragraphs.

TierNameCharactersWordsChosen at
homeHome rowasdfghjkl;69under 18 WPM
homeTopHome and top rows+ qwertyuiop41118 to 27
lettersEvery lettera to z33228 to 37
commonCommon wordsa to z68138 to 51
commonLongLonger wordsa to z76752 to 67
capitalsCapitals+ A to Z20168 to 84
punctPunctuation+ ,.;:!?()-'"16685 to 99
numbersNumbers+ digits and .:/-,$%127(by node)
symbolsSymbolsletters, digits, @#$%^&*_+=/<>~-! plus the vertical bar and the backtick118(by node)
codeCodeeverything183100+
proseProsesentences with punctuation371(by node)

Plus 20 quotes for the sprint's Quote mode.

tierForWpm in js/xp.js maps the rolling skill number onto that ladder, and it is the single reason the same arcade game is right for both audiences. Difficulty and sector multiply on top; they never replace it. A fixed table would mean picking an audience.

The "(by node)" tiers are DRILL material and only ever appear where a player asks for them by name (a curriculum node, an Academy group, a sprint mode). The arcade's falling craft label themselves from ARCADE_TIERS in js/words.js, which is this ladder with punct, numbers and symbols removed: fragments, part numbers and bare operators drill exactly what they claim under a node, and read as the game speaking garbage when they rain out of the sky (see 7.2).

5.5 Weak keys#

weakKeys(n) returns the worst keys the model is confident about (at least 12 presses), scored on accuracy first and latency second. They are used for:

Your weak keys are the one thing a Versus room does NOT share.

6. Modes and surfaces#

The app is six tabs. Two of them hold games, the rest are where the game is read, spent and compared.

TabIdWhat is there
ArcadearcadeThe game hub (one card per registry entry) staged as an operations deck with a holographic sector chart, the pre-flight briefing, and the running game. The hub and the game are never on screen together
TrainingtrainThe Academy on top, the curriculum (Flight School) below
VersusversusHead to head racing, signed in with a claimed name
ProgressprogressWhat is open today, how good you are now, what you have done
LeaderboardsranksEight opt-in boards
ArmoryarmoryStaged as a hangar bay: the loadout first (it is the point of the economy), then the three vendors, then cosmetics and the collection

The router mirrors the active tab into location.hash, so app.html#arcade deep-links. The ids are stable even if a caption is renamed.

6.1 The game catalogue#

js/games/registry.js is the only list of what games exist.

GameIdStatusModesBoard scope
Starfall KeysstarfallLiveOne mode (Endless), four difficultiesDifficulty, plus a deepest-wave board
Flight ChecksprintLive60 seconds, 15 seconds, Quote, Weak keysThe two timed modes
Wing CommandcoopAnnouncedPair, Squadron(none yet)
The ForgeforgeAnnouncedWorst five, Transitions, The ladder(none yet)
TerminalterminalAnnouncedTokens, Lines, Symbol storm(none yet)

An announced card is not a lock. It is a game that has not been BUILT yet, it says so in those words, and it must never show a padlock, a level or any implication that the player fell short. Nothing on this site is gated; the only thing standing between a player and an announced game is us.

7. Starfall Keys#

The flagship. Your base sits on the lower edge, craft descend carrying words, typing a word destroys the thing carrying it.

7.1 The field#

Simulation units are FRACTIONS of the playfield, so nothing depends on canvas size and a phone turned over mid-run never moves a threat relative to the base.

ConstantValueMeaning
STEP1/60 sFixed timestep, with an accumulator, so a 144Hz laptop and a throttled phone run the same simulation
MAX_FRAME0.25 sThe most a slept tab may catch up in one frame
VIEW_TOP-0.04The sliver above the field a craft drifts in from
REVEAL_TOP0.12The deepest strip the reveal stat can buy
BASE_Y0.93A threat at or past this has arrived
MAX_PARTICLES260Decoration ceiling

Descent speed is in playfield heights per second, which is the honest unit: what matters is how long a threat takes to arrive.

7.2 The wave cycle#

preflight (2200 ms, skippable after 700 ms)
  -> waveActive: the plan is played back, threats descend, encounters fire
  -> waveSummary when the MANDATORY work is done (an ignored opportunity never
     holds a wave open), 4200 ms, skippable by a key, hull regen applies
  -> bossIntro on a boss wave: frozen, protected, left by a deliberate action
  -> bossActive: the fight
  -> bossVictory: frozen indefinitely, the reward already banked
  -> next wave

Those are the ENCOUNTER STATES, and every system consults the same policy about them. preflight, waveSummary, bossIntro, bossVictory and runOver are FROZEN: the simulation does not step at all, so heat does not decay, an event does not expire, a buff does not drain, the pace denominator does not grow and no time-based reward accrues. That is implemented in the CLOCK (now() returns the instant the freeze began) rather than as a flag each system has to remember, which is what makes an indefinite reward review safe: reading it for ten minutes is worth exactly nothing.

7.2a One difficulty contract#

Typing context changes are protected. Boss phases, formations, shield commands, replacement passages and returns from a mini-boss show a 1.2-second reading cue with a countdown sound and a distinct ready sound. The next prompt is visible, but combat, timers, heat and scoring stay frozen. Trailing keys, Backspace, charge attacks and other combat shortcuts are discarded. Solo play also waits for 220 ms without input; Versus uses the fixed duration. A held key must be released before its repeat can type into the next prompt. A partially typed field target disappearing through escape or incidental damage uses the same protection. Completing an ordinary word still allows immediate targeting.

On desktop viewports at least 1,000 px wide, fixed-tier bosses keep their battlefield on the left and phase instructions and transmissions on the right. The current action stays visible; Phase help contains the full rules and recovered transmission. The finish-word cue appears above the passage, and expiring mechanic notices never move the reading surface.

A numbered challenge is fixed, not adaptive. js/games/challenge.js is the shared source for preview, ordinary waves and bosses. Personal pace suggests a tier once, then settings.challengeTier remembers the selection. A faster run, new Flight Check, manually entered baseline or stronger weapon never changes the selected tier's workload. All 19 tiers are open from the start.

These are internal paragraph-equivalent scheduling ratings, not minimum measured typing speeds. Mission selection displays loadout survival estimates.

TierInternal wave ratingInternal boss rating
189
21213
31820
42528
53235
64044
75055
86066
97279
108594
11100110
12115127
13130143
14150165
15175193
16200220

Mission selection recommends the highest tier whose upper loadout survival estimate fits the player's measured pace. With no evidence it uses the existing 30 WPM fallback. The four ordinary stages use 0.88, 0.92, 0.96 and 1.00 of nominal WPM, with interpolation for a different boss cadence, then the current formation's pressure factor. Boss target = round(nominal WPM * 1.10). Demand does not secretly increase with depth. Cadet, Pilot, Ace and Nightmare remain combat settings for hull pressure and salvage, separate from the numbered typing workload. Sector still determines enemy composition and boss cadence.

Every tier button and the selected mission show estimated survival WPM for the equipped loadout at 95% accuracy, without charge attacks. Each button forecasts the checkpoint it will launch; the boss is included in the block estimate and also shown separately from full hull with a reserve. Slower players can succeed; the estimates are not minimum speeds. A planner creates real words, schedules arrivals and checks deadlines with the shared effort model before a wave starts. Movement remains subject to the universal readable vertical speed cap.

The work model (js/games/typing-effort.js):

Cj    characters still required in segment j, separators included
rj    that segment's typing rate as a FRACTION of ordinary prose
W     sum(Cj / rj)          paragraph-equivalent characters
A     acquisition still owed, in seconds, charged ONCE per engagement
T(B)  = 12 * W / B + A      seconds

The reciprocal is the point: a random-letter rate of 0.50 means twice the typing time, not half the workload. CONTENT decides the rate; PRESENTATION decides the acquisition. They are independent, which is why a multiword weak-key target is still weak-key content that merely amortises one acquisition over several words.

ContentRatePresentationRateAcquisition
prose1.00paragraph1.000 s
words0.95line1.000.15 s
glyph0.80stack1.000.25 s
code0.72token0.950.35 s
random0.55mote0.950.35 s
drill0.52chunk0.950.40 s

Hidden text (a Blackout) adds HIDDEN_REVEAL_S (0.45 s) to the acquisition and nothing else: stacking a rate penalty on top would charge twice for one mechanic. A vocabulary tier can modify the rate (punct 0.90, numbers 0.88, symbols 0.85, code 0.85), and it is an AUTHORED TAG rather than an inference from the string.

At B = 60: five characters of prose take 1.00 s, a five-letter isolated word takes 1.46 s, five characters of weak-key rock take 2.42 s.

The loadout survival estimate is a separate model. js/games/loadout-demand.js simulates three representative blocks, using actual task words and authored boss text, at 95% accuracy. It includes fitted hull, shields, damage reduction, field slowing, reveal, assists, heat, turret delay, optional charge use, splash, repairs and boss mechanics. Mission-selection advice sets useCharges:false for both ordinary enemies and boss formations. Each fitted hardpoint is evaluated as a complete strategy; their stats are not added together. In the charge-enabled model one sample allows an overlapping area target. Home uses its calibrated attack clocks and a 5% model hull margin. Other sectors reserve 20% hull plus one complete authored boss attack cycle across all three samples, including spaced, random and paired core mistakes. It starts from full hull and shield with no optional pickups.

The range is the minimum and maximum model threshold across those samples, not a statistical confidence interval or a guarantee. The fresh-hull boss estimate is separate; arriving damaged can raise the required pace. The model allows some enemies through, so clearing every enemy requires more typing. Random events, mini-bosses, positioning, charge timing and manual target choices can change survival. Exact player behavior and every combat interaction are not simulated. The assumptions and limits are available in the collapsed Equipment survival estimate. This secondary estimate never replaces Home's fixed pace in the briefing, slider or tier recommendation. A 30 WPM reference suggests Home Tier 5 in the opening group, irrespective of equipped gear.

Vocabulary starts from the fixed nominal tier and advances one language rung per six waves, within ARCADE_TIERS. It never substitutes a player's newly improved rolling speed into the same selected challenge.

7.2b Where a run may open: checkpoints#

A run opens on wave 1, or on the start of a block whose preceding boss was ACTUALLY DEFEATED, in this sector, at this combat difficulty and numbered challenge tier. Nothing else.

In solo play, continuing from a full boss victory restores hull to 100%, just as restarting at that earned checkpoint would. Service happens on Continue, after the fight result is recorded; it grants no shield, score or salvage. Mini-bosses and Versus do not receive this repair. Defensive equipment still matters within each five-wave block and during every boss fight.

start points = 1 + n*K, where K is the sector's boss cadence (5, or 4 in the Rift)
authorisation = a saved clear, never a formula and never a highest-wave number
SituationRestart
No boss defeated; death on wave 4 or on boss 51
Boss 5 defeated; death on waves 6 to 106
Boss 10 defeated; death on the wave 15 boss11
Boss 15 defeated16 becomes available
Rift boss 8 defeated; death on boss 129

Because a start point is 1 + n*K it is never a multiple of K, so a normal start can never land ON a boss wave. That is arithmetic rather than a check. A harder difficulty's clear also opens the equivalent checkpoint at every EASIER combat difficulty; the reverse never happens. Checkpoints are shared across all threat tiers, including existing tier-specific and legacy adaptive clears. Changing threat tier preserves the selected unlocked start. The cadence is stored WITH the progress, so a later change to a sector's boss spacing conservatively drops back to wave one rather than reinterpreting a clear that was earned against a different schedule.

A DIRECT BOSS START EXISTS ONLY AS A DEVELOPER HOOK. opts.devWave bypasses the resolver so tools/check-app.py can reach a boss without playing four waves first, and it is deliberately a DIFFERENT KEY from startWave: no panel writes it, no saved setting carries it, no URL reads it and normalizeState knows nothing about it, so there is no path from a player's own configuration to one.

This replaced an arbitrary stepper from 1 to 50 with a row of boss-wave presets. Two things were wrong with it: it offered the boss itself, which skips the block that gives the fight meaning; and nothing proved the player had ever been there, so wave 45 was one click away on a profile that had never cleared wave 5. Account level now opens destinations, while checkpoints determine where a run in an open sector may resume. All threat tiers remain available.

Only a defeated boss grants a clear. A surviving hull keeps the fight going. Losing all hull ends the run on that wave without unlocking the next checkpoint; a boss shot absorbed by shields never ends the attempt.

Checkpoint attempts compare individual waves. Current performance-v1 Starfall grants real target performance XP and combat scrap on a checkpoint attempt. Every cleared wave can set its own score and scrap best and enter its exact sector/difficulty/tier/rules leaderboard. Clearing wave 16 from a saved checkpoint is comparable with clearing that same wave after flying the earlier block. An unfinished wave, including an unfinished boss, cannot set a wave record. A later death preserves earlier clears when the finished run banks.

Checkpoint attempts still do not fabricate lifetime depth records or depth badges for waves skipped. Abandoning a run banks no new wave records. Manual personal pace only recommends a tier, so it no longer invalidates a fixed-tier wave record. Legacy adaptive run formats keep their original ranking gates.

Completed is not reached. wavesCompleted is counted as waves end; result.wave is the wave the run was standing in when it finished. The old result.wave - startWave + 1 counted a reached-but-failed wave, so every depth-shaped reward paid for one wave that never happened.

js/games/starfall.js reports meta.startWave, meta.wavesCompleted and meta.checkpoint as plain facts and decides none of the pricing; js/run.js prices it, exactly as it prices everything else. The pre-flight, the launch button, the chrome bar above the game, the opening card and the end screen all say so, so the trade is never discovered afterwards.

7.3 Enemy catalogue#

TYPING A WORD OUT DESTROYS IT, always, with no trigger and no meter involved. That baseline is deliberate and must stay true. The capacitor is what the typing EARNS on top, and a discharge costs the target word its own letters.

A craft carries ONE TO THREE WORDS, and the count is the craft. It sets the size drawn on screen, the damage on arrival (per word still carried), and the number of separate engagements it takes to clear. Fewer, heavier things arrive than used to, because each one is now worth looking at.

Presentation, and why a character is not a character#

Twenty letters of prose, twenty letters arriving one isolated word at a time, and twenty letters of the six keys you are worst at are three different amounts of work. The game used to count them as one, which is why a meteor shower could fill the screen while the threat meter read CALM.

PRESENTATION is the property that fixes it. It is not the word list and not the length, it is whether a reader can see and parse what is coming.

PresentationRateAcquisitionWhat it looks likeCarried by
paragraph1.000 sA boss transmission, on a surface you are already readingBoss, mini-boss
line1.000.15 sA whole sentence, visible at once; target choice after each word and SpaceElite, Carrier
stack1.000.25 sTwo or three words, all visible; target choice after each word and SpaceCourier, and ANY craft carrying more than one word
token0.950.35 sOne word, alone, with nothing to read ahead intoAny craft carrying exactly one word
mote0.950.35 sA glyph or two, in numbersMote (a carrier's swarm)
chunk0.950.40 sWeak keys in a row, no language under itAsteroid

Presentation is now a RATE and an ACQUISITION rather than a single effort multiplier, and the difference matters in three places. A multiplier is a statement about score; a rate divides into seconds, which is what a schedule needs. Most of what makes a lone short word expensive is FINDING it, which is a fixed cost per engagement that does not scale with length, so folding it into a per-character weight priced a four-letter drone and a fourteen-letter one identically per character and kept charging it to a target the player was already holding. And the old multiplier was applied twice, alongside a blanket 0.8 discount in js/xp.js whose justification was the same acquisition.

paragraph and line are the reference at 1.00 because prose is what typing speed is measured in everywhere else on this site, and because meaning is what lets a reader run ahead. The numbers come out of the reading literature (Salthouse 1986 measured about 174 ms a character for prose against 178 ms for the same words in random order, and random letters far slower than either) and were re-derived here from acquisition cost per engagement over the character counts this game deals. Two independent derivations agreed inside 8 percent.

The counter-intuitive result the design turns on survives unchanged: A STACK IS CHEAPER PER CHARACTER THAN A LONE WORD, because the overhead is the acquisition and not the letters. Stacking is the forgiving rung, and the way to make the game harder is to issue words ALONE.

The SCORE still uses a single weight per character, because a keystroke that cost twice as much is worth twice as much and the player who takes the hard target should be paid for it. That weight is now DERIVED from the model above (effortOf: the rate turns real characters into paragraph-equivalent ones, and the acquisition is converted at the reference pace of 40 WPM), so score and schedule cannot drift apart. It comes out within a tenth of the hand-written table it replaced: a sentence 1.02, a phrase 1.12, a lone five-letter word 1.34, a two-glyph mote 1.90, a five-character rock 2.29. Effort is still deliberately NOT spent on XP or scrap: js/run.js prices those off measured pace and real characters, and a multiplier there would be a way to earn faster by choosing what to shoot at.

A STACK IS CHEAPER PER CHARACTER THAN A LONE WORD, and that is the counter-intuitive result the whole design turns on. The overhead is the ACQUISITION, not the letters: find it, read it, commit, type, let go. One acquisition spread over twelve characters beats one acquisition per four and a half. So stacking is the forgiving rung, and the way to make the game harder is to issue words ALONE rather than to pile them up.

Effort is spent in exactly three places, and deliberately not in a fourth:

ThreatRadiusWordsPresentationDamage on arrivalWord lengthKill scoreSpawn weightFrom waveSpecial behaviour
Drone141token6 a word3 to 6031One contextual word
Courier212 to 3 requestedstack9 a wordauthored phrase3071A meaningful phrase, typed continuously
Cruiser244 to 6, adaptedline11 a wordauthored sentence4053A whole sentence from the current scene
Asteroid191chunk0 (it is an OPPORTUNITY, see 7.8)3 to 625n/a2Not in the mandatory pool at all. Its one "word" is a chunk built from YOUR weakest keys, it carries a reward chosen when it was planned, and it damages the ship only by physically hitting it
Splitter171token7 a word4 to 62034On death by typing or splash it becomes two drones at 1.35x speed
Elite305 to 8line7 a word, bulk 32 to 990guaranteed2Carries an INTACT SIGNAL out of js/lore.js. Drops salvage
Carrier345 to 8line8 a word, bulk 32 to 9140guaranteed4An elite with 3 to 5 motes flying formation around it
Mote91mote31 to 38never queuedanyA shard of a word. Only ever arrives with a carrier
Power-up131token0the capital wordnone(dropped)anyFalls at 0.55x speed. Missing one costs nothing

The elite, the carrier and the swarm#

AN ELITE IN EVERY WAVE FROM WAVE TWO, drawn before anything else so it comes out of the wave's budget rather than on top of it. A sentence craft is not a rare event to be lucky into: it is the rung of the effort table that makes the other four legible, because you cannot feel that a lone word is expensive until you have just read forty characters of prose off one hull in the time three drones would have taken. From wave 4 there is a 35% chance it is a Carrier instead.

It carries an INTACT SIGNAL, not a bag of words. signalWords in js/words.js takes a real line out of the SIGNALS corpus in js/lore.js, whole, and returns its words with the authored spelling intact. Every sentence has proper capitalization and punctuation, including names and possessives. The word tier limits its base letters; it never strips sentence capitals or full stops. The planner counts every character actually typed. Short enemies also mix scene words with coherent abstract concepts such as 'free will' and 'burden of proof'. They need not advance the story, but their words must belong together.

NO SENTENCE, NO SENTENCE DISCOUNT. Gameplay includes short authored sentences inside the two restricted keyboard tiers. A missing whole sentence becomes one tier-valid word, drawn and priced as a token. Couriers likewise use a complete phrase or one word. No multi-word fallback assembles random vocabulary.

THE SWARM FLIES IN FORMATION AND SCATTERS. A carrier's motes hold a station on a ring around it, so they arrive WITH the sentence and compete for the same seconds of attention, which is the entire point of the pairing: one craft is asking you to read and the things around it are asking you to aim. When the carrier dies the link drops and every mote falls from wherever it was. Their positions are a pure function of the shared clock and their own seeded station, never of wall time, so both renderers and both clients in a race agree.

A mote carries a SHARD, not a short word (shardFor in js/words.js): one to three characters sliced out of the middle of a real word. A short word is still a word, with a shape your eye knows; a shard has none, which is what the 1.60 is pricing. It also cannot be done with wordFor, because several tiers have no words that short and would answer with the same fallback entry every time.

bulk caps what a word count does to size and damage. Those are driven by words carried, which is right at one to three and absurd at eight: a sentence craft would otherwise be drawn three times the size of a cruiser and hit for eight times a drone. Elites and carriers cap at 3. The real length still shows up in the health ring and in the threat meter.

ONE CRAFT IS ONE STRING. A multi-word craft presents an intact phrase and asks for Space between its words. Starting a word commits aim through that word; after Space, another ship’s initial switches targets. A craft reading crab mint is nine keystrokes including the space, and the space bar in the place a reader's hands already go to put a space types the separator instead of firing the capacitor.

That is why the presentation table above is a consequence rather than a choice: token is reached only by a craft carrying ONE word, and anything carrying more is a stack. A multi-word craft that revealed its words one at a time hid half of what it was asking for (nothing to read ahead into, which is the entire saving a phrase is priced on) and dropped its lock at the boundary, which left the space bar there as the trigger. It also means a held craft's later words are never re-rolled for a first-letter collision, because they are never acquired by their first letter and swapping one out under the player's eyes would be the game cheating.

The held lock is a PREFERENCE and not a commitment, though, and that is what keeps it from becoming a trap. Between words there is nothing typed into it, so the box over your base is empty: its own next letter is answered first (which is the whole point, and the reason its words need no collision check), while any other letter on the field takes you straight there and backspace lets go of it outright. Reading a sentence through is what the held lock is FOR; it is not a claim on the next thing you press.

Both renderers draw a held craft the same way: its words sit at full size on ONE line, the cleared ones staying in place and going faint, which is the progress readout (a courier coming apart left to right needs no other one). The commit key is lit on the FIRST word only, because after that the lock is held and no key is choosing anything.

The radius grows 30% per word carried and shrinks back as words are stripped. Word length ranges are multiplied by the wave's wordLen and by any live event's length multiplier, then floored at 2. Arcade words are always SOLID (no spaces), because space is the fire control: the lexicon keeps its phrases for the drills and the sprint, and the arcade picker filters them out.

A PHRASE IS TYPED AS A PHRASE, SPACES AND ALL, and that is the one place the fire control stands down. A stack or a line puts several words on one craft, with target choice after each completed word and Space, written the way a phrase is written anywhere. So the separator is a character the craft ASKS FOR: round laugh track is eighteen keystrokes, not sixteen.

THE LABEL IS A WINDOW, AND THE REST IS A NUMBER. A craft does not print its whole string. It prints the word under your caret in full, then whole following words while they fit, then an ellipsis, then the keystrokes it still owes you:

face-to-face part-time  22          two words and their separator, all shown
high-speed full-time... 34          more behind, and 34 keys left to kill it
signal                              one word: the word is already the cost

That number is the threat's LIFE in the unit you pay in. It counts the rest of the word you are typing, every word behind it, and the separators between them, and it ticks down as you type. It is the fastest way to compare two craft when you are choosing which to commit to, and it is why an eight word elite no longer draws a label wider than a phone. Words you have finished leave the line, so the word under the caret stays centred on the craft and the caret never jumps.

That space used to reach the discharge and spend the capacitor to delete the NEXT word of the phrase being read, which looked exactly like the space having been accepted; when the meter could not pay it fizzled instead, so one keystroke did two different things a word apart. The two meanings are now split by what is being ASKED FOR, a question the simulation can always answer:

Where the space is typedWhat it does
Between the words of a held phrase (sentenceGap)Types the separator. Counts as typed and correct, banks charge at the weapon's rate, keeps the combo, records original typed work for its target. Never fires
Inside a word, or with nothing locked, or on any craft carrying one wordDISCHARGES, exactly as before
Between the words of a held phrase with red in the boxJoins the correction buffer like any other key. An uncorrected mistake owns the keyboard, and handing the trigger back there would be the original bug reached from the other side

Because the separator is asked for, missing it is an ordinary mistake and is paid for in the ordinary way: the next word's first letter lands in the correction buffer to be taken back. After Space, the next word is a fresh target choice. Type its initial to continue, or another ship’s lit initial to switch. Completed words remain removed when you return. A started word holds aim; Backspace can erase its prefix to release it. Escape pauses without throwing away that word.

The separators are counted in threatChars, so the threat meter's Required WPM prices the keystrokes the field is really going to ask for. They are recorded in the per-key model exactly as the sprint records them (the space itself yes, bigrams across it no), and skill.js's drillable() keeps the space bar out of the weak key list while the Progress heat map still draws it.

Every kill drops SCRAP, and the amount pops out of the wreck where it died: 1 + 0.35 per letter the craft was carrying, rounded, before the run's salvage multiplier, which js/run.js applies at the end like every other reward.

Home fleet and visible damage. Painted Fleet is the default art setting, also available through Settings > Art style. Home has detailed painted 2D ships with distinct silhouettes: hooked drones, needle couriers, heavy gunships, armored elites and three different mini-bosses. The five player hull shapes retain their identities and equipped weapon readouts. Light craft weave within bounded paths; selecting a target holds that extra movement while you read. The planner still controls descent, word counts and deadlines.

Multi-word hulls and bosses have intact, damaged, heavily damaged and critical images on exactly the same canvas and pivot. Completed words progressively reveal breached armor, broken weapon housings and hot internal machinery. Rewind restores the appropriate image. Boss damage persists across phases; shield projectors show broken emitters and cracked shield faces. Word cells remain separate readable indicators, with fewer visual cells on small craft.

Exhaust starts at engine nozzles; attack flashes and shots start at weapon mounts. Sparks and sampled hull fragments emerge from damaged components, with size and outward speed scaled to the craft. Boss destruction lasts about 2.4 seconds: component blasts, a core rupture, then separating wreckage. Combat stops and rewards are banked immediately; the reward card appears afterward. An explicit pause or hidden tab also pauses the destruction sequence.

Words, targeting cues and attack warnings remain crisp overlays. Reduced motion retains damage images and uses a short wreck fade without moving debris. Ink, Rendered, Pixel and Vector remain selectable. Painted Fleet uses Ink outside Home and the existing fallback if a sprite fails to load.

The Home fleet preview, linked in this manual's footer, lets you inspect ship sizes, switch damage stages and replay boss destruction.

A splitter's children do not split, and neither splits when killed by a blast (a nuke or an emergency flare), because a panic button that seeded two fresh drones would be worse than useless against exactly the wave it exists for.

Incoming attacks. A hostile reaching BASE_Y launches a visible shot at the ship. The shot takes 0.65 seconds of active simulation time to arrive; damage is applied on impact, scaled by sector toughness and the hull's damage multiplier, with shields absorbing it first. The playfield has no horizontal boundary line. Impact sparks and a short hull-hit or shield-absorption message explain the result. Pending shots hold the wave open and freeze during pauses and protected cards. A boss launches at its existing attack range, and defeating it before impact cancels its shot. A successful full boss clear also neutralises remaining escort shots before the reward review. A boss shot that lands ends the attempt even if a shield absorbs the damage. Power-up drops never attack.

7.4 Targeting and the lock#

RuleBehaviour
AcquiringThe first character locks the LOWEST threat whose word starts with it and whose typing has not begun. Lowest is both the most urgent and the one your eye is already on
While lockedEvery later keystroke belongs to that lock, for as long as there is anything typed into it
A lock at zero charactersCommits you to NOTHING, except for a held phrase still waiting for its separator. A stack can hold its lock across a word boundary. Its own next letter is answered first, which reads a sentence straight through; once the separator is served, any OTHER letter on the field takes you there, exactly as it would with nothing locked
Committing revealsA hidden word (Blackout, the Oracle) shows itself the moment you lock it
A wrong keyLANDS, in red, in the box over your base. Nothing else is accepted until backspace has taken it out. It costs heat, accuracy and the combo, stalls the turret, and marks the target as fumbled for the rest of this engagement
The correction capAt most three uncorrected characters (BAD_CAP). Past that the keyboard accepts nothing but backspace, so a moment of confusion can never become twenty red letters to pick out one at a time
A stray keyA character no craft on screen answers to is a miss (heat, accuracy, the beat) but never a correction: nothing has been committed to, so there is no word it belongs to
BackspaceTakes back the red first, then the letters you got right, and then the COMMITMENT: when there is nothing typed left the lock is released and the whole field is open again. It never does nothing, which is what stops a target you no longer want from becoming a trap. The box carries the same control as a button, because a phone's soft keyboard reports no Backspace at all
AssistsAbsorbs heat and firing delay for a limited number of slips per wave. The error must still be backspaced; accuracy and combo penalties remain
Correction at every difficultyKeeps the correct prefix and the target. Backspace removes the typo, then typing continues from the same letter. The mistake still costs heat, accuracy, the combo and the stall. Weapons never restart the word
EscapePauses during a word, pending separator or error; releases an empty target preference after Space
The word running outIf the meter never caught the word up, the target takes a FRESH SHORT word and starts clean
A word clearedThe lock is RELEASED. A craft with words left keeps flying, one word lighter and visibly smaller, and committing to its next word is a fresh decision

Mandatory correction and stable reading text#

An incorrect character never replaces or inserts a glyph in the target word or boss passage. It highlights the expected character cells instead. A separate input line shows the accepted prefix, the actual erroneous characters and their count. The error buffer holds up to three characters; further input pauses until Backspace removes them. Correct letters do not advance while any error remains. Boss commands follow the same rule.

Space, arrow and touch discharge, offensive flares, weapon swaps and reserve nukes are blocked while an error remains, without spending resources. A departing target, help card or pause does not erase errors. Defensive reserve powers remain usable. Assists cushion heat and firing delay; no equipped item bypasses correction. After correcting a boss typo, the next ten newly scored correct characters use after-typo damage, and the eleventh restores clean damage. Backspacing previously scored text cannot farm damage, combo, recovery or escort fire.

No two craft on screen offer the same opening letter. The first letter is the whole targeting interface, so an ambiguous one would turn "commit to that target" into a coin toss the player cannot see. freeLetters() is what is taken and wordAvoiding() draws around it, at every point a word can appear: on spawn, when a craft moves to its next word, and when a fumbled word is re-issued. Both renderers draw that letter in the accent colour. The picker always makes the same NUMBER of draws from the seeded stream whatever it chooses, which is what keeps a Versus room in step while letting two clients with different screens resolve a collision differently.

Corrections always preserve correct letters. The old Strict setting is retired, including on existing profiles. Ace and Nightmare increase combat pressure without changing how Backspace works.

Each owned weapon or attachment occupies one slot. Fitting an item from the other mount moves it and clears the source attachment slot (weapons fall back to the starter or an empty secondary). Old duplicate loadouts keep the primary copy and clear the secondary without deleting ownership or upgrades.

7.5 The capacitor, and the accuracy axis#

Typing a word out destroys it. Nothing below changes that. What follows is what the typing EARNS alongside: every correct character also banks CHARGE, measured in letters, through chargeFor():

c = clean ? dmgClean : dmgFoul
c = c * profile.clean or profile.foul     (the encounter's vulnerability, if any)
c = c * (1 + min(0.6, comboDmg * combo))  (comboDmg weapons only)
c = c * pierce * profile.pierce           (inside a boss transmission only)
c = c * swapDamageMult(msSinceSwap)       (0.5 rising to 1 over 600 ms)
c = c * chargeRate                        (the meter's own speed)
floor at 0.05, capped in total at chargeCap

chargeRate is 0.4 at the baseline, and that number is the whole balance of the feature: a correct character banks a little under half a letter, so about two and a half words of typing buy one word deleted for free. At one letter a character every word typed would buy another outright and the field would clear twice over.

clean is whether the CURRENT WORD has been fumbled, not whether the run has. The bargain is per engagement: a slip costs you the charge those characters did not bank and nothing else, which keeps it a cost rather than a spiral.

A discharge costs the target word its remaining untyped letters, less anything a neighbouring kill's splash has already paid into it. Up Arrow or Fire spends that much and KEEPS the rest, so surplus carries. With nothing locked it fires at whatever is closest to your base, which is the only auto-target that is never wrong.

What this feels like. With a Lance (1.55 clean, 0.45 foul) ten clean characters bank a free six-letter word; the same ten characters after a slip bank about a fifth of one. The word you were typing dies either way. So accuracy does not save you keystrokes on the word in front of you, it hands you whole words you never have to type at all, and the letters a discharge skips are a SNAP SHOT worth 14 each. Nothing is deducted and nothing scolds you: you simply earn less of the one thing that saves you time.

AREA weapons (blast above zero) are the other shape a capacitor can take. They fill slower. A discharge spends exactly blastCost charge and clears one current word on every threat inside the radius, regardless of word length. Surplus charge stays banked. The bargain is not precision against forgiveness but patience against reach: hold through a thin wave, dump into a thick one.

A decision about WHEN, made blind, is a guess, so both renderers say what a discharge would take, and they say it ON THE CRAFT rather than as a circle over the field. Every threat standing in the blast is MARKED (corner brackets in the 2D view, its own lock ring in the 3D one), green once the meter could pay for the shell and violet while it could not. The radius itself is never drawn: what the player is deciding is which of these die, and that is a property of each craft rather than a shape in the sky. The marked set is computed once a frame from the same target and radius the discharge uses, so it can never promise a set different from the one that dies.

A mistype STALLS the turret for the weapon's stall (240 ms base, 60 to 600 after gear). The stall stops FIRING and not typing: a slip already costs accuracy, the combo, heat and a backspace, and taking the keyboard away as well would be four punishments for one mistake and would read as the game freezing. Correcting the mistake ends the stall early, because by the time a player has found the key the beat has been served.

accuracyDemand() collapses all of that into one sentence, and it is what the Armory, the pre-flight briefing and the in-game weapon chip all show: the accuracy at which this loadout's charge-per-second crosses the honest baseline's. It compares the two at every accuracy from 70% to 100%, weighting the clean and fouled numbers by the odds of getting a five-letter word out without a slip, rating a combo weapon at the streak that accuracy actually earns, and charging for the stall. A precision weapon reads "pays off above 88% accuracy", a forgiving one "pays off below 95%", an area weapon "pays off on a crowd, not on accuracy". It is derived rather than written beside an item, so it cannot drift from the numbers it describes.

Splash pays splash * targetWordLength into the nearest other threat's current word, within a squared distance of 0.35 (with x scaled by 1.4 for aspect), making the next deliberate discharge over there cheaper. Credit is capped at the current word's length. Splash never advances the locked target or a word already partly typed, including a held phrase at its separator. Unengaged targets can still be destroyed by collateral. Ordinary typing always completes every visible letter. A fully credited word can be discharged for zero charge with a single-target weapon. Area weapons retain their fixed shell cost. The arc shows where the credit landed. Splash cannot chain-trigger power-ups and does not reach the encounter's own craft.

Boss phase command words appear in a large card centered in the playfield. After the command is typed, the paragraph returns to the bottom reading panel. Character positions remain stable while typing in both surfaces. The space cursor uses the original plain cyan block, without an extra open-box symbol. Boss review freezes gameplay, but cosmetic particles, flashes, shake and scrap numbers finish fading on a separate presentation clock. Obsolete auto-shots are removed when the full boss encounter is cleared.

Weapon controls and power-up reserve#

The item picker and Hangar keep a sticky wallet visible while browsing. It shows current scrap and boss cores and refreshes after purchases or upgrades, including when the catalogue is scrolled on a phone.

ActionHow to trigger itCost and result
Type a wordType the visible lettersClears that word and earns charge for correct keys
Fire an extra shotUp Arrow or the Fire button; Space outside a phrase separatorSingle target: remaining letters minus splash credit. Area: fixed blastCost. Surplus charge stays stored
Switch weaponTab with a second mount fittedOnly the active weapon and its attachment contribute; brief spin-up reduces output
Collect asteroid lootDestroy the asteroid; the drop collects automatically after its animationFirst collection stores it, then offers guided practice. No pickup typing or function key is required
Use stored power-upsF1 Shield, F2 Slow, F3 Repair, F4 Focus, F5 Nuke, or click a slotOne charge per type; consumes it only if it can have an effect
Review power-up rulesHow to use, above the five slotsPauses solo play for the full explanation
Read weapon rulesLoadout weapon card; Compare on a picker or vendor cardActual resolved build, including upgrades, mods and gambits; no equipment changes during comparison

The loadout and vendor descriptions share js/weapon-guide.js. Their clean and after-typo rates come from chargeFor, boss output from damageFor, and streak thresholds from the resolved comboDmg. A six-letter single-target shot is the common comparison; area weapons state their fixed shell price. These examples start from empty charge and zero combo with neutral target armour. They compare steady rates, not a prediction that every future word will remain fouled. Normal words reset on the next word. Bosses and mini-bosses recover clean damage after correcting the error and typing 10 consecutive new correct keys, or a new passage, whichever comes first. Further typos restart the count without stacking a deeper penalty. Backspace does not reset recovery and already-scored keys cannot advance it.

Higher charge earnings buy extra shots sooner. Precision weapons trade a strong clean rate for a weaker rate after mistakes; area weapons trade slower charging for several targets per shot; streak weapons reward sustained accuracy. There is no universal best weapon. Home's pacing remains solvable with the starter single-target weapon and without reserve power-ups.

A mini-boss clear restores waveActive; clearing a mini removes only its own escorts and keeps the ordinary wave queue. A full boss clear first settles its idempotent receipt, then removes enemies and enters bossVictory before rendering the review. A settlement exception cannot remove the boss and leave an empty active encounter. Boss combat contributes to active combat time.

7.6 Heat and jams#

ConstantValue
Heat per mistype13, times any event heat multiplier
Heat capacity100 base, heatCap from gear (clamped 50 to 320)
Heat decay20 per second base, heatDecay from gear (clamped 8 to 80)
Jam duration1,150 ms
Heat left after a jam45% of capacity
Wave startHeat resets to 0, or to 50% under the Hot Start gambit

A jam preserves the lock, the correct prefix and the correction buffer. It shakes the screen and pauses typing and firing; Backspace still corrects during the jam. It deliberately does not count the ignored keys as mistakes: the mistake that caused the jam has already been paid for, and charging again for the second you cannot fire would make heat a spiral rather than a lesson.

7.7 Combo, score and the Zone#

Combo is consecutive correct characters. A mistype applies the equipped combo retention. Combo still drives feedback and streak-sensitive combat equipment. It does not multiply current Starfall score or XP.

The compact combat HUD keeps the active build's Charge bonus visible below the weapon, with a meter toward +60% and the combo needed to reach it. A typo briefly shows the actual streak change, including any retained bonus. A build without this stat says None. During exposed-core typing the label changes to Boss damage: its percentage compares damage per new correct key with and without combo, after the boss damage cap. If the cap limits the benefit, the panel says Damage capped and states the raw streak separately. Shield commands and repairs label the bonus Streak ready instead of claiming to deal damage. Armory explains the per-combo gain, typo retention and cap using the active build's resolved equipment.

Score is the sum of defeated targets' performance receipts, defined in section 4.1. A word, kill, snap shot, boss, phase or wave does not grant additional flat points. Skipped text cannot score. Faster accurate work earns more points for the same original target; an unrewarded echo or reset cannot be farmed.

The Zone remains a feedback and contract-progress state. It lights after a combo of 20 with at least 96% accuracy over the recent 40 keys (at least 12 samples), tolerating one miss. Its time is recorded for Flow State and other progress, but it adds no Starfall score or per-second XP. Training and legacy run formats retain their prior Zone reward rules.

FOCUS is a combat aid: it halves mistake heat for 10 seconds, extendable to 20 seconds. It no longer doubles score.

7.8 Asteroids, rewards and flares#

ONLY AN ASTEROID PRODUCES A TEMPORARY POWER-UP, AND NOTHING ELSE IN THE GAME DOES. An asteroid is an OPPORTUNITY: it is excluded from the wave's mandatory work, it never blocks a wave from ending, it does not raise the required pace, and it can only hurt you by physically hitting your ship.

FieldMeaning
role: 'opportunity'Not counted as work anywhere: not in the wave budget, not in the threat meter, not in the wave-clear test
rewardTypeChosen when the rock is PLANNED, not rolled off the kill
collisionPolicy: 'player-hull-only'The base line is not an attack line for it
blocksWaveClear: falseIgnoring it can never delay progression
RewardEffectDurationCap
NUKESpends stored charge with a 20% damage bonus across eligible visible enemies; keeps unused charge and protects the current reading targetinstant
SHIELDRestores 22% of maximum hull and adds 20 shieldinstant60 shield
SLOWThe whole field descends at half speed8,000 ms16,000 ms
FOCUSHalf mistake heat10,000 ms20,000 ms
REPAIRCorrect typing repairs hull while invulnerable; each typo removes one second10,000 ms from activation50% of maximum hull

Destroying a rock reveals its named reward at the impact location. Typing, a deliberate weapon shot (including an area shot), or splash can earn it. Destruction and collection never activate the effect.

First discovery: the reward appears for 700 ms, then collects automatically into its empty slot. No typing, click or function key is needed. Its 600 ms collection flight finishes before solo play pauses for a guided game scene. The pickup never takes the current typing target. Collection stores the item; only later activation spends it. The lesson's copy is disposable, so watching it leaves the real pickup available. Skip or Escape returns to the same game. Discovery is saved per profile and survives reloads and profile sync. Multiple discoveries queue their lessons; protected encounters delay the next lesson.

Five fixed slots: F1 Shield, F2 Slow, F3 Repair, F4 Focus, F5 Nuke. Each type holds exactly one charge; the buttons are also clickable and touchable. Keys never shift when another slot empties. A key repeat cannot spend an automatically collected replacement. F1-F5 browser shortcuts are suppressed only while the game owns the keyboard; modified browser shortcuts and dialogs retain control. Some keyboards require Fn. The How to use button reopens the explanations.

Charged nuke: its finite total budget is stored charge * 1.2, shared across targets. It removes complete words, never a partial word. The entire locked target, partially typed targets and phrases awaiting a space are protected, as are bosses, typed-only objectives, opportunities and pickups. The slot previews estimated damage and charge spending, or explains why it cannot fire yet. Actual spending follows the words removed, so excess charge stays banked. With no affordable eligible work, both the item and charge remain stored. Nuke kills cannot chain splash or splitter spawns, and grant no false correct keystrokes or WPM. Optional power-ups remain excluded from the mission's loadout forecast.

Hull repair: F3 consumes a stored Repair, opens a typing passage and starts ten seconds of invulnerability. Correct characters restore hull, including spaces, with a repair sound on each healing key. Recovery is calibrated to 50% of maximum hull over ten seconds at the mission's reference typing pace, capped at 50% per item or full hull. Armour does not reduce healing. A full hull keeps the item stored. Each typo only subtracts one second, without combat damage penalties, heat, charge loss or a combo reset, and without advancing the cursor; typing the expected character resumes healing. F3 cancellation ends the attempt immediately.

Enemies, projectiles, spawns and boss clocks continue during repair, but incoming hits cannot damage hull or consume shield points while repair is active. A protective outline, INVULNERABLE countdown, blocked-hit ripple and sound show the protection. Reduced motion keeps a steady outline and blocked-hit label. Protection ends on completion, cancellation or timer expiry, including expiry caused by mistakes. Expiry immediately removes the passage and restores enemy targeting, even mid-word. The activation timer prevents unlimited protection without typing. Repair keys earn no weapon charge or combat damage. Their practice accuracy is recorded separately from combat productivity. Each typo is counted once. Cancellation, expiry, full hull and completed healing all return control immediately. Previously discovered EMP pickups migrate to Repair discovery.

Hull and shields have separate bars and point counts in the HUD, beside typing labels and on the boss/repair reading panel. Equipment can supply more starting shield than the 60-point pickup cap; the display preserves that capacity, and using a pickup never reduces an existing shield. Typing labels render above combat effects. Kill receipts move out of their way; notices yield visibility whenever they intersect current enemy text or the active reading/input panel.

Familiar pickups: the named drop appears for at least 700 ms, then fills its empty slot with a visible collection cue. Reduced motion uses a stationary confirmation instead of collection travel. If its slot is full, one spare drifts downward with a visible countdown and disappears after 15 seconds of active play. Use the stored item before expiry and the waiting copy collects automatically, without activating. There is one waiting drop per type; additional copies merge with that spare without resetting its timer.

Transitions: waiting drops carry their remaining lifetime across waves and boss fights. Pauses and protected review cards freeze their timer; active combat transmissions continue it. Familiar drops can fill an empty slot during combat transmissions. Stored charges have no timer, but both inventory and waiting drops end with the run. Neither drops nor stored items block wave completion, raise required WPM, receive damage or count as kills. Versus retains its shared clock: first discoveries explain themselves in a nonblocking notice instead of pausing the race.

The planned asteroid cadence is unchanged. At most two unbroken rocks are allowed on screen; full inventory no longer suppresses the opportunity schedule. Power-ups cannot generate other power-ups.

Stacking is centralised and capped. Timed effects extend up to their stated cap. A reward that would do nothing remains stored with an explanation; it is never silently replaced with a different effect. Controls are inactive while paused, on a transition or reward card, and after the run ends. During a boss, stored effects can be used, but a nuke clears escorts rather than the boss.

Cadence, not chance. In Home there is at most one opportunity in the air at once, at most two a wave, roughly one per 24 seconds of ACTIVE COMBAT TIME, and none before wave 2. Active combat time excludes every card, countdown and protected transition, so pausing can never accumulate a backlog of overdue rocks. Boss fights suppress them entirely (during a transmission the keyboard belongs to the paragraph, so a reward the player cannot choose to take is not an opportunity). After the last enemy, visible asteroids remain targetable until destroyed or until they naturally leave the field. Unspawned opportunities are discarded at wave end; they do not extend the wave. A boss introduction still sweeps loose asteroids without damage or reward. Revealed power-ups are separate and survive both transitions.

Collision means contact with the ship. Ordinary hostiles fire aimed shots when they reach attack range. A rock is not aiming at anything, so it is tested against the ship's own hull, SWEPT from its previous position to its next so a fast rock cannot tunnel through on a long frame, in simulation coordinates with the field's aspect applied. A direct contact damages the ship exactly once (10, before the sector and hull multipliers); a rock that crosses the base line anywhere else leaves harmlessly, with no damage, no miss, no combo loss and no penalty for having chosen to ignore it.

What this replaced. Every kill used to roll for a power-up: 85% from a "dropper" and 3% from everything else, and the drop spawned another typed target. That made a shield, a slow or a screen clear an ordinary consequence of playing rather than something you chose to go after, and made "can I survive this wave" a question about luck. And an asteroid used to damage the base for crossing the base line at any x position at all, which is why ignoring one felt punished.

Auto-fire never prefers a reward. The turret's shot, an untargeted discharge and an emergency flare all aim at the earliest ACTUAL damaging impact, skipping harmless pass-by rocks and skipping a target already guaranteed to die from a round in flight.

Emergency flares (Ctrl + Space) instantly destroy one threat during ordinary waves, prioritizing the enemy closest to the base. If only opportunities remain, a flare can destroy an asteroid and store its reward. Flares do not spend weapon charge and cannot be fired during boss fights.

Your module and its upgrades determine the rack capacity, capped at 8. Racks start full and refill to that capacity after every full boss victory. The victory screen shows how many were restored. Ordinary waves and mini-bosses do not refill them, and unused flares never accumulate beyond capacity. A loadout with no flares, including the Empty Racks gambit, receives none.

7.9 Difficulties and sectors#

Current solo typing workload is selected by numbered challenge tier (section 7.2a). Cadet, Pilot, Ace and Nightmare remain combat and salvage settings; neither adds a performance score or XP multiplier. The following catalogue fields are retained for training and legacy compatibility:

DifficultyLegacy XP and score multiplierLegacy speed field
Cadet0.8x0.75x
Pilot1.0x1.0x
Ace1.4x1.3x
Nightmare2.0x1.7x

Account level unlocks destinations: Home is open at level 1, The Belt at level 4 (480 lifetime XP), Deep Field at level 6 (1,150 XP), and The Rift at level 8 (2,149 XP). Operations shows each requirement and remaining XP; Armory repeats the requirements alongside equipment advice. Complete runs to bank XP. Training and Flight Check placement also count toward account level. Power remains a recommendation once a destination is open.

These are provisional milestones, estimated around successive opening thirds (roughly waves 1-17) at 40-50 WPM and 95% accuracy. They are not wave requirements: faster players earn XP sooner, slower players later, and charges reduce paid typing work. Existing saved boss clears preserve access to that sector. A stale locked destination falls back to Home when the hub or a solo run opens.

SectorRecommended powerSpeedDamage takenSalvageCoresBoss every
Home Sector01.00x1.00x1.00x1.0x5 waves
The Belt261.14x1.10x1.25x1.2x5 waves
Deep Field581.32x1.25x1.60x1.5x5 waves
The Rift921.55x1.45x2.20x2.2x4 waves

The sector's damage column multiplies what reaches your hull AND the health of a boss phase (a phase's health is the length of the transmission that opens it, times this number).

Skill substitutes for gear, at SKILL_POWER_PER_WPM = 1.2 points of power per WPM above the 40 WPM reference. So roughly every 10 WPM is worth 12 points of power, because a threat destroyed early never tests your hull at all. sectorAdvice() says this in words rather than blocking anybody.

7.10 The end of a run#

A run ends when the hull reaches zero, or when an optional duration expires (a timed Versus round, which counts as complete because the player played the whole thing). Leaving the tab or navigating away calls stop(), which abandons: no score, no XP, no History, no board, and only the keystrokes go to the skill model.

What Starfall reports to finishRun():

FieldContents
game, modestarfall, and the board scope (the difficulty, or versus)
completeWhether the run ended properly
durationMs, typed, correct, wrong, wpm, netWpm, accThe plain measurements
keysThe per-character and per-bigram tally, with timings
score, wave, combo, difficultyThe arcade extras
meta.eventsThe encounter ledger: what fired, whether it cleared, its multipliers, characters typed under it
meta.zoneMsMilliseconds held in the Zone
meta.sector, meta.lootMult, meta.gambitMultWhat was flown and what was bet
meta.medianMsMedian keystroke latency, for the worker

The game computes NO rewards. It reports facts, and js/run.js decides what they were worth.

7.11 The renderer#

Starfall draws on ONE canvas: the hand-drawn 2D view in js/games/starfall.js with the generated sprite layer from js/art.js over it.

It used to have a second, optional 3D view (Three.js and troika-three-text, vendored under vendor/, lazily imported, reached at its own /3d address behind a settings.render3d toggle). That view is retired (owner's call, 2026-08). It was removed rather than switched off: the module, the whole vendor directory, the import map, the /3d and /2d redirects, the setting, the URL switch, the Settings toggle and the probe3d() test seam are all gone, and with them the only third-party code this repo has ever carried. It is in git history if it is ever wanted back.

Two rules outlived it, because neither was really about having two views:

7.12 Art, and what happens when it is missing#

The flat view draws generated sprites over its hand-drawn shapes, and the Arcade and Armory are staged with rendered backdrops. js/art.js is the one module that knows where any of it lives; everything else asks by key and never hard-codes a path. ART_DIRECTION.md is the companion document that says how the art itself was made and what it has to look like.

Two families, with two different compositing contracts:

FamilyWhat is in itHow it is drawn
HologramsGear icons, the galaxy, the scrap and cores currenciesGlowing objects authored on pure black, composited additively (screen blend in the DOM, lighter on canvas), so they need no alpha channel and can never grow a halo
Solid craftThreat sprites, bosses, mini-bosses, hull renders, the player's baseReal alpha cutouts, because they occlude the starfield rather than adding to it

Vector fallback is law. Nothing that draws a sprite may assume it loaded: every caller checks spriteOk() and falls back to the hand-drawn shapes that shipped before any of this art existed. The app must play identically with assets/art/ deleted, the same way it already must play without webfonts and without Firebase. Every function in js/art.js is best-effort and silent, so a missing file downgrades the look and changes nothing else.

Two consequences worth knowing:

7.13 Four art styles, and how to change them#

Settings carries an Art style row with four complete looks for the same game. It changes pictures and nothing else: no rule, no number, no reward and no leaderboard reads it, so switching mid-account costs nothing and proves nothing.

StyleWhat you get
InkThe default. Cel-shaded craft with a hard ink line, flat colour and a lit rim, rigged in moving LAYERS like the pixel pack and the only style that shows your fitted gear ON the ship. assets/art-ink/, about 1.4 MB.
RenderedPre-rendered craft, holographic gear icons, painted sector vistas. The look that shipped first. assets/art/.
PixelHand-drawn pixel art, generated inside the repo by tools/build-pixel.mjs and composited in moving LAYERS by js/rig.js. assets/art-pixel/, about 51 KB for the whole set.
VectorNo sprites at all: the hand-drawn shapes underneath. The lightest of the four, and the one that proves the fallback guarantee above is real rather than theoretical.

A layered pack's layers are the simulation, drawn. This is the part worth knowing as a player, because it means the craft are telling you things the HUD would otherwise have to:

Proportion carries the rest of the report: a Warden is the widest craft in the game because it blocks, a Raider is the narrowest because it is fast, a courier is flat because it is carrying rather than fighting.

Two things are true of the Ink pack and of nothing else:

The weapons are the exception, and they are deliberately not drawn on the hull. A gun is the one part that has to be identifiable at a glance, and seen from directly above, small, and dark against a dark hull, it was not: it read as a lump on the exact part of the picture the screen exists to decide. So the two hardpoints are a pair of large slots across the base of the bay instead, split by a slash, carrying the weapon's own inventory art at a size you can recognise, its power, its position on the axis and the accuracy it pays off at. Presentation retreated where it was not earning its place and the decision got the room instead.

The sky behind the field belongs to no pack, and it moves. The playfield's backdrop is three bands of points and specks scrolling at three different rates. The nearest and fastest band is deliberately the faintest thing on the screen, because the words are typed over all of it. The scroll speeds up with how fast the field is really descending and is capped so it can never strobe under the text, and reduced motion slows the whole thing to a crawl. Which sector you are in is said by how thick the debris is and by the sector-tinted nebula behind it, never by a shape.

There used to be a fourth and furthest band carrying the sector's own architecture: a watch ring and traffic lanes over Patrol Space, rock shelves in the Belt, hulls at extreme range in the Deep Field, a torn seam and its wrecks in the Rift. It is gone (owner's call, 2026-08). Each of those was a large shape filled at half the surface token, which on a near-black stage is a visibly lighter patch with a hard edge, and the Home ring at playfield width was two hundred pixels across sitting directly behind the base. The band moved a pixel a second, which was meant to keep it out of the way and instead meant it read as a rendering artefact rather than as scenery. The rule that replaced it: a backdrop element is either small enough to read as texture or fast enough to read as motion, and large-and-nearly-still is neither.

ART_DIRECTION.md sections 8 to 12 are the full contract for the newer styles, including how to regenerate each pack, what every layer means, how the sky is built and how gear is socketed onto a hull.

The weapon you are firing is visible. weaponVisual() derives the turret's SILHOUETTE from what the weapon actually does rather than from its id: a splash weapon flares, a combo feeder carries its drum, a precision weapon lances. What it FIRES comes from the identity table instead, because a projectile has to be nameable from the corner of the eye rather than merely appropriate (section 7.15). Both are recomputed on every swap, so pressing Tab visibly changes the gun before a single shot is fired.

7.13 Music#

Four tracks, played by scene and crossfaded over 900 ms so a scene change is a dissolve rather than a cut:

SceneWhen
opsThe map room and every calm deck: the arcade hub, Training, Progress
hangarThe Armory
combatA live Starfall run
bossA boss or mini-boss encounter, back to combat when it resolves

Music is on by default at half volume, and both are in Settings. js/music.js creates no element and fetches no byte until music is enabled AND a scene is set AND the browser has seen a user gesture, so a visitor who never plays never pays for it. Every play() is best-effort: an autoplay refusal parks the intent and the first real gesture retries it, and nothing in the module throws, because a music failure must never cost a frame or a keystroke.

This is the one deliberate exception to "no audio assets". Keystroke-rate SOUND EFFECTS stay synthesized in js/audio.js, because they fire from keydown handlers and must never wait on a decode. Music is long-form and streamed, so files are the right tool for it and the wrong tool for a keypress.

7.13b What your build sounds like#

The sound describes the WEAPON THAT IS EQUIPPED, and the audio layer computes nothing. The keystroke blip used to climb a pentatonic scale off the RAW COMBO and, past fifteen characters, cycle inside the top octave forever. The gameplay underneath it is nothing like that shape:

The gameplayWhat the old sound said
The streak bonus is min(0.6, comboDmg * combo), and comboDmg is a RESOLVED stat: 0 on most weapons, 0.009 on a Chain Driver, 0.005 from a Tracer Feed, moved again by upgradesThe same combo of 40 sounded identical on all three, though it is +36%, +20% and +0%
The bonus CAPS, and past the cap a longer streak changes nothingThe blip kept climbing, which sounds like more power arriving
comboKeep RETAINS a fraction through a mistake: combo 40 can become 20 and +56% become +28%It fell all the way to the bottom, which is what a total loss sounds like
Most weapons have no streak stat at allIt played the whole ascending melody for a bonus that does not exist

The fix is not a cleverer mapping in the audio file: that would be a second copy of the equipment rules, and a second copy drifts. The simulation resolves ONE result per action, js/games/combat-feedback.js projects it into semantic facts from the SAME resolved stats the damage used, and js/audio.js renders those facts.

A musical rise with real state. The main short pluck rises from 220 to 880 Hz along a smoothly interpolated pentatonic contour as stored charge goes from empty to full. It holds at capacity and drops after charge is spent; a mistake does not empty the capacitor. A full cue sounds once on entering full, including weapons with no streak bonus. A quiet lower voice tracks the actual streak bonus independently. During boss transmissions the main note follows the streak bonus, since boss typing deals damage directly and does not bank charge. Sine and triangle voices keep this soft at fast typing speeds. Loadout offers separate charge and streak listening previews, using the same sound mapping.

Absolute bonus landmarks. The streak voice maps to the real bonus percentage at +0, +10, +20, +30, +40, +50 and +60, interpolated between, so the same +30% sounds like +30% on every build. Timbre identifies the weapon; it does not redefine what a percentage sounds like. Cap completion is a separate fact (atCap, capFraction), so a future weapon with a different ceiling cannot make "half of this weapon's maximum" and "+30%" the same sound. The bonus itself stays continuous: +20.7% is not rounded to +20% in combat to match a sound.

Loadout (base level, nothing else contributing)CoefficientCombo reaching +60%
Service Repeater, no streak mod0never: no streak bonus
Chain Driver alone0.01250
Service Repeater plus Tracer Feed0.00786
Chain Driver plus Tracer Feed0.01932

Those thresholds are DERIVED from resolved stats, never from item names: upgrades, attachments and gambits all move them.

Three facts, three cues. "Streak +30%", "this word is fouled" and "the capacitor is full" are three different mechanics, and the old single rising tone collapsed all of them into one. A mistake emits ONE composite consequence after every rule has applied: the error cue, then a transition DOWN to the bonus the player really has (ending at the retained value, not at zero), plus a separate restrained colour if the current word lost its clean output. A mistake that leaves the bonus still at its cap plays no streak-collapse sound at all. Keys pressed into an already blocked correction buffer get the plain error cue and never announce a loss a second time. A shield command reports a command action, never fictitious damage or charge. Retyping a boss character that already landed is ACCEPTED INPUT and not new output, and is reported as such.

And the HUD says the same thing. The strip carries the SCORE multiplier and the WEAPON bonus as two separate readouts, because they are two different mechanics and a x3 score chip was being read as damage. The combo tooltip no longer says "correct characters in a row", which combo protection made simply false.

7.14 The threat meter: Required WPM#

js/games/threat.js. One number, and it ships with its own sentence:

Threat, Required WPM: the sustained typing speed, at perfect accuracy, that would clear every WINNABLE threat before it deals damage, typing in deadline order.

It is not a mood ring. It is a schedulability bound, and it is worth knowing where it comes from, because the shape of the maths is what makes the number trustworthy.

The grounding. Every threat on the field is a job with two numbers: the characters still to be typed to neutralise it, and the seconds until it deals damage. The player is one processor. A set of jobs is clearable at a speed s exactly when, for every deadline, the characters due by then fit inside it (the processor-demand criterion for earliest-deadline-first scheduling on one machine). So the minimum feasible speed is the worst prefix:

sort jobs by deadline
demand = max over k of ( sum of chars due by deadline k ) / deadline k
Required WPM = demand * 12          (one word is five characters)

That is honest and it is also unusable raw, for two reasons, both of which get a surgical fix rather than a fudge factor.

Fix A, the deadline floor. As any single enemy's arrival approaches zero, its term approaches infinity, and a HUD number that runs away at the exact moment the player most needs to read it is worse than no number. Every deadline is therefore floored at FLOOR_S, 2.5 seconds, which is about perceive plus retarget plus type a short word: the granularity a human can act at. Every term is then bounded by the total outstanding characters over 2.5 seconds, so no denominator can reach zero and a closing threat SATURATES instead of diverging.

The floor's other half, which is not optional. Inside 2.5 seconds the number systematically understates: twenty-five characters due in two seconds reads as 120 WPM and truly needs 150. The number is a LOAD AVERAGE; the sub-floor urgency is carried per threat by the word plate itself (section 7.15). Ship one without the other and the metric lies exactly where it matters.

Fix B, triage. A threat no human could still save is not demand, it is history, and leaving it in the sum makes the number scream about work that cannot be done. So a threat leaves the sum when its characters exceed what 200 WPM could produce in the time it has left, and rejoins when it drops back under 85% of that line. The gap is hysteresis, so the boundary cannot flicker, and the exit is reachable in principle whenever a deadline GROWS (a slow field, a stall mechanic), which is why LOST is a state and not a tombstone. Watching the number collapse from 160 to the winnable residue IS the triage signal.

The knowable future. The spawn queue and its cadence are state, not a die roll, so spawns due inside the next six seconds join the sum as long-deadline jobs at their expected character count. Their deadlines are far away, so the maths discounts them naturally: a heavy wave three seconds out reads as a calm pre-warning rather than a spike, and nothing peeks at the random stream to produce it.

Weapon independence is a hard constraint. Characters are counted at the honest baseline: one correct character erases one letter, which is exactly what the starter weapon does. Splash already paid into a word, weapon bonus damage and the capacitor never enter. The number is identical whatever is equipped, which is what the owner asked for and what makes it comparable between two players and between two of your own runs.

And demand and supply are the SAME UNIT. Both sides are paragraph-equivalent characters, through js/games/typing-effort.js: the demand is what the field still asks for, and the capacity is measured from the work the player actually got through, not from the raw characters they pressed. Comparing a weighted demand against an unweighted supply is exactly the failure the effort model exists to stop, and it is why there are now two labelled WPM figures on screen (REQ at the top of the field, "Your WPM" in the strip) rather than two unlabelled ones that appear to contradict each other.

TermCounted as
The word being typedIts untyped letters, divided by that content's rate
The words behind it on the same craftTheir full length, plus the separators the craft will ask for
An acquisitionOnce per ENGAGEMENT, and NOT at all for a target already held. A live readout that kept charging the same third of a second every frame was most of why Required WPM drifted upward while the player was typing
A splitterPlus its children's OWN pre-costed work, from the plan's descriptors, rather than a flat eight characters nobody costed
A boss or mini-bossThe characters actually left in front of the player, capped by the plate, priced as paragraph prose; plus the transmissions behind it
A boss's escortsNOT added as manual typing jobs. During a transmission the keyboard belongs to the paragraph and the escorts die to the auto-fire that same typing drives, so counting their words would state a pace nobody could be asked to type
An opportunityNot a threat. Excluded, unless it is genuinely on course for the hull, which is real incoming damage
MistypesNever padded in. Errors are a capacity-side cost, and counting them on both sides would be double counting

Smoothing. The raw bound is stepwise (a kill removes a job outright), so the displayed value is an asymmetric exponential average: it rises fast (tauUpS 0.35 s, because danger arrives quickly) and falls slowly (tauDownS 0.9 s, which is the exhale after a cleared wave). It runs on sim time, so a pause causes no jump at all.

Pressure and the bands. The number stays ABSOLUTE, because "the field wants 90 WPM" means the same thing to everybody. The severity bands are RELATIVE: demand divided by a rolling measurement of what this player actually produces under load. That measurement is LOAD GATED, advancing only while there is something to type, because a twenty-five second intermission would otherwise decay it to the floor and make the next trivial wave read as an emergency. Sandbagging is not exploitable: typing slower lowers capacity and makes the bands more alarming, not less.

BandPressureWhat it means
0 CALMunder 0.35Coast
1 ACTIVE0.35 to 0.7Normal play
2 STRAINED0.7 to 1.0Feasible if you type cleanly
3 CRITICAL1.0 to 1.4You cannot clear everything. Triage now
4 OVERRUNover 1.4Losing ground

A band escalates only after the pressure has held over the line for a quarter of a second, and de-escalates only after it has sat safely under it for over a second, so the readout can never strobe between two bands at a boundary.

Bosses use attack intentions. During an encounter the required-WPM meter is hidden. The boss strip shows its next volley and time until launch, while hull and shields show how much damage the player can withstand. Escort interception shares the passage's typing, so escort words are not added as manual work.

Where it runs. As a derived pass inside the simulation, every sixth fixed step (10 Hz, so its dt is a deterministic 0.1 s), reading sim state and writing one output block. It is FEED-FORWARD: no gameplay code reads it back, it draws from no random stream, and it cannot change what spawns or how fast anything falls. A seeded replay is byte-identical whether the meter runs or not. Display quantisation (round to 1 under 120 WPM, to 5 above it, hold unless the value moved by 2 or settled for 400 ms) happens in the view, so the shown integer never flickers under the reader's eyes and the smoothing itself stays untouched.

ParameterValue
floorS2.5 s
capCps16.67 characters per second (200 WPM)
lostEnter / lostExit1.10 / 0.85 of that line
spawnHorizonS6 s
tauUpS / tauDownS0.35 s / 0.9 s
capacityTauS20 s, load gated
capacityClampWPM15 to 200
capacityWarmupChars50, before which the difficulty's reference pace stands in
tier reference WPMCadet 30, Pilot 50, Ace 75, Nightmare 90
bandsUp0.35, 0.7, 1.0, 1.4
band dwell up / down0.25 s / 1.2 s, de-escalating at 0.92 of the boundary
metricEveryTicks6 (10 Hz)
displayCapWpm240, shown as 240+
Versus capacityfixed at 60 WPM, so the same board shows the same band on every client

What it does under each situation is pinned by tools/check-modules.mjs, because the whole value of the number is that it behaves predictably:

SituationBehaviour
Empty screen0, CALM
A 40-character wave arriving in three secondsA gentle pre-warning around 30 WPM. Never a spike
A 25-second intermissionCapacity frozen, band unchanged across the lull
One tank, 20 chars, arriving in 30 s then 3 s then 1 sRises, then SATURATES at the floor. Never diverges
The same tank at 0.4 sEnters LOST, leaves the sum, the number glides down
That tank knocked back to 4 sExits LOST, rejoins the sum, its plate restores
Eight five-letter craft all arriving at onceAround 160 WPM, falling as the hopeless ones drop out
A hovering boss with no escortsMain 0, boss readout live. Correct
A mistype stormDemand unchanged, capacity falls, pressure rises. Honest
PausedFrozen exactly, with no jump on resume

7.15 Reading the field without looking at it#

The design law behind every readout added to the arcade, and the one to argue with before adding another:

The player's fovea belongs to the word they are typing. Design as if they never look away during a wave. Anything that requires reading text elsewhere on screen mid-fight is a design failure.

That leaves three channels, and every critical state has to arrive through at least one of them:

ChannelWhat it is good at
Peripheral visionMotion, luminance, position and extent. Hue poorly, text not at all
The word and its caretThe one place the eyes already are: glow colour, the typed prefix, the plate itself
AudioTimbre, pitch, intensity, with no visual cost whatsoever

Four rules follow from it, and they are why the HUD looks the way it does.

Identity rides orthogonal channels. Any two things that must be told apart differ in at least three of shape, thickness, colour pair, motion, particles, impact and sound, and at least one differentiator has to survive grayscale. That makes the whole scheme colourblind-safe by construction rather than by exception.

Changes announce, states confirm. A steady glow is adapted out within seconds, so a transition gets one short salient event (a pulse, a chime) and the steady state exists to be verified when the player has a moment. The precise numbers exist for confirmation, never for discovery.

Each system owns a region and a motion. So that the worst case (full charge, OVERRUN threat, low hull and a boss all at once) cannot collide in one channel:

SystemRegionMotionSound
ThreatTop and side edges, pill top centreBreathing in place, boundedTwo-note chimes
ChargeThe base, the bottom edge, the bar under the wordFilling, then travelling ALONG the edgeThe discharge, and the meter's own tones
Damage and hullFull-frame flash, the base itselfA single short flashThud
BossThe top strip, its own barIts own health bar drainingThe boss sting and the heavier score
WeaponsThe fire lane, the turret, the caretPer-weapon tracer signaturePer-weapon voice

Severity is intensity and rate, not just hue. A band change moves colour AND luminance AND thickness AND animation rate together, so it reads in far periphery and in grayscale. And motion is bounded: the vignette pulses on the change, breathes for about three seconds to announce itself, then holds STATIC. A standing strobe under maximum reading load is attention tax, and nothing anywhere modulates large-area luminance faster than a couple of hertz.

Reduced motion never means reduced information. Every cue has a static equivalent that says the same thing, listed with the cue.

CueFullReduced motion
Threat vignettePulse, breathe, holdStraight to the static hold at the band's opacity and thickness
Threat pillScale pop on a band changeThe number, the pips and the border colour, unanimated
Deadline tiersPlate outline pulsing at 1 to 2 HzThe static underline thicknesses and outline colours, which carry the same three tiers
Charge stripTravelling highlight when it can payThe strip at its fill, brighter when ready
Weapon tracersWobble, jitter, shimmer, embersShape, colour, thickness and trajectory, all kept, everything else dropped
Resume countdownDigits scaling inThe digits, plainly. The countdown itself is functional preparation, not decoration

The site's Motion setting now drives all of it: the arcade used to read the system preference only, so choosing Reduced in Settings quietly did nothing here. It resolves to either.

The per-word layer. This is where the threat number's two delegations land, on the exact plate they belong to:

ConditionTreatment
Arriving inside 4 sA 2 px amber underline
Inside 2.5 s (the metric's floor)A 3 px underline, an amber plate outline, a slow pulse
Inside 1.5 sA 4 px underline, a red outline, a faster pulse
LOST (the triage verdict)The plate desaturates, a diagonal strike draws across the word, and its opening letter stops being highlighted

A struck-through word can still be typed at: the strike is a view-layer verdict and the simulation is untouched, so a splash or a flare can still take it, and the player who insists is not blocked. It is advice with teeth, in the same voice sectors use about power.

Weapon identity. Every weapon fires a visibly different projectile, so a player whose eyes never leave the word can name what they are holding from the edge of vision. Eight shape families cover the catalogue, each with its own motion signature:

FamilyShapeMotionWeapons
BoltShort capsule, halo under coreFast, dead straightService Repeater, Arc Welder (slower, thicker)
MortarFat teardrop with an ember headLobbed parabola, dropping embersFlak Battery, Burst Cannon (smaller, quicker)
ArcJagged polyline in a sheathHitscan, geometry re-rolled every 33 msChain Driver
BeamRazor: white core, sheath, hazeInstant, then fadesRailgun (shimmer sweep), Lance (thin, ice-white), Longbarrel Cannon (short, amber)
FanFive dart slivers convergingFast, each dart wavering on its own phaseScatter Array
SlugOne massive round behind compression arcsSlow, grinding, with a smoke wakeBulwark Repeater
GlyphThe typed letters themselvesSteady, weaving, legible only early in flightNova Lance
WaveA sine rope with lit crestsThe phase SCROLLS along the ropeTempest Array

Weapons sharing a family differ in at least two other channels. Identity also reaches the fovea and the base: the turret's muzzle and rim light burn in the equipped weapon's halo and crossfade over 300 ms on Tab, the typing box wears the same pair, a kill draws a short ring in that colour AT the word that died, and the pause screen lists both hardpoints with a swatch and a one-line trait. WEAPON_IDENTITY.md carries the full recipes, including the flourishes no shipped weapon uses yet, so a future weapon lands inside the system rather than beside it.

A tracer is decoration and obeys the renderer rule: it reads the run state, never writes to it, and every decorative roll comes from Math.random and the wall clock rather than from the run's seeded streams. The hit was resolved by the simulation before the tracer was born.

7.16 Pause#

Pausing costs nothing, changes nothing that is scored, and is available at any moment of a solo run.

It is the clock, not a flag forest. The run has its own now(), and while the run is paused that function returns one frozen instant. Every timer in the game is expressed against it: the director's encounter clocks, the mistype stall, the jam, the next spawn, the breather, the elapsed time the WPM denominator is built from. So they all stop together and all resume together, with no jump and nothing to individually adjust, and no timestamp anywhere in the simulation is ever rewritten. It also means the pace a run is scored on cannot be diluted by pausing, which is the property that lets pause exist at all on a site that ranks people by speed.

TriggerBehaviour
Escape with nothing locked, or the HUD pause keyPauses
The tab going hiddenPauses. Before this, the wall-clock timers kept running while the frame loop slept, so a player who answered a message came back to a field that had happened without them
The keyboard catcher losing focus mid-waveOne silent refocus attempt, then a pause. A game silently eating keystrokes reads as frozen
A modal dialog opening over a live wavePauses
A Versus roundCannot pause. The key is refused and the button is not drawn, because a race against a shared clock cannot stop for one player

Keystrokes during a pause are dropped, not buffered. A buffered key would fire into a field the player did not watch evolve. Nothing is lost by dropping: the typed prefix of the current word is simulation state and is still there on resume.

Resume is a countdown, 3-2-1 over 1.8 seconds, and the simulation unfreezes at its end. Escape during the countdown backs out to the pause screen. Two details are there for phones and for fairness: the keyboard catcher is refocused inside the resume gesture itself (a mobile browser raises its keyboard only from a user gesture, so it comes up DURING the countdown rather than after the field is already moving), and for a moment after GO, any keystroke that was already in flight is ignored, so the key that resumed the run cannot also fire into it.

The pause screen dims and desaturates the frozen field behind a glass panel carrying the run so far in sim time, the peak threat reached, the band-coloured threat history, and the loadout legend, which doubles as the place to actually learn what each weapon's tracer looks like.

7.17 The flight recorder#

Every run records itself, always, into js/games/eventlog.js. Three consumers: the F8 timeline, the pause screen's sparkline, and the headless checker, which uses it as a test oracle to assert that the game did what the screen claims it did.

The hot path allocates nothing. A record is five typed-array stores and an increment: no objects, no strings, no formatting. Strings never enter the buffer at all, so a word travels as a character code and a length, an entity as its numeric id. That is what lets the log stay on during a 140 WPM run whether or not anybody ever opens it, and formatting happens only in the overlay or on export, both of which are allowed to be slow.

Two rings, split by provenance. Simulation truth (spawns, keys, kills, damage, metric transitions) and view-side happenings (pause, resume) wrap independently, so the sim record of two seeded runs stays comparable even when one player paused fifty times and the other never did.

Ticks, not wall clock. Every record is stamped with the run's fixed-step tick counter, which freezes with the pause, so a record's place on the timeline is a fact about the run rather than about the evening it was played on. A pause therefore has no WIDTH on the timeline and is drawn as a hatched marker carrying its real-world duration, which is the honest picture of "the run did not experience this".

Alongside it, a 1 Hz aggregate (kills, misses, damage, the raw Required WPM and the band it was in) is what the sparklines draw from. The band is recorded per sample deliberately: bands are pressure-relative, so they cannot be recovered from the WPM series afterwards.

The timeline (F8, live or paused, and it costs nothing until first opened) draws six lanes on one canvas, in a colourblind-safe palette where lane POSITION always co-signals with colour:

LaneCarries
FLOWMatch, waves, boss start and end, power-ups, pause and resume
THREATSSpawns, and the LOST verdicts
TYPINGOne progress bar per word from first keystroke to completion, with each mistype a notch beneath it
COMBATKills, discharges, splash, auto-shots, damage taken, jams
METRICBand changes, the Zone, encounters, boss encounter transitions
SYSTEMWeapon swaps, boss phases

Keystrokes deliberately never render as individual chips: ten seconds of fast typing would be an unreadable picket fence, so a word is one bar and a flurry reads as a handful of them. Records of one type inside a quarter second coalesce into one chip with a multiplier. The bar carries lane filters, live tail, wheel zoom from two seconds to three minutes, drag to scrub, click to decode a record, and an NDJSON export of the whole run.

8. Encounters: events, mini-bosses and bosses#

A wave counter that only ever spawns faster is a difficulty curve, not a rhythm. Encounters are the rhythm: three tiers of escalation that interrupt the ordinary run at different scales, each worth more than the minute before it.

8.1 The director#

makeDirector() decides what fires and when. It owns no rendering and no spawning: the game asks it for numbers and draws the banner itself.

RuleValue
Never during a boss waveA boss IS the event
Never two at onceOne encounter at a time
CooldownAt least 3 waves since the last encounter
Guaranteed introductionWave 3 always fires the Cargo Convoy, a gift with a banner on it, never a test
A ladder, not a flat deckEvery event has a minWave it cannot fire before, so the punishing ones wait until ordinary waves are familiar
Otherwiseclamp(0.22 + wave * 0.02, 0.22, 0.55) chance per wave
Mini-bossesOnly from wave 6, with a rising share of the pool
WaveChance an encounter firesMini-boss share of the pool
3guaranteed0%
634%15%
1042%24%
1348%32%
1654%39% (capped)
17 and up55% (capped)39%

Every choice is drawn from the run's seeded generator, so two players in a Versus room meet the same events on the same waves with no server dealing them. Nothing in js/games/events.js reads Math.random.

8.2 Events#

Short and frequent. A modifier plus a reward multiplier. The spawn block is a patch applied over the game's own numbers for the duration, so the game never branches on an event id.

EventFires fromDurationXP multChip multWeightWhat it does
Salvage Windowwave 11 in Home16 s2.2x1.6x8A SALVAGE WINDOW. It no longer replaces the wave with unavoidable rock: it doubles the opportunity cadence (still capped) and the ordinary wave carries on underneath it. Every rock is still built from your weakest keys, and every one of them is optional
Ion Interferencewave 522 s2.0x1.4x9Typos add 50% more heat while active; cooling and heat capacity help
Blackoutwave 11 in Home20 s2.5x1.6x7Uncommitted targets show only their opening letter
Scout Flightswave 420 s1.8x1.4x10Short drones and couriers, with acquisition priced and a 10% formation pressure discount
Overdrive Windowwave 715 s2.4x1.8x6Twice the normal clean-kill bonus while active
Precision Protocolwave 425 s2.2x1.5x8Double typo heat and triple clean-kill bonus while active
Cargo Convoywave 128 s1.6x3.0x6Larger ships with short escorts; completed work earns triple scrap while active. Guaranteed on wave 3

An event’s bonus window ends when its active timer expires. Its multipliers pay only for work completed while active; surviving an idle timer earns nothing. Heat and clean-kill modifiers reset immediately on expiry. The already planned ships retain their words and composition until cleared. The banner states the event’s actual effect, and expiry says “bonus window complete.”

8.3 Mini-bosses#

A stationary enemy with escorts and two or three transmissions. It trades fire until defeated or your hull reaches zero. It has no event timeout.

Mini-bossProfileLinesLength bandAttack patternInitial escortShield wordXP multChip multWeight
RaiderUnremarkable2short2 × 4 burst; 4 damage with drone cover3 dronesnone2.0x1.8x10
HarvesterPlated3short10 damage cannon; 5 damage with cruiser cover2 splittersnone2.2x2.0x9
WardenVolatile2medium7 damage pulse; 2 × 4 volley2 dronesBREACH2.4x2.0x7

A mini-boss's escort and shield are attached to its first line only. Its transmissions run 38 to 60 characters at the short band, 144 to 200 at medium, and it carries 16 short lines and 9 medium ones, so a mini-boss you meet three times in an evening has said something different every time.

8.4 Bosses#

The milestone, every fifth wave (every fourth in the Rift), is a named, multi-phase fight that tests more than sustained paragraph typing. A boss has a typing target 10% above its selected tier's nominal pace. Mechanical phases require original typed work that high boss-damage weapons cannot bypass.

Mechanical phase rotas#

BossOrdered mechanical phases
SentinelTwin shield relays; Break the formation; Precision weakpoints
Hive MindBreak the formation; Precision weakpoints; Twin shield relays
DreadnoughtPrecision weakpoints; Twin shield relays; Break the formation; Precision weakpoints
OracleTwin shield relays; Precision weakpoints; Break the formation

Twin shield relays. A generator on each side must be typed to open a limited core exposure. The left uses left-hand QWERTY words; the right uses right-hand words. Below nominal 60 WPM each uses one word; at 60 or above each uses two. They are visibly marked and immune to offensive charge shortcuts. A closed window restores the generators and repairs 4% of the core's fixed initial maximum health, bounded by that maximum. Mistakes and word-goal forecasts never increase that maximum or enlarge future repairs. Core health can reach zero mid-word, but the phase waits for that word to finish. An expired exposure also lets the current word finish before closing. Boss attacks continue during that word; a second word cannot extend the opening. The reading surface names and highlights the closing word, then the protected transition previews the returning generators without counting trailing keys. The exposure window is clamped to 5 to 18 seconds and priced against selected typing demand. Recreated generator work and reissued core text carry no fresh reward positions.

Every new generator, formation target, weakpoint and echo draws fresh real vocabulary from the shared lexicon and an expanded hand-specific word list. A separate seeded picker remembers words across the run, exhausts eligible unused vocabulary before recycling the least recently used words, and avoids matching target initials where possible. Returning shields draw new words; the deliberate Rewind mistake penalty still resets the same original words. Each replacement preserves its slot's character count, so vocabulary variety does not alter the forecast workload, attack budget or reward eligibility.

Break the formation. Distinct groups contain a typed-only Ward, a Brood ship and a Runner. A Brood can create an extra echo after a typing mistake, at most twice for that target. The extra enemies are pressure, not bonus score, XP or scrap. Regular charge tools can clear eligible unprotected enemies; boss damage bonuses never apply to formation ships. Below nominal 100 WPM there are two groups; at 100 or above there are three.

Precision weakpoints. Each group presents a marked Rewind target and a Weakpoint, both typed-only. A Rewind typo can reset its original words, at most twice. The wrong input still needs correction, and every original character position can earn a reward once. The same two/three-group threshold applies.

Boss attack timing is frozen from the selected challenge and the priced mechanical workload, never recalculated from the player's live WPM. Bosses hold position and repeat visible volleys; there is no global WPM deadline. Higher WPM usually reduces exposure to attacks. Accuracy reduces recovery and extra work. Damage to an exposed paragraph core is capped at 1.35 per newly typed character after equipment/profile modifiers, preserving a limited weapon advantage without allowing a boss weapon to erase the mechanical phase.

The arrival, and the reward review#

A boss used to spawn straight into its first phase: the transmission panel, the health bar, the descent and the damage clock all began in the frame the player was still finishing an ordinary wave in.

Arrival is now two steps. bossIntro builds the encounter, lays out the panel where the typing will happen, names what has arrived and states its first attack and defensive profile, and STOPS. Nothing runs: no clocks, no descent, no damage, no escorts. The boss wave sends no ordinary craft at all and any optional rocks still drifting are swept up first, so nothing competes with it. The Begin control arms after a protected entrance of 1,000 ms, and only a DELIBERATE action leaves: a fresh Enter, or the button. Ordinary letters and Space are consumed and score nothing, because they are typing and typing is exactly what the player was doing a moment ago.

Victory is resolved once, damaging actions stop immediately, the residual escorts are despawned with no kill credit and no drops (finishing off three drones after the boss is dead is an anticlimax and unpriced work), the encounter is SETTLED (17.4), and then bossVictory shows what was actually banked: the salvage, the duplicates and their conversion, the cores, the first clear, and the newly unlocked restart wave. It is frozen and has no timer. The player reads it for as long as they like, at a cost of exactly nothing.

Between phases there is no dialog. A paragraph reissue or an unexpected phase change gets a brief protected visual handoff (380 ms) without advancing combat, and the previous input batch is cleared so its tail cannot become mistakes on the next passage. Ordinary continuing characters inside one passage are never interrupted.

The input barrier#

An 800 ms timeout is not a barrier: a 90 WPM player beats it without noticing, so they finish a boss, keep typing for a beat, and the reward screen they never saw is gone, with those characters scored against their accuracy.

Crossing a protected boundary bumps an INPUT GENERATION. Everything about the old context dies with it: the correction buffer, the keyboard catcher's contents, the lock, and any multi-character batch a virtual keyboard is midway through delivering (the generation is checked between every character and the remainder is discarded). Keys physically held at the crossing are CARRIED: neither their release nor an auto-repeat of them may confirm, and a key has to be let go of and pressed again. Confirmation is a fresh Enter that is not a repeat and not an IME commit, or a pointerdown that BEGAN on the armed control in this generation. It changes state and returns: the same event may never also type the first letter, spend charge, fire a flare or dismiss the next panel. Tab is left to normal focus navigation so a keyboard user can reach the button, and blur or a hidden tab clears the held-key tracking so focus loss cannot leave a card permanently unconfirmable.

BossProfileRepeating attacks (base damage, before armour)Phases
The SentinelUnremarkable8 cannon; 2 × 5 volley; 5 damage with 2 drones3
Hive MindSwarming3 damage with 3 drones; 3 × 2 volley; 3 damage with 2 drones3
DreadnoughtPlated12 cannon; 3 × 4 broadside; 6 damage with 1 cruiser4
The OracleVolatile8 pulse; 2 × 4 volley; 5 damage with 2 drones3

Your typing is the weapon. While a transmission is live the turret has no target list: every CHARS_PER_SHOT (6, scaled by the weapon's fire rate, minimum 2) correct characters fires a round that destroys whatever is closest to your base. Type well and the escorts never arrive. Stall, or spray mistakes, and your guns fall silent exactly when the screen is filling up. The answer to "the boss is overwhelming me" is always "type better", which is the answer this whole site is built to reward.

Every boss hit uses hull combat. Armour reduces it and shields absorb it before hull is lost. A nonfatal hit leaves the encounter active.

Boss exchanges and equipment#

Bosses and mini-bosses hold position near the top and repeat visible attack patterns. There is no descent, breakthrough loss, mini-boss timeout, or overtime enrage. Lose only when your hull reaches zero; win by stripping all phases. Timed Versus rounds still end at their agreed round duration.

The attack intention shows the next volley, damage per hit after fitted armour, escorts, and seconds until launch. Shields absorb damage on impact. Cadence is frozen from the selected target pace and priced opening mechanical work: roughly seven volleys over a target-pace full-boss clear, three for a mini-boss, with a minimum four-second cycle. It repeats indefinitely rather than ending the fight. More health and armour buy more exchanges; weapons and accuracy shorten the fight.

Build or actionEffect during a boss exchange
Hull and damage reductionSurvive more incoming hits; attack damage never scales to your maximum health
Shields and Shield reserveAbsorb incoming damage; a reserve activated while shots travel still works
Phase breakDelays the next volley by a full cycle and applies fitted per-wave hull repair once
Precision and pierceAffect exposed-core damage, capped at 1.35 per new character; no bonus against generators, formations or weakpoints
Forgiving weaponsPreserve output; after-typo boss damage is capped at the clean rate to prevent intentional-mistake rewards
Area / splashA typed escort volley can intercept up to three / two nearby escorts
Fire rateControls the correct-key cadence of escort volleys
CoolingReduces heat and overheating interruptions
Repair / SlowRepair trades attack typing for hull recovery; Slow halves the boss attack clock and its projectiles
Flares / NukeRemove eligible escorts; typed-only Wards, Rewinds, Weakpoints and generators resist offensive shortcuts

Boss reinforcements respect a five-hostile cap. Escorts launch in nearby formations; their interception time includes shield commands and scales to baseline typing. A missed escort deals its class's base damage (drone 6, cruiser 11, splitter 7), without multiplying it by an unused word stack. Queued ordinary-wave spawns wait during a mini-boss. Repair never holds boss escorts or volleys. Phase breaks repair hull, while shields remain a finite reserve. Weapon swaps do not clear accuracy recovery. Stored capacitor charge is retained for normal waves. The recovery counter is shown below the passage.

8.5 Vulnerability profiles#

The reason a loadout is a counter-pick rather than a preference. A weapon choice that is simply "how I like to play" is a personality quiz; a weapon choice that is right for the Dreadnought and wrong for the Hive Mind is a decision.

ProfileNameClean damageFumbled damageSplashPiercePrefers
standardUnremarkable1.0x1.0x1.0x1.0xnothing in particular
armouredPlated1.0x1.0x0.35x1.5xprecision
swarmSwarming1.0x1.0x1.9x0.7xpressure
volatileVolatile1.0x0.75x1.0x1.0xforgiveness

The profile belongs to whatever encounter owns the field, so the Dreadnought's plating shrugs off a Flak Battery even while you are shooting its escorts.

Nothing enforces the counter-pick. loadoutAdvice() tells you in one sentence whether what you are carrying suits what is coming, and bossSchedule() puts the rota on the pre-flight screen so you can choose before the run. Bringing the wrong thing makes a fight harder, never impossible, which is the same stance sectors take about power.

8.6 Laps: the roster cycles#

Bosses arrive in order and the roster repeats. Each full lap raises the boss:

What scales per lapHow
NameGains a Roman numeral (Dreadnought II)
Attack damage+22% of base volley damage per lap
Scrap+35% per lap
Escort size+1 craft per initial phase escort per lap, subject to the five-hostile cap
Phase healthUnchanged (it is the transmission's length)

So wave 25 is the Sentinel again but meaner, rather than a boss nobody has met.

8.7 What an encounter pays#

Current Starfall scores all defeated enemy and boss objectives through the same measured target-performance formula. Neither an event multiplier nor a flat boss/phase/first-kill bonus grants additional XP or score. A powerful weapon cannot turn untyped boss text into performance rewards. Already paid positions, regenerated objectives and mistake-spawned echoes never pay again.

Cleared events have base combat salvage 18, mini-bosses 40, and bosses 120 + 40 * completedPhases, through the shared salvage scale from section 4.3. Enemy kills also pay their original carried-work salvage value. Separate encounter receipts still grant the authored loot, duplicate conversions, cores, first-clear tally and checkpoint once at victory. The run report itemizes those receipts rather than paying them again. A failed encounter grants no clear receipt. Legacy eventBonusXp/eventBonusScrap remain compatibility helpers for older run formats, not the current Starfall reward source.

9. Gear, weapons and builds#

Nine mounts, seven categories, fifty-three items. The catalogue is SIDEGRADES, not a ladder: every top-end item is better at what it does and worse at something else. Remove the downsides and the build system collapses into a shopping list where the best item is simply the most expensive one, which tools/check-modules.mjs checks for.

9.1 The slots#

SlotNameWhat it decides
weaponPrimaryWhat a correct character is worth, clean and after a slip. The accuracy bargain
attachmentPrimary attachmentTunes the primary toward precision or toward forgiveness
weapon2SecondaryThe other answer, one Tab away. Fitting one reduces heat capacity
attachment2Secondary attachmentTunes the secondary
hullHullHow much punishment the base takes before it is over
targetingTargetingMistake forgiveness, combo protection, and earlier reveals
coolantCoolantHeat capacity and how fast it bleeds off. Fewer jams
reactorReactorCombat salvage and the pace of the field
moduleModuleOne utility of your choosing. The panic buttons live here

A fresh profile owns and wears the starter of every slot, and the second hardpoint defaults to EMPTY rather than to the starter weapon: a one-weapon build is the default and the second mount is something you choose to fit.

What is fitted is the button that changes it. Clicking the item in a slot opens the slot picker: one popup listing everything that slot accepts, from the Armory's loadout and from the Arcade's pre-flight alike, because wanting a different weapon while reading the boss rota that made you want it is the ordinary case and walking to another tab to do it loses the sector, the rota and the launch button. It is the same list either way, and the screen behind it repaints with the new power and pace rather than being replaced.

The picker defaults to Owned. Each compact tile shows its icon, name, rarity border, upgrade level and equipped/owned status. Browse all gear reveals the complete catalogue, with search, availability and name/price/progression sorting. Weapons remain sidegrades; nothing ranks them by damage or power.

Hover or focus updates a shared inspector without changing equipment. Clicking or pressing Enter keeps an item selected; moving outside the grid restores that selection after previewing another tile. Escape dismisses a transient preview, then closes the picker. Touch uses the same inspect-then-equip flow.

The comparison is always visible. Selected and currently equipped items have separate adjacent panels with the same ordered rows. The row set is shared across all candidates for that slot so numbers do not jump around while browsing. Numbers describe the resulting build, including other gear, upgrades and gambits, with that mount active. Unchanged values remain visible. Green/red signed differences identify gains and losses; downward arrows mark stats where lower is better. All numerical effects are outside expanders. Optional item descriptions remain under About these items. An empty secondary is labelled as empty, never as the primary weapon.

The action names the destination mount and explains which item is replaced. The old item remains owned. Moving an item from another mount also identifies the source and what will occupy it afterward. Invalid moves cannot leave a primary weapon empty. Buying shows the Quartermaster's actual price and the currency shortfall, and the wallet stays visible in the dialog header.

Item power. Every item carries one number, on the same scale as the ship's own rating and a sector's recommendation: what that item alone is worth over the bare baseline, out of the same weights, stated at the upgrade level you own it at. So "Titan Frame, 49" reads directly against "the Rift recommends 92". It is signed and it is not floored at zero: an item that trades rating away for something the rating cannot see is an ordinary thing in this catalogue (a Chain Driver at -2 is buying combo scaling, a Glasswing at -4 is buying speed with hull), and a number that could only ever go up would be the ladder this catalogue is not. Two opposite weapons land within a point or two of each other on purpose, because they really are the same amount of gear pointed in different directions; what tells them apart is the axis.

9.2 What an item does, in words#

Every equippable item states itself in plain sentences wherever it is shown: on the Armory cards, in the picker, at the vendors, on the pre-flight hardpoints and (as a hover) on the kit icons. A stat row is only readable by somebody who already knows the mechanics, and the mechanics are exactly what a new player is trying to learn, so "+0.55 clean, -0.55 foul" becomes "banks 55% more charge per correct character while the word is CLEAN" and "banks 55% less after a slip, so a fumbled word earns you almost nothing".

Those sentences are DERIVED from the same stat deltas the game reads (explainGear() in js/gear.js), never written beside an item, so an item that is retuned cannot end up described by last month's numbers. Cosmetics get the same treatment and their sentence is the honest one: it changes how something looks and nothing else.

Beside each sentence is the same delta as a signed chip, gains in green and penalties in red. The two are separate tables in separate files (STAT_WORDS in js/gear.js, STAT_INFO in js/modes/picker.js) and nothing forces them to agree, so a stat that reaches only one of them draws no chip at all and says so to nobody. That has happened: the capacitor stats and the renamed flare stat were described in words while advertising "no effect either way" in numbers. tools/check-modules.mjs now compares the two key sets and fails on the difference by name.

9.3 The stat sheet#

The game reads the aggregate, never the items, so a new stat is one entry here plus one use in the game.

StatBaseClamped toMeaning
dmgClean10.5 to 3.2What a correct character is worth to the meter while this word is unfumbled
dmgFoul10.2 to 2The same after a slip on this word
chargeRate0.40.2 to 0.65Letters of charge per point of the two above. Well under one on purpose: see 7.5. Area weapons pay for their reach here
chargeCap206 to 128Letters of charge the active mount holds
blast00 to 0.45Discharge radius in playfield widths. Above zero makes it an AREA weapon, which spends blastCost per shot
stall24060 to 600Milliseconds the turret cannot fire after a mistype
splash00 to 1.4Fraction of a kill's word length paid into the nearest other threat's word
pierce10.4 to 2.6Multiplier against bosses and mini-bosses
comboDmg00 to 0.02Extra charge per point of combo, capped at +60%
fireRate10.5 to 2Multiplier on characters per shot in a transmission (lower is faster)
maxHp10040 to 400Base health
dmgMult10.35 to 1.4Multiplier on damage taken
regen00 to 30Health restored per wave or boss phase cleared
heatCap10050 to 320Heat before the turret jams
heatDecay208 to 80Heat bled per second
comboKeep00 to 0.85Fraction of the combo kept through a miss
assists00 to 8Typos protected from heat and firing delay per wave; correction remains required
reveal00 to 4Extra seconds a word is readable before it is in range
fieldSlow10.55 to 1.2Multiplier on descent speed (below 1 is easier)
scoreMult10.75 to 1.45Legacy compatibility only; never applied to current Starfall performance rewards
salvageMult10.8 to 1.6Scrap and drop quantity
flares00 to 8Emergency flares, which swat the thing about to land whatever the meter says
shield00 to 140One-off absorb at the start of a run

The two bold clamps are the ones that keep the central claim true. The floor on dmgFoul is the other important one: a fumbled word must always still be payable, or a slip with a Railgun would mean standing there typing forever, which is a punishment rather than a cost. The floors on chargeRate and the ceiling on stall are the same promise for the same reason.

How stats combine. Plain numbers add. scoreMult and salvageMult multiply. dmgMult and fieldSlow are reductions (a +1 upgrade makes a 0.9 into a slightly stronger 0.886, never a larger number). comboKeep takes the best rather than stacking. Only the LIVE hardpoint's weapon and attachment contribute, so carrying two weapons is never a way to add their numbers together.

9.4 Weapons#

The accuracy axis, running from "devastating while clean, useless after a slip" at one end to "never punished, never spectacular" at the other. Read the pairs as bargains, not as a ladder.

The axis is measured from two things, because its two ends are made of different stuff. The precision end is the SPREAD: how much more a correct character banks while the target is clean than after a slip, which is exactly what a Railgun sells. The forgiving end is REACH: splash and blast pay you for words you never aimed at, so a slip on the one in front of you costs less of your output. Blast counts for a little over twice its number, because the widest discharge in the catalogue is 0.34 against a splash that runs to 0.6 and the two should be worth comparable reach at their own tops. The whole thing is scaled so the CATALOGUE spans the track rather than a theoretical maximum spanning it: the baseline sits at zero, a Railgun at 0.97, a Flak Battery at -0.79, and all five bands (Suppression, Forgiving, Balanced, Sharpshooter, Precision) are occupied. Measured on the spread alone, as it was, the entire suppression half of the catalogue read "Balanced" and the left half of every axis track on the site was empty.

WeaponCostRequiresStat changesWhat it feels like
Service Repeaterfreeavailable immediatelyno charge generation or capacityType each word to destroy it.
Capacitor RepeaterHome boss 1 rewardAutomatically equipped on first receipt0.2 charge per correct key, 20 capacityFive words typed buy about one skipped word. Shift+Space fires.
Longbarrel Cannon375 scrapavailable immediatelydmgClean 0.4, dmgFoul -0.4, pierce 0.25Banks well on a clean word and sulks after a slip. The first step toward precision.
Scatter Array375 scrapavailable immediatelydmgClean -0.05, dmgFoul 0.15, splash 0.35, pierce -0.2Barely notices a mistake, and never hits hard. Splashes onto whatever is nearest.
Lance1,700 scraplevel 12dmgClean 0.55, dmgFoul -0.55, pierce 0.35, fireRate 0.1A clean stretch hands you free words. A fumbled one hands you none.
Flak Battery1,625 scraplevel 10dmgClean -0.1, dmgFoul 0.2, splash 0.6, pierce -0.35, blast 0.2, chargeRate -0.1Charges slowly. Each fixed-price shot clears a word from every marked target and keeps spare charge. Best against crowds, weak against armour.
Chain Driver1,875 scraplevel 15dmgClean -0.12, dmgFoul -0.18, comboDmg 0.012, chargeCap 4Weak on its own. Every point of combo feeds it, so it lives on unbroken streaks.
Arc Welder1,450 scraplevel 9dmgClean 0.05, dmgFoul 0.05, heatDecay 9, fireRate -0.1, chargeCap -4Steady charge and fast cooling, with a smaller reserve. Spend shots often.
Railgun4,800 scraplevel 26dmgClean 0.9, dmgFoul -0.75, pierce 0.5, fireRate 0.25, salvageMult 1.08High charge earnings and boss damage while clean, very low earnings after a typo. Also recovers more salvage.
Nova Lance18 coreslevel 32dmgClean 0.75, dmgFoul -0.6, pierce 0.6, splash 0.2, heatCap -18Precision and armour penetration with splash support. Mistakes and heat are the price.
Bulwark Repeater15 coreslevel 28dmgClean 0.05, dmgFoul 0.3, splash 0.5, maxHp 20, salvageMult 0.95Forgives everything, plated, and pays for it in ceiling. The endurance build, finished.
Burst Cannon1,275 scraplevel 11chargeRate -0.09, blast 0.16, blastCost -2, dmgFoul 0.1, dmgClean -0.05, pierce -0.15Affordable six-charge shells for small groups. Narrower reach than Flak; weak against armour.
Tempest Array18 coreslevel 31chargeRate -0.12, blast 0.34, blastCost 2, chargeCap 10, splash 0.25, dmgClean 0.1, pierce -0.2, salvageMult 0.96Wide ten-charge shells and a deep reserve. Save for a crowd; single targets are inefficient.

What those numbers actually do. With no attachment and no upgrades:

WeaponCleanFumbledSplashPierceMeterBlastStallAxisPowerClean characters for one free 7-letter wordFumbledThe one sentence
Service Repeater1.001.000.001.000.000.00240Balanced0Not availableNot availableTyping only: no charge attacks
Capacitor Repeater1.001.000.001.000.200.00240Balanced-153535Never beats the baseline
Longbarrel Cannon1.400.600.001.250.400.00240Sharpshooter31330Pays off above 88% accuracy
Scatter Array0.951.150.350.800.400.00240Forgiving31916Pays off below 95% accuracy
Lance1.550.450.001.350.400.00240Precision31239Pays off above 88% accuracy
Flak Battery0.901.200.600.650.300.20240Suppression52620Pays off on a crowd, not on accuracy
Chain Driver0.880.820.001.000.400.00240Balanced32022Pays off above 94% accuracy
Arc Welder1.051.050.001.000.400.00240Balanced31717Pays off at any accuracy
Railgun1.900.250.001.500.400.00240Precision61070Pays off above 86% accuracy
Nova Lance1.750.400.201.600.400.00240Precision91044Pays off above 86% accuracy
Bulwark Repeater1.051.300.501.000.400.00240Forgiving151714Pays off at any accuracy
Burst Cannon0.951.100.000.850.310.16240Forgiving62421Pays off on a crowd, not on accuracy
Tempest Array1.101.000.250.800.280.34240Suppression122325Pays off on a crowd, not on accuracy

Read the two character columns together: that is the whole design. Every one of these weapons destroys the word you type, on the character you finish it. What differs is what the typing EARNS: a Railgun hands you a free seven-letter word every ten clean characters and effectively never after a slip, while a Flak Battery is steady either way and takes a whole pocket of the field with it when it does go off. The power ratings say they are the same class of item, because power is a statement about gear and not about the pilot.

The last column is accuracyDemand(), and it is the number to choose by if you only read one: the accuracy at which that weapon starts beating the baseline. An area weapon deliberately never wins that comparison, because it is not trying to: it wins by taking three words at once.

9.5 Attachments#

One socket per hardpoint, and its whole job is to move the weapon along the axis. The obvious play is to double down (a Lance with a Focusing Lens); the interesting one is to correct (a Railgun with a Recoil Damper, which is still sharper than anything else and no longer catastrophic when you slip).

AttachmentCostRequiresStat changes
Empty Socketfreeavailable immediatelynone
Focusing Lens275 scrapavailable immediatelydmgClean 0.2, dmgFoul -0.15
Recoil Damper275 scrapavailable immediatelydmgFoul 0.28, dmgClean -0.1
Match Actuator1,350 scraplevel 14dmgClean 0.35, dmgFoul -0.35
Ballast Weight1,350 scraplevel 14dmgFoul 0.4, salvageMult 0.96
Splitter Prism1,200 scraplevel 11splash 0.3, dmgClean -0.1
Armour Piercer1,525 scraplevel 17pierce 0.4, splash -0.15
Overclock Coil1,275 scraplevel 13fireRate -0.25, heatCap -18, stall 45
Capacitor Bank1,100 scraplevel 10chargeCap 24, chargeRate -0.02
Reservoir Bank2,600 scraplevel 22chargeCap 48, chargeRate -0.03
Diffusion Cell1,275 scraplevel 12blast 0.1, chargeRate -0.04
Tracer Feed3,000 scraplevel 19comboDmg 0.007, dmgFoul -0.12
Gyro Mount1,625 scraplevel 16assists 1, dmgClean -0.1
Resonator12 coreslevel 30dmgClean 0.25, splash 0.2, fireRate -0.1, heatCap -15, dmgFoul -0.15

The Gyro Mount trades clean-word damage for an assist. Targeting-slot assistance has no score penalty. The Resonator is the one attachment that asks for nothing back, which is why it is priced in cores.

9.6 Hulls#

HullCostRequiresStat changes
Standard Framefreeavailable immediatelynone
Reinforced Hull275 scrapavailable immediatelymaxHp 25, chargeCap -2
Bulwark1,275 scraplevel 8maxHp 45, dmgMult 0.9, salvageMult 0.97
Aegis Plating3,600 scraplevel 18maxHp 55, dmgMult 0.85, shield 30, salvageMult 0.94
Mender Frame1,875 scraplevel 15maxHp 30, regen 9, chargeCap -4
Glasswing1,700 scraplevel 14maxHp -25, salvageMult 1.254
Titan Frame18 coreslevel 30maxHp 90, dmgMult 0.72, regen 6, shield 25, salvageMult 0.9

9.7 Targeting#

Targeting improves mistake forgiveness, combo retention and word visibility without reducing score. Duelist's Reticle instead offers a salvage bonus with less heat headroom.

TargetingCostRequiresStat changes
Open Reticlefreeavailable immediatelynone
Assist Module325 scrapavailable immediatelyassists 2
Combo Governor1,350 scraplevel 10comboKeep 0.5, assists 1
Predictive Lock3,450 scraplevel 20assists 3, reveal 1.2
Duelist's Reticle3,900 scraplevel 24salvageMult 1.18, heatCap -20
Oracle Sight15 coreslevel 28comboKeep 0.75, assists 4, reveal 2

9.8 Coolant, reactor and module#

CoolantCostRequiresStat changes
Stock Ventfreeavailable immediatelynone
Twin Radiator250 scrapavailable immediatelyheatDecay 10, stall -45
Cryo Loop1,275 scraplevel 9heatCap 45, heatDecay 14, stall -70, chargeRate -0.03
Run-Hot Manifold1,525 scraplevel 13heatCap -25, heatDecay -4, stall 80, salvageMult 1.242
Zero-Point Sink3,900 scraplevel 22heatCap 80, heatDecay 26, stall -110, salvageMult 0.96
ReactorCostRequiresStat changes
Standard Cellfreeavailable immediatelynone
Field Dampener475 scrapavailable immediatelyfieldSlow 0.92, salvageMult 0.96
Overcharged Cell1,200 scraplevel 7salvageMult 1.12, heatCap -15
Salvage Magnet1,625 scraplevel 12salvageMult 1.25, heatDecay -3
Flux Capacitor4,200 scraplevel 24fieldSlow 0.88, salvageMult 1.21, heatDecay -6, chargeCap -4
Singularity Core21 coreslevel 34fieldSlow 0.8, salvageMult 1.44, maxHp -20
ModuleCostRequiresStat changes
Empty Mountfreeavailable immediatelynone
Chaff Launcher350 scrapavailable immediatelyflares 2
Emergency Shield525 scrapavailable immediatelyshield 45, chargeCap -3
Time Dilator1,775 scraplevel 16fieldSlow 0.9, reveal 0.8, salvageMult 0.95
Charge Battery3,750 scraplevel 21flares 4, maxHp 15, heatCap -12
Anchor Protocol12 coreslevel 26comboKeep 0.6, heatDecay 8, salvageMult 0.94
Prospector's Rig15 coreslevel 30salvageMult 1.3, flares 2, maxHp -15

9.9 Upgrades#

Every owned item goes to +5. Each level is worth UPGRADE_STEP (14%) of the item's base stats, and an item's DOWNSIDES scale too: a +5 Glasswing is even more fragile, which keeps a sidegrade a sidegrade at every level.

scrap for the step from +n = round(basePrice * (0.35 + 0.30 * n * n))
basePrice for a core item  = cores * 420
the last two steps (+4, +5) also cost 2 and 4 cores respectively
ItemBase price+1+2+3+4+5Total scrapTotal cores
Assist Module325114211504991167434946
Lance17005951105263551858755182756
Titan Frame756026464914117182305838934812706

Upgrading a good item competes with buying the next one up rather than being strictly worse, and the core cost on the last two steps means the very best loadout still has a boss fight standing behind it rather than an afternoon of drills.

9.10 Power#

One number for "how kitted am I", the way an ARPG shows item level. It is compared against a sector's recommendation and shown on the loadout screen. A bare call rates the BETTER of the two hardpoints, because a player who brought the right weapon for half the fight is equipped for the place.

StatWeight per point above base
maxHp0.30
dmgMult-34
regen1.4
heatCap0.10
heatDecay0.55
comboKeep26
assists5.5
reveal6
fieldSlow-46
scoreMult16
salvageMult12
flares7
shield0.22
dmgClean15
dmgFoul13
splash10
pierce9
comboDmg220
fireRate-14

Survivability is weighted heaviest because that is what sector difficulty actually tests. dmgClean and dmgFoul are weighted almost equally on purpose: a Lance is only more powerful than a Scatter Array in the hands of somebody who stays clean, and if precision alone raised power the Rift would look gated behind a weapon rather than behind a decision.

9.11 Two hardpoints#

A loadout frozen for a whole run makes vulnerability profiles a gotcha: you meet the Dreadnought's plating with a Flak Battery in your hands and there is nothing to do but remember for next time. Carrying two weapons and swapping with Tab turns that into a decision made DURING the fight.

Three things stop it from being free:

CostValue
The swap drops your lockImmediately
Spin-upSWAP_MS 600 ms, during which damage ramps from SWAP_DAMAGE 0.5 back to 1
Fitting a second hardpoint at allheat capacity -10, whichever weapon is live; the legacy score factor is not applied

So a single-weapon build preserves that heat margin. The question is two specialists (answer more situations, trade heat headroom) against one specialist and an empty mount (answer one thing perfectly).

9.12 Gambits#

Opt-in handicaps, taken before a run, that change combat risk and salvage. They never multiply current Starfall performance score or XP. They stack multiplicatively. This is the pressure valve for a player who has out-geared their sector: rather than nerfing their gear, let them BET it.

GambitMultiplierWhat it removes
No Shield1.15xStart with no absorb, whatever your hull says
Empty Racks1.12xNo emergency flares
Hot Start1.18xEvery wave begins at half heat
Iron Discipline1.20xNo assists and no combo protection, whatever your targeting says
Paper Hull1.35xHalf the base health you would otherwise have
Sudden Death1.60xOne hit ends the run. Any hit

Gambits OVERRIDE gear rather than subtracting from it, so "no assists" means none regardless of what is bolted on. Taking all six multiplies rewards by 3.94x, and js/run.js clamps the applied multiplier to 4x.

9.13 The cheat#

Settings carries an Unlock everything button, and it is labelled as a cheat because it is one. It grants the whole gear and cosmetic catalogue through the same paths a drop uses, so an item unlocked this way is indistinguishable from one earned.

It exists for a plain reason: a build system nobody can browse is a build system nobody learns, and nothing on this site is gated anyway, so it takes away no content. What it takes away is the EARNING, which is most of the medium loop. It touches no XP, no level, no leaderboard and no scrap: you can still not afford the upgrades, and your boards still say what you actually typed.

9.14 Four builds that work#

Worked examples, because a stat table does not teach a build. Stat numbers below come from loadoutStats() for that set of items at +0. Charge damage is listed before the separate 1.35 boss-core cap; typed-only objectives ignore that bonus. All four builds leave the performance score and XP formula unchanged.

The Purist. Railgun, Match Actuator, empty second mount, Open Reticle, Glasswing, Run-Hot Manifold, Overcharged Cell, Empty Mount.

Charge damage2.25 clean, 0.20 fumbled (the floor)
Survivability75 hull, no shield, no flares, no assists, heat capacity 60
EarningSalvage x1.60, the equipment cap. Performance score and XP unchanged
Power rating0

Power 0 in the Rift, which recommends 92. That is the point: this build is not under-geared, it is geared for a pilot who does not intend to be hit. Add gambits until it stops being easy.

The Long Haul. Bulwark Repeater, Recoil Damper, Titan Frame, Oracle Sight, Zero-Point Sink, Flux Capacitor, Charge Battery.

Damage0.95 clean, 1.58 fumbled. A slip costs almost nothing
Survivability225 hull, damage taken x0.72, 25 shield, 4 assists, 4 flares, 75% of the combo kept, 2 seconds of reveal, heat capacity 168, field at 0.88x
EarningSalvage x0.99. Performance score and XP unchanged
Power rating179

Its hull, weapon and cooling trade some salvage for endurance; the reactor recovers most of that difference. Oracle Sight cushions mistakes.

The Counter-picker. Lance with an Armour Piercer for the Dreadnought on the primary, Flak Battery with a Splitter Prism for the Hive Mind on the secondary, Combo Governor, Mender Frame.

Primary1.55 clean, 0.45 fumbled, pierce 1.75
Secondaryforgiving and wide, one Tab away
Survivability130 hull, 9 regen per wave, 1 assist, half the combo kept
EarningPerformance score and XP unchanged; the second mount costs 10 heat capacity
Power rating40

The Prospector. Scatter Array, Recoil Damper, Aegis Plating, Assist Module, Cryo Loop, Salvage Magnet, Prospector's Rig, flown in the Rift.

Damage0.85 clean, 1.43 fumbled, 0.35 splash
Survivability140 hull, damage taken x0.85, 30 shield, 2 assists, 2 flares
EarningSalvage x1.53, which the Rift then multiplies by 2.2. Performance score and XP unchanged
Power rating72

Cores still only come from bosses, so even the farming build is about surviving to fight more of them.

10. Loot and the economy#

10.1 Two currencies#

CurrencyWhere it comes fromWhat it buys
ScrapTime and consistency: every run, every contract, every duplicateMost of both catalogues, and every upgrade
CoresONLY bosses and mini-bosses. Nothing else in the game produces oneThe Archivist's stock, and the last two upgrade levels of anything

Cores being boss-only is what makes a boss structurally worth starting rather than merely worth more points, and it is what the Archivist's stock is priced in. A contract that any run could finish must never pay one for nothing: the two contracts that do pay cores ask for a boss, a wave 15, or three clean runs.

10.2 Rarity#

Rarity is DERIVED from what an item costs and what it asks of you, rather than being a field on all 56 cosmetic entries. That keeps one source of truth: if an item is expensive or gated behind level 40, it IS rare, and the two can never disagree.

RarityColourDerived fromDuplicate valueBase drop weight
Standard#A4B2D2free, no requirement20% of costnever dropped
Polished#38DFD2anything cheaper than the bands below25%58
Rare#8B7BFFlevel 10+, or 1,000+ scrap30%30
Elite#F2B33Dlevel 22+, or 2,000+ scrap, or any badge requirement35%10
Legendary#FF5D8Flevel 40+, or 3,500+ scrap, or a badge plus 2,000 scrap40%2

An item may override this by carrying its own rarity, which is how a cheap thing can be made special deliberately.

10.3 Drop tables#

rolls is how many cosmetic cards the source turns over; scrap and cores are inclusive ranges; floor forces every roll to at least that rarity.

SourceCosmetic rollsScrapCoresFloorRarity weights (polished / rare / elite / legendary)
Event cleared010 to 260
Cargo Convoy cleared160 to 140078 / 20 / 2 / 0
Mini-boss killed145 to 900 to 162 / 28 / 9 / 1
Boss killed2140 to 2801 to 340 / 36 / 19 / 5
Boss killed for the FIRST time3220 to 4002 to 4rare30 / 40 / 24 / 6

All drop quantities are then multiplied by the sector's loot multiplier, the loadout's salvage multiplier and any gambit multiplier.

Only a CLEARED encounter drops. An undefeated boss grants no clear loot.

10.4 The three anti-frustration rules#

  1. A duplicate is never nothing. It converts to scrap at the rarity's rate and the reveal card says so. "You got something you already have, and it was worth nothing" is the fastest way to make a loot system feel hostile. Rolling also PREFERS items you do not own, so the duplicate path is a fallback rather than the common case.
  2. A pity counter guarantees an Elite or better within PITY_AT (6) rolls, applied to the FIRST roll of a batch so a guarantee does not become three. It is re-derived from what was actually GRANTED, so a roll that found nothing to give does not quietly eat a step of protection.
  3. A first kill floors at Rare. The first time you beat something should never pay out worse than the tenth.

10.5 The vendors#

Three shopfronts over the two catalogues, because a single undifferentiated shop is a spreadsheet and a shop with a face is a place you visit.

VendorCurrencyStockPricing
The QuartermasterscrapEverything, alwaysList price
The SalvagerscrapFive items, rotating at local midnight25% off
The ArchivistcoresPrestige stock onlyCores, which only bosses drop

The Salvager's five are drawn from a generator seeded on the DATE, so everybody sees the same five things on the same day with no server dealing them, and the countdown to the restock is the reason to look in tomorrow.

purchase() is the one payment path: it takes payment and grants in one block with nothing between the two lines that can throw, because "paid, not granted" is the one failure a player would never forgive.

10.6 Cosmetics#

Five purely decorative slots, 56 items. Nothing here affects gameplay. "Does this affect the game" is answered by which file an item lives in (js/cosmetics.js or js/gear.js), so the two are never blurred.

A cosmetic gated behind level 40 is legal precisely because it is a RECORD of reaching level 40 and changes nothing about play.

Ships (12)

ShipCostRequiresRarity
Standard IssuefreeStandard
Ember900Polished
Jade Runner1,200Rare
Nightshade1,500Rare
Drifter1,800Rare
Crimson Lance2,000badge: a 100 comboLegendary
Gilded Arrow2,200level 15Elite
Bulwark2,600level 25Elite
Void Cutter3,200badge: wave 20Legendary
Solar Flarefreebadge: 90 WPMElite
PhantomfreeStarfall rank 10Polished
Wardenfreelevel 40Legendary

Trails (10)

TrailCostRequiresRarity
VapourfreeStandard
Running DarkfreeStandard
Ion Wake700Polished
Ember Wake900Polished
Jadewash1,100Rare
Goldstream1,400level 12Rare
Aurora1,600level 20Rare
Ghostlight2,400badge: ten flawless runsLegendary
Solar Windfreebadge: three bosses in one runElite
NovafreeStarfall rank 15Polished

Keycaps (10)

KeycapCostRequiresRarity
SlatefreeStandard
Cream600Polished
Carbon800Polished
Mint1,000Rare
Amber1,200level 10Rare
Rose1,200Rare
Dusk1,500level 18Rare
Beaconfreebadge: 70 WPMElite
Ghostfreebadge: no weak keysElite
Championfreelevel 50Legendary

Name plates (10)

PlateCostRequiresRarity
Standard PlatefreeStandard
Steel700Polished
Beacon Plate1,000Rare
Amber Plate1,300level 14Rare
Rose Plate1,300Rare
Dusk Plate1,600level 22Elite
Void Plate2,000badge: wave 30Legendary
Jade Platefreebadge: 30 curriculum starsElite
Duellist Platefreebadge: ten Versus winsElite
Gold Platefreelevel 60Legendary

Titles (14)

TitleRequires
No titlefree
Cadetfree
Quick Fingersbadge: 50 WPM
Surgeonbadge: 99% over 600 characters
Regularbadge: seven day streak
Wavebreakerbadge: wave 20
Boss Killerbadge: six bosses in one run
Scholarbadge: every curriculum node cleared
Night Owlbadge: a run between two and five in the morning
Centurionbadge: 110 WPM
Duellistbadge: fifty Versus wins
Marathonerbadge: thirty day streak
Collectorbadge: twenty thousand scrap earned
Legendlevel 80

Every title is free: a title is a record of something, so charging for it would make it a purchase instead.

11. The Training Grounds#

The Training tab is two ladders stacked. The Academy on top teaches the keyboard; Flight School below it is the curriculum, which teaches speed. They are scored on deliberately different axes and neither gates the other.

11.1 The Academy#

"Slow is smooth, and smooth is fast."

Coverage and accuracy, never speed. A player who certifies the whole keyboard at 22 WPM has done exactly as well as one who did it at 90, because what is being measured is whether every key is under your fingers and whether you hit it correctly, which is the thing speed is built on top of later. There is no WPM, no latency and no time anywhere in js/academy.js. If you find yourself adding a speed term to that file, it belongs in js/skill.js.

Twenty one groups across four stages. The key pool is CUMULATIVE: a group's drill material may use its own new keys plus everything earlier in the ladder, which is why the drills turn into real words surprisingly early and why nothing already learned goes stale.

StageGroupKeys addedThe idea
Home KeysIndex Anchorsf jThe bumps. Find them without looking and everything else has an address
Home KeysMiddle Fingersd kOne step in from the anchors
Home KeysRing Fingerss lThe weakest fingers on the strongest row
Home KeysLittle Fingersa ;The outside edge
Home KeysThe Stretchg hThe index fingers reach inward. The hand does not move
Home KeysThe Whole Home Rowasdfghjkl;All ten mixed. The first real checkpoint
The Top Rowr and ur uUp, and back down to the bumps
The Top Rowe and ie iTwo of the most common letters in English
The Top Roww and ow oRing fingers up
The Top Rowq and pq pThe far corners. Everybody is slow here
The Top Rowt and yt yThe inner reach
The Top RowTop Row and HomeqwertyuiopTwo rows mixed. Most short English words are now reachable
The Bottom Rowv b n mv b n mThe index fingers go down
The Bottom Rowc and commac ,Middle fingers down
The Bottom Rowx and full stopx .Ring fingers down
The Bottom Rowz and slashz /The last two corners
The Bottom RowEvery Lettera to zThe whole alphabet in real words. The second checkpoint
The Whole BoardCapitalsA to ZShift with the opposite hand, never the same one
The Whole BoardPunctuation, . ' " ; : ! ? -What turns typed words into typed sentences
The Whole BoardThe Number Row1 to 0The row nobody practises, and the one that slows real work most
The Whole BoardSymbols!@#$%^&*()[]{}<>/=+_~ plus backslash, vertical bar and backtickThe last thing between you and the diploma

Drill material. Real words wherever the cumulative pool can spell them, because a beginner typing "dad" and "flask" is learning something a beginner typing "fjfj djdj" is not. Roughly half the items in a drill must contain one of the group's NEW keys, or a wide pool would quietly stop teaching the group it is named after. The earliest groups fall back to short alternating chunks, because there is no English word in "f j" alone. Nothing repeats twice in a row: a repeat reads as a stutter and stops testing the transition into the key.

Certification is judged from the SHARED per-key model, and that is what makes testing out honest:

BarValueWhy
keySamples20 pressesBefore the model is allowed an opinion about a key at all
keyAcc90%EVERY key in the group must clear this. The strict half
groupAcc95%One completed drill must have reached this
reps1At least one completed drill on the group

The per-key floor is what "completeness" means: not "the group averaged 95" but "there is no key in here you are still missing". And the evidence is read out of state.keys rather than kept locally, so a key drilled in the arcade, or measured by the Flight Check, counts exactly as much as one drilled here.

That is the whole route a proficient typist takes. The placement seeds real per-key data, testOutCandidates() lists every group whose keys already clear the bar, and one clean drill certifies each. They are through in a few minutes and into the arcade, where their time is better spent.

A beginner walks the ladder, and groupStatus().blockers tells them in plain words what is still missing ("3 keys not practised enough", "q, p below 90%", "a drill at 95% or better"), because a beginner should never read a bare "not certified".

Nothing here is gated and graduation unlocks nothing. Every group is startable on the first visit, in any order. Certifying one is worth 300 XP, the largest flat award outside a boss. Graduating the whole keyboard is worth 3,000 XP, the largest flat award anywhere, because that is the one big number a slow typist can reach on their first evening. What graduation produces is a diploma(): recognition, a date and a duration. Not a key.

11.2 Flight School: the curriculum#

Twenty nodes in five groups, an ordered walk rather than a set of locks. Every node is playable from minute one; what the walk provides is an ORDER and a recommendation, which is a different service from a gate.

GroupNodeMaterialCharactersSignpost pace
FoundationsHome Row Anchorshomeasdfjkl;18
FoundationsThe Home Rowhomeasdfghjkl;22
FoundationsReaching UphomeToptop row plus home25
FoundationsReaching Downlettersbottom row plus home28
FoundationsThe Whole Alphabetlettersa to z32
The whole keyboardCommon Wordscommon36
The whole keyboardCapitals and ShiftcapitalsA to Z38
The whole keyboardEveryday Punctuationpunct,.'";:!?-40
The whole keyboardThe Number Rownumbers123456789042
The whole keyboardSymbols and Bracketssymbolsshifted row, brackets, slashes45
Real textLonger WordscommonLong48
Real textSentencesprose52
Real textParagraphsprose56
Real textCodecode(){}[];=<>_.55
PrecisionClean Sweepcommon45
PrecisionYour Trouble Keysgenerated live from your model40
PrecisionAwkward Pairsgenerated from your worst bigrams44
SpeedSprint Burstcommonfifteen seconds flat out70
SpeedTwo Minute Cruiseprose74
SpeedThe Long Haulprosefive minutes without a fade78

The signpost pace is not a gate and not what stars are measured against. Stars come from beating your own baseline (section 4.2). The goal number is there so the card can say what this material is usually comfortable at, and so the recommender can tell that a 110 WPM typist has no business being sent to the home row (OUTGROWN, 1.3x measured speed).

The two adaptive nodes are never skipped. Your Trouble Keys and Awkward Pairs build their material from the model, so their difficulty tracks whoever is typing: a 120 WPM typist still has a weakest key and a pair their fingers argue about, and drilling those is exactly what is left to do at that speed.

12. Flight Check: the sprint#

One surface doing three jobs.

12.1 The three jobs#

  1. The sprint. A timed typing test, a quote, or a drill on your own weakest keys. It reports through finishRun() like every other game, and the two timed modes carry leaderboards.
  2. The drill surface. Every Academy lesson and every curriculum node runs here. The Training Grounds hands it an explicit word list plus a meta tag, and that tag rides into the RunResult so the funnel scores the right thing. An Academy drill leads its results screen with accuracy and the per-key breakdown rather than a WPM number, because that is what it was judged on.
  3. The placement. See section 4.5. It runs a 60 second sprint and then grants, seeds and reports, and it deliberately does NOT go through finishRun().

12.2 The modes#

ModeClockMaterialRanked
60 seconds60,000 msMixed everyday wordsYes
15 seconds15,000 msMixed everyday wordsYes
QuoteuntimedOne of 20 real passages, punctuation and capitals attachedNo
Weak keys45,000 ms46 chunks built from the keys the model says are letting you downNo

Why the timed passage is NOT adaptive, when everything else on the site is: a board where each player typed material chosen for them is a board that compares nothing. So the timed modes and the placement all draw the same mixed passage of everyday words. Personal material lives in the Weak keys mode and in the Training Grounds, where nothing is ranked against anybody else.

Passage length for a timed run is sized at 22 characters per second, which is 264 WPM: comfortably past the fastest human on record, so nobody can reach the end of it.

12.3 Reading and the caret#

Three lines are visible and the caret rides the second one, so there is always a line of what is coming next below it. A fast typist reads ahead instead of typing into a wall.

A gap longer than 2,000 ms is treated as somebody answering the door rather than a slow reach, and is not folded into a key's mean latency.

13. Versus#

Head to head racing, for signed-in players with a claimed screen name.

13.1 Why Firestore and not the worker#

Everything else on this site talks to a Cloudflare Worker whose store is KV: eventually consistent, which is exactly right for a leaderboard and exactly wrong for a race. Two people typing against each other need each other's progress inside a few hundred milliseconds and they need it PUSHED. Firestore gives both, on the identity pool the site already authenticates against, so Versus costs no new service.

Four collections, no composite indexes: typePlayers (a presence card per account), typeLobbies (the room code IS the document id, so a shared link is a direct lookup), typeGames and typeChats.

13.2 The two formats#

Nobody referees. Both formats are built from a SEED in the game document and every client builds the identical race from it through mulberry32.

FormatLengthBuilt from the seedScored on
Starfall90 sThe whole spawn schedule up front: 4 + min(9, wave) threats per 11 second wave, each with its word, entry position and descent ratePoints
Sprint340 characters, hard stop at 210 sThe same passageNet WPM

A threat's position is a pure function of the shared clock (spawn moment, descent rate) rather than something integrated frame by frame, so a phone that dropped ten frames is still looking at exactly the same sky as the laptop it is racing. A client that reloads mid-race meets everything that fell while it was away in one frame: those words really did land on its base, so they cost what they cost, but they are not drawn or sounded.

Each client grades itself, which is safe because there is nothing secret here: the word lists ship in js/words.js either way, so a server holding the answers would be guarding a door with no wall attached. What the design DOES guarantee is that nobody can write anybody else's numbers, and that is enforced by the Firestore rules (a seat is a key in a map and only its owner may touch it) rather than by good manners.

13.3 Race tuning#

ConstantValue
Room code5 characters from ABCDEFGHJKLMNPQRSTUVWXYZ23456789 (no I, O, 0 or 1)
Seats per room6
Countdown5,000 ms
Starting hull (starfall format)100
Wave length (starfall format)11,000 ms
Threat damage7, or 13 for a long word
Seat heartbeat15,000 ms
A seat is not counted after46,000 ms of silence
Host considered gone after90,000 ms
Progress pushedEvery 500 ms, throttled
ChatLast 40 lines, 240 characters each

13.4 What a race never touches#

Not the skill model, not the curriculum, not state.games, not the Academy, not History, not a solo leaderboard, and it does not go through finishRun() at all. A race is a different measurement (a shared seed, other people's pressure, nothing chosen by the player) and letting it feed the same numbers would quietly make two things one.

The only account-level trace is state.mp:

FieldMeaning
playedRaces finished
wonRaces won, which requires at least one opponent
pointsRanking points: max(1, playerCount - yourPlace), or 1 for a solo race. Raw scores are not summed because a starfall score and a sprint WPM are different units
bankedThe last 40 game ids, so a reload cannot count a race twice

Four versus badges read that tally on the next completed SOLO run, and a win may post to the versus wins board if the player has opted into leaderboards.

13.5 The four reliability rules#

Each was a bug first on the sibling site, and every one is load bearing:

  1. A listener's first snapshot comes from the local cache and can be a version behind (a transaction never lands locally), so nothing destructive may act on a snapshot until vsFresh() says the server confirmed it.
  2. A dotted updateDoc CREATES the map it writes into, so every seat write goes through vsTouchSeat, a transaction that only writes a seat that still exists. Because that is a server read every fifteen seconds it doubles as the backstop for a wedged lobby listener.
  3. Firestore's error callback is TERMINAL, so every long-lived listener is attached through vsWatch, which re-opens with backoff and never gives up on a connection error (only on a rules one). Everything re-opens at once on visibilitychange and online, because backoff measured against a sleeping clock is the wrong shape.
  4. A result is banked exactly once per account, guarded by state.mp.banked and persisted.

14. The meta layer#

The loops below the run. Everything in js/run.js closes inside a single run; everything here is what makes tomorrow worth turning up for. Each piece is a named idea rather than decoration, and nothing in it is a lock: a contract you ignore costs you nothing, a broken streak takes nothing away that you already had, and ascension is opt-in.

14.1 Contracts#

The Zeigarnik effect: an unfinished, clearly stated task nags in a way an open-ended one does not. Three daily and one weekly, each a single sentence with a number in it, seeded from the date so everybody gets the same set with no server dealing them. The three dailies are drawn without replacement and never two that track the same thing, because three "type N characters" contracts is one contract wearing three hats.

Daily contractGoalScrapCores
Keep Typing1,200 correct characters120
Long Shift2,500 correct characters220
Three SortiesFinish 3 runs of anything140
Hold the LineReach wave 10 in Starfall180
Deep PatrolReach wave 15 in Starfall2601
BountyBring down a boss2001
Clearing WorkKill 2 mini-bosses170
Steady HandsFinish a run at 97% accuracy or better200
Smooth Is FastFinish 3 runs at 97% or better3001
UnbrokenReach a combo of 60190
In the ZoneSpend 45 seconds in the Zone240
Academy BusinessCertify an Academy key group220
Range TimeFinish 2 Academy or Training drills150
Storm ChaserClear 3 field events180
Time TrialFinish a Flight Check sprint130
Weekly contractGoalScrapCores
The Long Week15,000 correct characters9002
Boss HunterBring down 5 bosses1,1003
Into the DeepReach wave 25 in a single run1,0003
Academy TermCertify 4 key groups9002
Precision Week10 runs at 97% or better1,0002
Flow State5 minutes in the Zone1,2003

Wave and combo contracts take the BEST single run rather than a sum, which is what the wording promises. A finished contract waits to be CLAIMED: collecting a reward you can see is worth more than one that lands silently, and the claim is the reason to open the panel tomorrow.

14.2 The streak#

Loss aversion, deliberately blunted. A streak that shatters after one missed day punishes exactly the person who was ill, and they do not come back.

RuleValue
AdvancesOnce per local day, on any completed run
Insurance earnedOne token every 5 days kept, capped at 3
Insurance spentAutomatically, on the first day you miss
What insurance doesPreserves the streak at its current length rather than growing it
Daily bonus in training / legacy formatsmin(200, 20 + days * 12) scrap and min(500, 60 + days * 28) XP; current Starfall tracks the streak without this flat award

The bonus flattens because a bonus that keeps growing turns a game into an obligation.

14.3 The comeback bonus#

The likeliest moment to lose somebody is the run after a long gap, so that run pays extra instead of showing them how much they missed. After 5 days away, the first completed training or legacy-format run pays clamp(round(120 * min(days, 30) / 5), 120, 700) XP. Current Starfall keeps performance XP tied to the defeated targets and adds no comeback XP.

14.4 The Zone and ascension#

Covered in sections 7.7 and 4.7. Total time in the Zone accumulates in state.meta.zoneMsTotal and feeds the weekly Flow State contract.

15. Achievements#

Sixty two badges, each a single pure predicate over the state and the run that just finished. checkBadges() stamps state.badges itself, so a badge can never be granted twice. Badges earned in current Starfall are recorded without flat badge XP. In training and legacy formats, badge XP lands on the ACCOUNT only, never on a game's own XP: a game rank is a measure of how much of that game you have played, not of how many account-wide milestones happened to fall while you were playing it.

Mileage

BadgeXPRequirement
First Flight100Finish your first run
Ten Sorties150Finish ten runs
Fifty Sorties300Finish fifty runs
Hundred Sorties500Finish a hundred runs
Five Hundred Sorties1,000Finish five hundred runs
Ten Thousand Keys200Press ten thousand keys
A Hundred Thousand Keys450Press a hundred thousand keys
A Million Keystrokes1,200Press a million keys

Levels

BadgeXPRequirement
Recruit100Level 5
Ensign150Level 10
Lieutenant250Level 20
Commander400Level 30
Ace700Level 50
Vanguard900Level 75
Grandmaster1,200Level 100

Speed

BadgeXPRequirement
Thirty Club120A run at 30 WPM or better
Fifty Club20050 WPM
Seventy Club32070 WPM
Ninety Club50090 WPM
Hundred and Ten750110 WPM
One Thirty1,100130 WPM. Professional pace

Accuracy

BadgeXPRequirement
Not One Miss250A run of real length with no mistyped character
Ten Times Flawless600Ten flawless runs banked
Surgical40099% accuracy over six hundred characters
Perfect Wave200Clear a whole wave without one mistyped key
Five Perfect Waves450Five such waves in one run
Steady Hand30097% accuracy for a full minute of sprint

The arcade

BadgeXPRequirement
Wave Five120Reach wave 5
Wave Ten220Reach wave 10
Wave Twenty450Reach wave 20
Wave Thirty800Reach wave 30. The words stop being words
Boss Down200Your first boss
Three Down350Three bosses in one run
Fleet Breaker700Six bosses in one run
Chain of 25120A 25 character combo
Chain of 50250A 50 character combo
Chain of 100500A 100 character combo
Chain of 200900A 200 character combo
On Fumes400Finish a run with a tenth of your base left
Not a Scratch500Reach wave 10 without losing any hull
Perfect Storm900Wave 10 with a hundred combo and not one mistyped key

Learning

BadgeXPRequirement
First Clear150Clear your first curriculum node
Ten Stars250Ten curriculum stars
Thirty Stars500Thirty stars
Full Sweep800Clear every node at least once
Perfect Curriculum1,200Three stars on every node
No Weak Links700Every key you type often at 95% or better
Old Enemy450Bring a key you used to miss constantly back to 97%
Flight Checked100Take the Flight Check and get placed

Everything else

BadgeXPRequirement
Quartermaster200Earn a thousand scrap
Outfitter400Earn five thousand scrap
Collector800Earn twenty thousand scrap
Contender200Play ten Versus games
First Blood200Win your first Versus game
Ten Wins450Win ten Versus games
Fifty Wins900Win fifty Versus games
Three Day Streak200Play three days in a row
Seven Day Streak400Seven days in a row
Thirty Day Streak1,000Thirty days in a row
Full Roster500Finish a run of every game in the arcade
Night Owl300Finish a run between two and five in the morning
Second Wind400Come back after a month away and set a personal best on the first run

16. Leaderboards, accounts and identity#

16.1 The boards#

The Leaderboards tab opens on Starfall wave score, with a separate wave scrap category. Sector, combat difficulty, numbered challenge tier and wave selectors compare like with like. Both also carry the rules version performance-v1. The two independent personal bests may come from different attempts, and each column shows the measured WPM and accuracy from its own attempt.

Board familyRanked onScope
Starfall wave scoreBest performance points on a cleared waveRules, sector, difficulty, tier, wave
Starfall wave scrapBest credited combat salvage on a cleared waveThe same exact scope
Sprint, 60 / 15 secondsNet WPMSprint duration
Starfall Cadet / Pilot / Ace / Nightmare (legacy)Earlier cumulative pointsEarlier adaptive rules only
Starfall deepest wave (legacy)Earlier depthEarlier adaptive rules only
Account levelAccount level, backed by lifetime XPAccount
Versus winsRaces wonAccount

Progress has a Starfall wave-record card and a direct Compare on leaderboards button. The save keeps 600 wave scopes with the most recently improved bests, bounded for cloud sync. Existing history, gear, currency and legacy bests stay intact; old aggregate totals cannot be invented into per-wave records.

Strictly opt-in. Posting needs the existing opt-in and signature. A cleared wave is submitted when a finished run banks, including earlier clears in a run that later ends in defeat. A half-finished wave or abandoned run is excluded. Checkpoint attempts rank within their exact wave scope. Opting in or signing in can resync saved bests; pending sends recheck consent and identity.

The shared big-world-quiz Worker owns two new routes: POST /typing/wave-score with up to 64 wave samples in one batch, and GET /typing/wave-board with a versioned board identifier. New data uses its own typing:wave: KV namespace. It never shares earlier typing:board: Starfall scores. The server validates the whole batch before writing, checks finite bounded counters and duration, recomputes WPM and accuracy, and bounds score by the maximum per-character performance reward. Score and scrap preserve separate winning evidence and server timestamps. Replays keep existing equal or higher bests.

These are plausibility checks for a local client, not an authoritative replay or proof against a modified client. Verified names prove account identity, not competitive input integrity. Guest and account storage keys are separated. Every remote name is escaped before rendering. Worker KV remains eventually consistent, so simultaneous submissions are subject to that backend's limits.

The Worker is a separate deployable. Until its update is available, local records work and the new boards show an availability error. A client rejects a response without the matching rules version and board, rather than displaying an incompatible legacy table. Existing sprint, level, versus and legacy board routes retain their earlier behavior.

16.2 One identity, three save files#

The same Firebase project authenticates Big World Quiz, Big Piano Quiz and Big Typing Quiz, so one account and one verified screen name work everywhere. Progress does NOT: this site syncs to its own collection.

SiteFirestore collection
Big World Quizusers/<uid>
Big Piano QuizpianoUsers/<uid>
Big Typing QuiztypingUsers/<uid>

Screen names come from the shared registry at /name on the worker, which is the source of truth. SN_NAME_RE and SN_RESERVED in js/state.js mirror the worker's rules and are mirrored a third time in big-piano-quiz; the worker will refuse anything they let slip.

Everything works signed out. Firebase is lazily imported on first use, the account area is hidden entirely when it is not configured, and a fully local profile loses nothing except cross-device sync and Versus.

17. Data model and persistence#

Everything the player owns lives in ONE localStorage blob under typingQuiz.v1, and the whole blob is what syncs to Firestore.

BranchContents
profilePlacement record: placed, placeOffered, placeWpm, placeAcc, placeLevel
xptotal, level, scrap, cores, earnedScrap
gearowned (id to level), equipped (slot to id), gambits
lootopened, pity, best, byRarity
metaContracts, streak, ascensions, lastRunAt, zoneMsTotal
gamesPer game: xp, rank, plays, timeMs, best by mode key, badges, bosses
keys, bigramsThe per-key model, capped at 140 and 400 entries
curriculumPer node: stars, plays, bestWpm, bestAcc, baseWpm
academyPer group: reps, chars, bestAcc, certified; plus graduated
skillruns, chars, ewmaWpm, ewmaAcc, bestWpm, bestAcc; plus baseline (the PARAGRAPH baseline: wpm, source, acc, durationMs, at, confidence) and contexts (observed prose / words / phrase / random pace, kept BESIDE the baseline and never blended into it)
progressStarfall's own versioned progression: `starfall['<sector><difficulty>tier:<N>'] (plus retained legacy scopes) = { cleared: [wave...], every }, the receipts grant ledger that makes an encounter's reward idempotent, and one pending` receipt whose save failed
badgesid to { at, n }
cosmeticsowned list and equipped per slot
historyNewest first, capped at 200 runs
waveRecordsUp to 600 versioned sector/difficulty/tier/wave scopes, each with separate bestScore and bestScrap evidence
settingsSound, music, difficulty, sector, nullable challengeTier (1 to 19 after recommendation), keyboard, caret, motion
lbLeaderboard opt-in, signature, country
mpVersus tally and banked game ids

Three rules hold this together:

  1. normalizeState() is the only source of shape guarantees. Any path that replaces state wholesale (boot, cloud adopt, clear all data) runs it, it is safe to run twice over the same object, and every new field is added there as well as in freshState().
  2. saveState() is the ONE writer. It stamps updatedAt and pokes the cloud through a hook, so a mutation can never quietly skip the sync.
  3. The blob has to stay small, because it syncs. That is why History, keys, bigrams, grant receipts and banked race ids are all capped.

17.4 Encounter settlement#

A boss pays when it dies, not when the run does, and it pays once. js/encounter-rewards.js is the service; js/run.js reads the receipts it left rather than rolling anything of its own.

RuleWhy
The encounter id is run : sector : difficulty : wave : kind : id : #occurrenceA retry is a new run and a new id; a replayed UI callback, a second Continue press or a reload resolve to the SAME id and grant nothing again
The seed is FROZEN into the receiptA re-roll is not merely refused, it is impossible: there is nothing left to roll
First-kill eligibility updates AS EACH ENCOUNTER SETTLESTwo bosses of one kind in one run used to both read "first kill" off the same stale snapshot
Loot, currency, the first-clear tally, the checkpoint and the receipt are ONE update, then one saveHalf of a settlement is worse than none
A failed save keeps the receipt PENDING and retries the same identifierNever a fresh roll; the victory screen says so rather than pretending
finishRun ITEMISES the receipts and adds nothingCalling the roll again there is exactly the double payment this exists to prevent
Rewards already settled stay earned when a later wave kills the playerAn intentional refinement of the older all-at-run-end behaviour

What it does NOT promise is global exactly-once across devices. js/cloud.js reconciles whole state documents (it takes the newer one, it does not merge fields), so two devices settling the same encounter concurrently is a conflict resolved by whichever document is newer, exactly as every other field is. A real global transaction would need a backend design, and claiming one here would be a lie.

Pity, duplicate conversion, repeat-boss loot and the first-kill floor are all unchanged: they live in js/loot.js and the service calls them.

Per-identity slots. A signed-in account stores under typingQuiz.v1:u:<uid>, so two people sharing a browser do not share a save file, and signing out returns you to the local one.

18. For developers#

18.1 The shape of the repo#

No build step, no bundler, no test suite, no package.json, and no third-party code of any kind: no npm, no CDN, no vendored library, no import map. The deployable output IS the repo root, served as-is by Cloudflare Pages. The one dependency this repo ever had (Three.js and troika, for the retired 3D view) went with it.

The one thing that is generated rather than hand-written is bible.html, and it is committed too, so nothing has to be run before a deploy. Media lives under assets/ (art in assets/art/, the four music tracks in assets/music/) and none of it is load-bearing: both are skins over a game that plays without them.

Three pages, sharing one design language and no stylesheet:

PageStylesheetScriptDepends on the app
index.html (front page)css/home.cssjs/home.jsNo. It imports nothing from js/, fetches nothing and touches no localStorage
app.html (the game)css/app.cssjs/app.js (ES modules)It is the app
bible.html (this document)css/bible.cssjs/bible.jsNo. Same isolation rule as the front page

The isolation is the point: a broken module cannot take down the landing page or the manual.

18.2 The module graph#

js/ is one module per concern, acyclic. js/app.js is the entry point: it imports every module, holds the router and init(), and wires the cross-module hooks. Nothing imports it back.

LayerModules
Pure helpersutil.js (imports nothing)
Statestate.js
Rulesxp.js, words.js, skill.js, academy.js, gear.js, loot.js, meta.js, vendors.js, achievements.js, cosmetics.js
Presentationart.js (the asset registry and its vector fallback), music.js (the four-track score)
Servicesaudio.js, cloud.js, board.js, nav.js
The funnelrun.js
Gamesgames/registry.js, games/starfall.js, games/sprint.js, games/events.js, games/threat.js, games/eventlog.js, games/debugpanel.js, games/parallax.js
The difficulty contractgames/typing-effort.js (what text costs to type), games/wave-plan.js (what a wave is, before it is flown), games/combat-feedback.js (what the equipped build is actually doing)
Settlementencounter-rewards.js (idempotent encounter rewards and the checkpoint record)
Boss surfacegames/transmission-view.js (persistent character nodes for the transmission)
Panelsmodes/arcade.js, modes/train.js, modes/progress.js, modes/ranks.js, modes/armory.js
Multiplayerversus.js
Shellapp.js

Because modules run in strict mode with their own scope, the few shared mutable bindings are reassigned through exported setters (setState, setCurrentStorageKey, setApplyingRemote, setCurrentTab), and the subsystem cycles are broken by hooks that app.js wires at init():

HookBreaks the cycle
setSyncHookso state.js never imports cloud.js
setIdTokenProviderso board.js never imports cloud.js
setAfterAuth, setBusyProbeso a remote copy is never applied on top of a live run
setSwitchTab, setPaintLevelChip, setRefresh*so a panel can drive the shell without importing app.js

18.3 The invariants#

These are the ones an edit breaks by accident. Each is stated as the thing that must remain true.

  1. finishRun() is the one funnel. It is the only writer of XP, scrap, cores, the skill model, badges, gear grants, per-game bests, History, contracts and leaderboard submissions. If a game needs a reward it does not grant, add it there.
  2. Only complete runs count. abandonRun() is the single exception and it takes ONLY the keystrokes.
  3. normalizeState() owns the state shape, and saveState() is the one writer.
  4. #kbCatch is persistent and must never be rebuilt or re-parented. A phone raises its keyboard only for a focused input.
  5. Nothing is ever gated. Where that would let somebody keep something they did not earn (opening a run deep), the answer is to PRICE it in the funnel and say so on the screen, never to lock it.
  6. Current Starfall word tiers follow fixed challenge pace and wave depth. Personal skill still recommends training and a starting challenge.
  7. The Academy never scores speed.
  8. The placement and the Academy head start only ever RAISE.
  9. Gear must never multiply XP.
  10. Every strong gear item keeps a downside.
  11. Cores come from bosses and mini-bosses and nowhere else.
  12. The performance ledger pays each original target position at most once. Encounter clear receipts remain separately idempotent.
  13. Loot rolls only on CLEARED encounters.
  14. Cosmetics never affect gameplay.
  15. The seeded PRNG is what lets Versus work without a referee. Introducing a bare Math.random into a seeded path silently desynchronises a race.
  16. Never render un-escaped user data. The rule is about the PATH a string takes, not about who wrote it, so authored catalogue strings go through escapeHtml too.
  17. _headers names every origin the page may reach. A new external dependency is two edits, not one.
  18. Sound effects are synthesized, music is streamed, and the line between them is the point. Every effect is made at runtime in js/audio.js on one compressor bus, created on the first user gesture and never at import time, because a typing game fires a sound on every keystroke and a decoded buffer per hit would stall exactly the sound that must never stall. The four music tracks are real files, fetched only once music is on and a scene is set. Do not add an audio FILE for anything that fires from a keydown handler.
  19. The Google Fonts stylesheets must stay async. A pending cross-origin stylesheet blocks script execution, and this has shipped as a bug on a sibling site where it read as "every link is broken".
  20. A renderer reads the run and never writes to it. The rule outlived the second view it was written for and keeps its teeth for the reason underneath it: a decorative draw that consumed the simulation's randomness would desynchronise a Versus race by being pretty.
  21. The art is a skin, never a requirement. Every sprite call is gated on spriteOk() with the hand-drawn shape behind it, and the game must play identically with assets/art/ deleted.
  22. There is no third-party code, no vendor/, no npm, no bundler, no CDN and no import map. Adding some is a real decision.
  23. The registry is the only list of what games exist.
  24. The threat meter is feed-forward. It runs inside the simulation so its timing is deterministic, but no gameplay code may read its output back, and it may never draw from a seeded stream. A seeded replay has to be byte-identical whether the meter runs or not. Its character counts stay at the honest baseline, or the number stops being weapon-independent and stops being the thing the player was promised.
  25. Pause is the clock. It works because the run's now() freezes, so every timer stops together. Do not add a timer that reads the wall clock directly, and do not "fix" a subsystem by adjusting its timestamps on resume: that is the bug this design exists to make impossible.
  26. The event log never allocates and never stores a string. It is on during every run at keystroke rate, so a record is typed-array stores and nothing else. Formatting belongs to the overlay and the export.
  27. A peripheral cue carries its information without hue and without motion. Every state that reaches the player through the edge of vision also reaches them through shape, thickness, extent or position, and every animated cue has a static form that says the same thing. Reduced motion is never reduced information.
  28. One difficulty contract, and every schedule is built from it. The threat meter, the wave planner, the boss attack cadence, the pre-flight preview and the diagnostics all price work through js/games/typing-effort.js, in paragraph-equivalent characters, against the run's FROZEN baseline. Three separate estimators used to answer the same question three slightly different ways. Do not add a fourth, and do not multiply an effort weight on top of a rate fraction: they are the same fact stated two ways, and applying both is the double-counting the model exists to remove.
  29. The paragraph baseline is not the rolling average. ewmaWpm blends every completed run, which is the right evidence for picking a word tier and the wrong evidence for scheduling a wave, because it is the number the effort model is supposed to be EXPLAINING. Only a Flight Check or the player's own hand may write skill.baseline, and it is frozen for the length of a run: a player typing well clears faster rather than meeting a field that accelerated to cancel their improvement.
  30. The Home Sector is answerable with the starter single-target weapon, at every depth, through every event and every boss lap. Area damage helps and is never required; a random power-up helps and is never required. It is policy DATA (SECTOR_POLICY) rather than scattered wave-number conditions, and it is enforced after an event has patched the wave and after children are budgeted, because those are the two places it used to leak.
  31. An opportunity is optional, and optional means it costs nothing to ignore. A reward rock is excluded from the wave budget, from the required pace, from the wave-clear test and from auto-fire's target list, and it damages the ship only by physically hitting it. Only an asteroid can originate a temporary power-up.
  32. A protected card freezes the SIMULATION, not the spawner. now() freezes, so heat does not decay, an event does not expire, a buff does not drain and no time-based reward accrues. That is what makes an indefinite reward review safe.
  33. A protected card is left by a deliberate action, never by typing. Crossing the boundary bumps an input generation and clears everything about the old context; ordinary letters and Space are consumed and score nothing; a key held across the crossing has to be released and pressed again. An 800 ms timeout is not a barrier, because a fast player beats it without noticing.
  34. Nothing about a character's state may change its box. On any reading surface: colour, background and inset shadows are free; display, width, padding, border, letter-spacing, weight, transforms and swapping the text itself are not. See 18.5.
  35. A boss pays when it dies, exactly once, through js/encounter-rewards.js, with the seed frozen into the receipt. finishRun itemises those receipts and grants nothing again.
  36. A checkpoint comes from a saved clear. Not from a formula, not from a highest-wave number, not from an aggregate boss count and not from a legacy setting. Every entry point resolves through resolveStartWave.
  37. The sound describes the equipped build, and audio computes nothing. js/games/combat-feedback.js projects one authoritative result per action from the resolved stats the damage itself used; js/audio.js renders it. A second copy of the equipment rules in the sound layer is a second copy that drifts. Pitch means an ABSOLUTE bonus percentage, never a combo count modulo anything, and a weapon with no streak stat plays no streak melody.

18.4 How to add things#

A new mini-game. Write a module under js/games/ exporting meta, start(host, opts), stop() and ideally isRunning() and snapshot(). Add one entry to js/games/registry.js. Report the result through finishRun(). Nothing about the panel, the router or the scoring funnel changes. A soon entry is an announcement and must read as one.

A new sprite. Drop the file under assets/art/ in the directory its prefix implies and it resolves through artPath() with no code change; a key that needs a different home goes in the SPECIAL map in js/art.js. Draw it through sprite()/spriteOk(), never through a raw Image, and leave the vector shape behind it working. ART_DIRECTION.md states what it has to look like.

A new threat. One entry in KINDS in js/games/starfall.js (radius, damage, word length range, kill score, spawn weight, first wave, and any of the weak, splits or drops behaviour flags). If it needs a behaviour none of those cover, add the flag next to them rather than branching on the id in the step loop.

A new gear item. One entry in GEAR in js/gear.js with slot, cost or cores, an optional req, and stats as deltas from BASE_STATS. Give it a downside, or tools/check-modules.mjs is entitled to fail. If it needs a stat that does not exist, add it to BASE_STATS, give it a clamp in loadoutStats(), a weight in POWER_WEIGHTS, and one use in the game.

A new event or boss. One entry in EVENTS, MINI_BOSSES or BOSSES in js/games/events.js, plus its lines in TRANSMISSIONS or MINI_LINES. A boss needs a profile from PROFILES and a brief explaining the counter-pick, because the pre-flight screen shows both. Never read Math.random in that file.

A new badge. One row in BADGES in js/achievements.js: an id, a name, a description, an XP value and a pure predicate. It is stamped automatically and can never be granted twice.

A new word tier. One entry in TIERS in js/words.js whose words stay strictly inside the tier's own chars, plus its place in TIER_ORDER. tools/check-modules.mjs asserts every tier the curriculum names exists.

A new weapon's projectile identity. One entry in WEAPON_ID in js/games/starfall.js naming a shape family from WEAPON_IDENTITY.md, a core and halo pair, and the one-line trait the pause legend shows. It must differ from every other weapon on shape or motion as well as colour, and its halo must stay out of the reserved hues (the threat ramp, the charge teal, the damage red, the boss violet). A genuinely new SHAPE is a new draw function beside the eight, plus its reduced-motion form, plus its row in that document.

A new event type in the log. One id in EV and one row in EV_NAMES and EV_SLOTS in js/games/eventlog.js, then put it in a lane in js/games/debugpanel.js. Payloads are three integers and a float: encode, do not stringify.

18.5 Verifying a change#

Serve the repo over http (the file protocol will not do: a browser refuses a module script from an opaque origin) and drive it with Playwright against the pre-installed Chromium. Two checkers stand in for a test suite, and both exit non-zero on the first failure:

CommandWhat it proves
node tools/check-modules.mjsThe arithmetic the progression design rests on: skill out-scales gear, targeting assistance preserves score, a sector advises and never blocks, an abandoned run banks nothing, every curriculum tier exists in the lexicon, every Academy group builds real material, weapons are bargains rather than a ladder, both hardpoints behave, the threat meter's whole acceptance table (section 7.14), the event log's ring, filters and export, the effort model's ordering and its infeasibility answer, a plan's structural contract and the Home policy, encounter settlement's idempotence and the checkpoint rules, and that the combat feedback matches the damage the same action deals
node tools/check-starfall-balance.mjsThe question the other two cannot answer: CAN THE WAVES BE FLOWN, at the pace they promise, with the starter weapon and nothing else. 100 seeds per baseline (20, 40, 60, 90, 120 plus the supported edges) over four complete boss blocks, flown by a deterministic agent that reads before it types and pays a fresh acquisition on every switch; plus every forced event variant at depth, and the sector policy checked structurally. It DERIVES ITS OWN demand arithmetic, because a test that validates a helper by calling the same helper validates nothing
python3 tools/check-app.pyEvery module parses and imports, the router reaches every tab, a banked run moves the level and survives a reload, the placement only raises, all three art styles work, a real run can be PLAYED a word at a time, pausing freezes the sim tick and a key pressed during it moves nothing, checkpoints are offered only where they were earned and never on a boss wave, a boss opens on a protected intro that ordinary typing cannot dismiss and a held Enter cannot confirm, ADVANCING THE CURSOR THROUGH A BOSS PASSAGE MOVES NO GLYPH, an ignored asteroid costs nothing and never collides, an encounter settles once and survives a reload, the log records the run and its provenance filter holds, F8 opens and closes the timeline, and all three pages have no page errors or missing files

Module bindings are not global, so page.evaluate(() => state) cannot reach them. Two doors exist instead: window.BTQ in js/app.js is the deliberate test seam, read by nothing in the app, and localStorage.getItem('typingQuiz.v1') is the persistence path.

SeamAnswers
state(), save(), clearAll()The save file
finishRun, switchTab, openFlightCheckDrive the shell and the funnel
games, nodes, nextNode, weakKeys, skill(), level(), cloud()The catalogues and the measurements
sfField()What the running game is asking for right now: the next character, whether the capacitor can fire, what is on the field. It is how the checker PLAYS rather than hammers
pause(reason), resume({instant}), isPaused(), getSimTick()The pause surface. The tick is the honest test: it is the log's clock, so if it moves while paused the whole pause story is false
getThreat()The threat meter's output block
getEventLog(opts), exportLogNDJSON(), onEvent(cb)The flight recorder, which is the test ORACLE: it says what the run actually did, rather than what the screen appears to say
sfTx()The boss paragraph as the SCREEN has it: the exact string on the nodes, the cursor, and the bounding box of every character. It exists for one assertion that cannot be made any other way, and which every other kind of test was blind to: advancing the cursor must not move a single glyph

A LAYOUT BUG NEEDS RECTANGLES, not a screenshot and not a DOM shape. The boss paragraph's old renderer made the current character an inline-block with a min-width and substituted a NBSP for the current space. Both are legal, both render, neither throws, and both MOVE THE TEXT: an atomic inline hands the line breaker a wrap point on either side of it, so a word near the right edge split at whichever letter the cursor was passing through and re-joined a keystroke later. Nothing but measuring every character's box at every cursor position catches that. The rule it produced is worth keeping in mind for any reading surface: NOTHING ABOUT A CHARACTER'S STATE MAY CHANGE ITS BOX. Colour, background and inset shadows are free; display, width, padding, border, letter-spacing, weight, transforms and swapping the text itself are not.

18.6 Deploying, and the build stamp#

Two deployables, and only one of them is in this repo:

DeployableWhere it livesWhere it goes
The static sitethis repo rootCloudflare Pages
The backend Workerthe big-world-quiz repoDeployed from there, serving all three sites

Adding or changing a /typing/* endpoint is a commit in that other repo. Neither deploy implies the other is live.

Two files in the repo root are read by Cloudflare Pages rather than by a browser, and neither is reproduced by a plain local serve, so both have to be tested by deploying them or by serving with an equivalent handler:

FileWhat it does
_headersSecurity headers and the Content-Security-Policy that names every origin the page may reach
_redirectsThe two renderer addresses, /3d and /2d

Every deploy is stamped. All three pages carry a short content hash in the footer, written by node tools/stamp.mjs and visible as plain text (no JavaScript involved, so it still reads when the JavaScript is the broken thing). It is a hash of the DEPLOYABLE OUTPUT rather than a git commit, because a stamp recording the current commit cannot be committed: writing it changes the tree, which changes the commit.

Before committing:

node tools/build-bible.mjs     # if GAME_BIBLE.md changed
node tools/stamp.mjs           # always
node tools/check-modules.mjs
python3 tools/check-app.py

Both checkers fail on a stale stamp, deliberately: a stamp somebody forgot to regenerate is worse than none at all, because it states confidently that a stale deploy is fresh.

18.7 This document's own pipeline#

GAME_BIBLE.md is the source. tools/build-bible.mjs renders it into bible.html, which is committed like everything else, so the site still has no build step at serve time. The generator owns the page shell, the contents sidebar and the anchors; css/bible.css and js/bible.js own the look and the search. node tools/build-bible.mjs --check exits non-zero when the page is out of date with the markdown, and tools/check-modules.mjs runs that check so a stale page cannot ship quietly, exactly as with the stamp.

19. Balance reference#

Quick answers to the questions balance arguments actually start with.

19.1 How long does a level take?#

The following table describes TRAINING and legacy pace XP, not current Starfall. Assuming continuous typing at the stated pace and 95% accuracy, pace XP only (no flat bonuses, no events, no gambits):

Net WPMXP per minuteMinutes from level 1 to 10To level 20To level 42 (the placement cap)
25122921,3717,351
4036974572,450
609437175938
801841989479
1003111153284
130576629153

In training a beginner reaches level 10 far faster than that table suggests, because flat bonuses dominate their early runs: a first run, a first day, a first node clear, a first Academy certification and a couple of wave milestones is over 1,000 XP before any pace XP is counted, and level 10 costs 3,508.

That gap is the design working. Read the two columns together: the expert's XP is almost all pace, the beginner's is almost all flat, and neither is being paid for something they did not do.

19.2 What does the placement save?#

In the training pace model, a 100 WPM typist is placed at level 22, which is 20,398 XP, which is about 65 minutes of continuous play at their own pace. A 130 WPM typist is placed at level 30, which is 41,115 XP, or about 70 minutes at theirs. That is the whole argument for the Flight Check existing: without it, the first hour of an expert's time is spent re-proving something one minute already proved.

19.3 Does gear out-earn skill?#

Current Starfall gear contributes exactly 1x to performance score and XP. Difficulty, tier, combo, the Zone, FOCUS and ascension also contribute 1x. They can change survival and the number of enemies defeated, and salvage equipment can increase scrap, but they do not increase points for the same measured original typing work.

At a fixed output of original characters, 80 WPM pays twice 40 WPM before the accuracy factor. At sustained equal accuracy and enough enemies available, twice the speed also clears twice the original work, producing approximately four times the XP per minute. This relationship is bounded by the 260 WPM reward ceiling, finite work, typing-time measurement and the one-second sample floor. It is an illustrative rate, not a guarantee about every wave or build.

19.4 How much does accuracy cost?#

Two separate penalties, applied in different currencies:

AccuracyXP kept (squared)What it costs in the arcade
100%100%Nothing. Clean words die early with a precision weapon
95%90%Corrections take time, core damage enters recovery, and marked mechanics may add work
90%81%Heat is a constant background concern
85%72%Jams start happening in the middle of waves
70%49%Frequent corrections, heat and extra work substantially reduce progress

20. Glossary#

TermMeaning
AssistA typo protected from heat and firing delay; correction is still required. Refills per wave. Targeting-slot assists have no score penalty
Axis (accuracy)Where a loadout sits between precision (a huge clean number and a weak fumbled one) and suppression (flat either way, and paid for words you never aimed at). Measured from the clean/fumbled spread minus splash and blast
Item powerWhat one item alone is worth to the power rating, on the same scale a sector recommends. Signed, and not floored at zero: an item may trade rating for something the rating cannot see
Band (boss)Which length of transmission a boss phase uses: short, medium or long
Band (threat)One of the five severity levels, from CALM to OVERRUN, that the threat number's pressure falls into. Shown as pips, the pill's border and the screen edges
ScrapThe soft currency. Time and consistency, not speed
CleanA target that has not been fumbled during this engagement
ComboConsecutive correct characters
CoreThe hard currency. Only bosses and mini-bosses produce one
Checkpoint runA Starfall run opened at an earned block. Cleared waves set scoped score/scrap records; skipped depth grants no depth badge
EncounterAn event, a mini-boss or a boss. Anything the director stages
Fumbled (foul)A normal word you have mistyped on, or a boss in its ten-key accuracy recovery window
GambitAn opt-in combat handicap with a salvage multiplier; no Starfall performance multiplier
HardpointA weapon mount. There are two, swapped with Tab
HeatRises on mistypes. Full heat jams the turret
Jam1,150 ms during which the turret takes no input at all
LedgerPer-target typing evidence and once-only reward receipts; also the separate encounter-clear grant record
LockThe threat your keystrokes are currently going to
LOSTA threat nobody could still save, struck through on its plate and taken out of the threat number. Still typeable, just no longer worth your keystrokes
PressureThe threat demand divided by what you actually produce under load. What the bands are cut from, and the reason the bands are personal while the number is absolute
Required WPMThe threat number: the pace, at perfect accuracy, that would clear everything winnable before it lands
Pace factorThe superlinear speed term in the XP formula
PityThe counter that guarantees an Elite drop within six rolls
PowerOne number summarising a loadout, compared against a sector's recommendation
ProfileA vulnerability sheet: how an encounter resists splash, pierce and mistakes
RevealSeconds of extra legibility bought by gear, drawn as a strip above the field
SectorA destination with its own enemies and loot weighting, unlocked by account level
CorrectionBackspace removes mistyped characters before correct letters. Ordinary targets keep their prefix; marked Rewind targets can reset at most twice
Challenge tierOne of 16 fixed typing workloads, 8 to 200 nominal WPM; separate from a vocabulary tier
Vocabulary tierA word pool; current solo Starfall derives it from selected nominal challenge pace and wave depth
TracerA weapon's projectile as drawn: one of eight shape families with its own motion, so the equipped weapon is nameable from the corner of your eye
TransmissionThe prose a boss broadcasts, which is what you type to strip a phase
The ZoneThe flow state, lit by a long clean streak; feedback and contract progress in Starfall, without score or XP multipliers

21. Constants appendix#

Every tuning number, with the file that owns it. If a value here disagrees with the code, the code is right.

Starfall performance, js/games/enemy-performance.js

ConstantValue
PERFORMANCE_VERSIONperformance-v1
PERFORMANCE_REFERENCE_WPM40
PERFORMANCE_MAX_WPM260
PERFORMANCE_MIN_MS1,000
PERFORMANCE_SCORE_PER_XP10
Target rewardunique characters / 5 * capped unique-output WPM / 40 * reward accuracy squared

Fixed challenges and boss mechanics

ConstantValue
CHALLENGE_VERSIONchallenge-1
CHALLENGE_TIERS16, nominal 8 / 12 / 18 / 25 / 32 / 40 / 50 / 60 / 72 / 85 / 100 / 115 / 130 / 150 / 175 / 200 WPM
Boss typing targetround(nominal * 1.10)
BOSS_DAMAGE_CAP1.35 per original typed core character
MAX_MISTAKE_ADDS / MAX_TARGET_RESETS2 / 2 per target
WAVE_RULES_VERSION / WAVE_RECORD_CAPperformance-v1 / 600

Progression, js/xp.js

ConstantValue
MAX_LEVEL100
level costround(60 + 40 * level^1.28)
REF_WPM40
PACE_EXP1.35
pace clamp0.35 to 8
accuracy factor(acc/100)^2
PLACE_CAP42
per-game rank costround(120 + 70 * rank^1.15), cap 50
Starfall scrapOriginal carried-work kill value plus objective clears, scaled by salvage bonuses; no WPM or accuracy factor (section 4.3)

The run funnel, js/run.js

ConstantValue
MAX_PLAUSIBLE_WPM260
MIN_RUN_MS2,000
gambit multiplier clamp1 to 4
loot multiplier clamp0.5 to 6

The arcade, js/games/starfall.js

ConstantValue
STEP / MAX_FRAME1/60 s / 0.25 s
VIEW_TOP / REVEAL_TOP / BASE_Y-0.04 / 0.12 / 0.93
SPEED_BASE0.024 heights per second, the planner's starting descent
JAM_MS / JAM_RESET / HEAT_PER_MISS1,150 ms / 45% / 13
BREATHER_MS / COUNTDOWN_MS4,200 ms / 2,200 ms
COMBO_STEP / COMBO_CAP10 / 4x
ZONE_WINDOW40 keystrokes
SCORE_CHAR / SCORE_KILL / SCORE_PER_LETTER / SCORE_CLEAN2 / 12 / 6 / 30
SCORE_PHASE / SCORE_MINI / SCORE_BOSS / SCORE_WAVE400 / 600 / 1,500 / 100 per wave
SLOW_MS / FOCUS_MS / EMP_MS8,000 / 10,000 / 6,000 ms
SLOW_CAP_MS / FOCUS_CAP_MS / EMP_CAP_MS / SHIELD_CAP16,000 / 20,000 / 10,000 ms / 60
ROCK_CONTACT_DAMAGE10, and only on real contact with the hull
HULL_HALF_W / HULL_HALF_H0.085 / 0.045 playfield units, shared by the collision test
BOSS_INTRO_MS / PHASE_HANDOFF_MS1,000 ms protected entrance / 1,200 ms handoff (solo also waits for a 220 ms input gap)
MAX_PARTICLES260
PROGRESS_MS250 ms (how often a versus room hears from us)
Start waveAn UNLOCKED checkpoint (1 + n*K, after that block's boss was defeated), without a wave-depth cap. Above wave 1 the run is a checkpoint run. Selection, reload, launch and retry use the same earned clear record
TRACER_CAP22 tracers in flight, oldest stolen
Resume countdown1,800 ms, plus a 120 ms input guard after GO
Deadline tiers4 s, 2.5 s, 1.5 s to arrival

The difficulty contract, js/games/typing-effort.js

ConstantValue
SECONDS_PER_WORD_CHAR12 (60 seconds over 5 characters to the word)
Content ratesprose 1.00, words 0.95, glyph 0.80, code 0.72, random 0.55, drill 0.52
Presentation ratesparagraph 1.00, line 1.00, stack 1.00, token 0.95, mote 0.95, chunk 0.95
Presentation acquisitionsparagraph 0 s, line 0.15 s, stack 0.25 s, token 0.35 s, mote 0.35 s, chunk 0.40 s
Tier modifierspunct 0.90, numbers 0.88, symbols 0.85, code 0.85, tech 0.90, caps 0.97
HIDDEN_REVEAL_S0.45 s, on the acquisition only
Rate clamp0.20 to 1.10. A rate outside it is a bug, not a slower typist

The wave planner, js/games/wave-plan.js

ConstantValue
BLOCK_ENVELOPE / BOSS_ENVELOPE0.55, 0.62, 0.68, 0.76 / 0.80 of the baseline
DIFFICULTY_PRESSUREcadet 0.78, pilot 1.00, ace 1.22, nightmare 1.42
BLOCK_GROWTH+2% a cleared block, capped by the sector ceiling
Sector ceilingshome 0.92, belt 1.05, deep 1.15, rift 1.30
windowSclamp(30 + (wave - 1) * 1.3, 30, 72) seconds
VISIBLE_SPAN2.8 gaps, capped by the sector's concurrency limit
PERCEPTION_S / PERCEPTION_MULT1.5 s / 1.3x, the floor on a craft's visible lifetime
Home policy3 mandatory targets at once, 1 long phrase, no splitters, no carrier swarm
Home opportunities1 at a time, 2 a wave, one per 24 s of active combat, from wave 2
Home deferralsblackout and meteor before wave 11, blitz before wave 6
Repairdelay the tail, then drop the most expensive PENDING craft, at most 6 times, then a plain fallback wave

Combat feedback, js/games/combat-feedback.js

ConstantValue
LANDMARKS+0, +10, +20, +30, +40, +50, +60 percent, ABSOLUTE
COMBO_DMG_CAP0.60 (js/gear.js)
Audio pitch rangeSmooth pentatonic contour over 24 semitones; charge 220 to 880 Hz, bonus voice 165 to 660 Hz

Encounter settlement, js/encounter-rewards.js

ConstantValue
PROGRESS_VERSION1
RECEIPT_CAP240 receipts, oldest pruned, never the current run's
DIFF_ORDERcadet, pilot, ace, nightmare. A clear unlocks the same checkpoint at every EASIER difficulty

The threat meter, js/games/threat.js

ConstantValue
floorS2.5 s
capCps16.67 characters a second (200 WPM)
lostEnter / lostExit1.10 / 0.85
spawnHorizonS6 s
tauUpS / tauDownS0.35 s / 0.9 s
capacityTauS20 s, load gated
capacityClampWPM15 to 200
capacityWarmupChars50
bandsUp0.35 / 0.7 / 1.0 / 1.4
band dwell up / down0.25 s / 1.2 s, at 0.92 of the boundary
metricEveryTicks6 (10 Hz)
displayCapWpm240, shown as 240+
display quantisationto 1 under 120 WPM, to 5 above; 2 WPM deadband, 400 ms hold
tier reference WPM30 / 50 / 75 / 90 by difficulty
Versus capacityfixed 60 WPM

The flight recorder, js/games/eventlog.js

ConstantValue
Sim ring / view ring65,536 / 4,096 records
Aggregate series1 Hz, 1,800 samples, folded in place after that
Recordtick, type and provenance, three integers and a float. No strings
Timeline lanes6, Okabe-Ito, with lane position co-signalling
Coalescing window15 ticks (a quarter second)

Encounters, js/games/events.js

ConstantValue
BOSS_EVERY5 waves (4 in the Rift)
CHARS_PER_SHOT6
encounter cooldown3 waves
encounter chanceclamp(0.22 + wave * 0.02, 0.22, 0.55)
mini-bosses appearwave 6
lap scalingdamage +22%, scrap +35%, escort +1 per lap
band capsshort under 30 WPM, medium under 55 WPM

Gear, js/gear.js

ConstantValue
MAX_UPGRADE / UPGRADE_STEP+5 / 14% per level
SWAP_MS / SWAP_DAMAGE600 ms / 0.5
SECOND_HARDPOINTHeat capacity -10; legacy score x0.94 is ignored by current Starfall rewards
COMBO_DMG_CAP+60%
SKILL_POWER_PER_WPM1.2

Salvage, js/loot.js

ConstantValue
PITY_AT6 rolls
duplicate conversion20% to 40% of list price by rarity
first kill floorRare

The meta layer, js/meta.js

ConstantValue
INSURANCE_EVERY / INSURANCE_CAP5 days / 3 tokens
COMEBACK_AFTER_DAYS5
ZONE.enterCombo / enterAcc / graceMisses20 / 96% / 1
ZONE.scoreMult / xpPerSecLegacy 1.25x / 3.2; current Starfall applies neither
ASCEND_AT / ASCEND_BONUSlevel 100 / +6% each

The Academy, js/academy.js

ConstantValue
CERT.keySamples / keyAcc / groupAcc / reps20 / 90% / 95% / 1
Groups / stages21 / 4

The skill model, js/skill.js

ConstantValue
MIN_KEY_MS / MAX_KEY_MS40 / 3,000 ms
KEY_INERTIA / KEY_ALPHA_MIN0.25 / 0.1
KEY_KEEP / BIGRAM_KEEP140 / 400
SKILL_ALPHA_MIN / RUN_FULL_MS0.12 / 30,000 ms
CLEAR_ACC / STAR_ACC_392% / 96%
STAR_STEPS1.05x, 1.12x, 1.22x of your own baseline
BASE_UP / BASE_DOWN / MIN_BASELINE0.35 / 0.06 / 8 WPM
MIN_KEY_SAMPLE / OUTGROWN12 presses / 1.3x

Versus, js/versus.js

ConstantValue
CODE_LEN / MAX_SEATS5 / 6
COUNTDOWN_MS / STARFALL_MS5,000 / 90,000 ms
SPRINT_CHARS / SPRINT_CAP_MS340 / 210,000 ms
HB_MS / AWAY_MS / HOST_GONE_MS15,000 / 46,000 / 90,000 ms
WAVE_MS (race) / START_HP11,000 ms / 100

Presentation, js/art.js, js/music.js and js/state.js

ConstantValue
Music crossfade900 ms
Music tracksops, hangar, combat, boss
Music defaulton, at volume 0.5
Sprite fallbackspriteOk(), with the hand-drawn shape behind every call

State, js/state.js

ConstantValue
STORE_KEYtypingQuiz.v1
HISTORY_CAP / KEY_CAP / BIGRAM_CAP200 / 140 / 400
TYPING_BACKEND_URLthe shared worker, or empty for fully local

Home pacing and equipment progression, September 2026#

Home now sends a continuous sequence of actual priced typing tasks. It rebuilds the arrival schedule after meaning-preserving collision repairs, so safety adjustments do not introduce long empty stretches. Target acquisition is priced once, at a fixed duration. The live target ceiling grows with the requested pace; optional salvage never changes the arrival schedule. Weapons can create breathing room by clearing work early. Transitions remain protected.

Ordinary ships now carry one to eight words, with 1–3-word scouts mixed with 4–8-word larger ships. Faster baselines add more arrivals through a wave rather than packing its work into three enormous ships. Home allows up to ceil(target WPM / 10) simultaneous hostiles, clamped to 3–18, with at most six longer ships. Arrival cadence comes from priced typing work. Ordinary enemies use independent attack clocks and staggered firing stations ahead of the player; see Enemy approaches, attacks and withdrawal. A pending arrival never shortens an existing ship’s attack deadline. Runtime admission also checks the live field: partially cleared ships reserve every remaining word initial, preventing an ambiguous target choice.

Current solo Home uses the fixed numbered challenge contract in section 7.2a: ordinary stages 0.88, 0.92, 0.96 and 1.00 of nominal pace, with formation factors, and bosses at 1.10 of nominal. Personal baseline, combat difficulty and depth do not multiply that typing workload. Mixed Patrol and Heavy Convoy use 1.00, Scout Flights 0.90, and Relay Pairs 0.94. The pre-flight workload band includes event-driven formation variants. Equipment changes the separate survival estimate.

Boss attack cadence uses the same pressure function as the briefing, frozen at entry. No clock ends the fight. Faster typing and suitable weapons shorten exposure; defensive equipment absorbs more volleys.

Earning and spending#

DifficultyLegacy score / training pace XP onlyScrap difficulty factorBoss core bonus
Cadet0.8x0.85x0
Pilot1x1x0
Ace1.4x1.4x0
Nightmare2x1.9x1

Current Starfall score and XP always use the per-target performance formula, with no difficulty multiplier. Its combat scrap uses only eligible kills/objectives and salvage bonuses, never measured WPM or accuracy. Training and legacy formats retain their previous speed-based salvage factor. The hand-entered baseline is never an earning input. Boss loot uses difficulty, not a claimed typing speed. Harder encounters weight Elite and Legendary cosmetics more heavily. Receipts remain idempotent; an escaped boss grants nothing and a completed encounter is never paid twice at run end.

First upgrades cost roughly 250 to 525 scrap, so a beginner can choose protection, recovery or a first weapon without a long shopping grind. Specialist builds are the next investment. Advanced items cost more; masterworks cost 12 to 21 boss cores. Clearing more eligible enemies earns more Starfall scrap. Faster accurate typing earns more performance score and XP; it adds no scrap factor. Existing ownership and upgrade levels are retained.

Upgrades keep their five-step cap and increase item strengths and weaknesses together. Their scrap cost is base * (0.35 + 0.30 * currentLevel^2), with two cores for +4 and four for +5. Buying another role competes with perfecting one item. Statless starter and empty items cannot consume upgrade currency.

Choosing equipment#

Loadout, Vendors and Cosmetics remain reachable in the Armory. Vendors have compact shop selectors, then search, equipment type, availability and sorting controls. Functional equipment is the default; cosmetics have an explicit filter. Vendor cards show all changed build effects in a fixed stat order, with gains and tradeoffs labelled in text. Descriptions and firing explanations remain optional. The comparison opens the same compact side-by-side stat panels used by the inventory.

The slot picker keeps the current item visible, compares the selected mount, and offers Buy & equip. Buying from a vendor adds to inventory; Choose mount & equip opens the picker. This prevents a purchase from silently replacing a second weapon or attachment. The Salvager offers three progression-relevant gear choices, an aspirational choice where available, and a fifth discovery. The shelf is stored for the day, so purchases cannot reroll it.

Sector progression#

Home teaches steady acquisition, short stacks, one readable sentence at a time and deliberate use of stored shots. It remains answerable without area weapons at the selected pace. The Belt adds charging sentries, independent boss batteries and a finite reactor breach, making target priority useful. Deep Space combines longer reading with dangerous specialist encounters, rewarding recovery, cooling and armour penetration. The Rift combines more simultaneous work and mixed encounter profiles, making complementary weapon mounts useful. Deep Space and the Rift retain their authored encounter rules; future passes should test each new mechanic independently before combining them.

Arcade world guide#

The following guide is generated from STORY_BIBLE.md and describes the arcade setting.

Starfall Keys: arcade world guide#

Home Sector: Beacon Nine#

Beacon Nine is a working orbital shipyard: cyan docking lights, warm repair bays, slow salvage tugs and a bright planetary horizon. The player pilots its defense ship against the Scrap Armada, a rogue machine fleet that keeps arriving without clearance. The objective is straightforward: clear the sky and bring the ship home.

The mood is energetic space arcade action. Metal catches the sunlight, engine trails cross the dark, antenna arrays glow, and the hangar crew appreciates a spectacular finish. Radio messages are short, useful and occasionally cheeky. The machines can boast about their hardware. Flight Control can joke about the scrap bill. Neither needs a tragic backstory to make a good boss entrance.

The fifty-wave operation#

Every five-wave group has a distinct visual setting and objective:

WavesOperationSetting and objective
1–5Launch RingClear the first attack from the bright docking lanes.
6–10Chrome SwarmBreak the linked drone formations around the outer docks.
11–15Heavy MetalStop the armored push through the shipyard.
16–20Ghost SignalClear the interference surrounding the beacon.
21–25Solar RunHold the sunward side of the station through the glare.
26–30Salvage AlleyOpen the scrap route for the collection crews.
31–35Ion WeatherFight through blue clouds and bright engine trails.
36–40Night ShiftSecure the dark side of the orbital ring.
41–45Redline OrbitBreak the final screen around the approach lanes.
46–50Last LightFinish the attack and return to the home beacon.

These are briefing settings, not extra gameplay modifiers. The installed wave plans, weather effects, enemy mechanics and rewards remain authoritative. Home ends after the wave-50 boss. Its review leads to the run summary.

Enemy identities#

Defeating a command ship adds its scan to the Operations briefing. The scans are flavor and a record of familiar hardware, not an additional reward system.

Beyond the home ring#

The Belt is a rough salvage route with rocks, sentries and rival batteries. Deep Field is a distant shipping lane with larger hulls and rich scrap. The Rift is the dangerous edge of the flight map, with frequent command ships and rare salvage. Their existing wave pacing and unlock rules do not change.

Writing and implementation rules#

Game fiction is its own setting. Do not import characters, events, quotations, chronology or source text from the separate Book reader or manuscript. Keep the reader, its chapter files, art and reading preferences isolated.

Use flight, machine, weapon, station and salvage imagery. Keep briefings short enough to read between waves. Flavor must not promise a mechanic that does not exist. Boss IDs and combat behavior stay stable when their descriptions change.

js/lore.js owns fifty ordered wave dispatches, ten operation briefings and command-ship flavor. js/lore-variety.js owns optional radio traffic. General typing-library material is independent practice content. Neither pool imports or adapts the manuscript. Preserve typed spelling, keyboard eligibility, seed determinism and the existing whole-sentence rules.

Wave formations, target practice and returning to play#

Mixed Patrol alternates short scouts and larger ships. Scout Flights concentrates on one to three words per ship. Heavy Convoy uses larger ships with short escorts. Relay Pairs shortens the gap within a compatible pair and adds that time after the pair. The rotation changes across boss blocks; scout and cargo events select their matching formation. The wave banner names the current formation, while the breather forecasts the next patrol and notes that events may change it.

The first introduction opens a directed game rehearsal: finish red, pause on the pending separator, switch to orb, and return directly with s. A second practice covers switching after Space. The player controls every explanatory pause; the demonstration does not advance a paragraph on a timer. Skip records that the introduction was offered. The Armory Ability Guide and the ↔ control replay it at any time. It changes no combat resources or rewards.

Directed ability scenes#

Charge, Target Relay and all five power-ups use ability-lesson.js. It presents the production Starfall canvas, HUD, ships, targeting, input rules and effects inside an isolated practice frame. Explanations are short, reader-paced steps. A spotlight and adjacent label identify the relevant word, meter or slot. Show me plays the action, then freezes on its result. Back reconstructs the earlier checkpoint, Replay restarts the current step, Pause stops an action, and Skip or Escape always exits. Charge and Relay include real-input practice with no failure timer and a click-operated demonstration alternative.

The frame uses fresh, memory-only state, no recorder, no cloud boot, and no wave or encounter settlement. Its authored clock advances only during a demo or practice feedback. The actual run remains frozen. It inherits the player's art and motion settings. Armory → Ability Guide is the permanent replay door, including each discovered power-up. Unknown powers are not taught in earlier lessons. TUTORIAL_DESIGN.md records the design references and review criteria.

Every ordinary solo run saves its sector, difficulty and latest started wave immediately, independently of end-of-run rewards. Returning selects that wave’s earned block start: wave 19 selects Waves 16 to 20. A boss victory saves the next unlocked block immediately. Older saves without this position select their highest earned block in the selected sector and difficulty. Intentionally replaying an earlier block becomes the new last-played position. The position grants no checkpoint access; Versus and developer wave overrides do not change it.

Enemy approaches, attacks and withdrawal#

Hostile ships remain ahead of the player. Regular enemies approach staggered firing stations, no lower than 62% of field height. Raiders (one to three words) approach, aim, fire one 3–5 damage shot and retreat upward. Gunships fire three 3-damage shots; siege ships fire four. Heavy ships fire during their approach and shorten the intervals between shots, with a minimum readable warning. They withdraw after their last shot. Leaving the field causes no breach damage. Optional salvage retains its physical collision behavior.

enemy-attacks.js prices the original text at the mission's target WPM. Attack timing is independent of screen height and the old crossing-speed cap. Every ship displays its role, FIRE IN countdown, and filling warning bar; aiming lines and corners reinforce the warning without relying on color or animation. Kill before firing to prevent the shot. A launched projectile travels for 0.65 seconds and still hits after the firing ship dies. Shield and armour apply on impact. Missing the first shot does not make a heavy target worthless: killing it prevents subsequent shots.

Slow and fitted field slowing affect approach, aim and retreat together. Reveal delays the opening attack. Pauses and protected reading/tutorial states freeze the entire simulation. The threat meter and untargeted charge selection use the next firing deadline; harmless withdrawing ships leave the demand sum. The survival estimate uses the same finite attack schedules and allows chip damage, rather than assuming a damage-free trip across the screen.

Higher typing demand creates more overlapping arrivals and a larger live target ceiling, rather than accelerating the normal enemies or making giant paragraphs. scheduledOverlap describes unanswered arrival slots; liveTargetLimit describes actual admission capacity. Pending ships wait for capacity or distinct word initials without changing visible text or speeding up enemies. Beginner fields stay smaller.

Detailed run analysis and recordings#

Open Progress → Run analysis to review typing recordings, or expand Typing analysis and run timeline on a Starfall or Flight Check result. Recording starts with this feature; older History rows have only their original summary. The reward History and leaderboard rules are unchanged. Abandoned sessions earn no run rewards, but their input is retained in this separate analysis archive, labelled abandoned or interrupted.

Progress opens with typing measures and run analysis before currency, contracts and rank rewards. Recent WPM and accuracy are weighted averages across modes; they are labelled as observations rather than proof of skill improvement. The accuracy practice and 60-second measurement buttons lead to Training and the Flight Check directly from this summary.

Within a session group, the recent comparison uses median WPM and median accuracy from the latest three completed recordings with at least 30 seconds of measured typing. Once six exist, it compares the previous three without overlapping the windows. Short and unfinished sessions remain reviewable. The screen shows both changes and flags a speed increase paired with an accuracy decrease greater than half a percentage point. These observations are not a skill rating: text, run length, gear and fatigue can still vary.

Your typing over time defaults to all saved runs, in chronological order. It joins synced profile history with device-local recordings by recording ID, so an older summary-only run is charted and a run stored in both places appears once. The run table identifies summary-only entries; only actual recordings offer detailed review. A game filter and the narrower comparable groups are optional. The broad overview labels differences in settings and historical WPM definitions and does not combine them into a median skill comparison. If detailed storage is unavailable, profile history still supplies the graphs.

Immunity at the typing text: charge-immune enemies and boss passages carry a double rule and a TYPE ONLY label. Their focused input explains that charge shots and Nukes are blocked. Asteroids carry a single rule and NO NUKE, since charge shots still work on them. Color reinforces these marks but is not their only signal. Error cells, the caret and deadline underline retain their meaning. Ordinary targets being typed are temporarily skipped by Nukes, not marked immune.

The report includes correct WPM, accuracy, mistakes, corrections, a timeline with 5, 10 or 30 second buckets, and individual enemy and boss results. Select combat, enemies, bosses, mini-bosses, asteroids, power-ups, Repair practice, paragraph typing or all activity. Untyped targets show N/A, not a fabricated speed. Completed-run trends group the same game, mode, sector, difficulty, threat tier, starting checkpoint, baseline source, manual baseline and metric version. Placement measurements are separate from ordinary sprints. Pattern evidence also uses unfinished sessions in the same group.

Run results, selected-activity statistics and charts appear before calculation details. Expand How these numbers are measured for the full timing and reward methodology.

Correct WPM is correct accepted characters divided by five and engaged minutes. Retypes remain accepted attempts, matching the game. Accuracy is correct attempts divided by all scored attempts in the selected activity; backspace does not remove mistakes. Combat time excludes pauses, protected cards, asteroids, power-ups and target acquisition gaps. The existing estimated opening-character interval is recorded separately as synthetic time, so it can be included or removed by later analysis. Paragraph timing starts on its first key. Raw event timestamps are not clamped to the skill model's latency limits.

Timeline speed instead divides correct characters by five and the active window's minutes. Whole keystrokes must not be divided by a tiny fragment of engaged time left over at a bucket boundary: that previously produced false spikes of thousands of WPM. This window rate includes target-selection gaps, excludes paused time and ignores synthetic opening estimates. Run and target WPM retain their engaged-time definition. Final partial windows use their actual duration; windows under one second show no speed estimate. Their exact counts and accuracy remain available, and an event exactly at the end of the run belongs to the final window. Inactive windows are gaps in the speed line. Point tooltips and keyboard-focus labels include attempt counts, window length and engaged seconds. The timeline table also identifies targets. These rules are applied when reading existing recordings; raw events are never discarded or capped, and completed-run trends are unchanged.

Practice suggestions and strengths are evidence-based counts, not diagnoses. A pattern needs five attempts; a practice suggestion also needs two mistakes. Keys, preceding-key pairs, following-key pairs and three-character contexts are kept separately. A three-character context measures its middle key, and a following-key pair measures its first key. Whitespace and punctuation are retained. Follow-on characters in an existing error buffer count against accuracy but do not blame the expected key as a new independent mistake.

Recording format and storage#

js/run-analytics.js owns schema version 1 and metric version correct-chars-5-engaged-v1. Each recording contains a random run ID, start/end date, owner storage slot, run status, game/mode, relevant configuration, and an ordered event stream with both active and wall milliseconds. Starfall also records seed, balance version, starting wave, baseline, loadout, game stats, target spawn text and identity, word completions, target outcomes, encounter phases, state changes, pauses, weapon switches, discharges, flares and incoming damage. Each scored key stores actual and expected characters, text position, preceding/following text, target and prompt IDs, scope, raw key-to-key latency, blocked-error status and available keyboard/input-event metadata. Corrections, physical key releases and unscored gameplay controls are separate events. Input belongs only to the game, never account fields or other open dialogs. Prompts are stored once and referenced by ID; the stream preserves order even when a virtual keyboard delivers a batch at one timestamp. Virtual input does not promise physical key-release data that the browser never supplies.

js/run-archive.js writes IndexedDB database btq.run-archive.v1. Its runs store holds headers, summaries and contextual tallies indexed by owner slot; chunks holds event batches keyed by run ID and sequence. A header and its new batch commit in one transaction. Failed writes retain the pending events for retry and show a warning. Checkpoints are queued within two seconds of an event, with additional saves on pause, pagehide and completion. A browser crash can lose events since the last committed checkpoint; the surviving record remains labelled interrupted, never completed. Live data can still be exported from the end report when durable storage fails.

Event batches and cached pattern tallies use standard gzip compression through the browser's native compression streams, with plain JSON Blobs as the fallback when compression is unavailable or would make a payload larger. The public event schema and all available fields, timestamps and ordering are preserved; unavailable undefined properties are omitted, as in the JSON export. No samples are discarded and no clock precision is reduced. Compression finishes before opening the IndexedDB transaction. At run end, checkpoint batches are replaced atomically by one compressed batch so repeated context can compress across the whole run. The old checkpoints remain intact if that transaction fails. Repeated completion flushes do not rewrite the finished run.

The reader accepts both the original object-array chunks and encoded Blobs. Older completed or abandoned recordings are compacted when reviewed, only if their saved header has not changed or been deleted during conversion. Failed conversion preserves the original. Active/interrupted checkpoints remain independent batches, so recovery does not depend on a successful final merge.

For a reproducible size comparison, run node tools/check-archive-codec.mjs. Its varied-text fixture records 4,000 correct characters plus 119 mistakes and corrections with variable timing. Approximately 3.15 MB of uncompressed events becomes 325 KB including the compressed pattern cache and header, before IndexedDB's own bookkeeping. This is about a 90% reduction in payload size; actual runs vary with timing, text and encounters. This measures serialized storage payload, not the browser's exact disk allocation or live memory use.

Detailed recordings stay on this browser and are separated by guest/account storage slot. They are not included in cloud sync or the existing profile backup, whose compact History remains capped at 200. The detailed archive has no automatic run-count eviction. Browser storage clearing or quota limits can affect it. Export one run or the whole archive as JSON before clearing browser data. Export compressed downloads the same JSON in a standard .json.gz file where browser support is available. The ordinary JSON export stays readable and uncompressed. Exports omit the internal account-slot identifier. Delete a recording from its review when no longer needed. Clear all data also clears this slot's recordings. An exported recording is analysis data, never a reward receipt or a leaderboard submission.

analyseRecording(recording, { scope, bucketMs }) can recompute reports from events without changing game state. Run node tools/check-analytics.mjs for timing, scope and contextual evidence invariants, and python tools/check-analytics-browser.py for actual typing, reload durability, account isolation, export and responsive report checks.

Shield projectors and interception#

The shield phase uses two visibly linked projectors. Their word workload targets roughly 30 seconds at a fixed design pace (clamp(nominalWpm * 0.7, 8, 140)), including eight optional interception keys. Faster typing clears them sooner. The core opens for 15 seconds, with fixed health of round(designPace * 3.2) and 4% repair on closing. The reference rhythm is three openings with starter damage, fewer for strong typing and more under pressure; this is a balance target, not a forced loop count. Combat continues through each attempt, so slow clears face more attacks. Completed layers stay removed when the player switches targets at a word boundary. A projector keeps its silhouette size while its armor ring loses segments. All ordinary enemies also keep their size as remaining collision damage falls.

The closing countdown follows the passage cursor for the final three seconds. An already-started word can finish; a 500 ms protected beat keeps the outgoing passage visible, then replacement targets appear with input immediately enabled. Boss phase changes use the same outgoing beat when unread text remains. Completed generators and fully completed passages do not add a pause. Multiword enemies show their remaining keystrokes directly under the current word, independent of the read-ahead queue.

Up to two interceptors launch per relay phase, with only one live at a time. Each shows a six-second firing countdown; typing or discharging into it before launch prevents the shot. Its word never changes when the timer expires. These are bounded defensive targets with no repeat-farming rewards. The full-width battlefield keeps typing labels unobstructed; shield links, hit ripples and armor fragments communicate state without expanded instructions.

Threat selection uses one keyboard-accessible scale. Existing tiers1 through16 retain their authored work; tiers17 through19 extend it. The loadout survival range remains an estimate at95%accuracy without charges, not a measured skill requirement. Tests of steady cadence and bursty accelerated play can differ, so survival estimates must not be presented as validated human thresholds.

Belt combat identity#

The Belt uses industrial weapons with explicit firing intent. Selected planned drones become Sentries and selected cruisers become Siege drills. They descend normally, start charging only after entering view, and can fire twice. Each shot moves 25% of the original breach damage into a visible projectile; the remainder is paid on arrival. Destroying one prevents future shots but does not erase shots already travelling. Firing never replaces its reading or discards a typed prefix. First-shot timing scales with the authored reading workload; Slow also slows charging. These targets add priority decisions without adding hidden text or an unlimited damage source.

Every Belt boss opens with two independent batteries: a light gun and a slower heavy gun. Typing out a battery permanently disables it for that phase. Both must be disabled to advance. Their visible countdowns and damage appear beside the remaining-work counter under the current word. The ordinary boss attack pattern is suspended while the batteries provide the attack pressure. Repair does not pause them. The four combat designations are The Foreman, Scrap Choir, The Anvil and Flux Engine; they share a new industrial hull asset with canvas weapon effects. Encounter IDs and progression receipts retain their existing identity.

Scrap Choir's final reactor phase has two coolant clamps. Each stays broken after completion. Once both are gone the core remains exposed until defeated, with normal boss volleys still active. It has no timed reclosing, regenerated clamp cycle or extra relay interceptors. Other relay encounters retain their existing timing. This gives the foundry a sustained accuracy finish instead of another shield endurance loop.

The loadout forecast shares sentry damage clocks and battery timing with combat, includes projectile travel and attacks already in flight, and models the finite reactor exposure. Its battery policy finishes the light gun first; it is an estimate, not an optimal player or a measured human skill threshold. Automated replay findings must report actual measured WPM separately from input cadence.

On short desktop windows, boss prose uses a bounded reading viewport with whole-line caret following, preserving upcoming text without pushing correction controls and reserves below the game. Character nodes and passage content remain stable. Countdown headroom, a compact correction row and the existing accuracy/source information stay visible. Repair retains its own timed prompt and scrolling behavior. Larger desktop windows retain the expanded passage presentation. The masthead scrolls normally while a desktop game is mounted so it does not cover the combat HUD.

Ideas reading library#

Arcade enemy text now comes from the separate ideas library rather than the manuscript. The collection contains verified public-domain quotations, original research summaries, original short phrases, complete sentences, longer passages, and whole vocabulary words. Original writing is never presented as an author's quotation. Source metadata preserves author, work, translator, URL, locator, rights basis, verification notes, and verbatim text. Gameplay normalizes typographic punctuation for a standard keyboard; incomplete quotation excerpts remain catalog entries and are excluded from complete-reading selection.

The arcade footer links to Explore the reading library. Its browser filters by topic, format, writing type and search text, and exports the collection with source metadata. Gameplay draws from the whole eligible collection, with a gentle thematic preference: learning and kindness in Home, practice and achievement in the Belt, reflection and discovery in Deep Field, and courage and resilience in the Rift. Fresh readings take priority over themes. Media and source balancing keeps smaller books, movie favorites, songs and poetry visible alongside large anthologies. The existing training curriculum and archived manuscript remain available separately.

Generator sides are physical positions, not hand restrictions. Each carries a complete library reading; the selection varies within an exact character-cost pool. Whole original sentences on the same topic may be paired, with both entry IDs retained. Quotations are never spliced together. The remaining-work number sits below the active word, and only the final word destroys the generator. Small swarm targets and salvage rocks now carry whole words and are priced as word targets rather than glyph or random-key tasks. Boss passages select whole entries with repeat avoidance and a compact author or original-writing label.

Mini bosses and boss phases retain the speed-based short, medium and long reading bands. Short verses and brief lyric excerpts can enter shorter bands; longer stanzas and paragraphs support sustained phases. Openings remember earlier planned readings across encounters. Extra reissues use a separate live history so errors and combat timing cannot change future shared-seed waves. Generator and battery readings also include verses, retain exact character costs and distinct target initials, and rotate sources through returning shield cycles.