Specificatie

Het deckformaat

De draagbare, geversioneerde vorm waarin een presentatie wordt geserialiseerd, zodat een tweede implementatie hem kan lezen, renderen en round-trippen zonder de server of de opslag van Deckyard.

Een deck bewaart presentatie-inhoud, met slides als een array van { type, content }-records. De JSON beschrijft de inhoud los van de weergave, maar verwijzingen naar lokale uploads blijven afhankelijk van de bronserver.

De envelop

De envelop bevat de formaataanduiding en versie, presentatiemetadata en slides. De optionele velden lang en translations bevatten taalinformatie.

{
  "format": "deckyard.deck",
  "version": 1,
  "title": "My deck",
  "theme": "default",
  "slides": [
    {
      "type": "eu.deckyard.slide.title",
      "content": {
        "title": "My deck",
        "subheading": "An example in the open deck format",
        "background": "lime"
      }
    },
    {
      "type": "eu.deckyard.slide.quote",
      "content": {
        "quote": "A deck is data, not a rendering.",
        "authorName": "Deckyard",
        "authorTitle": "Format specification"
      }
    }
  ]
}
Het volledige voorbeelddeck staat op deze website, op deckyard.eu/spec/example-deck.json.

De envelop is inschikkelijk. Onbekende sleutels op het hoogste niveau worden door een importeur genegeerd en nooit geweigerd, zodat een nieuwere schrijver een veld kan toevoegen dat een oudere lezer simpelweg overslaat.

De documentatie beschrijft elk veld op het hoogste niveau, inclusief `lang` en `translations`, met het type en de verantwoordelijkheden van de lezer. Volledige referentie

Slides, en de ene spelling van een type-id

Een slide is een type plus een content-object waarvan dat type de vorm bepaalt. Een afwezig of leeg veld betekent "niet ingevuld": een importeur vult de standaardwaarden van het type in en maakt een verplicht veld nooit leeg. Draagbare slides hebben geen id, want ids horen bij opslag en worden bij import opnieuw gegenereerd.

slides[].type is de canonieke id van het type, en een type heeft er precies één: reverse-DNS voor een declarant met een domein (eu.deckyard.slide.title), namespace/naam voor een declarant zonder. De id noemt zelf al de definitie waartegen de slide geschreven is en mag een versie vastpinnen (@2), dus er is geen apart manifest om ernaast te leggen. Twee oudere spellingen - de kale registrysleutel title-slide en de gekwalificeerde core/title-slide - zijn restanten van vóór de convergentie, geen onderdeel van het formaat: Deckyard accepteert en normaliseert ze nog bij import, maar wat het exporteert is canoniek, en een tweede implementatie is ze niets verschuldigd.

{ "type": "eu.deckyard.slide.content", "content": { "title": "Why", "body": "..." } }

Contentschema's

De contentvorm van elk slidetype wordt beschreven door een JSON Schema dat wordt gegenereerd uit dezelfde veldregistry die de validatie draait en het editorformulier bouwt. Eén declaratie, vier afnemers, en geen manier waarop een schema een vorm kan beschrijven die de software niet accepteert.

Ze zijn geversioneerd via hun $id, en die draagt de versie van de contentvorm (15), niet de envelopversie (1). https://deckyard.eu/schema/v15/deck.schema.json is het hele deck, https://deckyard.eu/schema/v15/slide-types/<type>.schema.json is één type, en https://deckyard.eu/schema/v15/index.json geeft je de lijst. Alle drie zijn ze op te halen: formeel hoeft een $id dat niet te zijn, maar voor een formaat dat je aan anderen aanbiedt als standaard hoort het toch.

Extra properties zijn toegestaan. De schema’s beschrijven de bekende vorm van een slide. Gepubliceerde schemapaden blijven beschikbaar, ook voor types die later mogelijk worden uitgefaseerd, zodat een opgeslagen deck zijn schemaverwijzing kan behouden.

Verwijzingen naar beelden

Afbeeldingen worden per string aangeduid. Een lokale upload is een serverpad en is alleen draagbaar zolang die server bereikbaar is. Een externe https://-URL is al draagbaar en wordt door elke transformatie met rust gelaten.

Het pakket: een deck met zijn pixels

Waar de JSON-export nog naar plaatjes op een server wijst, draagt het pakket zijn eigen pixels mee. Het rendert en round-trript op een machine die de installatie waar het vandaan komt nooit gezien heeft, en het kan precies opsommen welke bestanden erin zitten.

De indeling is gemodelleerd op OCF, de verpakking die EPUB gebruikt, en om dezelfde reden: een ZIP waarvan de eerste ingang een ongecomprimeerd mediatype is, valt te herkennen aan een magic number voordat er iets is uitgepakt. Zes ingangen, in deze volgorde; twee ervan alleen als het deck ze nodig heeft.

mimetype
manifest.json
deck.json
theme.json
slide-types/<slug>.json
assets/<sha256>.<ext>
mimetype
Eerste ingang, ongecomprimeerd opgeslagen, met precies application/vnd.deckyard.deck erin.
manifest.json
Metadata van het pakket en de volledige inventaris van de bestanden, met de hash van het thema en van elk slidetype dat het pakket meeneemt. De oorspronkelijke bestandsnamen blijven erin staan, zodat hash-churn nooit in de leesbare structuur lekt, en meerdere bronnen bij één hash betekent dat dezelfde bytes vanaf meerdere plekken werden gebruikt.
deck.json
De draagbare envelop, met elke verwijzing naar een beeld herschreven naar een plek in het archief.
theme.json
Alleen als het deck een databasethema heeft: het themarecord zelf, zonder het id dat op een andere installatie niets betekent. Een bestandsthema hoort bij een installatie en reist alleen mee als id in deck.json.
slide-types/<slug>.json
Eén bestand per databaseslidetype dat het deck gebruikt, gebouwd in de app in plaats van in code. Coretypes en types die in code zijn gedefinieerd reizen mee als type-id op de slide.
assets/<sha256>.<ext>
De bytes van de bestanden, geadresseerd op de SHA-256 van hun eigen inhoud: beelden op slides, logo's van het thema en fontbestanden met een open licentie. Identieke bytes worden één keer opgeslagen.

Dat mediatype is geregistreerd. application/vnd.deckyard.deck is op 13 augustus 2026 toegekend in de vendor tree van IANA, na Expert Review. Een registratie in de vendor tree is geen standaardisatie: ze legt de naam vast, stelt vast dat hij van niemand anders is, en wijst naar deze specificatie. Het registratieformulier

  • Zelfdragend

    Elk lokaal beeld op een slide zit erin, net als de logo's en open-licentiefonts van een databasethema. Zo'n pakket rendert offline. Vier dingen blijven erbuiten: beelden die via een externe https://-URL gelinkt zijn, een bestandsthema, bestanden waarnaar vanuit een CSS-waarde verwezen wordt, en fonts die alleen bij naam meereizen: gelicentieerde fonts, en fonts waarvan de verzendende installatie geen bestand heeft.

  • Op inhoud geadresseerd en verifieerbaar

    De bytes van elk bestand hashen naar hun eigen verwijzing. De lezer hasht bij binnenkomst alles opnieuw en weigert een mismatch, dus een beschadigd of gemanipuleerd archief faalt hoorbaar.

  • Gededupliceerd

    Identieke bytes worden één keer opgeslagen, hoeveel slides er ook naar wijzen.

  • Opsombaar

    Het manifest noemt elk bestand dat een deck nodig heeft. Je kunt "wat zit hier eigenlijk in" beantwoorden zonder uit te pakken.

Elk veld in het manifest, en wat de import ermee doet, staat uitgeschreven in de documentatie. Volledige referentie

Wat gegarandeerd is, en wat lossy

Voor slides met inhoud is export naar import naar export een vast punt: na één normalisatieslag is de draagbare projectie stabiel, en identieke bytes hashen naar identieke adressen. Een test in de core-repo bewijst dat bij elke run tegen een meegeleverd voorbeelddeck. Twee randen zijn bewust wel lossy, en allebei zijn ze gespecificeerd zodat ze degraderen in plaats van crashen - en dat is precies wat het formaat veilig maakt om tegenaan te bouwen.

Onbekend slidetype
Importeert als plaatshouder die zegt welk type niet gevonden werd, of dat type bewust is uitgefaseerd en wat ervoor in de plaats komt, en die de oorspronkelijke inhoud als tekst meeneemt.
Ontbrekend lokaal beeld
Behoudt zijn oorspronkelijke verwijzing en importeert als losse verwijzing. Onschadelijk, en zichtbaar in plaats van stil. Het manifest noemt zulke verwijzingen onder missingAssets, en fonts die alleen bij naam meereizen onder fontsNotIncluded, zodat een lezer weet wat hij moet ophalen of vervangen.

Behandel auteursinhoud als onvertrouwde invoer

Het formaat heeft geen macro’s of eigen scripttaal. Een custom-html-slide kan HTML van de auteur bevatten en een embed-slide kan naar een externe URL verwijzen. Lezers moeten beide als onvertrouwde invoer behandelen; geslaagde schemavalidatie maakt die inhoud niet veilig om weer te geven.

Wat daaruit volgt is een plicht voor wie het formaat leest, geen eigenschap ervan: saneer auteurs-HTML voordat die een document bereikt, en isoleer ingesloten URLs in een frame dat niet bij de pagina eromheen kan. De pakketlaag verandert daar niets aan. Adressering op hash bewijst dat de bytes de ingepakte bytes zijn; over de vraag of ze veilig zijn om uit te voeren zegt het niets.

Versionering

version geeft de envelopversie aan en verandert wanneer de envelopvorm de compatibiliteit breekt. Slide-inhoud heeft een eigen schemaversie en migratiemechanisme. Lezers valideren tegen de versie die ze ondersteunen en tolereren onbekende sleutels volgens de regels van het formaat.