avatarScott Hatfield

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

13753

Abstract

med ‘key’ parameter.” Using the <code>key</code> parameter allows keys to be provided to public widgets when they are useful for different purpose. Finally, there is one widget in which GPT-4 did not place the <code>child</code> named parameter last. The recommendation to define the <code>child</code> argument last improves readability.</p><figure id="a594"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*ZefVz7JEu8ka3I2dJQ78HA.png"><figcaption></figcaption></figure><p id="035f">So, on the whole, the quality of the code is decent. If this view did not involve inputs that would open the keyboard, the overflow issue would not exist. That said, other related issues might pop up, like overflows caused when the host device is set to a large text scale factor. But, again, overall, this output is not bad as a first draft of the Flutter widget for this page.</p><h1 id="07c6">Experiment 2 — Design Reference Images to Specific Code Elements</h1><p id="17e7">Let’s try another experiment. In this one the focus shifts to a more detailed aspect of app development: using design reference images to generate specific code elements in Dart for Flutter applications. Here, the aim is to understand how multi-modal GPT-4 can be guided to concentrate on particular design features, such as background effects or header areas, and accurately translate them into code.</p><figure id="ba4b"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*vCKc-iGolBttPBAc"><figcaption>It’s Monday now and the developer is going to try a different tact to get ChatGPT to do his work for him.</figcaption></figure><h2 id="f1f6">Selecting a Design Mockup</h2><p id="fd1e">For this experiment, we are going to be mean to ChatGPT. Let’s select a highly complex background featuring complicated design elements. Furthermore, we will ask ChatGPT to build an animated background based on an image.</p><figure id="795b"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*WHLHxQeFFNTDZoArCQ7nXA.png"><figcaption>A splash screen with a decorative, animated background.</figcaption></figure><p id="ea2b">This is the kind of thing that, at least assuming it was created in code, would take a human a decent chunk of time to implement. So the opportunities for time savings with this example should be much greater than with the first experiment.</p><h2 id="bfb9">Generate Some Code</h2><p id="4bfe">Let’s give this one a try too. We will use a prompt asking ChatGPT (using GPT-4) to create a widget that will match the background design in the image above and, additionally, add an animation effect. Since we are being a bit mean with a difficult task, we will give ChatGPT more information in the prompt this time.</p><p id="fc89"><b>Prompt</b>:</p><blockquote id="1b7f"><p>Create a Flutter widget to be used as a decorative background based on the background in the attached image. As shown in the image, a randomly distributed series of dots are placed on the screen. Dots in close proximity to each other are interconnected with lines, creating a “web” effect. This decorative background should incorporate an animation in which the dots move slowly around the screen, “bouncing” off of the screen’s edges when the dots reach the bounds of the viewport.</p></blockquote><p id="0b74">And here’s the response verbatim from GPT-4.</p><p id="b935"><b>Response</b>:</p><blockquote id="574d"><p>Creating such a widget involves a combination of Flutter’s <code>CustomPainter</code> to draw the dots and lines, and <code>AnimationController</code> to animate the dots' movement. Here's a basic structure of the Flutter widget you could use:</p></blockquote><div id="e97b"><pre><span class="hljs-keyword">import</span> <span class="hljs-string">'dart:math'</span>; <span class="hljs-keyword">import</span> <span class="hljs-string">'dart:async'</span>; <span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-comment">/// <span class="language-markdown">A point class to represent each node in the web.</span></span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Point</span> </span>{ <span class="hljs-built_in">double</span> x, y; <span class="hljs-comment">// The x and y coordinates of the point</span> <span class="hljs-built_in">double</span> dx, dy; <span class="hljs-comment">// The delta movement on each axis</span>

Point(<span class="hljs-keyword">this</span>.x, <span class="hljs-keyword">this</span>.y, <span class="hljs-keyword">this</span>.dx, <span class="hljs-keyword">this</span>.dy);

<span class="hljs-comment">/// <span class="language-markdown">Updates the position of the point and reverses direction upon edge collision.</span></span> <span class="hljs-keyword">void</span> update(Size size) { x += dx; y += dy;

<span class="hljs-comment">// Reverse direction if the point hits the boundary</span>
<span class="hljs-keyword">if</span> (x &lt; <span class="hljs-number">0</span> || x &gt; size.width) dx = -dx;
<span class="hljs-keyword">if</span> (y &lt; <span class="hljs-number">0</span> || y &gt; size.height) dy = -dy;

} }

<span class="hljs-comment">/// <span class="language-markdown">A widget that uses the <span class="hljs-code">CustomPainter</span> to draw the background effect.</span></span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebBackground</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{ <span class="hljs-keyword">const</span> WebBackground({<span class="hljs-keyword">super</span>.key, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.width, <span class="hljs-keyword">required</span> <span class="hljs-keyword">this</span>.height});

<span class="hljs-comment">/// <span class="language-markdown">The width of the background effect.</span></span> <span class="hljs-keyword">final</span> <span class="hljs-built_in">double</span> width;

<span class="hljs-comment">/// <span class="language-markdown">The height of the background effect.</span></span> <span class="hljs-keyword">final</span> <span class="hljs-built_in">double</span> height;

<span class="hljs-meta">@override</span> WebBackgroundState createState() => WebBackgroundState(); }

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebBackgroundState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span><<span class="hljs-title">WebBackground</span>> </span>{ <span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span><Point> points = []; <span class="hljs-keyword">final</span> <span class="hljs-built_in">int</span> numberOfPoints = <span class="hljs-number">50</span>; <span class="hljs-keyword">final</span> Random random = Random();

<span class="hljs-meta">@override</span> <span class="hljs-keyword">void</span> initState() { <span class="hljs-keyword">super</span>.initState(); <span class="hljs-keyword">for</span> (<span class="hljs-built_in">int</span> i = <span class="hljs-number">0</span>; i < numberOfPoints; i++) { points.add( Point( random.nextDouble() * widget.width, random.nextDouble() * widget.height, random.nextDouble() * <span class="hljs-number">2</span> - <span class="hljs-number">1</span>, random.nextDouble() * <span class="hljs-number">2</span> - <span class="hljs-number">1</span>, ), ); }

<span class="hljs-comment">// Update the points' position over time to create the moving effect.</span>
Timer.periodic(<span class="hljs-keyword">const</span> <span class="hljs-built_in">Duration</span>(milliseconds: <span class="hljs-number">50</span>), (timer) {
  setState(() {
    <span class="hljs-keyword">for</span> (Point point <span class="hljs-keyword">in</span> points) {
      point.update(MediaQuery.of(context).size);
    }
  });
});

}

<span class="hljs-meta">@override</span> Widget build(BuildContext context) { <span class="hljs-keyword">return</span> CustomPaint( painter: WebPainter(points), child: Container(), ); } }

<span class="hljs-comment">/// <span class="language-markdown">Custom painter class to draw the web-like effect using the points.</span></span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebPainter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">CustomPainter</span> </span>{ <span class="hljs-keyword">final</span> <span class="hljs-built_in">List</span><Point> points;

WebPainter(<span class="hljs-keyword">this</span>.points);

<span class="hljs-meta">@override</span> <span class="hljs-keyword">void</span> paint(Canvas canvas, Size size) { <span class="hljs-keyword">final</span> paint = Paint() ..color = Colors.white.withOpacity(<span class="hljs-number">0.8</span>) ..strokeCap = StrokeCap.round ..strokeWidth = <span class="hljs-number">2.0</span>;

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> point <span class="hljs-keyword">in</span> points) {
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> otherPoint <span class="hljs-keyword">in</span> points) {
    <span class="hljs-keyword">if</span> (point != otherPoint) {
      <span class="hljs-keyword">if</span> ((point.x - otherPoint.x).abs() &lt; <span class="hljs-number">100</span> &amp;&amp; (point.y - otherPoint.y).abs() &lt; <span class="hljs-number">100</span>) {
        canvas.drawLine(Offset(point.x, point.y), Offset(otherPoint.x, otherPoint.y), paint);
      }
    }
  }
}

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> point <span class="hljs-keyword">in</span> points) {
  canvas.drawCircle(Offset(point.x, point.y), <span class="hljs-number">3.0</span>, paint..color = Colors.white);
}

}

<span class="hljs-meta">@override</span> <span class="hljs-built_in">bool</span> shouldRepaint(WebPainter oldDelegate) => <span class="hljs-keyword">true</span>; }</pre></div><blockquote id="a68e"><p>This code provides a starting point. The <code>WebPainter</code> draws dots and lines, while the <code>WebBackground</code> stateful widget contains the animation logic. You may need to adjust the velocity, radius, and the number of dots to fit your needs. The above animation makes dots move continuously and bounce back from the edges. Ensure that you call <code>setState</code> to redraw the widget periodically.</p></blockquote><h2 id="908c">Results in Flutter App</h2><p id="9f00">Let’s see how this code looks in a Flutter app. Since the code delivered by ChatGPT is a widget, I simply placed this widget into a <code>Scaffold</code> as the child of a <code>Stack</code> so that other design elements could be placed on top of the background effect. I also provided a background color for the <code>Scaffold</code>.</p><div id="bda0"><pre><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_MyHomePageState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span><<span class="hljs-title">MyHomePage</span>> </span>{ <span class="hljs-meta">@override</span> Widget build(BuildContext context) { <span class="hljs-keyword">return</span> Scaffold( backgroundColor: <span class="hljs-keyword">const</span> Color(<span class="hljs-number">0xFF16101A</span>), body: Stack( children: [ WebBackground( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, ), ], ), ); } }</pre></div><div id="1c57" class="link-block"> <a href="https://youtube.com/shorts/pzGsdCn2BWM?feature=share"> <div> <div> <h2>Flutter "Web Background" Widget Demonstraction</h2> <div><h3>A background effect for a Flutter app created by ChatGPT. This video is a demonstration of using images in prompts to…</h3></div> <div><p>youtube.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*IPyNry882FG7rCuu)"></div> </div> </div> </a> </div><figure id="f5f3"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*zEWeX9MeBZ3PDKZjl_3jQA.png"><figcaption>The original Figma design is on the left with the output from GPT-4 on the right.</figcaption></figure><h2 id="bafa">Analysis of the Generated Code</h2><p id="c1c9">Let’s dive into these results with some commentary.</p><p id="cdd8"><b>Accuracy in UI Resemblance</b></p><p id="7a82">If you work with AI assistants like ChatGPT a lot, you can sometimes start to see the cracks in the system. Things like the code always missing <code>const</code> keywords as mentioned before, or repeatedly having to remind the system to add comments, or the assistant getting into a pattern of starting every single response with “Certainly!” But then you get results like this one that really bring the amazement factor back to the technology.</p><p id="3e33">This result is really fairly incredible. First, ChatGPT interpreted the prompt requesting it to focus only on the background elements in the provided screenshot without any issues. And, while the colors are not quite the same, the overall design produced by ChatGPT is extremel

Options

y similar to the provided example.</p><p id="cc3c">And then there is the quality of the animation. This would by no means be an easy task for even an experienced Flutter developer to accomplish. I would estimate that this task would occupy a healthy chunk of an afternoon to complete and ChatGPT generated this background in a few moments. While there is a bit of finecsing to do with the output from ChatGPT to make it match the design exactly, this example illustrates the potential for massive time savings by using AI assistants like ChatGPT for Flutter development.</p><figure id="925a"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*xRGYoH6CimWojQBL"><figcaption>It turns out that the developer is getting replaced by AI after all.</figcaption></figure><p id="3def"><b>Code Quality</b></p><p id="efe8">The code quality in this example is again very good, if not perfect. ChatGPT again failed to use any <code>const</code> keywords where they were appropriate. There are also a handful of stylistic choices that I think could be improved, for example adding a few more comments for a widget of this complexity and using non-dynamic type declarations in the for-loops. However, again there are no compilation errors or major problems that would prevent the app from building.</p><h1 id="bf4a">Experiment 3 — Capturing Mood/Ambiance</h1><p id="5993">The third experiment explores a more abstract yet equally fascinating aspect of app design: translating the mood or ambiance conveyed by an image into UI elements using Dart code for Flutter applications. This test aims to uncover how effectively multi-modal GPT-4 can interpret and translate abstract concepts, like mood and ambiance, into tangible UI components.</p><h2 id="877b">Understanding the Concept</h2><p id="c35f">The core idea here revolves around the challenge of converting less tangible aspects, such as the feel or mood evoked by an image, into concrete UI elements. This requires a deep understanding of how colors, shapes, and layout contribute to the overall ambiance of an application.</p><h2 id="44b9">Selecting Images</h2><p id="d75b">The images selected for this experiment will be different than the previous two. Rather than using design mockups, the images in this experiment will simply be pictures that strongly evoke certain moods or themes. The key is to pick an image that distinctly conveys a particular moods, providing a clear emotional or thematic direction for the AI to follow.</p><p id="438c">So, here’s an image generated with DALL-E 3 based on the prompt, “Create a photorealistic image that strongly and distinctly conveys a dark, moody, and intimidating mood.”</p><figure id="2566"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*zQs6pemf3RqaV80l"><figcaption>Very foreboding.</figcaption></figure><h2 id="4079">Generate Some Code</h2><p id="e4b9">The prompt for this experiment will be a little different than the others since the image provided to ChatGPT will also be different. The AI system will be asked to create a landing page for a movie that evokes a mood similar to the one conveyed by the image above. However, the prompt will not contain details about the exact emotion as part of the experiment will be to determine how well ChatGPT evaluates the desired mood from the image.</p><p id="98c9"><b>Prompt</b>:</p><blockquote id="f507"><p>Create a widget for a Flutter web application used to create a landing page for a movie. The landing page should include a headline and a button to “Buy Tickets.” The landing page widget should be designed to evoke similar emotions to those conveyed by the attached image.</p></blockquote><p id="fff2">And here’s the response verbatim from GPT-4.</p><p id="41ef"><b>Response</b>:</p><blockquote id="09bf"><p>To create a Flutter widget that evokes the mood of the image you’ve attached, we’ll focus on a dark theme with a mysterious and slightly eerie ambiance, similar to what’s conveyed in the image. Here’s a conceptual outline of what the Dart code for such a widget might look like, including <code>dartdoc</code> comments for documentation:</p></blockquote><div id="d5ad"><pre>import <span class="hljs-string">'package:flutter/material.dart'</span>;

<span class="hljs-comment">/// A custom Flutter widget for a movie landing page that evokes an eerie and mysterious atmosphere.</span> <span class="hljs-comment">/// It features a headline and a button to purchase tickets.</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MovieLandingPage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{ <span class="hljs-comment">// Title of the movie to be displayed in the headline.</span> <span class="hljs-keyword">final</span> String movieTitle; <span class="hljs-comment">// Callback function that is called when the 'Buy Tickets' button is pressed.</span> <span class="hljs-keyword">final</span> VoidCallback onBuyTickets; <span class="hljs-comment">// Constructor to initialize the [MovieLandingPage].</span> <span class="hljs-title function_ invoke__">MovieLandingPage</span>({ Key? key, required this.movieTitle, required this.onBuyTickets, }) : <span class="hljs-title function_ invoke__">super</span>(<span class="hljs-attr">key</span>: key); @override Widget <span class="hljs-title function_ invoke__">build</span>(BuildContext context) { <span class="hljs-keyword">return</span> <span class="hljs-title function_ invoke__">Scaffold</span>( <span class="hljs-attr">backgroundColor</span>: Colors.black, // Dark theme background color <span class="hljs-attr">body</span>: <span class="hljs-title function_ invoke__">Container</span>( <span class="hljs-attr">decoration</span>: <span class="hljs-title function_ invoke__">BoxDecoration</span>( <span class="hljs-attr">image</span>: <span class="hljs-title function_ invoke__">DecorationImage</span>( <span class="hljs-attr">image</span>: <span class="hljs-title function_ invoke__">AssetImage</span>(<span class="hljs-string">'assets/images/movie_background.jpg'</span>), // Placeholder <span class="hljs-keyword">for</span> background image <span class="hljs-attr">fit</span>: BoxFit.cover, <span class="hljs-attr">colorFilter</span>: ColorFilter.<span class="hljs-title function_ invoke__">mode</span>( Colors.black.<span class="hljs-title function_ invoke__">withOpacity</span>(<span class="hljs-number">0.5</span>), BlendMode.darken, ), ), ), <span class="hljs-attr">child</span>: <span class="hljs-title function_ invoke__">Center</span>( <span class="hljs-attr">child</span>: <span class="hljs-title function_ invoke__">Column</span>( <span class="hljs-attr">mainAxisAlignment</span>: MainAxisAlignment.center, <span class="hljs-attr">children</span>: [ <span class="hljs-title function_ invoke__">Text</span>( movieTitle, <span class="hljs-attr">style</span>: <span class="hljs-title function_ invoke__">TextStyle</span>( <span class="hljs-attr">fontSize</span>: <span class="hljs-number">36</span>, <span class="hljs-attr">fontWeight</span>: FontWeight.bold, <span class="hljs-attr">color</span>: Colors.white70, ), ), <span class="hljs-title function_ invoke__">SizedBox</span>(<span class="hljs-attr">height</span>: <span class="hljs-number">20</span>), // Provides spacing between the title <span class="hljs-keyword">and</span> the button <span class="hljs-title function_ invoke__">ElevatedButton</span>( <span class="hljs-attr">style</span>: ElevatedButton.<span class="hljs-title function_ invoke__">styleFrom</span>( <span class="hljs-attr">primary</span>: Colors.white24, // Button color with transparency ), <span class="hljs-attr">onPressed</span>: onBuyTickets, <span class="hljs-attr">child</span>: <span class="hljs-title function_ invoke__">Text</span>( <span class="hljs-string">'Buy Tickets'</span>, <span class="hljs-attr">style</span>: <span class="hljs-title function_ invoke__">TextStyle</span>( <span class="hljs-attr">fontSize</span>: <span class="hljs-number">20</span>, <span class="hljs-attr">color</span>: Colors.white, ), ), ), ], ), ), ), ); } }</pre></div><blockquote id="84db"><p>In this code:</p></blockquote><ul><li><code>MovieLandingPage</code> is a stateless widget because it does not manage any state changes.</li><li>It takes <code>movieTitle</code> as an argument for the movie's name and <code>onBuyTickets</code> as a callback for when the tickets button is pressed.</li><li>The UI uses a dark theme with a semi-transparent overlay to give a mysterious feel, similar to the attached image.</li><li>The background image should be a dark, moody scene that fits the style of the movie. You will need to replace <code>'assets/images/movie_background.jpg'</code> with the actual path to your image asset.</li><li>The headline uses a large, bold font with a color that stands out against the dark background.</li><li>The button is styled to fit the eerie theme with a semi-transparent white color.</li></ul><blockquote id="ebad"><p>To match the mood of the image, you might want to customize the widget further by adding more visual elements that align with the aesthetic of the scene in the image, like bare tree branches or fog effects.</p></blockquote><h2 id="0b5f">Results in Flutter App</h2><p id="f5e0">In this experiment, ChatGPT generated a <code>StatelessWidget</code> used to create a screen in a Flutter app. So, using the normal “counter” example app for a new Flutter app, the default “MyApp” home page was replaced with the one from the ChatGPT output.</p><p id="2716">As the output from ChatGPT recommended, I replaced the image placeholder with a real image.</p><figure id="1f6c"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*V5mNNh0j6dK-LXFrUvawyg.png"><figcaption>Is using the same image I provided in the prompt cheating?</figcaption></figure><h2 id="2772">Analysis of the Generated Code</h2><p id="2194">Let’s take a look at the output from ChatGPT for this final experiment.</p><p id="01a2"><b>Accuracy in UI Resemblance</b></p><p id="156d">So, right off the bat, the AI system totally nailed identifying the mood conveyed in the image, which it described as “a dark theme with a mysterious and slightly eerie ambiance.” It also did a good job including the two other UI elements I described in the prompt. The rationalle for the overall design choices in this screen used to mirror the mood in the image are also quite compelling.</p><p id="0571">One could argue, however, that simply using the provided image as the background of the page in order to reflect the emotions conveyed by the image is a little like cheating. That said, again, it was successful in identifying the mood in the image, which was really the crux of this experiment.</p><p id="c15a"><b>Code Quality</b></p><p id="ed6d">The code quality from this experiment is basically the same as the previous two, with some warnings from the linter but nothing completely broken.</p><h1 id="306f">Concluding Thoughts</h1><p id="75f9">In this series of experiments leveraging ChatGPT for creating Flutter widgets, we have observed varied levels of efficacy and potential time savings. For straightforward tasks, such as drafting a basic Flutter widget for a simple login page, the AI’s output serves as a starting point. However, the nuances of design and functionality often necessitate manual adjustments by human developers. In these cases, the overall time savings might not be substantial as the developers still need to invest effort in refining and customizing the generated code to meet specific design requirements.</p><p id="f4b2">On the other hand, more complex tasks, such as the adaptation of a widget to create a complex animated background, exhibit the AI’s potential to deliver more significant time savings. Implementing such nuanced design features from scratch can be time-consuming. So ChatGPT’s ability to rapidly generate a rough initial implementation can be a big benefit, freeing developers to focus on higher-level aspects of the development process.</p><p id="f185">The last experiment diverged into the realm of abstraction, demonstrating ChatGPT’s capability to interpret and translate the evocative elements of a design into a corresponding digital experience. Although this was more exploratory, it showcases the versatility of GPT-4 in grasping and applying abstract design concepts, which can be especially useful in the early stages of creative processes.</p><figure id="ac7a"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*G_bHmKE77z1sc7c0"><figcaption>It turns out that the developer still has a job because AI still can’t take meetings with clients.</figcaption></figure><p id="642c">As AI systems like GPT-4 continue to evolve, their role in capturing and translating design elements into tangible drafts is likely to become an invaluable asset in the developer’s toolkit, particularly in accelerating the transition from concept to prototype. It will certainly be exiting to see how these tools continue to evolve in the future.</p><p id="3f9e">Thanks for reading and happy Fluttering!</p></article></body>

Images to Code: Multi-Modal GPT-4 in Converting Designs to Code

A Practical Look into Generating Dart Code with GPT-4 from Visual Inputs.

Among the most intriguing developments in the field of AI coding is the advent of multi-modal AI systems, particularly the GPT-4 model developed by OpenAI. This model’s ability to interpret various forms of data, including textual and visual inputs, and generate relevant and sophisticated outputs, marks a significant leap in AI capabilities. In this article, we delve into an innovative application of multi-modal GPT-4: generating Dart code for Flutter applications based on images.

Am I writing myself out of a job right now? No. Because we’re all safe until ChatGPT can take Teams meetings with clients.

Our exploration revolves around a series of experiments where multi-modal GPT-4, accessed through ChatGPT, is provided with images and tasked with generating Dart code. These experiments are not just about converting visuals into code; they aim to push the boundaries of AI-assisted development. We will examine various scenarios: from using design mockups commonly found on platforms like Dribbble to generate front-end pages, to interpreting specific aspects of design reference images such as background effects or header areas. We even venture into more abstract realms, like translating the mood or ambiance captured in an image into frontend code that resonates with those feelings.

These experiments represent a step towards a future where the line between visual design and code becomes increasingly blurred, where ideas can transition into tangible products with unprecedented speed and efficiency. This article aims to shed light on the possibilities and challenges of integrating AI into Flutter app development, providing insights and inspirations for developers and enthusiasts alike.

Experiment 1 — Design Mockups to Front-End Pages

This first experiment covers what might be the most immediate and obvious use case that comes to mind: testing the capabilities of multi-modal GPT-4 in translating a design mockup for a mobile app into functional Dart code for Flutter applications. So, imagine that you, as a Flutter devloper, have been provided with a design mockup from a design team, or just from a site like Dribbble. You are tasked with creating a Flutter screen to match the design. Could you simply use ChatGPT for this task and go home for the weekend early?

Rather than being replaced by AI, the developer gets to go home early on a Friday after getting all of his work done in one minute with GPT-4!

Selecting a Design Mockup

For this experiment, let’s choose a relatively simple UI for a login page, something that many applications will include.

A simple login page design created in Figma.

Generate Some Code

Alright, let’s give this a try. For this example, let’s try a simple prompt asking ChatGPT (using GPT-4) to create a widget that will match the design in the image above. The image is attached to the prompt.

Prompt:

Write a Flutter widget that creates the screen pictured in the attached design concept.

And here’s the response verbatim from GPT-4.

Response:

To create a Flutter widget that matches the design concept you’ve provided, you can follow the widget tree structure that includes a Scaffold, an AppBar (optional, if you want to include the back button as seen in the design), Image, TextFormFields for email and password, and TextButtons for the ‘Forgot Your Password?’ and ‘Log in’ functionalities. You would also likely have a link for ‘Create one’ referring to account creation.

Here is a code snippet that outlines the structure of the Flutter widget:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Login Screen',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: LoginScreen(),
    );
  }
}
class LoginScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // AppBar is optional: Uncomment the following lines if you want to include an AppBar.
      // appBar: AppBar(
      //   leading: IconButton(
      //     icon: Icon(Icons.arrow_back),
      //     onPressed: () {
      //       // Handle back button
      //     },
      //   ),
      //   elevation: 0,
      //   backgroundColor: Colors.transparent,
      // ),
      body: Padding(
        padding: EdgeInsets.all(20.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Image.asset('assets/logo.png'), // Replace with your asset image path
            SizedBox(height: 50),
            TextFormField(
              decoration: InputDecoration(
                labelText: 'Email',
                prefixIcon: Icon(Icons.email),
              ),
              keyboardType: TextInputType.emailAddress,
              // Add validation and logic
            ),
            SizedBox(height: 20),
            TextFormField(
              decoration: InputDecoration(
                labelText: 'Password',
                prefixIcon: Icon(Icons.lock),
                suffixIcon: IconButton(
                  icon: Icon(Icons.visibility_off),
                  onPressed: () {
                    // Handle password visibility
                  },
                ),
              ),
              obscureText: true,
              // Add validation and logic
            ),
            SizedBox(height: 20),
            Align(
              alignment: Alignment.centerRight,
              child: TextButton(
                child: Text('Forgot Your Password?'),
                onPressed: () {
                  // Handle forgot password
                },
              ),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              child: Text('Log in'),
              onPressed: () {
                // Handle login logic
              },
              style: ElevatedButton.styleFrom(
                minimumSize: Size(double.infinity, 50), // double.infinity is the width and 50 is the height
              ),
            ),
            SizedBox(height: 20),
            TextButton(
              child: Text("Don't have account? Create one"),
              onPressed: () {
                // Handle account creation
              },
            ),
          ],
        ),
      ),
    );
  }
}

Make sure to replace 'assets/logo.png' with the path to your actual logo asset. You will also need to implement the logic for handling the actions like 'Forgot Your Password?', 'Log in', and 'Create one'. Additionally, you may want to adjust styling, spacing, and other UI elements to closely match the design you've provided.

Remember to add detailed dartdoc comments as required for your code standards.

Results in Flutter App

So, let’s plug this code into your bog standard Flutter counter app and see what comes out the other side, with the only modification to the code generated by ChatGPT being an update to the image file path as the response suggests doing.

The original Figma design is on the left with the output from GPT-4 on the right.

Analysis of the Generated Code

Let’s dive into these results with some commentary.

Accuracy in UI Resemblance

Taking a look at the comparison between the original design and the output from GPT-4 above, this is not a bad start at all, especially considering that it took less than a minute. I would estimate that creating a view like this would take an experienced Flutter developer under 30 minutes to implement anyway, so not a giant task by any means, but still there is a gain to be made in productivity by using GPT-4 to at least get a start. Overall, the widget created by GPT-4 looks quite similar to the one in the Figma design.

The bad news is that the parts of the widget that the AI system didn’t quite nail are probably the ones that will be the most tedious for the human developer to go fix. This includes the outline and styling of the form fields, which can be time consuming to implement in a Flutter app because of the large number of customization options for form fields. Another example is the style of the “Log in” button which is, again, a bit time consuming for a human developer to bring into alignment with the design.

The comment made by ChatGPT saying, “if you want to include the back button as seen in the design,” is a little interesting since there is, in fact, no back button in the design.

So, in terms of accuracy to the design requirements, a human developer would either need to have some back and forth with ChatGPT to refine the output or simply fix the discrepancies manually. Either way, this refinement will cut in the time savings achieved by using ChatGPT in the first place.

It looks like the developer will not be knocking off for the weekend early after all.

Code Quality

So the visual appearance of the output from GPT-4 is not bad compared to the design but it will still require more work to match the design exactly. Let’s take a look at the quality of the code itself.

The good news is that, at least with this example, there are no outright compilation errors that would actually break a build. However, there is one significant problem with the code generated by GPT-4. This screen contains text input fields so, on a mobile device, the on-screen keyboard can be open. Because the view created by GPT-4 is not scrollable, this will result in an overflow.

Well that’s not good.

As with some of the visual aspects, this is not very difficult to fix; the quick and dirty way is to just wrap the Scaffold body in a SingleChildScrollView widget. But, again, this kind of issue does cut into the time the developer saved by using ChatGPT. It could also create an opportunity for regressions if testing failed to catch this overflow problem.

There are three different types of warnings from flutter analyze . Most of the warnings are recommendations to use the const keyword to improve performance. This is something I’ve personally noticed with GPT-4; it never seems to use the const keyword. The second type of warning is “Constructors for public widgets should have a named ‘key’ parameter.” Using the key parameter allows keys to be provided to public widgets when they are useful for different purpose. Finally, there is one widget in which GPT-4 did not place the child named parameter last. The recommendation to define the child argument last improves readability.

So, on the whole, the quality of the code is decent. If this view did not involve inputs that would open the keyboard, the overflow issue would not exist. That said, other related issues might pop up, like overflows caused when the host device is set to a large text scale factor. But, again, overall, this output is not bad as a first draft of the Flutter widget for this page.

Experiment 2 — Design Reference Images to Specific Code Elements

Let’s try another experiment. In this one the focus shifts to a more detailed aspect of app development: using design reference images to generate specific code elements in Dart for Flutter applications. Here, the aim is to understand how multi-modal GPT-4 can be guided to concentrate on particular design features, such as background effects or header areas, and accurately translate them into code.

It’s Monday now and the developer is going to try a different tact to get ChatGPT to do his work for him.

Selecting a Design Mockup

For this experiment, we are going to be mean to ChatGPT. Let’s select a highly complex background featuring complicated design elements. Furthermore, we will ask ChatGPT to build an animated background based on an image.

A splash screen with a decorative, animated background.

This is the kind of thing that, at least assuming it was created in code, would take a human a decent chunk of time to implement. So the opportunities for time savings with this example should be much greater than with the first experiment.

Generate Some Code

Let’s give this one a try too. We will use a prompt asking ChatGPT (using GPT-4) to create a widget that will match the background design in the image above and, additionally, add an animation effect. Since we are being a bit mean with a difficult task, we will give ChatGPT more information in the prompt this time.

Prompt:

Create a Flutter widget to be used as a decorative background based on the background in the attached image. As shown in the image, a randomly distributed series of dots are placed on the screen. Dots in close proximity to each other are interconnected with lines, creating a “web” effect. This decorative background should incorporate an animation in which the dots move slowly around the screen, “bouncing” off of the screen’s edges when the dots reach the bounds of the viewport.

And here’s the response verbatim from GPT-4.

Response:

Creating such a widget involves a combination of Flutter’s CustomPainter to draw the dots and lines, and AnimationController to animate the dots' movement. Here's a basic structure of the Flutter widget you could use:

import 'dart:math';
import 'dart:async';
import 'package:flutter/material.dart';

/// A point class to represent each node in the web.
class Point {
  double x, y; // The x and y coordinates of the point
  double dx, dy; // The delta movement on each axis

  Point(this.x, this.y, this.dx, this.dy);

  /// Updates the position of the point and reverses direction upon edge collision.
  void update(Size size) {
    x += dx;
    y += dy;

    // Reverse direction if the point hits the boundary
    if (x < 0 || x > size.width) dx = -dx;
    if (y < 0 || y > size.height) dy = -dy;
  }
}

/// A widget that uses the `CustomPainter` to draw the background effect.
class WebBackground extends StatefulWidget {
  const WebBackground({super.key, required this.width, required this.height});

  /// The width of the background effect.
  final double width;

  /// The height of the background effect.
  final double height;

  @override
  WebBackgroundState createState() => WebBackgroundState();
}

class WebBackgroundState extends State<WebBackground> {
  final List<Point> points = [];
  final int numberOfPoints = 50;
  final Random random = Random();

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < numberOfPoints; i++) {
      points.add(
        Point(
          random.nextDouble() * widget.width,
          random.nextDouble() * widget.height,
          random.nextDouble() * 2 - 1,
          random.nextDouble() * 2 - 1,
        ),
      );
    }

    // Update the points' position over time to create the moving effect.
    Timer.periodic(const Duration(milliseconds: 50), (timer) {
      setState(() {
        for (Point point in points) {
          point.update(MediaQuery.of(context).size);
        }
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: WebPainter(points),
      child: Container(),
    );
  }
}

/// Custom painter class to draw the web-like effect using the points.
class WebPainter extends CustomPainter {
  final List<Point> points;

  WebPainter(this.points);

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.white.withOpacity(0.8)
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 2.0;

    for (var point in points) {
      for (var otherPoint in points) {
        if (point != otherPoint) {
          if ((point.x - otherPoint.x).abs() < 100 && (point.y - otherPoint.y).abs() < 100) {
            canvas.drawLine(Offset(point.x, point.y), Offset(otherPoint.x, otherPoint.y), paint);
          }
        }
      }
    }

    for (var point in points) {
      canvas.drawCircle(Offset(point.x, point.y), 3.0, paint..color = Colors.white);
    }
  }

  @override
  bool shouldRepaint(WebPainter oldDelegate) => true;
}

This code provides a starting point. The WebPainter draws dots and lines, while the WebBackground stateful widget contains the animation logic. You may need to adjust the velocity, radius, and the number of dots to fit your needs. The above animation makes dots move continuously and bounce back from the edges. Ensure that you call setState to redraw the widget periodically.

Results in Flutter App

Let’s see how this code looks in a Flutter app. Since the code delivered by ChatGPT is a widget, I simply placed this widget into a Scaffold as the child of a Stack so that other design elements could be placed on top of the background effect. I also provided a background color for the Scaffold.

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF16101A),
      body: Stack(
        children: [
          WebBackground(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
          ),
        ],
      ),
    );
  }
}
The original Figma design is on the left with the output from GPT-4 on the right.

Analysis of the Generated Code

Let’s dive into these results with some commentary.

Accuracy in UI Resemblance

If you work with AI assistants like ChatGPT a lot, you can sometimes start to see the cracks in the system. Things like the code always missing const keywords as mentioned before, or repeatedly having to remind the system to add comments, or the assistant getting into a pattern of starting every single response with “Certainly!” But then you get results like this one that really bring the amazement factor back to the technology.

This result is really fairly incredible. First, ChatGPT interpreted the prompt requesting it to focus only on the background elements in the provided screenshot without any issues. And, while the colors are not quite the same, the overall design produced by ChatGPT is extremely similar to the provided example.

And then there is the quality of the animation. This would by no means be an easy task for even an experienced Flutter developer to accomplish. I would estimate that this task would occupy a healthy chunk of an afternoon to complete and ChatGPT generated this background in a few moments. While there is a bit of finecsing to do with the output from ChatGPT to make it match the design exactly, this example illustrates the potential for massive time savings by using AI assistants like ChatGPT for Flutter development.

It turns out that the developer is getting replaced by AI after all.

Code Quality

The code quality in this example is again very good, if not perfect. ChatGPT again failed to use any const keywords where they were appropriate. There are also a handful of stylistic choices that I think could be improved, for example adding a few more comments for a widget of this complexity and using non-dynamic type declarations in the for-loops. However, again there are no compilation errors or major problems that would prevent the app from building.

Experiment 3 — Capturing Mood/Ambiance

The third experiment explores a more abstract yet equally fascinating aspect of app design: translating the mood or ambiance conveyed by an image into UI elements using Dart code for Flutter applications. This test aims to uncover how effectively multi-modal GPT-4 can interpret and translate abstract concepts, like mood and ambiance, into tangible UI components.

Understanding the Concept

The core idea here revolves around the challenge of converting less tangible aspects, such as the feel or mood evoked by an image, into concrete UI elements. This requires a deep understanding of how colors, shapes, and layout contribute to the overall ambiance of an application.

Selecting Images

The images selected for this experiment will be different than the previous two. Rather than using design mockups, the images in this experiment will simply be pictures that strongly evoke certain moods or themes. The key is to pick an image that distinctly conveys a particular moods, providing a clear emotional or thematic direction for the AI to follow.

So, here’s an image generated with DALL-E 3 based on the prompt, “Create a photorealistic image that strongly and distinctly conveys a dark, moody, and intimidating mood.”

Very foreboding.

Generate Some Code

The prompt for this experiment will be a little different than the others since the image provided to ChatGPT will also be different. The AI system will be asked to create a landing page for a movie that evokes a mood similar to the one conveyed by the image above. However, the prompt will not contain details about the exact emotion as part of the experiment will be to determine how well ChatGPT evaluates the desired mood from the image.

Prompt:

Create a widget for a Flutter web application used to create a landing page for a movie. The landing page should include a headline and a button to “Buy Tickets.” The landing page widget should be designed to evoke similar emotions to those conveyed by the attached image.

And here’s the response verbatim from GPT-4.

Response:

To create a Flutter widget that evokes the mood of the image you’ve attached, we’ll focus on a dark theme with a mysterious and slightly eerie ambiance, similar to what’s conveyed in the image. Here’s a conceptual outline of what the Dart code for such a widget might look like, including dartdoc comments for documentation:

import 'package:flutter/material.dart';

/// A custom Flutter widget for a movie landing page that evokes an eerie and mysterious atmosphere.
/// It features a headline and a button to purchase tickets.
class MovieLandingPage extends StatelessWidget {
  // Title of the movie to be displayed in the headline.
  final String movieTitle;
  // Callback function that is called when the 'Buy Tickets' button is pressed.
  final VoidCallback onBuyTickets;
  // Constructor to initialize the [MovieLandingPage].
  MovieLandingPage({
    Key? key,
    required this.movieTitle,
    required this.onBuyTickets,
  }) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black, // Dark theme background color
      body: Container(
        decoration: BoxDecoration(
          image: DecorationImage(
            image: AssetImage('assets/images/movie_background.jpg'), // Placeholder for background image
            fit: BoxFit.cover,
            colorFilter: ColorFilter.mode(
              Colors.black.withOpacity(0.5),
              BlendMode.darken,
            ),
          ),
        ),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                movieTitle,
                style: TextStyle(
                  fontSize: 36,
                  fontWeight: FontWeight.bold,
                  color: Colors.white70,
                ),
              ),
              SizedBox(height: 20), // Provides spacing between the title and the button
              ElevatedButton(
                style: ElevatedButton.styleFrom(
                  primary: Colors.white24, // Button color with transparency
                ),
                onPressed: onBuyTickets,
                child: Text(
                  'Buy Tickets',
                  style: TextStyle(
                    fontSize: 20,
                    color: Colors.white,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

In this code:

  • MovieLandingPage is a stateless widget because it does not manage any state changes.
  • It takes movieTitle as an argument for the movie's name and onBuyTickets as a callback for when the tickets button is pressed.
  • The UI uses a dark theme with a semi-transparent overlay to give a mysterious feel, similar to the attached image.
  • The background image should be a dark, moody scene that fits the style of the movie. You will need to replace 'assets/images/movie_background.jpg' with the actual path to your image asset.
  • The headline uses a large, bold font with a color that stands out against the dark background.
  • The button is styled to fit the eerie theme with a semi-transparent white color.

To match the mood of the image, you might want to customize the widget further by adding more visual elements that align with the aesthetic of the scene in the image, like bare tree branches or fog effects.

Results in Flutter App

In this experiment, ChatGPT generated a StatelessWidget used to create a screen in a Flutter app. So, using the normal “counter” example app for a new Flutter app, the default “MyApp” home page was replaced with the one from the ChatGPT output.

As the output from ChatGPT recommended, I replaced the image placeholder with a real image.

Is using the same image I provided in the prompt cheating?

Analysis of the Generated Code

Let’s take a look at the output from ChatGPT for this final experiment.

Accuracy in UI Resemblance

So, right off the bat, the AI system totally nailed identifying the mood conveyed in the image, which it described as “a dark theme with a mysterious and slightly eerie ambiance.” It also did a good job including the two other UI elements I described in the prompt. The rationalle for the overall design choices in this screen used to mirror the mood in the image are also quite compelling.

One could argue, however, that simply using the provided image as the background of the page in order to reflect the emotions conveyed by the image is a little like cheating. That said, again, it was successful in identifying the mood in the image, which was really the crux of this experiment.

Code Quality

The code quality from this experiment is basically the same as the previous two, with some warnings from the linter but nothing completely broken.

Concluding Thoughts

In this series of experiments leveraging ChatGPT for creating Flutter widgets, we have observed varied levels of efficacy and potential time savings. For straightforward tasks, such as drafting a basic Flutter widget for a simple login page, the AI’s output serves as a starting point. However, the nuances of design and functionality often necessitate manual adjustments by human developers. In these cases, the overall time savings might not be substantial as the developers still need to invest effort in refining and customizing the generated code to meet specific design requirements.

On the other hand, more complex tasks, such as the adaptation of a widget to create a complex animated background, exhibit the AI’s potential to deliver more significant time savings. Implementing such nuanced design features from scratch can be time-consuming. So ChatGPT’s ability to rapidly generate a rough initial implementation can be a big benefit, freeing developers to focus on higher-level aspects of the development process.

The last experiment diverged into the realm of abstraction, demonstrating ChatGPT’s capability to interpret and translate the evocative elements of a design into a corresponding digital experience. Although this was more exploratory, it showcases the versatility of GPT-4 in grasping and applying abstract design concepts, which can be especially useful in the early stages of creative processes.

It turns out that the developer still has a job because AI still can’t take meetings with clients.

As AI systems like GPT-4 continue to evolve, their role in capturing and translating design elements into tangible drafts is likely to become an invaluable asset in the developer’s toolkit, particularly in accelerating the transition from concept to prototype. It will certainly be exiting to see how these tools continue to evolve in the future.

Thanks for reading and happy Fluttering!

Flutter
ChatGPT
AI
App Development
Software Development
Recommended from ReadMedium