Wat er nieuw is

Changelog

Elke release van Deckyard, in gewone taal. De details op commit-niveau staan op GitHub; hier lees je wat het betekent voor wie ermee werkt.

  1. v1.13.0 Nieuwste

    Beveiligingsrelease

    Deckyard vraagt zijn sanitizer niet meer aan een CDN, de meegeleverde lettertypes blijken al die tijd de verkeerde te zijn geweest, en er is nu een beeldbron zonder licentie eraan.

    Twee van de drie dingen in deze release zijn hetzelfde ding: een instance hoort de server van iemand anders niet nodig te hebben om goed te werken. De sanitizer kwam van een CDN, en de lettertypes die zelf gehost heetten te zijn bleken bij elke installatie opnieuw bij Google opgehaald te worden, zonder pin, en met de verkeerde bytes.

    Dit is een reden om te updaten. Blokkeert jouw instance third-party requests, of zit hij achter een firewall die cdn.jsdelivr.net stilletjes niet ophaalde, dan laadde de sanitizer van de editor helemaal niet. En los daarvan: vrijwel zeker heeft elk deck tot nu toe in een fallback-letter gerenderd in plaats van in de letter die het thema noemt. Allebei hieronder.

    De sanitizer wordt door je eigen instance geserveerd

    De app-shell laadde DOMPurify van cdn.jsdelivr.net, waarmee een derde partij een afhankelijkheid werd van twee dingen tegelijk: de beveiliging, en of de app überhaupt startte. Hij komt nu uit de npm-kopie die de server-side sanitizer al gebruikte, vastgezet met de integrity-hash uit package-lock.json.

    • Een air-gapped of CDN-geblokkeerde installatie krijgt een werkende sanitizer, waar hij eerder kreeg wat de browser deed als het script niet laadde.
    • Browser en server draaien nu dezelfde DOMPurify. De CDN-tag hing op 3.2.2 terwijl de server al op 3.4.12 zat.

    De lettertypes waren de verkeerde bytes

    Deze is het lezen waard, ook al staat hij als fix in de lijst. Google levert elke lettertypefamilie opgesplitst in subsets per schrift, en verwacht dat de browser er via unicode-range tussen kiest. De installer nam de @font-face die als eerste terugkwam, en dat was cyrillic-ext. Elke gecureerde letter op schijf bevatte dus geen enkele Latijnse glief, en alles wat erom vroeg, slides, exports, de themakiezer en de interface van de app zelf, rendeerde stilletjes in een fallback-letter. Alle vier de Inter-gewichten waren byte-identiek aan hetzelfde Cyrillische bestand.

    • Elk gewicht wordt nu geleverd als latin plus latin-ext, met een echte unicode-range op elke gegenereerde @font-face. Je decks gaan renderen in de letter die het thema daadwerkelijk noemt, wat voor de meeste installaties een zichtbare verandering is.
    • De download is vastgezet. scripts/google-fonts.lock.json legt van elk bestand de exacte URL, SHA-256 en bytegrootte vast, en de installer weigert wat daar niet mee overeenkomt. Tot nu toe was de inhoud van assets/fonts/google/ een functie van Googles releaseschema in plaats van van de versie die jij installeerde.
    • Exports verliezen ruwweg twee derde van hun lettertypegewicht. De meeste gecureerde families zijn variabele fonts waarbij elk gewicht naar hetzelfde bestand wijst, maar elk gewicht werd apart gedeclareerd, en een export base64-inlinet elke regel. Het standaardthema verscheepte zo’n 930 KB aan fonts waar ongeveer 253 KB uniek is, in elk standalone HTML-bestand en elke PDF- of PNG-render.
    • Twee ingebouwde thema’s exporteerden een fallback-letter waar hun CSS om een gewicht vroeg dat het thema niet noemde: Corporate miste Archivo 500, Midnight miste JetBrains Mono 500 en 700. Alle zes de thema’s zijn opnieuw gegenereerd, en een test faalt voortaan als een lijst weer afdrijft.
    • Namen van lettertypefamilies worden nu goed ge-escaped richting CSS. Een naam die op een backslash eindigt kon het sluitende aanhalingsteken van zijn eigen declaratie ontsnappen, en familienamen komen daar binnen via geüploade fonts en custom thema-JSON; het was dus bereikbare invoer en niet alleen een lint. Vijf plekken zetten namen en URL’s in CSS-strings, en op drie daarvan gebeurde helemaal geen escaping.

    Een beeldbron zonder licentie eraan

    Er is een derde beeldbron in de kiezer: 30 abstracte gradiënten, gerenderd uit de paletten van de zes ingebouwde thema’s. Geen API-sleutel, geen naamsvermelding, geen rate limit, geen extern verzoek.

    De reden dat hij bestaat is de licentievraag, niet de esthetiek. Stockbeeld komt van een API van een derde partij met voorwaarden eraan, en dat is ongemakkelijk op een publieke of gasttoegankelijke instance waar uploads uitstaan en stock de enige bron is die iemand heeft.

    • De schakelaar is stockMedia.bundled.enabled, en staat standaard uit. Er is een adminvinkje voor. Op een instance die hem laat staan verandert er niets.
    • Een gekozen gradiënt overleeft de export. De bestanden staan onder assets/gradients/, en dat is het voorvoegsel dat de exporteur inlinet, dus het werkt in PDF- en PNG-exports, gepubliceerde pagina’s en embeds zonder aparte behandeling.

    Het aantal ingebouwde slidetypes blijft 34.

    De volledige lijst op commit-niveau staat bij de release 1.13.0 op GitHub.

  2. v1.12.1

    Onderhoudsrelease

    Twee afgeschreven slidetypes verlaten het register, een pagina zonder video laadt geen videospeler meer, en links blijven leesbaar op donkere themavarianten.

    Een kleine release op dezelfde dag als 1.12.0, met één opruiming die het lezen waard is: de twee slidetypes die al een tijd waren afgeschreven, zijn nu echt weg. Er breekt niets, en er is niets te draaien.

    Twee slidetypes met pensioen

    content-columns-slide en card-stack-slide zijn uit de ingebouwde set. Het aantal ingebouwde slidetypes gaat van 36 naar 34.

    • Opgeslagen decks breken niet. Een slide van een van beide types rendert als gearchiveerde placeholder met alle inhoud nog zichtbaar, dus er gaat niets verloren en er crasht niets.
    • Card stack heeft een opvolger. De placeholder noemt icon-card-grid als doel om naar te herbouwen; dat type neemt dezelfde items[]-vorm, en scripts/migrate-slides.js doet de conversie voor je als je het in bulk wilt.
    • Content columns heeft geen opvolger. Bouw die slides opnieuw met het type dat past; er is geen automatische conversie, omdat er geen type is dat hetzelfde betekent.

    Een pagina zonder video doet nul third-party requests

    Bunny’s player.js werd op elke pagina van de live app geladen, of er nu een video in het deck zat of niet. Hij laadt nu lazy, en alleen als er daadwerkelijk een videoslide is. Voor een deck zonder video zijn dat nul third-party requests, wat zowel privacywinst als een snellere eerste laadbeurt is.

    Een themavariant met een eigen slide-achtergrond erfde de basiskleur voor links, die tegen die achtergrond kon wegvallen. De linkkleur wordt nu per variant afgeleid, dus een omgekeerde of donkere variant krijgt een leesbare link zonder handmatige override.

    Bij het upgraden

    • Afgeschreven slidetypes verwijderen in een 1.x-release is de bedoelde vorm. Deckyard blijft de hele beta op 1.x, dus zo’n opruiming wordt niet bewaard voor een major-versie.
    • Niets te draaien. Het migratiescript is optioneel en bestaat alleen voor wie zijn card stacks liever omzet dan als placeholder laat staan.

    De volledige lijst op commit-niveau staat bij de release 1.12.1 op GitHub.

  3. v1.12.0

    Feature-release

    De slide-editor is herbouwd op één generieke motor, dus elk type bewerkt hetzelfde, en `?lang=` wordt de enige manier waarop een URL een taal aanwijst.

    Bijna elk handgebouwd slideformulier in de editor is weg, vervangen door één editor die de declaratie van elk type leest. Je merkt het als consistentie eerder dan als een nieuwe functie: items toevoegen, verwijderen en herordenen werkt nu op elk slidetype identiek, omdat het letterlijk dezelfde code is.

    Deel je links met ?locale= erin, dan moeten die ?lang= worden. De oude alias is in deze release verwijderd; zie de URL-sectie hieronder.

    De editor is herbouwd

    De formulieren per type waren het oudste deel van de editor en het minst consistent: zeven verschillende collectieformulieren, elk met een eigen idee van hoe een toevoegknop eruitziet.

    • Eén generieke collectie-editor vervangt alle zeven. Lijsten, kaarten, matrix en de rest voegen toe, verwijderen en herordenen nu op dezelfde manier.
    • Grafieken en tabellen worden een gesloten vocabulaire per veld. Elk veld is een gedeclareerde control in plaats van een eigen formulier, en daarom gedragen ze zich nu als de rest van de editor.
    • De afbeeldingsformulieren werden ook declaraties, die één gedeelde elementkaart gebruiken.
    • Nieuwe items krijgen standaardwaarden in de taal van het deck. Item-defaults worden per deck-taal opgelost, dus een rij toevoegen aan een Nederlands deck zet er geen Engelse voorbeeldtekst meer in.
    • De slidelijst leest de labelField van elk type, zodat het label in de linkerlijst het veld is dat de slide daadwerkelijk herkenbaar maakt.

    Een URL die een taal noemt, wordt gevolgd

    • ?lang= is nu de enige URL-parameter voor de interfacetaal. De alias ?locale= is verwijderd. Binnen de app gebruikte niets hem, maar een link die je iemand hebt gestuurd misschien wel: die links moeten worden bijgewerkt, anders openen ze in de opgeslagen taal van de ontvanger in plaats van de taal die jij bedoelde.
    • ?lang= gaat boven de opgeslagen interfacetaal voor die sessie, dus een link die een taal noemt opent daar ook in, ook bij iemand die normaal in een andere taal werkt.

    Opgelost

    • Quoteslides springen niet meer terwijl je typt. De editor-canvas herschikte zich zodra het tekstveld focus kreeg, waardoor de tekst onder je cursor wegliep terwijl je erin klikte. Een gedelegeerde control op dezelfde slide zag er ook niet langer kapot uit.

    Voor wie zelf host

    • De retentie-opruimingen staan nu echt ingepland. Alle drie draaiden alleen als iets ze aanriep, en dat deed niets. Ze hangen nu in een dagelijkse job, die ACTIVITY_RETENTION_DAYS respecteert (standaard 180). Draai je je instance al een tijd, verwacht dan dat activiteitsdata ouder dan het retentievenster verdwijnt bij de eerste nachtelijke run na het upgraden; dat is wat de instelling altijd al hoorde te doen.

    Het aantal ingebouwde slidetypes blijft 36.

    De volledige lijst op commit-niveau staat bij de release 1.12.0 op GitHub.

  4. v1.11.0

    Feature-release

    Een slidetype heeft nu precies één schrijfwijze op de lijn, de schrijf-API weigert types die hij niet kent, en de PDF-export stopt met bestanden maken die niemand wilde versturen.

    Deze release beslecht iets waar het formaat vaag over was: hoe het type van een slide eigenlijk heet. Tot nu toe kon hetzelfde type je in twee schrijfwijzen bereiken, afhankelijk van welke deur het uit kwam, en kon een write elke willekeurige string in dat veld zetten. Allebei zijn hier opgelost. Daaromheen werden organisaties bruikbaar voor de mensen die erin zitten, en kreeg de PDF-export een ronde reparaties.

    Leest er iets dat jij draait slides[].type uit een export of een API-antwoord, lees dan de eerste sectie voordat je update. Opgeslagen decks migreren zichzelf, dus een instance hoeft niets; een integratie die op de oude schrijfwijze matcht wel.

    Eén schrijfwijze voor het type van een slide

    Export en elke lees-API schrijven nu de canonieke reverse-DNS-id, eu.deckyard.slide.title, en niets anders. Daarvoor kon ook de kale registersleutel op de lijn verschijnen, dus moest een consument beide schrijfwijzen kennen en raden waar hij naar keek.

    • Wat de kale sleutel las, moet om. Er is nu één schrijfwijze, en dat is de reverse-DNS-vorm.
    • Het slideTypes-manifest is uit de deck-envelope. Het beschreef de types die in het deck voorkwamen, werd door niets gelezen, en herhaalde een feit dat al op elke slide stond.

    De schrijf-API valideert het slidetype

    Een onbekend slides[].type is nu een 400 op elk schrijfpad. Op Postgres-installaties glipte voorheen elke string er stilletjes doorheen, waardoor een typefout in een integratie een deck opleverde vol slides die nooit konden renderen, zonder dat iets dat meldde tot iemand het opende.

    Schrijf je decks via de API, dan mislukt een onbekend type nu op het moment van schrijven in plaats van op het moment van lezen.

    Opgeslagen decks migreren vanzelf naar schema v4

    Decks die al op schijf staan met een oude typeschrijfwijze worden bij de eerstvolgende read of write naar de canonieke vorm gevouwen. Er is geen script om te draaien en geen downtime; een beheerder hoeft hier niets voor te doen.

    Organisaties: uitnodigen, en een profielscherm

    1.10.0 gaf multi-organisatie-installaties hun eerste schermen en liet twee voor de hand liggende gaten open. Die zijn hier gevuld.

    • Mensen uitnodigen in een organisatie vanuit de interface, met terugkoppeling over welke uitnodigingen er daadwerkelijk uit zijn gegaan.
    • Leden komen bij de ledenlijst, niet alleen admins, zodat een gewoon lid kan zien wie er verder in de organisatie zit.
    • Een organisatieprofiel-scherm, inclusief verwijderen voor de eigenaar.
    • Het beheren van de organisatie waar je op dat moment in zit gedraagt zich correct, wat het niet altijd deed als je bij meerdere hoorde.

    De PDF-export krijgt een ronde reparaties

    Vijf verschillende manieren waarop een PDF verkeerd kon uitpakken, allemaal verholpen:

    • Afbeeldingen worden gecapt op hun weergavegrootte in plaats van hun bronresolutie, wat het grootste deel verklaart van waarom geëxporteerde PDF’s zo groot waren.
    • Gradiënt-achtergronden worden gerasterd, en gradiënt-pseudo-elementlagen ook, zodat een verloop niet meer verdwijnt of gaat banden in de PDF.
    • Blurred shadows belanden niet meer als luminosity-masks in de PDF, wat een zachte schaduw in een grijze rechthoek veranderde.
    • Het slidelettertype is verankerd aan het thema, zodat het interfacelettertype van de app niet meer in het geëxporteerde bestand lekt.
    • Lokale url()-assets worden ge-inlined, en een afbeelding die niet op te halen is wordt leeggelaten in plaats van als kapot vakje achtergelaten.

    Nederlandse veldlabels voor acht slidetypes

    Vergelijking, tijdlijn, aftelklok, custom HTML, embed, lead capture, matrix en proces hadden Engelse veldlabels binnen een Nederlandse interface. Die zijn vertaald, dus een Nederlandse bewerksessie wisselt niet meer halverwege het formulier van taal.

    Voor wie zelf bouwt

    Het spec-werk van deze cyclus is zichtbaar in de referentiedocumentatie: het gepubliceerde JSON Schema is open en de structure-facet is normatief, type-id’s zijn reverse-DNS met -slide eraf, en de catalogus draagt nu drie tiers plus een fallback-facet die zegt wat een reader doet met een type dat hij nooit eerder zag.

    Het aantal ingebouwde slidetypes blijft 36.

    Bij het upgraden

    • Een breaking change in een minor-versie is de bedoelde vorm. Deckyard blijft de hele beta op 1.x; 2.0.0 is gereserveerd voor het verlaten van de beta, niet voor een opruiming die toevallig iets breekt. De ene-schrijfwijze-wijziging en de strengere schrijfvalidatie zijn precies zo’n opruiming.
    • Niets te draaien. Opgeslagen decks migreren bij gebruik; het werk zit in je integraties, als je die hebt.

    De volledige lijst op commit-niveau staat bij de release 1.11.0 op GitHub.

  5. v1.10.0

    Feature-release

    Organisaties krijgen een echte interface, een geëxporteerd deck verliest ongeveer de helft van zijn gewicht, en één slidetype verdwijnt - met de hernoeming die bij het upgraden vanzelf gebeurt.

    De kop van deze release staat niet op een slide: een installatie die meer dan één organisatie draait, heeft er eindelijk een interface voor. Daaromheen werden geëxporteerde decks fors lichter, en verdween een slidetype dat altijd al alleen een tweede naam voor een ander type was.

    Draai je op de file-store, dan heeft de upgrade één handmatige stap. Opgeslagen decks worden automatisch hernoemd door databasemigratie 056, maar een file-store-installatie draait eenmalig node scripts/migrate-lijstje-slide.js. Verderop staat het precies.

    Organisaties krijgen een interface

    Multi-organisatie-installaties hadden het datamodel al een tijd, en geen enkele manier om het te zien. Deze release voegt de schermen toe.

    • Een organisatieschakelaar in het gebruikersmenu, zodat je ziet in welke organisatie je werkt en ertussen kunt wisselen.
    • Adminschermen volgen nu je rol binnen de actieve organisatie, niet meer de instance-brede adminvlag. Wie admin is in organisatie A en gewoon lid in B, ziet in B geen adminschermen meer.
    • De Users-tab wordt in multi-org de ledenlijst van de actieve organisatie, en is nu ook een plek waar je iets doet: een rol wijzigen, iemand verwijderen, zelf vertrekken, eigendom overdragen. De lijst heeft paging, dus een grote organisatie blijft werkbaar.
    • Onderweg zijn verschillende rechtencontroles rond eigendom en organisatie-instellingen aangescherpt.

    Wat er nog niet is, dus reken er niet op: uitnodigen vanuit de interface, en het organisatieprofiel-scherm. Multi-organisatie blijft in ontwikkeling.

    Eén slidetype minder, en het hernoemen gebeurt voor je

    lijstje-slide is met pensioen. Het was een tweede naam voor list-slide en nooit een tweede type, waardoor dezelfde slide onder twee namen opgeslagen kon zijn, afhankelijk van hoe hij was gemaakt.

    • Opgeslagen decks worden automatisch hernoemd bij het upgraden, door databasemigratie 056.
    • File-store-installaties draaien eenmalig node scripts/migrate-lijstje-slide.js na de upgrade.
    • Wat er toch nog doorheen glipt, rendert als gearchiveerde slide die naar list-slide wijst, niet als een kapotte slide.

    Ook split-partner-title-slide verlaat in deze release het register. Het was al een paar versies gearchiveerd en dus niet meer te kiezen bij het bouwen van een deck; slides die het type nog dragen, vallen terug op een gearchiveerde slide. Samen brengt dat het aantal ingebouwde slidetypes van 38 naar 36.

    Een geëxporteerd deck sleept de editor niet meer mee

    Een standalone HTML-export verscheepte de volledige stylesheet van de editor: modals, inspectors, de slidetype-kiezer, instellingen, waar een geëxporteerd deck allemaal niets mee kan. De export verscheept nu alleen viewer-CSS. Dat scheelt ruwweg 92% op de stylesheet in het bestand, wat bij een echt deck neerkomt op ongeveer de helft van het totale gewicht.

    Visueel verandert er niets aan de export, en ?ui=min klapt de chrome nog steeds op dezelfde manier weg.

    Een groen-messing standaardthema

    Er is een nieuw ingebouwd thema, Forest: bosgroen met messing, warm papier en salie als vlakken, en een grafiekreeks die afwisselt in tint én helderheid, zodat twee categorieën naast elkaar meer verschillen dan alleen van kleur. Het is nu het standaardthema.

    Bestaande decks veranderen niet. Een deck slaat zijn thema-id op, dus alleen nieuwe decks en decks die expliciet op default staan verhuizen. Het paarse deckyard-thema houdt zijn id en zijn naam; het is nu een van de zes stijlen in plaats van degene die iedereen erft.

    Kleinere wijzigingen

    • Videoslides: de kijklink die in exports getoond wordt, stel je zelf in. Een video speelt niet af in een PDF, dus toont de export een link; waar die heen wijst mag je nu zeggen.
    • KPI-tegels halen hun kleuren uit het thema via tokens, in plaats van ze zelf mee te dragen.
    • De poster van een videoslide wordt nu gerenderd in de PDF- en PNG-placeholders.
    • AI-suggesties in reacties worden herkend aan de effectieve auteur, zodat een suggestie die namens iemand is gedaan het juiste label krijgt.

    Voor wie zelf host

    • Onderhoudsmodus voor deploys. De instance tijdens een deploy in onderhoud zetten betekent dat een opslag die midden in de deploy landt zichtbaar mislukt in plaats van stilletjes; dat is het verschil tussen opnieuw proberen en werk kwijt zijn.
    • Een gedeeltelijke write wist geen deck-kolommen meer. Een deel van een deck wegschrijven kon velden leegmaken die er niet bij hoorden.
    • Het gepubliceerde JSON Schema draagt geen legacy-velden meer, zodat een tweede implementatie die ertegen valideert niet wordt opgedragen velden te ondersteunen die Deckyard heeft laten vallen.
    • De editor werd rustiger. Deck-thumbnails worden gerenderd bij het opslaan in plaats van bij het kijken, en de slidelijst bouwt zichzelf niet meer opnieuw op bij elke lock- of reactie-gebeurtenis.

    De volledige lijst op commit-niveau staat bij de release 1.10.0 op GitHub.

  6. v1.9.0

    Feature-release

    Deck-thumbnails worden niet meer bij elke bewerking een grijs vlak, een tabel kan één kleur over zijn hele bovenste rij dragen, en AI-verfijnen accepteert de nieuwe vorm van tekstblokken.

    De tweede release van dezelfde dag, na 1.8.0, en de reden om te updaten staat bovenaan: het deckoverzicht flikkert niet meer terug naar grijs zodra je een deck opent.

    Thumbnails laden niet meer opnieuw na elke bewerking

    De kaart van een deck op het startscherm laat een plaatje van de eerste slide zien. Dat plaatje werd gecachet op het revisienummer van het deck, en dat verandert bij elke opslag - dus slide negen bewerken, of een deck alleen maar openen en weer sluiten, gooide het plaatje weg. En een weggegooid plaatje kost ongeveer tien seconden flikkerende placeholder voordat de kaart weer gevuld is.

    De cache gaat nu op waar het plaatje daadwerkelijk uit bestaat: slide 1 en het opgeloste thema. Een bewerking elders in het deck maakt dus niets meer ongeldig. Terwijl een nieuw plaatje wordt gerenderd, wordt het vorige geserveerd, zodat een kaart nooit leeg is puur omdat slide 1 één bewerking achterloopt.

    Eén kleur over de bovenste rij van een tabel

    De cel linksboven in een tabel nam altijd de kleur van de labelkolom, dus een soft-tabel laat een licht getinte hoek zien die net losstaat van de koprij. Dat is een prima look, en nu is het een keuze: een nieuwe instelling Top-left cell bepaalt of de hoek bij de labelkolom hoort (zoals eerst) of bij de koprij, zodat de hele bovenste rij als één band leest.

    Hij combineert met elke tabelstijl in plaats van een vierde stijl te zijn, dus je bestaande tabel houdt de stijl die hij heeft. Het verschil is zichtbaar bij soft; bij plain en panel verandert er niets, omdat de koprij en de eerste kolom daar al dezelfde kleur hebben.

    AI-verfijnen accepteert tekstblokken met vier rijen

    Sinds tekstblokken een array werden (rows[]) eiste het schema achter AI-verfijnen nog steeds de oudere genummerde velden, dus wees het elke array-vormige tekstblokken-slide af - ook verse, en elke slide die de vierde rij uit 1.8.0 gebruikt. Verfijnen valideert nu de array-vorm, met de genummerde velden optioneel en ongemoeid doorgegeven.

    Voor wie zelf host

    • server/data/deck-thumbs/ wordt opgeruimd. De map groeide met één bestand per bewerking aan een eerste slide en er ruimde nooit iets op. Oudere rasters van een deck worden nu verwijderd zodra het verse binnen is.
    • Een 500 in de log wanneer twee mensen dezelfde slide openden is weg. Het claimen van een slidelock is nu atomair; de editor ving die botsing altijd al stil op, dus dit was nooit zichtbaar in de interface, alleen in de serverlog.

    De volledige lijst op commit-niveau staat bij de release 1.9.0 op GitHub.

  7. v1.8.0

    Feature-release

    Een lijstslide houdt de tekstgrootte die je koos en vult de slide, tekstblokken mogen een vierde rij, en quote-slides typen zichzelf niet meer uit.

    Drie wijzigingen aan hoe slides eruitzien terwijl je ze leest, en geen ervan vraagt iets van je. Bestaande decks worden niet gemigreerd en er breekt niets; twee van de drie zorgen er simpelweg voor dat slides die je al hebt eruitzien zoals je ze bedoelde.

    Een lijstslide houdt de grootte die je koos

    Tekstgrootte “Large” kiezen op een lijst van zeven korte bullets deed niets: de slide kwam er op de standaardgrootte uit, in twee kolommen, met de onderste helft leeg. Twee losse oorzaken, allebei nu verholpen.

    • Een expliciet gekozen tekstgrootte wint. Vanaf zeven items werd die grootte weggegooid, in de veronderstelling dat de lijst nog één kolom was. Bij zeven items zijn het er twee, waar ongeveer twee keer zoveel tekst in past. Grootte en kolomaantal worden nu samen bepaald, tegen een opgemeten capaciteitstabel. Het enige geval dat nog terugschakelt - een lijst die zo lang en zo woordrijk is dat hij over twee kolommen heen loopt - zegt dat ook, in de inspector onder “Text size”, in plaats van stilletjes niets zichtbaars te doen.
    • De rijen benutten de overgebleven hoogte. Ze stapelden zich tegen de bovenkant van het lijstvak en lieten de rest van de slide leeg. Ze groeien er nu in mee, zodat de scheidingslijnen gelijkmatig over de slide verdeeld staan in plaats van samen te dringen in de bovenste helft.

    Nagemeten over 1512 combinaties van aantal items, titellengte, tekstlengte, subkop, kolommen en tekstgrootte: er loopt niets over, 628 ervan zijn voller, en geen enkele is leger.

    Decks die uit markdown zijn geïmporteerd profiteren mee. lijstje-slide, dat de importer nog steeds uitschrijft, was een volledige kopie van de definitie van list-slide die naar een veel oudere lay-out was afgedwaald; het is nu een echte alias, dus dezelfde inhoud rendert allebei de kanten op hetzelfde.

    Tekstblokken mogen een vierde rij

    Het maximum op een tekstblokken-slide gaat van drie rijen naar vier. Voor een slide met drie of minder verandert er niets - die renderen byte voor byte hetzelfde - en bij vier rijen wordt de lay-out een tandje strakker, zodat die extra rij past zonder over de titel heen te lopen.

    De vierde rij bestaat alleen in de canonieke rows[]-vorm, en dat is wat de editor schrijft. De oudere genummerde velden (row1, row2, row3) blijven bewust op drie staan, zodat handgeschreven of geïmporteerde inhoud zijn betekenis houdt.

    Quote-slides typen zichzelf niet meer uit

    Een quote-slide typte zijn citaat teken voor teken uit, en deed dat ongeacht de instelling “Builds” van het deck: builds uitzetten bereikte dit ene effect nooit. Hij schokte bovendien, omdat het quote-blok de hele groep centreert - citaat, naamregel en portretten - zodat het blok verschoof terwijl de tekst groeide.

    Het effect is weggehaald in plaats van bijgesteld; het kan later netjes terugkomen. De typemachine per bullet is een ander effect en werkt gewoon door: de onthulstijl “Typemachine” in de deck-instellingen is ongemoeid gelaten.

    De volledige lijst op commit-niveau staat bij de release 1.8.0 op GitHub.

  8. v1.7.1

    Onderhoudsrelease

    Eén fix: de stappen op een horizontale processlide staan weer op één bovenrand.

    Eén fix, op dezelfde dag uitgebracht als 1.7.0. Verder is er niets veranderd en hoef je niets te doen behalve updaten. De reden om überhaupt op 1.7.x te zitten staat in 1.7.0, waar PPTX-export stopte met stil kapot zijn na een PDF-import.

    Processlides staan niet meer scheef

    Op een horizontale processlide werd elke stap verticaal gecentreerd tegen de hoogste, dus een stap met een kortere beschrijving zakte als geheel omlaag: nummer, titel en al. Beschrijvingen zijn zelden even lang, dus de rij stond meestal een paar pixels scheef, op een manier die lastig te benoemen en makkelijk te zien was.

    De stappen delen nu één bovenrand, terwijl de groep als geheel gecentreerd blijft in de slide, zodat een deck dat er al goed uitzag niet ineens omhoog schuift. Ook nagemeten over meerdere rijen, bij zes stappen.

    Bestaande decks zien er na de update simpelweg beter uit.

    De volledige lijst op commit-niveau staat bij de release 1.7.1 op GitHub.

  9. v1.7.0

    Feature-release

    De veldenlijst die een agent krijgt komt nu uit de code die hem definieert, PPTX-export gaat niet meer stuk na een PDF-import, en het herkenningsteken van het formaat draagt de productnaam.

    Drie wijzigingen: een die repareert wat een AI in een slide schrijft, een die een bestand repareert waarvan bleek dat je het niet kon vertrouwen, en een hernoeming die niets van je vraagt.

    Gebruik je PPTX-export en bestandsimport op dezelfde instance, dan is dit een reden om nu te updaten. Op 1.6.0 en ouder leverde een PowerPoint-export na een PDF-import een deck op met onzin waar de slides hadden moeten staan, en zonder enige foutmelding. Hieronder de details.

    De catalogus die agents lezen wordt gegenereerd, niet bijgehouden

    Een slidetype declareert zijn velden één keer, in de registry. De lijst die een model via MCP kreeg was een tweede kopie daarvan, met de hand bijgehouden, en die was op vijf punten afgedwaald. Twee daarvan waren zichtbaar kapot:

    • video-slide kreeg een veldnaam aangeboden die niet bestaat. Agents kregen te horen dat ze videoUrl moesten vullen; het type leest source. Elke AI-geschreven videoslide viel dus stil terug op de demovideo.
    • payoff-slide kreeg een tagline aangeboden die het type helemaal niet leest.

    Die catalogus komt nu uit de registry, dus dit soort fout kan niet opnieuw ontstaan. Dezelfde wijziging vertelt agents ook over velden die een auteur allang met de hand kon invullen, maar die de catalogus nooit noemde.

    PPTX-export was stil kapot na een PDF-import

    Allebei de exports renderen via headless Chrome, en zodra er in hetzelfde serverproces een PDF-import was gedraaid, gaf Chrome een ander soort bytes terug. De PPTX-bouwer nam die voor lief, dus het bestand dat eruit kwam had onzin waar de slides hadden moeten staan, zonder ergens in de keten een foutmelding.

    Een herstart van de server hielp, en dat is precies wat een bug als deze laat overleven: het lijkt een toevalstreffer, en de volgende export gaat goed. Het is gefixt, en er staat nu een rooktest die een echte browser start, dus een stille regressie van deze vorm valt voortaan om in CI in plaats van in iemands deck.

    Het herkenningsteken van het formaat zegt deckyard.deck

    Het veld format in een draagbaar deck, en het mediatype van een .deck-pakket, zeiden slidecreator - een tijdelijke naam uit december 2025, geschreven voordat dit product zijn naam had. Ze zeggen nu deckyard.deck en application/vnd.deckyard.deck.

    Je hoeft niets te doen en er breekt niets. De oude waarden worden bij het lezen blijvend geaccepteerd, dus een deck dat door een oudere versie is geëxporteerd gaat gewoon open. De bestandsextensie verandert ook niet: een pakket downloadt nog steeds als <titel>.deck. Het enige dat aandacht verdient is eigen tooling die op het format-veld matcht; die moet beide waarden accepteren.

    De formaatspecificatie is meegegaan en noemt ze allebei.

    De volledige lijst op commit-niveau staat bij de release 1.7.0 op GitHub.

  10. v1.6.0

    Feature-release

    Een gepubliceerd deck vraagt niet langer dingen op die het niet gebruikt, en een ingesloten deck kan de presentatiebalken eromheen laten vallen.

    Twee wijzigingen, allebei over de pagina die je aan iemand anders geeft. Een gepubliceerd deck laadde syntax highlighting, wiskundeopmaak en een videospeler, of het nu code, formules of video bevatte of niet; nu laadt het die alleen als het ze echt heeft. En een deck in een iframe kun je om een minimale interface vragen, zodat het frame de slide is en verder niets.

    Vijftien verzoeken aan derden, terug naar nul

    Gemeten op een echt deck van negen slides zonder codeblokken, zonder formules en zonder video: vijftien verzoeken aan derden eerst, nu nul. Veertien daarvan gingen naar jsDelivr voor Prism (de core, tien hardgecodeerde taalpakketten en een themastylesheet) plus KaTeX, en één naar mediadelivery.net voor de Bunny-speler.

    Drie dingen die precies moeten:

    • Dit geldt voor elke gepubliceerde pagina, niet alleen de HTML-download. /p/, de embed-route en het geëxporteerde bestand komen uit dezelfde code, dus wie een link deelt heeft er net zoveel aan als wie een bestand opstuurt.
    • De verzoeken zijn voorwaardelijk geworden, niet verwijderd. Een deck met een codeblok laadt nog steeds Prism vanaf jsDelivr, nu de core plus de talen die dat deck echt gebruikt in plaats van tien vaste. Wiskunde laadt nog steeds KaTeX, en een Bunny-video nog steeds zijn speler. Een deck met een codeblok en een formule doet vijf verzoeken.
    • Er is niets gelekt en er is niets gerepareerd. Er werden verzoeken gedaan die niet nodig waren. Dat is iets anders dan een kwetsbaarheid, en het hoort niet als zodanig gelezen te worden.

    Waarom dit de kop is en geen prestatie-voetnoot: Deckyard is software die mensen zelf hosten om hun gegevens in eigen hand te houden, en jsDelivr draait op Fastly in de Verenigde Staten. Een deck dat naar twee Amerikaanse CDN’s belde om negen slides platte tekst te tonen, was een ongemakkelijk ding om aan een publieke instelling te geven.

    ?ui=min voor ingesloten decks

    Zet ?ui=min achter de URL van een gepubliceerd of geëxporteerd deck en de titelbalk en de knoppenrij verdwijnen, waarbij hun layoutrijen naar nul hoogte klappen. Het geschaalde podium van 1600x900 is dan het hele frame, en dat betekent dat een hostpagina een iframe kan maten met een gewone aspect-ratio: 16 / 9 in plaats van een vaste hoogte te compenseren.

    • Het voortgangsbalkje van 3px blijft. Het staat absoluut gepositioneerd, kost dus geen layouthoogte, en het frame blijft precies 16:9.
    • De zichtbare slideteller verdwijnt, want dat was het onderdeel dat op een smal frame afbrak, en de hostpagina kan zijn eigen teller tonen. Schermlezers horen nog steeds “Slide 3 van 9” en de titel van de slide.
    • Pijltjes, spatie, Home, End en F voor volledig scherm blijven allemaal werken.
    • Zonder de parameter verandert er niets, dus bestaande links blijven zoals ze waren.

    Naam en betekenis zijn gelijk aan de ui-optie die de embed-API al had, zodat de twee runtimes één vocabulaire houden.

    En passant kreeg de referentiedocumentatie van de standalone export een sectie over URL-parameters, die er tot nu toe helemaal niet was: loop, autoplay en interval bestonden al, maar stonden nergens opgeschreven.

    De volledige lijst op commit-niveau staat bij de release 1.6.0 op GitHub.

  11. v1.5.1

    Onderhoudsrelease

    Onderhoud aan dependencies, met één ding om vooraf te controleren: de praktische Node-ondergrens ligt nu op 22.13.

    Een onderhoudsrelease: zeven dependency-updates en de ene codewijziging die er één van nodig had. Niets nieuws, en niets gedraagt zich anders. Er is wel één ding dat je beter vooraf doet, en dat staat niet in de release zelf.

    Controleer eerst je Node-versie. Deckyard vraagt al een tijd Node 22 en dat blijft zo, maar twee dependencies in deze release hebben hun eigen ondergrens verhoogd: jsdom (25 naar 29) wil 22.13 of nieuwer, puppeteer-core (24 naar 25) wil 22.12. Draai je Node 22.0 tot en met 22.12, dan zat je op 1.5.0 goed en zit je nu onder allebei. npm handhaaft dat standaard niet, dus het installeert met een waarschuwing in plaats van een foutmelding, en de onderdelen die het zouden merken zijn de HTML-export en de sanitisatie. Precies het soort ding dat je drie weken later pas ontdekt, en daarom staat het hier.

    Wat er verder in zit

    • zod is naar 4 gegaan, en de AI-schemavalidatie is meegegaan: zod 4 haalde ZodError.errors weg en de vijf validators lazen dat veld. Beide zitten in deze release, dus aan de AI-generatie verandert er tussen 1.5.0 en 1.5.1 niets.
    • Chrome 150 onder de export, via puppeteer-core 25. Met de hand nagelopen op een echte render, want geen enkele test start een browser; de uitvoer is ongewijzigd.
    • jsdom 25 naar 29, vier majors onder de HTML-sanitizer. Eenentwintig XSS- en mXSS-vectoren door de vier sanitisatiefuncties geven op beide versies byte-identieke uitvoer. Er is hier niets gerepareerd; er is vastgesteld dat er niets verandert.
    • De RSS-, Atom- en JSON-feeds zijn ongewijzigd na feed 5 naar 6, plus een groep van acht minor- en patch-updates en twee CI-actions die een self-hoster nooit ziet.

    De volledige lijst op commit-niveau staat bij de release 1.5.1 op GitHub.

  12. v1.5.0

    Feature-release

    Deckyard kiest de tekstkleur op een gekleurd vlak nu op gemeten contrast in plaats van op helderheid, en de theme-editor laat het getal zien terwijl je kiest.

    Twee commits, en één ervan verandert hoe decks die je al hebt eruitzien. Deckyard zet zelf lichte of donkere tekst op een gekleurd vlak; die keuze liep op helderheid en loopt nu op een gemeten contrastverhouding, waardoor negen van de twintig paletkleuren in de vijf ingebouwde thema’s van tekstkleur wisselen. Daarnaast heeft de theme-editor een contrast-uitlezing gekregen, zodat het getal dat je voorheen ergens anders moest opzoeken nu naast de kiezer staat die het oplevert.

    Draai je Deckyard, lees dan de updatenotitie voordat het eerste “is er iets stuk?”-bericht binnenkomt. Tekst die gisteren wit was kan vandaag donker zijn, en dat is de herstelde fout, niet een nieuwe.

    De automatische tekstkleur wordt nu gemeten

    Kaarten, accentblokken en achtergrondvarianten krijgen hun tekstkleur van Deckyard en niet van jou. De oude regel splitste op helderheid: donkerder dan het midden, dus lichte tekst. Dat kiest de kleur die logisch oogt, niet de kleur die het beste leest. Beide kandidaten gaan nu door de contrastformule en de hoogste verhouding wint.

    Gemeten over alle vijf de ingebouwde thema’s:

    • Negen van de twintig paletkleuren krijgen een andere tekstkleur.
    • Elke omslag tilt een falend paar naar WCAG AA of beter. Geen enkel paar wordt slechter.
    • Paren onder AA: van negen naar één.
    • Het scherpste geval is het icoonblok van midnight, dat van 2,05:1 ging - wit op lichtblauw, praktisch onzichtbaar - naar 8,16:1.

    Het ene paar dat onder AA blijft is het accent #ea580c van playful op 4,40:1; daar is de accentkleur zelf de grens, niet de keuze van de tekstkleur.

    Omdat contrast niet symmetrisch is rond het midden van de schaal ligt het omslagpunt bij een relatieve luminantie van ongeveer 0,21, dus middel-lichte achtergronden krijgen voortaan donkere tekst. Precies die asymmetrie is de reden dat de oude regel zoveel paren onder AA liet landen.

    De theme-editor laat contrast zien terwijl je kiest

    Bij elk kleurenpaar in de editor staat nu de contrastverhouding en een WCAG 2.2-oordeel: faalt, AA of AAA, gemeten aan de drempel die bij de tekstgrootte van die rol hoort. Knoppen en koppen worden aan de lat voor grote tekst gelegd, bodytekst aan de strengere. Daarnaast staat een APCA Lc-waarde als tweede lezing.

    • Het rapporteert, het blokkeert niet. Een thema met een falend paar kun je gewoon opslaan. Een self-hoster kan een merkreden hebben om een variant met laag contrast te shippen, en een instellingenpaneel is niet de plek om dat te overrulen.
    • De verhouding staat er altijd, of het paar nu slaagt of niet, zodat contrast iets is waar je naartoe kunt sturen in plaats van een alarm dat pas afgaat als je er al overheen bent.
    • WCAG is het oordeel; APCA staat ernaast. WCAG 2.2 is waar EN 301 549 en de European Accessibility Act naar wijzen, dus dat is de claim waar iemand op kan leunen. APCA, kandidaatwerk voor WCAG 3, modelleert waargenomen contrast beter - vooral lichte tekst op donker, waar midnight op gebouwd is - maar beslist nooit.

    De uitlezing gaat over de vier hoofdkleuren en de achtergrondvarianten. Het merkpalet draagt bewust nog geen oordelen: die tokens worden binnenkort opnieuw gedefinieerd, en badges erop zouden bij aankomst al achterhaald zijn.

    Bij het updaten

    • Bestaande decks zien er anders uit, en dat is de bedoeling. Er is niets in te stellen en niets te migreren: de tekstkleur wordt bij het renderen afgeleid, dus een deck openen is genoeg. Het valt het meest op bij midnight en overal waar een icoonblok of accentkaart op een middel-lichte kleur stond. Meldt iemand het als bug, dan mat het paar waar hij naar kijkt vrijwel zeker onder de 4,5:1.
    • Een eigen thema profiteert zonder dat je het bewerkt. De afleiding is gedeeld, dus jouw eigen kleuren gaan door dezelfde meting. Open de theme-editor om te zien waar elk paar nu uitkomt.

    De volledige lijst op commit-niveau staat bij de release 1.5.0 op GitHub.

  13. v1.4.0

    Feature-release

    Een slidetype kan nu de regels dragen die jouw organisatie stelde aan het invullen ervan, en elk geregistreerd type is zichtbaar voor een agent of bewust achtergehouden.

    Wat een AI-agent van een slidetype wist, kwam tot nu toe uit een handgeschreven catalogus in Deckyard: redactionele tekst die zegt welk type je moet kiezen. Deze release zet dat open. Elk geregistreerd type is nu zichtbaar voor agents, ook de types die je eigen instance zelf definieert, en elk type kan de regels dragen die jouw organisatie stelde aan het invullen ervan: uit welke bron de cijfers moeten komen, welke peildatum geldt, wat er verplicht bij vermeld wordt. Het is de eerste feature waarin een self-hoster zelf iets invult, in plaats van dat er achter de schermen iets beter werkt.

    Er zijn die dag twee versies geknipt. 1.4.1 volgde een half uur later met één fix in de streaming-API, beschreven onder Bij het updaten. Installeer 1.4.1.

    Je huisregels reizen mee met het type

    • Elk geregistreerd type bereikt een agent, of wordt bewust achtergehouden. De tool get_slide_types liep tot nu toe de handgeschreven catalogus af, dus een type zonder catalogusregel was onzichtbaar voor agents - en niet te onderscheiden van een type dat met opzet was weggelaten. Hij leest nu de runtime-registry, en types die je zelf in de builder-UI definieert komen er ook in terecht. Van de 38 geregistreerde types worden er 31 aangeboden en dragen er 7 een expliciete opt-out; geen enkele is ongedocumenteerd, en een test laat de build vallen zodra dat verandert.
    • Een type kan zijn eigen gebruiksregels dragen. Naast de tekst die zegt waar een type voor is, kan een type nu de huisregels dragen voor het invullen ervan: de bron waar een grafiek uit moet komen, de peildatum die telt, het voorbehoud dat erbij hoort. Die regels gaan mee in elk antwoord van get_slide_types, na het schema, zodat een agent eerst de vorm leest en daarna jouw regel.
    • Vier plekken om ze te schrijven, afhankelijk van waar het type woont. Op de catalogusregel van een kerntype; als override in een fork, zonder het open-source-bestand te patchen; op een eigen, in een bestand gedefinieerd type; of in de builder-UI voor een type dat in de database staat. Regels zijn begrensd op 1000 tekens per type, want ze vermenigvuldigen zich met elk zichtbaar type in elk antwoord.

    Een verwijderd type houdt zijn inhoud

    Het type freeform-slide is niet langer geregistreerd. Het was al een tijd deprecated en werd nergens meer aangeboden, dus de meeste instances hebben zulke slides niet; staat er toch nog een in een opgeslagen deck, dan gaat er niets verloren. De inhoud blijft in de deck-JSON staan, en de slide toont nu een placeholder die het type benoemt, zegt dat het bewust is verwijderd en naar de opvolger wijst, in plaats van een kaal “Onbekend slidetype”.

    Die placeholder is nu een algemene belofte, niet een pleister voor één type. Op het canvas - editor, presenter, embed, PNG, PDF - is hij begrensd en vertelt hij hoeveel velden hij heeft weggelaten, want een 16:9-kader kan niet meegroeien. In de lees- en reflow-weergave laat hij alles zien, want dat is de plek waar je je inhoud terughaalt. Een deck importeren met een onbekend type bewaart de oorspronkelijke inhoud als markdown in plaats van hem te laten vallen; dat was de enige route waar echt iets sneuvelde. En de editor crasht niet meer op zo’n deck: die gaf voorheen een wit foutscherm in plaats van een placeholder.

    Een kortere inspector-rail

    De titelbalk “INSPECTOR” is weg; het kruisje waarmee je de rail inklapt blijft staan. De achtergrondsectie is gesplitst naar hoe vaak je eraan komt: kleur is een gewoon zichtbaar veld, terwijl de afbeelding met uitsnede, focuspunt en overlay in een ingeklapt blok zit dat een thumbnail toont zodra er een achtergrond staat. Op een titelslide ging de rail van ruwweg 1310 naar 376 pixels, waardoor Toegankelijkheid nu op één scherm past zonder scrollen.

    Opgelost

    • #slide=<n> werkt weer in geëxporteerde HTML. Een geëxporteerd standalone-deck negeerde de deep-link in de URL en opende altijd op slide 1, dus een export delen met een link naar een bepaalde slide deed niets. Het patroon werd uitgeschreven in een template-literal, waar \d inklapt tot een letterlijke d; het matchte dus nooit, en zat er al zolang de export-runtime bestaat.
    • GET /api/v1/image-library gaf altijd een 500. Een gedocumenteerd endpoint dat nooit heeft gewerkt: de route importeerde een functie die de opslaglaag niet exporteert. Hij is nu aangesloten, met de parameters voor zoeken, categorie en paginering daadwerkelijk geïmplementeerd en de OpenAPI-beschrijving gecorrigeerd naar de velden die de bibliotheek echt heeft.
    • Tags schrijven gaf een 400. PUT /api/presentations/:id/tags en POST /api/tags lazen de request-body één niveau te diep, dus tags schrijven via de API was dood bij aankomst.

    Bij het updaten

    • SSE-foutmeldingen hebben een andere vorm gekregen. Dit is de hele inhoud van 1.4.1. Server-sent events op de import-, conversie- en AI-generatiestreams dragen hun fouttekst nu in message in plaats van in error, en bevatten geen ok-veld meer. In de app zelf merk je er niets van; heb je een fork of integratie die op die streams meeluistert, dan is dit één veldnaam om om te zetten.
    • Een breaking change in een minor-versie is de bedoelde vorm. Deckyard blijft de hele beta op 1.x, dus 2.0.0 is gereserveerd voor het verlaten van de beta en niet voor een opruiming die toevallig iets breekt. Het verwijderen van freeform-slide hierboven is die wijziging.

    De volledige lijst op commit-niveau staat bij de releases 1.4.0 en 1.4.1 op GitHub.

  14. v1.3.0

    Feature-release

    Organisaties worden bruikbaar op één instance, uitlijning wordt een eigenschap van het blok, en een cross-user XSS in de slidelijst gaat dicht.

    De organisatie-track landt, en daarmee het antwoord op een vraag die maanden half gebouwd stond: hoe één Deckyard-instance meerdere organisaties bedient zonder dat ze elkaar zien. Er zit ook een beveiligingsfix in die op zichzelf al reden is om te updaten.

    Update als je een multi-user-instance draait. Deze release dicht een DOM-XSS in de slidelijst, onderaan deze pagina beschreven. Een slidetitel wordt door een mens getypt, dus in een deck dat je met collega’s deelt kan de payload uit iemand anders’ slide komen, en hij gaat af zodra je een slide in de lijst versleept. Er valt niets in te stellen: updaten is de fix.

    Organisaties op één instance

    Drie wijzigingen die alleen samen betekenis hebben:

    • Wie je bent hangt niet langer af van waar je bent. Elke authenticatie-lookup filterde op de organisatie die op je account gestempeld stond, terwijl lidmaatschap je bij meerdere kan laten horen. Wie zijn thuisorganisatie niet die van het verzoek was, kwam op niemand uit en kreeg een 401. Daarom is MULTI_WORKSPACE_ENABLED nooit end-to-end aangesloten: aanzetten zou mensen hebben uitgelogd. Identiteit wordt nu los vastgesteld, lidmaatschap is een aparte vraag.
    • Een verzoek draait in de organisatie waar je sessie op uitkwam. Van workspace wisselen veranderde alleen de sessiecookie: lezen, schrijven en lijsten bleven in de standaardorganisatie hangen. De organisatie reist nu mee met het verzoek, en alleen een organisatie waarvan je aantoonbaar lid bent: dat lidmaatschap wordt per verzoek opnieuw gecontroleerd, want een token overleeft een intrekking tot twee weken.
    • Ook de autorisatielaag kent organisaties. De rechtenlaag gaf workspace-brede lees- en schrijfrechten zonder organisaties ook maar te noemen, en leunde erop dat de opslaglaag de query zou afbakenen. In de praktijk hield dat, maar een laag die alleen standhoudt omdat de laag eronder eraan denkt af te bakenen is geen laag. De vier workspace-rechten controleren nu dat beide kanten in dezelfde organisatie zitten; eigenaarschap, auteurschap en toegang als collaborator blijven ongemoeid.

    Installaties met één organisatie, en dat zijn de meeste, gedragen zich precies als eerst en betalen hier niets voor: de organisatie komt uit de configuratie zonder database-lookup, en er komt nergens een query bij.

    Uitlijning hoort bij het blok

    Een titelslide uitlijnen betekende tot nu toe titel, ondertitel en metaregel elk op “gecentreerd” zetten, waarna ze nog steeds gecentreerd stonden op assen die ver uit elkaar liggen, want elk tekstvak zit ergens anders op de slide. Uitlijning is nu een eigenschap van het visuele blok in plaats van van elk veld erin, in één keer in te stellen via de layout-switcher die je al gebruikt. Velden die hun uitlijning niet meer zelf bezitten zeggen dat, in plaats van een knop te tonen die niets doet.

    Opgelost

    • Niets overleeft zijn eigen scherm meer. Een lifecycle-audit van de client vond zes lekken van dezelfde vorm: iets dat bij het openen werd geregistreerd en het sluiten overleefde zonder dat er nog iets was om het te stoppen. Openstaande reconnects bleven streams heropenen die niemand kon sluiten, en opruimacties die zich ná het afbreken meldden verdwenen in een map die niemand nog leegde. De notificatiebel en beide Q&A-streams verbinden nu opnieuw met backoff in plaats van elke 1,2 seconde per kijker aan te kloppen.
    • Een nieuwe deck begint in de taal van je interface. De app in het Engels openen gaf een Engelse interface met de taalknop in “Nieuwe presentatie” nog op de standaardtaal van de workspace. Een taal die je zelf koos wint nog steeds van allebei.
    • Een vastgelopen thumbnail komt altijd tot rust. Een kaart in het deck-overzicht waarvan de thumbnail nooit binnenkwam bleef eindeloos shimmeren. Elke kaart bereikt nu een echte eindtoestand, en schakelt alsnog over op de echte afbeelding als die later arriveert.
    • Card-stack volgt het thema. Het laatste-redmiddel-palet was een hardgecodeerd paars dat bij één thema hoort, dus een eigen thema kreeg kaarten buiten de huisstijl. Het wordt nu afgeleid van de accentkleur van het thema, met een neutrale reeks als allerlaatste vangnet.
    • Conflicten bij gelijktijdig opslaan spreken de standaard-foutvorm. Drie schrijfroutes voor presentaties gaven een zelfgebouwd antwoord terug als je opslaan botste met dat van iemand anders. Ze sturen nu de canonieke envelope, met de vaste codes conflict en locked en de revisiedetails erbij. Statuscodes blijven gelijk en de app merkt er niets van; bouwde je rechtstreeks op de API, dan draagt het veld error nu een machinecode en is de menselijke zin verhuisd naar message.

    Beveiliging

    Een cross-user XSS in de slidelijst. Het sleepbeeld dat ontstaat als je een slide oppakt, zette de titel van die slide rauw in de HTML. Een slide met een stukje markup als titel voerde dat uit zodra iemand hem versleepte, in de browser van degene die sleepte. Omdat slidetitels door mensen worden getypt en decks worden gedeeld, hoeven de schrijver en het slachtoffer op een multi-user-instance niet dezelfde persoon te zijn. Het sleepbeeld bouwt zijn label nu als tekst op, en twee naburige plekken in het JSON-debugvenster en het importpaneel zijn op dezelfde manier herbouwd.

    De volledige lijst op commit-niveau staat bij de 1.3.0-release op GitHub.

  15. v1.2.0

    Onderhoudsrelease

    Een kleine release: interfacetekst die alle talen bereikt, een vertaalde editor-melding, en een ronde hardening voor instances die publiek bereikbaar zijn.

    Een rustige release tussen twee grotere in. Aan het maken van een deck verandert niets; het werk zit in de taal van de interface en in de delen van de stack die aan het open internet grenzen.

    Alle talen krijgen de interface, niet alleen het Engels

    Deckyard komt in 12 talen, maar een label dat rechtstreeks in de code staat heeft geen sleutel om te vertalen, dus verscheen het overal in het Engels zonder dat een test daarover viel. Een audit vond en vertaalde de teksten die nog op het hoofdpad stonden: de melding van de slide-bibliotheek, het voorbeeldblok op een themakaart, de provider-hints en veldlabels in het databronvenster, de autoplay-schakelaar, de bediening van het focuspunt en de alt-tekst van het thema-logo. Een nieuwe controle in CI laat de build vallen op nieuwe hardcoded tekst, zodat de lijst alleen nog korter kan worden.

    De melding “Ongeldige JSON” in het JSON-debugvenster, de laatste rauwe tekst in een verder volledig vertaald venster, loopt nu ook door de vertaallaag.

    Hardening voor instances die publiek openstaan

    Deze ronde is gericht op de anonieme sandbox, en telt voor elke installatie waar onbekenden decks kunnen maken:

    • Rate limiting achter een reverse proxy. Staat Deckyard achter een proxy zonder dat de limiter dat weet, dan telt hij elk verzoek op het adres van de proxy zelf: alle bezoekers delen één bucket en één misbruiker legt de limiet op voor iedereen. Met TRUST_PROXY en TRUSTED_PROXY_COUNT telt hij op het echte adres van de bezoeker.
    • Een quotum per gast. Aantal decks en totaal aantal bytes zijn nu per gast begrensd op elk punt waar een deck ontstaat (aanmaken, importeren, dupliceren), met een kleinere limiet op de request-body die elk daarvan begrenst. Een gast aan het plafond krijgt een duidelijke 429 in plaats van het gedeelde volume vol te schrijven.
    • Nog een SSRF-gat dicht. Externe afbeeldingen liepen bij export al langs de guard; een CSS-background-image: url() die via een geïmporteerde custom-HTML-slide binnenkwam niet. Die wordt nu ingesloten of leeggemaakt voordat de HTML de renderer bereikt.

    De volledige lijst op commit-niveau staat bij de 1.2.0-release op GitHub.

  16. v1.1.0

    Feature-release

    De eerste grote release sinds Deckyard open source werd: live samenwerken, een vernieuwde editor, zelfstandige exports en een steviger self-hostingverhaal.

    Deckyard 1.1 is de eerste flinke release sinds de code openbaar werd. Hij verdiept precies de onderdelen die van Deckyard een platform maken in plaats van een slide-editor: mensen die tegelijk in dezelfde deck werken, exports die je aan iedereen kunt geven, en een self-hostingpad dat tegen een stootje kan.

    Live samenwerken

    • Live presence: zie wie er nog meer in een deck zit, met glijdende naamlabels en focus-chips op de slides die ze bewerken.
    • Conflictvrij samen bewerken op basis van CRDT’s, zodat twee mensen in dezelfde deck kunnen typen zonder elkaar in de weg te zitten.
    • Reacties met @-mentions en autocomplete, leesstatus per persoon, en GitHub-achtige abonnementen die je meenemen naar de threads waaraan je meedoet.

    Een scherpere editor

    • Een inspector die meebeweegt met je selectie en wisselt tussen element- en slide-instellingen.
    • Markdown inline bewerken op het canvas zelf, met een zwevende toolbar.
    • Versleepbare focuspunten op bijgesneden afbeeldingen, volledig met het toetsenbord te bedienen.
    • Kaarten inline herordenen met grip-handles, en beeldinstellingen openen vanaf een chip op de afbeelding zelf.
    • Een datagrid als een spreadsheet voor grafiek-slides, met een CSV-schakelaar om in één keer cijfers te plakken.

    Exports die van jou zijn

    • Eén exportvenster met kleurgecodeerde formaten, zodat het hele menu in één oogopslag leesbaar is.
    • Zelfstandige .deck-bundels die je exporteert en weer importeert met alles er nog in.
    • Losstaande HTML met ingesloten fonts, zodat een deck offline rendert zonder iets te hoeven ophalen.
    • Een semantische, herbruikbare HTML-leesexport, plus kleinere PDF’s dankzij beeldcompressie vóór het insluiten.

    Thema’s en merk

    • Rijkere themaconfiguratie die op het thema zelf wordt bewaard, inclusief achtergrond-presets en titel-slide-layouts.
    • Thema-surface-tokens lopen nu door het slide-ontwerpsysteem, zodat merkkleuren consistent landen over slidetypes heen.

    Self-hosting en beveiliging

    • SSO via één identity provider over OIDC voor zelfgehoste instances.
    • Een installer met één commando en interactieve .env-setup, plus een non-interactieve variant voor agents en CI.
    • Beveiliging over de hele linie aangescherpt: rate limiting en brute-force-throttling op authenticatie, SSRF- en CSRF-bescherming, autorisatie per resource voor live sessies, isolatie tussen workspaces, en security headers.

    Toegankelijkheid

    • Een HTML-semantiekslag door de renderlaag: landmarks, echte lijsten en RTL-ondersteuning.
    • Een kop-overzicht van het document voor visuele export en embed, en een toegankelijkheidspaneel met inklapbare regels.

    De volledige lijst op commit-niveau staat bij de 1.1.0-release op GitHub.

  17. v1.0.0

    Publieke lancering

    Deckyard wordt open source. Het hele platform - maken, presenteren, publiceren, samenwerken - komt op GitHub onder de MIT-licentie.

    De eerste publieke release. Deckyard was al een werkend platform dat dagelijks werd gebruikt; 1.0 is het moment waarop de broncode van jou werd om te lezen, te draaien en aan te passen.

    Wat er live ging

    • Het volledige platform van begin tot eind: 35+ slidetypes, live presenteren, publiceren op het web met één klik, en samenwerken.
    • Self-hosting vanuit één Docker Compose-bestand, Node en Postgres.
    • AI op je eigen voorwaarden: gebruik je eigen sleutel, stel de prompts bij, of stuur het aan via MCP.
    • Exporteren naar PDF, PowerPoint, zelfstandige HTML, PNG en JSON, zodat niets vastzit.
    • MIT-gelicenseerd, GDPR-native, gebouwd om te draaien op infrastructuur die jij beheert.