Commit c9156602 authored by Irun's avatar Irun
Browse files

Added position and size info to content.md, changed default agent for improvement.

parent c9b4db6b
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -68,14 +68,15 @@ export function collectImageAssets(rootNode) {
    const w = bb?.width || 0;
    const h = bb?.height || 0;

    if (w >= 40 && h >= 40 && node.id && !seenById.has(node.id)) {
    if (w >= 10 && h >= 10 && node.id && !seenById.has(node.id)) {
      const hasImageFill = node.fills?.some(
        (f) => f.type === "IMAGE" && f.visible !== false
      );
      const matchesNamePattern =
        node.name && /logo|icon|svg|image|img|photo|illustration/i.test(node.name);
      const isEmptyGroup = node.type === "GROUP" && (!node.children || node.children.length === 0);

      if (hasImageFill || matchesNamePattern) {
      if (hasImageFill || matchesNamePattern || isEmptyGroup) {
        seenById.add(node.id);
        assets.push({ id: node.id, name: node.name || "image", width: w, height: h, y: bb?.y || 0 });
      }
+27 −2
Original line number Diff line number Diff line
@@ -23,6 +23,13 @@ const OUT_DIR = path.join(BASE_PATH, 'output');

fs.mkdirSync(OUT_DIR, { recursive: true });

function ensureGitignoreEntry() {
  const gitignorePath = path.join(BASE_PATH, '.gitignore');
  const content = '*\n!.gitignore\n';

  fs.writeFileSync(gitignorePath, content);
}

const config = {
  allowPositionals: true,
  options: {
@@ -44,6 +51,15 @@ function loadSessionCode() {
  return null;
}

function posInfo(absBB, refX, refY, extra = {}) {
  const x = Math.round((absBB?.x || 0) - refX);
  const y = Math.round((absBB?.y || 0) - refY);
  const w = Math.round(absBB?.width || 0);
  const h = Math.round(absBB?.height || 0);
  const extraStr = Object.entries(extra).map(([k, v]) => `, ${k}: ${v}`).join("");
  return `{x: ${x}, y: ${y}, w: ${w}, h: ${h}${extraStr}}`;
}

async function main() {
  const channel = loadSessionCode();
  if (!channel) {
@@ -51,6 +67,8 @@ async function main() {
    process.exit(1);
  }

  ensureGitignoreEntry();

  const globalTimer = setTimeout(() => {
    console.error("Script timed out after 10 minutes");
    process.exit(1);
@@ -244,7 +262,7 @@ async function main() {
    console.log("Saved design-tokens.json");

    // 9. content.md
    const lines = [`# ${document.name}`, "", `![Full page overview](page.png)`, ""];
    const lines = [`# ${document.name}`, "", `{w: ${Math.round(bb.width || 0)}, h: ${Math.round(bb.height || 0)}}`, `![Full page overview](page.png)`, ""];

    if (visibleSections.length === 0) {
      lines.push("---", "");
@@ -253,14 +271,18 @@ async function main() {
          (a.absoluteBoundingBox.y || 0) - (b.absoluteBoundingBox.y || 0) ||
          (a.absoluteBoundingBox.x || 0) - (b.absoluteBoundingBox.x || 0)
      )) {
        lines.push(posInfo(t.absoluteBoundingBox, rootX, rootY, { fontSize: t.style?.fontSize || 16 }));
        lines.push(`${getFontSizeLevel(t.style?.fontSize || 16)}${t.characters}`, "");
      }
    } else {
      for (const section of visibleSections) {
        const sectionFilename = sectionFilenameMap.get(section.node.id);
        const sectionW = Math.round(section.node.absoluteBoundingBox?.width || 0);
        const sectionH = Math.round(section.node.absoluteBoundingBox?.height || 0);
        lines.push("---", "", `## Section ${section.index}: ${section.name}`);
        lines.push(`![Section ${section.index}](sections/${sectionFilename})`, "");
        lines.push(`{w: ${sectionW}, h: ${sectionH}}`, `![Section ${section.index}](sections/${sectionFilename})`, "");

        const sectionX = section.node.absoluteBoundingBox?.x || 0;
        const sectionY = section.node.absoluteBoundingBox?.y || 0;
        const sectionBottom = sectionY + (section.node.absoluteBoundingBox?.height || 0);
        const sectionTexts = textBySections.get(section.index) || [];
@@ -283,12 +305,15 @@ async function main() {
        for (const item of items) {
          if (item.type === "text") {
            const t = item.data;
            lines.push(posInfo(t.absoluteBoundingBox, sectionX, sectionY, { fontSize: t.style?.fontSize || 16 }));
            lines.push(`${getFontSizeLevel(t.style?.fontSize || 16)}${t.characters}`, "");
          } else if (item.type === "asset") {
            const a = item.data;
            lines.push(posInfo({ x: a.x, y: a.y, width: a.width, height: a.height }, sectionX, sectionY));
            lines.push(`![${a.name}](assets/${assetFilenames.get(a.id)})`, "");
          } else {
            const f = item.data;
            lines.push(posInfo(f.node.absoluteBoundingBox, sectionX, sectionY));
            lines.push(`![${f.node.name}](sections/${floatingFilenameMap.get(f.node.id)})`, "");
          }
        }
+3 −3
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@ Implement a page from a Figma export in `.figma-to-code/output/`.

## What to read

1. `.figma-to-code/output/$ARGUMENTS/content.md` — the source of truth. Sections in order, text content, image references.
1. `.figma-to-code/output/$ARGUMENTS/content.md` — the source of truth. Sections in order, text content, image references, sizes and positions (relative to each section).
2. `.figma-to-code/output/$ARGUMENTS/design-tokens.json` — colors and font sizes used on this page.
3. Read only the `page.png` referenced in the `content.md` to get the general idea. Let the subagents read and manage the screenshot and assets of each section separately.

@@ -24,7 +24,7 @@ Note: If the user explicitly wants a responsive design, try to get and use the e
- Collect important information about the project for the design implementation.
- Determine the correct route file for this page from the existing routes in.
- Implement section by section, top to bottom, following content.md order, one by one.
- For each section spawn an agent from `agents/section-implementer.md` and give it:
- For each section spawn a subagent from `agents/section-implementer.md` and give it:
  - Guidelines from the project to help it write a code that matches the project's standards
  - The `content.md` and the specific line range for that section.
  - The `design-tokens.json`
@@ -39,4 +39,4 @@ Note: If the user explicitly wants a responsive design, try to get and use the e
## Afterwards

- Ask the user to inspect the result. Some times hidden elements in the design get included in the data, and should be removed manually.
- If explicitly told to, continue with `/improve-design-implementation.md`, otherwise, offer to do that
- If explicitly told to, continue with `improve` skill, otherwise, offer to do that
+4 −4
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
description: For improving the implementation of an extracted Figma page design.
argument-hint: Page name
disable-model-invocation: true
model: haiku
model: sonnet
---

Improve the implementation of a page from a Figma export in `.figma-to-code/output/` to better match the design.
@@ -13,7 +13,7 @@ Improve the implementation of a page from a Figma export in `.figma-to-code/outp

## What to read

1. `.figma-to-code/output/$ARGUMENTS/content.md` — the source of truth. Sections in order, text content, image references.
1. `.figma-to-code/output/$ARGUMENTS/content.md` — the source of truth. Sections in order, text content, image references, sizes and positions (relative to each section).
2. `.figma-to-code/output/$ARGUMENTS/design-tokens.json` — colors and font sizes used on this page.
3. The images referenced in content.md — view each one before coding the section that uses it.

@@ -24,11 +24,11 @@ Note: If the user explicitly wants a responsive design, try to get and use the e
- Collect important information about the project for the design implementation.
- Determine the correct route file for this page from the existing routes in.
- Use Playwright MCP to get the page snapshot.
  - Use `browser_resize` to match the design screenshot width.
  - Use `browser_resize` to match the design screenshot width. This is important to get accurate screenshots later.
  - Use `browser_navigate` to get to the page.
  - Note: Sometimes the user need to manually close the browser. In such case, inform them rather than retrying over and over.
  - Use `browser_snapshot` with set depth (should be around 3) to get the refs of the sections.
- For each section spawn an agent from `agents/section-improver.md` and give it:
- For each section spawn a subagent from `agents/section-improver.md` and give it:
  - Guidelines from the project to help it write a code that matches the project's standards
  - The section's ref from the Playwright snapshot
  - The `content.md` and the specific line range for that section.
+1 −1
Original line number Diff line number Diff line
---
name: section-implementer
description: FE developer that focuses on implementing a section of a page
model: haiku
model: sonnet
maxTurns: 40
color: blue
---