Ontwerp
Techniek
Systemen
Beweging
Roy Heilbron
portfolio · bezig00
ROY HEILBRON
Werk

Struq Voice

Dicteren op Windows dat landt in het venster waar je al werkte.

Jaar
2026
Rol
Ontwerp, architectuur, bouw en release. Alleen.
Status
live
Stack
Electron, React, TypeScript, SQLite, Whisper, Parakeet
Struq Voice: hou een toets ingedrukt, spreek, laat los, en de tekst staat er
Wat het is

Een dicteerprogramma voor Windows dat in de tray zit. Je houdt Ctrl+Spatie ingedrukt in welk venster dan ook, je praat, je laat los, en de tekst staat bij je cursor. Het transcriberen gebeurt op je eigen machine. Er gaat geen audio naar buiten.

Het probleem

Dicteren op Windows vraagt je meestal om weg te gaan van waar je mee bezig bent. Je opent een app, neemt op, wacht, kopieert, gaat terug en plakt. Tegen de tijd dat de zin in het document staat, is de gedachte die hem opleverde al weg. De afstand tussen praten en de tekst zien staan is het hele probleem, en die afstand zit in de wachttijd en in het wisselen van venster.

Vier stappen: hold, speak, release, paste, elk met de techniek erachter
Het hele pad, in de bewoording van de app zelf. Hieronder staat wat daar technisch onder zit.
Hoe het is gebouwd

Vier vensters, elk met één taak

Het hoofdproces doet levenscyclus, tray, sneltoetsen, engines, plakken en opslag. Een verborgen venster houdt de microfoon warm. Een overlay toont de opnamestatus en kan geen focus krijgen. Het hoofdvenster bestaat alleen als je het opent. Geen enkel venster kent het werk van een ander.

Eén toestandsmachine voor een opname

Van idle naar arming, listening, transcribing en delivering, met foutpaden terug naar idle. Tray, overlay en hoofdvenster tekenen alle drie uit uitzendingen van diezelfde toestand. Niets anders bezit opnamestatus, dus twee schermen kunnen niet iets anders beweren.

Grenzen die vastliggen in code

De renderer importeert nooit uit main. Gedeelde code heeft geen side effects en geen Electron-imports, dus die draait in beide processen en in tests. Elk IPC-kanaal staat in één bestand en nergens anders. Elk venster draait met context-isolatie aan, node-integratie uit en sandbox aan. Geen uitzonderingen.

Drie engines met een router ertussen

Parakeet lokaal voor 25 Europese talen, Whisper lokaal voor lastige audio en 99 talen, en een cloudmodel voor wie niets wil installeren. De router valt terug als een engine niet klaar is, faalt of te lang duurt. Welk model wordt aangeraden hangt af van de processor, de videokaart en het geheugen van de machine.

Het Dictate-scherm met woorden, spreektijd, tempo en de recente transcripties
Dictate. De sneltoets staat onder in beeld omdat je hem daar nooit hoeft te zoeken: hij werkt overal.
Keuzes en wat ze kostten
  1. 01

    De microfoon staat altijd open

    Aanleiding

    Een audio-apparaat openen kost 100 tot 300 milliseconden. Dat zit precies in het pad tussen de toets indrukken en het eerste woord.

    Keuze

    Een verborgen venster houdt getUserMedia open met een AudioWorklet die doorloopt. Een opname begint dus met aanhangen aan een buffer die er al is. De 250 milliseconden audio van vóór de toetsaanslag horen bij de opname, zodat een vroeg eerste woord niet wegvalt.

    Wat het kostte

    Er staat permanent een venster open en er loopt permanent audio door het geheugen. Dat is geheugen dat je kwijt bent voor iets wat je misschien uren niet gebruikt.

  2. 02

    Vergaderingen decoderen buiten het hoofdproces

    Aanleiding

    De aanroep die audio omzet naar tekst blokkeert de draad waarop hij draait. Bij een dictaat van drie seconden merk je dat niet. Bij een vergadering van een uur staat daarmee ook de tray stil, en de sneltoetsen, en de instellingen, en elk venster.

    Keuze

    Een vergadering start een apart proces met een eigen event loop. Dat proces doet spraakdetectie, herkenning en het uit elkaar halen van sprekers, en wordt afgeschoten zodra de vergadering stopt.

    Wat het kostte

    Zolang een vergadering loopt staat het model twee keer in het geheugen. Dat is de reden dat het proces per vergadering wordt gestart en niet warm blijft staan.

  3. 03

    De overlay mag nooit focus krijgen

    Aanleiding

    Als de opname-indicator het actieve venster wordt, plakt de tekst daarna in het verkeerde venster. Precies de fout die het hele idee onderuithaalt.

    Keuze

    De overlay wordt aangemaakt met focusable op false, zodat Windows het voorgrondvenster niet wisselt terwijl er een opname loopt. Het plakken gebeurt met een nagebootste Ctrl+V via dezelfde low-level hook, met een PowerShell-terugval voor het zeldzame venster dat dat weigert.

    Wat het kostte

    De overlay kan geen toetsaanslagen aannemen, dus annuleren moest via een globale sneltoets die alleen bestaat terwijl er een opname loopt.

  4. 04

    Lokaal valt nooit vanzelf terug op de cloud

    Aanleiding

    Een router die netjes terugvalt zou bij een fout in de lokale engine je audio naar een server sturen.

    Keuze

    Van lokaal naar cloud gebeurt alleen als je dat zelf aanzet. De cloudsleutel wordt versleuteld opgeslagen met Windows DPAPI en komt nooit terug door IPC naar een renderer.

    Wat het kostte

    Als de lokale engine stukgaat, krijg je een foutmelding in plaats van een transcript. Dat is de bedoeling.

  5. 05

    Updates ondertekend met Ed25519

    Aanleiding

    Er is geen commercieel code-signing certificaat, en zonder dat komt een updatekanaal neer op: voer uit wat de feed serveert.

    Keuze

    Elk bestand draagt een handtekening over hash en versienummer, gecontroleerd tegen een publieke sleutel die in de app is meegecompileerd. Een mislukte controle breekt de installatie af in plaats van te waarschuwen.

    Wat het kostte

    SmartScreen waarschuwt nog steeds bij de eerste installatie. Dat kost vertrouwen bij mensen die de uitleg niet lezen.

Het Models-scherm met een aanbeveling voor deze pc en de volledige catalogus
Eén aanbeveling per machine, met de processor, videokaart en hoeveelheid geheugen die de keuze bepaalden er kaal onder.
Wat er nu staat
  • Werkt in elke Windows-applicatie, ook in applicaties die globale sneltoetsen normaal wegvangen.
  • Eenendertig modellen in de catalogus, met echte bestandsgroottes en sha256-controle uit de Hugging Face API.
  • Vergaderingen worden opgenomen, per spreker uit elkaar gehaald en geëxporteerd als Markdown, tekst of ondertitels.
  • Elk transcript doorzoekbaar via FTS5, met een gevirtualiseerde lijst die bij duizenden regels op snelheid blijft.
  • Ontbreekt een native module, dan start de app alsnog. Zonder database geen geschiedenis, zonder toetsenbordhook valt push-to-talk terug op toggle.
Een vergaderingstranscript met tijdcodes en drie sprekers
Een vergadering, per spreker uit elkaar gehaald. Dit deel draait in een eigen proces, zodat de rest van de app blijft reageren.