流れ — flow

Behavior has
a home, now.

Nagare keeps every interaction's styles, animation, logic, and state together — under one name, in one place. No more hunting across CSS, handlers, a tween library, and a store for a single hover.

npm install @nagarejs/react
AboutWhy Nagare exists

A hover is one thing. It starts, it runs, it ends — and everything it owns should live in the same place.

Most frontends split a single interaction across four or five tools: CSS for the look, a handler for the logic, a tweening library for motion, a store for state. Nagare collapses that into one declaration — a soul — bound to an element with a single data-soul attribute.

Behaviors are detectors: hover, click, swipe, onIdle, and more. Each one runs a lifecycle — start, update, end — and each lifecycle can carry Tailwind classes, real CSS with inline @if conditions, and a plain JS block with no ceiling: gsap, canvas, fetch, anything.

DemoLive souls, running on this page
.hover()

Lift & glow

Move your cursor over the circle.

hover
soul("card")
  .hover({
    onStart: {
      css: `transform: translateY(-6px)`,
      js: function (this: any) {
        this.state.hovered = true
      }
    },
    onEnd: { css: `transform: translateY(0px)` }
  })
.click()

State toggle

Click to flip state — color follows @if.

click
soul("card")
  .click({
    onStart: {
      css: `
        @if active { background: violet }
        @else { background: black }
      `,
      js: function (this: any) {
        this.state.active = !this.state.active
      }
    }
  })
.longpress()

Charge up

Press and hold for 500ms.

longpress
soul("card")
  .longpress({
    onStart: {
      js: function (this: any) {
        this.state.charged = !this.state.charged
      }
    }
  })
.swipe()

Direction read

Swipe on touch — reports left/right/up/down.

swipe
soul("card")
  .swipe({
    onStart: {
      js: function (this: any) {
        // this.params.direction
        this.state.dir = this.params.direction
      }
    }
  })
.onIdle()

Ambient dim

Stop moving the mouse for 2.5s.

onIdle
soul("card")
  .onIdle({
    idleTimeout: 2500,
    onStart: { css: `opacity: 0.35` },
    onEnd:   { css: `opacity: 1` }
  })
.drag()

Free movement

Drag horizontally on touch.

drag
soul("card")
  .drag({
    onUpdate: {
      js: function (this: any) {
        this.el.style.transform =
          `translateX(${this.params.x}px)`
      }
    }
  })
BehaviorsEvery detector Nagare ships with

Pointer

  • hover
  • click
  • press
  • release
  • drag

Touch

  • tap
  • longpress
  • swipe
  • enter
  • exit

Lifecycle

  • onMount
  • onVisible
  • onInvisible
  • focus
  • blur

Environment

  • scroll
  • resize
  • onIdle
  • networkChanged
  • onOrientationChange

Blocks

  • tw
  • css
  • js
  • @if / @else
  • state

Reuse

  • template()
  • preset()
  • useSoul()
  • delay
  • idleTimeout
InstallPackage outline
Package@nagarejs/react · @nagarejs/core
Installnpm install @nagarejs/react
Core onlynpm install @nagarejs/core  // vanilla JS, custom adapters
Intellisensenpm install @nagarejs/ts-plugin --save-dev
FrameworksNext.js, Remix, Astro, TanStack, Vite
Binding<div data-soul="card">
Entry hookuseSoul((soul) => { ... })
AuthorMizumi · github.com/Mizumi25/nagare
ProductionHow Nagare behaves under stress

Nagare is a lifecycle detector, not an animation engine. It fires a lifecycle and applies styles — it doesn't interpolate, tween, or manage timing.

Element disappearsSilent no-op, no crash. Listener cleanup fix planned.
Rapid state updatesHolds up. State stays consistent, no race conditions.
prefers-reduced-motionNot applicable — no animation engine. Handle in your js block.
Escape / interruptionLifecycle completes. Handle interruption logic in your js block.

The js block is intentionally no-ceiling — anything you can do in plain JavaScript you can do inside it. prefers-reduced-motion, escape handling, cancelling a fetch mid-flight — all of that lives in the js block by design, the same way React doesn't cancel a setState because the user hit escape.

Give your next hover
a home.