Skip to content

Repository files navigation

MkDocs Displaymotron

A MkDocs plugin that extends markdown image syntax to support videos, 3D models, galleries, figures with captions, and file previews.

Syntax

All features use the extended markdown image syntax:

![alt-text](path){attribute1=value1 attribute2="value with spaces"}
  • ![alt-text] - Optional description
  • (path) - Path to file or directory (relative to the markdown file)
  • {attributes} - Optional space-separated key=value pairs

Installation

# mkdocs.yml
plugins:
  - displaymotron:
      text_encoding: utf-8
      text_collapsed: true
      gallery_allowed_extensions: []
      gallery_blocked_extensions: []
      model_allowed_extensions: []
      model_blocked_extensions: []

Modules

plugin.py - Core Plugin

The main DisplaymotronPlugin class orchestrates all functionality:

How it works:

  1. Intercepts markdown during on_page_markdown()
  2. Uses regex to find all ![](path){} patterns
  3. Resolves paths relative to the markdown file's directory
  4. Routes to the appropriate renderer based on file type:
    • Directories → Gallery
    • .mp4, .webm, etc. → Video
    • .stl, .dxf → 3D Model
    • .png, .jpg, etc. with caption → Figure
    • Other files → Text/Binary preview
  5. Tracks which features are used via page metadata
  6. Injects feature-specific CSS in on_post_page()
  7. Copies JS files to the build directory in on_post_build()

Path Resolution: The plugin tries two locations when resolving paths:

  1. Direct path relative to the markdown file
  2. Path inside a subdirectory matching the markdown filename (without extension)

For example, if docs/tutorial.md contains ![](model.stl), the plugin checks:

  1. docs/model.stl
  2. docs/tutorial/model.stl

video.py - Video Rendering

Converts video files to HTML5 <video> elements.

Supported extensions: .mp4, .webm, .ogg, .mov, .avi, .mkv

Attributes:

Attribute Default Description
controls true Show video controls
autoplay false Auto-play on load
loop false Loop playback
muted false Mute audio
preload metadata Preload strategy (none, metadata, auto)
width - Video width
height - Video height
align - Alignment (left, center, right)
style - Inline CSS
class - CSS class

Example:

![Demo Video](demo.mp4){controls="true" width="640" autoplay="true" muted="true"}

Output:

<video controls autoplay muted preload="metadata" width="640">
  <source src="demo.mp4" type="video/mp4">
</video>

model3d.py - 3D Model Viewer

Renders interactive 3D models using Three.js with orbit controls.

Supported extensions: .stl, .dxf

Attributes:

Attribute Default Description
width 100% Container width
height 600px Container height
color ffffff Model color (hex without #)

Features:

  • Drag to rotate (orbit controls)
  • Right-click drag to pan
  • Scroll to zoom
  • Q/E keys for camera roll
  • Reset view button
  • Download model button
  • Info panel with model statistics
  • Keyboard shortcuts help overlay
  • Mini axes helper in corner

Example:

![Engine Part](engine.stl){width="100%" height="500px" color="4CAF50"}

How it works:

  1. Creates a container div with unique ID
  2. Stores model path and attributes as data attributes
  3. JavaScript (displaymotron_init_3d.js) lazily loads Three.js
  4. Initializes scene with adaptive lighting (3 directional lights)
  5. Loads the model using appropriate loader (STLLoader or DXFLoader)
  6. Auto-centers and scales model to fit view
  7. Sets up OrbitControls for interaction

gallery.py - Image Gallery

Creates a responsive masonry gallery from a directory of images and videos.

Supported files:

  • Images: .png, .jpg, .jpeg, .gif, .svg, .webp, .bmp
  • Videos: All video extensions from video.py

Attributes:

Attribute Default Description
cols 3 Number of columns
width - Item width % (alternative to cols: cols = 100/width)
orderby natural date for date-sorted, otherwise natural alphanumeric

Example:

![My Photos](photos/){cols=4}
![Portfolio](portfolio/){width=25 orderby=date}

How it works:

  1. Scans the directory for supported files
  2. Sorts files (natural sort or by date)
  3. Generates gallery HTML with aspect-ratio preserving containers
  4. JavaScript (displaymotron_init_gallery.js) initializes Packery.js
  5. Uses ImagesLoaded to wait for all images before layout
  6. Re-layouts on window resize and SPA navigation

Layout engine:

  • Uses Packery.js for masonry grid
  • Each item preserves aspect ratio using padding-bottom technique
  • Images/videos are absolutely positioned within their containers
  • Handles dynamic content via MutationObserver

figure.py - Figures with Captions

Renders images as HTML5 <figure> elements with styled captions.

Supported extensions: .png, .jpg, .jpeg, .gif, .svg, .webp, .bmp

Attributes:

Attribute Default Description
caption - Caption text (required for figure mode)
caption-width image width Maximum caption width
caption-align center Caption text alignment
caption-style - Additional CSS for caption
align center Figure alignment (left, center, right)
width - Image width
class - CSS class for figure

Single figure:

![Mountain](mountain.jpg){caption="A beautiful mountain vista" width="600"}

Figure rows: Place multiple figures on the same line to create a flex row:

![](photo1.jpg){caption="First"} ![](photo2.jpg){caption="Second"} ![](photo3.jpg){caption="Third"}

Aligned figures:

![](left.jpg){caption="Left side" align="left" width="300"}
![](right.jpg){caption="Right side" align="right" width="300"}

How it works:

  1. First pass: Detect consecutive figures on the same line (figure rows)
  2. Render rows as flex containers with equal-width items
  3. Second pass: Process remaining single figures
  4. Apply alignment via CSS (center margins, float left/right)
  5. Caption width defaults to image width for visual consistency

textfile.py - Text and Binary File Display

Renders files in collapsible <details> elements with download buttons.

Text files:

  • Displayed with syntax highlighting class
  • Collapsible by default (configurable via text_collapsed)
  • Uses configured encoding (default: UTF-8)

Binary files:

  • Shows 256-byte hex dump preview
  • Download button provided

Example:

![](config.yaml)
![Source Code](main.py)
![](data.bin)

How it works:

  1. Attempts to read file as text with configured encoding
  2. If successful: renders as <details> with <pre><code> content
  3. If decode fails: treats as binary, shows hex dump
  4. Adds download button with SVG icon
  5. Displays file size and error messages if applicable

Configuration:

plugins:
  - displaymotron:
      text_encoding: utf-8      # File encoding
      text_collapsed: true      # Start collapsed

JavaScript Dependencies

Located in js/ directory:

File Purpose
displaymotron_init_gallery.js Gallery initialization, Packery/ImagesLoaded lazy loading
displaymotron_init_3d.js 3D viewer initialization, Three.js lazy loading
three.min.js Three.js library for 3D rendering
OrbitControls.js Camera orbit controls
STLLoader.js STL file parser
DXFLoader.js DXF file parser
packery.pkgd.min.js Masonry layout engine
imagesloaded.pkgd.min.js Image load detection

Lazy Loading: JavaScript dependencies are only loaded when their features are actually used on a page. The initialization scripts use dynamic imports to load libraries on demand.

SPA Compatibility: Both gallery and 3D initialization scripts:

  • Subscribe to Material theme's document$ observable
  • Use MutationObserver for dynamic content
  • Handle pageshow event for bfcache restoration

Configuration Reference

plugins:
  - displaymotron:
      # Text file settings
      text_encoding: utf-8        # Encoding for reading text files
      text_collapsed: true        # Collapse text blocks by default
      
      # Gallery extension filtering
      gallery_allowed_extensions: []   # Whitelist (empty = allow all)
      gallery_blocked_extensions: []   # Blacklist
      
      # 3D model extension filtering  
      model_allowed_extensions: []     # Whitelist (empty = allow all)
      model_blocked_extensions: []     # Blacklist

Extension Filtering Logic:

  1. If allowed_extensions is not empty → only those extensions work
  2. If blocked_extensions is set → those extensions are denied
  3. Otherwise → all supported extensions work

Processing Flow

Markdown Source
      │
      ▼
┌─────────────────────────────┐
│  on_page_markdown()         │
│  ┌───────────────────────┐  │
│  │ Pass 1: Figure Rows   │  │
│  │ (consecutive figures) │  │
│  └───────────────────────┘  │
│  ┌───────────────────────┐  │
│  │ Pass 2: All Patterns  │──┼──► Route by file type
│  └───────────────────────┘  │
└─────────────────────────────┘
      │
      ▼
┌─────────────────────────────┐
│  Type Detection             │
│  ┌────────────────────────┐ │
│  │ Directory? → Gallery   │ │
│  │ Video ext? → Video     │ │
│  │ 3D ext?    → Model3D   │ │
│  │ Image+cap? → Figure    │ │
│  │ Image only → Passthru  │ │
│  │ Other?     → Textfile  │ │
│  └────────────────────────┘ │
└─────────────────────────────┘
      │
      ▼
┌─────────────────────────────┐
│  on_post_page()             │
│  Inject feature-specific    │
│  CSS based on metadata      │
└─────────────────────────────┘
      │
      ▼
┌─────────────────────────────┐
│  on_post_build()            │
│  Copy JS files to site dir  │
└─────────────────────────────┘

Examples

Complete Page Example

# Project Documentation

## Demo Video
![](demo.mp4){controls="true" width="100%"}

## 3D Model Preview
![Prototype](prototype.stl){height="500px" color="2196F3"}

## Photo Gallery
![Project Photos](images/){cols=4 orderby=date}

## Architecture Diagram
![System Architecture](diagram.png){caption="System architecture overview" width="800"}

## Side-by-Side Comparison
![Before](before.jpg){caption="Before"} ![After](after.jpg){caption="After"}

## Configuration File
![](config.yaml)

License

MIT

About

A MkDocs plugin that extends markdown image syntax to support videos, 3D models, galleries, figures with captions, and file previews.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages