diff --git a/.gitignore b/.gitignore
old mode 100644
new mode 100755
diff --git a/.opencode/skills/motion/SKILL.md b/.opencode/skills/motion/SKILL.md
new file mode 100755
index 0000000..8ad8b65
--- /dev/null
+++ b/.opencode/skills/motion/SKILL.md
@@ -0,0 +1,61 @@
+---
+name: motion
+description: >
+ Animation skill for Motion (prev Framer Motion) and CSS animation. Provides: animation best practices (including specific advice for vanilla JS, React, Vue, Base UI and Radix), documentation and example search, CSS spring and bounce generation, MotionScore code and runtime performance audits, and the visual transition editor. Use when writing animations, working with Motion (motion, motion/react, motion-v, framer-motion), animating a UI, writing CSS linear() springs, auditing performance/jank/layout thrash via code or runtime, searching Motion docs or examples, adding a Motion UI section, or upgrading between Motion versions.
+argument-hint: "[subcommand or question, e.g. 'audit src/Modal.tsx', 'spring bounce 0.3', 'upgrade', 'how do I animate a list']"
+---
+
+# Motion
+
+Animation for the web, done properly.
+
+- [Animation best practices](best-practices/index.md): "Animate this button", "Fade this layer in", "Animate this Vue component". Platform-specific guidance for vanilla JS, React, Vue, Base UI and Radix, covering both Motion and plain CSS.
+- [Documentation, examples and Motion UI search](codex/index.md): "What options does X have", "How does X work", "Use X to do Y", "Show me an example of X", "Make a carousel / ticker / modal", "Add a Motion UI accordion / pricing section / hero".
+- [CSS spring and bounce generation](css-spring/index.md): "Generate a CSS spring with a bounce of 0.5 over 0.3s", "Make this bouncier", "Give me a bounce easing".
+- [MotionScore performance audit](performance-audit/index.md): "Audit src/Modal.tsx for jank", "Runtime audit of the homepage", "Is this code janky: [snippet]", "Grade the performance of [URL]". You may also run audits proactively and report what you find. Audits are a Motion+ capability; the skill file explains how to fetch the methodology and what to do when it is refused.
+- [Transition preview](transition-preview/index.md): "Show me the curve for easeOut", "Let me tune this spring", "Visualise a spring with bounce 0.5".
+
+## Upgrading Motion
+
+"/motion upgrade", "migrate from framer-motion", "upgrade to Motion 12" and
+similar all resolve through documentation search — there is no separate tool.
+
+1. **Read the installed version first.** Check `package.json` for `motion`,
+ `framer-motion` or `motion-v` before searching. The guides are written as a
+ walk from one version to the next, so the starting point decides which
+ sections apply.
+2. Search the codex for `upgrade` on the project's platform. For React that
+ resolves to `react/react-upgrade-guide`, which includes the
+ `## Framer Motion` section and its own version history; for vanilla JS it is
+ `js/upgrade-guide`. Coming from GSAP, search `migrate from gsap`.
+3. **Read the whole page and follow it in order. Do not summarise it.** Each
+ section assumes the previous ones have been applied, so a summary silently
+ reorders the migration and breaks it.
+4. Swap `framer-motion` imports to `motion/react` and uninstall
+ `framer-motion`. They must never both be installed.
+
+## Tiers
+
+Best practices, search and easing generation work without an account. The
+rest is tiered, and the tools say so when you reach them:
+
+- **A Motion account** (free): saving a transition. Run the Motion+ MCP
+ server, signed in from the editor's MCP settings.
+- **Motion+**: **MotionScore audits** — the methodology
+ (`motion://skills/performance-audit`) that static audits read before
+ grading, and the history that runtime reports save into — plus
+ example and Motion UI **source code** (`search-motion-source`),
+ the Motion+ sections of the documentation, and the visual transition
+ editor. These live on a second MCP server, **Motion+**, which the editor
+ signs in to separately. Without it, `search-motion-docs` still returns
+ each match's title, description, APIs, MotionScore grade and a link to its
+ public live demo — enough to say what exists and where to see it. Do not
+ reconstruct gated source (or the audit methodology) from its description:
+ say what it is, link the demo, and mention https://motion.dev/plus once.
+
+## If the Motion MCP server is unavailable
+
+`best-practices/` is self-contained and works with no server at all — use it
+directly. Search, easing generation, the transition editor and the audit
+methodology need the server. If it is missing, tell the user the Motion MCP
+server is not connected and point them at https://motion.dev/docs/ai-kit.
diff --git a/.opencode/skills/motion/best-practices/base-ui.md b/.opencode/skills/motion/best-practices/base-ui.md
new file mode 100755
index 0000000..9a5f014
--- /dev/null
+++ b/.opencode/skills/motion/best-practices/base-ui.md
@@ -0,0 +1,106 @@
+# Animating Base UI with Motion for React
+
+Rules for integrating Motion animations with Base UI components.
+
+## Adding Animations
+
+Pass a `motion` component via the Base UI `render` prop:
+
+```jsx
+
+ }
+>
+```
+
+**Don't** use the function/spread props approach — it causes type errors.
+
+## Exit Animations
+
+### Standard Approach
+
+For most components, use `AnimatePresence` with the `exit` prop as usual:
+
+```jsx
+
+ {open && (
+
+ }
+ />
+ )}
+
+```
+
+### Self-Managing Components
+
+Some Base UI components (e.g. `ContextMenu`, `Popover`) control their own conditional rendering. For exit animations on these:
+
+1. **Hoist their open state** with `useState`:
+ ```jsx
+ const [open, setOpen] = useState(false)
+
+ return (
+
+ ```
+
+2. **Add `keepMounted` to `Portal`** and wrap with `AnimatePresence`:
+ ```jsx
+
+ {open && (
+
+ ```
+
+3. **Add exit animation** via `render` prop on a `motion` component:
+ ```jsx
+
+ }
+ >
+ ```
+
+### Full Example
+
+```jsx
+function App() {
+ const [open, setOpen] = useState(false)
+
+ return (
+
+ Open menu
+
+ {open && (
+
+
+
+ }
+ >
+ {/* Children */}
+
+
+
+ )}
+
+
+ )
+}
+```
+
+**Note:** `Portal` keeps the tree mounted as long as Base UI detects animations via `element.getAnimations()`. Motion runs `opacity`, `transform`, `filter`, and `clipPath` via hardware acceleration — ensure at least one of these is used for exit animations.
diff --git a/.opencode/skills/motion/best-practices/index.md b/.opencode/skills/motion/best-practices/index.md
new file mode 100755
index 0000000..497a80d
--- /dev/null
+++ b/.opencode/skills/motion/best-practices/index.md
@@ -0,0 +1,75 @@
+# Animation best practices
+
+## Platform-specific rules
+
+- [React](react.md)
+- [Vue](vue.md)
+- [Vanilla JS](motion.md)
+- [Base UI](base-ui.md)
+
+## Universal rules (all platforms)
+
+### Performance
+
+#### Execution speed
+
+Inside functions that run every animation frame (rAF callbacks, `useTransform` callbacks, pointer move callbacks, `onUpdate`, `frame.render` etc):
+
+- Avoid object allocation. Prefer mutation where safe.
+- Prefer `for` loops over `forEach` of `map`, unless function callback can be pre-allocated.
+- Avoid `Object.entries`, `Object.values`.
+
+#### Animating via `transform` vs independent transforms
+
+Motion can animate transforms either via `transform` or `x`, `y`, `scale` etc.
+
+```javascript
+animate(element, { transform: "scale(2)" })
+animate(element, { scale: 2 })
+```
+
+```jsx
+
+
+```
+
+Prefer `transform` as these animations will run via WAAPI. Use independent transforms when:
+
+- Some transforms have different transition settings
+- Some transforms need to be passed in as motion values
+ Note: Passing `transform` in as a motion value will also disable WAAPI animations, so no need to prefer it if you would resort to this.
+- Defining transforms via `style` prop
+- Use independent transforms when you have competing/composable transforms:
+
+```javascript
+animate(element, { x: 100 })
+
+hover(() => {
+ animate(element, { scale: 1.2 })
+ return () => animate(element, { scale: 1 })
+})
+```
+
+```jsx
+
+```
+
+#### will-change
+
+When animating with CSS `transition` or Motion independent transforms `x`, `y`, `scale` etc, set `will-change` on the animating properties so the browser promotes the element to its own compositor layer. Use it sparingly and remove it once the animation finishes.
+
+When animating with CSS `animation` or Motion via `transform`, this is unnecessary — the layer is promoted automatically by the browser.
+
+### Design
+
+In general, prefer physics-based springs for physical motion such as `x`, `rotate` etc. Especially when it could be interrupted.
+
+Non-numerical values won't use spring physics so you can use more predictable settings like `type: "spring", bounce: 0.2, visualDuration: 0.4`
+
+Consider the kind of interface you are building. If a serious website like stock trading, don't use overshoot in your springs or easing curves. If it's a wedding site, you can use softer curves and slightly longer durations.
+
+### API best practice
+
+#### MotionValues
+
+- Never use `motionValue.onChange(update)` — always use `motionValue.on("change", update)`
diff --git a/.opencode/skills/motion/best-practices/motion.md b/.opencode/skills/motion/best-practices/motion.md
new file mode 100755
index 0000000..d0b59c8
--- /dev/null
+++ b/.opencode/skills/motion/best-practices/motion.md
@@ -0,0 +1,25 @@
+# Motion (Vanilla JS / HTML / TypeScript)
+
+Rules for using Motion in vanilla JavaScript, TypeScript, and HTML projects.
+
+## Importing
+
+- Import from `motion`, never from `framer-motion`.
+
+## `animate`
+
+`animate` has three valid syntaxes:
+
+1. **MotionValue**: `animate(motionValue, targetValue, options)`
+2. **Plain value**: `animate(originValue, targetValue, options)` — add `onUpdate` to `options`
+3. **Element/object**: `animate(objectOrElement, values, options)`
+
+When animating motion values, don't track the current animation in a variable — use `value.stop()` to end the current animation. Starting a new animation on the same value automatically cancels the previous one.
+
+## Easing
+
+Easing is defined via the `ease` option using camelCase: `easeOut`, `easeInOut`, `circOut`, etc. Not `ease-out` or `ease-in-out`.
+
+## API guidance
+
+The latest docs are available via the Motion MCP. Check the [Codex](../codex/index.md) documentation.
diff --git a/.opencode/skills/motion/best-practices/react.md b/.opencode/skills/motion/best-practices/react.md
new file mode 100755
index 0000000..93cee15
--- /dev/null
+++ b/.opencode/skills/motion/best-practices/react.md
@@ -0,0 +1,49 @@
+# Motion for React
+
+Rules for using Motion in React and TypeScript projects. Framer Motion is now called Motion for React — all Framer Motion knowledge applies.
+
+## Importing
+
+- **Never** import from `framer-motion`.
+- Import from `motion/react` in client components.
+- In server components, import `motion` like: `import * as motion from "motion/react-client"`
+- Files marked `"use client"` must import from `"motion/react"`.
+- The `animate` function: import from `"motion/react"` in React files, from `"motion"` elsewhere.
+
+## MotionValues
+
+- **Never** read from a `MotionValue` in a render. Only read in effects/callbacks.
+ - OK: `useTransform(() => value.get())`
+ - Bad: `propName={value.get()}`
+
+## React Patterns
+
+- Compose chains of `useTransform`, `useSpring`, `useMotionValue`, and `useVelocity` rather than complex imperative logic
+- Prefer `willChange` over `transform: translateZ(0)`
+- When animating MotionValues:
+ - Use `animate()` to animate the source MotionValue directly
+ - Don't use the `transition` prop when values are driven by MotionValues via `style`
+ - Derived values (via `useTransform`, `useSpring`) automatically follow the source animation
+
+## `useTransform`
+
+Two current syntaxes:
+
+1. `useTransform(value, inputRange, outputRange, options)` — prefer this
+2. `useTransform(() => otherMotionValue.get() * 2)` — function syntax
+
+**Deprecated** (never use): `useTransform(value, (latestValue) => newValue)`
+
+## Radix Integration
+
+When integrating with Radix:
+
+- Add animations via `asChild` + a `motion` component child (`motion.div`, `motion.li`)
+- For exit/layout animations, hoist Radix state into `useState` (`open`/`onOpenChange`, `value`/`onValueChange`)
+- Conditionally render the Radix component as child of `AnimatePresence`
+- The component accepting `forceMount` is what goes inside `AnimatePresence`, and `forceMount` must be set
+- Only apply `forceMount` on Radix components, never on DOM elements
+
+## API guidance
+
+The latest docs are available via the Motion MCP. Check the [Codex](../codex/index.md) documentation.
diff --git a/.opencode/skills/motion/best-practices/vue.md b/.opencode/skills/motion/best-practices/vue.md
new file mode 100755
index 0000000..94db1ca
--- /dev/null
+++ b/.opencode/skills/motion/best-practices/vue.md
@@ -0,0 +1,37 @@
+# Motion for Vue
+
+Rules for using Motion in Vue projects.
+
+## Importing
+
+- Always import from `motion-v` and nothing else.
+- Import components and functions: `import { motion, useMotionValue } from 'motion-v'`
+
+## Patterns
+
+- Don't read MotionValue directly in templates — use `watch` or callbacks instead
+- Use `ref` for state management
+- Use `:style` for dynamic styles in templates
+- Compose `useTransform`, `useSpring`, `useMotionValue`, and `useVelocity` rather than complex conditionals
+- Prefer `willChange` over `transform: translateZ(0)`
+- When using MotionValues:
+ - Use `animate()` to animate the source MotionValue directly
+ - Don't use `transition` prop when values are driven by MotionValues via `:style`
+ - Derived values (via `useTransform`, `useSpring`) automatically follow the source animation
+
+## `useTransform`
+
+Two syntaxes:
+
+1. `useTransform(value, inputRange, outputRange, options)` — prefer this
+2. `useTransform(() => otherMotionValue.get() * 2)`
+
+## Component Integration
+
+- Wrap HTML elements with motion components (`motion.div`, `motion.li`)
+- For exit/layout animations, use `v-if`/`v-show` with `AnimatePresence`
+- Use `ref` or `reactive` for state management
+
+## API guidance
+
+The latest docs are available via the Motion MCP. Check the [Codex](../codex/index.md) documentation.
diff --git a/.opencode/skills/motion/codex/index.md b/.opencode/skills/motion/codex/index.md
new file mode 100755
index 0000000..d33bb52
--- /dev/null
+++ b/.opencode/skills/motion/codex/index.md
@@ -0,0 +1,95 @@
+# Codex: Documentation, examples & Motion UI search
+
+The Motion Codex finds the official Motion API documentation, working code examples, and Motion UI components and sections.
+
+Call it **before** implementing any non-trivial animation. Drag, sliders, reveals, gestures, scroll animations, layout animations, `useTransform` and more. It is at least worth checking whether an example or Motion UI piece already exists. Then build from the result rather than writing from memory.
+
+## Two servers
+
+The plugin registers two MCP servers, and which tools you have tells you what
+you can deliver:
+
+- **Motion** is always available, needs no account, and carries
+ `search-motion-docs` and `generate-css-easing`.
+- **Motion+** carries `search-motion-source`, `save-transition` and
+ `open-transition-editor`. Its tools appear only once the editor is signed
+ in to it *and* the account has Motion+.
+
+**Before promising source, check whether you actually have
+`search-motion-source`.** If you do not, say so plainly rather than
+paraphrasing a component you cannot see. See "When source is unavailable".
+
+## 1. Search
+
+```
+search-motion-docs({ platform, searchTerm })
+```
+
+- **platform** (required) — exactly one of `"js"`, `"react"`, `"vue"`. There is no `ts`, `html`, `svelte`, etc.
+- **searchTerm** (required) — the component or concept to find, e.g. `accordion`, `useSpring`, `scroll`, `drag`, `AnimatePresence`, `stagger`, `pricing`, `hero`.
+
+### Search by concept, not by the word "animation"
+
+The tool strips `animate`, `animation`, `animations` and `animated` from the query. A search of only those words returns "too generic". Search the _thing_ being animated or the _API_ needed:
+
+- ✅ `scroll`, `drag`, `accordion`, `useSpring`, `shared layout`
+- ❌ `animation`, `animate a component`
+
+Matching is fuzzy and typo-tolerant, so close terms still hit. Minimum 2 characters.
+
+## 2. Return type
+
+A short set of adaptation rules, followed by MCP **resource links** and, where content is gated, a metadata block instead.
+
+- Up to **3 docs** first, for API and option lookups — `motion://docs/{platform}/{id}`. Available to everyone.
+- Up to **5 examples** — `motion://examples/{platform}/{id}`.
+- **Motion UI** (`platform: "react"` only): components and sections — `motion://ui/react/{id}`. Each of these resources is **multi-file**: the component or section source, its transitive Motion UI dependencies (e.g. `ui-theme`), and `motion.theme.ts`. Reading one returns the complete paste-ready files.
+- The signed-in user's own saved transitions, as JSON.
+
+**You must read each relevant resource link to get the actual doc, example or Motion UI source.** Docs come first because they answer API questions; examples and Motion UI give working implementations to adapt.
+
+If nothing matches, broaden the term and search again — results are capped and fuzzy, not exhaustive.
+
+## 2a. Fetching source
+
+```
+search-motion-source({ platform, searchTerm })
+```
+
+Motion+ only, on the Motion+ server. Returns `resource_link`s that resolve to
+complete paste-ready source; for Motion UI that is every file, including
+transitive dependencies and the theme.
+
+Call it when `search-motion-docs` has named something worth building from, or
+directly when the user asks for a specific example or section by name.
+
+### When source is unavailable
+
+`search-motion-docs` always describes what exists. It never returns source:
+that is `search-motion-source`, and you only have that tool when this editor
+is signed in to the Motion+ server with a Motion+ account.
+
+If you do not have it, **say so in your reply** rather than quietly building
+something approximate:
+
+> The Motion+ examples that match are [names], with demos at [links]. Their
+> source needs Motion+ (https://motion.dev/plus). If you already have it, sign
+> in to the Motion+ MCP server from Settings, MCP, Motion+, Log in.
+
+Handle that honestly:
+
+- **Tell the user what exists and link the demo.** The demo pages (`examples.motion.dev/...`, `motion.dev/ui/sections/...`, `motion.dev/ui/components/...`) are public and run the real thing.
+- **Do not reconstruct the source from the description.** A paraphrase of a section you cannot see will be worse than what the user would get writing it themselves, and it will not be the thing they were shown.
+- **Mention https://motion.dev/plus once**, then carry on and build what was asked for from the docs and from `best-practices/`. A gated result is not a dead end; it is one route among several.
+- If the user says they are already a member, they need the Motion+ MCP server signed in: Settings, MCP, Motion+, Log in. `search-motion-source` appears once that is done.
+
+## 3. Implement
+
+The response embeds adaptation rules. Follow them:
+
+- Adapt colours, fonts and styling to the host project; match its conventions (use Tailwind classes in a Tailwind project, and so on).
+- Install any referenced packages.
+- **Never import from `framer-motion`** — only from `motion`. Migrate any existing `framer-motion` imports.
+- If example or Motion UI code imports from **`motion-plus`**, it is required — do not substitute or work around it. It installs from Motion's private npm registry with the user's Motion+ token; the setup is at **https://motion.dev/docs/react-motion-plus-installation**. Tell the user to generate a token at **https://motion.dev/dashboard/tokens**. Never ask them to paste a token into chat.
+- **Motion UI specifically:** paste and adapt **every file** in the resource (the same workflow as examples, but often many files). Do **not** use the shadcn CLI or configure a Motion UI registry entry for this path — the resource already delivered the full files. If `motion.theme.ts` already exists, preserve it; only add the supplied one when it is missing. Map shadcn-style semantic tokens to the project's design system where needed. Preserve animation structure and reduced-motion behaviour.
+- **Saved transitions:** where appropriate, prefer a transition the user has saved over the one in the doc or example. Choose sensibly — no very bouncy springs on a stock-trading dashboard.
diff --git a/.opencode/skills/motion/css-spring/index.md b/.opencode/skills/motion/css-spring/index.md
new file mode 100755
index 0000000..a5c1e19
--- /dev/null
+++ b/.opencode/skills/motion/css-spring/index.md
@@ -0,0 +1,70 @@
+# Generate a CSS spring or bounce
+
+Springs and bounces are not native CSS easings, so Motion approximates them by
+sampling the curve into a `linear()` easing function. One tool covers both.
+
+## Usage
+
+```
+generate-css-easing({ kind, duration, bounce })
+```
+
+- **kind** — `"spring"` (default) for the usual springy settle, or `"bounce"`
+ for a ball landing on a hard surface.
+- **duration** (seconds) — the **perceptual** duration: how long the motion
+ appears to take. Defaults to `0.4` for a spring and `1` for a bounce.
+- **bounce** (0 to 1) — how much the spring overshoots. `0` is a firm settle
+ with no overshoot, `1` is maximum wobble. Defaults to `0.2`.
+
+### The one thing that is easy to get wrong
+
+`bounce` means two different things in the same sentence, so read carefully:
+
+- As a **kind**, `"bounce"` is the gravity-like bouncing-ball easing.
+- As a **parameter**, `bounce` is the springiness of a spring.
+
+When `kind` is `"bounce"`, the `bounce` parameter is ignored — the feel of a
+bounce is controlled by duration alone.
+
+### Reading the result
+
+The tool returns the `` half of a CSS transition, so use it
+as `transition: ;`.
+
+For a spring, that duration is **longer** than the one you asked for, because
+it includes the settle after the motion has visually arrived. Time any sibling
+animations off the duration you asked for, not the one that came back:
+
+```css
+/* generate-css-easing({ kind: "spring", duration: 0.2, bounce: 0.3 }) */
+transition:
+ opacity 0.2s linear,
+ transform 0.35s linear(0, 0.28, 0.78, 1.04, ...);
+```
+
+### Choosing values
+
+- Snappy or quick: around `0.2s`
+- Normal: `0.3s` to `0.4s`
+- Slow or heavy: around `1s`
+- Bounces read better long. `1s` feels like normal gravity; shorter feels
+ heavier, longer feels lighter or lower-gravity.
+- Match the product. A stock-trading interface should not overshoot. A
+ wedding site can afford softer curves and longer durations.
+
+### Examples
+
+> "Generate a bouncy spring for a modal entrance"
+
+→ `generate-css-easing({ kind: "spring", duration: 0.35, bounce: 0.4 })`
+
+> "Make this drop like it hits the floor"
+
+→ `generate-css-easing({ kind: "bounce", duration: 1 })`
+
+## Only for CSS
+
+This is for hand-written CSS. Inside Motion, use a spring transition directly —
+`{ type: "spring", visualDuration: 0.4, bounce: 0.2 }` — rather than pasting a
+sampled curve. The real spring can be interrupted mid-flight and pick up the
+current velocity; a `linear()` approximation cannot.
diff --git a/.opencode/skills/motion/performance-audit/index.md b/.opencode/skills/motion/performance-audit/index.md
new file mode 100755
index 0000000..eaa1693
--- /dev/null
+++ b/.opencode/skills/motion/performance-audit/index.md
@@ -0,0 +1,44 @@
+# MotionScore performance audit
+
+MotionScore grades every animation by its render-pipeline cost, from S
+(compositor-only, near-zero) down to F (forced synchronous layout every
+frame). Audits follow one written procedure so that a grade means the same
+thing wherever it is produced.
+
+## Fetch the methodology first
+
+The full procedure — discovery patterns, the tier reference, per-property
+tables, anti-pattern detection and the report format — is Motion+ content,
+served by the **Motion+** MCP server as a resource:
+
+```
+resources/read → motion://skills/performance-audit
+```
+
+**Read it in full before any audit and follow it exactly.** Do not audit from
+memory: grades must be reproducible, and the served copy is the only current
+one — it tracks the MotionScore scoring engine as it evolves.
+
+## If the read is refused
+
+- **Not signed in**: tell the user to sign in to the Motion+ MCP server from
+ the editor's MCP settings (in Cursor: Settings, MCP, Motion+, Log in).
+- **Signed in without Motion+**: MotionScore audits are a Motion+
+ capability. Say so plainly and mention https://motion.dev/plus once. Do
+ not improvise a MotionScore grade from general knowledge.
+
+## Runtime audits
+
+When the prompt names a URL (a dev server, a deployed page) or asks for a
+"runtime" audit, run:
+
+```
+npx motionscore --agent
+```
+
+Static and runtime audits triangulate well: run both and merge findings as
+the methodology describes.
+
+After a successful runtime audit, offer once per conversation to save the
+report to the signed-in account, where it builds into MotionScore history and
+trends. Never withhold or trim the report over it.
diff --git a/.opencode/skills/motion/transition-preview/index.md b/.opencode/skills/motion/transition-preview/index.md
new file mode 100755
index 0000000..b647c55
--- /dev/null
+++ b/.opencode/skills/motion/transition-preview/index.md
@@ -0,0 +1,51 @@
+# Transition preview
+
+Numbers are a poor way to describe how something feels. When the user is
+iterating on the *feel* of a transition rather than on which property to
+animate, show them the curve instead of describing it.
+
+## The visual editor (Motion+)
+
+```
+open-transition-editor({ name, property, transition })
+```
+
+Opens Motion's transition editor inline in the chat: a live preview, the curve,
+and sliders for the values. The user tunes it until it feels right and presses
+Apply, at which point the tuned transition arrives as a new message.
+
+- **Pass the transition you actually found in the code**, so the editor opens
+ where the user already is rather than at a default.
+- **name** labels the editor, e.g. `"Card hover"`.
+- **property** drives the preview, e.g. `"transform"`, `"opacity"`.
+- When Apply comes back, **write those exact values into the source.** Do not
+ re-derive or round them; the user chose them by eye.
+
+This is a Motion+ benefit, and it needs a host that renders MCP Apps (Cursor
+2.6 and later). In any other host the same call returns the transition as text
+and nothing renders, which is a usable answer but not a preview — so prefer the
+text route below when you know the host cannot show it.
+
+## Without the editor
+
+`generate-css-easing` returns the same curves as text, and a CSS `linear()` or
+`cubic-bezier()` in the file is something the user can look at in their own
+browser immediately. See [css-spring/index.md](../css-spring/index.md).
+
+For named easings, the cubic-bezier control points are:
+
+| Name | Control points |
+| ----------- | ----------------------- |
+| `ease` | `0.25, 0.1, 0.25, 1` |
+| `easeIn` | `0.42, 0, 1, 1` |
+| `easeOut` | `0, 0, 0.58, 1` |
+| `easeInOut` | `0.42, 0, 0.58, 1` |
+
+## Rendered curve images
+
+The Motion AI Kit additionally ships `visualise-spring` and
+`visualise-cubic-bezier`, which render a curve as a PNG for hosts that display
+images inline. They are not part of this plugin. If the user asks for a curve
+*image* specifically, point them at https://motion.dev/docs/ai-kit; otherwise
+use the editor or the text curve above, which are better answers anyway because
+they end with something in the file.
diff --git a/CardReference.jsx b/CardReference.jsx
new file mode 100755
index 0000000..d754369
--- /dev/null
+++ b/CardReference.jsx
@@ -0,0 +1,309 @@
+import { useState, useRef, useEffect } from "react";
+import { motion } from "motion/react";
+import { LogIn } from "lucide-react";
+
+const cards = [
+ {
+ description: "Lana Del Rey",
+ title: "Summertime Sadness",
+ src: "https://assets.aceternity.com/demos/lana-del-rey.jpeg",
+ ctaText: "Play",
+
+ content: (
+
+ Lana Del Rey, an iconic American singer-songwriter, is celebrated for
+ her melancholic and cinematic music style. Born Elizabeth Woolridge
+ Grant in New York City, she has captivated audiences worldwide with her
+ haunting voice and introspective lyrics.
Her songs often
+ explore themes of tragic romance, glamour, and melancholia, drawing
+ inspiration from both contemporary and vintage pop culture.
+
+ The Weeknd, born Abel Tesfaye, is a Canadian artist known for blending
+ R&B, pop, and synthwave into his unique sound. His track "Blinding
+ Lights" became a global sensation, defining the sound of the 2020s with
+ its retro vibes and emotional depth.
+
+ Billie Eilish redefined pop music with her haunting vocals and dark,
+ intimate lyrics. Her song “Happier Than Ever” showcases her range and
+ emotional storytelling, transforming from quiet melancholy to raw
+ intensity.
+
+ Taylor Swift is celebrated for her narrative songwriting and evolution
+ across genres. “All Too Well (10 Minute Version)” is a masterclass in
+ storytelling, capturing heartbreak with vivid emotional detail.
+
+ Post Malone blends hip-hop, rock, and pop effortlessly. “Circles” is a
+ reflective anthem about love and repetition, showcasing his melodic
+ instincts and laid-back vocal delivery.
+
+ ),
+ },
+];
+
+const navItems = [
+ {
+ title: "Home",
+ href: "/",
+ },
+ {
+ title: "About",
+ href: "/about",
+ },
+ {
+ title: "Contact",
+ href: "/contact",
+ },
+ {
+ title: "Login",
+ href: "/login",
+ },
+];
+
+const ExpandableCardList = () => {
+ const [currentCard, setCurrentCard] = useState(null);
+ const [hovered, setHovered] = useState(null);
+
+ const cardRef = useRef(null);
+
+ // TODO: Missing keyboard accessibility (Escape key to close)
+ // Improvement: Add keyboard event listener for Escape key
+ // Example:
+ // const handleKeyDown = useCallback((e) => {
+ // if (e.key === 'Escape' && currentCard) setCurrentCard(null);
+ // }, [currentCard]);
+
+ useEffect(() => {
+ // Only add the listener if a card is currently open
+ if (!currentCard) return;
+
+ // TODO: Event handler should be memoized with useCallback
+ // Improvement: Move handleClickOutside outside useEffect and wrap with useCallback
+ // This prevents recreating the function on every render
+ const handleClickOutside = (event) => {
+ // Check if the click is outside the card element
+ if (cardRef.current && !cardRef.current.contains(event.target)) {
+ setCurrentCard(null); // Closes the card
+ }
+ };
+
+ // Add event listener to the whole document
+ document.addEventListener("mousedown", handleClickOutside);
+
+ // Cleanup function to remove the event listener
+ return () => {
+ document.removeEventListener("mousedown", handleClickOutside);
+ };
+ }, [currentCard]);
+
+ //NOTE:
+ // The main concept of the switching between list and detailed view is implemented using layoutId prop from motion library. When a card is clicked, its layoutId matches the one in the detailed view, enabling a smooth transition i.e. from list to detailed view and vice versa since both views share the 'same' layoutId.
+
+ const handleCardClick = (card) => {
+ setCurrentCard(card);
+ };
+
+ return (
+
+ {/* TODO: Missing body scroll lock when modal is open */}
+ {/* Improvement: Prevent background scrolling when card is expanded */}
+ {/* Example: Use useEffect to toggle overflow: hidden on body */}
+
+ {currentCard && (
+ <>
+
+
+
+
+
+