particle-academy / dark-slide
Standalone presentation read/write tool for agentic deck creation. Framework-agnostic PHP core that writes .pptx (Office Open XML) with inline markdown formatting + headings, real tables, gradient backgrounds, syntax-highlighted code, and embedded media — and reads them back with high fidelity. Opti
Requires
- php: ^8.2
- ext-dom: *
- ext-libxml: *
- ext-zip: *
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0|^11.0
- pestphp/pest: ^3.0|^4.0
- phpunit/phpunit: ^10.0|^11.0|^12.0
Suggests
- illuminate/support: Only needed when using the optional Laravel service provider, facade, or artisan command. Compatible with 10.x through 13.x. The core DarkSlide\Agent + writer require zero framework.
README
PHP package for reading and writing presentation files (.pptx) from a
JSON-friendly schema. Framework-agnostic core with an optional Laravel
adapter. Designed to round-trip with the
@particle-academy/fancy-slides
JS package's Deck schema — what the JS editor emits, DarkSlide writes
to a real Office Open XML file that opens in PowerPoint, Keynote,
Google Slides, and LibreOffice Impress.
Why
Sister project to holy-sheet
(XLSX writer). The two share an "agent emits JSON, PHP writes a real
document" pattern:
| Document type | JS authoring | PHP writing |
|---|---|---|
| Spreadsheets | fancy-sheets | holy-sheet |
| Presentations | fancy-slides | dark-slide |
Quickstart
use DarkSlide\Agent; $deck = [ 'id' => 'demo', 'title' => 'My deck', 'theme' => ['name' => 'default'], 'slides' => [ [ 'id' => 's1', 'layout' => 'title', 'elements' => [ [ 'id' => 'e1', 'type' => 'text', 'x' => 0.1, 'y' => 0.4, 'w' => 0.8, 'h' => 0.2, 'content' => 'Welcome to dark-slide', 'format' => 'plain', 'style' => ['fontSize' => 56, 'weight' => 'bold', 'align' => 'center'], ], ], ], ], ]; // Validate before writing — catches malformed agent output $errors = Agent::validate($deck); if (!empty($errors)) { foreach ($errors as $e) { echo "{$e['path']}: expected {$e['expected']}, got {$e['got']}\n"; } exit(1); } // Write to disk $result = Agent::write($deck, '/tmp/my-deck.pptx'); // $result === ['path' => '/tmp/my-deck.pptx', 'bytes' => 18432, 'slides' => 1] // Or get the bytes in memory (no temp file) $bytes = Agent::toBytes($deck);
Laravel
use DarkSlide\Laravel\Facades\DarkSlide; DarkSlide::write($deck, storage_path('app/decks/demo.pptx')); return response(DarkSlide::toBytes($deck), 200, [ 'Content-Type' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'Content-Disposition' => 'attachment; filename="demo.pptx"', ]);
Schema
Mirrors @particle-academy/fancy-slides's Deck shape exactly. Coordinates
are 0..1 fractions; DarkSlide converts to PPTX EMU (914,400 per inch) on
write.
See docs/schema.md for the full reference.
Element coverage (v0.3)
| Element | Writer | Reader |
|---|---|---|
| text | ✅ markdown spans + headings (# / ## / ###) |
✅ markdown spans reconstructed |
| image | ✅ (data URI + local path) | ✅ as data URI |
| shape | ✅ (rect, rounded-rect, ellipse, triangle, line, arrow) | ✅ |
| code | ✅ syntax-highlighted runs (JS/TS, PHP, JSON, bash, CSS, Python, HTML) | ✅ as text |
| table | ✅ real <a:tbl> (header + striped body rows) |
✅ round-trips columns + rows |
| background | ✅ solid color, gradient (linear-gradient(…)), image |
✅ solid, gradient, image-as-data-URI |
| chart | placeholder (renders as text fallback) — real chart parts on the v0.4 roadmap | ⚠ skipped |
| embed | not representable in pptx | n/a |
What's new in v0.3
- Markdown headings.
# / ## / ###paragraph prefixes informat: "markdown"text elements emit larger bold runs in the pptx. - Syntax-highlighted code blocks. The
codeelement now ships one<a:r>per token, colored by kind (keyword / string / comment / number / builtin / punctuation). Pure-PHP tokenizer, zero third-party deps. Languages:javascript,typescript,jsx,tsx,php,json,bash,css,python,html. - Reader fidelity for v0.2 features. Tables, gradients, embedded images, and inline bold/italic/code spans now round-trip back to the Deck schema.
Agent tool-use surface
Agent::validateAndRepair($schema) returns ['ok' => bool, 'schema' => array, 'errors' => list] — wire it into your LLM tool to give the agent structured feedback on its emitted decks. Mirrors holy-sheet's pattern.
License
MIT