Plugin Documentation¶
Displaymotron Core¶
Displaymotron intercepts markdown image syntax {attrs} and renders different content based on path type:
| Path Type | Handler |
|---|---|
| Directory | Gallery module |
.mp4, .webm, etc. |
Video module |
.stl, .dxf |
Model3D module |
| Image + figure attrs | Figure module |
| Text file | Textfile module |
| Binary file | Textfile (hex preview) |
Centralized Extensions (extensions.py)¶
IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".bmp"}
VIDEO_EXTENSIONS = {".mp4", ".webm", ".ogg", ".mov", ".avi", ".mkv"}
MODEL_EXTENSIONS = {".stl", ".dxf"}
Plugin Lifecycle¶
on_config → Register JS files
on_page_markdown → Process all  patterns
on_post_page → Inject CSS for used features
on_post_build → Copy JS files to site
Page Meta Flags¶
Each feature sets a flag in page.meta to enable conditional CSS injection:
displaymotron_videodisplaymotron_3ddisplaymotron_textdisplaymotron_gallerydisplaymotron_figuredisplaymotron_columnizer
Gallery Module¶
Renders directory contents as masonry image gallery using CSS columns.
Syntax¶
{cols=3 orderby=name}
Attributes¶
| Attribute | Description |
|---|---|
cols=N |
Number of columns (default: 3) |
width=N% |
Column width percentage (alternative to cols) |
orderby=date\|name |
Sort order (default: name with natural sort) |
Flow Diagram¶
@startuml
start
:Parse attributes (cols, orderby, width);
:Scan directory for images/videos;
:Sort files (natural or date);
:Get image dimensions for aspect ratios;
:Determine container width;
note right
From columnizer data-width-em
or default 70em
end note
:Compute column reductions;
:Generate CSS with container queries;
:Build HTML gallery div;
stop
@enduml
Responsive Column Reduction¶
Galleries reduce columns as container narrows. Breakpoints use cascading ratios relative to container width:
starting_width = container_width_em (or 70em default)
reduction_ratio = 0.6
For 3-col gallery at 70em:
3→2 at 70 × 0.6 = 42em
2→1 at 42 × 0.6 = 25.2em
Each breakpoint is relative to the previous, creating proportional spacing.
Container Query Integration¶
Galleries detect their container via data-width-em attribute on columnizer columns:
@container displaymotron-col (max-width: 42.0em) {
#gallery-abc123 { column-count: 2; }
}
For galleries outside columns, uses @container content instead.
Columnizer Module¶
Creates multi-column layouts using curly brace syntax.
Syntax¶
<div class="displaymotron-columns" markdown="1">
<div class="displaymotron-column" data-width-em="46.2" style="flex: 0 0 calc(66.0% - 0.5em);" markdown="1">
First column content
</div>
<div class="displaymotron-column" data-width-em="11.9" style="flex: 0 0 calc(17.0% - 0.5em);" markdown="1">
Second column content
</div>
<div class="displaymotron-column" data-width-em="11.9" style="flex: 0 0 calc(17.0% - 0.5em);" markdown="1">
Third column content
</div>
</div>
Width Calculation¶
- Explicit widths sum up
- Remaining percentage divided among auto columns
- Each column gets
data-width-emattribute:70 × width_pct / 100
Flow Diagram¶
@startuml
start
:Parse markdown line by line;
:Detect opening brace {;
:Track brace depth;
:Accumulate block content;
:On depth=0, extract content;
:Parse [width=X%] arguments;
:Continue until chain breaks;
note right
Chain breaks on:
- Blank line
- Non-brace content
- Less than 2 blocks
end note
:Calculate column widths;
:Generate HTML with flex layout;
:Add container-type: inline-size;
stop
@enduml
Generated HTML¶
<div class="displaymotron-columns" markdown="1">
<div class="displaymotron-column" data-width-em="46.2"
style="flex: 0 0 calc(66% - 0.5em);" markdown="1">
Content...
</div>
<div class="displaymotron-column" data-width-em="23.8"
style="flex: 0 0 calc(34% - 0.5em);" markdown="1">
Content...
</div>
</div>
CSS Container Setup¶
.displaymotron-column {
min-width: 0;
container-type: inline-size;
container-name: displaymotron-col;
}
Figure Module¶
Renders images with captions, supporting rows, columns, and inline floating.
Syntax¶
{caption="My caption" align=left width=300}
Attributes¶
| Attribute | Values | Description |
|---|---|---|
caption |
string | Caption text |
caption-width |
CSS value | Max caption width |
caption-align |
left/center/right | Caption text alignment |
align |
left/center/right | Figure alignment/float |
gridType |
row/col | Layout direction for chains |
normalizeHeights |
true/false | Equal heights in row |
normalizeWidths |
true/false | Equal widths in column |
aspectRatio |
fixed/stretch/zoom | Image fit mode |
rowHeight |
CSS value | Fixed row height |
colHeight |
CSS value | Fixed column height |
Figure Chains¶
Consecutive figures on same line form a chain:
{gridType=row}  
Flow Diagram¶
@startuml
start
:Parse figure attributes;
:Extract FigureConfig;
if (Multiple figures on line?) then (yes)
:Build figure chain;
:Apply hierarchical inheritance;
:Group by gridType boundaries;
if (gridType=row?) then (yes)
:Calculate aspect ratios;
:Set flex-grow per image;
:Render horizontal row;
else (col)
:Calculate inverse ratios;
:Set flex-grow per image;
:Render vertical column;
endif
else (single)
if (Inline float?) then (yes)
:Render with float: left/right;
else (no)
:Render centered figure;
endif
endif
stop
@enduml
Inline Floating¶
Figures without blank line before them float alongside text:
Some text here.
{caption="Float right" align=right width=200}
More text wraps around the image.
Height/Width Normalization¶
Row normalization uses aspect ratios for flex-grow:
# flex-grow = width / height (aspect ratio)
aspect_ratios = [img_width / img_height for img in images]
Column normalization uses inverse:
# flex-grow = height / width (inverse aspect ratio)
inverse_ratios = [img_height / img_width for img in images]
NarrowNav Plugin¶
Auto-calculates minimum navigation sidebar width based on nav item titles.
Configuration¶
plugins:
- narrownav:
char_width_em: 0.6 # Character width estimate
indent_per_level_em: 1.2 # Indent per nesting level
base_padding_em: 4.5 # Base padding (scrollbar, arrows)
min_width_em: 8.0 # Minimum width
max_width_em: 20.0 # Maximum width
Flow Diagram¶
@startuml
start
:on_nav hook receives Navigation object;
:Walk nav.items recursively;
:For each item:;
: width = len(title) × char_width_em;
: width += depth × indent_per_level_em;
: width += base_padding_em;
: track max_width;
:Clamp to min/max bounds;
:on_post_build writes CSS file;
:on_post_page injects CSS link;
stop
@enduml
Width Calculation¶
total_width = (len(title) * char_width_em) +
(depth * indent_per_level_em) +
base_padding_em
Generated CSS¶
/* Auto-generated by NarrowNav plugin */
.md-sidebar--primary {
width: 14.2em;
}
.md-sidebar--primary .md-sidebar__scrollwrap {
width: 14.2em;
}
Integration: Gallery + Columnizer¶
When gallery is inside a columnizer column:
@startuml
participant Columnizer
participant Plugin
participant Gallery
Columnizer -> Plugin: Process {blocks}
Plugin -> Plugin: Calculate column widths
Plugin -> Plugin: Add data-width-em to HTML
Plugin -> Gallery: render(..., container_width_em=35.0)
Gallery -> Gallery: Compute breakpoints from 35em
Gallery -> Gallery: Generate @container displaymotron-col queries
@enduml
The data-width-em attribute bridges columnizer width to gallery breakpoint calculation, enabling proper responsive behavior when galleries are nested inside columns.