Your First Artwork¶
PyFreeform gives you two ways to create art: from an image or from scratch. Both use the same powerful grid system.
Load an Image¶
Scene.from_image() divides a photo into a grid of cells. Each cell knows the color and brightness of the pixels beneath it.
from pyfreeform import Scene
scene = Scene.from_image("MonaLisa.jpg", grid_size=35, cell_size=12)
for cell in scene.grid:
cell.add_dot(radius=0.25, color=cell.color) # (1)!
scene.save("artwork.svg")
cell.coloris the hex color sampled from the image at this cell's position.
Size by Brightness¶
Make bright areas pop and dark areas recede by tying dot radius to brightness:
for cell in scene.grid:
radius = cell.brightness * 0.42 # (1)!
if radius > 0.025:
cell.add_dot(radius=radius, color=cell.color)
cell.brightnessis a float from 0.0 (black) to 1.0 (white).
Polish It¶
Add a subtle border and vary opacity for a finished look:
scene = Scene.from_image("MonaLisa.jpg", grid_size=40, cell_size=11)
for cell in scene.grid:
radius = cell.brightness * 0.45
if radius > 0.027:
cell.add_dot(
radius=radius,
color=cell.color,
opacity=0.6 + cell.brightness * 0.4,
)
for cell in scene.grid.border(): # (1)!
cell.add_border(color="#333344", width=0.3)
scene.save("artwork.svg")
grid.border()selects only the cells on the grid's outer edge.
Start with a Grid¶
Scene.with_grid() creates an empty grid — no image needed. Use position and math to drive the visuals.
from pyfreeform import Scene, Palette
colors = Palette.sunset()
scene = Scene.with_grid(cols=12, rows=12, cell_size=25, background=colors.background)
for cell in scene.grid:
if (cell.row + cell.col) % 2 == 0:
cell.add_fill(color=colors.primary, opacity=0.7)
else:
cell.add_fill(color=colors.secondary, opacity=0.3)
scene.save("pattern.svg")
Add Shapes¶
Use cell.normalized_position to drive size, rotation, and opacity based on where each cell sits in the grid:
from pyfreeform import Polygon
for cell in scene.grid:
nx, ny = cell.normalized_position # (1)!
t = (nx + ny) / 2
cell.add_polygon(
Polygon.diamond(size=0.3 + t * 0.5),
fill=colors.accent,
opacity=0.4 + t * 0.6,
rotation=t * 45,
)
normalized_positionreturns (nx, ny) where both values range from 0.0 (top-left) to 1.0 (bottom-right).
Layer Curves for Flow¶
Stack curves on top for an organic finish:
import math
for cell in scene.grid:
nx, ny = cell.normalized_position
curvature = math.sin(nx * math.pi * 2) * 0.6
cell.add_curve(
start="left", end="right",
curvature=curvature,
width=0.8,
color=colors.line,
opacity=0.3 + ny * 0.4,
)
What's Next?¶
You've seen how PyFreeform turns a few lines of code into visual art. Now learn the concepts behind it: