Skip to content

Scene

Everything starts with a Scene. Three constructors cover all use cases: Scene(w, h) for freeform art, Scene.from_image() for image-based art, and Scene.with_grid() for grid-based art without an image.

See also

For a hands-on walkthrough, see Scenes and Grids.

Scene

Scene(width: int, height: int, background: str | tuple[int, int, int] | None = None)

Bases: Surface

The main container for all drawable objects in PyFreeform.

A Scene holds entities, grids, and connections. It manages rendering to SVG and provides the primary API for creating artwork.

Creating Scenes

scene = Scene.from_image("photo.jpg", grid_size=40)

With an empty grid

scene = Scene.with_grid(cols=30, rows=30, cell_size=12)

Manual (for non-grid art)

scene = Scene(800, 600, background="#fafafa")

Working with the Grid
scene = Scene.from_image("photo.jpg", grid_size=40)
for cell in scene.grid:
    cell.add_dot(color=cell.color)
scene.save("art.svg")

Attributes:

Name Type Description
width float

Scene width in pixels

height float

Scene height in pixels

background str | None

Background color (or None for transparent)

grid Grid

The primary grid (if created with from_image or with_grid)

Create a new empty scene.

For image-based art, use Scene.from_image() instead. For grid-based art, use Scene.with_grid() instead.

Parameters:

Name Type Description Default
width int

Scene width in pixels.

required
height int

Scene height in pixels.

required
background str | tuple[int, int, int] | None

Background color (None for transparent).

None

background property writable

background: str | None

Background color as string, or None.

grid property

grid: Grid

The primary grid (created by from_image or with_grid).

Index by row then column, iterate for all cells:

  • scene.grid[row][col] — single cell
  • scene.grid[row] — list of cells in that row
  • for cell in scene.grid: — all cells, row by row

Raises:

Type Description
ValueError

If scene was created without a grid.

Example
scene.grid[0][0].add_fill(color="coral")

for cell in scene.grid:
    cell.add_dot(color=cell.color)

grids property

grids: list[Grid]

All grids in the scene.

entities property

entities: list[Entity]

All entities (including those in grids).

connections property

connections: list[Connection]

All connections in the scene (auto-collected from entities and surfaces).

from_image classmethod

from_image(source: str | Path | Image, *, grid_size: int | None = 40, cell_size: int = 10, cell_ratio: float = 1.0, cell_width: float | None = None, cell_height: float | None = None, background: str | None = None) -> Scene

Create a scene from an image file (one-liner for image-based art).

This is the recommended way to create image-based artwork:

scene = Scene.from_image("photo.jpg", grid_size=40)
for cell in scene.grid:
    cell.add_dot(color=cell.color)
scene.save("art.svg")
Two modes
  • grid_size=N (default): N columns, auto rows from aspect ratio. Scene size = cols * cell_size x rows * cell_size.
  • grid_size=None: Grid fits the image. Cols/rows derived from image dimensions ÷ cell size. Scene size ≈ image dimensions.

Parameters:

Name Type Description Default
source str | Path | Image

Path to image file, or an Image object.

required
grid_size int | None

Number of columns (rows auto-calculated from aspect ratio). Pass None to derive grid from image dimensions.

40
cell_size int

Base size of each cell in pixels.

10
cell_ratio float

Width-to-height ratio (e.g., 2.0 for domino cells).

1.0
cell_width float | None

Explicit cell width (overrides cell_size and cell_ratio).

None
cell_height float | None

Explicit cell height (overrides cell_size).

None
background str | None

Background color (defaults to dark blue).

None

Returns:

Type Description
Scene

Scene with grid loaded from image, ready to iterate.

The grid's cells will have typed properties: - cell.color: Hex color string - cell.brightness: Float 0.0-1.0 - cell.rgb: Tuple (r, g, b) - cell.alpha: Float 0.0-1.0

with_grid classmethod

with_grid(*, cols: int = 30, rows: int | None = None, cell_size: int = 10, cell_width: float | None = None, cell_height: float | None = None, background: str | None = None) -> Scene

Create a scene with an empty grid (for non-image-based art).

scene = Scene.with_grid(cols=30, rows=30, cell_size=12)
for cell in scene.grid:
    cell.add_dot(color="coral")
scene.save("art.svg")

Parameters:

Name Type Description Default
cols int

Number of columns.

30
rows int | None

Number of rows (defaults to same as cols for square grid).

None
cell_size int

Base size of each cell in pixels.

10
cell_width float | None

Explicit cell width (overrides cell_size).

None
cell_height float | None

Explicit cell height (overrides cell_size).

None
background str | None

Background color.

None

Returns:

Type Description
Scene

Scene with empty grid, ready to iterate.

add_grid

add_grid(grid: Grid) -> Grid

Add a grid to the scene.

Grids created via Scene.from_image() or Scene.with_grid() are added automatically. Use this only for manually-created grids.

Parameters:

Name Type Description Default
grid Grid

The Grid to add.

required

Returns:

Type Description
Grid

The added grid (for chaining).

remove

remove(entity: Entity) -> bool

Remove an entity from the scene.

Searches both direct entities and grid cells.

Parameters:

Name Type Description Default
entity Entity

The entity to remove.

required

Returns:

Type Description
bool

True if entity was found and removed.

remove_grid

remove_grid(grid: Grid) -> bool

Remove a grid from the scene.

Parameters:

Name Type Description Default
grid Grid

The grid to remove.

required

Returns:

Type Description
bool

True if grid was found and removed.

clear

clear() -> None

Remove all objects from the scene.

to_svg

to_svg() -> str

Render the scene to an SVG string.

Entities and connections are sorted by z_index before rendering. Lower z_index values render first (underneath). Higher z_index values render last (on top).

Returns:

Type Description
str

Complete SVG document as string.

save

save(path: str | Path, renderer=None) -> None

Save the scene to an SVG file.

Parameters:

Name Type Description Default
path str | Path

File path (will add .svg extension if missing).

required
renderer

Optional Renderer instance. Defaults to SMILRenderer.

None

crop

crop(padding: float = 0) -> Scene

Crop the scene viewBox to fit the visual bounds of all content.

Useful for transparent exports (icons, badges) where you don't want dead space around the artwork.

Parameters:

Name Type Description Default
padding float

Extra space around the content in pixels.

0

Returns:

Type Description
Scene

self, for method chaining.

Example
scene = Scene.with_grid(cols=1, rows=1, cell_size=200)
scene.background = None
cell.add_dot(color="coral")
scene.crop()       # Tight crop
scene.crop(10)     # 10px breathing room
scene.save("icon.svg")

trim

trim(top: float = 0, right: float = 0, bottom: float = 0, left: float = 0) -> Scene

Remove pixels from one or more edges of the scene.

Adjusts the viewBox so the specified number of pixels are clipped from each side. Can be chained with :meth:crop.

Parameters:

Name Type Description Default
top float

Pixels to remove from the top edge.

0
right float

Pixels to remove from the right edge.

0
bottom float

Pixels to remove from the bottom edge.

0
left float

Pixels to remove from the left edge.

0

Returns:

Type Description
Scene

self, for method chaining.

Example
scene.trim(top=20)                # clip 20px from the top
scene.trim(top=10, bottom=10)     # clip both edges
scene.crop().trim(left=5, right=5)  # tight crop then shave sides