meander provides a core function reflow to segment pages and wrap content around images.
See the documentation.
Quick start
The function meander.reflow takes a sequence of
- obstacles: use
placedto put content at specific positions of the page, - containers: use
containerto specify where text can be laid out, - flowing content: provide text with
content. - optionally
pagebreak,colbreak,colfillcan be used to produce multi-page layouts and fine-tune which text goes into which container.
#let my-img-1 = box(width: 7cm, height: 7cm, fill: orange)
#let my-img-2 = box(width: 5cm, height: 3cm, fill: blue)
#let my-img-3 = box(width: 8cm, height: 4cm, fill: green)
#let my-img-4 = box(width: 5cm, height: 5cm, fill: red)
#let my-img-5 = box(width: 4cm, height: 3cm, fill: yellow)
#import "@preview/meander:0.2.5"
#meander.reflow({
import meander: *
// As many obstacles as you want
placed(top + left, my-img-1)
placed(top + right, my-img-2)
placed(horizon + right, my-img-3)
placed(bottom + left, my-img-4)
placed(bottom + left, dx: 32%,
my-img-5)
// The container wraps around all
container()
content[
#set par(justify: true)
#lorem(430)
]
})

Use multiple containers to produce layouts in columns.
#let my-img-1 = box(width: 7cm, height: 7cm, fill: orange)
#let my-img-2 = box(width: 5cm, height: 3cm, fill: blue)
#let my-img-3 = box(width: 8cm, height: 4cm, fill: green)
#import "@preview/meander:0.2.5"
#meander.reflow({
import meander: *
placed(bottom + right, my-img-1)
placed(center + horizon, my-img-2)
placed(top + right, my-img-3)
// With two containers we can
// emulate two columns.
// The first container takes 60%
// of the page width.
container(width: 60%, margin: 5mm)
// The second container automatically
// fills the remaining space.
container()
content[#lorem(470)]
})

If your Meander environment shares page(s) with other content,
use the option placement: box.
The overflow parameter determines what happens to text that doesn’t
fit inside the provided containers.
You can see this in effect in the example below:
- the text in green is before the Meander environment
- the text in blue is the Meander environment itself
- the text in black is the overflow handled by Meander
- the text in red is after the meander environment
#import "@preview/meander:0.2.5"
#set par(justify: true)
#text(fill: green)[
#lorem(200)
]
#meander.reflow(
placement: box,
overflow: text,
{
import meander: *
container(
width: 48%,
height: 50%,
style: (text-fill: blue),
)
container(
width: 48%,
height: 50%,
align: right,
style: (text-fill: blue),
)
content[#lorem(700)]
})
#text(fill: red)[
#lorem(200)
]

Meander allows precise control over the boundaries of obstacles, to draw complex paragraph shapes.
#import "@preview/meander:0.2.5"
#meander.reflow({
import meander: *
placed(
center + horizon,
boundary:
// Override the default margin
contour.margin(1cm) +
// Then redraw the shape as a grid
contour.grid(
// 25 vertical and horizontal subdivisions.
// Just pick a number that looks good.
// A good rule of thumb is to start with obstacles
// about as high as one line of text.
div: 25,
// Equation for a circle of center (0.5, 0.5) and radius 0.5
(x, y) => calc.pow(2 * x - 1, 2) + calc.pow(2 * y - 1, 2) <= 1
),
// Underlying object
circle(radius: 3cm, fill: yellow),
)
container(width: 48%)
container(align: right, width: 48%)
content[
#set par(justify: true)
#lorem(570)
]
})

For a more in-depth introduction, including
- debug mode,
- alternative recontouring techniques,
- styling options,
- multi-page handling and page overflow options,
- tips to get better segmentation,
please consult the documentation.