- convert: drop --standalone from the DOCX→MD pandoc call. It emitted its own YAML title block, which collided with the frontmatter the script prepends (a ZDDC docx with title metadata produced two stacked --- blocks). Matches the HTML→MD path, which already omits it. - index.sh: remove the no-op cleanup()/trap EXIT — unsetting a global as the process exits does nothing; the per-folder `unset latest_files` is the real reset. - README: trim the generic Advanced Usage / Performance / "Perfect for" filler, and fix the Troubleshooting note that wrongly pointed at a zddc.conf template key (template is -T / auto-discovery). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| convert | ||
| convert-diff | ||
| custom.css | ||
| index.sh | ||
| README.md | ||
| viewer-template.html | ||
| zddc.conf | ||
ZDDC Pandoc Tools
A collection of tools for converting Markdown documents to HTML with a professional viewer interface, optimized for technical documentation and engineering documents.
Server-side conversion (zddc-server)
The shell scripts in this folder are standalone CLI/batch tools.
zddc-serverimplements its own on-demand conversion (Go packagezddc/internal/convert) and does not call these scripts. It does, however, reuse the sameviewer-template.htmlandcustom.css(embedded at build time). See AGENTS.md → "Server-side document conversion" for the authoritative reference.
zddc-server can render any served .md on demand: requesting the sibling URL
<path>/foo.docx (or .html / .pdf) returns the converted bytes — no query
string. A real on-disk file of that name always wins; the virtual conversion
only fires when the requested file doesn't exist but foo.md does. The browse
app's markdown editor surfaces these as DOCX/HTML/PDF download links (auto-saving
a dirty buffer first so the output matches what's on screen).
Architecture. The Go code does the minimum — it execs pandoc and
chromium-browser directly. The sandbox and resource caps live in the runtime
image, where /usr/local/bin/{pandoc,chromium-browser} are wrapper scripts
that run the real binary inside a per-conversion bubblewrap sandbox
(--unshare-all, read-only binds, --tmpfs /tmp, --clearenv) under cgroup v2
memory/PID caps. I/O is via stdin/stdout plus a per-call scratch dir. There is no
container runtime and no image pulling at request time.
The PDF flow is two-stage: pandoc renders the markdown through
viewer-template.html to standalone HTML, then headless Chromium prints that HTML
to PDF — preserving the viewer template's print-media CSS rather than going
through pandoc's LaTeX template.
Converted bytes are cached at <dir>/.zddc.d/converted/<base>.<ext> with mtime
synced to the source, so a fresh cache hit is a stat-and-serve with no exec.
A PUT/DELETE/MOVE on the source .md purges the sidecars. Per-project header
metadata (client/project/contractor/project_number) comes from the .zddc
convert: cascade; title/tracking_number/revision/status are derived from the
filename via zddc.ParseFilename.
Relevant flags (defaults in parens):
--convert-pandoc-binary(pandoc) /--convert-chromium-binary(chromium-browser;chromiumon Debian) — PATH-resolved name or absolute path--convert-scratch-dir($TMPDIR) — host scratch root for template + intermediates--convert-mem-mib(1024) — per-conversion memory cap (cgroupmemory.max)--convert-pids(256) — per-conversion PID cap (cgrouppids.max)--convert-timeout(60s) — per-conversion wall clock (Gocontext.WithTimeout)
If pandoc/chromium aren't on PATH (e.g. running zddc-server outside the runtime
image) the endpoint serves 503 with a Retry-After; the rest of the server keeps
working. Running against raw pandoc/chromium with no wrapper gives a working but
unsandboxed endpoint — fine for dev iteration.
Features
Document Conversion (convert)
- Batch processing: Convert multiple Markdown files at once
- Force overwrite:
-fflag to overwrite existing output files - Custom output directory:
-oflag to specify output location - Configuration-driven: Uses
zddc.conffor project-specific settings - Template integration: Automatically applies the viewer template
- Progress tracking: Real-time conversion status and summary
Professional Viewer Template (viewer-template.html)
- Modern responsive design: Works on desktop, tablet, and mobile
- Table of Contents (TOC): Auto-generated sidebar navigation with smooth scrolling
- Print optimization: Professional formatting for PDF generation
- Page break controls for tables
- Repeating table headers
- Proper page numbering
- Clean print layout
- URL hash navigation: Shareable links to specific document sections
- Mobile-friendly: Collapsible sidebar and touch-optimized interface
- Professional styling: Clean typography optimized for technical documents
Usage
Basic Conversion
# Convert all Markdown files in current directory
./convert *.md
# Convert with force overwrite
./convert -f *.md
# Convert to specific output directory
./convert -o rendered/ *.md
# Combine flags
./convert -f -o rendered/ *.md
Configuration (zddc.conf)
Create a zddc.conf file in your project directory. It is sourced as shell,
so use var="value" syntax (no spaces around =). Only these four variables are
read; all are optional and feed the document header via pandoc --variable:
contractor="Contractor Name" # contracting organization (header)
client="Client Name" # client org (header, paired with project)
project="Project Name" # full project name
project_number="AR 28088" # shown in parentheses after the project name
The template path is discovered automatically (input dir → script dir →
symlink target) or set per-run with -T; the output directory is set with -o.
They are not zddc.conf keys.
Directory Structure
your-project/
├── zddc.conf # Configuration file
├── document1.md # Source Markdown files
├── document2.md
└── rendered/ # Generated HTML files
├── document1.html
└── document2.html
Template Features
Navigation
- TOC Generation: Automatically creates navigation from document headings
- Smooth Scrolling: Click TOC items for smooth navigation to sections
- Hash URLs: Address bar updates with section anchors for sharing
- Mobile Menu: Collapsible sidebar for mobile devices
Print Styling
- Page Breaks: Tables won't split across pages
- Header Repetition: Table headers repeat on each page
- Professional Layout: Optimized margins and typography
- Page Numbers: Sequential page numbering in footer
Responsive Design
- Desktop: Full sidebar with TOC always visible
- Tablet: Collapsible sidebar with overlay
- Mobile: Hamburger menu with full-screen TOC overlay
File Types Supported
- Input: Markdown (
.md), DOCX (.docx), and HTML (.html/.htm) files (auto-detected: DOCX→MD, MD→HTML, HTML→MD; override with-t md|html|docx). Direct DOCX→HTML is not supported — convert to MD first. - Output: HTML files with embedded CSS and JavaScript (plus MD and DOCX targets)
- Images: Supports embedded images and diagrams
- Tables: Full table support with print optimization
- Code: Syntax highlighting for code blocks
Dependencies
- pandoc: Document conversion engine
- Modern browser: For viewing generated HTML files
- Optional: Web server for serving files (prevents CORS issues)
Troubleshooting
Common Issues
- Template not found: Keep
viewer-template.htmlbeside the script (or input), or pass-T /path/to/template.html - Permission errors: Make sure
convertscript is executable (chmod +x convert) - Missing output: Check that output directory exists or use
-oto create it - Print issues: Use "Print to PDF" in browser for best results