easeul

Installation

Import the layer once and declare the layer order before Tailwind. Getting that order wrong is the single most common failure.

Install

npm i easeful

Any React app: Next, Vite, React Router, Astro with React islands. The stylesheet itself is plain CSS and works anywhere, and the TypeScript types are React only.

Set it up in one command

easeful init makes every change on this page: the layer order, the import, the declaration file, and the lint rule. It prints the diff and asks before it writes.

bash
npx easeful init

easeful doctor checks the same four things and exits non-zero, so it can run in CI. It names the layer-order failure specifically, which is the one that produces no error and no animation.

bash
npx easeful doctor

Both are idempotent, and both decline rather than guess: two candidate stylesheets, a CommonJS or TypeScript flat config, or an export default with no array in it all print instructions instead. The rest of this page is what the commands do, for doing it by hand.

Import the layer

Once, globally, in the stylesheet your app already loads. In a Next app that is app/globals.css, the one imported by app/layout.tsx. In a Vite app it is src/index.css, imported by src/main.tsx. Everything easeful ships lives inside @layer easeful, so your own unlayered CSS always wins without a specificity fight.

css
@layer easeful, theme, base, components, utilities;
@import "easeful";
@import "tailwindcss";

Without Tailwind, drop the @layer line. It exists to fix an ordering problem that only Tailwind creates.

Declare the layer order first

This is the single most common failure, and it fails quietly: the attribute is present, the CSS is loaded, and nothing animates. The @layer line has to come before any @import when Tailwind v4 is present. A layer's position is fixed by where it is first named, so if Tailwind names its layers first, easeful lands after them and loses.

Activate the types

One line in a declaration file, anywhere your tsconfig.json already includes. It gives an editor the attribute and its values. It does not fail a build on a wrong one, because TypeScript leaves hyphenated JSX attributes unchecked, and the TypeScript page explains what that does and does not buy.

ts
/// <reference types="easeful/types" />

You can add "easeful/types" to the types array in tsconfig.json instead, with one thing to know: declaring that array at all switches off the automatic inclusion of every other @types package, so anything you were relying on ambiently, node most often, has to be listed beside it. The reference file has no such cost, which is why it is the instruction here.

React only, either way. The augmentation targets React's HTMLAttributes, so in a project without React it fails to compile and should be skipped. The stylesheet is unaffected, and the CSS is the whole library.

Give an agent the vocabulary

Optional, and worth the ten seconds if you code with Claude. The package ships a skill file generated from the same manifest as the CSS, so an agent gets the four preset names, the two attributes, the layer-order trap and the composition rules without guessing.

bash
npx easeful skill

That writes .claude/skills/easeful/SKILL.md in the project, which you can commit so everyone working on it gets the same one. Add --global to install it under your home directory for every project on the machine instead.

The file is also served raw at /skill.md if you would rather read it first, or drop it somewhere else:

bash
curl -o SKILL.md https://easeful.sanyam.sh/skill.md

Any tool that reads AGENTS.md needs nothing extra. The package ships one of those too, with the same body.

Catch a wrong value

Optional, and the only step that turns a typo into a failure. The package ships an ESLint rule that checks every literal data-motion against the same manifest the CSS is generated from. ESLint 9 or newer, flat config.

js
// eslint.config.mjs
import easeful from "easeful/eslint"

export default [...easeful.configs.recommended]

The TypeScript page lists the five things it catches and the one thing it cannot see.