with one click
with one click
[HINT] Download the complete skill directory including SKILL.md and all related files
| name | new |
| description | End-to-end workflow for building a new Terrae component from scratch |
| argument-hint | ["component-name"] |
End-to-end workflow for building a new Terrae component from scratch.
Covers all 8 outputs:
Component structure, patterns, responsiveness, and performance rules are in .claude/rules/react/component.md.
| # | Output | File(s) |
|---|---|---|
| 1 | Component source file | src/registry/map/{name}.tsx |
| 2 | Barrel export | src/registry/map/index.tsx (update) |
| 3 | Registry entry | registry.json (update) |
| 4 | Example file(s) | src/app/docs/_components/examples/{name}-example.tsx |
| 5 | Documentation page | src/app/docs/{slug}/page.tsx |
| 6 | Sidebar navigation | src/app/docs/_components/docs-sidebar.tsx (update) |
| 7 | Components listing | src/app/docs/components/page.tsx (update) |
| 8 | Changelog entry | src/app/docs/changelog/page.tsx (update) |
When the developer requests a new component:
Ask for:
MapHeatmap, MapPolygon)MarkerContent, MarkerPopup)"core" or "features" (most components are features)useHeatmapControl)If there are multiple valid implementation approaches (e.g., Mapbox layers vs DOM overlay, canvas vs CSS animations, GeoJSON source vs custom rendering), present the options with trade-offs and let the developer choose before writing code.
Follow the map component rules in .claude/rules/react/component.md for the component structure, template, patterns, and barrel export.
src/registry/map/{component-name}.tsxheat-map.tsx)src/registry/map/index.tsxUpdate registry.json by adding an entry to the items array.
Follow this structure:
{
"name": "heat-map",
"type": "registry:ui",
"title": "Map Heatmap",
"description": "Short description of the component.",
"dependencies": ["mapbox-gl"],
"devDependencies": ["@types/mapbox-gl"],
"registryDependencies": ["https://www.terrae.dev/map.json"],
"files": [
{
"path": "src/registry/map/heat-map.tsx",
"type": "registry:ui",
"target": "components/ui/map/heat-map.tsx"
}
]
}
name uses kebab-case with ``prefix (e.g.,heat-map)registryDependencies always includes ["https://www.terrae.dev/map.json"] (the core Map component that all other components depend on)dependencies only if the component needs packages beyond mapbox-glmapbox-gl directly can have empty dependencies (e.g., watermark)Location: src/app/docs/_components/examples/{name}-example.tsx
Use kebab-case for the file name.
The basic example should demonstrate the simplest usage of the component.
import { Map, MapHeatmap } from "@/registry/map"
export const HeatmapExample = () => {
const accessToken = process.env.NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN || ""
return (
<div className="h-full w-full">
<Map accessToken={accessToken} center={[-74.006, 40.7128]} zoom={10}>
<MapHeatmap id="heatmap-basic" {/* ...minimal props */} />
</Map>
</div>
)
}
"use client" if the example uses hooks, event handlers, or browser APIs — purely compositional examples that just render map components don't need it@/registry/map<div className="h-full w-full">process.env.NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN || "" as the access token — the Map component validates it and shows an error if missing, so examples don't need their own checkheatmap-color-example.tsx, heatmap-custom-example.tsx)Location: src/app/docs/{slug}/page.tsx
Use the lines-animated/page.tsx as the gold standard reference.
The slug should match the sidebar href (e.g., /docs/heatmap → src/app/docs/heatmap/page.tsx).
import { DocsLayout, DocsSection, DocsCode, DocsLink } from "../_components/docs"
import { ComponentPreview } from "../_components/component-preview"
import { CodeBlock } from "../_components/code-block"
import { HeatmapExample } from "../_components/examples/heatmap-example"
import { getExampleSource } from "@/lib/get-example-source"
import { Metadata } from "next"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
export const metadata: Metadata = {
title: "Heatmap",
}
const HeatmapPage = () => {
const basicSource = getExampleSource("heatmap-example.tsx")
return (
<DocsLayout
title="Heatmap"
description="Short description of what the component does."
prev={{ title: "Previous Component", href: "/docs/previous" }}
next={{ title: "Next Component", href: "/docs/next" }}
>
<DocsSection title="Installation">
<p>First, make sure you have the base map component installed:</p>
<CodeBlock code={`npx shadcn@latest add https://www.terrae.dev/map.json`} language="bash" />
<p className="mt-4">Then install the heatmap component:</p>
<CodeBlock
code={`npx shadcn@latest add https://www.terrae.dev/heat-map.json`}
language="bash"
/>
</DocsSection>
<ComponentPreview code={basicSource}>
<HeatmapExample />
</ComponentPreview>
{/* Additional sections with examples, props tables, etc. */}
</DocsLayout>
)
}
export default HeatmapPage
metadata with a titleDocsLayout with title, description, prev, and next navigation linksCodeBlocks (base map + component)ComponentPreview goes directly after Installation (no section title or description, just the demo)ComponentPreview to wrap each example with its source codegetExampleSource("filename.tsx") to load example source codeDocsCode for inline code references in descriptionsDocsSection with a title for each sectionTable when the component has many configurable propsprev/next to match adjacent items in the sidebar navigationUpdate src/app/docs/_components/docs-sidebar.tsx:
NavItem entry in the correct section of the navigation arraybadge: "new"{ title: "Heatmap", href: "/docs/heatmap", icon: Flame, badge: "new" },
Sections:
"Explore" — Story, Changelog"Get Started" — Introduction, Installation, Comparison, Components, Hooks, Reference"Core" — Map, Controls, Compass, Marker, Popup"Features" — Everything elseUpdate src/app/docs/components/page.tsx:
ComponentItem entry to the components arrayisNew: true{
title: "Heatmap",
href: "/docs/heatmap",
description: "Short description matching the registry description",
icon: Flame,
category: "features",
installCommand: "npx shadcn@latest add https://www.terrae.dev/heat-map.json",
isNew: true,
},
category is "core" or "features" (must match the sidebar section)installCommand URL follows the pattern https://www.terrae.dev/{registry-name}.jsonmapboxOnly: true if the component only works with Mapbox GL (not MapLibre)Update src/app/docs/changelog/page.tsx:
Add a new entry to the components array of the most recent (topmost) ChangelogEntry in the changelogs array:
{
title: "Heatmap",
description: (
<>
New <code className="rounded bg-muted px-1 py-0.5 text-xs">MapHeatmap</code> component for
visualizing data density on the map. Supports customizable color ramps, radius control,
and intensity adjustment.
</>
),
href: "/docs/heatmap",
},
components for new components, features for new features, fixes for bug fixes, properties for new propsdescription uses JSX with inline <code> tags for component nameshref linking to the docs pageBefore finalizing, show all changes: