Build Decktopus

KINDAback to the verdict

0%0 of 17 items done

Saved on this device only. Tick prerequisites first, then work the phases in order · do not start one until the checks above it pass.

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.

estimated effort multi-daythe files for this build are in the project pack

RuntimeReact with TypeScript on Vite, local first, no accountGeometryEvery position and size stored in English Metric Units on a fixed slide canvasTextMeasured with the real font before it is accepted into a box, never clipped silentlyGenerationAn outline first, then slots with declared character capacity that the model fillsExportA presentation file written directly, plus PDF, with a report of anything approximated

Before step 1

Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.

  1. 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

  2. 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

  3. 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

  4. 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

  5. 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.

VariableNeededExampleWhere the value comes from
VITE_SLIDE_W_EMUrequired12192000Slide width in the format's units. Confirm against a file your target application made.
VITE_SLIDE_H_EMUrequired6858000Slide height in the same units.
VITE_MIN_FONT_PTrequired14The shrink floor. Below this, a box is marked as overflowing instead.
VITE_MODEL_ENDPOINToptionalhttps://api.example.com/v1Outline and slot generation. The editor works without it.
VITE_MODEL_API_KEYsecretoptionalsk-...redactedOnly needed for generation. Set a provider-side spend limit.
VITE_EXPORT_ALLOW_OVERFLOWrequiredfalseThe override. Turning it on is recorded in the fidelity report.

The build, in order

  1. 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.

    1. Converting at export is where a deck stops matching itself.

      Files src/model/units.tstests/units.test.ts

    2. The screen is a view of the document, not its coordinate system.

      Files src/canvas/render.ts

    3. So a slot's capacity means something measurable.

      Files src/model/layouts.ts

    done when · tick each as it passes
    watch 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.
  2. 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.

    1. Otherwise you measured a font nobody will see.

      Files src/text/measure.tstests/measure.test.ts

    2. Six point body text is not a solution.

      Files src/text/autofit.ts

    3. In the sorter and the header, not in a console warning.

      Files src/ui/Header.tsx

    done when · tick each as it passes
    watch 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.
  3. 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.

    1. The structure is the part a human should own.

      Files src/generate/outline.ts

    2. A character budget is the only instruction that actually constrains length.

      Files src/generate/slots.tstests/generate.test.ts

    3. An empty slot is honest; a clipped one is not.

      Files src/generate/apply.ts

    done when · tick each as it passes
    watch 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.
  4. Presenting it in a room

    The deck can be delivered from a laptop with notes, a clock and no surprises.

    1. Nothing about the room is under your control.

      Files src/present/preload.ts

    2. It is the only reason presenter view exists.

      Files src/present/PresenterView.tsx

    3. You will forget them between decks.

      Files src/present/Help.tsx

    done when · tick each as it passes
    watch 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.
what this build does not replace
after v1, if you want it

Need the files? The project pack on the verdict page hands your agent the whole brief · more presentations.