SSGOI

Motion overrides

Keep the preset's effect and tune the physics or overlap you want to change.

Choose the effect, then override its motion

The second argument is an override object. Each callback receives the animation built for that direction, with its registered child names inferred.

import { axis, spring, InertiaIntegrator } from "@ssgoi/core";

export const tunedAxis = axis(
  { type: "x", variant: "default" },
  {
    override: {
      forward({ animation }) {
        const outgoing = animation.select("out");
        const incoming = animation.select("in");

        outgoing.set({
          integrator: new InertiaIntegrator({ acceleration: 150, resistance: 1.5 }),
        });
        incoming.set({
          integrator: spring({ stiffness: 320, damping: 30 }),
          startAt: { after: outgoing, at: 0.3 },
        });
      },
      backward({ animation }) {
        animation.set({ integrator: spring({ stiffness: 400, damping: 35 }) });
      },
    },
  },
);

Omitted directions and properties keep their preset defaults. Callbacks run before playback and receive the original core context. The route rule and history decide forward/backward; the preset does not change that decision.

Select a named animation

A selected child can contain one element or a whole group. Its name is registered by the preset, so it does not depend on DOM order.

PresetNames
Axis, Drill, Slide, Fade, Scroll, Strip, Rotate, Jaeminout, in
Blindout, in — each contains its strips
Sheetsheet, background, overlay
Zoomtile, background, content, overlay
Heroshared, out, in
Filmout, in, borders

animation.select("in").set(...) changes the selected group. animation.set(...) explicitly changes the whole composite. Use the whole composite when its surfaces should share the same progress. Missing optional effects remain empty named groups.

Film retains its baked scale and translation choreography. An integrator override changes progression through that path; its internal scale-down, translate, and scale-up springs are not separate public children.

Choose first arrival or complete settling

Start conditions reference sibling animations. A numeric threshold and a completion condition have different meanings.

const outgoing = animation.select("out");
const incoming = animation.select("in");

// Start when outgoing first reaches 30% progress.
incoming.set({ startAt: { after: outgoing, at: 0.3 } });

// Or wait until outgoing has completely settled.
incoming.set({ startAt: { after: outgoing, at: "settled" } });

A spring can overshoot 100% before it settles. Numeric 1 means its first crossing, while "settled" waits for completion. The existing positional startAt arrays and sequence shorthand preserve their numeric first-crossing behavior. Set timing before playback; references outside the parent, cycles, and invalid thresholds are rejected.

Use physical parameters

Springs accept stiffness and damping. You can pass a built-in class, a semantic preset, or your own Integrator instance.

import { spring, SpringIntegrator, InertiaIntegrator, scale, snappy } from "@ssgoi/core";

spring({ stiffness: 320, damping: 30 });
new SpringIntegrator({ stiffness: 320, damping: 30 });
new InertiaIntegrator({ acceleration: 150, resistance: 1.5 });
scale(snappy, 1.2); // Preserve its curve and run it faster.

The web adapters re-export these helpers, including @ssgoi/react. A spring does not accept a duration/bounce recipe. Keep integrator instances stateless so animations can share them safely.

Read next