跪拜 Guibai
← Back to the summary

Scaling from 18 to 553 Custom Widget Logos with an AI-Driven Engineering Pipeline

When AI Meets Flutter | Crafting 500+ Widget-Specific Logos

Preface

Open the widget list in FlutterUnit, and every widget has its own "business card":

These graphics are not generic icons pulled from some icon library; they are 553 SVG logos designed specifically for the semantics of Flutter widgets.

Before this work was completed, FlutterUnit's database already contained 553 widgets, but only 18 had custom logos integrated into the app, a coverage rate of just 3.25%. The remaining widgets shared a single Widget.svg as a default image. Now, all 553 database widgets have valid SVGs and are fully integrated into the runtime mapping, achieving 100% coverage.

Going from 18 to 553, AI helped us solve more than just "drawing faster." It transformed a seemingly repetitive art task into an engineering system capable of understanding, producing, integrating, and verifying.


I. This Was Not a Simple Batch Image Export

The most obvious solution is to feed the 553 widget names into an image generation model and batch export 553 images. But this approach quickly runs into problems:

Therefore, this work did not treat AI as a "name in, image out" machine. We involved AI in five stages: understanding the widget, establishing a specification, writing SVG, integrating into the project, and automated verification.


Step 1: Understand the Widget First, Then Decide What to Draw

The core of a logo is not to be pretty, but to help users build a cognitive model of the widget.

Before designing, the AI needed to combine the widget name, Flutter semantics, demo code, and sibling widgets to determine the most expressive capability. Ultimately, we categorized the expression methods into three types:

  1. Real Control Miniature: Suitable for widgets with stable appearances like Card, Chip, and Button.
  2. Structural Relationship Diagram: Suitable for Container, Flex, Stack, and scrolling/constraint-related widgets.
  3. Content Sample: Suitable for content-bearing widgets like Text, RichText, and Icon.

Taking the Chip family as an example, they share a capsule-shaped silhouette. InputChip, ChoiceChip, and FilterChip then express their differences through avatars, selected states, or filter symbols. For animation widgets, the main body of the base widget is retained, and the semantics of "motion" are expressed through displacement trajectories, before/after states, or direction of change.

This design approach avoids two extremes: on one hand, all logos looking completely unrelated, and on the other, sibling widgets being too similar to distinguish.


Step 2: Let AI Create Within Constraints

When the count reaches the hundreds, aesthetic consistency is more important than the stunning quality of any single image. To achieve this, we first established a set of Widget Logo visual specifications:

The specification is not to limit AI's creativity, but to establish a common language for hundreds of creations. The AI can choose completely different visual metaphors for SliverAppBar and CupertinoPicker, but they will still look like they belong to the same FlutterUnit widget catalog.


Step 3: Directly Produce Maintainable Native SVGs

The official assets were not created by generating bitmaps and then auto-tracing them. Instead, native SVGs were written directly.

This has several advantages:

The AI's advantage here is very clear: it can both understand "what is the most unique behavior of this widget" and translate the design intent into well-structured SVG code. When facing many sibling widgets, it can also reuse a proven visual skeleton, modifying only the parts with real semantic differences.

But "batch" does not mean generating everything in one go and calling it done. The actual process used small-batch progression: design a group, integrate a group, preview a group, correct a group, then move on to the next. This allows for early detection of systemic issues in proportion, color, or semantics, preventing errors from spreading across hundreds of files.


Step 4: From Asset Directory to Flutter Runtime

An SVG appearing in assets/images/widgets/ does not guarantee the user will see it.

FlutterUnit currently resolves the widget name explicitly via widgetLogo(widgetName). If the mapping is missed, even if the SVG file is perfectly correct, the runtime will fall back to the generic Widget.svg. In the early project, there were cases where valid assets were generated but could not be displayed because they weren't added to the mapping.

Therefore, the AI was not just responsible for creating files, but also for closing the engineering loop:

  1. Obtain the exact English widget name from assets/flutter.db.
  2. Use the widget name as the SVG file name, strictly matching case.
  3. Add the widget to the widgetLogo mapping.
  4. Confirm that both the list page and detail page reuse the same resolution result.
  5. Keep Widget.svg as a safe fallback to prevent UI anomalies from unknown widgets.

This step moved the logo work from "art resource organization" into the actual runtime chain of the Flutter application.


Step 5: Let a Program Check the Program's Output

When the number of files exceeds 500, manually clicking through each one is no longer sufficient for quality assurance. We built a dedicated audit script for this purpose, cross-checking the database, SVG assets, and Dart mapping.

Each logo must pass at least the following checks:

Beyond automated checks, visual verification was also necessary. For this, the project added a web-based local SVG Gallery, turning the hundreds of SVGs scattered in the resource directory into a searchable, filterable, and side-by-side comparable widget catalog.


II. Web Preview: Building a Visible Feedback Loop for AI

Directly inspecting SVG source code only reveals <rect>, <path>, and color values. Even if the XML is perfectly legal, there might be issues like a subject that is too small, lines that are too thin, uneven padding, or sibling icons that are too similar.

If you had to launch the full Flutter app and navigate page by page to find the corresponding widget after every modification, the feedback speed for 500+ logos would be very slow. Therefore, we added a lightweight local web preview tool to the repository:

python .local/svg-gallery/server.py

1. What the Web Preview Does

After starting the service, visiting http://127.0.0.1:8765 in a browser shows the complete FlutterUnit Widget SVG Gallery.

This tool does not maintain a separate, easily outdated component list. The Python service directly reads the widget ID, name, family, and star rating from assets/flutter.db, then checks if assets/images/widgets/<WidgetName>.svg exists, is non-empty, and can be parsed. The frontend fetches real-time data via /api/components and loads the SVGs directly from the repository via /svg/<WidgetName>.svg.

This means: as soon as the AI modifies and saves an SVG, refreshing the browser shows the result. The database, resource files, and preview page always use the same single source of truth. There's no need for manual export, and no illusion of "it's in the preview but not in the app" caused by caching an old list.

The Gallery generates a preview card for each widget, displaying:

The page supports searching by widget name or ID, and switching between "All," "Has SVG," and "No SVG" views. The top statistics show the current result count, the number of valid SVGs, and the number of empty slots in real time. For batch production, the "No SVG" filter acts as an instant visual TodoList; asset coverage is only truly closed when the last empty card disappears.


2. Why the Overview is More Important Than a Single Image

Opening a single logo almost always feels "not bad." But placing hundreds of logos into the same responsive grid quickly exposes problems:

The Web Gallery displays SVGs at approximately 112px by default, close to the product's intermediate viewing size. The AI can first search for a target widget, then search for its family members, placing them in the same field of view for comparison. This way, modifications are no longer just about "does this one image work," but also consider "does it look harmonious when placed in the entire widget catalog."

For example, when designing Row, Column, Flex, and Wrap, single-image previews are used to check their respective arrangement semantics, while the overview is used to confirm they share the same layout language. When designing the Chip family, you can quickly check if the capsule skeleton is consistent and if the differences for choice, input, and filter are clear enough.


3. The Respective Responsibilities of Web Preview and Flutter Runtime

The Gallery is not a replacement for the real Flutter device interface, but an intermediate layer to increase iteration speed. The division of labor is very clear:

Verification Layer Main Role
Audit Script Checks if files, XML, canvas, database names, and Dart mapping are correct.
Web Gallery Quickly views all SVGs, searches and filters widgets, compares visual weight, padding, and family consistency.
Flutter Runtime Verifies the 80px list, 120px detail view, real layout, theme background, and the final rendering pipeline.

The Web Preview shortens the feedback cycle from "launch app, enter page, find widget" to "save file, refresh browser." Suspicious logos filtered out by the overview are then taken into FlutterUnit's list and detail pages for final confirmation at 80px, 120px, and against different backgrounds.

This forms a very practical closed loop:

AI understands widget semantics → writes SVG → Web overview quickly discovers visual issues → adjusts SVG → automated audit → Flutter runtime verification

In this loop, the web page acts like a "visual workbench" built specifically for AI collaboration. It immediately translates code changes into images that a person can judge, allowing the developer to quickly point out "this one is too heavy," "that one is too similar," "this group is not unified," and the AI can then precisely modify the SVG based on specific feedback, rather than re-guessing the requirements.

A machine can confirm if the XML is correct, but it cannot independently judge if a graphic truly looks like Flexible. An AI can quickly provide a design, but it still needs a person to make aesthetic and product judgments at key points. The combination of automated auditing, Web overview, and real application testing is the reason this process could stably scale to 553 logos.


III. Summarizing Design Experience into a Style Skill

Completing a batch of logos is not difficult. What's difficult is ensuring that months later, with a different developer, a new AI session, or even an upgraded round of Flutter widgets, newly added assets still maintain the same style.

If the rules only exist within a single conversation, the context disappears when the task ends. If only a very long prompt is kept, it's hard to know later which parts are mandatory engineering constraints and which were just temporary choices for a specific widget.

Therefore, we organized the stable, reusable knowledge from this practice into a repository-level Skill:

.agents/skills/design-flutterunit-widget-logos/
├── SKILL.md
├── references/
│   └── visual-style.md
├── scripts/
│   └── audit_widget_logos.py
└── agents/
    └── openai.yaml

This Skill is not a long manual on "how to draw," but a working protocol for AI collaborators.


1. SKILL.md: Telling the AI How to Work

The entry file defines when this capability is activated and what a logo must go through from understanding to delivery:

It constrains the decision-making process, not mechanically dictating which geometric shapes every logo must consist of. This maintains overall consistency while leaving appropriate room for expression for different widgets.


2. visual-style.md: Preserving a Passable Visual Language

Detailed styles are placed separately in a reference file. The AI reads it only when actually executing a logo task. It contains:

Separating the visual specification from the entry file keeps the Skill concise while allowing design details to evolve independently. If it's later discovered that a certain stroke is not clear enough on a dark theme, only the style reference needs to be updated, and subsequent AIs will inherit this experience in new tasks.


3. Audit Script: Turning "Should Be" into "Must Pass"

Some style rules are aesthetic judgments, but others can be accurately calculated. The latter should not require the AI to re-reason each time, so they are solidified in audit_widget_logos.py.

The script is responsible for checking that files are non-empty, XML is parsable, canvas size, viewBox, database widget name, and runtime mapping. The Skill explicitly requires running the script live when coverage is involved, forbidding the copying of old numbers from the documentation. This way, even if new widgets are continuously added to the database, the AI still reports the true state of the current repository.


4. Gallery: Adding Visual Verification Capability to the Skill

The Skill also specifies the Web Gallery as a verification entry point. The audit script answers "are the files correct," the Gallery helps answer "is the entire set harmonious," and the Flutter runtime ultimately answers "does the effect the user actually sees hold up."

Therefore, this Skill actually connects three types of knowledge:

  1. Domain Knowledge: The semantics and family relationships of Flutter widgets.
  2. Design Knowledge: FlutterUnit's colors, skeletons, proportions, and visual grammar.
  3. Engineering Knowledge: The database, SVG directory, Dart mapping, audit script, and preview entry points.

The next time a new widget is added to the project, the developer doesn't need to re-explain the entire history to the AI. Just by proposing "design and integrate a logo for the new widget," the Skill will bring the same specifications, tools, and completion standards back to the work site.

This is also where AI collaboration is more valuable than one-off generation: the result is not just 553 SVGs, but a method formed in the process, encoded into a project capability that is version-manageable, continuously improvable, and reusable by subsequent AIs.


IV. The Final Result: 553 / 553

Based on the current repository and assets/flutter.db, the audit results are as follows:

Metric Result
Database Widgets 553
Valid Widget SVGs 553
Integrated into Mapping 553
Mapping Coverage 100%

From the initial 18 custom logos and 3.25% coverage to all 553 widgets now having independent visual identities, AI drastically compressed the time required for semantic analysis, SVG writing, repetitive integration, and verification.

More importantly, the project gained not just over 500 images, but a set of capabilities that can continue to evolve: visual specifications, a design method, native SVG assets, a runtime mapping, an audit script, and a local preview tool.


What AI Truly Changed

This practice showed us that AI's most valuable help for open-source projects is often not completing one isolated task for the developer, but making ideas that were previously too large in scale to start, executable.

If relying entirely on manual work, the cost of understanding semantics, conceiving metaphors, writing SVGs, integrating code, and checking each item for 553 widgets would be so high that this task would remain on the TodoList indefinitely. After AI compressed the massive repetitive work, human energy could be focused on the truly important judgments: Does this graphic express the widget's essence? Is it unified enough within its family? Can the user understand it at a glance?

AI did not replace design, nor did it replace development. It acted more like a collaborator who understands Flutter, SVG, and automation tools simultaneously. The person is responsible for direction, taste, and the final choice; the AI is responsible for scaling the specification to hundreds of concrete objects and using engineering means to ensure the results can be landed.

This is perhaps the most shareable aspect of FlutterUnit's logo project: The significance of AI is not just generating content, but helping an idea cross the scale barrier to ultimately become a real, complete, and maintainable product capability.