Michael McRoskey

AI-Powered Visual Dev: A New Workflow for Flutter Devs

Transcript

Michael

Thanks. I'm so excited to talk to you today about AI-powered visual development. So a question that we often ask ourselves is, what will app development look like two years from now? And I'm here to convince you that there are three aspects to it. The first is AI-powered, second, universal, and three, visual. So let's talk about AI-powered. This doesn't need much convincing. I mean, ChatGPT's popularity has never been higher. But perhaps more relevant is that NYC's latest Winter 2025 startup batch, over a quarter of their batch had 95% of their code base completely written by AI. So AI-powered development means full-stack awareness of what you're building. So that's the design, the data structure, the actual code behind it. So it's not just about, you know, auto-completing a function here, but it's understanding kind of the entire app experience and helping you to build it faster. Okay. Number two, universal. Let's unpack that. So in my mind, AppLogic should be defined once in a single code base and really target any screen or any environment. And that's why at my company, we chose Flutter, obviously one of the fastest growing and most popular UI frameworks today. You can see it here in this chart. It is leading in terms of global developer engagement ahead of frameworks like React Native, SwiftUI and others. And I think that there's other aspects to Universal. So for instance, at my company, we write front end and back end code in Dart. So we share functions, models, data handling across the entire stack. And of course, it also means that whenever we make a change, we can deploy it to any environment. So we have an iOS app, we have web, obviously, we have desktop for Mac OS and Windows, and it all just works. But I think there's another aspect to Universal, and that's team-friendly. So in this case, designers, developers, product managers, they can all work in one environment and with one framework. And we know a lot about customers who have fragmented applications across different stacks and different approaches of development. And we found that just simply standardizing enables these teams to collaborate much more effectively. So visual is this next natural abstraction layer. And what do I mean by that? So technology always progresses in waves of abstractions that really help us to manage complexity and increase productivity. So in 1945, programming meant physically rewiring circuits. So we have binary code as an abstraction of physical states. And then language comes in as this abstraction of binary logic. And then languages like C in the 1970s, they gave programmers way more control than assembly. But by the 1990s, you have Java and Python, really high level languages that kind of manage all the memory management and any of the low level details. And then we enter IDEs like VS Code. And these also abstract and support programming languages. We think of things here such as syntax highlighting or linting or some of the debugging tools that exist. And then somewhere around this area of the stack, we have libraries and frameworks like Flutter. And these of course abstract common patterns and target environments. But this is where visual development takes a major leap, and this is abstracting UI implementation and a lot of basic logic flow. So I want to mention this is not really instead of code, but it's on top of frameworks and code. So it makes specific tasks like editing UI layout vastly faster and simplified. And then finally, AI comes in and kind of abstracts all of the layers, enabling users to just focus on intent. And this abstracts away not just syntax, but often the structure or boilerplate or even architectural patterns. So each layer here has automated or simplified the layer below, and it's allowed focus on much higher level problems. But it's not just about choosing one layer. I think modern development requires leveraging each one for its specific skills. So you might use traditional code for customization or optimization, UI, you know, visual frameworks for mocking out UI really quickly, and of course, AI for architectural leaps, and all while relying on the fundamental languages and frameworks beneath. So, hi, I'm Michael. I'm the interim PM at Flutter Flow, where I lead our marketplace, which is a growing library of Flutter app templates. And I live close by in Munich, Germany, with my wife and two kids. Previously, I worked at Google in kind of the developer tooling space. really when the space was just starting to heat up. I'll be honest, it had been pretty dry before LLMs started to consume our entire code base. But now with everything that we're building at Flutter Flow, I think this is the most exciting time ever to be in developer tooling. So in case you're not familiar with it, this is where Flutter Flow sits in that abstraction hierarchy. It is a visual development platform for Flutter, and it renders changes live as you edit. And I think it's dramatically more intuitive to just adjust padding visually like this, than with code. And the same is true for other visual properties. For instance, if we wanted to change alignment or the main axis size or the main axis alignment or cross axis alignment, you don't have to keep all of these constants in memory and you can just visualize it live as you go. So in my opinion, Flutter Flow is one of the most complex Flutter apps ever built. Our platform has generated billions of lines of Flutter code, and it's now powering apps for major banks, startups, and enterprises. So it's a complex product, but it also enables building really complex use cases. But about mid last year, we wanted to give ourselves a challenge. So we asked ourselves, what if we could build our product within our product? That would surely test the limits of extensibility, but also give us a really high degree of visual control. And this is a bit of a facetious result of that challenge. This was our April Fool's Day prank last year, where we recreated our builder as a T-shirt builder, and we allowed people to actually order physical swag and we shipped it to their homes. Jokes aside, we were serious about doing this for Flutter Flow and also desperate to avoid a recursive loop. And so in part one of this talk, I want to dive into the practical now. I want to show you how we used Flutter Flow and AI to improve our existing Flutter app. And then hopefully you'll walk away with some tools that you can use today in your app. And then in part two, I want to give you a glimpse into the possible future. I'll share some insights that we've had in our three plus year integrating AI into our product. So one of the most common things that folks tell me is that they really want to leverage Flutter Flow, but they already have an existing Flutter app. So today I want to show you a really powerful workflow that we're using right now to bring the power of visual development directly into your existing apps. And let me show you some examples of where we've done exactly this. So since day one, we've had this, I guess, kind of average looking new project dialogue. I'd say there's kind of two main issues with it. The first is that it just needed a facelift. It needed to look a little bit modern and cleaner. And the second is that our library of community submitted libraries and templates has grown to almost a thousand since we launched. And they offer so much more capabilities than these example apps that we had on day one. And so we decided to rebuild this in Flutter Flow. And the basic flow is this. We design visually a component in Flutter Flow, including all the animations and loading state. And then we use our CLI tool to export this as a library. And finally, we import this into our existing code base as a dependency. The results of this were pretty incredible. You can see it here, this is our new project dialogue. I think what would have taken probably three times as long to implement just took hours. We also have this clear separation of concerns where this UI approach could handle all the UI state transitions, any validation, the error messages showing up, and then our code base could handle all of the data and actions. So this is the Flutter Flow Builder itself, and you'll notice the widget tree on the left is just a standard widget tree. We've got a large visual canvas for editing in the middle, and then on the right side, you can see all of the parameters defined for this component, including action callbacks that also take their own parameters. And we can scroll here and see what happens when we do the on tap on this button. And this is a visual way to edit logic, but at the very bottom, we see we actually execute those callbacks. And jumping to the Flutter code and our existing code base, it looks something like this. We basically just import the package. And of course, we have to update pubspec.yaml just to make it aware of it. And then we just call this widget and we can pass in our existing logic, in this case, the dashboard service to those function callbacks. So we've already done this in a few other places. That was one example. In this case, we also quickly mocked up a new onboarding questionnaire, and we just imported it in. This took probably a day or two. And finally, this little Canvas settings on the left shows up and allows people to adjust safe area and whether we render pixel overflows. What's cool about this is that when we designed it, we used a widget builder parameter. It's that kind of X on the right-hand side. And what that allowed us to do is leverage existing widgets in our Flutter code base that weren't existing in Flutter Flow. And then we could just reference them when we actually did the import. So yeah, the workflow is pretty straightforward. Step one, we design the components visually in Flutter Flow. Step two, we export this code as a library. And then step three, we import that library into our existing Flutter code base. Okay, so the idea behind these is hopefully it makes it really easy to visually iterate really quickly. I would love to demo this for you right now. Okay, so let's swipe over. This right here is an app that I've created. It's called Null Safe Nursery. It's a baby clothes store for Flutter-themed baby clothes. And I'd really like to add kind of a gift carding feature right here. And so we're going to go to Mobbin and search for gift cards just to get some inspiration. And I actually really like this Uber wallet. Perfect. And I'll just take a screenshot of that. That should land it on the desktop. We'll go to Flutter Flow and we're going to use this sketch to component feature we have. We can just drag that image right in, generate the component, give it a few seconds, and this should translate it into Dart code. Perfect. Okay, that looks all right. Let's go ahead and insert that. I'll name it gift card. And now the first thing I notice is that that main access size needs to be minimum. And then let's check. Yep, that looks good. Okay, let's rename UberCash to be null safe bucks. And then we need a value for this and we want to pass it in. So I'll define a parameter and we could just call this something like current balance. And that's going to be a double. Okay. And then we can go and add this callback function that's just going to be the on tap when you hit add funds. And now let's bind those values. So I'll select that and I see the current balance right there. We can also adjust the formatting here and I'll just make it a decimal and make sure that it's a currency. We can go ahead and confirm. Now let's take this and we'll go to our actions and we'll add an action and let's search for the execute callback. Perfect. And it's the callback there. Awesome. Okay, now we're ready to export this. So let's just copy that command from our CLI. And we're back in our IDE here. I'll just open a new terminal. And then we can just make a new dependencies directory and go into it and paste our command. Okay, awesome. Now that is all set. It's running pub-get, but we actually need to update our pubspec.yaml first, make it aware of this. And thank you to autocomplete for knowing what I want. Let's go to our home screen. Now we just need to do the import at the top, which is pretty simple. Again, thank you autocomplete. And then I have a to-do right here, which I'm going to go ahead and start typing in. We actually want a value listenable builder. And then we just need to fix some things. It's not const. And let's make this, I think, async. Okay. And awesome. That should be ready to go. Let us hot restart this on the web. Cool, we can enter the shop and if we scroll down we should now see... Cool, okay, it's there and let's test the functionality. Awesome. Okay, I noticed a couple things. The first thing is the padding. Let's just go ahead and change the padding to be 24 on each side. And then I also I want kind of a custom format for this. this double that's showing and so i can go ahead and pass in whatever format but in this case let's just truncate to do two decimal places okay awesome i'll go ahead and confirm that and then we'll have to pull the code again and hot restart do that really fast and now if we go down this works just as you would expect and wouldn't that be amazing if all you needed to do for a gift card is uh click add funds and it just adds money Okay, so special thanks to ChatGPT for generating these mockups. I just wanted to show you that as a really quick example here. But now, that's hopefully immediately actual something you can do today. But I'd love to shift to give you a glimpse into where we believe the future of Flutter development is heading. And we've been researching kind of the best applications of AI in our product for really over the past three years. And I think one of the most striking insights from our research is that what wasn't possible just 12 months ago is absolutely possible today. And I think there's two implications of this. The first is it's absolutely okay to revisit bad ideas, things that seemed impossible a year ago. And the second is that it's so important to build your AI scaffolding to be vendor and model agnostic. So you can really test and take advantage of all the competition in the space and all of their updates. So I want to show you an example in our product from 2021. And just as a background, both our CEO and CTO were ML engineers at Google, and so they were obsessed with AI well before ChatGPT came out. And so, yeah, they implemented this. This is OpenAI's Codex model back in 2021. And for context, this is like a full year before ChatGPT is released. But you can already see it's a good implementation of using natural language to help generate some code. And now, if we shift to something that we just publicly launched two days ago, you'll see a remarkable difference. So that is Dreamflow. Dreamflow is this new conversational app building experience that our team's been working on, and it really combines the power of large language models with really deep Flutter expertise. And in this case, it generates complete Flutter applications, all from natural language. And of course it was built in Flutter Flow. So these are some of the generations that we've seen users create just in the past couple days. It's pretty incredible. I'd encourage you to check it out yourselves. So I guess we go from 2021 to now, we go from those single line function generations to full app generations. And an obvious question to ask is what changed? And I think there's three core learnings here. One is external and really something that we adapted to. And then the others are insights that we found in working really deeply with these models. So crucially, the models themselves, the capabilities of these models is accelerating at an insane rate. And I would love to show you an example of that. So this is the same prompt sent to models from one year ago versus today. And we just want it to recreate one screen in this Delta Airlines app. And so let's go ahead and send it in. And this is what it generated. So airline apps are bad, but I don't think they're this bad. So we went back to the drawing board and we really tweaked our system prompt. We experimented with functionality-based prompts versus UI-based prompts. And this is still March of last year. We reran with this new system prompt, and these were the results. still terrible. And so if we fast forward to two days ago, I re-ran the same prompt on Wednesday, and this is what Dreamflow came up with. It's remarkable. I mean, I think it's amazing. I might even prefer this, I think, to the original Delta airline style. It's a little cleaner. But it's amazing to see how much these models have changed in such a short time. So the model updates alone will yield really impressive performance improvements. But I would say in order to take advantage of these improvements, there's kind of three key things that you need to keep in mind so that you don't have to do constant rewrites. The first is to have a versioned pipeline so that you can really test changes, you can roll back to previous model versions, etc. The second is that you should build to be model and vendor agnostic, where you can so you can swap in these models and test them. And the final thing is that it's really important to have kind of this eval tracking layer where you can look at the same prompts over time and score the outputs. So another fascinating discovery that we had was that the input and output for these models matters. And I'll chat about this for a second. So in our research, we experimented with creating specialized domain specific language specifically for Flutter UI. And the basic idea is that if we minified into this format, we could use AI to make really precise edits really quickly. And so we could turn a page into this format and then feed it to the model as an example in the system prompt and then hope that the model produces something pretty similar. And spoiler alert, this didn't actually work very well. So first, it's worth asking, why did we go down this path? I think it really comes down to three things. So this DSL language, it really enables precision, right? So you can see individual widget nodes are namespaced. So if you wanted to make a really targeted edit, you could. Number two, it's minified. And so that just means less tokens in, less tokens out, hopefully faster inference time, hopefully lower costs for you. And of course, it's programmatically defined. And we know that AI models work really well when they have structure, and so feeding it a structure and hopefully it can deal with that. But you might have already guessed at the issues here. The first is what a headache for engineers. Like, to debug this was miserable because you constantly had to deserialize or serialize just to see what the LLM had outputted. And then number two, you know, as we continue to build out our product and we add new features, Every new feature needs a definition in this abstraction layer. And ideally, lots of examples of how it's used contextually so that the AI model knows what to do with it. And then finally, we would find that, you know, anytime we tried to deserialize an LLM result, like half the time we would run into errors where it just couldn't deserialize because the LLM had hallucinated some properties that were non-existent. So what we found instead is that the LLMs just love writing Dart code. And this fixed a lot of our prior issues. So first of all, we could just run and test immediately. Developers could just read exactly what was going on and manually inspect it. Number two, like we could leverage the fact that these LLMs were trained manually. already directly on billions of lines of Dart code. And so, although sometimes there's an asterisk here, we have to untrain that, and I'll talk about that in a second. And finally, you know, it's just gonna be syntactically correct by default. We know these models are pretty good at this stuff, And Dart has a clean syntax, obviously. So we can actually shift a lot of our prompting, not as much in examples, but rather showing architectural guidance or handling edge cases or giving some stylistic guides. So that brings me to our third big insight, which is that generic prompts produce generic results. And so the true power comes from injecting Flutter-specific domain knowledge. And we have a massive repository of Flutter domain knowledge because we have so many different app deploys and projects and different pub.dev packages that people have used, the different unique versions, different app store deploys. And so we have a ton of experience with just handling these edge cases. And so we can inject this knowledge right into the LLM to fix some of the issues from outdated training data. And here's an example I like to share because we have so many users on so many environments and platforms. They use all these packages. We often have to bake in logic that handles some of these platform limitations of pub.dev packages. And so for instance, like with audio recording, we know that Safari for Mac OS might expect a different encoding format than Chrome on Android 14. And so our infra can basically handle all this weird stuff so that the model doesn't have to guess. And here's another use case where we untrain the model. We prompt the model to use these theme constants like title large, body medium, or label small instead of these outdated styles like headline five because these text styles have obviously changed. They're categorized by function now instead of arbitrary numbers. But the training data that fed those models doesn't necessarily reflect that. And maybe this is obvious, but one of the more surprising findings was that simply using all caps for certain phrases had a noticeable difference on generation quality. And so we definitely have a few PRs come in that just change the letters to be all caps. So improved generation comes from injecting Flutter-specific expertise. This means understanding which Flutter packages solve specific problems the best, handling edge cases across browsers and platforms, and of course, a little iteration with prompt magic. And actually, that's a lot. A lot of testing. So there you have it. In part one, I showed you a practical workflow that you can use today to leverage the power of AI visual development in your app. And in part two, I gave you a preview into the future that we see for Flutter development. And actually I do have one request Given that I'm surrounded by probably the most amount of Flutter experts I've ever been in the same room with, we're currently looking for alpha testers to try out a new visual editing experience that's for existing Flutter code bases. So if you are interested, please check out this QR code, or of course, you can reach out to me afterwards. So what's most exciting to me is how these modalities are converging. I think the future of Flutter development isn't about choosing between coding, using visual tools, or AI. It's about using all of them, the powerful combination of all three, with you orchestrating which to use and when. Thank you so much. I'm so excited to answer some questions.

Vadym

Good to see you, first of all. Yeah, good to see you too. Again. And say hi to all the Flutter Flow team for me. So, starting from Costas, what tool did you use for the presentation? Seems cool.

Michael

Thank you. It's a combination of After Effects with a lot of exports with like alpha transparency and then Kino with Magic Move.

Vadym

I've heard it's super complex and heavy presentation, right? It's like two and a half gigabytes. I don't know how it got so big. It's not that big, yeah. It's more or less average MP3 file, yeah. Then anonymous question, I guess. It's a Lucas question. So, does Flutter Flow allow you to define a design system?

Michael

Yeah, that's a really good question. We do have now designed libraries. So the idea behind it is, you know, all of your color scheme, the theme colors for both light and dark mode. Also, any of the fonts, custom icons you use, you can package that all up as a library and then either import it into an existing Flutter app, or you could now import libraries into existing Flutter Flow projects. And there could be transitive dependencies, I mean, we import all the way down the chain. So it's really powerful. I guess one that comes to mind right now is we implemented Shad CNUI all in Flutter Flow. And we've seen some really cool use cases there where it just automatically makes your app look a lot more professional and cleaner by using something like that.

Vadym

That's good. Now for long answers I will ask long questions. So the question is: how can we integrate Flutter flow with already existing stacks if possible? Say make use of models from freeze routine to gorouter and report and many other things.

Michael

Yeah, it's a really good question. I think what I just showed, basically being able to export the raw code. You can export the code at any time. So we have the CLI tool. Also, if you define a library, it's basically really easy to import it into to an existing Flutter code base. Other things that we've seen is if you want to, you can use our VS Code extension to basically pull in all of your Flutter Flow project files, and then you can edit the code directly there, 'cause we support custom code within our projects. So if you wanted to define some classes, or you have a very specific function that has some special, Pub.dev dependencies. You can do all of that within Flutter Flow itself. And we're actually really excited soon. In a couple of weeks, we're releasing some really important improvements to custom code so that hopefully a lot more of the logic that you have already existing in your Flutter app can just work directly within Flutter Flow.

Vadym

People asking, I've already read the question, it's already also uploaded. People asking if we are going to lose a bit of joy of writing the code and understanding the code. Because, yeah, it's kind of part of excitement when you made it work.

Michael

Yeah, no, I hear that. I would say, I mean... I think each tool has its capabilities, right? So I find a lot of joy in doing the visual iteration. You can be really precise about kind of the UI experience, the UX, all the animations and stuff and iterate really quickly. So I find a lot of joy in that. And I think that's where the visual side excels. I found AI to be really helpful for when I'm like editing a code base that I don't know much about. Like it's brand new to me. I kind of have to ask a couple of questions to get oriented. And obviously when I'm like delving into areas, I don't quite know. And then I would say like where traditional just coding shines is really like, security or performance heavy applications that really need to be optimized and tweaked. And I just don't think the AI is quite there yet. So I think it really comes from choosing the right tool for the right purpose, basically.

Vadym

as Iverson, actually. And speaking about that application, your AI generates, have you had a chance to check the code?

Michael

A little bit, yeah. So like with Dreamflow?

Vadym

Yeah, yeah, yeah, that one. How it looks like?

Michael

It looks pretty good. I think, yeah, I mean, I'm biased, of course, but I mean, I encourage you to try it out because you'll see, I think it follows a lot of the standard conventions that you would expect.

Vadym

okay so as always as you said like we need to be good prompt engineers to ask specific things not just a way like I do this

Michael

and we've also seen that you know if you have like a 25 character prompt like a 200 character prompt is going to beat that one out in terms of actually achieving what you're asking it

Vadym

yeah and still related to that what kind of code flutter flow generate a dream flow i guess about clean code clean architecture stuff yeah

Michael

i think if you're familiar with um the way that flutter flow generates code i think that dream flow generates code uh slightly more towards um standards that Flutter and Dart developers are used to. And I think we do our best to inject the best practices, like I mentioned, in the prompts so that it's clean, it's readable, hopefully commented where you would expect it to be. But I found that in using Dreamflow, the generated code feels to me like a lot cleaner and more extensible.

Vadym

And probably we'll ask the last question from the most upvoted, but yeah, it's like, do you recommend, so be honest or be biased, I don't know. Do you recommend using Flutter Flow for business complicated and feature heavy applications? Business complicated, so it's a lot of business logic here.

Michael

it's a great question. I do. And the only reason I say that is because we have existing enterprise customers. We have major banks, major world banks that are using this. And I think it really comes down to the kind of the project organization, especially if you're working in a larger team, it makes sense. to organize your code base so that everyone has defined responsibilities, whether it's on the UI side or the logic side. And I think Flutter Flow is a tool that's really built really well for teams to collaborate like this. So I'd say give it a shot, but the proof is in the existing customers we have on the enterprise side who have been able to successfully ship apps way faster by using a visual tool

Vadym

to sell it even better can you give us names uh

Michael

yes i can although i'm forgetting if which ones we have announced and which ones we haven't um but i i believe access bank uh in india is is one that we've announced and um i know joe and the juice the the app is all built in flutterflow um there's plenty more on our uh showcase uh on our website but uh yeah it's I'd say it's also a really fun tool. So try it out.

Vadym

I believe you already sold it to me. Sold, sell, sell, sell. I see. Anyway, thank you, Michael. That's amazing. Thanks, FlutterFlow. Round of applause. Thank you so much. We're good. Thank you. Good to have you.

Edit on GitHub