Skip to content

Commit 751ab06

Browse files
committed
Make Mission Run burnout chase explicit
1 parent 09534cd commit 751ab06

3 files changed

Lines changed: 86 additions & 32 deletions

File tree

src/data/site.ts

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,21 @@ export const miniGame = {
5353
ariaLabel: 'Maintainer Day - mini game',
5454
controlsHintHtml:
5555
'←/→ or A/D move/backpedal · Space/↑/W or JUMP leap · ↓/S enters pipes · Esc quits',
56-
voidTitle: 'MAINTENANCE DEBT',
57-
voidSubtitle: 'unfunded fixes, CVEs, and release work',
58-
voidWarning: 'unfunded maintenance is catching up. keep moving.',
59-
voidSignLines: ['KEEP MOVING', 'CVE DRIFT', 'RELEASE LAG'],
60-
voidGameOverTitle: 'DEBT CAUGHT UP',
56+
voidTitle: 'BURNOUT',
57+
voidSubtitle: 'unpaid urgency / no backup / no rest',
58+
voidWarning: 'burnout is catching up. keep moving.',
59+
voidSignLines: [
60+
'FREE SLA',
61+
'4:59 CVE',
62+
'PR FLOOD',
63+
'NO BACKUP',
64+
'HARD DEADLINE',
65+
'WEEKEND PAGE',
66+
'DM PING',
67+
'NO REST',
68+
],
69+
voidPressureBursts: ['ONE MORE?', 'URGENT?', 'JUST FIX', 'ANY UPDATE?', 'WHY SLOW?', 'NO OWNER'],
70+
voidGameOverTitle: 'BURNOUT CAUGHT UP',
6171
voidGameOverPrefix: 'you lasted',
6272
voidSecondLabel: 'second',
6373
voidSecondsLabel: 'seconds',
@@ -82,55 +92,55 @@ export const miniGame = {
8292
{
8393
title: 'ARCHIVED REPO',
8494
main: 'you archived the repo.',
85-
void: 'the repo still went read-only.',
86-
detail: 'an enterprise still ships it in prod - for free.',
95+
void: 'you stopped before the repo did.',
96+
detail: 'the issues kept arriving after your last good day.',
8797
},
8898
{
8999
title: 'STALE BOT WON',
90100
main: 'the stale bot closed the last real bug.',
91-
void: 'automation kept smiling while the queue grew.',
92-
detail: 'nobody noticed until the next deploy broke.',
101+
void: 'the bot closed symptoms while people kept pinging.',
102+
detail: 'automation cannot absorb disappointment for you.',
93103
},
94104
{
95105
title: 'FREE SLA',
96106
main: 'someone demanded a same-day fix for $0.',
97-
void: 'the free SLA still followed you home.',
98-
detail: 'their incident became your unpaid weekend.',
107+
void: 'free urgent support followed you home.',
108+
detail: 'their incident became your unpaid evening.',
99109
},
100110
{
101111
title: 'SECURITY FRIDAY',
102112
main: 'the CVE arrived at 4:59 on Friday.',
103-
void: 'the advisory arrived faster than help did.',
104-
detail: 'everyone needed a patch; nobody funded the patch.',
113+
void: 'the Friday CVE took the last quiet hour.',
114+
detail: 'everyone needed a patch; nobody funded calm coverage.',
105115
},
106116
{
107117
title: 'PR QUEUE',
108118
main: 'the PR queue became a second job.',
109-
void: 'review debt kept sprinting behind you.',
119+
void: 'the review queue turned into a second shift.',
110120
detail: 'tiny fixes still needed taste, tests, and releases.',
111121
},
112122
{
113123
title: 'QUICK FIX',
114124
main: 'the quick fix had five hidden migrations.',
115-
void: 'the quick fix brought its own maintenance debt.',
116-
detail: 'one line became a week of compatibility work.',
125+
void: 'one "quick" fix unpacked a week of hidden work.',
126+
detail: 'compatibility work moved into your calendar.',
117127
},
118128
{
119129
title: 'BUS FACTOR 1',
120130
main: 'the only maintainer stopped answering.',
121-
void: 'bus factor one finally caught up.',
122-
detail: 'the project did not fail loudly; it just went quiet.',
131+
void: 'being the backup plan became the whole plan.',
132+
detail: 'the project did not fail loudly; you just stopped opening it.',
123133
},
124134
{
125135
title: 'RELEASE NEVER',
126136
main: 'the release train waited for one tired human.',
127-
void: 'the unreleased patch kept aging behind you.',
128-
detail: 'green CI is not the same as maintained.',
137+
void: 'the release waited for the only tired human.',
138+
detail: 'green CI did not give you a weekend.',
129139
},
130140
{
131141
title: 'ISSUE FLOOD',
132142
main: 'the issue tracker filled with duplicate reports.',
133-
void: 'the duplicate reports learned to run.',
143+
void: 'duplicate reports became background noise.',
134144
detail: 'triage is work, even when the answer is no.',
135145
},
136146
{

src/scripts/game.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { miniGame } from '../data/site';
55
maintainer. You ship for $0 while the expense monsters keep coming:
66
RENT · TAX · ELECTRIC · WATER · MOBILE · SUBS · GAS · LOAN · FEES.
77
Bump ? blocks for GitHub ★ (worth $0), grab the COFFEE, and find the secret
8-
NEW PROJECT IDEA — the maintenance debt grows, so the maintainer grows with it.
8+
NEW PROJECT IDEA — the pressure grows, so the maintainer grows with it.
99
1010
Reach the finale and you win, obviously: the lights warm up and fireworks go up
1111
because ManagedCode is glad to have you here, funding the maintenance work
@@ -458,7 +458,7 @@ export function createMascotGame(): Game {
458458
const { finale } = pickGameOverFinale();
459459
if (!finale)
460460
return `${miniGame.voidGameOverTitle}\n${miniGame.voidGameOverPrefix} ${seconds} ${label}.`;
461-
return `${finale.title}\n${miniGame.voidGameOverPrefix} ${seconds} ${label}.\n${finale.void}\n${finale.detail}`;
461+
return `${miniGame.voidGameOverTitle} / ${finale.title}\n${miniGame.voidGameOverPrefix} ${seconds} ${label}.\n${finale.void}\n${finale.detail}`;
462462
};
463463
const formatMainGameOver = () => {
464464
const { finale } = pickGameOverFinale();
@@ -1019,7 +1019,12 @@ export function createMascotGame(): Game {
10191019
if (voidT % 105 === 0) {
10201020
voidDragon.mouth = 30;
10211021
sound('fire');
1022-
addParticle(player.x + 42, VOID_GROUND - 74, 'FEATURE?', C.subs);
1022+
const pressureBursts: readonly string[] = miniGame.voidPressureBursts;
1023+
const label =
1024+
pressureBursts.length > 0
1025+
? pressureBursts[Math.floor(voidT / 105) % pressureBursts.length]
1026+
: 'URGENT?';
1027+
addParticle(player.x + 42, VOID_GROUND - 74, label, C.subs);
10231028
}
10241029
if (voidGap() <= VOID_DRAGON_HIT_GAP) {
10251030
gameOver();
@@ -1816,17 +1821,19 @@ export function createMascotGame(): Game {
18161821
block(x, VOID_GROUND + 3, TILE, 2, C.sign);
18171822
}
18181823

1824+
const signColors = [C.subs, C.mobile, C.rent, C.electric, C.tax, C.water, C.fees, C.life];
18191825
miniGame.voidSignLines.forEach((line, i) => {
18201826
const wx = 120 + i * 220;
18211827
const y = 58 + (i % 2) * 20;
18221828
const w = textW(line, 1) + 8;
18231829
block(wx - 4, y - 4, w, 13, C.sign);
1824-
block(wx - 4, y - 4, w, 1, i === 0 ? C.subs : i === 1 ? C.mobile : C.rent);
1830+
block(wx - 4, y - 4, w, 1, signColors[i % signColors.length]);
18251831
text(line, wx, y - 2, 1, C.starHi);
18261832
});
18271833

18281834
text(miniGame.voidTitle, camX + 12, 14, 2, C.rent);
1829-
text(miniGame.voidWarning.toUpperCase(), camX + 12, 36, 1, C.starHi);
1835+
text(miniGame.voidSubtitle.toUpperCase(), camX + 12, 34, 1, C.mobile);
1836+
text(miniGame.voidWarning.toUpperCase(), camX + 12, 46, 1, C.starHi);
18301837
const seconds = voidSeconds();
18311838
const gap = Math.max(0, Math.min(1, (voidGap() - VOID_DRAGON_HIT_GAP) / 180));
18321839
const danger = gap < 0.18;
@@ -2378,8 +2385,10 @@ export function createMascotGame(): Game {
23782385
camX: Math.round(camX),
23792386
voidT,
23802387
voidTitle: miniGame.voidTitle,
2388+
voidSubtitle: miniGame.voidSubtitle,
23812389
voidWarning: miniGame.voidWarning,
23822390
voidSignLines: [...miniGame.voidSignLines],
2391+
voidPressureBursts: [...miniGame.voidPressureBursts],
23832392
voidSeconds: voidSeconds(),
23842393
voidDragonX: Math.round(voidDragon.x),
23852394
voidGap: Math.round(voidGap()),

tests/functional.spec.ts

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -944,8 +944,10 @@ test.describe('Mission Run mini-game', () => {
944944
camX?: number;
945945
voidT?: number;
946946
voidTitle?: string;
947+
voidSubtitle?: string;
947948
voidWarning?: string;
948949
voidSignLines?: readonly string[];
950+
voidPressureBursts?: readonly string[];
949951
voidSeconds?: number;
950952
voidDragonX?: number;
951953
voidGap?: number;
@@ -1112,7 +1114,7 @@ test.describe('Mission Run mini-game', () => {
11121114
expect(after?.poseT).toBeGreaterThan(0);
11131115
});
11141116

1115-
test('pipe descent crossfades into the survival chase without flashing the old scene @desktop', async ({
1117+
test('pipe descent crossfades into a burnout chase with grounded pressure labels @desktop', async ({
11161118
page,
11171119
}) => {
11181120
await useDesktopAuditViewport(page);
@@ -1202,12 +1204,44 @@ test.describe('Mission Run mini-game', () => {
12021204
expect(voidStart?.transitionLabel).toBe('DOWN PIPE');
12031205
expect(voidStart?.transitionT ?? 0).toBeGreaterThan(0);
12041206
expect(voidStart?.transitionDuration ?? 0).toBeGreaterThan(voidStart?.transitionT ?? 0);
1205-
expect(voidStart?.voidTitle).toBe('MAINTENANCE DEBT');
1206-
expect(voidStart?.voidTitle).not.toBe('BACKLOG');
1207-
expect(voidStart?.voidWarning).toBe('unfunded maintenance is catching up. keep moving.');
1208-
expect(voidStart?.voidSignLines).toEqual(['KEEP MOVING', 'CVE DRIFT', 'RELEASE LAG']);
1207+
expect(voidStart?.voidTitle).toBe('BURNOUT');
1208+
expect(voidStart?.voidTitle).not.toBe('MAINTENANCE DEBT');
1209+
expect(voidStart?.voidSubtitle).toBe('unpaid urgency / no backup / no rest');
1210+
expect(voidStart?.voidWarning).toBe('burnout is catching up. keep moving.');
1211+
expect(voidStart?.voidSignLines).toEqual([
1212+
'FREE SLA',
1213+
'4:59 CVE',
1214+
'PR FLOOD',
1215+
'NO BACKUP',
1216+
'HARD DEADLINE',
1217+
'WEEKEND PAGE',
1218+
'DM PING',
1219+
'NO REST',
1220+
]);
1221+
expect(voidStart?.voidPressureBursts).toEqual([
1222+
'ONE MORE?',
1223+
'URGENT?',
1224+
'JUST FIX',
1225+
'ANY UPDATE?',
1226+
'WHY SLOW?',
1227+
'NO OWNER',
1228+
]);
12091229
expect(voidStart?.voidGap ?? 0).toBeGreaterThan(120);
12101230

1231+
await page.evaluate(() => {
1232+
const w = window as Window & {
1233+
__mgameAdvanceVoid?: (frames?: number) => void;
1234+
__mgameHoldVoidDirection?: (dir?: -1 | 0 | 1) => void;
1235+
};
1236+
w.__mgameHoldVoidDirection?.(1);
1237+
w.__mgameAdvanceVoid?.(106);
1238+
});
1239+
1240+
const afterFirstPressureBurst = await readGame();
1241+
expect(
1242+
afterFirstPressureBurst?.particles?.some((particle) => particle.text === 'URGENT?')
1243+
).toBe(true);
1244+
12111245
await page.evaluate(() => {
12121246
const w = window as Window & {
12131247
__mgameAdvanceVoid?: (frames?: number) => void;
@@ -1256,10 +1290,11 @@ test.describe('Mission Run mini-game', () => {
12561290
).__mgameAdvanceGameOver?.();
12571291
});
12581292
await expect.poll(async () => (await readGame())?.state, { timeout: 5000 }).toBe('over');
1293+
await expect(page.locator('[data-mgame-msgtext]')).toContainText('BURNOUT CAUGHT UP');
12591294
await expect(page.locator('[data-mgame-msgtext]')).toContainText('ARCHIVED REPO');
12601295
await expect(page.locator('[data-mgame-msgtext]')).toContainText('you lasted');
12611296
await expect(page.locator('[data-mgame-msgtext]')).toContainText(
1262-
'the repo still went read-only'
1297+
'you stopped before the repo did'
12631298
);
12641299
});
12651300

0 commit comments

Comments
 (0)