Contribution guidelines for the project.
This guide explains how to get started, the project structure, and the conventions to follow so your contributions fit in.
Note: This project uses pnpm as the package manager; you must have pnpm installed globally to run commands and tests locally.
git checkout -b feature/YourFeatureName).pnpm install to set up all required packages.Open an issue describing what you expected, what actually happened, steps to reproduce, and any helpful screenshots or code.
Every suggestion matters. Describe the context, what should change, and include examples or references if available.
A good component has a clear purpose, performs well, is easy to use, is well documented, and feels considered in both design and animation quality.
Use kebab-case for all folder and file names: fluid-distortion, magnetic-button-demo, etc.
Here’s where each type of file lives:
src/registry/base holds the main components for export.src/registry/demos holds demo components.src/registry/demos/index.ts exports the demo components.src/content holds documentation.(src/registry)
├── base
│ └── your-component
│ └── your-component.tsx # Your new component
├── hooks
│ └── use-frame-loop.ts # Shared hooks
├── demos
│ ├── your-component-demo
│ │ └── your-component-demo.tsx # Your new demo component
│ └── index.ts # Exports the demo components
(src/content)
├── en
│ ├── components
│ │ ├── _dir.yml
│ │ ├── your-component
│ │ │ └── your-component.mdx # Your new component documentationEach component should have a single responsibility and reside in a single file to keep it self-contained and easy to reuse.
If some logic, like a hook, is shared across multiple components, place it in a shared folder in src/registry and reference it in the component's shared field in src/registry/index.ts. One example is the use-frame-loop hook.
const NAMED_X_CONSTANT = {...} as const
const NAMED_Y_CONSTANT = "value" as const
type ComponentExample = {...}
type ComponentExampleProps = {...} & ComponentProps<'div'>
function helperFunction() {...}
export function ComponentExample({}: ComponentExampleProps) {...}All components should use Tailwind CSS for styling. Inline styles may be used only when the style depends on runtime values that cannot be expressed with Tailwind classes. Use current available Tailwind utilities and CSS variables or add new ones as needed.
This project uses motion.dev for DOM-based animations and React Three Fiber for WebGL/shader effects. Choose the library that best fits the effect you are implementing.
For interactive components, add keyboard support and ARIA roles/labels where practical. Purely visual or complex animations that can’t fully support accessibility are exempt. Optimization like reduced motion should be handled by the developer using the component.
Create a new folder in the src/registry/base folder with the name of the component:
export function ComponentName() {
return <></>
}Create a demo component in the src/registry/demos folder and structure it how you want:
import ComponentName from '@/registry/base/component-name/component-name'
export function ComponentNameDemo() {
return <ComponentName />
}Export the demo component in the src/registry/demos/index.ts file:
export const demos: Record<string, React.LazyExoticComponent<React.ComponentType>> = {
'component-name': lazy(() => import('./component-name-demo/component-name-demo')),
}Add the component to the registry by including its name and dependencies in src/registry/index.ts:
export const components: TRegistryComponent[] = [
{
name: 'new-component',
files: ['new-component.tsx'],
description: 'My new component',
shared: ["hooks/my-shared-hook", "utils/my-shared-utility"],
dependencies: [
'example-dependency-1',
'example-dependency-2',
],
},
]Add the metadata for the component in the frontmatter:
---
title: "New Component"
description: "My new component"
icon: 'Component'
---Add a preview of the component by using the <DocComponentPreview /> component with the same exact name of the demo component.
<DocComponentPreview name="component-name-demo" />Add the installation guide by using the <DocInstallGuide /> component with the same exact name of the base component.
<DocInstallGuide name="component-name" />Provide a code example of the component by using the language of the code.
import { MyComponent } from 'my-component'
<MyComponent/>Add the API of the component by using the following table format:
| Name | Type | Default | Description |
| ----------------- | ------- | --------- | -------------------------------------------------------------------- |
| `speed` | number | `1.0` | Controls the animation speed multiplier. |
| `color` | string | `#ff5733` | Sets the primary color of the component. |Provide a detailed list of the component's credits:
[Author Name](https://example.com)
Designed the original component concept.
[Library Name](https://example.com)
Used for animation utilities within this component.Use conventional commits: start your commit message with the type of change (feat, fix, chore, docs, refactor, style, test) followed by a precise, descriptive message.
To run tests locally be sure you have all the dependencies installed, in both the root and the packages/cli-tool folder.
Tests run automatically on every pull request. They verify that every component has its files, demo, export, and documentation in sync.
You can also run them locally to catch issues early by running pnpm test