🎨

GraphX™

pub package style: effective dart License: MIT

| rendering | prototype | design |

Making drawings and animations in Flutter extremely simple.


WARNING: this lib is on alpha stage, some APIs might change in future releases.

Yet, it went through a lot of testing while making samples and prototypes, and I believe it can be usable for production apps!

NOTE: For now, GraphX™ uses the $ prefix convention for all internal and private members (properties and methods). DO NOT call them in your code... is meant to be consumed internally by the lib, it will remain as it is, at least initially, while the package takes shape.


wiki-tips.

To get some extended, boring explanations, and eventually some sample codes, check the GraphX™ Wiki


prototyping

GraphX is all about visuals, here you have some screen captures of random prototypes I've been doing, while developing and testing graphx.

artificial horizon parallax game charts pie color 2 simple particles drawing api playful v1

... jump to other gifs samples ...

Background.

GraphX™ is here to help you build custom drawings in your Flutter apps. Providing a great versatility to power those screen pixels to a different level.

It's inspired by the good-old Flash API, which forged my way into programming back in the days, and inspired many other rendering frameworks, in several languages through the years.

I was thinking how much I missed to "play" with code, to make things more organic, artistic, alive... I totally love Flutter, but I always feel that it requires too much boilerplate to make things move around (compared to what I used to code).

Even if GraphX™ is not an animation library (although has a small tween engine), nor a game engine, It can help you build really awesome user experiences! It just runs on top of CustomPainter... Using what Flutter SDK exposes from the SKIA engine through the Canvas, yet, gives you some "framework" to run isolated from the Widget's world.

Can be used to simple draw a line, a circle, maybe a custom button, some splash effect on your UI, or even a full-blown game in a portion of the screen.

Mix and match with Flutter as you please, as GraphX™ uses CustomPainter, it is part of your Widget's tree.

Concept.

This repo is a very early WIP ... the library still lacks of support for loading remote assets, 2.5 transformation and some other niceties.

Yet, it has a ver basic support for loading rootBundle assets:

AssetLoader.loadBinary(assetId)  
AssetLoader.loadGif(assetId)  
AssetLoader.loadTextureAtlas(imagePath, xmlPath)  
AssetLoader.loadTexture(assetId)  
AssetLoader.loadImage(assetId)  
AssetLoader.loadString(assetId)  
AssetLoader.loadJson(assetId)  

GraphX™ also provides basic "raw" support for Text rendering, using the StaticText class.


How does it work?

GraphX™ drives a CustomPainter inside. The idea is to simplify the usage of Flutter's Canvas, plus adding the display list concept, very similar to the Widget Tree concept; so you can imperatively code, manage and create more complex "Scenes".

The library has its own rendering cycle using Flutter's Ticker (pretty much like AnimationController does), and each SceneWidgetBuilder does its own input capture and processing (mouse, keyboard, touches). Even if it runs on the Widget tree, you can enable the flags to capture mouse/touch input, or keystrokes events (if u wanna do some simple game, or desktop/web tool).

Sample code.

  body: Center(
    child: SceneBuilderWidget( /// wrap any Widget with SceneBuilderWidget
      builder: () => SceneController.withLayers(
        back: GameSceneBack(), /// optional provide the background layer
        front: GameSceneFront(), /// optional provide the foreground layer
      ),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text(
            'You have pushed the button this many times:',
          ),
          Text(
            '$_counter',
            style: Theme.of(context).textTheme.headline4,
          ),
        ],
      ),
    ),
  ),

GraphX™ is based on "Scenes" layers, each SceneBuilderWidget requires a SceneController. This controller is the "initializer" of the Scenes layers, which can be:

  • back (background painter),
  • front (foreground painter),
  • or both.

Also takes a SceneConfig(), so you can configure what you need from the Widget's side. You can make use of some predefined Scene configurators:

  • SceneConfig.static: If you plan to only use this scene to draw some graphics, like a background.
  • SceneConfig.games: Activates all GraphX features, auto render and update, pointers and keyboard support.
  • SceneConfig.tools: Shortcut of games, helpful if you wanna use it in some custom drawing editor, or similar with keyboard shortcuts.
  • SceneConfig.interactive (default): Probably the most common setup for mobile, enables all features except keyboard support.
  • SceneConfig.autoRender: Allows you to have a ticker running, and auto update the scene, with NO inputs (mouse/touch/keyboard), if you wanna have an animated Widget, or maybe if you wanna control it externally.

Each "Scene Layer" has to Sprite, this root class represents the starting point of that particular scene hierarchy. Think of it as MaterialApp widget is to all other children Widgets in the tree.

Here we get into GraphX™ world, no more Widgets Trees or immutable properties. According to the SceneConfig you pass down, you will have different capabilities. You can make custom UI widgets, games, or make use of GraphX to create a static drawing, like curved backgrounds, or complex shapes.

Is a good practice to override addedToStage() as your entry point, here the Scene engine is ready, the root class has been added to the stage, so the glorified Stage will be available to use:

class GameScene extends Sprite {
  
  @override
  void addedToStage() {
    /// Here you can access the `stage`, get the size of the
    /// current Scene, keyboard events, or any stage property
    /// You can initialize your DisplayObjects here to play
    /// "safe" if you need to access any stage property.
  }

For now, GraphX™ has a few classes for rendering in the "display list": Like Shape (for "pen" drawings commands through it's graphics property), Sprite (create hierarchies of rendering objects), StaticText (for Texts), GxIcon (for Flutter icons), Bitmap (for Images), MovieClip(for Spritesheet and Gif support), SvgShape (dependency for svg package not included), SimpleParticleSystem (to create optimized particles for games), and Flare/Rive render objects which will live in another package/utility to avoid dependencies.

By the way, in the previous example, GameScene is the root node in the display tree, the entry point where DisplayObjects renders, and where you need to add your own objects.

For instance, to create a simple purple circle:

@override
void addedToStage(){
    var circle = Shape();
    circle.graphics.lineStyle(2, Colors.purple.value) /// access hex value of Color
      ..drawCircle(0, 0, 20)
      ..endFill();
    addChild(circle); // add the child to the rootScene.
}

Sprite internally extends from the abstract class DisplayObjectContainer, and as the name implies, can have other children inside, yet Shape is a DisplayObject, and can't have children. That makes it a bit more performant on each painter step.

We could also use our root scene to draw things:

@override
addedToStage(){
  graphics.beginFill(0x0000ff, .6)
  ..drawRoundRect(100, 100, 40, 40, 4)
  ..endFill();
...
}

Pointer signals has been "simplified" as Mouse events now... as it's super easy to work with single touch / mouse interactions in DisplayObjects. There are a bunch of signals to listen on each object... taken from AS3, and JS.

  • onMouseDoubleClick
  • onMouseClick
  • onMouseDown
  • onMouseUp
  • onMouseMove
  • onMouseOver
  • onMouseOut
  • onMouseScroll

They all emit a MouseInputData with all the needed info inside, like stage coordinates, or translated local coordinates, which "mouse" button is pressed, etc.


I will keep adding further explanation in the upcoming days.

Demos.

Some demos are only using GraphX™ partially, and might have big CPU impact

Flutter widget mix

Split RGB

Input Text particles

FishEye particles

FishEye particles (basic)

Particles emitter

ShapeMaker clone

Mouse follower

basic hit test

SpriteSheet rendering

DisplayObject Pivot

Simple solo-ping-pong game

First Experimentation with rendering

Color spectrum (based on SuperDeclarative! workshop)

UI Line Button


Feel free to play around with the current API, even if it's still rough on edges and unoptimized, it might help you do things quicker.

SKIA is pretty powerful!


help & socialize.

DiscordTelegram
Discord ShieldTelegram

Screencast Demos.

(Some demos uses GraphX's only for ticker, input events or initial scene graph, making usage of direct Canvas calls)._


Donation

You can buymeacoffee or support GraphX™ via Paypal

Donate via PayPal

Support via buymeacoffee

Resources to get you started if this is your first Flutter project:

For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.

Libraries

graphx