Closeness sets the orbit.
Each friend carries a single score, closeness ∈ [3, cap]. It maps to an orbit radius on one universal scale — higher closeness, tighter orbit. The 0.92 exponent gently widens the inner zones. What the cap is depends on what you are to each other: friends cap at 86, an outer band — romance and family cap at 98, allowed to climb almost to the sun's surface. Same closeness, same orbit, for everyone; intimacy just unlocks the innermost sky.
Drag the slider — the four bands are the “friendzones.” 87–98 is intimate-only, past the friend cap.
Moments push. Silence pulls.
Logging a moment nudges closeness by how it felt: 🔥 radiant +12, ☀️ warm +7, 🌗 steady +2, 🌫️ distant −6, ❄️ cold −12.
Between moments, time drifts a friend outward — but gently: a 4-day grace period costs nothing, then 0.45 points per quiet day, capped at −28. Silence alone can never erase a friendship. This drift math is the same for every relationship type — your cap only shapes how close you can get, never how far quiet can pull you back.
Tap a feeling to log a moment (it resets the silence clock), then scrub the quiet days.
Every signal decays with a half-life.
There are no cutoff windows anywhere in the app. Every observation keeps a vote forever — the vote just halves with each half-life. One knob per signal:
Which way are they leaning?
Two kinds of evidence live on one timeline: reads you tag on moments (“leaning in” / “pulling away”, weight 1) and their explicit declaration (weight 2.5). Lean is the decay-weighted average — the newest evidence naturally leads, no precedence rules needed. Even one ancient read fully drives the value until it's superseded.
New events land at “today” (right edge) and outweigh the past. Diamonds are declarations (2.5×).
History is mass.
Warm history accumulates into a foundation (90-day half-life), and a solid past damps how hard fresh negative signals can swing you — a rough week with an old friend reads differently than one with a stranger. Positive lean always passes through untouched.
displayedLean = lean < 0 ? lean · (1 − 0.6 · f) : lean
Energy, momentum, volatility.
Three more decayed signals give each planet its weather:
⚡ Energy
How alive the bond is. Sign-agnostic — a fight is energy too. Saturates around ~4 fresh moments.
🧭 Momentum
Decay-weighted net change — which way things are actually going. Feeds the prediction below.
🌪 Volatility
How often the story flips sign, weighted so recent weaving beats ancient flip-flops.
Energy drives orbital speed — a neglected bond crawls at 0.35×, a vivid one races at 1.5×. Speed also falls off Kepler-style with radius: far planets move slower.
Signals paint the planet.
Nothing about a planet's look is random or stored — appearance is a pure function of the signals. Energy → radiance (body lightness and glow). Lean → temperature: the hue rotates at most 18° toward gold (45°) when they lean in, toward ice (255°) when they pull away — the identity hue always survives, and a cold lean drains saturation. Volatility → turbulence, a progressive stack: storm bands from 0, an unstable rim above 0.4, an erratic corona above 0.7.
core = 62 + 18·e %L, glowα = 0.12 + 0.28·e
bands ∝ v, rim = smoothstep(0.4, 0.8, v), corona = smoothstep(0.7, 1.0, v)
Push volatility past 0.4, then 0.7, to watch the rim and corona kick in.
A dotted path shows where you're headed.
Set an intention for a friend and a dotted trajectory curves out of their planet, arriving about a month ahead at the orbit the physics predicts — your stated pull, plus the momentum you've actually got:
drift → eff − 18 + min(0, m)
No streaks. No scores to win.
Just honest orbits.
Thirty seconds after seeing a friend: tap them, tap how it felt, done. The physics remembers everything else — gently, forever.
open your cosmos