Skip to content

Colors, Styles & Palettes

PyFreeform provides a coherent color and styling system. Master three concepts: the color parameter split, style objects, and palettes.

The Color Parameter Split

This is the most important API distinction to remember:

Parameter Used by Description
color= Dot, Line, Curve, Text, add_fill, add_border Stroke-like entities
fill= Rect, Ellipse, Polygon Filled shapes

fill= vs color= comparison

Top row: entities using color=. Bottom row: entities using fill=.

Common mistake

Writing cell.add_polygon(verts, color="red") will raise an error. Use fill="red" for shapes.

Color Formats

All color parameters accept:

  • Named colors: "red", "coral", "navy", "salmon"
  • Hex strings: "#ff6b6b", "#f00", "#FF6B6B"
  • RGB tuples: Colors from cell.rgb can be formatted to hex with cell.color

Opacity

Every entity supports opacity (0.0 transparent → 1.0 opaque, default 1.0):

cell.add_dot(radius=0.1, color="coral", opacity=0.5)
cell.add_fill(color="navy", opacity=0.3)

Shape-Specific: fill_opacity & stroke_opacity

Shapes (Rect, Ellipse, Polygon) support independent opacity for fill and stroke:

cell.add_ellipse(
    rx=0.45, ry=0.45,
    fill=colors.primary,
    stroke=colors.accent,
    stroke_width=3,
    fill_opacity=0.4,     # Semi-transparent fill
    stroke_opacity=1.0,   # Fully opaque stroke
)

Fill opacity progression

Fill opacity from 0.2 to 1.0 with constant stroke opacity.

Layered Opacity

Stack semi-transparent shapes for color mixing effects:

Opacity layering

Three overlapping circles at 50% opacity — colors blend where they overlap.

Style Objects

Instead of repeating parameters, define a style object once and reuse it:

from pyfreeform import DotStyle, LineStyle, ShapeStyle

dot_small = DotStyle(color="coral", opacity=0.6)
dot_large = DotStyle(color="gold", opacity=0.9)
line_thin = LineStyle(width=1, color="#666688", opacity=0.4)
shape_hex = ShapeStyle(color="teal", opacity=0.5)

for cell in scene.grid:
    cell.add_dot(radius=0.15, style=dot_small)  # Apply directly
    cell.add_line(start="top", end="bottom", style=line_thin)

Style reuse

Three zones using different pre-defined styles — consistent look with no parameter repetition.

All Style Classes

Class For Methods Key Fields
DotStyle add_dot() color, opacity
LineStyle add_line(), add_diagonal(), add_curve(), add_path() width, color, cap, start_cap, end_cap
FillStyle add_fill() color, opacity
BorderStyle add_border() width, color, opacity
ShapeStyle add_ellipse(), add_polygon(), add_rect() color (→ fill), stroke, stroke_width
TextStyle add_text() color, font_family, bold, italic
ConnectionStyle Connection width, color, cap

Builder Methods

Styles are immutable. Use .with_*() to create modified copies:

base = LineStyle(width=2, color="coral")
thick = base.with_width(4)          # New style, width=4
arrow = base.with_end_cap("arrow")  # New style, with arrow cap

Palettes

8 pre-built color palettes with 6 named colors each:

Midnight

Midnight

Sunset

Sunset

Ocean

Ocean

Forest

Forest

Monochrome

Monochrome

Paper

Paper

Neon

Neon

Pastel

Pastel

Using Palettes

from pyfreeform import Palette

colors = Palette.midnight()
scene = Scene.with_grid(cols=10, rows=10, cell_size=20, background=colors.background)

for cell in scene.grid:
    cell.add_dot(color=colors.primary)
    cell.add_border(color=colors.grid, width=0.3)

Named Colors

Name Purpose
colors.background Scene background
colors.primary Main element color
colors.secondary Supporting element color
colors.accent Highlight/emphasis color
colors.line Lines and connections
colors.grid Grid borders

Custom Palettes

my_palette = Palette(
    background="#1a1a2e",
    primary="#ff6b6b",
    secondary="#4ecdc4",
    accent="#ffe66d",
    line="#666688",
    grid="#3d3d5c",
)

Utilities: colors.with_background("#000"), colors.inverted(), colors.all_colors().


What's Next?

Learn the "killer feature" — positioning entities along any path:

Paths & Parametric Positioning →