aboutsummaryrefslogtreecommitdiff
path: root/docs/tweens.org
blob: 9ac87cd8d48415adad424ad3cae1a77e2cd01159 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#+title: Tweens
#+author: Downstroke Contributors

* Overview

The =downstroke-tween= module interpolates **numeric** entity properties over wall-clock time. It is **decoupled** from the engine: you create tween values, call =tween-step= each frame from your =update:= hook, and store the returned entity back into the scene.

Durations and delays are in **milliseconds**, matching the =dt= argument to =update:=.

* Import

#+begin_src scheme
(import downstroke-tween)
#+end_src

* Core API

** ~make-tween~

#+begin_src scheme
(make-tween entity #!key props duration (delay 0) ease (on-complete #f))
#+end_src

| Keyword | Meaning |
|---------+---------|
| ~props~ | Alist =((#:x . 200) (#:y . 40))= — keyword keys, numeric targets |
| ~duration~ | Positive integer, milliseconds of interpolation (after ~delay~) |
| ~delay~ | Non-negative integer ms before interpolation starts |
| ~ease~ | Easing symbol (see table below) or ~(lambda (t) ...)= with ~t~ in $[0,1]$ |
| ~on-complete~ | Optional ~(lambda (entity) ...)=, called **once** when the tween reaches its targets |

Start values are captured from ~entity~ at construction time. While the tween runs, intermediate values may be **inexact** (flonums) even if starts and ends are integers.

** ~tween-step~

#+begin_src scheme
(tween-step tween entity dt)
#+end_src

Returns ~(values new-tween new-entity)~. Advance time by ~dt~ (ms). Before ~delay~ elapses, ~entity~ is unchanged. After completion, further steps return the same values (idempotent). When the tween completes, ~on-complete~ runs with the **final** entity (targets applied), then the callback slot is cleared.

** ~tween-finished?~ / ~tween-active?~

Predicates on the tween struct.

* Easing

Each ease maps normalized time ~t ∈ [0,1]~ to an interpolation factor (usually in ~[0,1]~; ~back-out~ may exceed ~1~ briefly).

| Symbol | Procedure |
|--------|-----------|
| ~linear~ | ~ease-linear~ |
| ~quad-in~, ~quad-out~, ~quad-in-out~ | quadratic |
| ~cubic-in~, ~cubic-out~, ~cubic-in-out~ | cubic |
| ~sine-in-out~ | smooth sine |
| ~expo-in~, ~expo-out~, ~expo-in-out~ | exponential |
| ~back-out~ | overshoot then settle (Robert Penner–style) |

** ~ease-named~ / ~ease-resolve~

~ease-named~ turns a symbol into a procedure. ~ease-resolve~ accepts a symbol or procedure (identity for procedures) for use in custom tooling.

All easing procedures are exported if you want to compose curves manually.

* Order of operations with physics

Tweens usually **fight** velocity and gravity if both update ~#:x~ / ~#:y~. Typical pattern:

1. Set the entity’s ~#:skip-pipelines~ to skip integration steps you do not want (see [[physics.org][Physics]]).
2. Run ~tween-step~ for that entity.
3. Run your normal physics pipeline (collisions can still run).

Clear ~#:skip-pipelines~ in ~on-complete~ when the tween ends.

Example skip list for “kinematic shove” while keeping tile collisions:

#+begin_src scheme
(entity-set player #:skip-pipelines
  '(jump acceleration gravity velocity-x velocity-y))
#+end_src

* Demo

=bin/demo-tweens= (source =demo/tweens.scm=) shows one row per easing and a crate that tweens horizontally while integration is skipped and tile resolution still runs.

* Limitations (current version)

- Single segment per tween (no built-in chains or yoyo).
- Numeric properties only.
- No engine integration — you wire ~tween-step~ yourself.