NAGARE✦流れ — flow
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/reactA 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.
Move your cursor over the circle.
soul("card")
.hover({
onStart: {
css: `transform: translateY(-6px)`,
js: function (this: any) {
this.state.hovered = true
}
},
onEnd: { css: `transform: translateY(0px)` }
})Click to flip state — color follows @if.
soul("card")
.click({
onStart: {
css: `
@if active { background: violet }
@else { background: black }
`,
js: function (this: any) {
this.state.active = !this.state.active
}
}
})Press and hold for 500ms.
soul("card")
.longpress({
onStart: {
js: function (this: any) {
this.state.charged = !this.state.charged
}
}
})Swipe on touch — reports left/right/up/down.
soul("card")
.swipe({
onStart: {
js: function (this: any) {
// this.params.direction
this.state.dir = this.params.direction
}
}
})Stop moving the mouse for 2.5s.
soul("card")
.onIdle({
idleTimeout: 2500,
onStart: { css: `opacity: 0.35` },
onEnd: { css: `opacity: 1` }
})Drag horizontally on touch.
soul("card")
.drag({
onUpdate: {
js: function (this: any) {
this.el.style.transform =
`translateX(${this.params.x}px)`
}
}
})| Package | @nagarejs/react · @nagarejs/core |
|---|---|
| Install | npm install @nagarejs/react |
| Core only | npm install @nagarejs/core // vanilla JS, custom adapters |
| Intellisense | npm install @nagarejs/ts-plugin --save-dev |
| Frameworks | Next.js, Remix, Astro, TanStack, Vite |
| Binding | <div data-soul="card"> |
| Entry hook | useSoul((soul) => { ... }) |
| Author | Mizumi · github.com/Mizumi25/nagare |
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 disappears | Silent no-op, no crash. Listener cleanup fix planned. |
|---|---|
| Rapid state updates | Holds up. State stays consistent, no race conditions. |
| prefers-reduced-motion | Not applicable — no animation engine. Handle in your js block. |
| Escape / interruption | Lifecycle 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.