Contributing

Learn how to contribute to glsilk and help make it better for everyone.

Getting Started

Setup

Fork and clone the repository, then install dependencies:

git clone https://github.com/jefferypippitt/gl-silk.git
cd gl-silk
pnpm install

Create a .env.local file:

.env.local
# App origin (local dev)
NEXT_PUBLIC_BASE_URL=http://localhost:3000

# For testing and previewing components with the open in v0 button.
NEXT_PUBLIC_BASE_URL=https://<id>.ngrok-free.app
NEXT_PUBLIC_APP_URL=https://<id>.ngrok-free.app
NEXT_PUBLIC_V0_BASE_URL=https://<id>.ngrok-free.app

Start Public Tunnel

Start a tunnel on the fixed domain (hostname only, no https):

ngrok http --domain=<id>.ngrok-free.app 3000

If domain reservation isn't available, use:

ngrok http 3000

Then copy the printed https://<id>.ngrok-free.app and ensure your .env.local uses that URL for NEXT_PUBLIC_V0_BASE_URL.

Run Dev Server

Start Next.js locally:

pnpm dev

Create Component Files

Create your component directory in registry/new-york/components/your-component-name/:

my-button.tsx
demo.tsx

1. Create the demo file (demo.tsx):

"use client";

import { MyButton } from "./my-button";

export function MyButtonDemo() {
  return (
    <div className="flex flex-wrap gap-4 justify-center">
      <MyButton>My Button</MyButton>
    </div>
  );
}

2. Create documentation file (content/docs/components/your-category/my-button.mdx):

The file should include:

  • Frontmatter with title and description
  • Installation using ```npm shorthand (auto-generates npm/pnpm/yarn/bun tabs)
  • <Steps> for installation flow
  • Quick Start section with import and usage example
  • Examples with <ComponentPreview> in Preview/Code tabs
  • <TypeTable> for API reference

See content/docs/components/buttons/mesh-gradient.mdx for a complete example.

Register Component

Add your component to two registry files:

1. components/mdx/component-registry.tsx — For documentation pages:

import { MyButtonDemo } from "@/registry/new-york/components/my-button/demo";

export const componentRegistry: Record<string, React.ComponentType> = {
  // ... existing components
  "my-button-demo": MyButtonDemo,
};

2. components/registry/dynamic-component-loader.tsx — For blocks page:

import { MyButtonDemo } from "@/registry/new-york/components/my-button/demo";

const componentMap: Record<string, React.ComponentType> = {
  // ... existing components
  "my-button": MyButtonDemo,
};

3. registry.json — For registry entries:

Add a main entry for your component:

{
  "name": "my-button",
  "type": "registry:component",
  "category": "buttons",
  "title": "My Button",
  "description": "Description of your button component.",
  "dependencies": [],
  "files": [
    {
      "path": "registry/new-york/components/my-button/my-button.tsx",
      "type": "registry:component"
    },
    {
      "path": "registry/new-york/components/my-button/demo.tsx",
      "type": "registry:component"
    }
  ]
}

4. Demo Variations — If you create multiple demo files (e.g., sizes-demo.tsx, variants-demo.tsx):

Create separate registry entries for each demo variation. This ensures the "Open in v0" button works correctly for each demo.

For example, if you have sizes-demo.tsx:

{
  "name": "my-button-sizes",
  "type": "registry:component",
  "category": "buttons",
  "title": "My Button - Sizes",
  "description": "My button with different size variants.",
  "dependencies": [],
  "files": [
    {
      "path": "registry/new-york/components/my-button/my-button.tsx",
      "type": "registry:component"
    },
    {
      "path": "registry/new-york/components/my-button/sizes-demo.tsx",
      "type": "registry:component"
    }
  ]
}

Make sure the OpenInV0Button name in your MDX file matches the registry entry name: <OpenInV0Button name="my-button-sizes" />

After adding entries to registry.json, build the registry:

pnpm registry:build

Best Practices

  • Follow existing patterns in the codebase
  • Add responsive design considerations
  • Ensure accessibility compliance
  • Test across different browsers

Commit Convention

When you create a commit, follow the convention category(scope or module): message using one of these categories:

CategoryDescription
feat / featureCompletely new code or new features
fixBug fixes (reference an issue if present)
refactorCode changes that are not a fix nor a feature
docsDocumentation changes (README, usage docs, etc.)
buildBuild changes, dependency updates
testAdding or changing tests
ciCI configuration changes (GitHub Actions, etc.)
choreChanges that don't fit any of the above

Example: feat(components): add new prop to the button component

glsilk