Panelcode: layout markup and visualization

Jeremy Douglass

Panelcode is a minimal markup language for describing visual compositions as abstract layouts.

Use Panelcode to quickly encode visual layouts for search and visual exploration. Panelcode is optimized to be quickly and easily writable, readable, and editable by hand, with an emphasis on speed, concision, and human judgement. The tools were developed with a particular focus on compositions made of panels such as those occuring in comics, graphic novels, newspapers, magazines, websites, et cetera, and the first test cases have been performed on comics.

Panelcode supports multiple encoding schemes, but examples in this document use its base scheme: gridcode. Panelcode also has many extensions and shorthands, a number of which are touched on here: markup for blank spaces, annotations, unencoded regions, panel shapes, and bleeds. Finally, Panelcode has renderers to create multiple outputs, including SVG (Scalable Vector Graphics), scaffolding TEI-XML, and HTML-Tables.

This document focuses on the gridcode HTML5-CSS3 renderer, which renders panelcode as either HTML5 web content or stand-alone SVG image files. It is an illustrated tour of some of Panelcode’s rendering features. Rather than walking through the complete language syntax, or discussing the design of the parser, it instead focuses on the gridcode renderer and walks through an illustrated tour of basic examples of Panelcode and what you can do with it: describe, summarize, compare, annotate, and vizualize layouts. This renderer supports:

This page was rendered from a Markdown document with inline Panelcode. Throughout the page you will find rendered examples – hover over them to access resizing controls and to unfold the code view, showing the code which rendered the gallery

Basics: rows and columns

Panelcode is a very efficient shorthand when encoding simple page layouts. Encodings may be written by hand and then parsed and programmatically processed for many purposes: searching, analyzing, rendering graphics and creating information visualizations, or producing scaffolds for layout editing or marking up pages with metadata.

A number in Panelcode signifies a simple row of panels. A single number (“3”) is a valid Panelcode string that describes a layout with a single row of 3-columns.

The Panelcode strings “1” “2” and “3” appearing at the bottom of each glyph are not page numbers – each number describes the row of panels in each layout.

In Panelcode, a sequence of panels is the basic unit of description: A “4” means four panels, as in a typical daily newspaper comic, for example. Those panels proceed in whatever typical reading order they were encoded in – left-to-right rows and top-to-bottom columns, in this case, but Panelcode input and/or output can be automatically mirrored for e.g. manga, scanlations and imported reprints.

Rows are joined into layout stacks using underscores: 1_1 or 1_1_1.

The default row operator “_” (the underscore) is the glue used to build complex pages by connecting of simple rows. While 3 described three horizontal panels, 1_1_1 describes three vertical panels. This can be made more concise with one of the shorthand extensions, but it reflects a fundamental aspect of panelcode “gridcode”-style encoding design: it is organized by a primary reading order (top-to-bottom) and a secondary reading order (in this case, left-to-right). In fact, panels connected by the column operator “+” are commonly collapsed into row counts: the horizontal panelcode layout 3 could also be writtn 1+1+1. (The vertical panelcode layout 1_1_1 can – with an extension – be written 3v.)

Combine different row counts into layouts: 1_2, 1_2_3 et cetera.

When the row operator is used to combine rows then each row may have different panel counts, and every row is assumed by default to be full-width with its own unique panel dimensions. This is fundamentally unlike a spreadsheet, HTML <table>, or other tabular data presentation system. In such systems columns are fixed, and rows must be marked of in units or multiples of those columns. In order to create a 1_2_3_4 on a spreadsheet requires 12 columns, and each row must be expressed in multiples of those columns.

These fixed column constraints are essentially the limitations of attempting to express design grids in tabular data presentation formats. By contrast Panelcode is based on a flexible design grid paradigm – and in fact uses the emerging CSS flex / flexbox and CSS grid standards for this renderer, which are likewise based on an evolution of web design away from tabular data and towards design grids.

[Although note that the original Panelcode HTML-Tables renderer accomplished this by making every row or rowgroup its own independent table – such workarounds are often painful, but not impossible.]

Combine 2_2 or 3_3_3 row counts into stacks to form grids.

This is not to say that spreadsheet-style grids are impossible or even difficult in Panelcode. A chessboard-sized grid can be described by an 8_8_8_8_8_8_8_8 – or, using multiplier shorthand, an 8*8.

Reading a Panelcode Image

Panelcode visualizations may have a different appearance and different elements depending on the renderer, however there are some basics that are common to the Panelcode concepts. Consider this glyph:

A Panelcode glyph is an abstract representation of a layout – like a design wireframe. It may describe a page, a screen, or some other medium – and, in fact, it may describe many different objects as having the same abstract composition. In fact, this abstraction is the key to comparing disperate layouts. (To say that two graphic novel pages have the same glyph is less like saying two songs have the same notes or two poems have the same rhymes, and more like saying two songs have the same rhythm, or that two poems have the same rhyme scheme.)

The margins of a Panelcode glyph may display additional information, including:

Depending on the renderer this box-model of a page or screen may support empty area and unencoded regions (see more below). It may also support the use of encoded metadata to styling panels with different textures or colors etc. to indicate their nature – e.g. full page spread – or annotations of contents – e.g. incidents of speech (see more below). Panelcode glyphs are designed to be viewed en masse in large collections or from a distance, but individaul panels may include numbers that indicate the encoding order – which is often (but not always) the expected reading order for the panels in a given layout.

Panelcode glyphs appear by default on an abstract unit square – for example, it is neither the vertical rectangle of the comic book nor the horizontal rectangle of the newspaper cartoon strip. This is to emphasize the concept that a particular geometric arragement of panels might refer to either medium, or both, or something.Panelcode glphys can also be styled to media-specific dimensions – either the dimensions of a media genre (e.g. a contemporary US comic), a specific object (e.g. Mouse Guard), or a mixed media collection (e.g. the artifacts of Building Stories).

The glyph for c3+1_2_1+c3 rendered on a unit square, then rerendered while tagged as a newspaper comicstrip (14x10 aspect ratio, Sunday half-page) or as a comicbook page (11x17 aspect ratio, contemporary US comic). Panelcode output may visually match the specific media it was encoded from, or it may also abstract page dimensions when comparing layouts in mixed media collections.


Spans are a simple way of creating more complex layouts than combining rows will allow. A span specifies that a panel is proportionately wider that other in its row (column span) or that a panel occupies multiple rows in a rowgroup (row span). A panel may have both its column span and row span specified. In Panelcode spans are indicated with the c and r attributes, which are attached to panels as suffixes.

Column Spans

Columns are the basic unit of panelcode: 1, 2, 3 etc. is the code for a single row of 1, 2, or 3 columns. Panels in simple rows are commutative: a row of 3 = 2+1 = 1+1+1 – all describe the same layout.

However, this assumes that each panel is of the same proportional width. When this is not the case, the c attribute plus a number argument can be added to individual panels to define their proportional width in units. The panelcode 2 is instead written as an expanded group of 1 + 1 of individual panels. One of those panels is annotated with the suffix .c2 – this sets the column span equal to 2, making the second column twice as wide as the first (and its default span of c1).

Panelcode attributes are each attached to the panel number with a . – several attributes may be chained, in any order. When the number is 1, the attribute affects only that panel. When the number describes a simple group, the attribute applies to every panel in that group.

A common use of column spans in comic layouts is to create staggered rows.

Note that writing panelcode in a compact style, the initial . may be ommitted: 1c2. Further, the panel number 1 may be ommited – a bare attribute c2 implicitly modifies a single panel.

Row Spans

Rows are also fundamental to panelcode – multiple simple rows may be assembled into a single layout with the row delimiter _, e.g. 1_2. For panels that cross multiple rows, however, simple rows must instead defined as complex rowgroups using the , rowgroup delimiter, and a panel must be marked with the rowspan attribute r plus the number of rows to span – 1.r2, 1.r3 et cetera. As with column spans, the 1.r2 row span may be shortened to 1r2 – or simply r2.

One of the most common rowgroups is the simple left-hand rowspan: r2+1,1.

This looks complex when compared with the similar layouts 1_2 or 2_1.

Because the long panel is oriented horizontally rather than vertically these layouts can be described without rowspan notation – but rowgroup delimiters introduce a lot of flexibilty to build complex layouts.

The + delimiter continues along the same row, while the , delimiter acts like a carriage return, leaving the row and proceeding to the next available blank space below. For example, in r5 + r4, 1, the next available space for the 1 is on the 5th row.

[This concept of a “rowspan” argument is present in early HTML Tables, and also incorporated into CSS3 Grid. Panelcode uses these concepts in part because they are longstanding traditions in rendering tabular data, and in part because shared concepts make it easier to parse a panecode string into a straightforward sequence of HTML or CSS elements that can directly render the described layout.]

Column span and row span attributes may also be combined, as in the multi-row, multi-column panel in this example:

These C-shaped compositions of 3 panels are uncommon in newspaper comics, but are an extremely common building block of graphic novel and comicbook pages. A typical comicbook might composite this panelgroup along with one or two simple rows:


Panelcode can also specify methods for companion image display. Specfing an img path displays that image on top of the layout. The ishow and ihide attributes make the image interactively show or hide on hover.

Use iover to style the image as semi-opaque (onion skin). The “over” image layer can also be made interactive with ishow or ihide – from barely opaque to fully shown, or from barely transparent to fully hidden.

Images can also be displayed in a companion layout joined into a spread either before or after the associated panelcode layout, using ibefore or iafter. These inserted pages optionally take a separate label, ilabel.

Finally, a collection such as a spread or gallery can all be styled in the same way using a single argument. Here is a gallery:

- styled with iover ishow:


Panelcode can be rendered in different display sizes and styles for different purposes. Shown here: full size (default), thumb, mini, micro, and micro2.

These glyphs are the same html or SVG output, but rendered with a different CSS3 class label. The level of display detail is styled as well – “thumb” has a caption and panel id, “mini” has only a caption, and “micro” is just a bare glyph image. Collections of Panelcode glyphs can be restyled at the gallery webpage level by changing a single class tag.

default style







The following sequence counts through the number of simple, row-based compositions of 1-3 rows, and 1-3 panels per row, giving a maximum grid of 3x3.

An interesting property of Panelcode strings is that, once reduced to simple rows, each string is part of a numeric sequence, counting through the space from a blank page up to the maximum compositional grid. For example, given a work which is never more than 3 columns wide or 3 rows tall, any Panelcode is a ternary number (base 3), running from 1 (a full page) to 3_3_3 (a 3x3 grid).

Panelcodes (and hence the layouts the represent) can be sorted ), and these sortings have some interesting properties. and a set of strings can be sorted. This sorts a . ternary (base 3) number. complexity of each page. A zero-padded numeric sort (shown here) (those composed of simple rows) is that they can be sorted within a maximum grid (e.g. 2x2, 3x3, 4x4). Different sortings methods present different groupings of intuitively “similar” layouts. For example, an alphabetic sort groups layouts by increasing complexity of the top row (1, 2, 3 panels) and then by the second row within each group (1_1, 1_2, 1_3), et cetera.


Consider the example of comics. While some genres of comics (such as newspaper strips) generally subdivide the available space into panels, many other forms commonly use compositions that leave significant regions of blank space.

When a 0 is used to encode a blank region the corresponding empty area is rendered on the Panelcode grid. For example, 1_0 encodes a page whose bottom half is empty.

In the most complex cases, empty panels can also take column and row arguments, so compositions with large whitespace regions or complex combinations of blank and filled areas can be quickly marked: (0+0c2r2,1)_(c2+0)_(1+c2).

Ambiguity and Complexity

An empty or blank panel is a placeholder – the 0 in a blank panel indicates that it does not count towards the total of a group or a total composition. By contrast, unencoded regions may count for one panel – or more than one panel.

An unencoded region is a collection of panel-like objects whose geometry is too complex or too non-cartesian to be encode in Panelcode shorthand.


Scale is a descriptions independent of the encoding direction. Whether using left-to-right (LTR) or right-to-left (RTL) encoding, a scaled panel will look the same.

This is not the case for skew, tilt, or rotation, however. These are described in terms of the reading / encoding order. Skewing “forward” leans in to the reading direction, “back” leans away. Tilting and rotate “up” rises in the reading direction, “down” falls.

Fill: color and style


Comic Books

Newspaper comicstrips: ratios and flow

The newspaper comic strip, as a form, has a very interesting relationship to panel geometry. Panels almost invariably hhave a fixed height and often have a fixed sequence of width ratios – traditionally 3:1:2:2:1:3. These ratios were designed with a fluid layout property: a single piece is produced as a six-panel sequence may be laid out (or may have been laid out) in a variety of column counts and aspect ratios in different newspapers, taking up a quarter page or half page, respectively – or a third of a page, if the optional first two panels are dropped – or even (rarely) a full page.

When there is no specific page (or there are many pages, or the page is fluid) then Panelcode can render a sequence of panel geometry without a particular page formatting.

(NOTE: did this with w12, could create wx and/or use flex. Also overrode unit square dimensions manually– could make horizontal scroll a style tmeplate).

The Panelcode here is a simple list of column ratios. It has been further annotated with color so that we can more easily see the panels flow between different layouts.

(1.c3     + 1        + 1.c2       + 1.c2      + 1      + 1.c3)  
( + 1.yellow + + 1.c2.cyan + + 1.c3.magenta)

While a comic strip would never appear in this extreme horizontal format in a newspaper, this stream of panels can automatically flow into a dynamic layout – for example with no particular columns specified, the CSS3 layout algorithm packs the panels into a unit square in a way that echos the row arrangement of the “Sunday full-page,” one of the layouts for which the six-panel comic strip format was originally designed.

Other major reconfigurations of the Sunday newspaper also emerge automatically from setting the number of layout columns, including the quarter-page, half-page, and full-page.

One of the interesting properties of Panelcode is that these simple layout regroupings – the kind that a newspaper might perform during layout – are manifest in the transformation of one layout to another. Beginning with the Panelcode for a long strip of panels, we can indicate the row groups of any of the standard newspaper layouts merely by rearranging parantheses:

    no col, 1 rows:  (c3 + 1 + c2 + c2 + 1 + c3)  
     6 col, 2 rows:  (c3 + 1 + c2)_(c2 + 1 + c3)  
     4 col, 3 rows:  (c3 + 1)_(c2 + c2)_(1 + c3)  
     3 col, 4 rows:  (c3)_(1 + c2)_(c2 + 1)_(c3)

While in graphic novels and comicbooks the unit of composition is often the page itself, in the comicstrip the unit of composition is often part of a page – whether in a newspaper publication or in a compendium of reprints. Panelcode can be used to mark up compositions of multiple layouts, layouts can be joined together into pages, and pages can be joined together into two-page spreads (or more).


Links: Daily strips might be in a single column or in a double-column – e.g. see THE DAILY GRUNT, 2003 or a 1949 comics page from the Huntingdon Daily News. See also a Daily Herald Sunday page.


An encoding may indicate and be rendered in Lef-to-Right (LTR) or Right-to-Left (RTL) reading order.

Here the same Panelcode string is rendered in Japenese manga reading order on the right and as a mirrored translation on the left. Panel labels are preserved, with “1” starting in the upper right or upper left, respectively.

A sequence of pages can also be rendered RTL, as when encoding the pages of a tankoban. Here the Panelcode:


…is rendered as a right-to-left page sequence of RTL pages, with panel “1” beginning on the far right and “9” ending on the lower left.


A bleed is an annotation on a panel indicating that it proceeds over the margin and to the edge of the layout space. Panels bleeds are specified with the keyword bleed plus a directional suffix – they may bleed up, down, back, or forward.

Direction can be combined. A panel with adjascent bleeds in two directions proceeds to a corner. A panel with opposing bleeds cuts across the page in a band.

Panels may also bleed to three different edges, for example bleed-back-up-down. For convenience, these bleeds may also be specified with the primary direction plus -half:

A full-page spread may also be full-bleed, with bleeds in all four directions. This may be written bleed-up-down-back-fwd, but for convenience it call simply be written bleed-all:

For quick writing and editing, bleed annotations may be minified with b- plus a string with one letter per directon. -half and -all are shortened to h and a.

Although it is rare, a group, row, or layout may also be assigned a bleed that applies to every panel inside it – for example, rows of panels that all bleed to the top or bottom, or columns of panels that all bleed to the inside or outside of a spread.

-fwd and -back here relate to the reading direction – in a left-to-right us comic, -fwd bleeds to the right. In right-to-left panelcode marked rtl Japanese manga, fwd bleeds to the left. Because bleeds relate to the overall flow of the layout, the same encoding can be tagged for either ltr or rtl reading direction and it will render correctly with no other changes.

A layout may contain any combination of panels with bleeds and non-bleeds, in any directions. The overall composition is preserved when tagged rtl.

In the CSS renderer bleeds directed towards the interior panels may be used to emulate panel overlaps – but this is not what they are designed for.

Levels of specificity

Whitespace: delimited data entry

Because panelcode ignors linebreaks and whitespace , panelcode can be arranged in a variety of ways to make it more compact and minified, or to make writing , reading , or editing easier.

So this two-page spread can be described in a single line:

…or broken up in various ways, for adding spaces around delimters for readability, organizing each page of a spread on its own line with optional arguments immediately below.

Panelcode can also be written in a delimiter-prefix style , with one code unit or set of arguments per line. Each line begins with a delimiter indicating that it is a new spread “|”, layout “;” row “_”, rowgroup line “,”, or column “+”.

© 2017 Jeremy Douglass

Resize all galleries:

panelcode: fence pre-processor