KQ-1859 · ANT/COLUMN
Ant Column
A pixel-art colony on a Canvas 2D grid, run as a two-scent forager model: ants pour out of the nest, follow food scent with three sensors and a seeded wander, and an ant that reaches the pointer's scent or a crumb walks home on the home scent and its own bearing, laying food scent, so within seconds the search condenses into a neat single-file column round every pebble and every element marked data-obstacle. The scent follows the pointer on springs.glide, so the column's head swings after it and the body wobbles as the ants re-route; a click drops a crumb that lands on springs.recoil and is carried home a bit at a time while the nest's rim flicks bright. The keyboard's way in is one focus stop: arrow keys move the scent, Enter or Space drops a crumb at it, Escape lifts it.
Fernworks · field kitchen
Every crumb finds its way home.
Arrow keys move a scent the ants follow; Enter or Space drops a crumb there for them to carry home; Escape lifts the scent.
0 bits carried home · click to drop a crumb
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/ant-column
Props
- ants
- number
- default 140
- How many ants live in the nest, 10 to 400.
- pheromone
- number
- default 0.6
- How strong and how lasting the scent trails are, 0 (faint, quick to fade, loose paths) to 1 (bold, lasting, a tight column).
- pixel
- number
- default 3
- The size of one pixel of the colony, in px, 2 to 6. Ants are two pixels long.
- speed
- number
- default 0.5
- How fast the ants walk, 0 to 1.
- wander
- number
- default 0.3
- How much each ant meanders off its line, 0 (marching) to 1 (dithering).
- nest
- AntColumnPoint
- default { x: 0.1, y: 0.72 }
- Where the nest's mouth sits, as fractions of the box.
- crumbs
- readonly AntColumnPoint[]
- default [{ x: 0.86, y: 0.32 }]
- Crumbs already on the ground when the colony starts, as fractions of the box.
- crumbSize
- number
- default 18
- How many bits a crumb breaks into: one ant carries one bit home.
- obstacles
- readonly AntColumnPebble[]
- default two pebbles
- Pebbles the ants walk round: centres as fractions of the box, radii in px.
- avoidContent
- boolean
- default true
- Ants also walk round any element inside the colony marked data-obstacle, such as a card in your content.
- antColor
- string
- default "var(--foreground)"
- The ants' colour, any CSS colour; resolved on the element so it follows the theme.
- trailColor
- string
- default "var(--accent-bright)"
- The scent trails' colour.
- crumbColor
- string
- default "oklch(from var(--warn) 0.8 c h)"
- The crumbs' colour: a pigment at a fixed lightness, so it reads the same in both themes.
- earthColor
- string
- default "var(--ink-3)"
- The nest mound's and the pebbles' colour.
- children
- React.ReactNode
- default —
- Content above the colony: a heading, a card, a call to action. Mark a card data-obstacle and the column routes round it.
- interactive
- boolean
- default true
- The pointer leaves a scent the ants seek and a click drops a crumb; the keys do both.
- paused
- boolean
- default false
- Hold the colony where it is.
- label
- string
- default "Ant colony"
- Names the colony for assistive technology.
- seed
- number
- default 3
- Seeds every ant's wander and every crumb's shape, so two colonies never walk alike.
- dpr
- number
- default 2
- Cap on the canvas's device pixel ratio, at most 2.
- onCarry
- (total: number) => void
- default —
- Fires each time an ant brings a bit home, with the colony's total so far.
- onCrumb
- (x: number, y: number) => void
- default —
- Fires when a crumb is dropped, with its place in px from the box's top left.
- disabled
- boolean
- default false
- Shows the colony at work but takes no input.
- className
- string
- default "h-56 w-full"
- Sizes the box.
| Prop | Type | Default | Description |
|---|---|---|---|
| ants | number | 140 | How many ants live in the nest, 10 to 400. |
| pheromone | number | 0.6 | How strong and how lasting the scent trails are, 0 (faint, quick to fade, loose paths) to 1 (bold, lasting, a tight column). |
| pixel | number | 3 | The size of one pixel of the colony, in px, 2 to 6. Ants are two pixels long. |
| speed | number | 0.5 | How fast the ants walk, 0 to 1. |
| wander | number | 0.3 | How much each ant meanders off its line, 0 (marching) to 1 (dithering). |
| nest | AntColumnPoint | { x: 0.1, y: 0.72 } | Where the nest's mouth sits, as fractions of the box. |
| crumbs | readonly AntColumnPoint[] | [{ x: 0.86, y: 0.32 }] | Crumbs already on the ground when the colony starts, as fractions of the box. |
| crumbSize | number | 18 | How many bits a crumb breaks into: one ant carries one bit home. |
| obstacles | readonly AntColumnPebble[] | two pebbles | Pebbles the ants walk round: centres as fractions of the box, radii in px. |
| avoidContent | boolean | true | Ants also walk round any element inside the colony marked data-obstacle, such as a card in your content. |
| antColor | string | "var(--foreground)" | The ants' colour, any CSS colour; resolved on the element so it follows the theme. |
| trailColor | string | "var(--accent-bright)" | The scent trails' colour. |
| crumbColor | string | "oklch(from var(--warn) 0.8 c h)" | The crumbs' colour: a pigment at a fixed lightness, so it reads the same in both themes. |
| earthColor | string | "var(--ink-3)" | The nest mound's and the pebbles' colour. |
| children | React.ReactNode | — | Content above the colony: a heading, a card, a call to action. Mark a card data-obstacle and the column routes round it. |
| interactive | boolean | true | The pointer leaves a scent the ants seek and a click drops a crumb; the keys do both. |
| paused | boolean | false | Hold the colony where it is. |
| label | string | "Ant colony" | Names the colony for assistive technology. |
| seed | number | 3 | Seeds every ant's wander and every crumb's shape, so two colonies never walk alike. |
| dpr | number | 2 | Cap on the canvas's device pixel ratio, at most 2. |
| onCarry | (total: number) => void | — | Fires each time an ant brings a bit home, with the colony's total so far. |
| onCrumb | (x: number, y: number) => void | — | Fires when a crumb is dropped, with its place in px from the box's top left. |
| disabled | boolean | false | Shows the colony at work but takes no input. |
| className | string | "h-56 w-full" | Sizes the box. |