diff --git a/.prettierignore b/.prettierignore
index 3454d92..4cea0a3 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1,4 +1,3 @@
-/examples
pnpm-lock.yaml
packages/core/__tests__/fixtures/vite/vite.config.ts
packages/core/__tests__/fixtures/next/tsconfig.json
diff --git a/AGENTS.md b/AGENTS.md
index 7a811ea..9c1a7f3 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1,3 +1,5 @@
+
+
# Guidelines for AI Agents in this Repo
This repository contains **React Zero-UI**, a library for global UI state without React re-renders.
@@ -5,15 +7,68 @@ Use these tips when working with the codebase or generating examples.
## How React Zero-UI works
-1. `useUI()` writes to `document.body.dataset` using keys you specify (e.g. `theme` → `data-theme`).
-2. Build tooling scans for all keys and values, generating CSS variants for each.
-3. When a setter is called, the corresponding body attribute changes instantly with no React re-render.
+1. `useUI()` writes to `document.body.dataset` using keys you specify.
+
+```tsx
+const [staleValue, setValue] = useUI<'open' | 'closed'>('sidebar', 'closed');
+```
+
+- `key` → becomes `data-{key}` on `
` (e.g., `sidebar` → `data-sidebar="closed"`).
+- `defaultValue` → used for SSR to avoid FOUC.
+- The first value is **always stale** — do NOT rely on it for reactive updates.
+
+2. Consumption is done strictly with tailwind variant classNames:
+
+```html
+
+```
+
+3. Build-time tooling scans all `useUI()` keys and values, then generates matching Tailwind variants.
+
+4. At runtime, calling the setter updates the `data-*` attribute on `` immediately. No VDOM. No re-renders.
+
+---
+
+## Best Practices for AI Agents
+
+- ✅ Use `useUI()` **only for UI state**: themes, layout flags, open/closed toggles, etc.
+- ✅ Prefer **kebab-case keys**: e.g. `sidebar-open`, `theme-dark`.
+- ✅ Always provide a `defaultValue`: prevents FOUC and enables SSR.
+- ✅ Do **NOT** use the first value from `useUI()` for logic — it DOES NOT UPDATE.
+- ✅ You can call setters **from anywhere** in the app — no prop drilling or context needed.
+- ✅ Tailwind classes must use `key-value:` pattern:
+
+ - `theme-dark:bg-black`
+ - `accent-blue:text-blue-500`
+ - `sidebar-open:translate-x-0`
+
+---
+
+## Example: Toggle Theme
+
+```tsx
+// Set state
+const [, setTheme] = useUI<'light' | 'dark'>('theme', 'light');
+;
+```
+
+```html
+
+
+```
+
+---
+
+## What NOT to do
+
+- ❌ Don't use `useUI()` for business logic or data fetching
+- ❌ Don't rely on the first tuple value for reactivity
+- ❌ Don't use camelCase keys (will break variant generation)
+
+---
+
+## Summary
-## Best practices
+**React Zero-UI is a ZERO re-render UI state engine with global state baked in.** It replaces traditional VDOM cycles with `data-*` attribute flips and compile-time CSS. No React context. No prop drilling. No runtime cost.
-- Only use `useUI` for UI-only state (themes, flags, etc.).
-- Prefer kebab-case keys (`sidebar-open`) so generated variants are predictable.
-- Always pass a default value to `useUI(key, defaultValue)` to avoid flashes during SSR.
-- The first value is ALWAYS STALE, do not use it if you need reactivity.
-- Mutate the state anywhere in the app: `const [, setTheme] = useUI('theme', 'light');` then call `setTheme('dark')`.
-- Compose Tailwind classes anywhere with the pattern `key-value:` like `theme-dark:bg-black`.
+Think of it as writing atomic Tailwind variants for every UI state — but flipping them dynamically at runtime without re-rendering anything.
diff --git a/examples/demo/.prettierignore b/examples/demo/.prettierignore
deleted file mode 100644
index cab8289..0000000
--- a/examples/demo/.prettierignore
+++ /dev/null
@@ -1,27 +0,0 @@
-# package artifacts
-node_modules/
-.next/
-dist/
-coverage/
-test-results/
-.pnpm-store/
-package-lock.json
-
-# logs / temp files
-npm-debug.log*
-yarn-error.log*
-.DS_Store
-**/playwright-report/
-
-# IDE/editor
-.vscode/
-
-# tarballs produced during local tests
-*.tgz
-
-# local scratch files
-t.py
-todo.md
-
-# keep these files
-!next-env.d.ts
diff --git a/examples/demo/.prettierrc.json b/examples/demo/.prettierrc.json
deleted file mode 100644
index d74c679..0000000
--- a/examples/demo/.prettierrc.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "semi": true,
- "trailingComma": "es5",
- "singleQuote": true,
- "tabWidth": 2,
- "useTabs": false,
- "printWidth": 160,
- "endOfLine": "lf",
- "arrowParens": "avoid",
- "bracketSpacing": true,
- "jsxBracketSameLine": false,
- "singleAttributePerLine": true,
- "plugins": [
- "prettier-plugin-tailwindcss"
- ]
-}
\ No newline at end of file
diff --git a/examples/demo/.zero-ui/attributes.js b/examples/demo/.zero-ui/attributes.js
index 8363de9..ef1b0a2 100644
--- a/examples/demo/.zero-ui/attributes.js
+++ b/examples/demo/.zero-ui/attributes.js
@@ -4,7 +4,7 @@ export const bodyAttributes = {
"data-active": "zero",
"data-menu-open": "false",
"data-mobile-menu": "closed",
- "data-scrolled": "down",
+ "data-scrolled": "up",
"data-theme": "light",
"data-theme-test": "light"
};
diff --git a/examples/demo/next.config.ts b/examples/demo/next.config.ts
index 5e891cf..a67a28b 100644
--- a/examples/demo/next.config.ts
+++ b/examples/demo/next.config.ts
@@ -1,7 +1,7 @@
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
- /* config options here */
+ /* config options here */
};
export default nextConfig;
diff --git a/examples/demo/package.json b/examples/demo/package.json
index 6350dbf..f644810 100644
--- a/examples/demo/package.json
+++ b/examples/demo/package.json
@@ -1,37 +1,35 @@
{
- "name": "react-zero",
- "version": "0.1.0",
- "private": true,
- "type": "module",
- "scripts": {
- "dev": "next dev",
- "build": "next build",
- "start": "next start",
- "lint": "next lint",
- "lint:fix": "next lint --fix",
- "format": "prettier --write .",
- "format:check": "prettier --check .",
- "type-check": "tsc --noEmit",
- "clean": "rm -rf .next"
- },
- "dependencies": {
- "@austinserb/react-zero-ui": "^1.0.19",
- "@vercel/analytics": "^1.5.0",
- "clsx": "^2.1.1",
- "motion": "^12.16.0",
- "next": "15.3.3",
- "react": "^19.0.0",
- "react-dom": "^19.0.0"
- },
- "devDependencies": {
- "@tailwindcss/postcss": "^4.1.10",
- "@types/node": "^20",
- "@types/react": "^19",
- "@types/react-dom": "^19",
- "postcss": "^8.5.5",
- "prettier": "^3.5.3",
- "prettier-plugin-tailwindcss": "^0.6.12",
- "tailwindcss": "^4.1.10",
- "typescript": "^5"
- }
-}
\ No newline at end of file
+ "name": "react-zero",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint",
+ "lint:fix": "next lint --fix",
+ "format": "prettier --write .",
+ "format:check": "prettier --check .",
+ "type-check": "tsc --noEmit",
+ "clean": "rm -rf .next"
+ },
+ "dependencies": {
+ "@austinserb/react-zero-ui": "^1.0.21",
+ "@vercel/analytics": "^1.5.0",
+ "clsx": "^2.1.1",
+ "motion": "^12.16.0",
+ "next": "15.3.3",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0"
+ },
+ "devDependencies": {
+ "@tailwindcss/postcss": "^4.1.10",
+ "@types/node": "^20",
+ "@types/react": "^19",
+ "@types/react-dom": "^19",
+ "postcss": "^8.5.5",
+ "tailwindcss": "^4.1.10",
+ "typescript": "^5"
+ }
+}
diff --git a/examples/demo/postcss.config.mjs b/examples/demo/postcss.config.mjs
index 0829fc6..2e0aa24 100644
--- a/examples/demo/postcss.config.mjs
+++ b/examples/demo/postcss.config.mjs
@@ -1,7 +1,5 @@
// postcss.config.mjs
-const config = {
- plugins: ['@austinserb/react-zero-ui/postcss', '@tailwindcss/postcss'],
-};
+const config = { plugins: ['@austinserb/react-zero-ui/postcss', '@tailwindcss/postcss'] };
export default config;
diff --git a/examples/demo/src/app/(test)/ReactState.tsx b/examples/demo/src/app/(test)/ReactState.tsx
index 086b357..2c2c287 100644
--- a/examples/demo/src/app/(test)/ReactState.tsx
+++ b/examples/demo/src/app/(test)/ReactState.tsx
@@ -5,180 +5,168 @@ import { useState } from 'react';
import { useRenderTracker } from './ReactTracker';
export function TestComponentWithState() {
- const ref = useRenderTracker('TestComponentWithState');
- const [accent, setAccent] = useState<'violet' | 'emerald' | 'amber'>('violet');
- const [theme, setTheme] = useState<'light' | 'dark'>('light');
- const [menuOpen, setMenuOpen] = useState(false);
-
- return (
-