Animations, portals, and media are grouped together because they all involve runtime-owned behavior that is declared during component conversion.
That does not make them hidden. It means the widget tree describes what should exist, then the runtime tracks the transient state needed to make it behave across frames.
Animation contract
Animation in Fission is runtime-owned motion requested against stable widget identity.
| | |
|---|
| Identifies which visual property is animated | Examples include opacity, position, scale, or other supported properties. |
| Describes where the animation begins | Lets an animation start from a known value instead of guessing from current rendering. |
| Full request for one animation | Contains property, target, timing, easing, and related metadata. |
| | Controls how progress moves from start to end. |
| | Required when the runtime needs to track an animation across reconversions. |
Widgets request animation through ctx.request_animation_for(...) or ctx.anim_for(id).request(...). The runtime stores the active animation state and exposes current values through ViewHandle.
Do not store per-frame animation progress in GlobalState. App state should hold durable facts such as "the panel is open" or "the item was selected." The runtime can animate from the old visual state to the new visual state.
Portal contract
A portal is the runtime mechanism for content that should render outside the normal parent layout while still belonging to the same app model.
| | |
|---|
| | Keeps modal, flyout, toast, and other overlays predictable. |
| One registered portal item | Holds the content and layer identity for runtime composition. |
| Stable authoring identity | Used by flyouts, popovers, and layout-aware overlays. |
Use portals when content genuinely belongs above the main tree: modals, drawers, flyouts, popovers, menus, tooltips, and toasts. Do not use portals to avoid learning normal layout. Ordinary rows, columns, stacks, and scroll regions should remain inline.
Higher-level widgets such as Modal, Drawer, Popover, Tooltip, Menu, and Toast exist so most apps do not need to register low-level portal entries directly.
Some widgets represent host-backed or specialized surfaces rather than ordinary paint-only content.
| | What it tells the runtime |
|---|
| | A video surface exists at this widget identity, with source and sizing metadata. |
| | An embedded browser surface exists at this widget identity, with requested URL and metadata. |
| | A terminal surface needs host process, cell buffer, focus, input, and scrollback coordination. |
| Scene3D and chart 3D paths | A scene needs 3D primitives, camera, lighting, and renderer support. |
The runtime keeps these registrations tied to layout identity and host presentation. The shell still owns the platform-specific implementation: video decoding, embedded browser engine, terminal process integration, or graphics backend details.
Runtime-owned state
The runtime tracks several kinds of state that usually should not live in GlobalState directly:
| Why it stays out of product state |
|---|
Active animation progress | It is transient frame state derived from durable product state. |
Hover, press, focus, and gesture tracking | It describes current input interaction, not product truth. |
| It belongs to the visible runtime surface unless the product explicitly saves a scroll position. |
Portal layering and placement | It is layout/runtime composition around the widget tree. |
Video/web/terminal surface state | It is host integration state around a registered surface. |
Hero-position bookkeeping | It connects prior and current layout geometry for a visual transition. |
Store the durable decision in app state; let the runtime manage the transient mechanics.
Common mistakes
Do not start side effects in component conversion to drive animation or media. Declare the desired widget tree and registrations, then let the runtime and shell handle frame progression.
Do not put a modal or popover's open state inside a local widget field. Store show_settings, active_menu, or similar product-visible state in GlobalState and let the widget tree include or exclude the overlay from that state.
Do not use WebView as a substitute for building normal Fission screens. It is for embedded web content that genuinely needs a browser surface.
Do not expect every media surface to have identical behavior on every host without validation. Video, embedded browsers, terminal sessions, and 3D graphics live close to platform capabilities and deserve target-specific tests.
Related pages
For the component conversion contract, see Widget authoring boundary. For the guide-level explanation, read Media, animation, portals, and 3D. For concrete media widgets, see Media and custom surfaces.