Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fire

A desktop productivity organism.

A fire burns in a window on your machine. Your work is its only fuel. It begins dying the moment you stop, it climbs from a spark in dry leaves to an omniversal flame across 2600 continuous stages, and if you let it go out, it takes your session down with it.

This is a native desktop application (Electron), and it runs as a desktop pet: a small, transparent, always-on-top flame with no window frame, no taskbar entry, and click-through enabled so it floats over your work without ever getting in the way. There is no window to open or manage — it lives in the system tray. It runs locally, reads your OS directly, and makes no network requests of any kind.


The one idea

The fire is always decaying. Work does not add progress — work offsets decay.

There is no pause, no banked credit, no coasting. Every frame of a healthy fire is live evidence that you are working right now.

dL/dt  =  gain(work)  −  decay(ascension, starvation)  −  poison(distraction)

Higher forms cost exponentially more to sustain. A campfire nearly maintains itself. A quasar demands near-continuous focus. The Omniversal Flame is asymptotically reachable and is meant to be nearly impossible to hold.


Install

npm install
npm start

Requires Node 20+.

A transparent flame appears in a corner of your screen and a flame icon appears in your system tray. Right-click the tray icon for everything: move it to a different corner, resize it, make it clickable/draggable (it's click-through by default), customize its look, pick a theme, declare a Sabbath, edit settings, or quit.

The pet

  • Transparent — only the fire is visible; there is no panel or box.
  • Click-through — clicks pass straight to whatever is behind it. Toggle this from the tray to drag it somewhere new.
  • Always-on-top, all-workspaces — a productivity pet you cannot bury or escape by switching desktops.
  • Glanceable — no numbers by default. The epoch name whispers in only when you climb, when you're starving, or during a shutdown countdown.
  • Tray-only — no dock icon, no taskbar entry, no Alt-Tab clutter.

For a full framed window with the complete HUD (useful for debugging or if you just want the dashboard), set window.mode to "window" in ~/.fire/config.json.

Customize the look — live, no restart

Right-click the tray → Customize… opens a small panel. Everything in it is applied to the pet as you drag and saved to ~/.fire/config.json, so it survives a restart. There is also a Theme submenu of one-click presets (Classic Fire, Cold Fire, Toxic, Violet Void, Molten Gold, Inferno, Vortex, 3D Rotating Column, Voxel Figure, Voxel Flame, …).

The fire shader stays one shader — every fire control is a modulation of it. Most defaults are identity; the only exceptions are the Effects (embers and bloom ship on by tasteful defaults). Set those two to 0 and the fire is exactly the original — nothing else changes the base look until you move a control.

Group Controls
Scene Fire (the productivity pet) or Voxel — a pixelated 3D scene of rotating figures. Pick a figure: flame · cube · sphere · torus · a humanoid figure · a woven knot/mesh · an obsidian cube of black glass · a space cube of drifting nebula and stars · a faceted crystal gem · a plasma orb threaded with electric arcs · a DNA helix · a spinning galaxy. Each rotates and has a small idle animation.
Colour Hue rotation · a colour cycle (living colour — the hue drifts on its own) · saturation · brightness · a custom base → mid → tip gradient blended over the physical blackbody ramp (Custom palette). Applies to both scenes.
Motion Animation speed (also the voxel spin speed) · turbulence
Shape Size (master zoom — shrink it so the big cosmic tiers don't fill the screen) · width · height · swirl (bias a plume toward a spinning vortex)
3D Rotating column — wraps the fire texture around a vertical cylinder and spins it in depth, with round limb shading
Effects Embers — rising, twinkling sparks off the flame (more when you're working). Bloom & rays — soft glow bloom plus god-rays and a 4-point starburst on the bright cosmic tiers. Both are on by tasteful defaults; set them to 0 for the plain fire.
Pixelate Chunky pixel blocks. Works on the fire; strongest in the voxel scene.

There are one-click presets for the animated looks too — Aurora, Iridescent, Rainbow Cycle, Ember Storm, Nova Bloom — and for the new voxel scenes (Crystal Gem, Plasma Orb, DNA Helix, Galaxy).

The Voxel scene renders on its own canvas and is a separate raymarched shader (shaders/voxel.frag) — the fire itself is never touched. Fire is the default; switching scenes is live. (Importing your own .obj/.glb models is a planned follow-up; today's figures are built-in.)

All of it lives under theme in ~/.fire/config.json if you would rather edit it by hand; out-of-range values are clamped on load, so you can't break the renderer from the file. See config.example.json.

Progression — reshape how the climb feels

Right-click the tray → Progression (climb pacing), or open Customize… and scroll to the Progression section. This reshapes how the fire's look paces the 2600-stage climb using a mathematical growth curve, without touching the game: your stages, epochs, ceiling and ledger all still run on the real ascension — only the picture's tempo changes.

Pick a curve and tune a couple of knobs:

Curve Feel
Linear the default — the look tracks the ladder one-to-one
Eased slow-in / slow-out — a gentle build and settle (power)
Logistic a smoulder, then an explosion, then a plateau — set where it lands (midpoint, rate)
Gompertz a lag where nothing seems to happen, then a burst (lag)
Richards front-loaded or back-loaded drama (nu asymmetry)
Bézier an authored ease

For example Late Bloom keeps the whole first two-thirds of the ladder a low ember and compresses all the cosmic spectacle into the top. Every curve is forced monotone and endpoint-pinned (a spark still precedes a star; stage 0 and stage 2600 look exactly as they do today), so you can't create a discontinuity or a backwards ladder — even by hand-editing progression in ~/.fire/config.json. The default is identity, so a fresh install is unchanged until you opt in.

Trackers — counters, notes, timers in a ticker

Right-click the tray → Trackers. You can keep small things next to the fire, shown one at a time in a quiet ticker carousel that cycles under the flame:

Type What it is
Counter A number you bump up or down by a step you set — days-since, reps, a score, coffees.
Note A short phrase you edit — your current focus, a reminder, a mantra.
Countdown Counts down from a duration to zero, then a desktop notification fires.
Stopwatch Counts up since you start it — time on task.

Open Trackers → Manage trackers… to add, rename, edit, and delete them. For a quick change without opening anything, the tray Trackers submenu can bump a counter by its step or start/pause/reset a timer directly. Timers keep real time across a restart, and everything is saved under trackers in ~/.fire/config.json. Trackers are independent of the fire — they never change how it looks or burns.

Always there — start at login

Right-click the tray icon → Start at login. The pet then launches with your session every time. (On Windows/macOS this uses the OS login-item registry; on Linux/WSL it writes ~/.config/autostart/fire.desktop.) You can also set "autostart": true in ~/.fire/config.json.

Which OS is it watching?

fire sees whatever desktop it can actually reach:

You are on Sensor Notes
Windows native Win32 full experience
WSL Windows, via interop reads the Windows desktop, not the Linux one
Linux/X11 xdotool + xprintidle sudo apt install xdotool xprintidle

The WSL case is deliberate and important. A WSL-local sensor would report a serene, idle desktop while you are three hours into Shorts on the Windows host. fire runs a resident powershell.exe probe across the interop boundary so it watches the desktop you actually use.

Recommended: for the full experience (a shame overlay that can cover Windows apps, correct always-on-top behavior), run it natively on Windows — clone to the Windows filesystem and npm install && npm start from PowerShell. Running under WSLg works and is fine for development, but the overlay is confined to the WSLg surface.


How it knows you are working

Two sensors, sampled at 4 Hz:

  1. Foreground window — process name + title bar text → FUEL / NEUTRAL / POISON
  2. Input activity — milliseconds since last input, and a burst count
idle > 120s          → −0.30   you are gone. the fire notices.
idle > 45s           →  0.00   staring is not working.
POISON window        → −1.00   actively hostile
FUEL, typing hard    → +1.00
FUEL, reading        → +0.35   thinking counts. it should.
NEUTRAL              →  ×0.15

Ten minutes of Shorts erases three epochs.

Privacy

fire reads only a process name, a window title, and a millisecond idle timestamp. It does not read keystrokes, key codes, clipboard, page content, or window contents. It has no network code. Everything lives in ~/.fire/.


The ladder

26 epochs × 100 substages = 2600 stages. The renderer consumes ascension as a raw float and morphs continuously, so adjacent stages are nearly identical and there are no sprite swaps anywhere.

Spark · Ember · Kindling Flame · Campfire · Bonfire · Pyre · Wildfire ·
Firestorm · Fire Tornado · Living Flame · Forge-Heart · Solar Flare ·
Protostar · Main-Sequence Star · Blue Giant · Supernova · Pulsar · Magnetar ·
Quasar · Accretion Disk · Galactic Core · Galaxy Cluster · Cosmic Web ·
Universe-Flame · Multiversal Conflagration · Omniversal Flame

At Living Flame (epoch 9) the fire stops being a thing and starts being someone. It looks back at you. Everything above that is cosmological.

Your sustained work quality sets a hard ceiling you cannot exceed:

Sustained work You top out around
reading only Fire Tornado
a solid day Pulsar
flawless Omniversal Flame (asymptotic)

Punishment

Rung Trigger Effect Default
0 GUTTER unfuelled 20s fire visibly suffers on
1 WARN lost an epoch notification naming what you lost on
2 SHAME L < 40 fullscreen overlay + your permanent record on
3 BLOCK L < 15 block poison windows off
4 LOCK extinction force OS screen lock off
5 NUCLEAR extinction OS shutdown off, and disarmed

Enable rungs in ~/.fire/config.json.

Arming the shutdown

Shutdown can destroy unsaved work, so it requires deliberate consent:

{
  "punish":  { "lock": true },
  "nuclear": {
    "enabled": true,
    "consent": "I ACCEPT THE LOSS OF UNSAVED WORK"
  }
}

The flag alone does nothing. The phrase must match exactly.

Six independent guards must all pass before the machine powers off. It will not fire if:

  • it is not armed (flag + exact phrase)
  • the lock rung is disabled (shutdown may never outrank a rung you turned off)
  • the machine is dormant
  • the app launched less than 120 seconds ago
  • a sleep/crash gap was detected this session
  • a countdown is already running

Every guard is re-checked at the moment of firing, not just when the countdown starts. The countdown is 60 seconds, fullscreen, and abortable with Esc or the button. All of this is covered by tests in test/safety.test.js.


Dormancy — you are never punished for time you could not work

If the machine is asleep, locked, hibernating, or crashed, you cannot be working, so you cannot be failing. Ascension freezes completely.

Two independent mechanisms, because neither alone is enough:

  1. Power events (suspend / lock-screen / shutdown) — fast and explicit, but silent on hard crashes, power loss, and some lid-close paths.
  2. The wall-clock gap guard — if real time advanced far past our tick loop, the process was frozen, and that interval is discarded unconditionally.

The guard is the backstop that makes sleep, crash, lid-close, and power-cut all resolve identically with no special cases.

A crash is never a death. If the sensor itself fails, fire goes dormant rather than assuming you stopped working — it refuses to judge what it cannot see.

Declared away-time is available too, and is logged rather than punished:

window.fire.sabbath(true)   // stepping away on purpose

The Ledger

~/.fire/ledger.jsonl is append-only and never rewritten. Every death you have ever caused stays in it permanently, and is shown back to you in the shame overlay.

{"t":"2026-07-20T18:04:11Z","event":"EXTINCTION","peakL":1840,
 "peakEpoch":"Quasar","livedFor":19442,"killedBy":"POISON:Shorts","punishment":"LOCK"}

~/.fire/state.json is checkpointed every 5s via atomic tmp+fsync+rename, so a kill -9 costs you at most five seconds.


Layout

src/main/          truth lives here
  engine.js        the heat equation — pure, synchronous, no I/O
  tiers.js         the 26 epochs
  sensors/         index.js · windows.js · linux.js · probe.ps1
  classify.js      {proc,title} → FUEL | NEUTRAL | POISON
  session.js       dormancy: power events + wall-clock gap guard
  punish.js        the ladder and the safety contract
  store.js         atomic state + append-only ledger
  themes.js        the look, as data: schema, presets, clamp gate (pure)
  progression.js   climb pacing: growth-curve remap of ascension, clamp gate (pure)
  trackers.js      user trackers (counters/notes/timers), as data + transitions (pure)
  tray-icon.js     generated flame PNG for the tray (pure encoder + Electron glue)
src/renderer/      the fire itself
  gl.js            WebGL2 host for the fire shader
  voxel.js         WebGL2 host for the pixelated 3D scene (sibling of gl.js)
  shaders/         fire.frag (continuous morph, zero branching) + voxel.frag
  hud.js           4 Hz sim → 60 fps render, everything interpolated; scene switch
  settings.html/js the live Customize… panel
  trackers.html/js the trackers manager panel; a ticker carousel in the HUD

engine.js is pure — step(state, {w, dt}) → newState, no Electron, no clock, no I/O. That is what makes the entire simulation testable without a display.

Tests

npm test

109 tests covering the heat equation, equilibrium math, dormancy, the gap guard, classification against real window titles, every nuclear safety guard, the theme system (clamp/validation, presets, scene/figure selection, the generated tray-icon PNG), the progression curves (identity, monotonicity, endpoint pinning, the remap LUT), and the trackers (clamp gate, counter/timer transitions, countdown expiry, formatting).

Tuning

Everything lives in ~/.fire/config.json. To make it crueller, raise DECAY_BASE or POISON_RATE. To make the top reachable, raise CLIMB_RATE.

Custom rules are checked before the built-ins:

"rules": [
  { "class": "POISON", "title": "hacker ?news", "why": "HN" },
  { "class": "FUEL",   "title": "reddit\\.com/r/rust", "why": "research" }
]

About

A desktop productivity organism — your work is its only fuel. Live-customizable flame (colours, shape, motion, 3D) across 2600 continuous stages.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages