Files
hyperframes/packages/studio/src/utils/sdkShadowNumeric.ts
T
Vance IngallsandClaude Opus 4.8 0e5caa453a refactor(studio): dedup shadow numeric-equal + GSAP script extraction (#1516)
* fix(studio): serialize GSAP script commits per file (shadow request race)

Rapid GSAP edits (ease/duration/keyframe/property) fired overlapping
read-modify-write POSTs to one script file — coalesceKey only dedupes edit
history, not requests. The gsap_fidelity shadow then diffed an op against
whichever POST's scriptText resolved, which could predate that op → false
"expected null, actual power2.out" mismatches. Server persists correctly; a
pure client request-pairing race.

Adds createKeyedSerializer (per-key promise chain, rejection-safe, self-
cleaning). commitMutation now serializes every GSAP-script commit per target
file by default (key `gsap-file:<path>`) — covering all op types and all
animations, not just one meta family — so same-file POSTs can't interleave.
Distinct files run concurrently; an explicit serializeKey still overrides.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(studio): dedup shadow numeric-equal + GSAP script extraction

Code-review cleanup (no behavior change):
- Extract the relative-epsilon float compare into shared sdkShadowNumeric.relEqual,
  used by both timing parity (sdkShadow) and GSAP value fidelity (numericEqual) —
  was duplicated verbatim, risking divergent tuning.
- Export extractGsapScript from sdkShadowGsapFidelity and import it in the keyframe
  shadow instead of the byte-identical clone (the regex + marker set must stay in
  sync with document.ts; one copy is safer).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 12:41:25 -07:00

12 lines
571 B
TypeScript

/**
* Relative-epsilon numeric equality shared by the shadow diffs (timing parity +
* GSAP value fidelity). Both writers round-trip durations/positions through JS
* number formatting, so a value like 3.1 can read back as 3.0999999999999996.
* Treat values within 1e-6 * max(1, |a|, |b|) as equal — tight enough that a
* real 2 vs 1 (or 0.5 vs 0.49) still flags, loose enough to absorb float noise.
*/
export function relEqual(a: number, b: number): boolean {
if (a === b) return true;
return Math.abs(a - b) <= 1e-6 * Math.max(1, Math.abs(a), Math.abs(b));
}