What you get
One Dart file. Every widget lands in a Positioned inside a Stack at the x and y you drew, so Flutter's flex system never gets the chance to reinterpret your layout.
import 'package:flutter/material.dart';
class Reminders extends StatefulWidget {
const Reminders({super.key});
@override
State<Reminders> createState() => _RemindersState();
}
class _RemindersState extends State<Reminders> {
late TextEditingController _c3;
double _h3 = 96.0;
@override
void initState() {
super.initState();
_c3 = TextEditingController(text: '')..addListener(_measure3);
_measure3();
}
@override
void dispose() {
_c3.dispose();
super.dispose();
}
void _measure3() {
final tp = TextPainter(
text: TextSpan(
text: _c3.text.isEmpty ? ' ' : _c3.text,
style: const TextStyle(fontFamily: 'Inter', fontSize: 16),
),
maxLines: null,
textDirection: TextDirection.ltr,
)..layout(maxWidth: 254);
final h = tp.height + 20 < 96.0 ? 96.0 : tp.height + 20;
if (h != _h3) setState(() => _h3 = h);
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: SizedBox(
width: 390.0,
height: 844.0 + ((_h3 - 96.0)),
child: Stack(
children: [
Positioned.fill(child: Container(color: Color(0xFFFFFFFF))),
Positioned(
left: 24,
top: 64,
child: SizedBox(
width: 200,
height: 28,
child: Text(
'Reminders',
textAlign: TextAlign.left,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 22,
color: Color(0xFF17171A),
height: 1.3,
fontWeight: FontWeight.w700,
),
),
),
),
Positioned(
left: 24,
top: 112,
child: Container(
width: 220,
height: 96,
decoration: BoxDecoration(
color: Color(0xFF2A50D8),
borderRadius: BorderRadius.circular(16),
),
),
),
Positioned(
left: 24,
top: 232,
child: Container(
width: 280,
height: _h3,
decoration: BoxDecoration(
color: Color(0xFFFFFFFF),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Color(0xFFE4E1D8), width: 1),
),
child: TextField(
controller: _c3,
maxLines: null,
textAlign: TextAlign.left,
style: TextStyle(
color: Color(0xFF17171A),
fontFamily: 'Inter',
fontSize: 16,
),
decoration: InputDecoration(
hintText: 'Add a note...',
hintStyle: const TextStyle(color: Color(0xFF9CA3AF)),
border: InputBorder.none,
isDense: true,
contentPadding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 10,
),
),
),
),
),
],
),
),
);
}
}It builds, and we check
Generated Flutter passes flutter analyze cleanly and flutter build web succeeds, both run against the real Flutter SDK via a dedicated verification suite (npm run verify:native) that runs outside the fast test suite because it needs the Flutter SDK installed. Code that analyses clean is a lower bar than code that builds, so we check both.
Which devices offer it
Flutter is offered for phone and tablet presets, macOS and Windows, and generic artboards. Not watchOS.
What it handles
Text outlines. A border on a text layer is an outline around the letters, not a box around them. Flutter strokes real glyph outlines through TextStyle.foreground with PaintingStyle.stroke, stacked under a fill copy, so the outline is exact rather than approximated, and matches the canvas at any width. (The React Native and SwiftUI exports approximate this instead, because neither has a text-stroke API.)
Placement. Positioned(left:, top:) inside a Stack, at your literal coordinates.
Multiline inputs that grow. A multiline TextField has its height measured live, matching its own font, size, and width, and grows to fit what the user types. Elements below move down by the same amount.
Scrolling. The screen wraps in a SingleChildScrollView sized to the full content height when content is taller than the device, and also whenever the design contains a multiline field, even if everything currently fits. The field can outgrow the device once someone types into it.
What it does not handle
- No responsive layout. No
LayoutBuilder, no breakpoints, noMediaQuery-driven branching. - No horizontal scrolling.
- watchOS is not a Flutter target.
Working with the output
Plain Dart, straight into your lib/. Nothing to install and no dependency on us.
The generated class is a StatelessWidget until the design contains a multiline field, at which point it becomes a StatefulWidget with a TextEditingController and a measured height per field. Widget names come from your canvas layer names, camelCased; unnamed shapes become shape1, shape2, and so on.
A Stack of Positioned widgets is not how a Flutter developer would hand-write a screen, and that is the deliberate trade. You are getting the canvas exactly, in exchange for output that is positional rather than idiomatic. If you need conventional flex layout, this is the wrong generator and our comparison pages are honest about who does that better.