Is there a good option for rendering static images from Flutter code?

Once in a while, I need to create some kind of diagram or graphic for things like docs, presentations, videos, or even emails.

Example:

The obvious choice is to use proprietary software for this: Google Slides, Lucidchart, Omnigraffle, MS Visio, Canva, Cavalry… Then take a screenshot and you’re done.

But sometimes, you want something that’s more evergreen and editable. E.g. if you’re making a diagram for an open source project, it’s not great to say “this diagram was made in Lucidchart”. When someone wants to edit it down the line (because something in the chart must inevitably be updated), they have to either recreate the chart from scratch, or buy a Lucidchart licence.

EDIT 2024-11-29 16:41 Additionally, sometimes you want to be able to scale your diagram creation. Maybe you want to update the diagram automatically with every commit. Or you want to generate 50 diagrams and keep all of them in sync with each other.

So you’d want to have an option of using an open source project that also has a human-readable (and human-editable) source syntax.

The traditional options are LaTeX and (maybe?) SVG.

  • SVG is technically human-readable, but if you’re trying to make something even a little bit complex, it’s super annoying. For example, if you decide that an element in your diagram needs to be a bit to the right, you have to manually move it and also update the positions of every other element whose position relates to it (e.g. an arrow that was pointing at the element). I wouldn’t want to manually edit any SVG that’s more than a few boxes with text in them.
  • LaTeX is ancient and it shows. While powerful, it’s also full of idiosyncracies. You need “packages” for almost anything. Many distributions of LaTeX lack support for basics things such as non-latin character. (Try printing ¯\_(ツ)_/¯ in your LaTeX distribution.) Things that should be easy are hard. And the whole system is optimized for generating PDFs (papers), not standalone graphics. Yes, there are solutions for everything but things are really complicated. Moreover, installations of LaTeX are several gigabytes in size (mine’s 9GB).

Most of the time, what I really want, is to write a tiny “app” in Flutter, and then run a command such as flutter_render lib/main.dart -o image.png and be done.

I realize there are golden tests. But these are hard to set up and have limitations (e.g. not rendering text correctly). I also realize I can create an app that takes a screenshot of itself (with RenderRepaintBoundary.toImage()) — but that’s a lot of boilerplate and you have to actually launch the app somehow.

Does anyone have a solution for this? Even if it’s a hack on top of Flutter driver, or even if it’s a semi-standardized RenderRepaintBoundary boilerplate, I’d love to see it.

If there’s nothing like that, then — well — here’s another idea for a side project. :face_holding_back_tears:

3 Likes

Not a dart option, but manim is quite handy for diagrams like that one. It’s an animation engine but can be used for programmatic diagrams too. A flutter version of that sounds really fun to build

1 Like

Maybe one of these domain languages can suit your needs?

If so, maybe there is already a package that implement those languages in Flutter. If not, “here’s another idea for a side project.” (by filip)

Example in D2:

vars: {
  d2-config: {
    layout-engine: elk
    # Terminal theme code
    theme-id: 300
  }
}
network: {
  cell tower: {
    satellites: {
      shape: stored_data
      style.multiple: true
    }

    transmitter

    satellites -> transmitter: send
    satellites -> transmitter: send
    satellites -> transmitter: send
  }

  online portal: {
    ui: {shape: hexagon}
  }

  data processor: {
    storage: {
      shape: cylinder
      style.multiple: true
    }
  }

  cell tower.transmitter -> data processor.storage: phone logs
}

user: {
  shape: person
  width: 130
}

user -> network.cell tower: make call
user -> network.online portal.ui: access {
  style.stroke-dash: 3
}

api server -> network.online portal.ui: display
api server -> logs: persist
logs: {shape: page; style.multiple: true}

network.data processor -> api server

Result:
image

1 Like

Thanks for reminding me of Manim. As a big fan of 3Blue1Brown, I’m definitely going to try that. Hopefully there’s an “export single image” option.

2 Likes

While I’m a fan of diagram scripting languages in general, and they do get me 90% there, my experience (mainly with DOT) is that they don’t provide enough fine-grained control. They’re fantastic when you want to show a nice binary tree or a Gantt chart from an abstract description, but they get clunky when you want to build something exact (e.g. the diagram in my original post). Maybe I should give them another try, though. Do you recommend one?

@filip I whipped up a quick package , needs more work to actually be nice to use but its there if you wanna take a look

Not quite a CLI tool yet, but you can write a file like

void main() {
  run();
}

void run() async {
  const scene = SizedBox(
    width: 640,
    height: 480,
    child: MathScene(
      shapes: [
        Circle(center: Offset(20, 20), radius: 10),
        Vector(source: Offset(30, 30), dest: Offset(50, 50))
      ],
    ),
  );

  await Mathviz.render(scene);
}

and running flutter run -d macos (For now) will give you this image.

Another caveat is that at present this file needs to be run inside a flutter project, need to dive into the rendering pipeline to see if that can be done away with

1 Like

https://3b1b.github.io/manim/getting_started/configuration.html#some-useful-flags

The -so option lets you skip the animation and output the last frame

1 Like

Would mermaid be something that fulfills these requirements? As of now there’s no good Dart implementation, and the ones I’ve seen realistically rely on either rendering a webview or running command line on the server etc.

Do you recommend one?

Don’t know if it will do exactly what you want (the extra 10%) but, hey, it’s a start.

Matt built an implementation of the Processing graphics language in Flutter: flutter_processing | Flutter package

I didn’t know 3blue1brown, thanks for this! :star_struck:

1 Like