To run any of these examples, you’ll want to save a bit of code in a python file, with any name, e.g.
geometry.py, and then run that file by navigating to it on the command line and constructing a call like,
One of the core concepts of Coldtype is the use of the
coldtype.geometry.Rect class to encapsulate rectangles and methods for slicing & dicing them.
The most basic rectangle is the one passed to a renderable, i.e. the
r variable you get when you define a renderable function, like
def rect(r) below. So to fill the entire canvas with a single random color, you can do something like this:
from coldtype import * @renderable((700, 300)) def rect(r): return DATPen().rect(r).f(hsl(random()))
@renderables have a rectangle associated with them (the full rectangle of the artifact canvas), and all rendering functions are passed rectangles, either via the first and only argument, or as a property of the first argument, as is the case with
@animation renderables, which pass a
Frame argument that makes the rectangle accessible via
f is the
But we’re getting ahead of ourselves.
Rect has lots of methods, though the most useful ones are
Here’s a simple example that insets, offsets, and takes.
@renderable((700, 300)) def iot(r): return (DATPen() .rect(r .take(0.5, "mnx") # "mnx" refers to the edge of the rectangle "minimum x" .inset(20, 20) .offset(0, 10)) .f(hsl(0.5)))
More complex slicing & dicing¶
N.B. You may have noticed that the rect functions that a mix of float and int arguments. That’s because a value less than 1.0 will be treated, by the dividing-series of rect functions, as percentages of the dimension implied by the edge argument. So in that
take(0.5, "mnx") above, the
0.5 specifies 50% of the width of the rectangle (width because of the
mnx edge argument).
Here’s an example that divides a rectangle into left and right rectangles, and shows another useful method,
square (which takes the largest square possible from the center of the given rectangle).
@renderable((700, 300)) def lr(r): ri = r.inset(50, 50) left, right = ri.divide(0.5, "mnx") return DATPens([ (DATPen() .rect(ri) .f(None) .s(0.75) .sw(2)), (DATPen() .oval(left .square() .offset(100, 0)) .f(hsl(0.6, a=0.5))), (DATPen() .oval(right .square() .inset(-50)) .f(hsl(0, a=0.5)))])
Here’s an example using
subdivide to subdivide a larger rectangle into smaller pieces, essentially columns.
@renderable((700, 300)) def columns(r): dps = DATPens() for c in r.inset(10).subdivide(5, "mnx"): dps += DATPen().rect(c.inset(10)).f(hsl(random())) return dps
Of course, columns like that aren’t very typographic. Here’s an example using
subdivide_with_leading, a useful method for quickly getting standard rows or columns with classic spacing.
@renderable((700, 500)) def columns_leading(r): dps = DATPens() for c in r.subdivide_with_leading(5, 20, "mxy"): dps += DATPen().rect(c).f(hsl(random())) return dps