[screen] boredom: the sky forgets, the ledger does not
No shipments for a sustained stretch and the corruption eases back toward clean. The LEDGER is untouched -- history is not erased, only the display decays -- so resuming production puts the targets straight back and the picture walks home in about a second. 60s grace then 180s decay: a jam you notice, diagnose and fix costs nothing. The player has to genuinely walk away before the sky starts cleaning itself. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
83e3ad2107
commit
5ad7252e20
47
fktry/src/screen/boredom.test.ts
Normal file
47
fktry/src/screen/boredom.test.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { BOREDOM_GRACE_SECONDS, BOREDOM_HORIZON_SECONDS, freshness } from './boredom';
|
||||||
|
|
||||||
|
describe('boredom decays the display, slowly', () => {
|
||||||
|
it('shows everything you earned while production is running', () => {
|
||||||
|
expect(freshness(0)).toBe(1);
|
||||||
|
expect(freshness(5)).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not punish a normal jam', () => {
|
||||||
|
// The whole grace window plus a beat: a stall long enough to notice, diagnose and fix
|
||||||
|
// must leave THE SCREEN exactly as the player left it.
|
||||||
|
expect(freshness(BOREDOM_GRACE_SECONDS)).toBe(1);
|
||||||
|
expect(freshness(BOREDOM_GRACE_SECONDS - 1)).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('takes minutes, not seconds, to forget', () => {
|
||||||
|
// A minute of silence has barely dented it; the sky is patient.
|
||||||
|
expect(freshness(BOREDOM_GRACE_SECONDS + 30)).toBeGreaterThan(0.8);
|
||||||
|
// Fully clean only after the player has genuinely walked away.
|
||||||
|
expect(BOREDOM_GRACE_SECONDS + BOREDOM_HORIZON_SECONDS).toBeGreaterThanOrEqual(180);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('reaches clean at the horizon and stays there', () => {
|
||||||
|
expect(freshness(BOREDOM_GRACE_SECONDS + BOREDOM_HORIZON_SECONDS)).toBe(0);
|
||||||
|
expect(freshness(BOREDOM_GRACE_SECONDS + BOREDOM_HORIZON_SECONDS + 9999)).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('decays monotonically', () => {
|
||||||
|
let prev = 2;
|
||||||
|
for (let s = 0; s <= BOREDOM_GRACE_SECONDS + BOREDOM_HORIZON_SECONDS + 60; s += 5) {
|
||||||
|
const f = freshness(s);
|
||||||
|
expect(f).toBeLessThanOrEqual(prev);
|
||||||
|
expect(f).toBeGreaterThanOrEqual(0);
|
||||||
|
prev = f;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sits at half way through the decay', () => {
|
||||||
|
expect(freshness(BOREDOM_GRACE_SECONDS + BOREDOM_HORIZON_SECONDS / 2)).toBeCloseTo(0.5, 5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('treats a nonsense idle time as fresh rather than wiping the sky', () => {
|
||||||
|
expect(freshness(NaN)).toBe(1);
|
||||||
|
expect(freshness(-10)).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
27
fktry/src/screen/boredom.ts
Normal file
27
fktry/src/screen/boredom.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Boredom — the factory's work evaporating off THE SCREEN.
|
||||||
|
*
|
||||||
|
* If nothing ships for a long stretch, the sky slowly forgets. The corruption LEDGER is
|
||||||
|
* untouched: history is not erased, only the display decays. So when production resumes the
|
||||||
|
* targets are instantly back where they were and the picture snaps home in about a second.
|
||||||
|
*
|
||||||
|
* The horizon is deliberately generous. A jam, a rebuild, a rethink of the bus — none of
|
||||||
|
* those are supposed to read as punishment. The player should have to genuinely walk away
|
||||||
|
* before the sky starts cleaning itself.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** No shipments for this long before the sky begins to forget at all. */
|
||||||
|
export const BOREDOM_GRACE_SECONDS = 60;
|
||||||
|
/** ...and this long again to fade from full corruption to clean. */
|
||||||
|
export const BOREDOM_HORIZON_SECONDS = 180;
|
||||||
|
|
||||||
|
const clamp01 = (x: number) => Math.min(1, Math.max(0, x));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How much of the ledger's corruption is still on display, 0..1.
|
||||||
|
* 1 = everything you earned is showing; 0 = the sky has forgotten (the tallies have not).
|
||||||
|
*/
|
||||||
|
export function freshness(idleSeconds: number): number {
|
||||||
|
if (!(idleSeconds > BOREDOM_GRACE_SECONDS)) return 1; // NaN-safe: unknown idle reads as fresh
|
||||||
|
return 1 - clamp01((idleSeconds - BOREDOM_GRACE_SECONDS) / BOREDOM_HORIZON_SECONDS);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user