How to write presentations using Bruce the Presentation Tool

Some of this document refers to the optional "examples" download from <>.

Bruce presentations are written as plain-text files in the ReStructuredText format with some extensions. If you have access to this HOWTO file in its original text format you may view it using Bruce (the HTML version is produced using the standard rst2html conversion tool.)

See the examples folder *.rst files for some samples, the simplest being "simple.rst" which displays plain text sentences centered on a white background (using the "big-centered" style):

.. load-style:: big-centered

Text displayed centered on the default white background.


A new page, separated from the previous using the four

Ut enim ad minim veniam.

A Page Title

Pages may optionally have titles which are displayed
centered at the top by default.

and so on. Blank pages are possible using ..blank:: in place of page content.

There's a lot of examples in the examples download, showing off most of Bruce's features. Get the examples from <>.

More Detail

Pages in Bruce are defined as being the text contained in a section or between transitions (horizontal rules, ----). It is important that a blank surrounds the transition line, otherwise ReST might try to interpret it as a title (which will often mean resulting in a parsing error). See "examples/test_sectioning.rst" for a file that mixes section-based and transition-based page delimiting.

There is also a "bullet mode" which treats each bullet point in a top-level bullet list as a single page. See "examples/test_bullet_mode.rst" for a file that uses this mode.

Bruce supports a large amount of ReStructuredText and some additional features:

  • inline markup for emphasis, strong, superscript, subscript and literal
  • literal and line blocks
  • block quotes
  • bullet, enumerated and definiton lists (including nesting)
  • images (inline and stand-alone)
  • tables (no row / column spanning yet)
  • page titles (section headings)
  • syntax highlighting of code if Pygments is installed
  • interactive Python interpreter sessions
  • styling including separate style sheets
  • backgrounds using images or gradients
  • transitions between pages
  • blank pages
  • gradual exposing of list items
  • plugins to create your own inline elements
Bruce will not line-wrap title text (doing so messes with layout way too much), so make sure your title fits in one line!
A :width: and/or :height: may be specified to scale the image when displayed. If only one is specified then the image's other dimension will be scaled to ensure the image aspect ration is retained. Images (and video, stylesheets, etc) are located using resource discovery described later.
No row or column spanning is implemented yet. Tables may have pretty much any arbitrary content though.
Embedded in the same manner as images, and may be scaled in the same way. Additionally video may be asked to loop using the :loop: flag.
Syntax-highlighting of code blocks if Pygments is installed. The range of languages supported by Pygments is at
blank pages

The ..blank:: directive allows you to have blank pages in place of page content, for example:

Lorem ipsum dolor sit amet, consectetuer adipiscing elit.


.. blank::


Donec auctor vestibulum risus. Vestibulum porttitor purus sed magna.
Embeds a Python interpreter in the page. The options available are :width: and :height: (default 1024 by 400). You may also have the optional flag :sysver: which will cause the standard Python interactive intepreter greeting with the Python version to be displayed.
Enables the author to compose a new inline element in Python code. See the section on writing plugins.
style sheets
Bruce Style Sheets (.bss) may be specified on the command-line or in the presentation itself using the load-page-style:: or ..load-style:: directives which take either a built-in style name or a ".bss" filename.

Style Changes

The rendering stylesheet may be altered on the fly using the and directives. Changes made in this way are immediate. The difference between the two directives is that the first will affect only the current page whereas the second will affect it and all subsequent pages.

Similarly the ..load-page-style:: directive only affects the current page whereas the ..load-style:: directive affects it and all subsequent pages.

The stylesheet is broken up into sections: default, literal, emphasis, strong, title, footer, block_quote, line_block, literal_block, layout and transition.

Default, title and footer may specify a horizontal alignment.

Default, literal_block and line_block may specify margin_left, margin_right, margin_top and margin_bottom.

All sections except layout, transition and literal_block may specify character styling in color, background_color, font_size, font_name, old and italic.

The layout section specifies the background_color and vertical alignment for page contents.

The transition section specifies the name of the page transition and time to run it for.

Specified as an HTML-like RGB or RGBA hex value, eg. #ff00ff for red=255, green=0 and blue=255, ie. purple. May also use the common HTML color names like red, white, gray etc.
Specified as per color above, indicates the color to place behind the text.
Size in points of the font.
Name of the font. Must be loadable using pyglet.resource.font, so must be discoverable using pyglet.resource. Use the tool in the pyglet distribution to discover a font file's name and other attributes if you're not sure. You may add new fonts using the resource directive.
Use a font's bold variant. Use yes or no.
Use a font's italic variant. Use yes or no.
One of left (default), center or right.
margin_left, margin_right, margin_top and margin_bottom
Margins surrounding paragraphs specified in pixels.
Only valid in the layout section; one of top (default), center or bottom.
position, hanchor, vanchor
Used for title and footer these specify how to place the text. See title and footer positioning.

As seen in the layout section. This defines the restricted size to be used by page contents (not including title and footer). By default some space is allocated so the page contents don't overwrite the page title and footer, if they are present and positioned in the usual top and bottom places. The viewport is specified as:


Giving the bottom-left corner x,y position and the width and height.
Must be one of the transition names listed below. Default is fade.
Gives the duration in seconds to run the current transition for. Default is 0.5.
Gives the bullet style to used for bullet lists. Default is 'bullet' and the other options are 'circle', 'box' and 'none'. This only indicates the bullet style for the first level of bullets - any deeper level will be automatically given a different bullet type (except where the style is 'none').
If set to "expose" then the subsequent top-level list items (bullet,
ordered or definition) will be gradually exposed on the page rather than displayed all at once. Several values are available:
The default, indicates that the list items should all be visible immediately on the page.
Expose each item in the list in turn with no fanciness.
Expose each item in the list in turn by fading them in (or out if hiding the list). Fading of list items containing tables should be avoided at this time.

The default builtin stylesheet may be seen in "examples/default_style.bss".

The "default" group is used as a fallback when a particular style is looked up and no explicit attribute is set. Thus all text is rendered in Arial by default, except in literal text where CourierNew is used. You may set title.font_name to override the font used in the title or default.font_name to override the font used everywhere (except literal text). You may refer to defaults using bare style attributes, so default.font_name and font_name are both equivalent.

Style changes are specified using the style directive. To change the font to 64-point bold, you would:

.. style::
:font_size: 64
:bold: yes

To change a single style element you may have the declaration on a single line:

.. style:: :font_size: 64

The code_* style names control the output of the Pygments rendering so if you've not got that installed you may ignore them. The complete set of names is (with the code_ prefix removed): keyword, text, generic, name, name_class, name_function, literal, punctuation, operator and comment.

Title and Footer Positioning

title positioning

The position of the title is controlled by the stylesheet. The default title styles are:

title.position = w/2,h
title.hanchor = center
title.vanchor = top

Which positions the title at the top-center of the viewport, anchored in the center/top of the text.

footer positioning

The position of the footer is controlled by the stylesheet. The default footer styles are:

footer.position = w,0
footer.hanchor = right
footer.vanchor = bottom

Which positions the foorer at the bottom-right of the viewport, anchored in the right/bottom of the text.

All positions may be Python expressions which will be evaluated. The expressions have the variables "w" and "h" available which are the width and height of the presentation viewport. To center the title, for example, the width could be specified as w//2. This will divide the width by two producing an integer (always try to produce an integer as it will result in more pleasing rendering).

Bruce Style Sheets (.bss)

If you wish to change the style of your presentation significantly from the built-in styles you may define your own Bruce Style Sheet. This allows you to alter any of the style properties described above and also change the page layout described below. The file may have two sections:

The contents of this section are parsed exactly the same as described in the page layout section below. This allows you to alter the page background decorations.

This section contains style properties. The syntax for the properties is simple:

property = value

for example:

color = white
bold = yes
italic = no
table.border_color = #ff0000
layout.background_color = black

By default your stylesheet will use the properties defined in the "default" stylesheet where you don't specify anything. You may use an inherit-style definition in your sheet to to specify another stylesheet (either built in or another .bss file), for example:

inherit-style = big-centered

you may only inherit from one other stylesheet though.

There are example .bss stylesheets in the "examples" download.

Transition Names

No transition effect. Immediate page change, no delay.
Fades to background color and then to next page.
Zoom out current page and zoom in new page.
Like jump_zoom but smoother.
Rotate and zoom our current page, rotate and zoom in new page.
move_in_left, move_in_right, move_in_bottom, move_in_top
Move the next page in from the specified side.
slide_in_left, slide_in_right, slide_in_bottom, slide_in_top
Slide the current page off and new page on from the specified side.

The following do not work on all machines:

  • flip_x, flip_y, flip_angle
  • shuffle
  • turn_off_tiles
  • fade_top_right, fade_bottom_left, fade_up, fade_down
  • corner_move
  • envelope
  • split_rows, split_cols

Page Layout

The page layout may also be defined on the fly. Unlike the stylesheet which may be modified in-place, the page layout must be specified entirely with each directive. The layout directive applies to the current and subsequent pages.

A blank layout directive ..layout:: will result in the default white background and no other decoration.

image-based decoration

You may draw images on the page which will appear under any content. The syntax for specifying an image is:


This will place the indicated image flush against the bottom-left of the page.

background gradients

You may specify a vertical or horizontal color gradient for the page background. This may be vertical or horizontal:

:vgradient:<top color>;<bottom color>
:hgradient:<left color>;<right color>
quad-based decoration

You may draw quads on the page which will appear under any content. The quads may have color gradients by specifying different colors for each corner. The syntax for specifying a quad is:

:quad:C<color spec>;Vx1,y1;Vx2,y2;Vx3,y3;Vx4,y4

Quad vertex color carries over if it's not specified for each vertex, allowing either solid color or blending.

Colors are specified in HTML format with either three or four channels (if three then the fourth, alpha channel is set to 255).

All positions (quad vertexes, title position, etc) may be Python expressions which will be evaluated. The expressions have the variables "w" and "h" available which are the width and height of the presentation viewport. To center the title, for example, the width could be specified as w/2.

Resource Discovery

Bruce can display images and video found in the same directory as the presentation source. You may enable Bruce to search additional paths to find images and video. Additionally you may load new fonts for display by referring to TrueType Font files. You do so using the ..resource:: directive.

adding a directory of resources:

.. resource:: <path to directory>

adding a font file:

.. resource:: <font filename>.ttf

To refer to the font later you'll need to know its name, which may differ from the filename. You may use the tool in the pyglet source to do so.

Writing Plugins

A plugin is used with the ..plugin:: directive. For example:

.. plugin:: test_plugin
:width: 300
:height: 300

The directive is referring to the plugin implemented in the file which is found using normal resource discovery. That file must contain:

  1. a class called Plugin which derives from bruce.plugin.Plugin, and
  2. an implementation of any or all of the methods described below.

If your plugin is animated you may request a regular tick from the clock by setting the property needs_tick either on your class or in your __init__ method.

__init__(self, width=800, height=400)__
Invoked when the presentation is parsed. Passed the width and height as specified in the presentation.
resize(self, width, height)
Invoked when the page the element is on is scaled.
place(self, layout, x, y)

Invoked when the page layout needs to position the element on screen. Passed a pyglet.text.IncrementalTextLayout instance and the pixel position of the bottom left of the element in that layout. This position almost always has a negative y value.

The element's opacity should be set according to its self.opacity attribute.

Note also that this method may be called multiple times for a single layout with the same position. And then removed. That's just the way it is.

set_opacity(self, opacity)
Indicates the opacity of the element has changed in response to Bruce fading the element into or out of display. The opacity will be an integer value from 0 to 255. It is also available as self.opacity.
remove(self, layout)
Invoked when page layout removes the element from display.
tick(self, dt)
Invoked if the element defines needs_tick before enter is invoked. Will be called once per "clock tick" with dt being the time in seconds since the last call.

Plugin contents should be rendered using the API with the Batch instance on the layout passed into the place() method.

Additionally any graphics elements added to the batch should use the group layout.top_group as the base group. This group defines positioning transformations without which your plugin content will most likely not be visible.

Again note you'll almost always receive a negative y position in the place() call. The transforms in layout.top_group adjust for this (the top of the layout is typically at y=0).

If you wish to alter the OpenGL context to turn on environment features such as texturing, or even just to perform additional transformations then you should define your own When you instantiate this group you should then pass it layout.top_group.

The following is an example plugin file used in "examples/test_plugin.rst":

import pyglet
from import *

from bruce import plugin

class TestGroup(
angle = 0

def set_state(self):
x, y =
glTranslatef(x, y, 0)
glRotatef(self.angle, 0, 0, 1)
glTranslatef(-x, -y, 0)

def unset_state(self):

class Plugin(plugin.Plugin):
needs_tick = True
def resize(self, w, h):
self.w, self.h = w, h

def tick(self, dt): += 1

def place(self, layout, x, y):
x1 = int(x)
y1 = int(y)
x2 = int(x + self.w)
y2 = int(y + self.h) = TestGroup(layout.top_group) = (x+self.w/2, y+self.h/2)
self.r = layout.batch.add(4, GL_QUADS,,
('c3B', (255, 0, 0) * 4),
('v2i', (x1, y1, x2, y1, x2, y2, x1, y2)),

def remove(self, layout):