Skip to content

Releases: kbrattli/react-native-smooth-clip-view

Release 0.2.5

Choose a tag to compare

@kbrattli kbrattli released this 30 Jul 04:40
a5d19b5

0.2.5 (2026-07-30)

Bug Fixes

  • align android begininteraction 'inherit' history with ios (f980ff2)

Code Refactoring

  • rename the shared native driver to drivers.native (f889630)

A second adversarial review of the 0.2.3/0.2.4 handoff stack re-confirmed the
architecture end to end and left two things worth shipping:

  1. Android beginInteraction() no longer resets the 'inherit' velocity
    history.
    It now records the frozen presentation as a plain sample —
    exactly what iOS has always done in smoothClipFreezePresentation — so a
    grab-and-instant-refling inherits bounded recent momentum instead of
    launching a dead spring. An unchanged value dedupes to a no-op whose
    timestamps keep aging, so a stale pair still inherits zero through the
    100 ms staleness guard. resetVelocitySamples had no remaining production
    call site and was removed from cpp/SmoothClipVelocityTracker.h; this only
    affects code that includes that header directly. Pinned by a new
    injected-timestamp XCTest covering the grab-record pairing both platforms
    execute.

  2. The shared native driver is now src/drivers.native.ts. The
    implementation Metro resolves on both platforms previously lived in
    drivers.ios.ts (with Android re-exporting it), inviting "iOS-only" edits
    to land in shared code. drivers.ios.ts and drivers.android.ts are now
    one-line re-exports; resolution, the public API, and behavior are
    unchanged.

Does 0.2.5 affect iOS? No — the velocity-history fix is Android-only C++
(iOS already had these semantics), and the rename is resolution-neutral.
iOS pixels are bit-identical to 0.2.4.

Also included: documentation corrections — the publishing checklist reflects
that 0.2.4 is on npm as latest, the driver's rejection-rollback comment now
matches the README contract (reachable 0-return cases deliver no completion),
the from JSDoc scopes its presentation.value claim to the native drivers,
kMaxFrameLeadS is documented as refresh-rate-independent latency slack, and
the README states the multi-host finished semantics and that keyframes
deliberately encode their own curve.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

Release 0.2.4

Choose a tag to compare

@kbrattli kbrattli released this 29 Jul 20:49
b56b41e

0.2.4 (2026-07-29)

Bug Fixes

  • harden 'inherit' velocity sampling and the frame-clock time axes (6768666)

Features

  • exact easing presets and a shared animation base type (6c8065a)

An adversarial review of the 0.2.3 handoff work confirmed the architecture
and found three defects in the margins, all fixed here:

  1. from + initialVelocity: 'inherit' corrupted the spring launch.
    A release seed identical to the last drag write zeroed the sample deltas
    (dead spring, Android only), and a distinct seed recorded in the same
    input batch divided sub-frame displacement by microseconds (wild
    overshoot, both platforms). Sample recording, coalescing, and the
    velocity projection now live in a shared header
    (cpp/SmoothClipVelocityTracker.h) executed verbatim by both platforms:
    identical re-records are dropped, and records closer than 4 ms merge
    into one observation so every surviving pair spans real frame time.
    Behavior note: a fast release exactly at the last drag position now
    inherits the drag velocity (iOS parity) instead of launching dead.

  2. The Android re-latch mixed clock axes. The remainder computation
    subtracted the post-anchor frame-axis start from wall time, shortening
    resumed animations by the first callback's dispatch latency. A
    wallStartedAtS twin — never rebased by the anchor — now carries the
    wall axis for bookkeeping.

  3. Post-stall run-ahead. The anchor's one-time shift bakes the first
    callback's dispatch latency into the frame axis; after a heavy stall the
    animation could lead wall time and complete early. advance() now
    re-anchors forward when frame-axis elapsed exceeds wall elapsed by more
    than one vsync — provably inert on calm frames.

ClipEasings exports the exact single-Bézier control points of the
standard polynomial easings (easeOutCubic = Easing.out(Easing.cubic),
etc.) so a parallel Reanimated content animation can run the identical
curve without hand-deriving control points. Also: README now documents the
real rejection contract (a fresh non-zero id plus one finished:false
completion; 0 with no completion only for destroyed-driver or off-main
calls), and the iOS timing/spring presentation-layer from-value is
documented as intended visual continuity.

New coverage: 6 deterministic velocity-tracker XCTests (shared-header
behavior pinned for both platforms) plus a registry integration test
asserting a bounded CASpringAnimation.initialVelocity for the fused-seed
handoff — 35 XCTests total.

Release 0.2.3

Choose a tag to compare

@kbrattli kbrattli released this 29 Jul 20:49
f31fec5

0.2.3 (2026-07-29)

Bug Fixes

  • anchor the Android animation clock to the choreographer frame axis (1218806)

Features

  • explicit-start animateTo via animation.from (70049a7)

An interactive drag hands off to animateTo mid-frame: the animation start
was stamped on steady_clock at the call, but the choreographer ticks the
integrator against frameTimeNanos — a vsync stamp that precedes the call.
The first fraction clamped to zero and re-rendered the start, a 1–2 frame
freeze whose visible size scales with drag velocity (invisible on a slow
drag, a 30–100 px freeze-then-jump on a fast one). The first advance()
now translates the start onto the frame-time axis preserving real elapsed
time: the first rendered frame advances honestly and later frames pace on
vsync. iOS was never affected (the render server interpolates committed
CAAnimations) and is bit-identical to 0.2.2.

animation.from packages the release handoff as a first-class option on
all three animation kinds: a fused take-ownership hot write issued
immediately before the animation, so the rendered value, the native start,
and keyframe 0 are identical by construction — replacing the two-call
setScalars(...) + animateTo(...) pattern apps had to discover, and
also re-grabbing from a running animation, which the implicit interactive
start silently skipped. Wire format unchanged; no native code touched.

See docs/android-frame-clock-anchor.md for the full defect analysis and
the architecture verdict.

Release 0.2.2

Choose a tag to compare

@kbrattli kbrattli released this 28 Jul 21:06
8f04fb8

0.2.2 (2026-07-28)

Bug Fixes

  • gate animation start on displayability; re-latch on last unregister (5a660a7)

0.2.1 started a held animation at the first registerView. Live diagnosis
proved that is still too early: a Core Animation animation committed while
the host's layer tree is detached from the render tree does not survive the
later attach commit. RNScreens presents transparentModal view controllers
asynchronously (even with animation: 'none'), so the install was stripped
~one frame after the window attach and the layer snapped to its model
values — the target. The symptom was byte-identical to the pre-0.2.1 bug.

Animations now hold until a registered view can actually display — layout
plus a window on iOS, attached plus real host geometry on Android — and
start inside the attach commit with a rebased clock, so the first visible
frame is t=0 of the full duration.

Fixed alongside, both platforms:

  • last-participant unregister mid-flight re-latches the remainder (start =
    the departing view's visible geometry, duration = remaining) instead of
    completing at the target, so a re-registering host resumes rather than
    snaps;
  • a take-ownership seed no longer cancels a held latch — a held latch is
    strictly newer intent than any value the seeder read;
  • frozen presentation skips unlaid-out views, so freezing beside a
    zero-geometry peer can no longer collapse the clip;
  • detached relayout and the keyframes install path defer on the same
    displayability gate.

Public API unchanged. Full write-up, including the addendum covering this
release, in docs/pending-animation-latch.md.

Release 0.2.1

Choose a tag to compare

@kbrattli kbrattli released this 28 Jul 17:43
e9e5824

0.2.1 (2026-07-28)

Bug Fixes

  • latch animateTo issued before the first host view registers (3a1155e)

An animateTo that raced its own host's Fabric mount used to hit the
registry's zero-views path: it stored the target as latest, emitted
finished: true and dropped the animation, so the host that mounted a
moment later statically applied the target and the clip jumped to its end
state. The animation is now latched (held out of the render/frame path) and
started by the first view registration, with its clock rebased so it runs
its full duration from the moment a frame can show it.

Behaviour change: an animateTo whose host never mounts now completes late
with finished: false (on replacement, cancel, take-ownership write or
driver destruction) instead of immediately with finished: true. Exactly
one completion per animation id still holds, and the public API is
unchanged.

Full write-up in docs/pending-animation-latch.md.

Release 0.2.0

Choose a tag to compare

@kbrattli kbrattli released this 27 Jul 20:40
3fa3c9d

0.2.0 (2026-07-27)

Features

  • animate example card content (9d384bb)
  • unified hybrid clip driver with native transitions and C++ px fanout (d8f6de9)

BREAKING CHANGES

  • the initialClip/animatedClip props are removed; drive
    clips through useSmoothClipDriver and the driverId prop instead.