From d539b450f3a664a7272dfe49e267bc82dde89235 Mon Sep 17 00:00:00 2001 From: Hunter Caron Date: Wed, 4 Feb 2026 16:35:47 +0100 Subject: [PATCH 1/5] Update icon and intro text --- plugins/code-link/public/icon.svg | 2 +- plugins/code-link/src/App.tsx | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/plugins/code-link/public/icon.svg b/plugins/code-link/public/icon.svg index 7d90705ce..0bf0ed84c 100644 --- a/plugins/code-link/public/icon.svg +++ b/plugins/code-link/public/icon.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/plugins/code-link/src/App.tsx b/plugins/code-link/src/App.tsx index 1999bf7c2..23f1dacee 100644 --- a/plugins/code-link/src/App.tsx +++ b/plugins/code-link/src/App.tsx @@ -416,14 +416,18 @@ function InfoPanel({ command }: InfoPanelProps) {
- - - - - + + +
-

Code Link

+

Connect to Terminal

Run the command locally in your terminal to get started.{" "} Date: Fri, 6 Feb 2026 15:27:06 +0100 Subject: [PATCH 2/5] Cleanup copy --- packages/code-link-cli/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/code-link-cli/src/index.ts b/packages/code-link-cli/src/index.ts index 6780e0746..5c85f0c45 100644 --- a/packages/code-link-cli/src/index.ts +++ b/packages/code-link-cli/src/index.ts @@ -57,7 +57,7 @@ program if (detected) { projectHash = detected } else { - console.error("No project ID provided and no existing code-link directory found.") + console.error("No Project ID provided and no existing Code Link directory found.") console.error("Copy the command from the Code Link Plugin to get started.") process.exit(1) } From 81492ecbc924260e5bae9db4786fad8340aff558 Mon Sep 17 00:00:00 2001 From: Hunter Caron Date: Fri, 6 Feb 2026 16:01:55 +0100 Subject: [PATCH 3/5] Remove full project hash persistence --- packages/code-link-cli/src/utils/project.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/code-link-cli/src/utils/project.ts b/packages/code-link-cli/src/utils/project.ts index 24e5196c0..f343c08a3 100644 --- a/packages/code-link-cli/src/utils/project.ts +++ b/packages/code-link-cli/src/utils/project.ts @@ -4,7 +4,6 @@ import path from "path" interface PackageJson { shortProjectHash?: string // derived short id (8 chars base58) - framerProjectHash?: string // full 64-char hex hash from Framer API framerProjectName?: string name?: string version?: string @@ -31,7 +30,6 @@ export async function getProjectHashFromCwd(): Promise { const packageJsonPath = path.join(process.cwd(), "package.json") const content = await fs.readFile(packageJsonPath, "utf-8") const pkg = JSON.parse(content) as PackageJson - // Return short id for port derivation return pkg.shortProjectHash ?? null } catch { return null @@ -70,7 +68,6 @@ export async function findOrCreateProjectDir( version: "1.0.0", private: true, shortProjectHash: shortId, - framerProjectHash: projectHash, framerProjectName: projectName, } await fs.writeFile(path.join(projectDir, "package.json"), JSON.stringify(pkg, null, 2)) From 6f32fcd0aa0100d559b1ff70e642a3fa3e399189 Mon Sep 17 00:00:00 2001 From: Hunter Caron Date: Fri, 6 Feb 2026 16:42:08 +0100 Subject: [PATCH 4/5] Add skills --- packages/code-link-cli/package.json | 3 +- packages/code-link-cli/skills/SKILL.md | 133 +++ .../skills/references/EXAMPLES.md | 869 ++++++++++++++++++ .../skills/references/PROPERTY_CONTROLS.md | 715 ++++++++++++++ .../references/PROPERTY_CONTROL_GUIDE.md | 332 +++++++ .../references/PROPERTY_CONTROL_TYPES.md | 488 ++++++++++ .../code-link-cli/src/helpers/installer.ts | 7 + .../code-link-cli/src/helpers/skills.test.ts | 90 ++ packages/code-link-cli/src/helpers/skills.ts | 141 +++ packages/code-link-cli/src/skills/SKILL.md | 137 +++ 10 files changed, 2914 insertions(+), 1 deletion(-) create mode 100644 packages/code-link-cli/skills/SKILL.md create mode 100644 packages/code-link-cli/skills/references/EXAMPLES.md create mode 100644 packages/code-link-cli/skills/references/PROPERTY_CONTROLS.md create mode 100644 packages/code-link-cli/skills/references/PROPERTY_CONTROL_GUIDE.md create mode 100644 packages/code-link-cli/skills/references/PROPERTY_CONTROL_TYPES.md create mode 100644 packages/code-link-cli/src/helpers/skills.test.ts create mode 100644 packages/code-link-cli/src/helpers/skills.ts create mode 100644 packages/code-link-cli/src/skills/SKILL.md diff --git a/packages/code-link-cli/package.json b/packages/code-link-cli/package.json index 4ef5ad6c3..ce92fb316 100644 --- a/packages/code-link-cli/package.json +++ b/packages/code-link-cli/package.json @@ -6,7 +6,8 @@ "type": "module", "bin": "./dist/index.mjs", "files": [ - "dist" + "dist", + "skills" ], "scripts": { "dev": "NODE_ENV=development tsx src/index.ts", diff --git a/packages/code-link-cli/skills/SKILL.md b/packages/code-link-cli/skills/SKILL.md new file mode 100644 index 000000000..fad7488c8 --- /dev/null +++ b/packages/code-link-cli/skills/SKILL.md @@ -0,0 +1,133 @@ +--- +name: framer-component-best-practices +description: Best practices for building and improving React code components in Framer, a no-code website builder. Covers property controls, animations, accessibility, and platform constraints. Use when creating, editing, or reviewing Framer components, working with ControlType property controls, or building React components for Framer projects. +license: MIT +metadata: + author: framer + version: "1.0" +--- + +# Framer Component Best Practices + +Best practices for building and improving React components in Framer with property controls, animations, and accessibility. + +## Core Rules + +### Component Structure + +```tsx +import { addPropertyControls, ControlType } from "framer"; +import { motion } from "framer-motion"; // NOT from "framer" + +interface MyComponentProps { + /* typed props */ +} + +/** + * @framerSupportedLayoutWidth any-prefer-fixed + * @framerSupportedLayoutHeight any-prefer-fixed + */ +export default function MyComponent(props: MyComponentProps) { + // component +} + +addPropertyControls(MyComponent, { + /* controls */ +}); +``` + +### Platform Constraints + +These will cause errors if violated: + +1. **Single file, default export** - Use named `function` syntax (not arrow functions), no named exports +2. **Imports** - Only `react`, `react-dom`, `framer`, `framer-motion`. Import `motion` from `"framer-motion"`, not `"framer"` +3. **Position** - Use `position: relative` on the root element, never `fixed` +4. **SSR** - Guard `window`/`document` access: `if (typeof window !== "undefined")` +5. **Annotations** - Include `@framerSupportedLayoutWidth/Height` in a `/** */` block comment immediately above the component function +6. **Types** - Provide a typed props interface (e.g. `MyComponentProps`). Avoid NodeJS types like `Timeout` — use `number` instead + +### Layout Annotations + +| Content | Width | Height | +| ----------------- | ------------------ | ------------------ | +| No intrinsic size | `fixed` | `fixed` | +| Text/auto-sizing | `auto` | `auto` | +| Flexible | `any-prefer-fixed` | `any-prefer-fixed` | + +Detect auto vs fixed sizing: check if `style.width` or `style.height` is `"100%"`. + +### Property Controls + +To make components configurable in Framer's properties panel, add property controls: + +- To make colors customizable, use `ControlType.Color`. Reuse the same prop for elements sharing a color. +- To make text styling customizable, use `ControlType.Font` with `controls: "extended"` and `defaultFontType: "sans-serif"`. +- For images, use `ControlType.ResponsiveImage`. Set defaults in the component body via destructuring (the control doesn't support `defaultValue`). +- Provide a `defaultValue` for every prop so components render correctly in the Framer canvas. Include at least one item in `ControlType.Array` controls. +- `ComponentName.defaultProps` is not supported in Framer — use `defaultValue` on the property control instead. +- Use `hidden` for conditional visibility: `hidden: (props) => !props.showFeature` +- Prefer sliders over steppers unless step values are large. +- Keep controls focused — make key elements configurable, hardcode the rest. +- See [Property Control Guide](references/PROPERTY_CONTROL_GUIDE.md) for detailed patterns, font styling rules, and recommended default values. + +### Image Defaults (in component body) + +```tsx +const { + image = { + src: "https://framerusercontent.com/images/GfGkADagM4KEibNcIiRUWlfrR0.jpg", + alt: "Default", + }, +} = props; +``` + +### Animation Performance + +```tsx +import { useIsStaticRenderer } from "framer"; +import { useInView } from "framer-motion"; + +const isStatic = useIsStaticRenderer(); +const ref = useRef(null); +const isInView = useInView(ref); + +if (isStatic) return ; // Show useful static state +// Pause animations when out of viewport +``` + +- For very complex animations, consider WebGL instead of `framer-motion`. +- Static preview should include visual effects, not just text. +- Wrapping state updates in `startTransition()` prevents UI blocking and keeps interactions smooth. + +### Text + +- For auto-sized components with text, apply `width: max-content` or `minWidth: max-content` to prevent text from collapsing. + +### Common Errors + +- WebGL cross-origin: handle `SecurityError: Failed to execute 'texImage2D'` for cross-origin images. +- Inverted Y-axis: check if WebGL images render upside down and accommodate. + +### Accessibility + +- `aria` roles on interactive elements +- Semantic HTML (`