AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
A monorepo of animated React Native + React Native Web UI components, styled with Tailwind via uniwind and powered by a custom Moti/Reanimated 4 layer.
Developer toolsTypeScript · JavaScriptGitHub @iv-stpnOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Loading the full README. The saved excerpt is shown below.
Animated React Native + React Native Web UI components, styled with Tailwind via uniwind and driven by a Moti / Reanimated 4 animation layer.
Components are written as React Native primitives — they compile to native (iOS / Android via Expo or bare RN) and to the web via react-native-web with a single shared codebase. No platform forks.
Every component lives at its own subpath — no barrel, no dead weight:
The lists below are generated from the package's exports map by
node packages/ui/scripts/check-readme.mjs --fix, which CI re-runs on every push.Read the full README ↗Animated React Native + React Native Web UI components, styled with Tailwind via uniwind and driven by a Moti / Reanimated 4 animation layer.
Components are written as React Native primitives — they compile to native (iOS / Android via Expo or bare RN) and to the web via react-native-web with a single shared codebase. No platform forks.
| Package | Description |
|---|---|
rn-motion-ui | Components, hooks, Moti layer, and utils — published as one package with subpath exports (no barrels) |
rn-motion-ui-icons | The MingCute icon set — 3,335 react-native-svg icons, one subpath export each |
Every component lives at its own subpath — no barrel, no dead weight:
import { Button } from 'rn-motion-ui/button'
import { Card } from 'rn-motion-ui/card'
import { useInView } from 'rn-motion-ui/hooks/use-in-view'
The lists below are generated from the package's
exportsmap bynode packages/ui/scripts/check-readme.mjs --fix, which CI re-runs on every push.
action-fab · action-feedback-modal · action-row · action-row-group · activity-island · adaptive-dropdown · adaptive-modal · animated-badge · animated-list · bottom-sheet · bouncy-accordion · breadcrumbs · button · button-group · button-swap · card · checkbox · checkbox-card · choice-group · close-button · color-picker · command-palette · cylinder-carousel · detail-header · dock · dock-inset · drag-behavior · drag-geometry · drag-manager · drag-scope · drag-store · drag-transfer · drag-types · draggable · dragzone · drawer · dynamic-island · elevated-button · file-icon · file-icons · full-sheet · hold-draggable · hold-menu · holdable · hover-menu · icon · icon-button · input · item-row · item-row-group · loader · menu · menu-item · menu-placement · modal-presenter · morphing-dock-switch · morphing-fab · morphing-menu · morphing-modal · morphing-switcher · multi-drag · multi-drag-manager · multi-drag-scope · multi-draggable · multi-step-menu · otp-input · overflow-actions · popover · portal · primary-actions · radio · radio-card · range-slider · reorderable-list · scroll-progress · scroll-reveal · · · · · · · · · · · · · · · · · · · · · · · · ·
hooks/direction-provider · hooks/use-arm-on-view · hooks/use-arrow-roving · hooks/use-auto-focus-on-show · hooks/use-breakpoint · hooks/use-calendar · hooks/use-controlled · hooks/use-date-picker · hooks/use-date-range-picker · hooks/use-direction · hooks/use-focus-trap · hooks/use-hover-capable · hooks/use-in-view · hooks/use-interval · hooks/use-menu-keyboard · hooks/use-modal-render · hooks/use-mount-effect · hooks/use-page-visible · hooks/use-press-state · hooks/use-reduced-motion · hooks/use-safe-insets · hooks/use-scramble · hooks/use-shake-animation
use-calendar, use-date-picker and use-date-range-picker are headless: they own the date arithmetic, the keyboard, the roving tab stop and the accessibility payload, and render nothing. There is no styled <Calendar /> in the package — you spread prop getters onto your own markup. Dates are ISO 'YYYY-MM-DD' strings throughout, never Date objects. See the package README for the full surface.
Pure helpers and the theme layer — tokens, easings, the surface ladder, and the runtime colour resolvers. Icons live in rn-motion-ui-icons.
breakpoints · calendar · calendar-format · calendar-props · calendar-selection · color · date-field · date-picker-props · ease · elevated · lib/cn · lib/glass · lib/haptics · lib/haptics-types · lib/typeguards · theme/motion · theme/use-theme-color
Animated primitives: moti/view · moti/text · moti/image · moti/scroll-view · moti/safe-area-view
Presence: moti/presence · moti/presence-context
Pressable / hover: moti/pressable · moti/pressable-context · moti/pressable-types · moti/hover · moti/hover-context · moti/merge
Core / hooks: moti/motify · moti/use-motify · moti/use-animation-state · moti/use-dynamic-animation · moti/use-moti-pressable · moti/use-moti-pressables · moti/use-moti-pressable-animated-props · moti/use-moti-pressable-interpolate · moti/use-moti-pressable-transition
Types / constants: moti/types · moti/color-keys
table-header · table-row · table-types · table-utils · use-column-reorder · use-table
The shell and presence hook the sheet family (bottom-sheet, full-sheet, drawer, adaptive-modal) is built on. Exported so a consumer can build a sheet of their own on the same primitives — but they are infrastructure, not a component API, and they change with the components that use them rather than on their own deprecation cycle.
overlay/blur-provider · overlay/overlay-blur · overlay/overlay-portal · overlay/overlay-shell · overlay/use-sheet-presence
This package ships TypeScript source — no prebuilt bundles. Two build-time plugins are required:
react-native-reanimated/plugin (Babel) — transforms Reanimated worklets.uniwind — resolves className props on RN components to styles at build time.babel.config.js:
module.exports = {
presets: ['babel-preset-expo'],
plugins: ['react-native-reanimated/plugin'],
};
Set up uniwind per its docs (Metro transformer + global.css Tailwind entry).
Alias react-native → react-native-web, pipe the Reanimated Babel plugin through your React transform, and add the uniwind Vite plugin. See storybook/web/.storybook/main.ts for a complete working reference.
optimizeDepsnote: Uniwind excludesreact-nativefrom Vite's dep optimizer, which breaks@react-native/normalize-colors. The reference config force-includesreact-native-webto work around this.
Import the token sheet in your global CSS, then override any token in a later @theme block:
@import "tailwindcss";
@import "uniwind";
@import "rn-motion-ui/tokens.css";
@theme {
--color-primary: oklch(52% 0.22 250); /* your brand color */
}
Backgrounds follow a surfaces system: an elevation ladder surface-1 … surface-8 with paired shadow recipes.
| Class | Role |
|---|---|
bg-surface-1 | Page background |
bg-surface-3 | Cards, popovers, dialogs, inputs |
bg-surface-4–8 | Stacked overlays |
shadow-surface-N | Elevation shadow — pair with the matching bg-surface-N |
bg-surface-hover | Translucent hover overlay on any surface level |
bg-surface-selected | Translucent selected overlay on any surface level |
In light mode, surfaces 3+ are pure white and shadows alone carry depth. In dark mode each level steps up in lightness with a subtle neutral tint (hue 270, chroma 0.004).
success / warning / info / danger each ship as a vivid fill plus a white foreground, so a filled status plate is two classes:
<View className="rounded-lg bg-success p-3">
<Text className="text-success-foreground">Saved!</Text>
</View>
danger is the destructive fill. warning and info hold the same value in both schemes; they already sit at mid lightness, so there is nothing a dark-mode lift fixes.
white and black are the two tokens that do not flip with the theme — identical in light and dark, on web and native. They cover the cases where a fixed color is the design intent rather than an oversight: a glyph on a vivid status fill, a gloss highlight, a scrim.
<Text className="text-white">On a vivid fill in both schemes</Text>
const white = useThemeColor('white'); // "rgb(255, 255, 255)"
Reach for them instead of a hardcoded #fff / #000. For anything that should track the theme, use foreground / surface-N.
Surface components (Card, Popover, AdaptiveDropdown, HoverMenu, MorphingModal, ActionFeedbackModal, AdaptiveModal, MorphingFAB) accept an elevation prop (1–8). It drives the background, drop shadow, and — in dark mode — the inset rim highlight together, keeping fill and rim calibrated at the same level.
useThemeColor(token) / useThemeColors() (from rn-motion-ui/theme/use-theme-color) resolve tokens to concrete sRGB strings for RN StyleSheet, SVG props, and Reanimated color animations. On web they read live CSS variables; on native they fall back to static maps derived from the same OKLCH definitions via rn-motion-ui/color — a pure-formula OKLCH → sRGB converter you can also use directly.
import { oklchToSrgb, cssColorToSrgb } from 'rn-motion-ui/color'
bun install
bun run storybook # web (Vite, hot reload)
bun run storybook:native # iOS/Android via Expo Go
bun run lint # Biome — whole workspace
bun run lint:fix # auto-fix
bun run typecheck # tsc --noEmit across all packages
bun run test # Vitest + Playwright interaction tests (real Chromium)
87 story files, 332 stories.
Every story runs as a vitest test; those with a play function run their interaction assertions in a real Chromium browser via @storybook/addon-vitest. packages/ui also carries a jsdom unit suite over the pure layers (Moti worklets, lib/, and the OTP edit logic).
This repo uses Changesets for versioning and publishing.
bun run changeset # describe your change
bun run version-packages # bump versions + generate changelogs
bun run release # publish to npm
CI (.github/workflows/release.yml) runs the changesets action on every push to main — it either opens a "Version Packages" PR or publishes if that PR is already merged.
sideEffects: ["**/*.css"] — CSS token file is side-effectful; all TS source is tree-shakeable.useReducedMotion consumed by every animated component — respects the OS reduced-motion preference.theme/motion holds the shared presets; every trigger-summoned panel (AdaptiveDropdown, HoverMenu, Popover) resolves its animation through resolveMenuMotion and takes the same motion prop.FileSystem's filter pipeline and the calendar/date-picker hooks ship as behaviour with no markup, so a consumer's own design system renders them. Their date layer is pure and React-free (lib/calendar*, lib/date-field), which is also what makes it unit-testable without a renderer.noUncheckedIndexedAccess, verbatimModuleSyntax).rn-motion-ui-icons.MIT © Ivan Stepanian
rn-motion-ui-icons is (MIT AND Apache-2.0): the wrapper components are MIT,
and the MingCute icon artwork they draw is Apache-2.0.
See packages/icons/NOTICE.
surface-1 … surface-8 elevation ladder with paired shadow recipes — follows Fluid Functionalism.scroll-toskeletonsmooth-scrollsortable-listspotlightspotlight-targetstar-ratingstateful-buttonsurfaceswipeable-listswitchtabletabstexttext-cascadetext-number-tickertext-revealtext-rollingtext-shimmertoastertoggle-groupuse-drag-behavioruse-drag-storeuse-draggablewheel-picker