Skip to content

Entities

All entities inherit from Entity and share common capabilities. Each entity type adds its own geometry, anchors, and behavior.

See also

For creative examples of each entity type, see Drawing with Entities.


Entity

Entity(x: float = 0, y: float = 0, z_index: int = 0)

Bases: ABC

Base class for all drawable objects in PyFreeform.

Entities are objects with identity - they can be moved, connected, and tracked. Unlike raw primitives, entities maintain relationships with other entities.

Attributes:

Name Type Description
position Coord

Current position (center point for most entities)

surface Surface | None

The surface containing this entity (Cell, Scene, or CellGroup)

connections Collection[Connection]

Connections involving this entity

Subclasses must implement
  • anchor(name): Return anchor point by name
  • anchor_names: Property listing available anchor names
  • to_svg(): Render to SVG element string

Initialize entity at position.

Parameters:

Name Type Description Default
x float

Initial x coordinate.

0
y float

Initial y coordinate.

0
z_index int

Layer ordering (higher = on top). Default 0.

0

position property writable

position: Coord

Current position of the entity (computed from relative coords if set).

x property

x: float

X coordinate of position.

y property

y: float

Y coordinate of position.

at property writable

at: RelCoord | None

Relative position as (rx, ry) fractions, or None if absolute mode.

binding property writable

binding: Binding | None

Current positioning binding, or None if absolutely positioned.

Returns a Binding describing how this entity is positioned: relative (at), along a path (along + t), or None for absolute mode.

rotation property writable

rotation: float

Rotation angle in degrees (accumulated, non-destructive).

scale_factor property writable

scale_factor: float

Scale factor (accumulated, non-destructive). Default 1.0.

rotation_center property

rotation_center: Coord

The center point for rotation and scaling transforms.

Default: entity position. Override for entities where the natural pivot differs (e.g., Rect center, Polygon centroid).

z_index property writable

z_index: int

Layer ordering (higher values render on top).

surface property writable

surface: Surface | None

The surface (Cell, Scene, or CellGroup) containing this entity, if any.

connections property

connections: Collection[Connection]

Connections involving this entity (insertion-ordered).

data property

data: dict[str, Any]

Custom data dictionary for this entity.

is_relative property

is_relative: bool

True when any property is relative (entity reacts to container changes).

Check individual properties (.at, .relative_radius, etc.) to see which specific properties are tracked.

anchor_names abstractmethod property

anchor_names: list[str]

List of available anchor names for this entity.

bounds abstractmethod

bounds(*, visual: bool = False) -> tuple[float, float, float, float]

Get bounding box of this entity.

Parameters:

Name Type Description Default
visual bool

If True, include stroke width in the bounds so the result reflects the rendered (visual) extent rather than pure geometry. Default is False (geometric bounds).

False

Returns:

Type Description
tuple[float, float, float, float]

Tuple of (min_x, min_y, max_x, max_y).

offset_from

offset_from(anchor_spec: AnchorSpec, dx: float = 0, dy: float = 0) -> Coord

Get a point offset from an anchor.

Sugar for entity.anchor(spec) + Coord(dx, dy).

Parameters:

Name Type Description Default
anchor_spec AnchorSpec

Anchor name, RelCoord, or (rx, ry) tuple.

required
dx float

Horizontal offset in pixels.

0
dy float

Vertical offset in pixels.

0

Returns:

Type Description
Coord

The offset point.

move_to_surface

move_to_surface(surface: Surface, at: RelCoordLike = 'center') -> Entity

Move entity to a position within a surface (stores relative coords).

Parameters:

Name Type Description Default
surface Surface

The target surface (Cell, Scene, or CellGroup).

required
at RelCoordLike

RelCoordLike within surface - either a RelCoord / (rx, ry) tuple where (0,0) is top-left and (1,1) is bottom-right, or a named position like "center", "top_left", etc.

'center'

Returns:

Type Description
Entity

self, for method chaining.

rotate

rotate(angle: float, origin: CoordLike | None = None) -> Entity

Rotate entity by angle degrees.

Without origin, rotates in place. With origin, also moves the entity around that point (like orbiting).

Parameters:

Name Type Description Default
angle float

Rotation in degrees (counterclockwise).

required
origin CoordLike | None

Point to rotate around. If None, rotates in place around the entity's natural center.

None

Returns:

Type Description
Entity

self, for method chaining.

scale

scale(factor: float, origin: CoordLike | None = None) -> Entity

Scale entity by factor.

Without origin, scales around the entity's natural center. With origin, also moves the entity toward/away from that point.

Parameters:

Name Type Description Default
factor float

Scale multiplier (1.0 = no change, 2.0 = double).

required
origin CoordLike | None

Point to scale around. If None, scales around the entity's natural center.

None

Returns:

Type Description
Entity

self, for method chaining.

fit_to_surface

fit_to_surface(scale: float = 1.0, recenter: bool = True, *, at: RelCoordLike | None = None, visual: bool = True, rotate: bool = False, match_aspect: bool = False) -> Entity

Automatically scale and position entity to fit within its surface bounds.

Convenience wrapper around :meth:fit_within that uses the containing surface as the target region.

Parameters:

Name Type Description Default
scale float

Fraction of available space to fill (0.0-1.0). 1.0 = fill entire surface, 0.85 = use 85%.

1.0
recenter bool

If True, center entity in surface after scaling. Ignored when at is provided.

True
at RelCoordLike | None

RelCoordLike within the surface as (rx, ry) fractions. Constrains fitting to the space available at that point so the entity doesn't overflow. (0.5, 0.5) uses the full surface (default).

None
visual bool

If True (default), include stroke width in bounds measurement so stroked shapes don't overflow.

True
rotate bool

If True, auto-rotate to maximize surface coverage.

False
match_aspect bool

If True, rotate to match the surface's aspect ratio. Mutually exclusive with rotate.

False

Returns:

Type Description
Entity

self, for method chaining

Raises:

Type Description
ValueError

If entity has no surface, scale is out of range, or both rotate and match_aspect are True.

TypeError

If at is a string (named anchors sit on surface edges where available space is 0).

Example
ellipse = cell.add_ellipse(rx=2.0, ry=1.2, rotation=45)
ellipse.fit_to_surface(0.85)  # Auto-constrain to 85% of cell
dot = cell.add_dot(radius=0.8)
dot.fit_to_surface(1.0, at=(0.25, 0.25))  # Fit in top-left quadrant

fit_within

fit_within(target: Entity | tuple[float, float, float, float], scale: float = 1.0, recenter: bool = True, *, at: RelCoordLike | None = None, visual: bool = True, rotate: bool = False, match_aspect: bool = False) -> Entity

Scale and position entity to fit within another entity's inner bounds.

Parameters:

Name Type Description Default
target Entity | tuple[float, float, float, float]

Entity (uses inner_bounds()) or raw (min_x, min_y, max_x, max_y) tuple.

required
scale float

Fraction of target inner bounds to fill (0.0-1.0].

1.0
recenter bool

If True, center entity within target after scaling. Ignored when at is provided.

True
at RelCoordLike | None

Optional relative position (rx, ry) within the target's inner bounds, where (0,0) is top-left and (1,1) is bottom-right. Available space is constrained by the nearest edges so the entity never overflows.

None
visual bool

If True (default), include stroke width when measuring bounds so stroked entities don't overflow after fitting. Set to False for pure geometric fitting.

True
rotate bool

If True, find the rotation angle that maximizes how much of the target space the entity fills before scaling.

False
match_aspect bool

If True, rotate the entity so its bounding box aspect ratio matches the target's. Mutually exclusive with rotate.

False

Returns:

Type Description
Entity

self, for method chaining.

Example
dot = cell.add_dot(radius=0.5, color="navy")
label = cell.add_text("0.5", color="white", font_size=50)
label.fit_within(dot)
# Position in top-left of a rect's inner bounds:
label.fit_within(rect, at=(0.25, 0.25))

connect

connect(other: Entity | Surface, start_anchor: AnchorSpec = 'center', end_anchor: AnchorSpec = 'center', *, path: Path | None = None, curvature: float | None = None, visible: bool = True, width: float = 1, color: ColorLike = 'black', z_index: int = 0, cap: CapName = 'round', start_cap: CapName | None = None, end_cap: CapName | None = None, opacity: float = 1.0, color_brightness: float | None = None, style: PathStyle | None = None, segments: int = 32) -> Connection

Create a connection to another entity or surface.

Parameters:

Name Type Description Default
other Entity | Surface

The entity or surface to connect to.

required
start_anchor AnchorSpec

Anchor spec on this entity (name, RelCoord, or tuple).

'center'
end_anchor AnchorSpec

Anchor spec on the other object.

'center'
path Path | None

Custom path geometry (e.g. Path.Wave()). For simple arcs use curvature instead.

None
curvature float | None

Arc curvature (-1 to 1). Positive bows left, negative bows right. Cannot be used with path.

None
visible bool

Whether the connection renders. Default True.

True
width float

Line width in pixels.

1
color ColorLike

Line color.

'black'
z_index int

Layer order (higher = on top).

0
cap CapName

Cap style for both ends.

'round'
start_cap CapName | None

Override cap for start end (e.g. "arrow").

None
end_cap CapName | None

Override cap for end end (e.g. "arrow").

None
opacity float

Opacity (0.0 transparent to 1.0 opaque).

1.0
color_brightness float | None

Brightness multiplier 0.0 (black) to 1.0 (unchanged).

None
style PathStyle | None

PathStyle object (overrides individual params).

None
segments int

Number of Bézier segments for path rendering.

32

Returns:

Type Description
Connection

The created Connection.

anchor

anchor(spec: AnchorSpec = 'center') -> Coord

Get anchor point by name or relative coordinate.

Parameters:

Name Type Description Default
spec AnchorSpec

Anchor specification. Can be: - A string name (e.g., "center", "start", "top_left", "v0") - A RelCoord or (rx, ry) tuple (0.0-1.0 fractions of bounding box)

'center'

Returns:

Type Description
Coord

The anchor position as a Coord.

Raises:

Type Description
ValueError

If string name is not valid for this entity.

relative_anchor

relative_anchor(spec: AnchorSpec = 'center') -> RelCoord

Anchor position as a fraction of the containing surface.

Like anchor() but returns a RelCoord instead of pixels, expressing the position as fractions (0.0–1.0) of the surface.

Parameters:

Name Type Description Default
spec AnchorSpec

Anchor name (e.g. "center", "top_left") or RelCoord.

'center'

Returns:

Type Description
RelCoord

RelCoord within the containing surface.

Raises:

Type Description
ValueError

If the entity is not in a surface.

relative_bounds

relative_bounds() -> tuple[float, float, float, float]

Bounds as fractions of the containing surface.

Returns the bounding box expressed as (min_rx, min_ry, max_rx, max_ry) where each value is a fraction (0.0–1.0) of the surface's width or height.

Returns:

Type Description
tuple[float, float, float, float]

Tuple of (min_rx, min_ry, max_rx, max_ry).

Raises:

Type Description
ValueError

If the entity is not in a surface.

distance_to

distance_to(other: Entity | Surface | Coord | tuple[float, float]) -> float

Euclidean pixel distance from this entity's position to another.

Accepts: Entity (uses position), Cell/Surface (uses center), Coord, or (x, y) tuple.

Parameters:

Name Type Description Default
other Entity | Surface | Coord | tuple[float, float]

An Entity, Surface/Cell, Coord, or (x, y) tuple.

required

Returns:

Type Description
float

Distance in pixels.

place_beside

place_beside(other: Entity, side: Literal['right', 'left', 'above', 'below'] = 'right', gap: float = 0) -> Entity

Position this entity beside another within the same surface.

Both entities must be in the same surface (cell, merged region, or scene). The gap is a fraction of the surface dimension (e.g. gap=0.05 is 5% of the surface width/height).

Parameters:

Name Type Description Default
other Entity

Reference entity (must share the same surface).

required
side Literal['right', 'left', 'above', 'below']

"right", "left", "above", or "below".

'right'
gap float

Gap as a fraction of the surface dimension.

0

Returns:

Type Description
Entity

self, for method chaining.

Raises:

Type Description
ValueError

If entities are not in the same surface.


Dot

Dot(x: float = 0, y: float = 0, radius: float = DEFAULT_RADIUS, color: PaintLike = DEFAULT_COLOR, z_index: int = 0, opacity: float = 1.0, color_brightness: float | None = None)

Bases: Entity

A filled circle at a specific point.

The fundamental "mark" in PyFreeform - think of it as touching a pen or brush to paper.

Attributes:

Name Type Description
position Coord

Center of the dot

radius float

Size of the dot

color str

Fill color

Anchors
  • "center": The center point (same as position)
Example
dot = Dot(100, 100)
dot = Dot(100, 100, radius=10, color="coral")
dot.move_to_surface(cell, at=(0.5, 0.5))

Create a dot at the specified position.

Parameters:

Name Type Description Default
x float

Horizontal position.

0
y float

Vertical position.

0
radius float

Radius of the dot in pixels.

DEFAULT_RADIUS
color PaintLike

Fill color (name, hex, or RGB tuple).

DEFAULT_COLOR
z_index int

Layer ordering (higher = on top).

0
opacity float

Opacity (0.0 transparent to 1.0 opaque).

1.0
color_brightness float | None

Brightness multiplier 0.0 (black) to 1.0 (unchanged).

None

radius property writable

radius: float

Radius in pixels (resolved from relative fraction if set).

color property writable

color: str

The fill paint as a string (color or gradient ref).

relative_radius property writable

relative_radius: float | None

Relative radius (fraction of min(surface_w, surface_h)), or None.

anchor_names property

anchor_names: list[str]

Available anchors: just 'center' for dots.

bounds

bounds(*, visual: bool = False) -> tuple[float, float, float, float]

Get bounding box (accounts for scale).

Uses color=, not fill=

dot = cell.add_dot(at="center", radius=0.1, color="coral")  # 10% of cell
dot = Dot(100, 200, radius=10, color="coral")
scene.place(dot)

Line

Line(x1: float = 0, y1: float = 0, x2: float = 1, y2: float = 0, width: float = DEFAULT_WIDTH, color: PaintLike = DEFAULT_COLOR, z_index: int = 0, cap: CapName = DEFAULT_CAP, start_cap: CapName | None = None, end_cap: CapName | None = None, opacity: float = 1.0, color_brightness: float | None = None)

Bases: EndpointEntity

A line segment between two points.

Unlike connections (which link entities), a Line is a standalone entity with its own start and end points. Lines can be placed in cells and have other entities positioned along them.

Attributes:

Name Type Description
position Coord

The start point of the line

width

Stroke width

color str

Stroke color

Anchors
  • "start": The starting point
  • "center": The midpoint
  • "end": The ending point
Example
line = Line(0, 0, 100, 100)  # From (0,0) to (100,100)
line = Line.from_points(Coord(0, 0), Coord(100, 100))
midpoint = line.anchor("center")
line = Line(0, 0, 100, 0, end_cap="arrow")  # Arrow at end

Create a line from (x1, y1) to (x2, y2).

Parameters:

Name Type Description Default
x1 float

Start x in pixels.

0
y1 float

Start y in pixels.

0
x2 float

End x in pixels.

1
y2 float

End y in pixels.

0
width float

Stroke width in pixels.

DEFAULT_WIDTH
color PaintLike

Stroke color (name, hex, or RGB tuple).

DEFAULT_COLOR
z_index int

Layer ordering (higher = on top).

0
cap CapName

Cap style for both ends ("round", "square", "butt", or "arrow").

DEFAULT_CAP
start_cap CapName | None

Override cap for start end only.

None
end_cap CapName | None

Override cap for end end only.

None
opacity float

Opacity (0.0 transparent to 1.0 opaque).

1.0
color_brightness float | None

Brightness multiplier 0.0 (black) to 1.0 (unchanged).

None

end property writable

end: Coord

The ending point (resolved from relative fraction if set).

length property

length: float

Length of the line (world space, accounts for scale).

anchor_names property

anchor_names: list[str]

Available anchors: start, center, end.

from_points classmethod

from_points(start: CoordLike, end: CoordLike, width: float = DEFAULT_WIDTH, color: PaintLike = DEFAULT_COLOR, z_index: int = 0, cap: CapName = DEFAULT_CAP, start_cap: CapName | None = None, end_cap: CapName | None = None, opacity: float = 1.0, color_brightness: float | None = None) -> Line

Create a line from two points.

Parameters:

Name Type Description Default
start CoordLike

Starting point.

required
end CoordLike

Ending point.

required
width float

Stroke width.

DEFAULT_WIDTH
color PaintLike

Stroke color.

DEFAULT_COLOR
z_index int

Layer ordering (higher = on top).

0
cap CapName

Cap style for both ends.

DEFAULT_CAP
start_cap CapName | None

Override cap for start end only.

None
end_cap CapName | None

Override cap for end end only.

None
opacity float

Opacity (0.0 transparent to 1.0 opaque).

1.0
color_brightness float | None

Brightness multiplier 0.0 (black) to 1.0 (unchanged).

None

Returns:

Type Description
Line

A new Line entity.

set_endpoints

set_endpoints(start: CoordLike, end: CoordLike) -> Line

Set both endpoints of the line.

Parameters:

Name Type Description Default
start CoordLike

New starting point.

required
end CoordLike

New ending point.

required

Returns:

Type Description
Line

self, for method chaining.

arc_length

arc_length() -> float

Return the length of the line segment.

angle_at

angle_at(t: float) -> float

Get the tangent angle in degrees at parameter t (world space).

For a line, the angle is constant (same at every point).

Parameters:

Name Type Description Default
t float

Parameter (unused — angle is constant for lines).

required

Returns:

Type Description
float

Angle in degrees.

point_at

point_at(t: float) -> Coord

Get a point along the line (world space).

Parameters:

Name Type Description Default
t float

Parameter from 0 (start) to 1 (end). Values outside 0-1 extrapolate beyond the line.

required

Returns:

Type Description
Coord

Coord at that position along the line.

to_svg_path_d

to_svg_path_d() -> str

Return SVG path d attribute for this line.

Cap values: "round", "square", "butt", "arrow", "arrow_in"


Curve

Curve(x1: float = 0, y1: float = 0, x2: float = 1, y2: float = 0, curvature: float = 0.5, width: float = DEFAULT_WIDTH, color: PaintLike = DEFAULT_COLOR, z_index: int = 0, cap: CapName = DEFAULT_CAP, start_cap: CapName | None = None, end_cap: CapName | None = None, opacity: float = 1.0, color_brightness: float | None = None)

Bases: EndpointEntity

A quadratic Bezier curve between two points.

Curves add organic, flowing shapes to your art. The curvature parameter controls how much the curve bows away from a straight line.

The key feature: use point_at(t) to position other elements along the curve, just like with lines!

Attributes:

Name Type Description
start Coord

Starting point

end Coord

Ending point

curvature float

How much the curve bows (-1 to 1, 0 = straight)

control Coord

The Bezier control point (calculated from curvature)

Anchors
  • "start": The starting point
  • "center": The midpoint of the curve (at t=0.5)
  • "end": The ending point
  • "control": The control point
Example
curve = Curve(0, 100, 100, 0, curvature=0.5)
midpoint = curve.point_at(0.5)  # Point on the curve

# In a cell:
curve = cell.add_curve(start="bottom_left", end="top_right", curvature=0.3)
cell.add_dot(along=curve, t=cell.brightness)

# With arrow cap:
curve = Curve(0, 100, 100, 0, curvature=0.5, end_cap="arrow")

Create a curve from (x1, y1) to (x2, y2).

Parameters:

Name Type Description Default
x1 float

Start x in pixels.

0
y1 float

Start y in pixels.

0
x2 float

End x in pixels.

1
y2 float

End y in pixels.

0
curvature float

How much the curve bows away from straight. 0 = straight line Positive = bows to the left (when facing end) Negative = bows to the right Typical range: -1 to 1

0.5
width float

Stroke width in pixels.

DEFAULT_WIDTH
color PaintLike

Stroke color.

DEFAULT_COLOR
z_index int

Layer ordering (higher = on top).

0
cap CapName

Cap style for both ends ("round", "square", "butt", or "arrow").

DEFAULT_CAP
start_cap CapName | None

Override cap for start end only.

None
end_cap CapName | None

Override cap for end end only.

None
opacity float

Opacity (0.0 transparent to 1.0 opaque).

1.0
color_brightness float | None

Brightness multiplier 0.0 (black) to 1.0 (unchanged).

None

end property writable

end: Coord

The ending point (resolved from relative fraction if set).

curvature property writable

curvature: float

The curvature amount.

control property

control: Coord

The Bezier control point.

Calculated from curvature: perpendicular to the line at its midpoint, offset by curvature * half the line length.

anchor_names property

anchor_names: list[str]

Available anchors.

from_points classmethod

from_points(start: CoordLike, end: CoordLike, curvature: float = 0.5, width: float = DEFAULT_WIDTH, color: PaintLike = DEFAULT_COLOR, z_index: int = 0, cap: CapName = DEFAULT_CAP, start_cap: CapName | None = None, end_cap: CapName | None = None, opacity: float = 1.0, color_brightness: float | None = None) -> Curve

Create a curve from two points.

arc_length

arc_length(segments: int = 100) -> float

Approximate the arc length of the curve by sampling.

Parameters:

Name Type Description Default
segments int

Number of line segments to approximate with.

100

Returns:

Type Description
float

Approximate arc length in pixels.

angle_at

angle_at(t: float) -> float

Get the tangent angle in degrees at parameter t on the curve.

Uses the derivative of the quadratic Bezier formula.

Parameters:

Name Type Description Default
t float

Parameter from 0 (start) to 1 (end).

required

Returns:

Type Description
float

Angle in degrees.

point_at

point_at(t: float) -> Coord

Get a point along the curve.

This is the key method for positioning elements along curves!

Parameters:

Name Type Description Default
t float

Parameter from 0 (start) to 1 (end).

required

Returns:

Type Description
Coord

Coord on the curve at parameter t.

Example
curve = cell.add_curve(curvature=0.5)
cell.add_dot(along=curve, t=0.5)  # Dot at curve midpoint

to_svg_path_d

to_svg_path_d() -> str

Return SVG path d attribute for this quadratic Bezier curve.

See also

See Paths and Parametric Positioning for Bezier curve techniques.


Ellipse

Ellipse(x: float = 0, y: float = 0, rx: float = 10, ry: float = 10, rotation: float = 0, fill: PaintLike | None = DEFAULT_FILL, stroke: PaintLike | None = DEFAULT_STROKE, stroke_width: float = DEFAULT_STROKE_WIDTH, z_index: int = 0, opacity: float = 1.0, fill_opacity: float | None = None, stroke_opacity: float | None = None, fill_brightness: float | None = None, stroke_brightness: float | None = None)

Bases: Entity

An ellipse (oval) with parametric positioning support.

Ellipses are defined by horizontal radius (rx), vertical radius (ry), and optional rotation. They support both parametric positioning via point_at(t) and direct angle-based positioning via point_at_angle(degrees).

Attributes:

Name Type Description
position Coord

Center of the ellipse

rx float

Horizontal radius

ry float

Vertical radius

rotation

Rotation in degrees (counterclockwise)

fill str | None

Fill color

stroke str | None

Stroke color

stroke_width

Stroke width in pixels

Anchors
  • "center": The center point (same as position)
  • "right": Rightmost point (0°)
  • "top": Topmost point (90°)
  • "left": Leftmost point (180°)
  • "bottom": Bottommost point (270°)
Example
ellipse = Ellipse(100, 100, rx=30, ry=20, fill="coral")
ellipse = Ellipse.at_center(Coord(100, 100), rx=30, ry=20)

# Parametric positioning (t from 0 to 1)
point = ellipse.point_at(0.25)  # Top of ellipse

# Direct angle positioning (degrees)
point = ellipse.point_at_angle(45)  # 45° from right

# In a cell:
ellipse = cell.add_ellipse(rx=0.3, ry=0.2, rotation=30)
cell.add_dot(along=ellipse, t=cell.brightness)

Create an ellipse at the specified center position.

Parameters:

Name Type Description Default
x float

Horizontal center position.

0
y float

Vertical center position.

0
rx float

Horizontal radius (half-width).

10
ry float

Vertical radius (half-height).

10
rotation float

Rotation in degrees (counterclockwise).

0
fill PaintLike | None

Fill color (name, hex, RGB tuple, or None for transparent).

DEFAULT_FILL
stroke PaintLike | None

Stroke color (None for no stroke).

DEFAULT_STROKE
stroke_width float

Stroke width in pixels.

DEFAULT_STROKE_WIDTH
z_index int

Layer ordering (higher = on top).

0
opacity float

Opacity for both fill and stroke (0.0-1.0).

1.0
fill_opacity float | None

Override opacity for fill only (None = use opacity).

None
stroke_opacity float | None

Override opacity for stroke only (None = use opacity).

None
fill_brightness float | None

Brightness multiplier for fill 0.0 (black) to 1.0 (unchanged).

None
stroke_brightness float | None

Brightness multiplier for stroke 0.0 (black) to 1.0 (unchanged).

None

fill property writable

fill: str | None

The fill paint as a string (color or gradient ref), or None.

stroke property writable

stroke: str | None

The stroke paint as a string (color or gradient ref), or None.

stroke_width instance-attribute

stroke_width = float(stroke_width)

rx property writable

rx: float

Horizontal radius in pixels (resolved from relative fraction if set).

ry property writable

ry: float

Vertical radius in pixels (resolved from relative fraction if set).

relative_rx property writable

relative_rx: float | None

Relative x-radius (fraction of reference width), or None.

relative_ry property writable

relative_ry: float | None

Relative y-radius (fraction of reference height), or None.

anchor_names property

anchor_names: list[str]

Available anchors: center, right, top, left, bottom.

at_center classmethod

at_center(center: CoordLike, rx: float = 10, ry: float = 10, rotation: float = 0, fill: PaintLike | None = DEFAULT_FILL, stroke: PaintLike | None = DEFAULT_STROKE, stroke_width: float = DEFAULT_STROKE_WIDTH, z_index: int = 0, opacity: float = 1.0, fill_opacity: float | None = None, stroke_opacity: float | None = None) -> Ellipse

Create an ellipse at a specific center point.

Parameters:

Name Type Description Default
center CoordLike

Center position as Coord or (x, y) tuple.

required
rx float

Horizontal radius.

10
ry float

Vertical radius.

10
rotation float

Rotation in degrees.

0
fill PaintLike | None

Fill color.

DEFAULT_FILL
stroke PaintLike | None

Stroke color.

DEFAULT_STROKE
stroke_width float

Stroke width.

DEFAULT_STROKE_WIDTH
z_index int

Layer ordering.

0
opacity float

Opacity for both fill and stroke.

1.0
fill_opacity float | None

Override opacity for fill only.

None
stroke_opacity float | None

Override opacity for stroke only.

None

Returns:

Type Description
Ellipse

A new Ellipse entity.

point_at_angle

point_at_angle(degrees: float) -> Coord

Get a point at a specific angle on the ellipse perimeter.

Parameters:

Name Type Description Default
degrees float

Angle in degrees (0° = right, 90° = top, counterclockwise).

required

Returns:

Type Description
Coord

Coord on the ellipse at the specified angle.

Example
point = ellipse.point_at_angle(45)  # Northeast
point = ellipse.point_at_angle(180)  # Leftmost point

arc_length

arc_length(segments: int = 100) -> float

Approximate the perimeter (arc length) of the ellipse by sampling.

Parameters:

Name Type Description Default
segments int

Number of line segments to approximate with.

100

Returns:

Type Description
float

Approximate arc length in pixels.

angle_at

angle_at(t: float) -> float

Get the tangent angle in degrees at parameter t on the ellipse.

Uses the derivative of the parametric ellipse equations, then adds the entity's rotation.

Parameters:

Name Type Description Default
t float

Parameter from 0.0 to 1.0 around the ellipse.

required

Returns:

Type Description
float

Angle in degrees (world space).

point_at

point_at(t: float) -> Coord

Get a point at parameter t along the ellipse perimeter.

This is the key method for parametric positioning (Pathable protocol).

Parameters:

Name Type Description Default
t float

Parameter from 0.0 to 1.0 around the ellipse. t=0 and t=1 are the same point (rightmost, 0°). t=0.25 is top (90°), t=0.5 is left (180°), t=0.75 is bottom (270°).

required

Returns:

Type Description
Coord

Coord on the ellipse at parameter t.

Example
ellipse = cell.add_ellipse(rx=0.4, ry=0.3)
cell.add_dot(along=ellipse, t=0.5)  # Dot at left side

to_svg_path_d

to_svg_path_d() -> str

Return SVG path d attribute for the full ellipse as two arcs.

Uses fill=, not color=

fill_opacity and stroke_opacity override opacity for independent control.

ellipse = cell.add_ellipse(rx=0.3, ry=0.2, fill="steelblue")  # 30%/20% of cell
ellipse = Ellipse(200, 150, rx=60, ry=40, fill="steelblue")
scene.place(ellipse)

Polygon

Polygon(vertices: Sequence[VertexInput], fill: PaintLike | None = DEFAULT_FILL, stroke: PaintLike | None = DEFAULT_STROKE, stroke_width: float = DEFAULT_STROKE_WIDTH, z_index: int = 0, opacity: float = 1.0, fill_opacity: float | None = None, stroke_opacity: float | None = None, fill_brightness: float | None = None, stroke_brightness: float | None = None)

Bases: Entity

A closed polygon defined by a list of vertices.

Vertices can be static coordinates or entity references. Entity-reference vertices track the referenced entity's position at render time — when the entity moves, the polygon deforms automatically.

Polygons can be filled, stroked, or both. Use classmethods like Polygon.star(), Polygon.hexagon() for common shapes.

Attributes:

Name Type Description
vertices list[Coord]

List of resolved Coord objects (computed at access time)

fill str | None

Fill color (or None for no fill)

stroke str | None

Stroke color (or None for no stroke)

stroke_width

Stroke width

Anchors
  • "center": Centroid of the polygon
  • "v0", "v1", ...: Individual vertices (resolved from specs)
Example
# Triangle from static points
tri = Polygon([(0, 0), (50, 100), (100, 0)], fill="blue")

# Entity-reference vertices (reactive)
a, b, c = Point(0, 0), Point(100, 0), Point(50, 80)
tri = Polygon([a, b, c], fill="coral")
b.move_to_surface(cell, at=(0.8, 0.3))  # triangle deforms automatically

# Mixed static and entity-reference
tri = Polygon([(0, 0), dot, (rect, "top_right")], fill="teal")

# In a cell (relative coordinates 0-1)
cell.add_polygon([(0.5, 0), (1, 1), (0, 1)], fill="red")

# Using shape classmethods
cell.add_polygon(Polygon.hexagon(), fill="purple")

Create a polygon from vertices.

Parameters:

Name Type Description Default
vertices Sequence[VertexInput]

List of vertex specs (at least 3). Each can be: - (x, y) tuple or Coord — static vertex - Entity — tracks the entity's position - (Entity, "anchor_name") — tracks a specific anchor

required
fill PaintLike | None

Fill color (None for transparent).

DEFAULT_FILL
stroke PaintLike | None

Stroke color (None for no stroke).

DEFAULT_STROKE
stroke_width float

Stroke width in pixels.

DEFAULT_STROKE_WIDTH
z_index int

Layer ordering (higher = on top).

0
opacity float

Opacity for both fill and stroke (0.0-1.0).

1.0
fill_opacity float | None

Override opacity for fill only (None = use opacity).

None
stroke_opacity float | None

Override opacity for stroke only (None = use opacity).

None
fill_brightness float | None

Brightness multiplier for fill 0.0 (black) to 1.0 (unchanged).

None
stroke_brightness float | None

Brightness multiplier for stroke 0.0 (black) to 1.0 (unchanged).

None

fill property writable

fill: str | None

The fill paint as a string (color or gradient ref), or None.

stroke property writable

stroke: str | None

The stroke paint as a string (color or gradient ref), or None.

stroke_width instance-attribute

stroke_width = float(stroke_width)

vertices property

vertices: list[Coord]

The polygon vertices (resolved from specs at access time).

relative_vertices property writable

relative_vertices: list[RelCoord] | None

Relative vertex positions (fractions of reference frame), or None.

anchor_names property

anchor_names: list[str]

Available anchors: center and vertices.

triangle classmethod

triangle(size: float = 1.0, center: tuple[float, float] = (0.5, 0.5)) -> list[tuple[float, float]]

Generate equilateral triangle vertices (pointing up).

square classmethod

square(size: float = 0.8, center: tuple[float, float] = (0.5, 0.5)) -> list[tuple[float, float]]

Generate square vertices.

diamond classmethod

diamond(size: float = 0.8, center: tuple[float, float] = (0.5, 0.5)) -> list[tuple[float, float]]

Generate diamond (rotated square) vertices.

hexagon classmethod

hexagon(size: float = 0.8, center: tuple[float, float] = (0.5, 0.5)) -> list[tuple[float, float]]

Generate regular hexagon vertices.

star classmethod

star(points: int = 5, size: float = 0.8, inner_ratio: float = 0.4, center: tuple[float, float] = (0.5, 0.5)) -> list[tuple[float, float]]

Generate star vertices.

regular_polygon classmethod

regular_polygon(sides: int, size: float = 0.8, center: tuple[float, float] = (0.5, 0.5)) -> list[tuple[float, float]]

Generate regular polygon with N sides.

squircle classmethod

squircle(size: float = 0.8, center: tuple[float, float] = (0.5, 0.5), n: float = 4, points: int = 32) -> list[tuple[float, float]]

Generate squircle (superellipse) vertices.

rounded_rect classmethod

rounded_rect(size: float = 0.8, center: tuple[float, float] = (0.5, 0.5), corner_radius: float = 0.2, points_per_corner: int = 8) -> list[tuple[float, float]]

Generate rectangle with rounded corners vertices.

Uses fill=, not color=

Entity-Reference Vertices

Vertices can be static coordinates or entity references:

Vertex type Example Behavior
(x, y) tuple or Coord (50, 100) Static — moves with polygon transforms
Entity Point(50, 100) Reactive — tracks entity's .position
(Entity, "anchor") (rect, "top_right") Reactive — tracks entity's named anchor

Entity-reference vertices are resolved at render time. When the referenced entity moves, the polygon deforms automatically.

Transforms and entity vertices

polygon.rotate() and polygon.scale() only affect static (Coord) vertices. Entity-reference vertices follow their entity, not polygon transforms.

See also

For all shape classmethods and polygon techniques, see Shapes and Polygons.


Rect

Rect(x: float = 0, y: float = 0, width: float = 10, height: float = 10, fill: PaintLike | None = DEFAULT_FILL, stroke: PaintLike | None = None, stroke_width: float = 1, rotation: float = 0, z_index: int = 0, opacity: float = 1.0, fill_opacity: float | None = None, stroke_opacity: float | None = None, fill_brightness: float | None = None, stroke_brightness: float | None = None)

Bases: Entity

A rectangle entity.

Rectangles can be used for backgrounds, cells, frames, and more. When placed in a cell, they can automatically fill the cell.

Attributes:

Name Type Description
position Coord

Top-left corner of the rectangle

width float

Rectangle width

height float

Rectangle height

rotation

Rotation in degrees (counterclockwise)

fill str | None

Fill color (or None for no fill)

stroke str | None

Stroke color (or None for no stroke)

stroke_width

Stroke width

Anchors
  • "center": Center point
  • "top_left", "top_right", "bottom_left", "bottom_right": Corners
  • "top", "bottom", "left", "right": Edge centers
Example
rect = Rect(0, 0, 100, 50, fill="blue")
rect = Rect(0, 0, 100, 50, fill=None, stroke="black", stroke_width=2)
rect = Rect(0, 0, 100, 50, fill="red", rotation=45)

Create a rectangle.

Parameters:

Name Type Description Default
x float

Top-left corner x.

0
y float

Top-left corner y.

0
width float

Rectangle width.

10
height float

Rectangle height.

10
fill PaintLike | None

Fill color (None for transparent).

DEFAULT_FILL
stroke PaintLike | None

Stroke color (None for no stroke).

None
stroke_width float

Stroke width in pixels.

1
rotation float

Rotation in degrees (counterclockwise).

0
z_index int

Layer ordering (higher = on top).

0
opacity float

Opacity for both fill and stroke (0.0-1.0).

1.0
fill_opacity float | None

Override opacity for fill only (None = use opacity).

None
stroke_opacity float | None

Override opacity for stroke only (None = use opacity).

None
fill_brightness float | None

Brightness multiplier for fill 0.0 (black) to 1.0 (unchanged).

None
stroke_brightness float | None

Brightness multiplier for stroke 0.0 (black) to 1.0 (unchanged).

None

fill property writable

fill: str | None

The fill paint as a string (color or gradient ref), or None.

stroke property writable

stroke: str | None

The stroke paint as a string (color or gradient ref), or None.

stroke_width instance-attribute

stroke_width = float(stroke_width)

width property writable

width: float

Width in pixels (resolved from relative fraction if set).

height property writable

height: float

Height in pixels (resolved from relative fraction if set).

rotation instance-attribute

rotation = float(rotation)

relative_width property writable

relative_width: float | None

Relative width (fraction of reference width), or None.

relative_height property writable

relative_height: float | None

Relative height (fraction of reference height), or None.

anchor_names property

anchor_names: list[str]

Available anchor names.

at_center classmethod

at_center(center: CoordLike, width: float = 10, height: float = 10, rotation: float = 0, fill: PaintLike | None = DEFAULT_FILL, stroke: PaintLike | None = None, stroke_width: float = 1, z_index: int = 0, opacity: float = 1.0, fill_opacity: float | None = None, stroke_opacity: float | None = None, fill_brightness: float | None = None, stroke_brightness: float | None = None) -> Rect

Create a rectangle positioned by its center.

Parameters:

Name Type Description Default
center CoordLike

Center position as Coord or (x, y) tuple.

required
width float

Rectangle width.

10
height float

Rectangle height.

10
rotation float

Rotation in degrees.

0
fill PaintLike | None

Fill color.

DEFAULT_FILL
stroke PaintLike | None

Stroke color.

None
stroke_width float

Stroke width.

1
z_index int

Layer ordering.

0
opacity float

Opacity for both fill and stroke.

1.0
fill_opacity float | None

Override opacity for fill only.

None
stroke_opacity float | None

Override opacity for stroke only.

None
fill_brightness float | None

Brightness multiplier for fill 0.0 (black) to 1.0 (unchanged).

None
stroke_brightness float | None

Brightness multiplier for stroke 0.0 (black) to 1.0 (unchanged).

None

Returns:

Type Description
Rect

A new Rect entity.

Uses fill=, not color=

x, y is the top-left corner. Use Rect.at_center() to position by center. Anchors are rotation-aware.

rect = cell.add_rect(width=0.8, height=0.4, fill="navy")  # 80%/40% of cell
rect = Rect(50, 50, width=160, height=80, fill="navy")
scene.place(rect)

Text

Text(x: float = 0, y: float = 0, content: str = '', font_size: float = DEFAULT_FONT_SIZE, color: PaintLike = DEFAULT_COLOR, font_family: str = DEFAULT_FONT_FAMILY, font_style: str = DEFAULT_FONT_STYLE, font_weight: str | int = DEFAULT_FONT_WEIGHT, bold: bool = False, italic: bool = False, text_anchor: str = DEFAULT_ANCHOR, baseline: str = DEFAULT_BASELINE, rotation: float = 0, z_index: int = 0, opacity: float = 1.0, color_brightness: float | None = None)

Bases: Entity

A text label at a specific position.

Text can be used for labels, annotations, data visualization, and typographic art. It supports: - Multiple font families (serif, sans-serif, monospace) - Alignment control (horizontal and vertical) - Rotation around the text position - Color and size customization

Attributes:

Name Type Description
position Coord

The anchor point for the text

content

The text string to display

font_size float

Font size in pixels

font_family

Font family name

font_style

normal | italic | oblique

font_weight

normal | bold | 100-900

color str

Text color

anchor Coord

Horizontal alignment (start, middle, end)

baseline

Vertical alignment (auto, middle, hanging, etc.)

rotation

Rotation angle in degrees

Anchors
  • "center": The text position (same as position)
Example
text = Text(100, 100, "Hello")
text = Text(100, 100, "Label", font_size=16, color="coral")
text.rotate(45)

Create text at the specified position.

Parameters:

Name Type Description Default
x float

Horizontal position.

0
y float

Vertical position.

0
content str

The text string to display.

''
font_size float

Font size in pixels.

DEFAULT_FONT_SIZE
color PaintLike

Text color (name, hex, or RGB tuple).

DEFAULT_COLOR
font_family str

Font family — "serif", "sans-serif", "monospace", or a specific font name.

DEFAULT_FONT_FAMILY
bold bool

If True, use bold weight.

False
italic bool

If True, use italic style.

False
text_anchor str

Horizontal alignment: "start" (left), "middle", "end" (right).

DEFAULT_ANCHOR
baseline str

Vertical alignment: "auto", "middle", "hanging" (top).

DEFAULT_BASELINE
rotation float

Rotation angle in degrees (counterclockwise).

0
z_index int

Layer ordering (higher = on top).

0
opacity float

Opacity (0.0 transparent to 1.0 opaque).

1.0
color_brightness float | None

Brightness multiplier 0.0 (black) to 1.0 (unchanged).

None

content instance-attribute

content = content

font_size property writable

font_size: float

Font size in pixels (resolved from relative fraction if set).

color property writable

color: str

The text paint as a string (color or gradient ref).

bold property writable

bold: bool

italic property writable

italic: bool

font_family instance-attribute

font_family = font_family

relative_font_size property writable

relative_font_size: float | None

Relative font size (fraction of surface height), or None.

has_textpath property

has_textpath: bool

Whether this text renders along a path (textPath mode).

anchor_names property

anchor_names: list[str]

Available anchors: just 'center' for text.

set_textpath

set_textpath(path_id: str, path_d: str, start_offset: str = '0%', text_length: float | None = None) -> None

Configure this text to warp along an SVG path.

Parameters:

Name Type Description Default
path_id str

Unique ID for the path definition.

required
path_d str

SVG path d attribute string.

required
start_offset str

Offset along the path where text starts.

'0%'
text_length float | None

Target pixel length for the text. When set, inter-character spacing expands or contracts so the text spans exactly this many pixels. Glyphs are not stretched. Emitted as textLength on both <text> and <textPath> for cross-browser support (Firefox reads it from <text>, Safari from <textPath>).

None

fit_to_surface

fit_to_surface(scale: float = 1.0, recenter: bool = True, *, at: RelCoordLike | None = None, visual: bool = True, rotate: bool = False, match_aspect: bool = False) -> Text

Scale font size so text fills its surface at scale.

Unlike fit=True on add_text() (which only shrinks), this method scales the font up or down to fill the available space.

Parameters:

Name Type Description Default
scale float

How much of the surface to fill (0.0-1.0). 1.0 = fill entire surface, 0.8 = use 80%.

1.0
recenter bool

If True, center text in surface after scaling.

True
at RelCoordLike | None

Optional surface-relative position (rx, ry).

None
visual bool

Unused for text (kept for signature compatibility).

True
rotate bool

If True, rotate to maximize fill before scaling.

False
match_aspect bool

If True, rotate to match surface aspect ratio.

False

Returns:

Type Description
Text

self, for method chaining.

Raises:

Type Description
ValueError

If entity has no surface.

font_size: pixels in constructor, fraction in builder

Text(x, y, content, font_size=16) uses pixels. cell.add_text(content, font_size=0.25) uses fraction of surface height (0.25 = 25%).

See also

See Text and Typography for text layout and textpath examples.


Path

Path(pathable: Pathable, *, segments: int = DEFAULT_SEGMENTS, closed: bool = False, start_t: float = 0.0, end_t: float = 1.0, width: float = DEFAULT_WIDTH, color: PaintLike = DEFAULT_COLOR, fill: PaintLike | None = None, z_index: int = 0, cap: CapName = DEFAULT_CAP, start_cap: CapName | None = None, end_cap: CapName | None = None, opacity: float = 1.0, fill_opacity: float | None = None, stroke_opacity: float | None = None)

Bases: Entity

Renders any Pathable as a smooth SVG <path> using cubic Bézier curves.

Pass in a Wave, Spiral, Lissajous, or any custom Pathable and get a smooth, stroked (and optionally filled) SVG curve. The path is sampled and approximated with Bézier segments (Hermite interpolation) for a clean result.

For closed paths, the last segment wraps smoothly back to the start with no visible seam.

Attributes:

Name Type Description
closed bool

Whether this is a closed path.

segments

Number of cubic Bézier segments used.

start_t

Start parameter on the source pathable.

end_t

End parameter on the source pathable.

Anchors
  • "start": The first point (t=0)
  • "center": The midpoint (t=0.5)
  • "end": The last point (t=1, or same as start if closed)
Example
from pyfreeform import Path, Coord
# Render a custom Wave path:
wave = Wave(start=Coord(0, 50), end=Coord(200, 50), amplitude=20, frequency=3)
path = Path(wave, width=2, color="blue")
scene.add(path)

# Closed Lissajous with fill:
liss = Lissajous(center=Coord(100, 100), a=3, b=2, delta=math.pi/2, size=80)
path = Path(liss, closed=True, color="navy", fill="lightblue", width=1.5)

# Sub-path (arc) of an ellipse:
ellipse = Ellipse(100, 100, rx=50, ry=30)
arc = Path(ellipse, start_t=0.0, end_t=0.25, color="red", width=2)

# Arc of a closed path as connection shape:
liss_arc = Path(Path.Lissajous(), start_t=0, end_t=0.5)
dot_a.connect(dot_b, path=liss_arc)

# In a cell:
spiral = Spiral(center=cell.center, start_radius=5, end_radius=40, turns=3)
cell.add_path(spiral, color="red", width=1)

Create a Path from a Pathable.

Parameters:

Name Type Description Default
pathable Pathable

Any object implementing point_at(t).

required
segments int

Number of cubic Bézier segments to approximate with. Higher = smoother but more SVG data. 64 is good for most curves; use 128+ for very detailed spirals.

DEFAULT_SEGMENTS
closed bool

If True, the path closes smoothly back to the start and SVG Z is appended. Enables fill.

False
start_t float

Start parameter on the pathable (0.0-1.0). Use with end_t to render a sub-section of the path.

0.0
end_t float

End parameter on the pathable (0.0-1.0). Use with start_t to render a sub-section (arc) of any path.

1.0
width float

Stroke width in pixels.

DEFAULT_WIDTH
color PaintLike

Stroke color.

DEFAULT_COLOR
fill PaintLike | None

Fill color for closed paths (ignored if not closed).

None
z_index int

Layer ordering (higher = on top).

0
cap CapName

Cap style for both ends ("round", "square", "butt", "arrow").

DEFAULT_CAP
start_cap CapName | None

Override cap for start only.

None
end_cap CapName | None

Override cap for end only.

None
opacity float

Overall opacity (0.0 transparent to 1.0 opaque).

1.0
fill_opacity float | None

Override fill opacity (defaults to opacity).

None
stroke_opacity float | None

Override stroke opacity (defaults to opacity).

None

fill property writable

fill: str | None

The fill paint as a string (color or gradient ref), or None.

closed property

closed: bool

Whether this is a closed path.

color property writable

color: str

The stroke paint as a string (color or gradient ref).

anchor_names property

anchor_names: list[str]

Available anchors.

arc_length

arc_length(samples: int = 200) -> float

Approximate the total arc length by sampling each Bézier segment.

Distributes samples evenly across all cubic Bézier segments and sums the polyline chord lengths — accurate for smooth curves with enough samples per segment.

Parameters:

Name Type Description Default
samples int

Total number of evaluation points distributed across all Bézier segments.

200

Returns:

Type Description
float

Approximate arc length in pixels.

angle_at

angle_at(t: float) -> float

Get the tangent angle in degrees at parameter t.

Uses the derivative of the cubic Bézier formula.

Parameters:

Name Type Description Default
t float

Parameter from 0 (start) to 1 (end).

required

Returns:

Type Description
float

Angle in degrees.

point_at

point_at(t: float) -> Coord

Get a point along the path.

Evaluates the stored cubic Bézier segments at parameter t.

Parameters:

Name Type Description Default
t float

Parameter from 0 (start) to 1 (end).

required

Returns:

Type Description
Coord

Coord on the path at parameter t.

to_svg_path_d

to_svg_path_d() -> str

Return the SVG path d attribute string.

Uses Hermite-to-cubic-Bezier fitting with C1 continuity — no sharp corners between segments. Use start_t/end_t to render a portion of any path.

See also

See Paths and Parametric Positioning for path rendering techniques.


EntityGroup

EntityGroup(x: float = 0, y: float = 0, z_index: int = 0, opacity: float = 1.0)

Bases: Entity

A reusable group of entities that behaves as a single entity.

Define child entities relative to (0, 0). When placed, an SVG <g> transform handles positioning and scaling — children are never mutated.

Works with all placement methods: - scene.add(group) — add to scene at group's position - cell.add(group) — center in cell - group.fit_to_surface() — auto-scale to fit surface bounds

For reuse, wrap creation in a factory function — each call returns a new independent instance.

Example
from pyfreeform import EntityGroup, Dot
import math

def make_flower(color="coral", petal_color="gold"):
    g = EntityGroup()
    g.add(Dot(0, 0, radius=10, color=color))
    for i in range(8):
        angle = i * (2 * math.pi / 8)
        x = 15 * math.cos(angle)
        y = 15 * math.sin(angle)
        g.add(Dot(x, y, radius=6, color=petal_color))
    return g

cell.add(make_flower())
cell2.add(make_flower(color="blue"))

Create an EntityGroup.

Parameters:

Name Type Description Default
x float

Initial x position (default 0).

0
y float

Initial y position (default 0).

0
z_index int

Layer ordering (higher = on top).

0
opacity float

Group-level opacity (0.0 transparent to 1.0 opaque).

1.0

children property

children: list[Entity]

The child entities in this group (copy).

rotation property writable

rotation: float

Current rotation angle in degrees.

scale_factor property writable

scale_factor: float

Current cumulative scale factor.

opacity instance-attribute

opacity: float = float(opacity)

add

add(entity: Entity) -> Entity

Add a child entity to this group.

The entity's position should be relative to (0, 0) — the group's local origin. When the group is placed, all children are offset by the group's position via SVG transform.

Parameters:

Name Type Description Default
entity Entity

The entity to add.

required

Returns:

Type Description
Entity

The added entity (for chaining or reference).

rotate

rotate(angle: float, origin: CoordLike | None = None) -> EntityGroup

Rotate the group.

Accumulates an internal rotation angle used by the SVG transform. If origin is provided, also orbits the group's position around that point.

Parameters:

Name Type Description Default
angle float

Rotation angle in degrees (counterclockwise).

required
origin CoordLike | None

Center of rotation in absolute coordinates. If None, rotates in place (children rotate around the group's local origin).

None

Returns:

Type Description
EntityGroup

self, for method chaining.

scale

scale(factor: float, origin: CoordLike | None = None) -> EntityGroup

Scale the group.

Accumulates an internal scale factor used by the SVG transform. If origin is provided, also adjusts the group's position so that the origin point remains fixed (used by fit_to_surface).

Parameters:

Name Type Description Default
factor float

Scale factor (0.5 = half size, 2.0 = double).

required
origin CoordLike | None

Center of scaling in absolute coordinates.

None

Returns:

Type Description
EntityGroup

self, for method chaining.

bounds

bounds(*, visual: bool = False) -> tuple[float, float, float, float]

Bounding box in absolute coordinates.

Delegates to rotated_bounds(0) which recursively computes exact analytical bounds for every child under the group's rotation and scale.

SVG output: <g transform="translate(x,y) rotate(r) scale(s)" opacity="o"> — children are never mutated.

EntityGroup vs CellGroup

EntityGroup inherits Entity — reusable composite shapes. CellGroup inherits Surface — merged multi-cell regions. Different purposes.

See also

See Transforms and Layout for EntityGroup composition patterns.


Point

Point(x: float = 0, y: float = 0, z_index: int = 0)

Bases: Entity

An invisible entity that renders nothing.

Use as a reactive vertex in Polygons or as a connection endpoint. Think of it as a thumbtack on a board — other shapes can reference it, and when the Point moves, everything attached follows.

Anchors
  • "center": The position (same as position)
Example
a = Point(0, 0)
b = Point(100, 0)
c = Point(50, 80)
tri = Polygon([a, b, c], fill="coral")
b.move_to_surface(cell, at=(0.8, 0.3))  # triangle vertex moves

anchor_names property

anchor_names: list[str]

Renders no SVG — used as a movable anchor for reactive polygon vertices or connection endpoints.

# Reactive polygon with add_point
a = cell.add_point(at=(0.5, 0.1))
b = cell.add_point(at=(0.9, 0.9))
c = cell.add_point(at=(0.1, 0.9))
tri = Polygon([a, b, c], fill="coral")
b.at = (0.8, 0.3)  # triangle vertex moves with it

See also

See Reactive Polygons for shared vertices and anchor tracking examples.