• English
  • Smoothing

    Streaming text usually arrives in bursts: a few characters in one update, a whole paragraph in the next. Smoothing separates receiving content from displaying it, so those updates appear at a steadier pace.

    See the buffer

    This demo receives text in chunks of different sizes. The normal text color marks content already displayed; the other color marks received content still waiting in the buffer. In an application, the buffered text is not visible yet.

    VisibleBuffered

    When a chunk arrives, the buffer grows first and the visible boundary follows. Pause to inspect their positions, or replay to watch how each incoming chunk changes the pace.

    How the spring sets the pace

    The built-in spring scheduler adjusts speed using the distance between the visible position and the waiting content. A larger backlog speeds up output; as the visible position approaches the end, the speed settles. Each frame keeps the previous frame's velocity so updates flow into one another.

    The scheduler calculates progress from elapsed time and carries fractional characters into the next update. Text can advance between network updates, without a fixed delay for every character. The demo uses the same SpringSmoothScheduler as the Smooth mapper.

    Use it in your application

    Choose your framework above each example. Pass the Core example’s mappers to the Core inputs; Core produces content and effect markers, while your renderer supplies their appearance. The components include those renderers.

    Enabling streaming uses spring smoothing by default:

    import type { MapperPluggable } from '@fluxdown/core';
    import { Smooth } from '@fluxdown/core-plugins/plugins/mapper/smooth';
    import { Scale } from '@fluxdown/core-plugins/plugins/mapper/scale';
    import { MutableState, toClosure } from 'stative';
    
    const isStreaming = MutableState.of(true);
    const active = toClosure(isStreaming);
    
    const mappers: MapperPluggable[] = [
      [Smooth, { enabled: active }],
      [Scale, { enabled: active }],
    ];

    You can also select the scheduler explicitly and add an animation effect:

    import type { MapperPluggable } from '@fluxdown/core';
    import {
      RafSmoothTicker,
      Smooth,
      SpringSmoothScheduler,
    } from '@fluxdown/core-plugins/plugins/mapper/smooth';
    import { Shad } from '@fluxdown/core-plugins/plugins/mapper/shad';
    
    const mappers: MapperPluggable[] = [
      [
        Smooth,
        {
          enabled: true,
          ticker: RafSmoothTicker,
          scheduler: SpringSmoothScheduler,
        },
      ],
      [Shad, { enabled: true }],
    ];

    Always pass the complete text received so far to text. Setting streaming to false reveals the remaining buffer immediately. Keep smoothing enabled if you want the remaining content to finish appearing gradually.

    Core uses the same Smooth mapper to produce trimmed content blocks, so the renderer does not need to schedule character updates. See Core state and updates for integration and your framework’s configuration for all options: React, Vue, Svelte, Angular, React Native, Lynx, Solid, or Taro.

    The reactive Core example owns its MutableState: call isStreaming.next(false) when receiving finishes, then dispose active and isStreaming with .destroy() after destroying Core.