figma-lens: Benutzerschnittstellen bauen, die zu Figma passen
figma-lens ist ein Figma-Plugin plus eine lokale Brücke. Der Benutzer wählt Frames in Figma Desktop aus und klickt auf Export to Claude. Die Brücke schreibt einen Ordner pro Frame:
design/
INDEX.md ← Liste aller exportierten Frames (hier starten)
<frame>/
spec.md ← ZUERST LESEN: kompakte Layer-Struktur mit genauen Werten
spec.json ← vollständige Daten (+ pro-Layer CSS von Figma) wenn spec.md nicht ausreicht
tokens.json ← Variablen (alle Modi), Stile, Nutzungszahlen von Rohwerten
[email protected] ← vollständige Darstellung (standardmäßig 2x)
sections/NN-name.png← Ausschnitte der obersten Blöcke in voller Auflösung
assets/*.svg ← Icons/Vektorgrafiken, einsatzbereit
images/* ← Original-Bitmaps, die als Bildfüllungen verwendet werden
compare/ ← geschrieben von `figma-lens check` (report.md, side-by-side.png, diff.png)
figma-lens.map.json ← (Projektwurzel) Figma-Komponente/Token → echter Code in diesem Projekt
Der Befehl figma-lens ist das CLI aus dem figma-lens-Repository (npm link dort macht es global verfügbar; ansonsten führen Sie node <figma-lens>/bin/figma-lens.js … aus). Führen Sie figma-lens help für alle Befehle aus.
Wenn es noch keinen Export gibt
- Starten Sie die Brücke für das Projekt des Benutzers und lassen Sie sie (im Hintergrund) laufen:
figma-lens bridge --out <projekt>/design. - Bitten Sie den Benutzer, den/die Frame(s) in Figma Desktop auszuwählen → Plugins → Entwicklung → Figma Lens → Export to Claude.
- Lesen Sie
design/INDEX.md, um zu bestätigen, dass sie angekommen sind.
Raten Sie nie ein Design aus einer Beschreibung, wenn ein Export möglich ist. Fragen Sie nach dem Export.
Arbeitsablauf
- Lesen Sie
spec.mdvollständig (es ist klein). Notieren Sie sich die Framegröße, die Layout-Struktur, die Variablen und Stile sowie die Assets. - Betrachten Sie die Bilder. Lesen Sie
sections/*.pngnacheinander für Details. Verwenden Sie[email protected]nur für das Gesamtbild, da große Bilder beim Anzeigen verkleinert werden. Werte stammen immer aus der Spezifikation, niemals durch Messen von Pixeln. - Verwenden Sie die Komponentenkarte (siehe „Komponentenkarte" unten). Jedes
⇒ USE …in spec.md ist verbindlich: verwenden Sie dieses Widget/Komponente und seine Eigenschaftszuordnung sowie zugeordnete Token ((color/primary ⇒ AppColors.primary)) anstelle von Rohwerten. Für Elemente, die als(not in map)markiert sind, durchsuchen Sie die Codebasis nach dem vorhandenen Theme und den vorhandenen Widgets (FlutterThemeData,AppColors,TextTheme, Abstandskonstanten,lib/widgets; Web CSS-Variablen, Tailwind-Konfiguration,src/components). Verwenden Sie Rohwerte nur, wenn kein Token existiert, und teilen Sie dem Benutzer mit, welche Sie hinzugefügt haben. - Wiederverwenden von Komponenten. Ein Layer, der als
component Button {Type=Primary}markiert ist, sollte das vorhandene Button-Widget oder die vorhandene Komponente des Projekts mit passenden Eigenschaften verwenden. Bauen Sie eine neue nur, wenn keine existiert, machen Sie sie wiederverwendbar und fügen Sie sie der Karte hinzu. - Bauen Sie von oben nach unten, folgen Sie der Struktur. Automatisches Layout wird auf Row/Column/flex abgebildet (Tabellen unten). Nur
@x,y-Layer (kein automatisches Layout oderabsolute) benötigen Stack/Positioned oder absolute Positionierung. - Verwenden Sie die exportierten Dateien. Legen Sie
assets/*.svgundimages/*in den Asset-Ordner des Projekts und referenzieren Sie sie. Zeichnen Sie niemals Icons neu und ersetzen Sie niemals ein Icon-Set durch ein anderes. - Kopieren Sie Text genau aus
"…"in spec.md, einschließlich Groß-/Kleinschreibung, Interpunktion und arabischen/RTL-Strings. Text mit mehrerenrun-Zeilen benötigt Rich-Text (TextSpan / verschachtelte Spans). - Überprüfen Sie mit der Vergleichs- und Korrekturschleife (unten). Erklären Sie einen Bildschirm nicht als fertig, indem Sie den Code lesen; beweisen Sie es mit einem Screenshot-Diff.
Vergleichs- und Korrekturschleife
Nachdem Sie einen Bildschirm gebaut haben, vergleichen Sie das tatsächliche Ergebnis mit Figma und korrigieren Sie, was abweicht:
- Führen Sie den Build aus, der diesen Bildschirm anzeigt:
- Web: Starten Sie den Dev-Server und öffnen Sie die Route.
- Flutter web:
flutter run -d web-server --web-port 8080, dann verwenden Sie diese URL. - Flutter Android: Führen Sie die App auf einem Emulator/Gerät aus und navigieren Sie zum Bildschirm.
- Überprüfen Sie ihn:
- Web / Flutter web:
figma-lens check --design design/<frame> --url http://localhost:<port>/<route>(der Viewport wird automatisch auf die Größe des Frames und den Maßstab eingestellt). - Android:
figma-lens check --design design/<frame> --adb --crop-top <statusleiste px> [--crop-bottom <nav-bar px>](Statusleiste ≈ 24–48 dp × Gerätedichte; zuschneiden, sodass nur der App-Inhalt verglichen wird).
- Web / Flutter web:
- Lesen Sie
design/<frame>/compare/report.md(Abweichung in %, die größten unterschiedlichen Bereiche und die Figma-Layer-IDs in jedem) und sehen Sie sichcompare/side-by-side.pngan (Figma | Build | Diff, rot = unterschiedlich). - Korrigieren Sie von oben nach unten: zuerst Höhen- oder Abstandsunterschiede (sie verschieben alles darunter), dann Größen, Farben, Typografie, Radien, Schatten. Schlagen Sie jede aufgeführte Layer-ID in spec.md nach, um die genauen Werte zu erhalten.
- Führen Sie die Prüfung erneut aus. Der Bericht zeigt den vorherigen Score, sodass Sie den Fortschritt sehen können.
- Stoppen Sie, wenn die Abweichung ≤ 3% beträgt (Text-Anti-Aliasing erreicht nie 0) oder wenn zwei aufeinanderfolgende Läufe keine Verbesserung mehr zeigen. Melden Sie dann den endgültigen Score und alles, was Sie nicht angleichen konnten, sowie den Grund (fehlende Schriftart, plattformbedingtes Rendering, dynamische Daten).
Regeln: Korrigieren Sie den echten Code, manipulieren Sie niemals den Diff (keine Screenshots oder Bilder des Designs innerhalb der App). Verwenden Sie beim Überprüfen dieselben Daten/denselben Text wie das Design (ggf. Mock-Daten), sonst dominieren Textunterschiede den Score.
Komponentenkarte
figma-lens.map.json (Projektwurzel) bildet Figma-Komponenten und -Token auf den Code dieses Projekts ab:
{
"components": {
"Button": { "flutter": "lib/widgets/app_button.dart#AppButton", "web": "src/components/Button.tsx#Button", "props": { "Label": "label", "Type": "variant" } },
"Icon/*": "SvgPicture.asset('assets/icons/<name>.svg')"
},
"tokens": { "color/primary": { "flutter": "AppColors.primary", "web": "var(--color-primary)" } }
}
- Noch keine Karte vorhanden → führen Sie
figma-lens map --design designaus. Es fügt jede Komponente und jeden Token aus den Exporten mit leeren Werten ("") hinzu. - Füllen Sie sie selbst aus: Durchsuchen Sie die Codebasis nach jeder Komponente (nach Namen, Aussehen, Eigenschaften) und jedem Token-Wert; schreiben Sie
path#Symbol(oder einen Ausdruck). Lassen Sie""nur, wenn noch nichts existiert."Prefix/*"trifft auf eine ganze Familie zu (Icons). - Nachdem Sie die Karte bearbeitet haben, führen Sie
figma-lens render design/<frame>aus, damit spec.md die⇒ USE-Pfeile anzeigt. Die Brücke wendet die Karte auch bei jedem neuen Export an. - Wenn Sie ein neues wiederverwendbares Widget für eine nicht zugeordnete Komponente erstellen, fügen Sie es der Karte hinzu.
Lesen von spec.md
- Einheiten sind Design-Pixel, die CSS-Pixel und Flutter-logischen Pixeln entsprechen. Multiplizieren Sie niemals mit dem Screenshot-Maßstab.
row|column gap G pad t,r,b,l main:X cross:Yist automatisches Layout.pad 16bedeutet, dass alle vier Seiten 16 sind.gap autobedeutet space-between.w:FILL h:HUGgibt die Größenanpassung auf jeder Achse an: FIXED (angezeigte genaue Größe), HUG (Inhalt umschließen) oder FILL (verfügbaren Platz einnehmen).@x,yist die Position innerhalb des Elternelements.absolutebedeutet ein absolut positioniertes Kind innerhalb eines automatischen Layouts.pin H/Vgibt Randbedingungen an (MIN = links/oben, MAX = rechts/unten, STRETCH = beide, CENTER, SCALE).bg A + Blistet Farben von unten nach oben auf.(name)ist eine Figma-Variable und[style name]ist ein Figma-Stil.- Farben sind
#RRGGBBoder#RRGGBBAA(Alpha am Ende). - Text verwendet das Format
"Zeichen" · Familie Stil (Gewicht) Größe/ZeilenHöhe Farbe. ZeilenHöhe ist px, % oder auto.lsist der Buchstabenabstand in px oder in % der Schriftgröße. radius 12setzt jede Ecke.radius tl,tr,br,blsetzt jede Ecke einzeln.smoothingist abgerundete Ecken im iOS-Stil; approximieren Sie es, oder ignorieren Sie es in Flutter, es sei denn, ein Squircle-Paket wird verwendet.drop-shadow x,y blur B spread S color,inner-shadow,layer-blur R,background-blur R.→ assets/x.svgbedeutet, dass der Layer ein Icon ist. Verwenden Sie das SVG in der angegebenen Größe.vars{itemSpacing=space/md}bedeutet, dass die Layereigenschaft an diese Variable gebunden ist. Verwenden Sie den Token.
Flutter-Zuordnung
| Figma | Flutter |
|---|---|
| column / row | Column / Row (verwenden Sie spacing: G auf Flutter ≥ 3.27, sonst SizedBox-Lücken) |
| wrap, rowGap R | Wrap(spacing: G, runSpacing: R) |
| pad t,r,b,l | Padding(padding: EdgeInsets.fromLTRB(l, t, r, b)). Achten Sie auf die Reihenfolge. |
| main MIN / CENTER / MAX / SPACE_BETWEEN | MainAxisAlignment.start / center / end / spaceBetween |
| cross MIN / CENTER / MAX / BASELINE | CrossAxisAlignment.start / center / end / baseline (baseline benötigt textBaseline) |
| HUG auf Hauptachse | mainAxisSize: MainAxisSize.min |
| FILL auf Hauptachse des Elternteils | Expanded (oder Flexible); grow N setzt flex: N |
| FILL auf Querachse des Elternteils | CrossAxisAlignment.stretch auf dem Elternteil, oder SizedBox(width: double.infinity) |
| FIXED w×h | SizedBox(width: w, height: h) |
@x,y / absolute | Stack + Positioned(left: x, top: y); verwenden Sie pin für rechts/unten |
| bg solid | BoxDecoration(color: Color(0xAARRGGBB)). Verschieben Sie Alpha nach vorne: #11223380 → 0x80112233. |
| gradient-linear von/nach | LinearGradient(begin: Alignment(fx*2-1, fy*2-1), end: Alignment(tx*2-1, ty*2-1), colors, stops) unter Verwendung von from/to in spec.json |
| radius | BorderRadius.circular(r) oder BorderRadius.only(...) |
| border W color inside | Border.all(width: W, color: …) (inside ist Flutters Standard; center/outside benötigen strokeAlign) |
| drop-shadow x,y blur B spread S | BoxShadow(offset: Offset(x, y), blurRadius: B, spreadRadius: S, color: …) |
| background-blur R | ClipRRect + BackdropFilter(filter: ImageFilter.blur(sigmaX: R/2, sigmaY: R/2)) |
| opacity | Opacity (oder Farb-Alpha für Farben) |
| text size/lineHeight | TextStyle(fontSize: size, height: lineHeight / size). Für %: height: pct/100. Setzen Sie leadingDistribution: TextLeadingDistribution.even, um Figmas vertikaler Zentrierung zu entsprechen. |
| weight 600 | FontWeight.w600 |
| ls px / ls % | letterSpacing: px / letterSpacing: size * pct / 100 |
| ellipsis maxLines N | maxLines: N, overflow: TextOverflow.ellipsis |
| align CENTER | textAlign: TextAlign.center. Verwenden Sie für RTL-Bildschirme TextAlign.start und EdgeInsetsDirectional. |
| assets/x.svg | SvgPicture.asset('assets/…/x.svg', width:, height:) (flutter_svg) |
| image fill FILL / FIT | Image.asset(fit: BoxFit.cover / BoxFit.contain) |
Web (CSS / Tailwind / React)-Zuordnung
| Figma | CSS |
|---|---|
| column / row | display:flex; flex-direction: column / row; gap: Gpx |
| wrap, rowGap R | flex-wrap: wrap; column-gap: G; row-gap: R |
| pad t,r,b,l | padding: t r b l (gleiche Reihenfolge wie CSS) |
| main MIN / CENTER / MAX / SPACE_BETWEEN | justify-content: flex-start / center / flex-end / space-between |
| cross MIN / CENTER / MAX / BASELINE | align-items: flex-start / center / flex-end / baseline |
| HUG | width/height: fit-content (oder einfach auto) |
| FILL (Hauptachse) | flex: 1 1 0; min-width: 0 |
| FILL (Querachse) | align-self: stretch |
| FIXED | width: Wpx; height: Hpx; flex-shrink: 0 |
@x,y / absolute | parent position: relative; child position:absolute; left:x; top:y (verwenden Sie pin für rechts/unten) |
colors #RRGGBBAA | gültiges CSS wie es ist |
gradient-linear Ndeg | linear-gradient(Ndeg, c1 p1%, c2 p2%) |
| drop-shadow | box-shadow: x y B S color (inner-shadow fügt inset hinzu) |
| layer-blur / background-blur R | filter: blur(R/2 px) / backdrop-filter: blur(R/2 px) |
| text | font: weight size/lineHeight family; letter-spacing (ls % → pct/100 em) |
| ellipsis maxLines N | display:-webkit-box; -webkit-line-clamp:N; -webkit-box-orient:vertical; overflow:hidden |
| assets/x.svg | <img src> oder inline SVG; behalten Sie die exportierte Größe bei |
spec.json enthält auch das von Figma generierte CSS (css) für die meisten Layer. Verwenden Sie es, um die CSS-Werte gegenzuprüfen; Token und Layout-Struktur stammen immer noch aus der obigen Struktur.
Regeln
- Spezifikationswerte haben Vorrang vor dem, was Sie im Bild sehen. Bei Konflikten vertrauen Sie der Spezifikation und erwähnen Sie den Konflikt.
- Runden oder „verbessern" Sie keine Werte (14 bleibt 14, nicht 16), es sei denn, der Benutzer fordert eine Normalisierung auf Token an.
- Ausgeblendete Layer werden nicht exportiert. Erfinden Sie keine Zustände (Hover, Fehler, leer), die nicht im Export enthalten sind; fragen Sie nach diesen Frames.
- Melden Sie fehlende Schriftarten. Wenn die Schriftfamilie nicht im Projekt gebündelt ist, sagen Sie dies und teilen Sie dem Benutzer mit, was hinzugefügt werden muss (pubspec fonts / @font-face).
- Fragen Sie für mehrere Breakpoints oder Zustände den Benutzer, jeden Frame zu exportieren. Jeder wird zu einem eigenen Ordner.