Skip to main content

Line-based geometry toolkit with chained effects and real-time preview.

Project description

Grafix

Grafix is a Python-based creative coding framework compatible with pen plotter.

Grafix demo

Press G at any time while a sketch is running to export a G-code (.gcode) file.

pen plotter art example

Installation

pip install grafix

macOS-first. Tested on macOS (Apple Silicon). Other platforms are not officially supported yet.

Quick start

from grafix import E, G, run


def draw(t: float):
    # All arguments automatically appear in the parameter GUI
    geometry = G.polyhedron()
    effect = E.fill().subdivide().displace().rotate(rotation=(t * 6, t * 5, t * 4))
    return effect(geometry)


if __name__ == "__main__":
    run(draw, canvas_size=(148, 210), render_scale=5.0)

Examples

grn 1 grn 2 grn 3
grn 4 grn 5 grn 6
grn 7 grn 8 grn 9
grn 10 grn 11 grn 12
grn 13 grn 14 grn 15

Core API

  • G lets you generate primitives such as sphere, polyhedron, grid, and more.
  • E lets you modulate primitives such as affine, fill, repeat, and more.
  • run lets you render a user-defined draw(t) function on each frame.

Optional features

  • L lets you define layers (stroke color, thickness, etc.).
  • cc lets you map MIDI CC messages to any parameter.
  • @primitive lets you register custom primitives (they become available under G).
  • @effect lets you register custom effects (they become available under E).
  • @preset lets you register reusable components (only selected params are exposed to the Parameter GUI).
  • P lets you call registered presets as P.<name>(...).
  • Export provides a headless export entrypoint.
  • Parameter GUI lets you tweak parameters live while the sketch is running.
  • Keyboard shortcuts let you export output quickly:
    • P saves a .png image
    • S saves a .svg file
    • V records an .mp4 video
    • G saves a .gcode file for pen plotters

Extending (custom primitives / effects)

You can register your own primitives and effects via decorators:

from grafix.api import effect, primitive


@primitive
def user_prim(*, r=10.0):
    ...


@effect
def user_eff(inputs, *, amount=1.0):
    ...

Notes:

  • Built-in primitives/effects must provide meta=... (enforced).
  • For user-defined ops, meta is optional. If omitted, parameters are not shown in the Parameter GUI.

Presets (reusable components)

Use @preset to register a component, and call it via P.<name>(...):

from grafix import P, preset


@preset(meta={"scale": {"kind": "float", "ui_min": 0.1, "ui_max": 10.0}})
def grid_system_frame(*, n_rows: int=5, r_cols: int=8, name=None, key=None):
    ...


P.grid_system_frame()

For IDE completion of P.<name>(...), regenerate stubs after adding/changing presets:

python -m grafix stub

Configuration

A config.yaml lets you locate external fonts and choose where Grafix writes runtime outputs (.svg, .png, .mp4, .gcode).

Grafix starts from the packaged defaults (grafix/resource/default_config.yaml) and then overlays user configs.

Config overlay order (later wins):

  • packaged defaults: grafix/resource/default_config.yaml
  • ./.grafix/config.yaml (project-local)
  • ~/.config/grafix/config.yaml (per-user)
  • run(..., config_path="path/to/config.yaml")

Paths support ~ and environment variables like $HOME.

To create a project-local config (starting from the packaged defaults):

mkdir -p .grafix
python -c "from importlib.resources import files; print(files('grafix').joinpath('resource','default_config.yaml').read_text())" > .grafix/config.yaml
$EDITOR .grafix/config.yaml

Config overlay is a top-level shallow update (no deep merge). If you override export:, keep both export.png and export.gcode blocks from the packaged defaults.

To autoload user presets from a directory:

paths:
  preset_module_dirs:
    - "sketch/presets"

To configure G-code export defaults (used when calling export_gcode(..., params=None)):

export:
  gcode:
    origin: [0.0, 0.0]
    y_down: false

To prioritize MIDI device connections when using midi_port_name="auto":

midi:
  inputs:
    - port_name: "Grid"
      mode: "14bit"
    - port_name: "TX-6 Bluetooth"
      mode: "7bit"
    - port_name: "auto"
      mode: "7bit"

Not implemented yet

  • LFOs to modulate any parameters with rhythm

Development

Geometry (the core data model)

Grafix is built around an immutable Geometry node, which represents a recipe (not yet realized polylines). Nodes form a DAG (directed acyclic graph):

  • op: the operator name (primitive/effect/concat are stored uniformly)
  • inputs: child Geometry nodes (empty for primitives)
  • args: normalized (name, value) pairs
  • id: a content-based signature derived from (op, inputs, args)

Primitives (G.*) create leaf Geometry nodes. Effects (E.*) take one or more input Geometrys and return a new Geometry that references them. Chaining operations in draw(t) builds the DAG.

When parameter_gui is enabled, the GUI edits the parameters (args) of ops. Updating a parameter creates new Geometry nodes with new ids, while unchanged subgraphs keep their ids — which makes caching/reuse straightforward during interactive previews.

RealizedGeometry (what primitives/effects compute)

Evaluating the Geometry DAG produces RealizedGeometry, a compact polyline representation:

  • coords: np.ndarray of float32, shape (N, 3) (x, y, z). A 2D (N, 2) array is also accepted (z=0 is implied).
  • offsets: np.ndarray of int32, shape (M+1,), where polyline i is coords[offsets[i]:offsets[i+1]]. offsets[0] is 0 and offsets[-1] equals N.

Custom primitives return a RealizedGeometry. Custom effects take Sequence[RealizedGeometry] (usually 1 input) and return a new RealizedGeometry. Treat input arrays as immutable (writeable=False) and avoid in-place mutation.

Dev tools (optional):

pip install -e ".[dev]"

Run a sketch:

python sketch/readme.py

List built-in ops:

python -m grafix list effects
python -m grafix list primitives
python -m grafix list

Regenerate API stubs (for P.<name>(...) completion):

python -m grafix stub

Headless export (PNG):

python -m grafix export --callable your_module:draw --t 0.0
python -m grafix export --callable your_module:draw --t 0.0 1.0 2.0 --out-dir data/output

Note: --callable module:attr follows Python import rules (make sure the module is importable from your current working directory / PYTHONPATH).

Benchmark (effect perf + report):

python -m grafix benchmark -- --help

Dependencies

Core (default):

  • numpy
  • numba
  • shapely
  • pyclipper
  • moderngl
  • pyglet
  • imgui
  • fontPens
  • fontTools
  • PyYAML
  • mido
  • python-rtmidi
  • psutil

External:

  • resvg (svg to png)
  • ffmpeg (video encoding)

Dev (optional):

  • pytest
  • ruff
  • mypy

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

grafix-0.0.5.tar.gz (3.5 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

grafix-0.0.5-py3-none-any.whl (3.6 MB view details)

Uploaded Python 3

File details

Details for the file grafix-0.0.5.tar.gz.

File metadata

  • Download URL: grafix-0.0.5.tar.gz
  • Upload date:
  • Size: 3.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for grafix-0.0.5.tar.gz
Algorithm Hash digest
SHA256 d90c77abcaef1b92329eda1ebd2c1bdd07365b7a31b2eaeeb708ea61758af007
MD5 f83fc91a3364287ab96a970539b78ce8
BLAKE2b-256 27263d9dc586ec18d35269f9a8700f5dd7c0623ef5076315d03658f1d9922d77

See more details on using hashes here.

File details

Details for the file grafix-0.0.5-py3-none-any.whl.

File metadata

  • Download URL: grafix-0.0.5-py3-none-any.whl
  • Upload date:
  • Size: 3.6 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for grafix-0.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 1342e3acc62eed93ed048e8ae025617ef7e45771efe87a6068891c395b8f30e5
MD5 fbd7908503d6bd9a3951ff6b07d69c64
BLAKE2b-256 88ff9ac8931987412bd410b163f716b83e465d597ff46e90fcc2b8792b1865e8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page