Skip to content

Commit 7502e0a

Browse files
committed
Added 't' variable for use in handout expressions
1 parent 8822959 commit 7502e0a

2 files changed

Lines changed: 17 additions & 11 deletions

File tree

Sequence/Sequence.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,7 @@ var Sequence = Sequence || (() => {
798798
const TIME_EXPR_SCOPE = {};
799799

800800
// Top-level identifiers allowed in value expressions
801-
const EXPR_ALLOWED_VARS = new Set(['orig', 'original', 'prev', 'previous', 'curr', 'current']);
801+
const EXPR_ALLOWED_VARS = new Set(['orig', 'original', 'prev', 'previous', 'curr', 'current', 't']);
802802
const EXPR_ALLOWED_ROOTS = new Set([...EXPR_ALLOWED_VARS]);
803803
// Top-level identifiers allowed in time expressions (only prev)
804804
const TIME_ALLOWED_ROOTS = new Set(['prev', 'previous']);
@@ -945,13 +945,16 @@ var Sequence = Sequence || (() => {
945945
return _currCache;
946946
};
947947

948+
const _t = context && context.t !== undefined ? context.t : 0;
949+
948950
const body = expr
949951
.replace(/\boriginal\b/g, '_orig')
950952
.replace(/\bprevious\b/g, '_prev')
951953
.replace(/\bcurrent\b/g, '_getCurr()')
952954
.replace(/\borig\b/g, '_orig')
953955
.replace(/\bprev\b/g, '_prev')
954-
.replace(/\bcurr\b/g, '_getCurr()');
956+
.replace(/\bcurr\b/g, '_getCurr()')
957+
.replace(/\bt\b/g, '_t');
955958

956959
const _ctx = {
957960
obj: context ? context.obj : null,
@@ -2556,7 +2559,7 @@ var Sequence = Sequence || (() => {
25562559
* @param {object} prevState - running state before this keyframe (prev)
25572560
* @param {object} liveObj - Roll20 graphic object (curr)
25582561
*/
2559-
const resolveDeltas = (deltas, initialState, prevState, liveObj, cumulative) => {
2562+
const resolveDeltas = (deltas, initialState, prevState, liveObj, cumulative, t) => {
25602563
const resolved = {};
25612564
Object.entries(deltas || {}).forEach(([attrName, parsed]) => {
25622565
if (!parsed || !parsed.expr) { resolved[attrName] = parsed; return; }
@@ -2569,7 +2572,7 @@ var Sequence = Sequence || (() => {
25692572

25702573
try {
25712574
const val = evalExpr(parsed.expr, orig, prev, curr,
2572-
{ obj: liveObj, cumulative: cumulative || {} });
2575+
{ obj: liveObj, t: t || 0, cumulative: cumulative || {} });
25732576
if (parsed.mode === 'abs') {
25742577
resolved[attrName] = { abs: val };
25752578
} else if (parsed.mode === 'mul') {
@@ -2761,6 +2764,9 @@ var Sequence = Sequence || (() => {
27612764
t = lastKfTime;
27622765
}
27632766

2767+
// Normalized time (0-1) for expression scope
2768+
const tNorm = t / duration;
2769+
27642770
let prevIdx = -1;
27652771
let nextIdx = kfs.length;
27662772
for (let i = 0; i < kfs.length; i++) {
@@ -2814,7 +2820,7 @@ var Sequence = Sequence || (() => {
28142820
const prevState = stateAt(i - 1);
28152821
const state = stateAt(i);
28162822
// Resolve any expression deltas before applying
2817-
const resolvedDeltas = resolveDeltas(kf.deltas, pb.initialState, prevState, obj, pb.cumulative);
2823+
const resolvedDeltas = resolveDeltas(kf.deltas, pb.initialState, prevState, obj, pb.cumulative, tNorm);
28182824
// Re-apply with resolved deltas via shadow
28192825
const shadow = makeShadow(prevState);
28202826
Object.entries(resolvedDeltas || {}).forEach(([attrName, parsed]) => {
@@ -2872,7 +2878,7 @@ var Sequence = Sequence || (() => {
28722878
// curr fetched lazily inside evalExpr via reg+obj
28732879
try {
28742880
const val = evalExpr(nextParsed.expr, orig, prev, undefined,
2875-
{ obj, reg, cumulative: pb.cumulative || {} });
2881+
{ obj, reg, t: tNorm, cumulative: pb.cumulative || {} });
28762882
nextParsed = nextParsed.mode === 'abs' ? { abs: val }
28772883
: nextParsed.mode === 'mul' ? { delta: val }
28782884
: { delta: (nextParsed.sign || 1) * val };

Sequence/TODO.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,16 @@ Either approach (or both) makes the system safe for virtual attributes without r
6565

6666
---
6767

68-
## Planned: `t` Variable in Expressions (Orbit / Cycle Animations)
68+
## Done: `t` Variable in Expressions (Orbit / Cycle Animations)
6969

70-
Add a normalized time variable `t` (0–1, representing elapsed fraction of the current loop cycle) to the expression scope so users can write orbit-style animations:
70+
Normalized time variable `t` (0–1, representing elapsed fraction of the current playback cycle) is available in value expressions:
7171

7272
```
73-
left: =orig_left + cos(t * 2 * PI) * distance
74-
top: =orig_top + sin(t * 2 * PI) * distance
73+
left: =orig + cos(t * 2 * PI) * 140
74+
top: =orig + sin(t * 2 * PI) * 140
7575
```
7676

77-
Needed for `!sequence generate orbit` and MovementAnimations parity. TBD whether this lives in Sequence's expression scope or in Choreograph.
77+
`t` is 0 at the first frame, 1 at the last frame, and resets each loop cycle.
7878

7979
---
8080

0 commit comments

Comments
 (0)