
Het dashboard opnieuw ontworpen rond één golfgrafiek
GeekBye v1.8.2 veranderde het dashboard van een afstandsbediening voor opnames in een alleen-lezen analyseweergave — een statsstrip en een 7-daagse golfgrafiek. Beide kenmerkende elementen waren tweede versies, geshipt binnen twintig minuten na hun eerste versies, op dezelfde middag.
Sommige releases voegen een feature toe. GeekBye v1.8.2 verwijderde er vooral één — en die verwijdering is het verhaal. In één enkele middag in februari 2026 veranderden achttien commits de dashboard-home van een afstandsbediening voor opnames in een alleen-lezen analyseweergave: vier stats en één activiteitsgrafiek. Onderweg shipte het een bar chart die tweeëntwintig minuten leefde, een raster van statkaarten dat twintig minuten leefde, en een handgemaakte SVG-golf die beide verving. De hele zoektocht zit bewaard in de commit-tijdstempels, en dat is de beste soort ontwerpdocumentatie die er bestaat.
Het dashboard was geen afstandsbediening meer
Vóór deze release was de dashboard-home een bedieningspaneel. Het opende met een hero card — een grote opname-widget met een LIVE-badge, Pause/Resume/Stop-knoppen, gradient blobs en een useSessionState-hook die alles aan de recorder koppelde. Het dashboard probeerde twee dingen tegelijk te zijn: de plek waar je naar je meetings kijkt en de plek waar je de recorder bestuurt. Twee producten, één scherm, stilletjes in concurrentie.
v1.8.2 koos er één. Het verwijderde de hero card en de useSessionState-bedrading — inclusief een effect dat je automatisch naar de detailpagina van een meeting bracht zodra een sessie eindigde, precies het soort "behulpzame" sprong die mensen midden in hun flow overvalt. Het starten en verbergen van de recorder verhuisde naar een simpele navbar-toggle (een hergebruikte knop die zo'n honderd regels kwijtraakte op weg van sessiecontroller naar aan/uit-schakelaar), ondersteund door een nieuwe navbar:hide-IPC-handler. Wat overbleef was een dashboard dat één ding doet: je laten zien wat je hebt opgenomen. Alleen-lezen. Rustig.
Er zit een kleine, menselijke bug in die overgang die het benoemen waard is, want het is precies het soort ding dat een herontwerp stilletjes introduceert en een scherp oog binnen hetzelfde uur opmerkt. De twee nieuwe sidebar-knoppen — Start en Hide — shipten met hetzelfde generieke grid-icoon, dus ze waren visueel identiek. Twaalf minuten later gaf een vervolgcommit Start een play-icoon, gaf Hide een eye-off-icoon, en kleurde Hide amber, zodat "laat de app verdwijnen" leest als een bewuste actie in plaats van een neutrale tweeling van "start." Iconen zijn copy. Twee knoppen die er hetzelfde uitzien zeggen hetzelfde, en deze betekenden niet hetzelfde.
De bar chart die tweeëntwintig minuten leefde
Dit is het deel waar ik van hou, en het is volledig leesbaar uit de git-log. Om 16:29:34 landde de eerste versie van het herontwerp: een 7-daagse activiteitsgrafiek getekend als balken — geanimeerde kolommen, een minimumhoogte zodat kleine dagen zichtbaar bleven, een gedimd stompje van 2 pixels voor dagen met nul. Redelijk. Conventioneel. Het soort grafiek dat je zonder nadenken pakt.
Om 16:51:21 — tweeëntwintig minuten later — werd hij verwijderd. De vervangende commit zegt precies wat hij deed: "replace bar chart with smooth wave area chart for 7-day activity." En om 16:52:21, één minuut later, haalde een andere commit de afgeronde kaart en rand rondom de golf weg, "for cleaner look."
Waarom? De commits zeggen alleen wat er veranderde, dus het waarom is een interpretatie — maar de vorm van de data maakt het overduidelijk. Dit is een tool waarbij een typische gebruiker nul, één of twee meetings op een willekeurige dag heeft. Zeven balken, de meeste 2 pixels hoog, ogen als een vrijwel lege vlakte. Diezelfde zeven getallen getekend als een doorlopend gevuld vlak ogen als een trend — een zachte golf die stijgt waar de week druk was. Er werd niets vervalst; de y-waarden zijn identiek. Het herontwerp koos gewoon de codering die schaarse, eerlijke data laat lezen als een vorm in plaats van als afwezigheid.
De stats kregen dezelfde behandeling op dezelfde klok. De eerste versie (16:29) zette vier getallen in een 2×4-raster van kaarten. Om 16:49 klapte het raster samen tot één inline statsstrip — een enkele omkaderde rij met haarlijnscheidingen, kleinere letters, één container in plaats van vier. Vijf vakken op het scherm (vier kaarten plus een grafiekkaart) werden er twee (een strip en een golf). De volgende PR voegde nog één eerlijk detail toe: het label "Total Time" werd "Time in Meetings", omdat totaal-van-wat een terechte vraag was die niemand zou moeten hoeven stellen.
Twintig minuten, van eerste versie tot finale, allemaal binnen één pull request. Waren die samengeperst in één enkele "redesign dashboard"-commit, dan was de zoektocht onzichtbaar geweest. Omdat dat niet gebeurde, kun je een ontwerper in real time zien convergeren.
De golf, mechanisch gezien
Er zit hier geen charting library. De golf is een inline SVG opgebouwd in JSX, en het is de moeite waard om ernaar te kijken, want het is een klein, eerlijk recept dat je voor elke sparkline kunt stelen.
De smoothing is de truc. Voor elk paar aangrenzende punten gebruikt het pad een cubic-bezier-segment waarvan de twee controlepunten op het horizontale middelpunt ertussen liggen — cpx = (prev.x + curr.x) / 2 — met de controlepunten op de eigen hoogte van elk uiteinde. Dat is de klassieke flat-tangent-smoothing: de curve glijdt door elk datapunt zonder ooit boven de hoogste of onder de laagste waarde uit te schieten, wat een naïeve Catmull-Rom-spline wél zou doen. Voor een grafiek over aantallen meetings is "teken nooit een bult die een waarde suggereert die niet plaatsvond" geen leuk extraatje; het is correctheid. Het gevulde vlak is dezelfde curve die langs de onderkant gesloten is en geschilderd met een verticaal gradient (cyaan, vervagend van 30% tot bijna niets), en de lijn tekent zichzelf met een framer-motion-pathLength-animatie, van links naar rechts.
Onder de SVG zit het dataloodgieterswerk, en dat is de stille held. Een nieuwe getAggregateStats()-methode op de transcript-repository draait drie prepared statements tegen de lokale SQLite-tabel transcript_sessions: totalen over alle tijd (aantal, opgetelde duur, gemiddelde duur), een voortschrijdende telling over zeven dagen, en een bucket per dag via GROUP BY date(created_at). Dan — en dit is het detail dat de grafiek robuust maakt — loopt een kleine JavaScript-loop de laatste zeven kalenderdagen af en vult elke dag die de query niet teruggaf aan met een nul. De grafiek krijgt daardoor gegarandeerd precies zeven punten, altijd.
Die garantie is wat de edge cases laat verdwijnen in plaats van dat je overal in de view guards nodig hebt. Een lege week? Zeven nullen, en een Math.max(count, 1) op de noemer houdt de lijn plat onderaan in plaats van te delen door nul. Een enkel datapunt dat de x-afstandsformule i / (n − 1) NaN zou laten opleveren? Kan niet gebeuren — de repository levert er nooit minder dan zeven. De weekdaglabels parsen elke bucket zelfs op T12:00:00 in plaats van op kaal middernacht, zodat een YYYY-MM-DD-string niet naar de vorige dag verschuift in een tijdzone met negatieve UTC. Repareer de vorm van de data bij de bron en de renderingcode mag met opzet naïef zijn.
Alles blijft op de machine. De stats-query leest de lokale database, keert terug via een getypeerd transcript:get-stats-IPC-kanaal, en animeert bij het mounten naar vier optellende getallen. Niets van je meetinggeschiedenis verlaat de laptop om deze grafiek te tekenen — wat, voor een tool die je gesprekken opneemt, de enige acceptabele manier is om een analyseweergave te bouwen.
Nog één bug, want herontwerpen slepen ze het licht in
Meegebundeld in dezelfde release zat een fix die niets met het dashboard te maken had en alles met het soort schuld waar een herontwerp over struikelt. De donkere scrollbar-styling van de app was afgedreven naar twee concurrerende CSS-definities van dezelfde class — een oudere paarse en een nieuwere wit-op-donker — en welke won hing af van de cascadevolgorde. Erger nog, alleen elementen die eraan dachten de class toe te voegen kregen überhaupt styling; al het andere viel terug op de standaard lichte scrollbar, en horizontale scrollbars werden nooit gestyled omdat de oude regels alleen een breedte instelden, nooit een hoogte. De fix verwijderde beide definities, stylede de scrollbar globaal op elk element, en haalde de nu dode class weg uit de tien componenten die hem hadden meegedragen. Het is een diff van twee regels, tien keer herhaald — de onglamoureuze belasting van iets twee keer stylen en beide laten voortbestaan.
Drie dingen die deze release ons leerde
- Trek af om te focussen. Het dashboard werd beter door minder te doen — de opnamebediening kwijtraken die het nooit nodig had en één helder ding worden. Een scherm dat zowel viewer als afstandsbediening is, zijn twee halve producten; kies er één en verplaats de ander naar waar hij thuishoort.
- Kies de codering die je data verdient. Schaarse aantallen lezen als afwezigheid in balken en als een trend in een area chart, uit identieke getallen. Dat is geen spin — het is de eerlijke vorm kiezen die echte, dunne data laat communiceren.
- Garandeer de vorm van je data stroomopwaarts. De back-fill-naar-zeven-loop is waarom de grafiekcode geen verspreide null checks heeft: deling-door-nul, NaN-bij-één-punt en ontbrekende dagen verdwijnen allemaal omdat de query precies zeven buckets belooft. Robuuste rendering begint een laag lager.
Voor het vorige hoofdstuk in het v1-verhaal, vier releases in zesentwintig uur (v1.7.6–v1.8.1); en voor de hele boog, de anatomie van software tot in de perfectie uitbrengen.