Build Decktopus
KINDAback to the verdict
A presentation editor whose hard problems are that a slide is a fixed box with no reflow, that generated text has to be measured against that box before it is accepted, and that an export has to reproduce the geometry in the units the target format actually uses.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the development server, the build and the export tests.
Get it nodejs.org or your version manager. open ↗
Verify
node --version prints v22 or higher - have readyfree with open licences
Why Export fidelity depends on embedding, and a font whose licence forbids it must be substituted deliberately rather than by accident.
Get it Choose open licensed families and keep the licence files with the project.
Verify
Each theme font has a licence file and an embedding permission noted - have readyfree with a viewer
Why The only meaningful test of an export is opening it in the tool your audience will use.
Get it Any widely used presentation application, including a free viewer.
Verify
An exported deck opens with boxes at measured positions - API keypay per token; a deck is small change
Why Generation is the only part that costs money and the only part that leaves the machine.
Get it A key with a spend limit set in the provider console.
Verify
An outline generates and one slide's slots fill within capacity - decidefree
Why It sets every layout slot and every capacity figure, and changing it later re-measures the entire deck.
Get it Pick the aspect ratio and dimensions, confirm them against a file produced by your target application, and write them in the configuration.
Verify
The configured dimensions match a file the target application created
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- decks(id, title, slide_w_emu, slide_h_emu, theme_id, created_at, updated_at) - slides(id, deck_id, position, layout_id, notes, generated_from_outline_item) - boxes(id, slide_id, role, x_emu, y_emu, w_emu, h_emu, z, style_json) · role ties a box to a slot in its layout - content(box_id, kind, text, asset_id, autofit_mode, measured_overflow) · measured_overflow is recomputed on every change and is never allowed to persist as true on a published deck - layouts(id, name, slots_json) · each slot declares its box and a character capacity measured at the theme's sizes - themes(id, name, fonts_json, palette_json, asset_ids_json) · fonts are files stored with the deck - outline(deck_id, position, heading, intent, notes) · the structure the generation fills, editable before any slide exists
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
VITE_SLIDE_W_EMU | required | 12192000 | Slide width in the format's units. Confirm against a file your target application made. |
VITE_SLIDE_H_EMU | required | 6858000 | Slide height in the same units. |
VITE_MIN_FONT_PT | required | 14 | The shrink floor. Below this, a box is marked as overflowing instead. |
VITE_MODEL_ENDPOINT | optional | https://api.example.com/v1 | Outline and slot generation. The editor works without it. |
VITE_MODEL_API_KEYsecret | optional | sk-...redacted | Only needed for generation. Set a provider-side spend limit. |
VITE_EXPORT_ALLOW_OVERFLOW | required | false | The override. Turning it on is recorded in the fidelity report. |
The build, in order
A slide is a fixed box in real units
Everything on a slide has a position and size in the units the presentation format uses.
Converting at export is where a deck stops matching itself.
Files
src/model/units.tstests/units.test.tsThe screen is a view of the document, not its coordinate system.
Files
src/canvas/render.tsSo a slot's capacity means something measurable.
Files
src/model/layouts.ts
done when · tick each as it passeswatch out- Authoring in CSS pixels and converting only at export means every box is a rounding error away from where it was, and the presentation format measures in English Metric Units where the standard's own example gives a four by three slide as 9144000 by 6858000 for ten by seven and a half inches, which is 914400 units to the inch. Store the units the format uses and convert for the screen, so an export is arithmetic rather than a translation.
Text that fits, or a slide that admits it does not
Overflow is a state the editor shows and the export refuses, never something that is quietly clipped.
Otherwise you measured a font nobody will see.
Files
src/text/measure.tstests/measure.test.tsSix point body text is not a solution.
Files
src/text/autofit.tsIn the sorter and the header, not in a console warning.
Files
src/ui/Header.tsx
done when · tick each as it passeswatch out- Measuring text before the web font has finished loading measures the fallback, so a box that fitted during editing overflows in the export and in the room, and the first time anyone sees it is on a projector. Wait for the font set to report ready before measuring, and re-measure every box when the theme's fonts change.
Generation that fills a structure
A model writes into slots with declared capacity, and anything that does not fit is rejected before it reaches a slide.
The structure is the part a human should own.
Files
src/generate/outline.tsA character budget is the only instruction that actually constrains length.
Files
src/generate/slots.tstests/generate.test.tsAn empty slot is honest; a clipped one is not.
Files
src/generate/apply.ts
done when · tick each as it passeswatch out- Asking a model for a finished slide and rendering whatever comes back produces a deck where half the bullet lists run off the bottom edge, and because generation feels like magic people ship it without opening slide fourteen. Generate against slots with capacities, measure every returned string, and make an unfittable response an empty slot with a reason attached.
Presenting it in a room
The deck can be delivered from a laptop with notes, a clock and no surprises.
Nothing about the room is under your control.
Files
src/present/preload.tsIt is the only reason presenter view exists.
Files
src/present/PresenterView.tsxYou will forget them between decks.
Files
src/present/Help.tsx
done when · tick each as it passeswatch out- Presenting from a view that fetches images as each slide appears means a slow room connection turns your deck into a slideshow of grey boxes, in front of people. Preload the whole deck's assets before presenting starts and refuse to begin until they are in memory, with a progress indicator.
A file other people can openproduct builder
Export produces a presentation file and a PDF, with a written report of everything that was approximated.
No conversion means no drift.
Files
src/export/pptx.tstests/export.test.tsSilence about fidelity is how decks embarrass people.
Files
src/export/report.tsWith a deliberate override, recorded.
Files
src/export/gate.ts
done when · tick each as it passeswatch out- Exporting a deck that still has boxes marked as overflowing produces a file that looks acceptable in your preview and cuts a sentence in half on somebody else's machine, which is the failure this whole build was designed to prevent. Make the overflow count a gate on export, with an override that has to be chosen deliberately and is recorded in the fidelity report.
That is the whole plan for Decktopus. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Real time co-editing.
- Importing other people's presentation files.
- Animations and transitions.
- Embedded forms and viewer analytics.
- high-fidelity import and export
- presentation and enterprise controls
- multiplayer cursors and comments
- large template libraries
- Speaker note generation from the outline, which is the one generated text with no box to overflow
- A rehearsal timer that records how long each slide actually took, which is more useful than any template
- Image placement from a local library with alt text required, so the export is accessible by default
Need the files? The project pack on the verdict page hands your agent the whole brief · more presentations.