@arinze-clinton/loupe
v0.4.1
Published
Timeline-first motion authoring tool — scrub, annotate, and review React animations against a deterministic timeline.
Maintainers
Readme
Your web animations, on a timeline. Scrub them like a video, pause on any frame, mark what's off, export the notes — all on real running code, not a recording.
Quick start
npm install @arinze-clinton/loupe -D
npx loupe initUsing pnpm / yarn / bun? Replace
npxwithpnpm exec,yarn, orbun x.
Wrap your app in one provider and mount the panel in dev:
import { LoupeRegistryProvider, LoupePanel } from '@arinze-clinton/loupe';
function App() {
return (
<LoupeRegistryProvider>
<YourApp />
{import.meta.env.DEV && <LoupePanel />}
</LoupeRegistryProvider>
);
}Then wrap any animated scene in a TimelineProvider and your motion values read from the shared clock:
import { TimelineProvider, useTimelineValue } from '@arinze-clinton/loupe';
import { motion } from 'framer-motion';
function MyScene() {
return (
<TimelineProvider
config={{
id: 'my-scene',
label: 'My Scene',
phaseOrder: ['enter', 'settle'],
phaseDurations: { enter: 600, settle: 400 },
}}
>
<FadingBox />
</TimelineProvider>
);
}
function FadingBox() {
const opacity = useTimelineValue(0, 1, { phase: 'enter' });
return <motion.div style={{ opacity }}>Hello</motion.div>;
}That's enough. The panel finds the scene, the scene's animations read from the shared clock, and you can scrub.
Already got animations?
Run npx loupe refactor — Loupe walks you through each fire-and-forget animation in your project, shows the before and the after, and asks before changing anything. Nothing gets refactored without your sign-off.
Using Claude, Cursor, or Copilot? npx loupe init installed a skill that lets you ask in plain English: "audit my animations", "make this scrubbable". The agent does the same walkthrough.
The idea
Every animation is a function of time. Loupe owns the time.
Scrubbing back is just setting time to zero. Pausing is just freezing the clock. Reviewing your animation feels like reviewing a video edit, not poking at a black box.
Once a scene is wrapped in <TimelineProvider>, every animated value reads from the same shared clock. The floating panel drives that clock — and lets you annotate any frame you want to change. Notes export as Markdown your AI agent (or teammate) can act on.
CLI
| Command | What it does |
|---|---|
| loupe init | Wire Loupe into your project. Writes a sample scene + (optionally) installs the Claude skill. |
| loupe scan | Find every animation in your project and report which are timeline-bound vs fire-and-forget. |
| loupe refactor | Walk through each fire-and-forget animation interactively. Show-and-paste, no auto-edits. |
| loupe check | Print the version installed, what's declared in package.json, and the latest on npm. |
| loupe uninstall | Remove @arinze-clinton/loupe and the files loupe init wrote. Won't touch files you've edited. |
Why my scene isn't pickable
If hovering over your animation highlights the page behind it (not the scene itself), a pointer-events: none ancestor is making the scene invisible to document.elementFromPoint. Common in production code that wraps autoplaying vignettes so they don't intercept page clicks.
Wrap the scene in <SceneRoot> instead of a bare <div>:
import { SceneRoot } from '@arinze-clinton/loupe';
<SceneRoot>
{/* your animated content */}
</SceneRoot><SceneRoot> flips to pointer-events: auto whenever Loupe is mounted and back to none in production builds where it isn't. You get pickable scenes in the workbench and click-through behavior in prod, without remembering the rule.
Requirements
- React 18+
- Framer Motion 11+
- Modern desktop or mobile browser
Docs
License
PolyForm Shield 1.0.0 — use it freely in any project, including commercial work. You may not fork it into a competing product.
