npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@khesira/textflow

v1.2.2

Published

A framework agnostic canvas physics text slider

Readme

@khesira/textflow

A lightweight, high-performance, framework-agnostic canvas physics text slider written in TypeScript.

This library packages a 2D physics engine into a native Web Component (Custom Element), allowing you to create beautiful, dynamic text streams that float and collide organically across the screen. It works seamlessly with Astro, Svelte, Vue, React, or pure HTML.


Features

  • 🚀 Framework Agnostic: Built on the native Web Components standard. Zero runtime dependencies.
  • 🛡️ Resource-Efficient & Leak-Proof: Automatically pauses the physics loops when the browser tab is blurred (visibilitychange) or the element is removed from the DOM (disconnectedCallback).
  • 🖥️ High-DPI / Retina Ready: Canvas automatically scales with window.devicePixelRatio for razor-sharp text rendering on 4K and OLED displays.
  • 🧠 Smart Physics-Engine: Text speed and impulse-exchange upon collision are calculated based on the text's font size (mass-inertia principle).
  • ⚙️ Runtime Validated: Built-in sanitization catches malformed JSON configuration gracefully without crashing the engine.

Installation

Install the package via your favorite package manager:

bun add @khesira/textflow
# or npm install @khesira/textflow

Usage

1. In Astro (or similar Frontend Frameworks)

Register the custom element in your client-side script and pass your configuration via data-* attributes.

---
import type { Settings } from '@khesira/textflow';

interface Props {
    texts: string[];
}

const { texts } = Astro.props;

const settings: Partial<Settings> = {
    font: "Inter, sans-serif",
    color: "#ffffff",
    background: "transparent",
    maxTexts: 12,
    maxAcceleration: 4,
    marginTop: 20,
    marginBottom: 20,
    debug: false
};
---

<textflow-container
    data-texts={JSON.stringify(texts)} 
    data-settings={JSON.stringify(settings)}
></textflow-container>

<script>
    import { registerTextFlowSlider } from '@khesira/textflow';
    
    // Teaches the browser the new HTML tag <textflow-container>
    registerTextFlowSlider();
</script>

2. Pure HTML / JavaScript

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>TextFlow Demo</title>
    <style>
        body { background: #111; }
        textflow-container { margin: 2rem auto; }
    </style>
</head>
<body>

    <textflow-container 
        data-texts='["TypeScript", "Bun", "Astro", "Canvas", "Physics"]'
        data-settings='{"maxTexts": 8, "color": "#00ffcc"}'>
    </textflow-container>

    <script type="module">
        import { registerTextFlowSlider } from './node_modules/@khesira/textflow/dist/textflow.js';
        registerTextFlowSlider();
    </script>
</body>
</html>

Configuration (Settings)

The component always fills the available width of its host container. Control the width using regular CSS on the element or its parent. The height can be configured via settings.

| Property | Type | Default Value | Description | |:------------------|:------------|:------------------|:-----------------------------------------------------------------------| | height | string | "200px" | CSS height of the slider component. | | font | string | "sans-serif" | Font family used inside the Canvas rendering context. | | color | string | "#ffffff" | Text color (accepts hex, rgb, rgba, or CSS color names). | | background | string | "transparent" | Background color of the canvas container. | | maxTexts | number | 10 | Maximum number of text elements allowed on screen simultaneously. | | maxAcceleration | number | 3 | Maximum velocity cap for the text particles. | | headings | Heading[] | ['EAST','WEST'] | Flow directions of the texts picked randomly on each page load. | | minSpawnMs | number | 1000 | The minimum timespan of spawning a new text. | | maxSpawnMs | number | 2500 | The maximum timespan of spawning a new text. | | marginTop | number | 0 | Top boundary padding (in pixels) to restrict the spawn area. | | marginBottom | number | 0 | Bottom boundary padding (in pixels) to restrict the spawn area. | | debug | boolean | false | Enables red AABB bounding boxes and highlights the canvas clear zones. |

Headings

The headings setting controls the possible flow directions. On each page load, one direction is picked randomly from the provided list.

Allowed values:

'NORTH' | 'NORTHEAST' | 'EAST' | 'SOUTHEAST' | 'SOUTH' | 'SOUTHWEST' | 'WEST' | 'NORTHWEST' | 'NONE'

Spawn rates

The values for minSpawnMs and maxSpawnMs control the timespan between text texts spawn. Each cycle any random value between minSpawnMs and maxSpawnMs is picked and a new text is spawned after that period of time.

Usage

const settings: Partial<Settings> = {
    headings: ['NORTH', 'SOUTHEAST', 'WEST'],
    // ...
};

Use Partial<Settings> to allow for optional properties.

Architecture

The library follows a strict Model-View-Controller (MVC) inspired architecture to decouple data, state machine, and side effects:

  • TextElement: Represents the physical text particle, housing position, speed, and bounding box.
  • World: The state machine driving the physics engine, handling backward-loop garbage collection, and processing 2D broad-phase collisions.
  • TextFlowView: Isolated rendering layer that handles drawing text onto the high-DPI scaled 2D context.
  • TextWriter: Factory class that manages the pseudo-randomized generation of new TextElement batches based on viewport requirements.
  • TextFlowElement: The HTML Custom Element orchestrating the components and bridging browser lifecycles.

License

MIT License – feel free to use it in your personal portfolio or commercial projects!