API Reference#

flowerevolver#

Every class and free function here is bound directly from the C++ core (src/bindings/python/*.cpp) via nanobind - the same code path the JS/WASM API’s FEService and the native C++ library’s include/fe/FlowerEvolver.hpp both go through, so behavior (and, for Flower/DNA’s JSON, wire format) matches across all three.

FlowerEvolver - generates 2D/3D flowers from CPPN genomes evolved via EvoAI.

Native Python bindings (nanobind) around the same C++ core that powers the JS/WASM API and the native desktop app – genomes and rendered images round-trip with both (see Flower.to_json()/from_json()).

Quick start:

from flowerevolver import make_flower

flower = make_flower(radius=64, num_layers=3, P=6.0, bias=1.0) flower.petals.image.to_png_bytes() # -> bytes, ready to write to disk flower.to_json() # -> str, the genome

class flowerevolver.DNA(*args, **kwargs)#

Bases: object

The genome underlying a Flower - a small collection of CPPN genomes (a stats genome plus another for petals), evolved via EvoAI. Most code creates these indirectly, through make_flower()/reproduce()/mutate() rather than by hand. Individual genomes aren’t exposed to Python (EvoAI::Genome has no binding of its own) – treat DNA as an opaque, sized container.

clear(self) → None#

Removes every genome, leaving size() == 0.

distance = <nanobind.nb_func object>#
from_json = <nanobind.nb_func object>#
get_fitness(self) → float#

Reads back the fitness set via set_fitness() (from genome[0]); 0.0 if this DNA is empty.

mutate(self, rates: flowerevolver._core.MutationRates) → None#

Mutates every existing genome in place (topology and weights), according to rates. This never adds or removes genomes – size() before and after is always identical; what changes is each genome’s internal structure, not how many there are.

reproduce = <nanobind.nb_func object>#
set_fitness(self, fitness: float) → None#

Applies the same fitness value to every genome this DNA holds.

size(self) → int#

Number of genomes this DNA holds.

to_json(self) → str#

Serializes to a compact JSON string – this DNA’s own genomes array, not wrapped in the outer {“Flower”: …} shape Flower.to_json() produces (a bare DNA isn’t a complete, renderable Flower on its own). Round-trips with DNA.from_json().

class flowerevolver.Effects(*args, **kwargs)#

Bases: object

Per-stat effect strengths derived from the genome, roughly -100..100 each.

property agility#

(self) -> float

property intelligence#

(self) -> float

property luck#

(self) -> float

property strength#

(self) -> float

property vitality#

(self) -> float

class flowerevolver.Flower(*args, **kwargs)#

Bases: object

A complete flower: its genome (dna) and rendered image (petals). Usually created via make_flower()/reproduce()/mutate() rather than constructed directly.

property dna#

(self) -> flowerevolver._core.DNA

from_json = <nanobind.nb_func object>#
property petals#

(self) -> flowerevolver._core.Petals

to_json(self) → str#

Serializes to the same {“Flower”: {“dna”: …, “petals”: …}} JSON shape used throughout this project’s ecosystem (the JS/WASM API, the native desktop app, Generation.json/Session.json’s own per-flower entries) – round-trips with Flower.from_json(), and interoperates with genomes saved by any of those.

class flowerevolver.Image(*args, **kwargs)#

Bases: object

A simple RGBA pixel buffer - what Flower.petals.image and every draw_*()/make_*() call’s rendered output is. Pixel colors are plain (r, g, b, a) tuples of 0-255 ints, not a separate bound Color type.

create(self, width: int, height: int, color: tuple[int, int, int, int]) → None#

Allocates a width x height buffer, filled with color (r, g, b, a).

get_pixel(self, x: int, y: int) → tuple[int, int, int, int]#

Returns the (r, g, b, a) color at (x, y); (0, 0, 0, 0) if out of range.

property height#

(self) -> int

set_pixel(self, x: int, y: int, color: tuple[int, int, int, int]) → None#

Sets the pixel at (x, y) to color (r, g, b, a). Out-of-range x/y are silently ignored (matches the C++ API – see setPixel’s own bounds-check comment in src/fe/Image.cpp).

to_png_bytes(self) → bytes#

Encodes to an in-memory PNG and returns it as bytes – e.g. pathlib.Path(‘flower.png’).write_bytes(image.to_png_bytes()).

property width#

(self) -> int

class flowerevolver.MutationRates(*args, **kwargs)#

Bases: object

Rates controlling how DNA.mutate()/mutate() perturbs a genome. Every parameter is independent – a given mutation call can add a node, add a connection, and perturb weights all at once, each gated by its own rate below.

property act_type_rate#

Rate to change a neuron’s activation function.

property add_conn_rate#

Rate to add a new connection.

property add_node_rate#

Rate to add a new node.

property disable_rate#

Rate to disable a currently-enabled gene.

property enable_rate#

Rate to enable a currently-disabled gene.

property perturb_weights_rate#

Rate to change the weight of a connection.

property remove_conn_rate#

Rate to remove an existing connection.

class flowerevolver.Petals(*args, **kwargs)#

Bases: object

The rendered-image half of a Flower (Flower.petals) - the generation parameters that produced it, plus the resulting image.

property P#

(self) -> float

property bias#

(self) -> float

property has_bloom#

(self) -> bool

property image#

(self) -> flowerevolver._core.Image

property num_layers#

(self) -> int

property radius#

(self) -> int

class flowerevolver.PetalsType(*values)#

Bases: Enum

Which part of a flower to render - passed to some of the lower-level make_*()/draw_*() calls.

TRUNK = 0#
PETALS = 1#
TRUNK_AND_PETALS = 2#
class flowerevolver.Sex(*values)#

Bases: Enum

MALE = 0#
FEMALE = 1#
BOTH = 2#
class flowerevolver.Stats(*args, **kwargs)#

Bases: object

Environment-dependent stats derived from a flower’s genome - see get_flower_stats().

property effects#

(self) -> flowerevolver._core.Effects

property health#

(self) -> int

property maturation_period#

(self) -> int

property max_temperature#

(self) -> int

property min_temperature#

(self) -> int

property sex#

(self) -> flowerevolver._core.Sex

property stamina#

(self) -> int

property toxicity_rate#

(self) -> float

Free functions#

flowerevolver.make_flower(radius: int, num_layers: int, P: float, bias: float) → flowerevolver._core.Flower#

Generates a brand new, random flower.

Parameters:
  • radius – pixel radius, clamped to [4, 256].

  • num_layers – clamped to [1, floor(log2(radius))].

  • P – controls roughly how many petals the flower can have.

  • bias – bias fed into the CPPN alongside radius/angle/layer.

Returns:

a Flower – .to_json() for the genome, .petals.image for the render.

flowerevolver.make_petals(radius: int, num_layers: int, P: float, bias: float) → flowerevolver._core.Flower#

Same as make_flower(), but renders just the petals (no stem).

flowerevolver.make_petal_layer(radius: int, num_layers: int, P: float, bias: float, layer: int) → flowerevolver._core.Flower#

Same as make_flower(), but renders just one petal layer (no stem).

Parameters:

layer – which layer to render, 0-indexed from the outermost.

flowerevolver.make_stem(radius: int, num_layers: int, P: float, bias: float) → flowerevolver._core.Flower#

Same as make_flower(), but renders just a stem (no petals).

flowerevolver.draw_flower(dna: flowerevolver._core.DNA, radius: int, num_layers: int, P: float, bias: float) → flowerevolver._core.Image#

Renders an existing DNA (e.g. from Flower.dna, or DNA.from_json()) instead of generating a new one.

Parameters:
  • dna – the genome to render; needs at least 2 genomes.

  • radius – pixel radius, clamped to [4, 256].

  • num_layers – clamped to [1, floor(log2(radius))].

  • P – controls roughly how many petals the flower can have.

  • bias – bias fed into the CPPN alongside radius/angle/layer.

Returns:

the rendered Image.

Raises:

ValueError – if dna has fewer than 2 genomes.

flowerevolver.draw_petals(dna: flowerevolver._core.DNA, radius: int, num_layers: int, P: float, bias: float) → flowerevolver._core.Image#

Same as draw_flower(), but renders just the petals (no stem).

flowerevolver.draw_petal_layer(dna: flowerevolver._core.DNA, radius: int, num_layers: int, P: float, bias: float, layer: int) → flowerevolver._core.Image#

Same as draw_flower(), but renders just one petal layer (no stem).

Parameters:

layer – which layer to render, 0-indexed from the outermost.

flowerevolver.reproduce(dna1: flowerevolver._core.DNA, dna2: flowerevolver._core.DNA, radius: int, num_layers: int, P: float, bias: float) → flowerevolver._core.Flower#

Breeds two genomes into a rendered child Flower. For crossover only, with no rendering, see DNA.reproduce() instead.

Parameters:
  • dna1 – the father’s genome.

  • dna2 – the mother’s genome; must have the same number of genomes as dna1.

  • radius – pixel radius, clamped to [4, 256].

  • num_layers – clamped to [1, floor(log2(radius))].

  • P – controls roughly how many petals the flower can have.

  • bias – bias fed into the CPPN alongside radius/angle/layer.

Raises:

RuntimeError – if dna1 and dna2 don’t have the same number of genomes.

flowerevolver.mutate(dna: flowerevolver._core.DNA, radius: int, num_layers: int, P: float, bias: float, add_node_rate: float = 0.20000000298023224, add_conn_rate: float = 0.30000001192092896, remove_conn_rate: float = 0.20000000298023224, perturb_weights_rate: float = 0.6000000238418579, enable_rate: float = 0.3499999940395355, disable_rate: float = 0.30000001192092896, act_type_rate: float = 0.4000000059604645) → flowerevolver._core.Flower#

Mutates a copy of dna and renders the result – dna itself is left untouched.

Parameters:
  • dna – genome to mutate; needs at least 2 genomes.

  • radius – pixel radius, clamped to [4, 256].

  • num_layers – clamped to [1, floor(log2(radius))].

  • P – controls roughly how many petals the flower can have.

  • bias – bias fed into the CPPN alongside radius/angle/layer.

  • add_node_rate – rate to add a new node.

  • add_conn_rate – rate to add a new connection.

  • remove_conn_rate – rate to remove an existing connection.

  • perturb_weights_rate – rate to change a connection’s weight.

  • enable_rate – rate to enable a currently-disabled gene.

  • disable_rate – rate to disable a currently-enabled gene.

  • act_type_rate – rate to change a neuron’s activation function.

Raises:

ValueError – if dna has fewer than 2 genomes.

flowerevolver.make_3d_flower(dna: flowerevolver._core.DNA, radius: int, num_layers: int, P: float, bias: float, flower_id: str, flower_params: str = '') → str#

Generates a 3D flower model.

Parameters:
  • dna – the genome to render; needs at least 2 genomes.

  • radius – pixel radius, clamped to [4, 256].

  • num_layers – clamped to [1, floor(log2(radius))].

  • P – controls roughly how many petals the flower can have.

  • bias – bias fed into the CPPN alongside radius/angle/layer.

  • flower_id – a unique string identifying this flower (used in the model’s own group names).

  • flower_params – JSON string, e.g. ‘{“sex”: 2, “useNormals”: true, “useEmissive”: false}’; “” for defaults.

Returns:

the 3D model as a glTF 2.0 JSON string.

Raises:

ValueError – if dna has fewer than 2 genomes, or radius/num_layers/flower_id are invalid.

flowerevolver.get_flower_stats(genome: str, humidity: float, temperature: int, altitude: int, terrain_type: int) → flowerevolver._core.Stats#

Derives environment-dependent Stats from a flower’s genome.

Parameters:
  • genome – a Flower.to_json()-shaped JSON string.

  • humidity – 0.0 to 1.0.

  • temperature – degrees, same scale as the resulting Stats’ min_temperature/max_temperature.

  • altitude – meters above sea level.

  • terrain_type – terrain type id.

Raises:
  • ValueError – if genome doesn’t contain a DNA with at least 2 genomes.

  • RuntimeError – if genome is malformed JSON entirely.

flowerevolver.get_version() → str#

The semver this extension was built from, e.g. “4.0.0”.

flowerevolver.get_commit_hash() → str#

The short git commit hash this extension was built from, or “unknown” for a build outside a git checkout.

flowerevolver.get_version_string() → str#

get_version() + “+” + get_commit_hash(), e.g. “4.0.0+a1b2c3d” – the one to put in a bug report.

flowerevolver.cli#

The flower-evolver console script installed alongside the package - matches the native desktop app’s own single-flower flags. See the module docstring below for the exact invocations; flower-evolver --help covers the same ground interactively.

FlowerEvolver CLI - matches the native desktop app’s own single-flower flags: -lf, -sf, -si, -s3d, -m, -repr, and the shared -l/-r/-p/-b generation parameters.

Three entry points (each self-sufficient - -lf/-repr just replace “start from a fresh flower” with “start from an existing one/two”). -m <n> mutates n times and saves only the final result, matching the native app - run this repeatedly (feeding each -sf output back in via -lf) if you want every intermediate step saved instead:

flower-evolver -l <numLayers> -r <radius> -p <P> -b <bias> -m <n> flower-evolver -lf <flower.json> -l <numLayers> -r <radius> -p <P> -b <bias> -m <n> -sf <out.json> -si <out.png> flower-evolver -repr <flower1.json> <flower2.json> -l <numLayers> -r <radius> -p <P> -b <bias> -m <n> -sf <out.json> -si <out.png>

Add -s3d <filename> to any of the above to also generate and save a 3D model (glTF) for the resulting flower, e.g.:

flower-evolver -sf flower.json -si flower.png -s3d flower.gltf

Use -se3d <filename> instead of (or alongside) -s3d for an emissive 3D model - same glTF export, but with useEmissive turned on, matching FEService.makeEmissive3DFlower()/drawEmissive3DFlower() on the JS/WASM side. Both can be passed together to save a regular and an emissive model from the same flower:

flower-evolver -sf flower.json -si flower.png -s3d flower.gltf -se3d flower_emissive.gltf

flowerevolver.cli.build_parser() → ArgumentParser#
flowerevolver.cli.main(argv: list[str] | None = None) → int#