Globale Timescale #90

Closed
opened 2026-09-14 07:28:03 +02:00 by admin · 1 comment

Ein globale Timescale (default: 1) - in der GUI selbst brauche ich (noch) keinen Regler. Wenn ich auf "Pause" gehe während dem Play Mode muss diese auf 0 gesetzt werden.

Was beeinflusst die globale Timescale: Particle Time, Shader Time, ich schätze auch die Deltatime

Ich glaube auch wenn ich auf "Play" klicke, dann wird die Time so gesehen nicht zurückgesetzt (Particle effect ist da wo er gerade ist und shader time ebenso - da bin ich mir aber nicht sicher), beim stoppen vom Play mode müsste daher die aktuelle globale Time auch wieder auf 0 gesetzt werden.

Ein globale Timescale (default: 1) - in der GUI selbst brauche ich (noch) keinen Regler. Wenn ich auf "Pause" gehe während dem Play Mode muss diese auf 0 gesetzt werden. Was beeinflusst die globale Timescale: Particle Time, Shader Time, ich schätze auch die Deltatime Ich glaube auch wenn ich auf "Play" klicke, dann wird die Time so gesehen nicht zurückgesetzt (Particle effect ist da wo er gerade ist und shader time ebenso - da bin ich mir aber nicht sicher), beim stoppen vom Play mode müsste daher die aktuelle globale Time auch wieder auf 0 gesetzt werden.
admin added this to the Development project 2026-09-14 07:28:03 +02:00
admin moved this to Next in Development on 2026-09-14 07:28:08 +02:00
Owner

Gebaut, gemessen, sechsfach gegengeprüft — 0e0a21d, Wiki 7c3ee88.

Deine drei Punkte

1. Globale Timescale, default 1, ohne Regler. src/core/time.ts hält ab jetzt eine Uhr: sie summiert dt * scale pro Frame, statt performance.now() zu lesen. ShaderLibrary.now() und ParticleLibrary.now() geben sie zurück, und Editor.tick reicht denselben Schritt an Welt, Editor-Lauf und Animations-Vorschau weiter. Deltatime, Partikelalter und Shaderzeit sind damit dieselbe Größe — die Timescale ist eine einzige Multiplikation. Kein Regler in der GUI, gesetzt wird sie über __gm.setTimeScale(v).

2. Pause setzt sie auf 0. Als Gatter, nicht als Überschreibung: effectiveScale(scale, paused) liefert 0, gameClock.scale behält seinen Wert. Ein späterer Regler überlebt die Pause damit. Weil die Uhr selbst stillsteht, braucht nichts darunter ein rebase wie der Hold aus #86.

3. Play setzt die Zeit nicht zurück — deine Vermutung war richtig. Belegt: beide Bibliotheken sind Modul-Singletons, ihre Startsekunde wird beim Laden gesetzt und nirgends zurückgesetzt; Play rührt sie nicht an.
Deine Schlussfolgerung habe ich korrigiert: nur beim Stop zurückzusetzen reicht nicht, denn danach läuft die Editor-Uhr weiter — ein späterer Play-Klick begänne bei „Sekunden seit dem letzten Stop", nicht bei 0. Jetzt wird an beiden Kanten zurückgesetzt: ein Lauf ist ab Sekunde 0 reproduzierbar, und nach dem Stop sieht die Scene View aus wie frisch geladen.

Zwei Funde, die nicht im Issue stehen

Die Falle beim Reset. ParticleField.startedAt ist eine absolute Sekunde dieser Uhr. Nach einem Reset liegt sie in der Zukunft, now - startedAt wird negativ, jedes Feld wäre tot. Eine Zeile in sync() lässt ein Feld mit Ursprung in der Zukunft neu anfangen — das deckt Scene, Game und Tab-Vorschau auf einmal und erledigt einen Altfehler mit: nach einem freigegebenen particleTime()-Freeze war die Vorschau vorher dauerhaft leer.

Ein latent flakiger Check, älter als diese Runde. ParticlePreview stellte die Vorschau auf Sekunde 0,5, indem es sich die Uhr ausrechnete, die 0,5 ergäbe (now - elapsed + held). Über 200 000 zufällige Ursprünge verfehlt der Umweg die letzte Stelle in 18,8 % der Fälle und zeigt in 9,4 % ein Partikel zu wenig, weil floor(0.5 * 20) dann 9 ist. Der Check war seit seiner Entstehung ein Münzwurf und fiel erst auf, als die neue Uhr den Stand der Zahlen verschob. Das Feld bekommt jetzt das Alter statt einer Uhr, die es ergäbe (ParticleField.hold).

Geprüft, nicht behauptet

./check.sh === CHECK EXIT 0 ===, 931 Tests (921 + 10 neue)
e2e 18 + 28 + 31 ALL PASSED – 113 Checks, E2E EXIT 0
e2e 31 mit der neuen Wache ALL PASSED – 35 Checks
e2e 25 (Animations-Vorschau) ALL PASSED – 37 Checks
Gültigkeit Neubau nach allen Gegenproben ergibt wieder index-DpJkjRx2.js — inhaltsgleich; keine Sonden im Diff

Sechs Gegenproben, jede beißt an ihrer Stelle:

Verbogen Ergebnis
Pause ignoriert (Gatter weg) 2 Unit-Tests
Frame erst skaliert, dann gedeckelt 1 Unit-Test
Kein Reset bei Play/Stop 2 FAILED: Uhr läuft durch, 13,30 → 13,78 statt Sprung auf 0
Selbstheilung des Feldes entfernt 2 FAILED: thawed: 0, afterRun: 0 statt 7/7
Welt bekommt rohes dt 1 FAILED: Uhr verdoppelt (0,62 → 1,20), Box nicht (61,7 → 60,0)
Animations-Vorschau auf rohem dt 1 FAILED: Bild rückt bei Skala 0 von Frame 0 auf 1

Entscheidung im Lauf

Auf Nachfrage: einheitlich. Alles, was sich von selbst bewegt, nimmt seinen Schritt von dieser Uhr — auch die Animations-Tab-Vorschau. Sie friert bei Pause also mit ein, obwohl sie weiter playing: true meldet. Eine zweite Uhr daneben ist das, was man vermeidet, nicht was man hinzufügt.

Zähler 833 (824 gemessen in CI-Lauf 34 + 9 neue).

Gebaut, gemessen, sechsfach gegengeprüft — `0e0a21d`, Wiki `7c3ee88`. ## Deine drei Punkte **1. Globale Timescale, default 1, ohne Regler.** `src/core/time.ts` hält ab jetzt **eine** Uhr: sie summiert `dt * scale` pro Frame, statt `performance.now()` zu lesen. `ShaderLibrary.now()` und `ParticleLibrary.now()` geben sie zurück, und `Editor.tick` reicht **denselben Schritt** an Welt, Editor-Lauf und Animations-Vorschau weiter. Deltatime, Partikelalter und Shaderzeit sind damit dieselbe Größe — die Timescale ist eine einzige Multiplikation. Kein Regler in der GUI, gesetzt wird sie über `__gm.setTimeScale(v)`. **2. Pause setzt sie auf 0.** Als **Gatter**, nicht als Überschreibung: `effectiveScale(scale, paused)` liefert 0, `gameClock.scale` behält seinen Wert. Ein späterer Regler überlebt die Pause damit. Weil die Uhr selbst stillsteht, braucht nichts darunter ein `rebase` wie der `Hold` aus #86. **3. Play setzt die Zeit nicht zurück — deine Vermutung war richtig.** Belegt: beide Bibliotheken sind Modul-Singletons, ihre Startsekunde wird beim Laden gesetzt und nirgends zurückgesetzt; Play rührt sie nicht an. **Deine Schlussfolgerung habe ich korrigiert:** nur beim Stop zurückzusetzen reicht nicht, denn danach läuft die Editor-Uhr weiter — ein späterer Play-Klick begänne bei „Sekunden seit dem letzten Stop", nicht bei 0. Jetzt wird an **beiden Kanten** zurückgesetzt: ein Lauf ist ab Sekunde 0 reproduzierbar, und nach dem Stop sieht die Scene View aus wie frisch geladen. ## Zwei Funde, die nicht im Issue stehen **Die Falle beim Reset.** `ParticleField.startedAt` ist eine *absolute* Sekunde dieser Uhr. Nach einem Reset liegt sie in der Zukunft, `now - startedAt` wird negativ, jedes Feld wäre tot. Eine Zeile in `sync()` lässt ein Feld mit Ursprung in der Zukunft neu anfangen — das deckt Scene, Game und Tab-Vorschau auf einmal und erledigt einen **Altfehler** mit: nach einem freigegebenen `particleTime()`-Freeze war die Vorschau vorher dauerhaft leer. **Ein latent flakiger Check, älter als diese Runde.** `ParticlePreview` stellte die Vorschau auf Sekunde 0,5, indem es sich die Uhr ausrechnete, die 0,5 *ergäbe* (`now - elapsed + held`). Über 200 000 zufällige Ursprünge verfehlt der Umweg die letzte Stelle in **18,8 %** der Fälle und zeigt in **9,4 %** ein Partikel zu wenig, weil `floor(0.5 * 20)` dann 9 ist. Der Check war seit seiner Entstehung ein Münzwurf und fiel erst auf, als die neue Uhr den Stand der Zahlen verschob. Das Feld bekommt jetzt **das Alter** statt einer Uhr, die es ergäbe (`ParticleField.hold`). ## Geprüft, nicht behauptet | | | |---|---| | `./check.sh` | `=== CHECK EXIT 0 ===`, **931 Tests** (921 + 10 neue) | | e2e 18 + 28 + 31 | **ALL PASSED – 113 Checks**, `E2E EXIT 0` | | e2e 31 mit der neuen Wache | **ALL PASSED – 35 Checks** | | e2e 25 (Animations-Vorschau) | **ALL PASSED – 37 Checks** | | Gültigkeit | Neubau nach allen Gegenproben ergibt wieder `index-DpJkjRx2.js` — inhaltsgleich; keine Sonden im Diff | **Sechs Gegenproben, jede beißt an ihrer Stelle:** | Verbogen | Ergebnis | |---|---| | Pause ignoriert (Gatter weg) | 2 Unit-Tests | | Frame erst skaliert, dann gedeckelt | 1 Unit-Test | | Kein Reset bei Play/Stop | **2 FAILED**: Uhr läuft durch, 13,30 → 13,78 statt Sprung auf 0 | | Selbstheilung des Feldes entfernt | **2 FAILED**: `thawed: 0, afterRun: 0` statt 7/7 | | Welt bekommt rohes `dt` | **1 FAILED**: Uhr verdoppelt (0,62 → 1,20), Box nicht (61,7 → 60,0) | | Animations-Vorschau auf rohem `dt` | **1 FAILED**: Bild rückt bei Skala 0 von Frame 0 auf 1 | ## Entscheidung im Lauf Auf Nachfrage: **einheitlich**. Alles, was sich von selbst bewegt, nimmt seinen Schritt von dieser Uhr — auch die Animations-Tab-Vorschau. Sie friert bei Pause also mit ein, obwohl sie weiter `playing: true` meldet. Eine zweite Uhr daneben ist das, was man vermeidet, nicht was man hinzufügt. Zähler **833** (824 gemessen in CI-Lauf 34 + 9 neue).
admin moved this to Done in Development on 2026-09-14 09:51:13 +02:00
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#90