Development guide for Crosswords
  • Contributing
  • Codebase
  • Designs
    • Crosswords Editor
    • Crosswords Player
    • Puzzle sets
    • Shared code
      • Background shapes for cells
      • ClueGrid widget
      • Crossword Quirks
      • CSS in Crosswords
      • Grid layout
      • GridState Modes refactor, take 2
      • Immutable XwordState
      • Revamping the libipuz edit APIs
      • Overlays on the grid
      • Play Cell
      • Play Grid Sizing
      • The PuzzleStack
      • Word List
      • Print Layout Templates
        • Goals
        • Rationale
        • Overall Approach
        • Next steps
        • Areas For Improvement
      • Print Layout
    • Drafts
    • Deprecated
  • Packaging
  • Maintainers
Development guide for Crosswords
  • Designs
  • Shared code
  • Print Layout Templates
  • View page source

Print Layout Templates

Status: Implemented

Author: Toluwaleke Ogundipe

Reviewers: Federico Mena Quintero, Jonathan Blandford

Goals

  • Specify a format for defining reusable print layout templates.

Rationale

Different puzzle kinds require slightly different layouts when printed on paper. All of them require the puzzle grid and the clues, but for example, in arrowword puzzles, the clues are embedded in the grid and they do not require a list of clues.

Overall Approach

Print layout templates are reusable, declarative specifications that define how different elements of a puzzle are arranged and rendered on a printed page. At its core, a template describes a layout for a specific page size and puzzle kind(s), breaking down the printable area into a hierarchy of elements, each with a distinct role, such as displaying the grid, clues, title, metadata, or other visual components.

These templates provide a consistent and flexible way to support various puzzle kinds and page sizes.

The Format

At the top-level, a TEMPLATE contains some metadata, the main page, and an optional overflow page with space for additional clues. Each page is typically a nested set of ELEMENTS.

Templates are defined in the JSON format as follows.

Important

  • The code blocks herein are not valid JSON but descriptions of the expected format.

  • Field/Member names are case-sensitive.

  • Unknown/Unexpected fields are ignored.

{
  // The page size of the template, in millemeters.
  "page_size": { "width": Float, "height": Float },

  // Applicable puzzle kinds (case-insensitive).
  "puzzle_kinds": [ String, ... ],

  // The main page.
  "main_page": Box,

  // Optional: An overflow page for additional clues.
  "overflow": Box
}

Where Box is a container of elements and has the following format:

  {
    // The orientation of the box (case-insensitive); one of:
    //
    // - horizontal
    // - vertical
    "orientation": String

    // Sub-elements of the box.
    "elements": [
      {
        // Relative ratio of the sub-element within the box;
        // Positive.
        "ratio": Float,

        // A sub-element.
        "element": Element
      }, ...
    ]
  }
  • ratio is optional and ignored for divider sub-elements.

  • sub-element ratios are relative i.e the effective/absolute ratio of each sub-element is (sub-element ratio) / (sum of all sub-element ratios); this is more flexible than absolute ratios, without significant additional cost.

  • Element defines a template element.

  • must contain at least one non-divider sub-element.

Template Elements

There are two basic categories of elements:

  1. DISPLAY elements: These might contain text, a grid, or something else, or even nothing at all (to insert white space between other elements).

  2. CONTAINER elements: These are used to arrange other elements.

Each element is identified by a KIND and may include associated data to customize its behavior, e.g font size/styles for text, or clue flow information for multi-region clue layouts.

An element has the following format:

{
  // The element kind (case-insensitive).
  "kind": String,

  // Optional: Used for element kinds that require extra info.
  "data": ...
}

The element kinds are as follows. Each doesn’t use the data field except stated otherwise.

  • TITLE: The puzzle’s title.

    • The data field has the following format:

      {
        // The font description with which to render text
        "font": String
      }
      
    • font is in the format accepted by pango_font_description_from_string(), with the following specifics:

      • only the font size is required, and must be in points.

      • if the font family is not specified, a default is used.

  • METADATA: The publisher, author, date, etc (as many as are defined).

    • The data field is as for the TITLE element kind.

  • INTRO: The puzzle’s intro.

    • The data field is as for the TITLE element kind.

  • NOTES: The puzzle’s notes.

    • The data field is as for the TITLE element kind.

  • GRID: The puzzle’s grid.

  • CLUES: The puzzle’s clues.

    • The data field has the following format:

      {
        // A unique (amongst CLUES elements) identifier;
        // Positive.
        "id": Integer,
      
        // Clue direction(s) to contain (case-insensitive). One of:
        //
        // - all: Contain all clue directions, one after another
        // - any: Any available clue direction
        // - <any of the standard IPUZ directions>
        "direction": String,
      
        // The ID of another CLUES element into which the content of this
        // element may flow.
        "flows_into": Integer,
      
        // The font description with which to render text
        "font": String
      }
      
    • id is required.

    • a source is a CLUES element into which no other flows.

    • an extension is a CLUES element into which another flows.

    • all data fields other than id are optional, with the following exception(s):

      • direction and font are required for a source.

    • for direction:

      • if specified, direction is ignored for an extension.

      • if direction all is used, there must be only one source.

      • if direction any is used, the direction of all sources must be any.

      • no two sources may have the same IPUZ direction.

    • for flows_into:

      • if specified, there must exist another CLUES element with that value as its id.

      • a CLUES element must not flow into itself.

      • multiple CLUES elements must not flow into the same other CLUES element.

      • clues may flow across pages, but only forward i.e a CLUES element must not flow into another on a page before it.

      • a cyclic flow (i.e a loop of CLUES elements that have no apparent source nor end) is invalid.

    • font is as for the TITLE element kind.

      • if not specified for an extension, it inherits that of its source.

  • SOLUTION: The puzzle’s solution in some form.

  • DIVIDER: A vertical/horizontal divider.

    • Has a pre-defined thickness (later defined by the print layout config).

    • NOTE: This is a standalone element, not a container.

  • SPACER: A blank space.

  • BOX: A container to organize elements.

    • The data field has the format of a Box as earlier defined for the page top-level:

Element kinds may be added, merged or removed over time as deemed fit.

Next steps

  • [ ] Define templates for common page sizes and puzzle kinds.

Areas For Improvement

  • [ ] Allow user-defined templates. This will require the following (amongst other things):

    • [ ] a version field in the format to prevent breakage when there are breaking changes to the format.

    • [ ] report errors during template loading, instead of treating them as programming errors.

  • [ ] A GUI to allow users to interactively create, modify and save layouts. This will require the following (amongst other things):

    • [ ] recursively serializing element structures to JSON (could use JsonBuilder + JsonGenerator).

Previous Next

© Copyright 2025, The Crosswords developers.

Built with Sphinx using a theme provided by Read the Docs.