collectui
by rayhankhilji
README.md
# collectui-mcp
**Show your coding agent a design, not a screenshot.**
You find a beautiful UI animation on [CollectUI](https://collectui.com/). You want Claude Code (or Codex, or Cursor) to build something like it. So you screenshot it, paste it in, and... the agent sees one frozen frame. It has no idea the dropdown springs open over 240ms, overshoots by 7%, and settles. It guesses. You get generic `ease-in-out` mush.
This MCP server fixes that. Paste a CollectUI link and your agent gets the actual numbers.
---
## What your agent actually receives
Real output, from a real post:
```
0.69s → 0.92s · TRANSITION · 231ms · translation — content travels right 75px
- Change focused on the upper-centre-right (81% of the change energy)
- Displacement: dx +75px, dy +0px (within the 644×350 content box)
- Best-fit easing: expo-out (snappy) → cubic-bezier(0.16, 1, 0.3, 1) (R²=0.98)
- Overshoot of 7% — a spring, not a plain ease
Where the movement happens:
| ░▓▓░|
| ░░██░|
| ░|
| ▒|
| ▒▓ |
```
That last bit is a heat map of the frame. Your agent can see the motion is in the top-right — not just that "something moved."
The brief also includes the colour palette (with contrast ratios), the layout structure, whether the animation loops seamlessly, and it ends with copy-pasteable CSS and framer-motion to start from.
**All of that is about 2,500 tokens. No images required.**
---
## Why not just send frames?
A 5-second GIF is ~150 frames. Sending even a fraction of those costs tens of thousands of tokens, and it *still* can't tell your agent that a transition is 231ms — because you can't measure time from a pile of stills.
So this measures the video directly and writes the answer down in words. Text is smaller, more precise, and more useful.
Images are still available when you want them — they're just opt-in, and the ones you get are chosen at meaningful moments (the start of a transition, its peak, where it settles) rather than sampled blindly.
---
## Setup
### 1. Prerequisites
You need **Node 18+** and **ffmpeg**.
```bash
brew install ffmpeg
```
(On Linux: `sudo apt install ffmpeg`. On Windows: grab it from [ffmpeg.org](https://ffmpeg.org/download.html) and make sure it's on your PATH.)
### 2. Get the code
```bash
git clone https://github.com/rayhankhilji/collectui-mcp.git
```
Then install and build it:
```bash
cd collectui-mcp && npm install && npm run build
```
### 3. Connect it to your agent
Pick whichever one you use. In every case, replace `/path/to/collectui-mcp` with wherever you actually cloned it — an **absolute** path, not a relative one.
<details open>
<summary><b>Claude Code</b></summary>
One command:
```bash
claude mcp add collectui --scope user -- node /path/to/collectui-mcp/dist/index.js
```
`--scope user` makes it available in every project. Use `--scope project` instead if you only want it in the current repo.
Verify it connected:
```bash
claude mcp list
```
</details>
<details>
<summary><b>Codex CLI</b></summary>
Add this to `~/.codex/config.toml`:
```toml
[mcp_servers.collectui]
command = "node"
args = ["/path/to/collectui-mcp/dist/index.js"]
```
</details>
<details>
<summary><b>Cursor</b></summary>
Add this to `~/.cursor/mcp.json` (or `.cursor/mcp.json` inside a project):
```json
{
"mcpServers": {
"collectui": {
"command": "node",
"args": ["/path/to/collectui-mcp/dist/index.js"]
}
}
}
```
</details>
<details>
<summary><b>Windsurf, Zed, or anything else that speaks MCP</b></summary>
Same shape as Cursor — it's a standard stdio MCP server:
```json
{
"mcpServers": {
"collectui": {
"command": "node",
"args": ["/path/to/collectui-mcp/dist/index.js"]
}
}
}
```
</details>
> **Path has spaces?** Quote it in shell commands (`node "/Users/me/my folder/collectui-mcp/dist/index.js"`). In JSON, no quoting needed beyond the normal string.
### 4. Use it
Restart your agent, then just talk to it normally:
> Look at https://collectui.com/designs/ui-interaction-ui-design-inspiration and build me the second one
> Analyse this and match the timing exactly: `<any collectui link>`
> Find me some dropdown animations on collectui and show me how the best one moves
Your agent calls the tools on its own. You don't need to name them.
---
## What it accepts
Give it any of these:
- A CollectUI category page — `https://collectui.com/designs/ui-interaction-ui-design-inspiration`
- A designer's page — `https://collectui.com/designers/someone`
- The trending page, or the homepage
- A CollectUI post id — `ce63a499-08b0-4782-866c-f99d0b7adc5b`
- The original X/Twitter post URL
- **Any direct image, GIF, or video URL at all** — this part works with no CollectUI involvement whatsoever
Point it at a listing and you get an index to choose from. Point it at one design and you get the full breakdown.
---
## The tools
| Tool | What it does |
|---|---|
| `get_design_context` | The main one. Link in, full design + motion brief out. |
| `browse_designs` | Search by keyword, category, designer, or feed. |
| `list_categories` | The site's 215 categories, for when you want to browse by kind. |
| `get_frames` | Pull exact frames at specific timestamps, once you know which moment matters. |
`get_design_context` takes a `detail` setting that controls cost:
| `detail` | You get | Roughly |
|---|---|---|
| `brief` | Measurements only, no images | 2.5k tokens |
| `standard` *(default)* | The above + 3 keyframes | 6k tokens |
| `full` | The above + 6 larger keyframes + a contact sheet | 12k tokens |
`brief` is genuinely enough most of the time — the timeline already tells the agent the durations, the easings, and the directions.
---
## How it works
1. **Finds the design.** CollectUI's catalogue lives behind a public read-only endpoint — the same one the website's own JavaScript calls. See [a note on that](#a-note-on-the-data-source) below.
2. **Crops away the presentation.** Designers frame their work on a big flat backdrop. That backdrop is detected and removed first. It matters more than it sounds: on one test post, skipping this step made the palette come back 94% beige, describing the *mat* instead of the *UI*.
3. **Decodes once.** Frames come out of ffmpeg as raw pixels at 64px wide, and everything is computed from that one pass. No image libraries, no temp files, no second decode.
4. **Measures the motion.** Frame-to-frame difference splits the timeline into holds and transitions. Each transition then gets:
- an 8×5 grid showing *where* the change is concentrated
- block matching to find which way things moved, and how far
- overshoot detection, which is what separates a spring from an ease
- its progress curve fitted against 14 standard easing curves, scored with R²
5. **Picks frames worth seeing.** At segment boundaries, motion peaks, and the middle of held states — never a uniform sample.
---
## Measured vs. inferred
Worth being straight about, since your agent will act on this.
**Measured from the file** — timings, dimensions, colours, contrast ratios, crop box, displacement, loop detection. These are read off the pixels.
**Inferred** — easing *names*, spring constants, and element roles. These come from curve fitting and heuristics. They're strong starting points, not ground truth.
One real limitation: displacement uses whole-frame block matching, so it reports the *dominant* movement. If three elements move in different directions at once, they average out. Every brief says so, so the agent doesn't over-trust it.
---
## A note on the data source
CollectUI has no public API. Its front-end reads from a Supabase endpoint using a read-only key that it ships to every browser that visits the site.
This project uses that same public endpoint — but it deliberately **does not** contain a copy of that key. It reads it at runtime from the live site bundle, exactly the way a browser does, and caches it locally. That way this repo never republishes someone else's credential, and nothing breaks if they rotate it.
It also caches every download, so re-analysing the same design doesn't re-fetch anything.
If CollectUI ever ships a real API, `src/api.ts` is the only file that needs to change — the analysis pipeline doesn't care where media comes from.
Please be reasonable with it. It's someone's site.
---
## Development
```bash
npm run build # compile
npm run dev # compile on change
```
Two scripts for poking at it directly:
```bash
node scripts/smoke.mjs <url-or-id> # run the full analysis, print the brief
node scripts/test-mcp.mjs # drive the server over stdio, like an agent would
```
Layout of the code:
```
src/
index.ts MCP server + the four tools
api.ts resolving CollectUI links to posts
media.ts downloading and caching
ffmpeg.ts every ffmpeg/ffprobe call
pack.ts assembles the brief you actually read
analysis/
motion.ts segmentation, easing fitting, displacement
color.ts palette extraction, contrast
layout.ts bands, matte detection, content box
```
---
## Contributing
Issues and PRs welcome. Especially interested in:
- better easing fits (spring parameter estimation is currently pretty rough)
- per-region motion tracking, so multiple elements moving at once don't average out
- text detection, so the brief can mention what the UI actually says
## License
MIT — see [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues