Shapes & Polygons¶
PyFreeform includes 8 built-in shape classmethods and a powerful EntityGroup system for composing your own.
Shape Gallery¶
All shapes are created as vertex lists and passed to add_polygon():
from pyfreeform import Polygon
cell.add_polygon(Polygon.hexagon(size=0.7), fill="coral")
cell.add_polygon(Polygon.star(points=5, size=0.7), fill="gold")
Available Shapes¶
| Method | Description |
|---|---|
Polygon.triangle(size=0.8) |
Equilateral triangle |
Polygon.square(size=0.8) |
Axis-aligned square |
Polygon.diamond(size=0.8) |
45-degree rotated square |
Polygon.hexagon(size=0.8) |
Regular hexagon |
Polygon.star(points=5, inner_ratio=0.4) |
N-pointed star |
Polygon.regular_polygon(sides, size=0.8) |
Any regular N-gon |
Polygon.squircle(size=0.8, n=4) |
Superellipse (n=2: circle, n=4: squircle) |
Polygon.rounded_rect(corner_radius=0.2) |
Rectangle with rounded corners |
All return list[tuple[float, float]] in relative coordinates (0-1), ready for any cell size.
Creative Applications¶
Hexagonal Tiling¶
for cell in scene.grid:
cell.add_polygon(
Polygon.hexagon(size=0.85),
fill=colors.primary,
stroke=colors.secondary,
stroke_width=0.5,
opacity=0.3 + t * 0.5,
)
Shape by Brightness¶
Choose shapes based on image data:
for cell in scene.grid:
b = cell.brightness
if b < 0.5:
verts = Polygon.star(points=5, size=0.4 + b)
else:
verts = Polygon.hexagon(size=0.4 + b * 0.4)
cell.add_polygon(verts, fill=cell.color)
EntityGroup¶
An EntityGroup is a composite entity — build it from simpler entities, then place it in any cell:
from pyfreeform import EntityGroup, Dot, Ellipse
def make_flower(petal_color, center_color):
group = EntityGroup()
for i in range(6):
angle = i * 60 * math.pi / 180
px, py = 12 * math.cos(angle), 12 * math.sin(angle)
group.add(Ellipse(px, py, rx=8, ry=4, rotation=i * 60, fill=petal_color, opacity=0.7))
group.add(Dot(0, 0, radius=5, color=center_color))
return group
Use it across cells:
for cell in scene.grid:
flower = make_flower(colors.primary, colors.accent)
cell.add(flower)
flower.fit_to_cell(0.85)
New instance per cell
Always create a new EntityGroup for each cell. Groups placed in cells should not be reused directly — wrap creation in a factory function.
Reactive Polygons¶
Polygon vertices don't have to be static coordinates — they can reference live entities. When a referenced entity moves, the polygon deforms automatically.
The Point Entity¶
A Point is an invisible entity that renders nothing. Think of it as a thumbtack on a board — other shapes can reference it, and when the Point moves, everything attached follows.
from pyfreeform import Point, Polygon
# Direct constructor (pixel coordinates)
a = Point(0, 0)
b = Point(100, 0)
c = Point(50, 80)
tri = Polygon([a, b, c], fill="coral")
Use add_point in cells
When working inside cells, prefer cell.add_point(at=(0.5, 0.1)) — it uses the same relative coordinate system as all other builder methods.
Shared Vertices¶
The real power: multiple polygons can share the same Point vertex. Moving the shared point deforms every polygon that references it:
shared = Point(150, 40)
tri1 = Polygon([Point(50, 150), Point(130, 150), shared], fill="coral", opacity=0.7)
tri2 = Polygon([Point(170, 150), Point(250, 150), shared], fill="teal", opacity=0.7)
# Move the shared vertex — both triangles deform
shared.position = (200, 30)
Anchor Tracking¶
Vertices can also track a specific anchor on any entity. Use the (entity, "anchor_name") syntax:
from pyfreeform import Point, Polygon, Rect, Coord
rect = Rect.at_center(Coord(200, 100), 100, 70, fill="teal")
tip = Point(50, 30)
# Polygon with one Point vertex and two Rect anchor vertices
tri = Polygon([tip, (rect, "top_left"), (rect, "top_right")], fill="coral", opacity=0.6)
Connections vs reactive vertices
Connections are live lines between entities — visual links that redraw when endpoints move.
Entity-reference vertices are live shape corners — polygon vertices that track entity positions. The polygon itself is the visual element; the vertices just follow.
Use connections when you want visible links. Use entity-ref vertices when you want shapes that deform.
Transforms and entity vertices
polygon.rotate() and polygon.scale() only affect static (Coord) vertices. Entity-reference vertices follow their entity, not polygon transforms.
fit_to_cell¶
Auto-scale any entity or group to fit within its cell:
0.7means fill 70% of the cell's area.
With Rotation¶
fit_to_cell works correctly with rotated groups:
What's Next?¶
Learn text placement, typography, and text-along-path effects: