Files
feuerwerk/todo-notes/on-key-down-repeat.md
T
rootandClaude Opus 5 3ab8d88ad6 Let On key down repeat while the key stays held
A held key fired once and then nothing, so sliding a Tetris piece sideways or
walking a menu meant building a timer next to every key node. Two settings on
the node do it now: Repeat after and Repeat interval, both in milliseconds so
the usual values stay whole numbers (300, 50) instead of 0.3 and 0.05. A delay
of 0 keeps the node exactly as it was, an interval of 0 means every frame.

The browser's own auto-repeat is deliberately not used - Input.press has always
dropped it - because its delay and rate are an operating-system setting of the
player's, not a game's. The repeat is built from the measured hold time instead,
per node, so two nodes on one key keep their own clocks. The rule itself is a
pure function in keyRepeat.ts and is checked without a world.

Both rows stay off the node body while the delay is 0: two lines of "0" on every
key node in every graph would be noise, and the screenshot said so. NodeDef gains
hiddenParams for that; the inspector still shows them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 22:44:00 +02:00

4.1 KiB
Raw Blame History

das on key down event node bräuchte ein "repeat" sprich wie wenn man auf der tastatur eine taste länger drückt:

  • man drückt die taste, das event wir ganz normal gefeuert
  • man hält länger gedrückt, nach einem bestimmten delay, feuert das event nochmal
  • hält man weiterhin gedrückt, feuert das event öfter hintereinandert

das ist ein beispiel szenario für tetris links/rechts shape bewegung

ich denk wir brauchen beim "on key down" event zwei properties:

  • repeat after (seconds)
  • repeat interval (seconds, nachdem das erstmal repeat after aufgerufen wurde)

ist repeat after auf 0 - kein effekt (alles wie bisher) ist repeat interval auf 0 - jedes weitere frame aufrufen


Umgesetzt

Genau die beschriebene Form: zwei Zahlen-Properties am On key down-Node.

Repeat after (ms) Haltedauer bis zur ersten Wiederholung. 0 = kein Effekt, alles wie bisher
Repeat interval (ms) Abstand der weiteren Wiederholungen. 0 = jedes Frame

Beide Felder sind Millisekunden — damit bleiben die ueblichen Werte ganze Zahlen (300, 50) statt 0,3 und 0,05. Die Uhr dahinter rechnet weiter in Sekunden; umgerechnet wird beim Auslesen der Node-Properties.

Der erste Druck feuert immer sofort und unveraendert — die Wiederholung haengt nur hinten dran.

Warum das nicht der Auto-Repeat des Browsers ist

Der Browser feuert bei gehaltener Taste selbst wiederholt keydown. Diese Ereignisse werden seit jeher verworfen (Input.press: if (!this.down.has(key)) ... // ignore auto-repeat), und das bleibt so: Verzoegerung und Rate sind eine Betriebssystem-Einstellung des Spielers, kein Spielparameter. Die Wiederholung wird stattdessen aus der gemessenen Haltedauer gebaut — damit ist sie auf jeder Maschine gleich und pro Node einstellbar.

Die Regel selbst steht als reine Funktion in src/core/graph/keyRepeat.ts, nicht als Bedingung im Runtime-Code — deshalb ist sie ohne Browser pruefbar. Die Haltedauer pro Node liegt in nodeState, derselben Ablage, aus der On timer seine Uhr bezieht.

Eine Entscheidung, die ich getroffen habe

Ein sehr kleines, positives Intervall wird auf 10 ms angehoben — dieselbe Untergrenze, die On timer schon hat. Sonst wuerde ein vertipptes 0,0001 bei einem langen Frame tausende Aufrufe in einem Bild ausloesen. 0 bleibt davon unberuehrt und behaelt seine eigene Bedeutung ("jedes Frame").

Der Node bleibt schmal

Zwei Zeilen Repeat after (ms): 0 an jedem Tastatur-Node waeren reiner Laerm gewesen — ich habe mir das Bild angesehen, es war deutlich sichtbar. Beide Zeilen bleiben vom Node-Koerper weg, solange die Verzoegerung 0 ist; der Inspector zeigt sie immer. Neu dafuer ist NodeDef.hiddenParams. Sobald eine Verzoegerung gesetzt ist, erscheinen beide — auch ein Intervall von 0, denn das ist dort eine Einstellung und keine Abwesenheit.

Der Beweis

Zwei On key down auf derselben Taste, einer schlicht, einer wiederholend — ein einziges Halten misst beide, damit "es hat wiederholt" nicht mit "die Taste kam oefter an" verwechselt werden kann.

Die folgende Ausgabe stammt aus dem Lauf vor der Umstellung auf Millisekunden (daher 0.300 / 0.050 / 0.75 s); das Modul tippt jetzt 300, 50 und 750. Der Nachlauf steht aus.

PASS  a hold shorter than the delay fires once, repeat or not
      – plain 0 → 1, repeating 0 → 1 over 120 ms with a 0.3 s delay
PASS  holding past the delay keeps the repeating node firing, while the plain one counts one press
      – plain +1, repeating +11 over 800 ms (press + ~10 repeats expected)
PASS  a node with no repeat set carries no repeat rows, the repeating one carries both
      – plain ["Key: Right arrow"], repeating [… "Repeat after (s): 0.300", "Repeat interval (s): 0.050"]
PASS  typing a new delay lands on the node
PASS  the delay typed into the inspector is the one the run uses
      – repeating 0 → 1 over 500 ms with the delay raised to 0.75 s

Der letzte ist der wichtigste: derselbe Graph, nur die getippte Zahl geaendert — und der Node schweigt. Damit haengt die Laufzeit nachweislich am Inspector-Wert und nicht an etwas anderem.