Installing and Running¶
Flitter is implemented in a mix of Python and Cython and requires at least
OpenGL 3.3 (Core Profile) or OpenGL ES 3.0. At least Python 3.10 is also
required as the code uses match/case syntax. It is supported and tested on
Apple Silicon macOS, Intel macOS, x86_64 Linux and x86_64 Windows. It is also
known to build and run on AArch64 Linux, but no pre-built packages exist. It
will probably work on AArch64 Windows, but this has never been tested.
Flitter is a command-line tool. It is assumed that you are comfortable using the command line on your OS of choice. You will also obviously need to be able to ensure that you have a recent Python install. Sadly, even on macOS Sonoma the system installed Python is only at version 3.9. You can normally download Python for your OS from the Python website. However, you may want to explore a package manager that can manage this sort of thing for you, like Homebrew or MacPorts.
Installing Flitter¶
Installing from the pre-built wheels¶
If you are installing on one of the supported platforms then, good news!, you
can install one of the pre-built wheels in the flitter-lang PyPI
package with just:
$ pip3 install flitter-lang
Otherwise you are going to need to install from the source distribution.
It is recommended to do the install into a Python virtual environment as Flitter draws on quite a few dependencies (see below). This is especially important if you are using Python 3.12 or later as it will simply refuse to install packages into the system environment. This is generally something as simple as:
$ python3 -m venv ~/.virtualenvs/flitter
$ ~/.virtualenvs/flitter/bin/pip3 install flitter-lang
Alternatively, do a user install with:
$ pip3 install --user flitter-lang
Assuming your Python install is set up well for your operating system, this
should just put the flitter script into your path for you. However, if this
isn’t working (on Windows, for example, you may need to have checked a box
during install) then you can also run Flitter as a Python package with:
$ python3 -m flitter.engine path/to/some/flitter/script.fl
macOS and sRGB¶
Flitter assumes that OpenGL windows are in the sRGB colorspace. However, modern Macs generally have displays that support the wider Display-P3 colorspace, and macOS OpenGL windows will default to this.
This results in colors on macOS appearing more vivid than on other platforms.
Colors in windows will not match output saved to image and video files (which
are always tagged as being in the sRGB colorspace), and loaded images or video
will not display accurately. Colors calculated from calibrated color functions
(like colortemp() or oklch()) will also not be displayed accurately.
Flitter is capable of telling macOS to change the window colorspace to
sRGB, but will only do so if the optional, macOS-only libraries pyobjc and
pyobjc-framework-Cocoa are installed. You can install these manually, or
automatically if you install Flitter with:
$ pip3 install "flitter-lang[macos]"
Installing from the source package¶
As Flitter uses Cython under-the-hood, you’ll need a working build
environment with a C compiler. On macOS this means downloading
Xcode. On Windows you’ll need Visual
Studio. On a Debian-variant Linux box, all
you should need to do is install the python3-dev package:
$ sudo apt install python3-dev
If you’ve safely navigated getting a working Python development environment, you can do the build from source with exactly the same install command as above.
Installing from the repo:¶
If you want to live on the bleeding edge, then you can build the current
head of the main branch with:
$ pip3 install https://github.com/jonathanhogg/flitter/archive/main.zip
Running Flitter¶
If you’ve installed Flitter in a virtual environment, then you’ll need to ensure that the scripts/bin folder for that environment is in your system path. You can then run Flitter with a command like:
$ flitter path/to/some/flitter/script.fl
If you’ve done a local pip install instead then – with a little luck – the
scripts folder is already in your path. Otherwise, you might want to try running
Flitter as a Python package:
$ python3 -m flitter.engine path/to/some/flitter/script.fl
Flitter takes one or more program filenames as the main command-line arguments. If multiple programs are given then they are loaded into separate pages and the first will be executed. By default, you can switch between pages by pressing the left- and right-arrow keys while a window has focus. However, full control over page switching is actually part of the controller infrastructure of Flitter.
The supported command-line options are:
--helpSee a list of these options.
--quiet|--verbose|--debug|--traceChange the amount of logging that is written out, from least to most noisy.
--verboseis useful for getting some basic runtime statistics,--debugshows a little of what is going on under-the-hood,--traceis incredibly noisy as it logs lots of object allocation and deallocation activity.--fpsFPSSpecify a target frame-rate for the engine to try and maintain. This defaults to 60fps, but it’s useful to be able to lower it if you are running an especially complex script and would prefer to run evenly at a slower rate than to have stuttering. It’s also useful when recording video output. You can also control frame-rate via a pragma.
--defineNAME=VALUEThis allows a name to be bound to a constant value in the language interpreter. This is useful for controlling conditional behaviour in a program, such as enabling video output or changing the window size. VALUE may be either a string or a numeric vector, with items separated by semicolons. You will need to appropriately quote it on the command-line if using semicolons.
--screenSCREENAllows you to ask Flitter to open windows on a distinct screen number. This depends on your desktop setup, but generally screen 0 is the main one and they count upwards from there. Specific windows can also be placed on specific screens by adding a
screen=Nattribute to the!windownode. This option controls the default if that is not done.--fullscreenRequests that windows are opened full-screen by default. Again, this can be controlled on a per-window basis with the
fullscreen=trueattribute to a!windownode.--vsyncRequests that windows use vertical-sync double-buffering. Also the
vsync=trueattribute.--stateFILENAMEAsks Flitter to save the system state periodically to a file and load again from this. This allows you to retain state across multiple sessions. This was primarily designed as a safety measure for reacting quickly to a crash during a live performance. Thankfully, Flitter is pretty resilient to crashes, but there are still some edge-cases where a code change can confuse the engine.
--resetonswitchThrows away the internal system state when switching between different pages. Normally state is saved and restored when switching pages. Throwing the last state away can be useful if running in a kiosk mode where each page should begin again fresh.
--simplifystateSECONDSSets the period after which the language simplifier will simplify on static state values. The default is 10 seconds. Set this to
0to disable simplifying on state.--nosimplifyCompletely disable the language simplifier. Generally there is no reason to do this, but running the simplifier is the slowest part of loading Flitter code and so it may be useful if very fast switching is required – particularly if a program has very large loops that are being unrolled and there is insufficient gain from doing the unrolling.
--lockstepTurns on non-realtime mode. In this mode, the engine will generate frames as fast as possible (which may be quite slowly) while maintaining an evenly incrementing beat counter and frame clock. This is designed for saving video output from non-interactive programs. It also has a specific effect on how the physics system runs.
--runtimeSECONDSRun for a specific period of time and then exit automatically. This is particularly useful for capturing videos of a specific length unattended. In
--lockstepmode, this is a period of the internal frame clock not the wall clock.--offscreenRequests that all
!windownodes actually be silently interpreted as!offscreennodes. This has the effect of running Flitter without any visual output. You’ll still need a windowed environment. You can conspire to run on Linux without a real windowed environment usingXvfb(and the CI tests are run just this way), but you should know that the Mesa software rasterizer is very, very slow. Flitter really wants a GPU.--openglesThis tells Flitter to request the OpenGL ES API instead of OpenGL Core. You can use this on devices that do not support the full OpenGL API, or that are using a compatibility layer like ANGLE. At the moment,
!canvas2D drawing is not supported on OpenGL ES.--profileRuns the Python profiler around the main loop. See Profiling below for details.
--vmstatsTurns on logging of Flitter virtual machine statistics. This will slow down the interpreter by quite a lot. The statistics are written out on exit at the
INFOlogging level, which means you will also need to have at least--verboselogging turned on to see the results. Be wary of interpreting these statistics: the overhead of doing the timing can make very simple instructions that are executed millions of times appear to be a larger source of execution cost than they really are.
Developing Flitter¶
If you want to edit the Flitter code – or just want to keep up-to-date with
current developments – ensure that cython and setuptools are installed in
your runtime Python environment, clone the repo, do an editable package
deployment directly from the clone directory, and then throw away the compiled
files:
$ pip3 install cython setuptools
$ git clone https://github.com/jonathanhogg/flitter.git
$ cd flitter
$ pip3 install --editable .
$ rm src/**/*.c src/**/*.so
Flitter automatically makes use of pyximport to (re)compile Cython code
on-the-fly as it runs. This allows you to edit the code (or pull a new version
from the repo) and just re-run flitter to pick up changes.
The code is linted with flake8 and cython-lint:
$ pip3 install flake8 cython-lint
$ flake8 src tests scripts
$ cython-lint src
And the test suite can be run with pytest:
$ pip3 install pytest
$ pytest
Checking code coverage¶
If you want to run code coverage analysis, then you will need to do a special in-place build with coverage enabled (Cython line-tracing):
$ env FLITTER_BUILD_COVERAGE=1 python3 setup.py build_ext --inplace
Importantly, this will not work on Python 3.12 or 3.13. Python 3.12 introduced a change in the profiling API that Cython is not yet compatible with. You will need to do a parallel install of either 3.11 or 3.10 and create a second virtual environment in which to do coverage analysis.
Once you have a coverage-enabled build, you can generate a code coverage report for the test suite with:
$ pip3 install coverage
$ coverage run -m pytest
$ coverage report
You will need to re-run setup.py if you change any of the Cython code. You
will need to delete all of these object files if you want to go back to using
the normal pyximport automatic recompile (and you will want to do so as the
coverage-enabled version of the code is significantly slower).
Profiling¶
Flitter has built-in support for running itself with profiling turned on:
just add the --profile command line option when running it. This is best
combined with --lockstep and --runtime=N to run for exactly N seconds of
frame time. At the end of execution (including a keyboard interrupt), the
standard Python profiler output will be printed, ordered by tottime.
However, by default, the Cython modules are not compiled with profiling
support. This means that only pure Python functions will be listed in the
profiler, with all time spent inside Cython code aggregated into those
functions’ runtime. All of the Cython modules can be compiled with profiling by
setting the FLITTER_BUILD_PROFILE environment variable to 1 and running
setup.py:
$ env FLITTER_BUILD_COVERAGE=1 python3 setup.py build_ext --inplace
As for compiling with code coverage, profiling Cython code is currently not supported on Python 3.12 or 3.13. You will need to use 3.11 or 3.10 to run profiling tests.
Recompiling all Cython modules with profiling enabled may not be the best thing
to do as the overhead of adding profiling support to Cython is quite high and
the results will be skewed by the cost of the profiling. It is probably better
to only compile profiling support into the module(s) that you are considering.
This can be done with cythonize:
$ cythonize --build --inplace --force -3 --annotate -X profile=True \
src/flitter/render/window/canvas3d.pyx
Generating the documentation¶
To generate a local HTML copy of the documentation, install sphinx,
myst_parser and the separate flitter-pygments
package (which adds syntax
highlighting support for Flitter to pygments):
$ pip3 install sphinx myst_parser flitter-pygments
You can then generate the docs with:
$ sphinx-build docs build/html
They can then be read from build/html/index.html.
Python package dependencies¶
The first-level runtime Python package dependencies are listed below. These will
all be installed for you by pip, but it’s useful to know what you’re getting
into.
av- for encoding and decoding videoglfw- for OpenGL windowinglark- for the language parserloguru- for enhanced loggingmako- for templating of the GLSL sourcemanifold3d- for constructive solid geometry operationsmoderngl- for a higher-level API to OpenGLnetworkx- used bytrimeshfor graph algorithmsnumpy- for fast memory crunchingpillow- for saving screenshots as image filespyserial- for talking to DMX interfacespyusb- for low-level communication with the Push 2 and LaserCuberegex- used bylarkfor advanced regular expressionsrtmidi2- for talking MIDI to control surfacesscipy- used bytrimeshfor computing convex hullsskia-python- for 2D drawingtrimesh- for loading 3D meshes
During install, pip will also use:
cython- because half of Flitter is implemented in Cython for speedsetuptools- to run the build file