# Feature index sphere

A shadcn/ui editorial features section for showing what you do at a glance: a big-type feature index that pulls each feature's images from a 3D sphere.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available for the docs, pricing and about pages: append `.md` to the URL or send an `Accept: text/markdown` header (the home page answers the header too). An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md).

## At a glance

- **Good for:** Agency and studio services pages; Product feature overviews with imagery; Editorial and portfolio websites
- **Category:** Marketing, Portfolio · **Type:** Features · **Style:** Motion, Dark mode
- **See it:** [Live preview](https://www.craftui.space/docs/templates/feature-sphere-section) · [Screenshot](https://www.craftui.space/llms.md/preview/feature-sphere-section.96e7970b.jpg)

![Feature index sphere](https://www.craftui.space/llms.md/preview/feature-sphere-section.96e7970b.jpg)

## Install

```bash
pnpm dlx shadcn@latest add https://www.craftui.space/r/feature-sphere-section.json
```

This is a paid item (SEC-0008): the install needs a craftUI plan or a purchase of it. Signed in, the docs page gives your personal install command. Plans: https://www.craftui.space/pricing

## Usage

```tsx
import FeatureSphereSection from "@/components/blocks/feature-sphere-section";

export default function Page() {
  return <FeatureSphereSection />;
}
```

With no props it renders with demo content; pass your own through the props below.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `string` | `"What we do"` | The section's heading, for screen readers (the index is the visible title). |
| `features` | `SphereFeature[]` | `built-in demo content` | What you do: each becomes a line in the index and a pile of images. |
| `extraImages` | `FeatureImage[]` | `built-in demo content` | Images that belong to no feature: they fill out the sphere. |
| `linkLabel` | `string` | `"View work"` | Text on each feature's link. |
| `defaultFeature` | `string` | — | The feature open at first, by id. Defaults to the first. |
| `onFeatureChange` | `(feature: string) => void` | — | Called with a feature's id when it opens. |
| `headingLevel` | `1 \| 2` | `2` | 1 when this is the page's main heading; 2 when the page has its own h1. |
| `sphereSide` | `"left" \| "right"` | `"right"` | Which side the sphere sits on, on wide screens. Defaults to "right". |
| `sphere` | `Omit< ImageSphereProps, "items" \| "groups" \| "group" \| "defaultGroup" \| "onGroupChange" >` | — | Any of the image sphere's own options: `count`, `turnDuration`, `pileSize`, `pileCurve`, `autoRotate`, `hint`, `className`, `aria-label` and so on. The section sets its images, groups and open group itself. |

It also accepts every `<section>` attribute (`className`, `id`, `aria-*` and so on).

### `SphereFeature`

| Field | Type | Description |
| --- | --- | --- |
| `id` (required) | `string` | Unique id, used by `defaultFeature` and `onFeatureChange`. |
| `label` (required) | `string` | The feature's name: one of the big lines in the index, e.g. "Architecture". |
| `description` (required) | `ReactNode` | A sentence or two shown under the name while the feature is open. |
| `href` | `string` | Where its link (`linkLabel`) goes. Without it, no link is shown. |
| `images` (required) | `FeatureImage[]` | This feature's images: they form its pile. |

### `FeatureImage`

| Field | Type | Description |
| --- | --- | --- |
| `src` (required) | `string` | Image URL. The card keeps its shape, cropped only past tall portrait (0.62) or 16:9. |
| `alt` (required) | `string` | Describes the image for screen readers. |

### `ImageSphereProps`

| Field | Type | Description |
| --- | --- | --- |
| `items` | `ImageSphereItem[]` | Your images. Each can belong to a group, which gathers into a pile. |
| `groups` | `ImageSphereGroup[]` | The groups items belong to, by id, with the label shown on hover. |
| `count` | `number` | Cards on the sphere; items repeat round it to fill them. Defaults to 240, or 140 on screens narrower than 40rem. Never fewer than items. |
| `autoRotate` | `boolean` | Turns slowly while nobody's using it and no group is open. |
| `defaultGroup` | `string \| null` | The group open at first, by id. |
| `group` | `string \| null` | The open group, when the parent decides it (e.g. from scroll). Clicks then only report through `onGroupChange`, and the block's own keyboard buttons are left out: the parent's controls take their place. |
| `onGroupChange` | `(group: string \| null) => void` | Called when a group opens (its id) or closes (null). |
| `allLabel` | `string` | The keyboard button that closes the open group. |
| `hint` | `ReactNode` | The line in the top corner, until the first touch. Pass null to hide it. |
| `turnDuration` | `number` | Seconds the globe takes for one full turn when idle. Defaults to 45. |
| `pileSize` | `number` | Most images a group's pile shows. Defaults to 12. |
| `pileCurve` | `number` | How curved the pile's images are, from 0 (flat) to 1 (most curved). Defaults to 0.6. |

### `ImageSphereItem`

| Field | Type | Description |
| --- | --- | --- |
| `src` (required) | `string` | Image URL. The card keeps its shape, cropped only past tall portrait (0.62) or 16:9. |
| `alt` (required) | `string` | Describes the image for screen readers. |
| `group` | `string` | A group's `id`. Items without one stay on the sphere. |

### `ImageSphereGroup`

| Field | Type | Description |
| --- | --- | --- |
| `id` (required) | `string` | Unique id that items point at with their `group`. |
| `label` (required) | `string` | The group's name: the tag beside the pointer on hover, and its keyboard button. |

## Files

The install adds:

- `components/blocks/feature-sphere-section.tsx`
- `components/blocks/image-sphere.tsx`
- `components/blocks/image-sphere-scene.ts`
- `components/blocks/image-sphere-gl.ts`

No npm dependencies beyond React and Tailwind CSS.