Skip to content

PATTERN Cited by 1 source

Observer-vs-actor animation

In real-time collaboration, render the same edit twice against different rendering contracts:

  1. Actor path (live feedback) — for the user initiating the change, the UI responds directly to that user's local input event (mouse movement, keystroke). Snappy. No animation in the critical path.
  2. Observer path (animation) — for every other user watching the same change, the UI smoothly animates between the pre-edit and post-edit state. Avoids the jarring snap that raw state replacement produces when the observer had no input context.

Same edit, two rendering contracts, chosen by role.

Why one-render-path isn't enough

Two failure modes appear when you try to collapse the two paths:

  • Animate the actor too → the actor's action feels laggy because their input is now gated on animation frames. Direct mouse movement → direct UI response is the snappiness contract users expect from their own inputs.
  • Don't animate the observer → the observer sees a discontinuous jump: an element appears elsewhere with no transition. Worse when the observer was simultaneously interacting with the page; their own viewport or cursor can end up in an unexpected position relative to the moved element.

Canonical instance: tables in FigJam

From the 2026-04-21 Figma engineering post:

First, we started with "live feedback" so that users editing a table could see their actions in real time, even without a lot of explicit animation. ... since it is tied to only one specific user's mouse movement (the person initiating the change), we realized that it was jarring for everyone else.

So, we decided to layer on more animation, allowing users observing the change to more clearly follow table edits as they happen.

The prototype was a designer mock (Jakub Świadek). Reifying it in production required an engineer (Tim Babb) to build a new framework to animate elements on the canvas, because the snappy actor path already existed and the observer path needed new plumbing.

Extended UX detail from the same post: rubber-band effect on drag limits. When a user drags a row/column past its allowed range, the element elastically resists rather than snapping to the limit — drawing the explicit game-industry analogy to "invisible walls and barriers to guide users onto the right path, without using explicit signage."

(Source: sources/2026-04-21-figma-how-figma-draws-inspiration-from-the-gaming-world)

Implementation shape (not fully disclosed)

The post does not specify the animation framework's internals (scheduler, tick rate, interpolation mode, whether it integrates with Materializer or runs as a sibling system). What's explicit:

  • Distinct render entry-points per role. Figma named the initiator path "live feedback" and the observer path "animation" — two user-visible labels implies two code paths in the rendering layer.
  • Animation framework is reusable. The same system supports the observer-side table-edit animation and the rubber-band drag-limit effect; generic enough to be built once and used across UX.
  • Collaboration-driven, not aesthetic-driven. Animation is here to serve multiplayer observability, not decoration. The framework is built because "multiplayer changes were a jarring experience," not because static-single-user UX demanded it.

When to reach for this pattern

  • Collaborative editing of structured data where edits commonly move, add, delete, or reorder visible elements (tables, spreadsheets, outlines, kanban boards, CAD, design canvases).
  • The actor-vs-observer split is asymmetric. If every user sees every change as "remote" (no single-user edit loop — e.g. pure viewing), you only need the observer path. If nobody observes anyone else (single-player), you only need the actor path.
  • You already pay the cost of real-time sync. If your sync layer can distinguish local vs remote edits at the render boundary, layering this pattern on top is cheap.

When it's overkill

  • Atomic edits that don't visibly move existing elements (chat messages appended, toggles flipped). Observers can accept raw state replacement.
  • No multiplayer context yet. Don't build the two-path render pipeline before you have the sync semantics it's meant to smooth.

Seen in

Last updated · 200 distilled / 1,178 read