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.37.0 Nieuwste

    Feature-release

    Bewerk een slide in de slidebibliotheek met het volledige slideformulier in plaats van alleen de naam; favorieten in de bibliotheek worden onthouden, per gebruiker; en een beveiligingsfix voor tags in de bibliotheek.

    Een slide in de slidebibliotheek bewerken betekende tot nu toe de naam en beschrijving aanpassen, of hem in een wegwerpdeck zetten om de rest te wijzigen. Nu opent Edit het volledige slideformulier. Deze release repareert ook de favorieten in de bibliotheek en dicht een gat in de controle op tags. Update als er meer dan één persoon op je installatie inlogt.

    Een bibliotheekslide bewerken met het volledige formulier

    • Edit opent hetzelfde formulier als in een deck, voor het type van die slide: geneste kaarten en leden, beelden via de gewone kiezer, achtergrond, de Layout-chip en de toegankelijkheidsvelden, met Undo en Redo. Opslaan schrijft terug naar hetzelfde bibliotheekitem; een tijdelijk deck is niet meer nodig.
    • Mag je een gedeeld teamitem niet wijzigen, omdat je niet de maker of een beheerder bent, dan blijft Edit grijs met de reden erbij, en maakt Duplicate to my library een persoonlijke kopie en opent de editor daarop.
    • Slaan twee mensen hetzelfde item tegelijk op, dan krijgt de tweede een conflict naast Save in plaats van de eerste te overschrijven, en sluit je de editor met niet-opgeslagen wijzigingen, dan vraagt hij het eerst.

    Favorieten worden onthouden

    • De ster in de slidebibliotheek blijft nu staan. Tot deze versie leek hij aan te staan en was hij na herladen weg. Favorieten zijn per gebruiker: de jouwe zijn van jou, een collega heeft eigen sterren.

    Beveiliging: tags volgen de rechten van het item

    • Tot deze versie kon een ingelogde gebruiker de tags wijzigen van een bibliotheekitem van iemand anders. Dat is dicht. Tags volgen nu dezelfde regel als de rest van het item: alleen wie het item mag wijzigen, kan de tags wijzigen, en het persoonlijke item van een ander is via de API helemaal niet bereikbaar.
    • Tags zijn alleen-lezen in het voorbeeld van de bibliotheek als je het item niet mag bewerken, net als de beschrijving.

    Geen databasemigraties tussen 1.36.1 en 1.37.0; een gewone upgrade volstaat. Het aantal ingebouwde slidetypes blijft 35.

    Zie voor de volledige lijst op commitniveau de 1.37.0-release op GitHub.

  2. v1.36.1

    Beveiligingsrelease

    Een beveiligingsfix voor de slidebibliotheek: een persoonlijk item kan alleen door de eigenaar worden gewijzigd of verwijderd, en een gedeeld teamitem door de maker of een beheerder.

    Een patch met één wijziging, en dat is een beveiligingsfix. Update als er meer dan één persoon op je installatie inlogt. Zit je nog op 1.35.0 of eerder, lees dan eerst de notities bij 1.36.0: de prullenbak-opruiming die daarin zit, draait bij de eerste start.

    Rechten in de slidebibliotheek worden op de server gecontroleerd

    • Tot deze versie kon een ingelogde gebruiker via de API het persoonlijke bibliotheekitem van een collega wijzigen of verwijderen. Dat is dicht. Elke wijziging aan een bibliotheekitem loopt nu door één controle op de server: je kunt alleen je eigen persoonlijke items wijzigen of verwijderen, en een gedeeld teamitem alleen als je de maker of een beheerder bent.
    • Twee gelijktijdige bewerkingen overschrijven elkaar niet meer stil. De tweede opslag krijgt een conflict in plaats van de eerste te vervangen.
    • Wijzig je de inhoud van een item, dan blijven de andere taalversies bij, in plaats van op de oude inhoud te blijven staan.
    • Een custom-HTML-slide in de bibliotheek opslaan volgt de regel van de editor: alleen wie custom HTML mag maken, kan er daar een aanmaken of wijzigen.

    Voor koppelingen

    • Naam, beschrijving of inhoud van een bibliotheekitem wijzigen via de API vraagt om de revisie. Elk item heeft nu een revision; stuur die mee in If-Match. Zonder antwoordt de server met 428, met een verouderde met 409. Een update met een veld dat de bibliotheek niet kent, wordt geweigerd met 400. De app zelf doet dit al.

    Het aantal ingebouwde slidetypes blijft 35.

    Zie voor de volledige lijst op commitniveau de 1.36.1-release op GitHub.

  3. v1.36.0

    Feature-release

    De prullenbak verwijdert nu wat hij zegt te verwijderen, na een bewaartermijn die je zelf instelt; een beeld uit ImageKit wordt eerst eigen media voordat het op een slide komt; en beeldblokken, tekstblokken en de editor volgen de leesvolgorde.

    De prullenbak zegt altijd al dat weggegooide presentaties na 30 dagen worden verwijderd, en tot deze release verwijderde niets ze. Nu wel. Dat is de wijziging die je leest voordat je update; de rest is een ImageKit-kiezer die decks niet langer aan een extern CDN vastknoopt, en een ronde fixes in lay-out en editor.

    Kijk in je prullenbak voordat je update. Vanaf deze versie verwijdert een dagelijkse opruiming elke presentatie die langer dan TRASH_RETENTION_DAYS (standaard 30 dagen) in de prullenbak staat definitief, inclusief thumbnails. De opruiming draait ook meteen bij het opstarten van de server, dus de eerste start na de upgrade ruimt de hele achterstand in één keer op: alles wat op jouw installatie al langer dan de termijn in de prullenbak staat, is binnen enkele minuten na het opstarten weg. Wil je die achterstand bewaren, herstel dan eerst wat je nodig hebt, of zet TRASH_RETENTION_DAYS hoger voordat je deployt. Er is geen waarde die de opruiming uitzet; 0, een negatief getal of alles wat geen getal is, valt terug op 30.

    De prullenbak houdt zich aan zijn belofte

    • Weggegooide presentaties worden na de bewaartermijn verwijderd. De opruiming is dezelfde verwijdering als Delete permanently, presentatie voor presentatie, inclusief thumbnails. Hij draait eens per dag, dus een presentatie kan tot een dag na de termijn nog bestaan.
    • Herstellen zet de klok stil. Een presentatie die je voor het einde van de termijn herstelt, blijft; gooi je hem opnieuw weg, dan begint een nieuwe termijn.
    • De prullenbak noemt de ingestelde termijn, in elke taal. Een installatie met TRASH_RETENTION_DAYS=7 zegt 7 dagen. Zie Trash & Recovery en de instellingen voor dataretentie (Engelstalig).
    • Definitief verwijderen kan alleen voor een presentatie in de prullenbak. De app weigert een presentatie definitief te verwijderen die niet eerst is weggegooid, en een verzoek om een presentatie te herstellen die niet in de prullenbak staat geeft nu 409 not_trashed in plaats van 400.

    Een keuze uit ImageKit wordt eigen media

    • Kies je een beeld uit ImageKit, dan wordt het eerst gekopieerd naar de eigen media van je installatie, en de slide verwijst naar die kopie. Een deck breekt niet meer als het bestand in ImageKit wordt verplaatst, hernoemd of verwijderd. Mislukt het kopiëren, dan blijft de kiezer open met de reden naast “Use this image” en blijft de slide zoals hij was. Decks die al ImageKit-URL’s bevatten worden niet aangepast.
    • Het kopiëren is een upload, dus het heeft uploads nodig. Op een installatie met DISABLE_UPLOADS=1, of in demo- of sandboxmodus, meldt de kiezer dat in plaats van het beeld te plaatsen.

    Lay-out en bewerken

    • Beeldblokken gebruiken de ruimte die ze hebben. Op een beeldblokkenslide die elke afbeelding in zijn oorspronkelijke verhouding laat, krijgen de beelden de maat van de ruimte onder de kop: vier liggende foto’s passen weer op één rij, een tweede rij duwt de inhoud niet meer over de kop, en de titels onder de beelden staan op één lijn.
    • Een collectie onder een kop centreert in de ruimte eronder. Tekstblokken met een paar rijen laten geen lege strook meer onderaan de slide, en een tabel centreert onder zijn bijschrift; inhoud die te lang is, begint nog steeds onder de kop. De kop van tekstblokken staat standaard gecentreerd, links uitlijnen zit nog in de Layout-chip.
    • Opmaak is zichtbaar terwijl je typt. De opmaakbalk verschijnt bij de cursor zodra je een tekstveld met opmaak bewerkt, ook een leeg veld, zodat je vet of cursief kunt aanzetten voordat je typt. Een link vraagt nog steeds om geselecteerde tekst.
    • De velden van tekstblokken staan in leesvolgorde: rijkop en kleur, de blokken, dan de pijl naar de volgende rij, met de subkop onderaan na alle rijen. De eerste rij krijgt ook een chip voor zijn kop.

    Kleinere wijzigingen

    • Importeer je een bestand dat geen .deck-bundle is, dan krijg je een gewone reden (“the file is not a zip archive”) in plaats van een foutmelding uit een bibliotheek, en een bundle met een kapotte manifest.json of deck.json noemt het kapotte bestand.
    • Bibliotheektegels in de slidekiezer houden hun eigen inhoud als je de weergave of de achtergrond van het voorbeeld verandert.

    Geen beveiligingsfixes in deze release; 1.36.1, dezelfde dag uitgebracht, is er wel een, dus update meteen daarheen. Het aantal ingebouwde slidetypes blijft 35.

    Zie voor de volledige lijst op commitniveau de 1.36.0-release op GitHub.

  4. v1.35.0

    Feature-release

    Een .deck-bestand draagt het hele deck, inclusief elke taal, het thema en eigen slidetypes; de leesexport leest als een document met echte lijsten, citaten, kaders en figuren; en een genummerde lijst die je in de editor typt toont niet langer 1, 1, 1.

    Eén dag na 1.34.0 landen twee sporen tegelijk: de tweede helft van het portabele deck, en de leesprojectie die van een deck een document maakt. Eén breaking change, in de vorm van de deck-export, en één fix die op zichzelf al een update waard is.

    Controleer je koppelingen voordat je update. De JSON-export en de .deck-bundle dragen nu elke taal van een deck, dus ?lang= op de JSON-export kiest er geen meer; content is de dominante taal. /api/v1/schema/deck.json beschrijft die export in plaats van het opgeslagen model: format, version en title zijn verplicht, id, schemaVersion, created, modified, settings en description zijn weg, en slides dragen geen id. Een import weigert een deck met een taal, of een vertaaltag, die de installatie niet kent, of waarvan lang het request tegenspreekt, in plaats van het stil te repareren. Twee kleinere reparaties die stil gebeurden zijn ook gestopt: een actieknop met een kale domeinnaam (example.com) of een tel:-link, en een LinkedIn-link zonder https://, worden niet meer getoond; de editor geeft een hint naast het veld zodat je de waarde kunt herstellen. Deckyard is in beta, dus dit komt in een minor-versie.

    Genummerde lijsten nummeren goed

    • Een genummerde lijst die je in de editor typt is één lijst. 1. Eerste, Enter, 2. Tweede typen liet losse alinea’s staan tot je het veld verliet, en een opgeslagen lijst met lege regels tussen de items werd getoond als drie lijsten die elk “1.” zeiden. Enter aan het eind van een regel die met 1. of - begint maakt er nu direct een lijstitem van en opent het volgende, lege regels tussen items splitsen een lijst niet meer, en een lijst die bij 3 begint toont 3. Decks die al in de gesplitste vorm zijn opgeslagen worden zonder aanpassing goed getoond.

    Een .deck-bestand draagt het hele deck

    • Exporteer en importeer een .deck vanuit de app. Het exportmenu heeft onder Data & bundle een .deck-rij, en het nieuw-presentatie-dialoog heeft een tab Import .deck, de standaard. Als iets niet meekwam blijft het dialoog open met de reden en een knop Open presentation; een kapotte bundle geeft een foutmelding bij het bestand.
    • Elke taal, de notities, de timing en de zichtbaarheid reizen mee. De JSON- en .deck-export dragen alle taalversies plus sprekersnotities, duur en zichtbaarheid per slide; een import zet de vertalingen terug als taalversies.
    • Het thema en de eigen slidetypes van het deck reizen ook mee. Een deck op een organisatiethema draagt dat thema: theme.json, de logo’s en de gecureerde Google-fonts als bestanden (Adobe-, Monotype- en geüploade fonts alleen op naam, met de reden erbij). Slidetypes uit Settings > Slide Types die het deck gebruikt gaan mee. Wie thema’s en slidetypes mag beheren ziet één vinkje om ze te installeren, standaard uit; een bestaand thema of type wordt nooit overschreven, een bezette slug krijgt -2. Zonder installeren landt het deck op het standaardthema en importeren die slides als placeholder die zegt dat de definitie in de bundle zit. Exporteren, importeren, exporteren levert byte voor byte dezelfde bundle.
    • Een slide op een eigen database-slidetype komt via JSON weer als zichzelf terug, en zijn vertalingen reizen mee in de JSON- en .deck-export.

    De leesweergave leest als een document

    De leesweergave (/p/…/reader) en de reflowable HTML-export volgen nu de structuur die elk slidetype vastlegt, in plaats van te raden op veldnamen.

    • Lijsten, citaten, kaders en voetregels zijn wat ze zeggen. Een genummerde list-slide is een genummerde lijst met zichtbare nummers; poll- en likert-opties zijn regels, geen tussenkoppen; een citaat is een <blockquote> met naam en functie in een <footer>; notities, tips en waarschuwingen zijn een <aside> met het soortwoord in de taal van het deck; een byline of logonaam is een <figcaption> onder het beeld; de eerste kolom van een tabel is een rijkop voor schermlezers.
    • Copy leest in de taal van het deck. Een callout zonder label wordt naar zijn soort genoemd (“Kernpunt”, “Let op”), ook in de inhoudsopgave, en de datatabel van een chart krijgt een samenvatting in de deck-taal (“Lijndiagram met 5 punten. Min: 25. Max: 85.”), die schermlezers ook op de slide zelf krijgen.
    • Waarden lezen als waarden. Een KPI leest “98%”, een countdown-duur is een <time> (1:30), een likert-slider noemt zijn schaal (1 “Nutteloos” tot 10 “Essentieel”), een actie- of kaartlink springt naar zijn dia (“Dia 3”), een social link is een echte link met het label als tekst, en het e-mailadres van de eindslide is een mailto:.
    • Een custom-HTML-slide leest als zijn inhoud, niet als codeblok met HTML en CSS. De eerste kop in de markup wordt de naam in de inhoudsopgave; inline styles en het CSS-veld blijven op de canvas en vallen in de leesweergave weg.
    • Beelden lezen echt of niet. Een beeld krijgt alleen een echte alt-tekst, expliciet of de naam van een logo of portret, nooit een bijschrift of bestandsnaam; een beeldset of galerij is één figuurgroep met één onderschrift; een decoratieve set verbergt al zijn beelden.
    • Publiceren weigert een betekenisvol beeld zonder alt-tekst, inline naast Publiceren, met slide en veld erbij (API v1: 422 missing_alt met details). Dat was een “toch publiceren”-bevestiging voor twee slidetypes.
    • De geprinte hand-out is de leesprojectie: dezelfde inhoud en structuur, inclusief figuren, kaders en lijsten, in de taal van het deck. De print-wrapper heet nu reader-slide; de oude print-slide en de print-klassen per type zijn weg, dus eigen print-CSS die daarop leunt moet mee.

    Kleinere veranderingen

    • Een beeld kiezen op een installatie met meer dan één bron (bibliotheek, gradiënten, ImageKit) toont per bron een kaart met omschrijving; ImageKit is de primaire keuze, en het achtergrondveld zegt waar het beeld voor is.
    • Elke HTML-uitvoer (presenter, export, embed, print, leesweergave) markeert de slide-wrapper met data-slide-type, de leesweergave markeert elk blok met data-field, en de variant van een callout, lijst of vergelijking en de toon van een matrixcel staan als attribuut, voor wie de HTML met CSS of een script leest.
    • deckyard-mcp --help noemt elke tool en prompt die de server registreert, ook die van een fork, zodat de lijst nooit achterloopt op de code.

    Voor forks en slidetype-auteurs

    • Nieuwe optionele declaraties: markup: true op een code-veld, nameKey op een beeldveld, unitKey, hrefKey, headingKey, duration: { secondsKey }, scale, de veldtypes url en email, orderedWhen, rowHeader: 'first', role: 'aside' met kindKey, role: 'attribution', termWhen, defaultFromOption met copyKey, een datasetSummary-functie en semantic: true op een enum. Zie docs/developer/slide-types.md en docs/reference/reflowable-html-export.md in de core.
    • De .deck-bundle is bundleVersion 3 (docs/reference/deck-bundle.md); een bundle met een onbekende versie wordt geweigerd in plaats van half gelezen. Een importantwoord zegt bundledTheme en bundledSlideTypes als iets meekwam maar niet is geïnstalleerd.

    Geen beveiligingsfixes in deze release. Het aantal ingebouwde slidetypes blijft 35.

    Zie voor de volledige lijst op commitniveau de 1.35.0-release op GitHub.

  5. v1.34.0

    Feature-release

    Eigen slidetypes zijn nu te zien via deellinks, bij meekijken en in de voorbeelden van slidetypes, exports zetten beeldrijen en emoji neer zoals de editor, en de leesexport geeft elke slide een echte kop.

    Een release met één nieuw gedrag voor de leesexport en een reeks fixes voor slidetypes die je eigen installatie toevoegt. Je hoeft niets te doen behalve updaten.

    Eigen slidetypes zijn overal te zien

    Een slidetype dat je installatie zelf toevoegt, of een type uit de slidetype-bouwer, wordt door de server getekend. Op een paar plekken werd die tekening nooit opgevraagd en stond er een lege placeholder.

    • Deellinks, meekijken en de sprekersnotities-weergave tonen die slides nu ook aan kijkers die niet zijn ingelogd. Bij een link met wachtwoord verschijnen ze zodra het wachtwoord is ingevoerd.
    • De instellingen voor slidetypes en de kiezer bij Slide invoegen tonen er een miniatuur van, waar eerst een lege tegel stond.

    Exports kloppen met de editor

    • Beeldblokken met afbeeldingen in hun oorspronkelijke verhouding blijven op één rij in PNG-, PPTX-, PDF- en printexports. Tot nu toe konden vier liggende afbeeldingen over twee rijen vallen en de titel bedekken.
    • Emoji verschijnen in kleur in exports vanuit de Docker-image, in plaats van als lege vakjes.

    Elke slide in de leesexport heeft een kop

    • De zichtbare kop van een sectie is het titelveld van de slide, per slidetype vastgelegd. Een quoteslide maakt van het citaat geen kop meer, en een beeldslide gebruikt de titel, niet het bijschrift.
    • Een slide zonder titel krijgt toch een kop voor schermlezers, vernoemd naar de slide, zodat de structuur van het document compleet blijft. Alleen zichtbare koppen krijgen een nummer.
    • Eigen slidetypes krijgen een zichtbare kop zodra ze vastleggen welk veld de kop is. Zonder dat krijgen ze de verborgen kop.

    Het aantal ingebouwde slidetypes blijft 35.

    Zie voor de volledige lijst op commitniveau de 1.34.0-release op GitHub.

  6. v1.33.5

    Onderhoudsrelease

    Opgeslagen slides in je slidebibliotheek tonen weer hun volledige inhoud, ook slides die zijn bewaard voordat het slideformaat veranderde.

    Een fix voor de slidebibliotheek. Je hoeft niets te doen behalve updaten.

    Oudere opgeslagen slides tonen weer hun inhoud

    • Een slide die in de bibliotheek is bewaard voordat een slidetype van vorm veranderde, toont nu alles wat erin staat. Tot nu toe kon zo’n item alleen titel en subtitel laten zien, bijvoorbeeld een teamslide zonder de mensen, zowel in het voorbeeld in de bibliotheek als na invoegen in een deck.
    • Voeg je zo’n item in, dan krijg je de huidige vorm van de slide, zodat je hem bewerkt als elke andere slide van dat type.
    • Decks waarin zo’n slide al eerder is ingevoegd, krijgen bij het openen de inhoud terug, zolang ze sindsdien niet zijn opgeslagen.

    Het aantal ingebouwde slidetypes blijft 35.

    Zie voor de volledige lijst op commitniveau de 1.33.5-release op GitHub.

  7. v1.33.4

    Onderhoudsrelease

    De "+ Subtitle"-knoppen op een slide werken weer op je eigen slidetypes: een klik maakt het veld aan en zet de cursor erin.

    Een fix voor installaties met eigen slidetypes. Je hoeft niets te doen behalve updaten.

    De ”+“-knoppen op je eigen slidetypes maken het veld weer aan

    • Op een eigen slidetype maakt een klik op ”+ Subtitle”, ”+ Meta” en dergelijke nu dat veld aan en zet de cursor erin. Tot nu toe deed de klik niets op elk slidetype dat je installatie zelf definieert, ook je eigen versie van een ingebouwd type, omdat de slide nog van de server aan het laden was toen de editor het nieuwe veld zocht.
    • Tekstvelden en opgemaakte tekstvelden werken allebei, en getypte tekst blijft na opslaan staan.
    • Klik je ergens anders terwijl de slide nog laadt, dan blijft er niets achter op de slide waar je begon.

    Voor installaties die Deckyard in code uitbreiden: het DOM-event slide-server-rendered bestaat niet meer. Wacht je op een server-gerenderde slide, gebruik dan slideRendered(el) uit client/lib/slide-runtime/slide-render.js; die geeft true zodra de markup erin staat en false als die nooit komt.

    Het aantal ingebouwde slidetypes blijft 35.

    Zie voor de volledige lijst op commitniveau de 1.33.4-release op GitHub.

  8. v1.33.3

    Onderhoudsrelease

    Een gedeeld deck openen blokkeert je collega's niet meer: een slide gaat pas op slot als je er echt iets aan wijzigt, en het slot gaat eraf als je stopt.

    Een fix voor teams die samen in hetzelfde deck werken, met live samen bewerken uit (de standaard). Je hoeft niets te doen behalve updaten.

    Een slide gaat op slot als je hem bewerkt, niet als je ernaar kijkt

    • Een deck openen of door de slides klikken zet niets meer op slot. Tot nu toe hield wie een gedeeld deck als eerste opende slide 1 vast zolang het tabblad openstond, dus iedereen daarna zag “This slide is being edited by someone else” en las dat als “je mag hier niet bewerken”.
    • De eerste wijziging die je aan een slide doet zet hem op slot. De titel of de instellingen van het deck aanpassen doet dat niet.
    • Het slot gaat er vanzelf af: twee minuten na je laatste wijziging, zodra je naar een ander tabblad of venster gaat, en als je naar een andere slide gaat. Wat nog niet was opgeslagen, wordt eerst opgeslagen. Ga je weer typen, dan komt het slot ongemerkt terug.
    • Bewerkt iemand anders de slide, dan blijft jouw wijziging niet staan: je ziet wie hem vasthoudt, en de slide toont weer zijn of haar versie, sprekersnotities inbegrepen.
    • Een slot dat achterbleef door een dichtgeklapte laptop of een gecrasht tabblad blokkeert de slide niet meer tot je herlaadt. Zodra het op de server verlopen is, is de slide binnen een halve minuut weer bewerkbaar.

    Het aantal ingebouwde slidetypes blijft 35.

    Zie voor de volledige lijst op commitniveau de 1.33.3-release op GitHub.

  9. v1.33.2

    Onderhoudsrelease

    Tekst naast een beeld staat in het midden van zijn kolom, zodat een korte titel en alinea in balans zijn met het beeld in plaats van bovenaan te hangen.

    Eén layoutfix, de derde release van vandaag. Je hoeft niets te doen behalve updaten; bestaande slides nemen het vanzelf over.

    Tekst naast een beeld staat verticaal in het midden

    • Op een image-text-slide staat de tekst nu in het verticale midden van zijn kolom: evenveel ruimte boven de titel als onder de laatste regel, de aside meegerekend. Dat geldt voor elke beeldbreedte en met het beeld links of rechts. Korte tekst naast een illustratie laat de onderste helft van de kolom niet meer leeg.
    • De image-set-slide doet hetzelfde in de layout met de beelden ernaast, waar de beelden als stapel naast de tekst staan.
    • Te lange tekst begint nog steeds bovenaan, dus de titel valt nooit van de slide.
    • De corner-layout en de image-set-layouts met een rij beelden houden de tekst bovenaan. Daar hoort de tekst bij het beeld erboven of ernaast, en de open ruimte eronder is onderdeel van het ontwerp.
    • Dit is de standaard, geen nieuwe instelling. Zet je fork in zijn eigen CSS een verticale uitlijning op de tekstkolom, dan blijft die waarde gelden.

    Het aantal ingebouwde slidetypes blijft 35.

    Zie voor de volledige lijst op commitniveau de 1.33.2-release op GitHub.

  10. v1.33.1

    Onderhoudsrelease

    Fullscreen op de gepubliceerde pagina en in de presenter: geen scrollbar, en beide balken komen als overlay terug als je de muis beweegt.

    Eén fix, op dezelfde dag uitgebracht als 1.33.0. Verder is er niets veranderd en hoef je niets te doen behalve updaten. De reden om überhaupt op 1.33.x te zitten staat in 1.33.0.

    Fullscreen vult het scherm

    • Op de gepubliceerde pagina verbergt fullscreen beide balken. Met F bleef de bedieningsrij onder de slide hangen, met een scrollbar om erbij te komen. Nu zijn de titelbalk en de bedieningsrij weg, vult de slide het scherm, en schuiven beide balken als overlay in zodra je de muis beweegt, zonder dat de slide verschuift. Na een paar seconden verdwijnen ze weer.
    • Een venster dat het scherm vult telt ook als fullscreen. De groene knop van Safari en F11 gebruiken de fullscreen-modus van de browser niet, dus de balken bleven staan. De pagina behandelt een schermvullend venster nu hetzelfde.
    • Pijltjestoetsen, spatie en een clicker halen de balken niet terug, dus ze flitsen niet meer bij elke slide in beeld. Met Tab in een balk komen ze wel, en een balk blijft staan zolang de muis erop rust.
    • De presenter volgt dezelfde regels. In fullscreen komt de bovenbalk nu samen met de voortgangsbalk terug, en de slide gebruikt de volle hoogte in plaats van ruimte over te laten voor een balk die verborgen is.
    • ?ui=min is ongewijzigd: daar zijn geen balken, en F werkt er nog steeds.

    Het aantal ingebouwde slidetypes blijft 35.

    Zie voor de volledige lijst op commitniveau de 1.33.1-release op GitHub.

  11. v1.33.0

    Feature-release

    Een nieuw slidetype voor twee of drie beelden, speaker notes en een thema-template in de PowerPoint-export, countdowns die starten als je erop aankomt en lopen op de gepubliceerde pagina, en één breaking change in chartdata.

    Tien dagen werk, grotendeels op twee fronten. De PowerPoint-export neemt meer van het deck mee: speaker notes, en een template dat uit je thema wordt opgebouwd. En de slides waarmee je presenteert kregen een reparatieronde uit het echte gebruik, van countdowns tot een stemstand die wie later aansloot niet te zien kreeg.

    Controleer je charts voordat je update. De eerste rij van de data van een chart is voortaan altijd de kop en wordt nooit geplot. Een opgeslagen chart waarvan de eerste rij data was, leest die rij nu als kolomnamen en verliest hem als punt. Draai node scripts/scan-chart-headers.js (leest Postgres via .env, of deck-JSON met --dir <pad>) en bekijk elke treffer: een jaartallenkop die eerder verkeerd gelezen werd, hoeft niets; data die echt geen kop heeft, krijgt in de grid-editor één koprij erbij. Deckyard is in beta, dus deze breaking change komt in een minor-versie.

    Een nieuw slidetype voor meerdere beelden

    • Beelden + tekst (image-set-slide) zet twee of drie beelden naast, boven of onder de tekst. De layouttegels “Rij boven”, “Rij onder” en “Naast de tekst” wisselen nu naar dit type.
    • image-text-slide is één beeld. Decks die er meerdere beelden op hadden opgeslagen, worden bij het lezen omgezet; er is geen migratie om te draaien. Een API-client die images[], imageFit of textColumns naar dat type schreef, schrijft voortaan een image-set-slide.

    PowerPoint-export

    • Speaker notes gaan mee in het PPTX, als PowerPoint-notities bij elke slide. Eerder kwamen ze alleen apart mee als notes.md of notes.docx in de handoff-zip. Het document staat bovendien op naam van je app.
    • Een nieuwe exportrij, “PPTX template”, downloadt een leeg .pptx met layouts uit het thema van het deck: achtergrond, fonts, tekstkleuren en logo, per slide ingesteld. Het is geen master die een bestaande presentatie herstijlt.

    Charts

    • Balken landen op de rasterlijn die hun waarde noemt. Een staafdiagram gebruikt één as per plot, dus een 7 staat niet meer op de lijn van 8; rasterlijnen van een lijndiagram blijven binnen het plot, en een negatieve balk verschijnt waar hij eerder wegviel.
    • Plakken in de cel linksboven van de grid leest de eerste rij als kolomnamen, en de AI schrijft kale jaartallen weer als serienamen.
    • Live-databindingen en de bronvermelding bij een quote schrijven naar een veld dat ook echt getoond wordt.

    Countdowns en live sessies

    • Een countdown die automatisch start, begint als je op zijn slide aankomt, niet bij het openen van de presentatie. Eerder liepen alle timers in het deck vanaf het moment dat je begon te presenteren. Weggaan van de slide pauzeert hem niet.
    • Countdowns lopen op de gepubliceerde pagina en in de embed, met Start, Pauze en Reset. Eerder bleven ze op hun starttijd staan.
    • De cijfers staan in het midden van de slide, met of zonder titel, in het kopfont en -gewicht van het thema. De preview in de editor flikkert niet meer tussen twee maten.
    • Een scherm of telefoon die midden in een stemming aanhaakt, ziet de stand die er al is in plaats van “Totaal: 0” tot de volgende stem.

    Kleinere reparaties

    • De ImageKit-bibliotheek toont de nieuwste bestanden eerst, ook in de tag-chips. Een grote bibliotheek liet tot nu toe alleen de oudste zestig zien.
    • Een backup-export is compleet: met de auteursfoto’s op quote-slides, zonder call-to-action-links als beeld, en met de uploads als UPLOADS_DIR is ingesteld.
    • Een eigen slidetype uit Instellingen krijgt dezelfde achtergrond-, toegankelijkheids- en logo-instellingen als een ingebouwd type, en is nu aan te maken via de publieke API en de MCP-tools in plaats van te falen met Unknown slide type.
    • De deeldialoog houdt één hoogte terwijl hij laadt. De tegels voor chart, KPI en Likert in de slidekiezer tonen een echt voorbeeld, en een Engelse countdown zegt “Time!”.
    • De leesweergave noemt een KPI-item naar zijn label en toont een videoslide als “Video” met een link in plaats van een video-ID.

    Voor forks en integratoren

    • create_presentation_from_slides weigert een sleutel die het type niet declareert (unknown_field) in plaats van hem te laten vallen, en accepteert elk example uit get_slide_types. update_slide met een type weigert een typewissel die hij niet kan omzetten.
    • Elke slide ontstaat in één fabriek, dus een deck uit een import, de AI of een agent krijgt dezelfde standaardwaarden als een invoeging in de editor, per taal; een pollslide van een agent krijgt nu een pollId.
    • Een slidetype declareert hoe getrouw het exporteert (fidelity: { pptx }); een type uit een bestand zonder die declaratie geeft bij het opstarten een waarschuwing. Zie docs/reference/slide-type-fidelity.md in core.
    • Nieuwe optionele velddeclaraties: itemLabelField op een items-veld, mediaRef op een string-veld, foldUnofferedTo op een enum. Een thema kan de achtergrond declareren waarop zijn slides beginnen (defaultBackground).

    Geen security-fixes in deze release. Het aantal ingebouwde slidetypes gaat van 34 naar 35.

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

  12. v1.32.0

    Onderhoudsrelease

    Een fork die eigen MCP-tools toevoegt, krijgt de storage scope aangereikt die hij nodig heeft, in plaats van vier regels core-logica te kopiëren en te zien verlopen.

    Een release met één item, en dat item is voor wie een fork draait. In de editor, in een presentatie of in een export verandert er niets; draai je Deckyard zoals hij komt, dan is deze update optioneel.

    Voor forks en integratoren

    • De custom-tools-naad reikt storageScopeOf(context) aan. Elke facade onder server/storage/ neemt sinds 1.4.0 een storage scope aan en weigert een kale repoRoot-string, maar de enige bouwer van die scope zat binnen core en stak de registerCustom-naad nooit over. Een fork-tool die storage wilde bereiken, kon dus ctx.repoRoot doorgeven en falen voor elke caller met een sleutel, of de logica van core naar de fork kopiëren en bij de volgende merge opnieuw kopiëren. storageScopeOf staat nu op de ctx van de naad, naast repoRoot en niet in plaats daarvan: repoRoot blijft het schijfpad voor thema’s en uploads, het is alleen geen storage-argument. De docs/reference/mcp-server.md van core laat de aanroep zien.

    Geen breaking changes en geen security-fixes in deze release. Het aantal ingebouwde slidetypes blijft 34.

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

  13. v1.31.0

    Feature-release

    Een thema kan een licht en een donker logo meegeven en Deckyard kiest per slide de zichtbare; en een vertaling die sinds mei de verkeerde slide toonde, wordt door een migratie hersteld.

    Twee dagen na 1.30.0, een release over dingen die een deck van zichzelf weet. Een thema kan nu meer dan één logo meegeven en Deckyard laten bepalen welke leesbaar is op de slide in kwestie. De beeldbibliotheek opent op het uploaden en niet op het raster. En een vertaling die in mei stilletjes achterbleef bij zijn bron, komt weer in de pas.

    Draai npm run migrate na het bijwerken. Migratie 081 brengt het schema van 12 naar 13 en herstelt taalversies die een migratie uit mei oversloeg: een vertaling die een archived slide toont waar de hoofdtaal een tijdlijn heeft, is weer een tijdlijn. Decks worden ook op elke read hersteld, dus er blijft intussen niets kapot, maar de migratie is wat het vastlegt.

    Een thema kan twee logo’s meegeven

    • logoOnDark en logoOnLight naast assets.logo, plus titleLogoOn* voor de titelslide. Deckyard leest de ondergrond van de slide zelf - achtergrondkleur, of een achtergrondfoto - en zet daar de mark neer die er zichtbaar is. Een thema met één mark gedraagt zich precies als voorheen, dus dit kost je niets tot je het wilt.

    De beeldbibliotheek en de slides

    • De picker begint bij het uploaden. De dropzone en het URL-veld staan bovenaan op één rij, met het raster eronder. Een URL die je plakt, schuift niet meer onder je vingers weg.
    • Een kaart over een foto krijgt een echte scrim. Tekst op een card-stack over een achtergrondbeeld lag op een glazige tint; die heeft nu een scrim die hem leesbaar maakt.

    Vertalingen komen bij

    • Elke taalversie migreert, niet alleen de dominante. De migratie uit mei raakte de bron aan en liet de vertalingen staan; daarom kon één taal een archived slide tonen waar de andere een tijdlijn hebben. Migratie 081 herstelt het opgeslagen deck, en een read repareert het in de tussentijd.
    • Een oude slidetype-naam wordt op elke read herschreven. Een deck dat nog een teruggetrokken typenaam draagt, laadt zonder dat iemand een script hoeft te starten, op elke backend en in elke taalversie.
    • De vertaalprompt behandelt een ongedeclareerde tekstsleutel als proza. Zo’n veld werd overgeslagen; het wordt nu in elke taal vertaald.

    Kleiner herstelwerk

    • De standaardtaal voor e-mail in de instellingen rolt terug naar wat de server heeft als het opslaan mislukt, in plaats van een waarde te tonen die nooit is bewaard.
    • OpenAI-compatibele providers krijgen het tokenbudget van de aanroeper, zodat een lange generatie niet meer op een vaste standaard wordt afgeknipt.

    Voor forks en integratoren

    • err.details heeft per foutcode een vaste vorm. Een API-consument kan op code schakelen en weet welke velden details draagt.
    • In MCP hoort de gate van een tool bij zijn naam. Een fork-registrar die een core-tool alleen omwikkelt, houdt de permission en de readOnly-vlag van die tool in plaats van ze te laten vallen. Een expliciete permission: null op een gegate tool gooit nu bij het opstarten in plaats van hem stil open te zetten. Dit raakt je alleen met een eigen custom/mcp-tools.js.
    • Er breekt niets: geen breaking change en geen security-fix in deze release.

    Het aantal ingebouwde slidetypes blijft 34.

    Voor de volledige lijst op commitniveau, zie de 1.31.0-release op GitHub.

  14. v1.30.0

    Feature-release

    Elke weigering in Deckyard verschijnt nu op de plek waar hij ontstond - bij het veld, naast de knop, waar de rijen hadden gestaan - en alt-tekst in de beeldbibliotheek volgt de talen van het deck zelf.

    Een kleine release, drie dagen werk aan één idee: een melding over iets wat jij nog moet herstellen hoort geen toast te zijn die verdwijnt terwijl je hem leest. 1.29.0 begon daarmee bij de opslaan-knop; 1.30.0 maakt het af in de editor, de instellingenschermen en de inlogpagina’s. En de beeldbibliotheek gaat er niet langer van uit dat jouw deck Nederlands en Engels is.

    Er is geen reden om hier haast mee te maken. Deze release repareert niets wat in 1.29.0 stuk is, en voor een fork verandert er geen vorm.

    Een weigering blijft staan waar je hem veroorzaakte

    • Een formulier dat nee zegt, zegt dat bij het veld. Een lege naam, een ongeldige kleur, het verkeerde bestandstype: de melding staat bij het veld, met de focus erop, in plaats van in een hoek van het scherm.
    • Een API die een opslag weigert, zegt dat naast de Save-knop. Instellingen-tabs, e-mailtemplates, de font- en thema-editor en het opslaan in de bibliotheek houden de weigering zichtbaar tot je volgende poging, zodat je hem kunt lezen terwijl je herstelt wat hij noemt.
    • Inloggen, wachtwoord resetten, een gedeeld deck openen en als gast binnenkomen doen hetzelfde. Dit waren de laatste schermen die nog een toast gebruikten voor iets waar de lezer wat mee moet.
    • Een lijst die niet laadt, zegt dat op zijn eigen plek. De deel-modal, de reacties, de prullenbak en de slide-bibliotheek tonen de fout waar de rijen hadden gestaan, en stelen daarvoor je focus niet.

    Alt-tekst volgt de talen van het deck

    • Eén alt-tekstveld per taal die het deck heeft, in het beelddetail én bij het uploaden, in plaats van een vast paar Nederlands en Engels. De AI-generator vult precies die talen, en een gekozen beeld zaait elke taalbuffer in plaats van één.

    Voor forks en integratoren

    • Er breekt niets. createInlineError() en de doctrine in docs/reference/feedback-surfaces.md zijn nu de enige manier om een weigering te tonen, en een guard-test weigert een zelfgeschreven *-error-klasse. Dit raakt je alleen als je fork eigen editor-panelen meelevert.

    Het aantal ingebouwde slidetypes blijft 34.

    Voor de volledige lijst op commitniveau, zie de 1.30.0-release op GitHub.

  15. v1.29.0

    Feature-release

    Een deck heeft geen twee talen meer maar een lijst, waarin elke taal een versie is die je bewerkt, presenteert en deelt; en elke embed sinds 1.0.0 negeerde zijn eigen instellingen, wat deze release herstelt.

    Dit is de release waarin een deck ophoudt “de Nederlandse of de Engelse” te zijn en een deck met een lijst taalversies wordt. Eén menu in de editor-topbalk laat zien welke versie je bewerkt, welke andere versies er zijn, en hoe ver elke versie vertaald is. Het is ook de release die de embed repareert: de instellingen die je aan een ingesloten deck meegeeft, kwamen sinds 1.0.0 niet aan.

    Neem deze update als je ergens een embed hebt draaien. De boot-payload die de embedpagina aan de speler doorgeeft, ging via HTML-escaping een raw-text scriptblok in en parste dus nooit, waardoor elke embed op standaardwaarden terugviel. Slideteller, taalwissel, start, loop, ui en een ingestelde allowedOrigins-lijst doen nu wat jij hebt ingesteld. Een lege origin-lijst laat nog steeds alle origins toe, zoals gedocumenteerd.

    Neem hem ook als je de MCP-server aan hebt staan. Een aanroep over SSE is nu gescopet op de organisatie van de API-sleutel waarmee hij zich aanmeldde, en toolaanroepen worden getoetst aan de rechten en het quotum van die sleutel.

    De talen van een deck zijn een lijst

    • Eén taalmenu, één versie per taal. Het vaste paar NL|EN in de editor-topbalk is weg. Daarvoor in de plaats noemt één knop de versie die je bewerkt, in de eigen taal (“Nederlands”), en opent op elke versie die het deck heeft plus de talen die je kunt toevoegen. Een deck met één taal toont één regel; een deck met vijf toont er vijf.
    • De bronversie blijft staan terwijl je een vertaling bewerkt. Overschakelen naar een vertaling schuift de bron van het deck niet meer onder je vandaan, en je kunt vanuit hetzelfde menu een andere versie tot bron maken zodra die de versie is die je bijhoudt.
    • De vertaalmodals noemen hun bron en doel, zodat je vóór het starten ziet welke richting je op gaat, en per taal krijg je een vertaalvoortgang die uit het deck zelf volgt in plaats van uit een schatting.
    • Geneste itemteksten worden nu ook vertaald. Tekstblokken met rijen van blokken (rows[].blocks[]) sloeg de vertaler over, waardoor ze in de brontaal terugkwamen.

    De viewer en de volgcodes volgen de versies

    • /p/ en de embed tonen één taalknop per bestaande versie, in plaats van een vast paar dat een taal kon aanbieden die het deck niet heeft.
    • Een sessie munt één volgcode per versie, zodat iemand die in zijn eigen taal meekijkt, ook in die taal binnenkomt.
    • De presentatorconsole rendert de thumbnail van de volgende slide in de decktaal, waar die eerder de interfacetaal aanhield.

    Nieuw op een slide

    • callout-slide, de admonition-familie. Note, tip, warning en de rest, als eigen slidetype.
    • Vergelijkingsslides hebben subvarianten: versus, before-after, pros-cons en tradeoff, zodat de opmaak volgt wat je werkelijk vergelijkt.
    • Aside-insets zetten een contrastblok binnen een slide, op de tekst-, lijst- en beeld-met-tekst-types, zonder dat er een aparte slide voor nodig is.
    • De titelslide heeft een eigen typografische trede (een maat boven de rest van de schaal), en de cover stapt vanzelf een maat terug als de tekst niet past, in plaats van eruit te lopen.

    Herstelwerk dat je merkt

    • Deck-thumbnails laden weer, en ze zijn content-addressed: een deck dat je zojuist wijzigde toont een actuele thumb en niet een oude uit de cache.
    • Een geweigerde opslag zegt welk veld weigerde, naast de knop die weigerde, met de focus op dat veld. Lokale formulierweigeringen staan nu inline bij het veld en niet in een toast die verdwijnt terwijl je hem leest.
    • Een fout klinkt als een fout. Een foutmelding wordt als zodanig aan een schermlezer doorgegeven, Escape sluit een melding, en een melding met een knop blijft staan tot je die knop hebt gebruikt.

    Voor forks en integraties

    • ⚠ Twee CSS-klassen hernoemd. .slide-title-universal wordt .slide-title en .slide-lijstje wordt .slide-list op het titel- en lijsttype, en .sfi-card-kicker wordt .sfi-card-title op het feedback- en follow-invite-type. De eigen stylesheets van Deckyard en de kernthema’s gaan mee; alleen een fork met eigen regels op de oude namen moet hernoemen. De families tsu-* en .lijst* blijven ongewijzigd. Deckyard blijft op 1.x zolang de bètabadge er staat, dus een minor-release met breaking changes is de bedoelde vorm en geen fout.
    • Definities van eigen slidetypes worden gevalideerd, en scaffold schrijft alleen definities die daar doorheen komen. Een slidetype uit de database krijgt zijn CSS gescopet op de eigen root, er is een vastgelegde scoping-conventie voor JS-types uit bestanden, en een gedeelde partials-bibliotheek voor eyebrows, badges en highlights.
    • Een ingelogde maar onbevoegde API-aanroep krijgt 403 in plaats van 404. Een weigering uit de opslag draagt nu details met field, index, itemIndex en reason, zodat een client kan aanwijzen wat er mis was.

    Het aantal ingebouwde slidetypes gaat van 33 naar 34 met callout-slide.

    Voor de volledige lijst op commitniveau, zie de 1.29.0-release op GitHub.

  16. v1.28.0

    Feature-release

    Eén commando rendert je thema over elk slidetype op één vel, Companion heet in alle twaalf talen hetzelfde, en het migratiescript voor achtergronden werkt eindelijk op Postgres.

    De derde release van de dag, en de enige met iets nieuws erin: een contactvel voor thema’s. Beheer je een thema, dan rendert npm run theme:preview <thema-id> nu elk slidetype tegen elke achtergrond die dat thema aanbiedt, op één HTML-pagina die je kunt doorscrollen. Zo ontdek jij waar een thema stukgaat, en niet je publiek.

    Een heel thema in één oogopslag

    • npm run theme:preview <thema-id> schrijft een contactvel. Eén tegel per combinatie van slidetype en achtergrond, gegroepeerd per type, plus een contrasttabel voor de vlakke achtergrondvarianten van het thema. Tot nu toe was de enige voorvertoning die van de themabewerker, die een databaseconcept over een handjevol types rendert; een fork die zijn huisstijl als bestandsthema in custom/themes/ versiebeheert had helemaal geen voorvertoning, en niemand zag wat een thema deed met de ruim dertig types die het paneel weglaat.
    • Een tegel is wat een export oplevert. Elke tegel gaat door hetzelfde renderpad als een PDF- of PNG-export, in plaats van een gelijkende namaak die de regressies zou blijven doorlaten waarvoor het vel bestaat. Er is geen draaiende server en geen database voor nodig.
    • Het vel loopt de matrix af die de editor aanbiedt, inclusief de achtergronden die een thema bovenop de eigen achtergronden van een slidetype legt, en het slaat een themagebonden type over onder een thema dat het niet kan gebruiken. De contrasttabel scoort wat eerlijk meetbaar is: een variant op een vlakke of gradiëntgrond krijgt een verhouding, artwork-gronden worden gemeld als niet gemeten in plaats van gescoord als een fout die ze niet hebben.

    Vertalingen kiezen één woord

    • “Companion” is in alle twaalf talen één productnaam. Negen talen hadden het vertaald - “Följevy”, “Begleitansicht”, “Acompañante”, “Compagnon”, “Asystent” en de rest - waardoor dezelfde weergave per taal op een andere functie leek. Het kernwoord is nu overal het leenwoord, terwijl de bepaling vertaald blijft, dus het Duits leest “Publikums-Companion” en het Frans “Companion du public”.
    • Het Italiaans spreekt je overal informeel aan. De taal stond al ongeveer twee op één in de tu-vorm, maar een eerdere ronde had de klikwerkwoorden naar het formele Lei geduwd (“Faccia clic”); ongeveer 260 strings lezen nu als één register, inclusief beleefdheidsbezittelijken en clitica. Een paar Italiaanse termen zijn tegelijk vastgelegd, waaronder de follow-along-uitnodiging, die het leenwoord gebruikt zoals het Engels en het Nederlands dat doen.
    • Het Pools en het Fins krijgen een handvol herschrijvingen waar de eerdere ronde iets leesbaars maar niet idiomatisch had achtergelaten. Sleutelverzamelingen, sleutelvolgorde en plaatshouders blijven in alle 27 bestanden ongemoeid; alleen de woorden veranderden.

    Voor wie zelf host

    • De migratie van oude achtergrondafbeeldingen werkt op Postgres en neemt taalversies mee. Het script liep één map met deck-JSON af, dus een Postgres-installatie migreerde niets en meldde een keurige nul, en de vertaalde versies van een deck werden in beide opslagvormen overgeslagen - in één productiedataset zaten daar meer oude slides dan in de decks zelf. Het accepteert nu --backend auto|file|postgres|both en loopt decks, taalversies en bibliotheekitems per constructie af. Draaide je de migratie eerder op een bestandsopslag, dan hoef je niets te doen; sloeg je ‘m over, dan werkt hij nu in beide opstellingen. Versiemomentopnamen blijven met rust tenzij je --include-versions meegeeft, want die vouw is verliesgevend en oude inhoud rendert toch correct tot de eerste bewerking na een herstel.

    Het aantal ingebouwde slidetypes blijft 33.

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

  17. v1.27.2

    Onderhoudsrelease

    Een thema dat je uitzette is nu echt uit in elke kiezer, het beeldenveld springt niet meer weg onder je cursor, en een handvol Engelse labels kiest één spelling.

    Drie reparaties, dezelfde dag geknipt als 1.27.1. De belangrijkste is de thema-allowlist: die stond gedocumenteerd als de zichtbare deelverzameling van thema’s, maar gedroeg zich als een etiket, zodat een thema dat je had teruggetrokken nog steeds bereikbaar was vanuit twee van de drie kiezers die er een aanbieden.

    Een teruggetrokken thema is ook echt weg

    • De enabledThemes-allowlist wordt server-side afgedwongen, in elke kiezer. GET /api/themes gaf eerst elk thema terug en merkte de thema’s buiten de allowlist als uitgeschakeld; alleen het aanmaakraster las dat merkteken, en een schakelaar “Toon alle thema’s” maakte het met één klik ongedaan. De themakeuze in de deckinstellingen en de rij “begin met een thema” op Home negeerden het volledig. Het endpoint filtert nu, dus geen enkele kiezer kan aanbieden wat de allowlist weglaat, en de zachte schakelaar is verdwenen.
    • Een deck dat ouder is dan de terugtrekking houdt zijn eigen thema. De kiezers geven het thema mee waar het deck op staat, en het opgeloste standaardthema blijft altijd in de lijst, zodat een organisatie zichzelf niet buiten het thema kan sluiten waarmee haar eigen nieuwe decks worden gemaakt.
    • Thema’s die je beheert blijven zichtbaar waar je ze beheert. Het instellingentabblad Thema’s vraagt om de ongefilterde lijst, want het kan geen vinkje aanbieden voor een thema dat het niet mag zien, en de vinkjes lezen nu de allowlist die daadwerkelijk geldt.
    • Nieuwe omgevingsvariabele ENABLED_THEMES, naast DEFAULT_THEME en met dezelfde volgorde: de app-instelling wint, dan de kommagescheiden variabele, dan helemaal geen allowlist.

    Opgelost

    • De lijst “Geselecteerde afbeeldingen” ververst ter plekke. Een vinkje aanzetten in een beeldenveld schreef de waarde weg, maar de lijst bleef de vorige tonen, en de twee paden die wél opnieuw tekenden bouwden het hele formulier op, waarmee de focus van het vinkje verdween dat je net had gebruikt. De lijst werkt zich nu ter plekke bij, en een selectie die over het maximum van het veld heen loopt zet het vinkje uit van de afbeelding die afviel, in plaats van ‘m geselecteerd te laten lijken.
    • Eén Engels per label. Vier sleutels droegen een ander Engels in het slidetype-register dan in de interface: “Centre label” tegenover “Center label”, een “Title (optional)” voor een veld dat sowieso niet als optioneel wordt gemarkeerd, een Nederlands voorbeeld in een Engelse hulptekst, en een paar aria-labels die hun eigen label herhaalden. Ze zijn het nu eens, wat betekent dat een paar Engelse labels in de inspector net anders lezen dan in 1.27.1; het Nederlands en de tien andere talen blijven zoals ze waren.

    Het aantal ingebouwde slidetypes blijft 33.

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

  18. v1.27.1

    Beveiligingsrelease

    Een thema kan de PDF-export niet meer het netwerk op sturen, een tweetalig deck houdt beide talen vast bij een samenwerkbewerking, de foto-achtergrond van een themavariant haalt de PDF, en de editor toont één achtergrondregelaar per slide.

    Een patchrelease vol reparaties, en één ervan gaat over werk niet kwijtraken. Een tweetalig deck met een text-blocks-slide kon stilletjes zijn tweede taal verliezen zodra iemand het in een samenwerksessie opende; dat is opgelost, samen met een PDF-export die thema-artwork liet vallen en een inspector die dezelfde achtergrondkiezer twee keer toonde.

    Neem deze update als iemand anders dan jij een thema kan bewerken. Een externe URL in een themavariabele bereikte tijdens een PDF-export headless Chrome, waarmee vrije CSS in de themabewerker een route werd voor server-side request forgery naar alles wat je exporthost kan bereiken. De export haalt externe URL’s nu uit themawaarden voordat het document wordt gerenderd.

    En neem ‘m vóór de volgende samenwerkbewerking als je tweetalige decks bewaart. De dominante taal werd bij een rondgang in beide versies geschreven, en niets waarschuwde je.

    Tweetalige decks overleven samenwerking

    • Verborgen proza is nog steeds proza. De samenwerkcodec behandelde elk verborgen veld als één machinewaarde die talen delen, maar de text-blocks-slide bewaart 38 verborgen spiegels van door mensen geschreven tekst, dus een rondgang vouwde ze samen tot één taal. Acht modules hielden er elf net verschillende opvattingen op na over wat vertaalbare tekst is; ze delen nu één definitie - een veld is tekst als zijn type dat zegt, op elk nestniveau - en de spiegels vertalen als het proza dat ze zijn.

    Exports renderen het artwork van het thema, en alleen dat

    • De beeldachtergrond van een themavariant komt aan in de PDF. Twee losstaande fouten maakten hem leeg: een lokale beeld-URL in een themavariabele ging nooit door de inbedpas die elk ander beeld neemt, en de gradiëntrasterizer plette een foto met leesbaarheidswaas tot zijn terugvalkleur. Goed in de editor, leeg in de export - nu in beide hetzelfde.
    • Themawaarden kunnen de export niet het netwerk op sturen. Dezelfde pas haalt nu elke externe URL uit themavariabelen voordat het document headless Chrome bereikt, en sluit daarmee een route voor server-side request forgery via vrije CSS in de themabewerker.
    • Twee sluimerende exportfouten gingen mee: een klassennaam die als deeltekst matchte en gradiënten als pixel-voor-pixel-arcering de PDF in duwde - seconden per pagina - en een stylesheetvolgorde waardoor het basisthema alleen in exports de eigen tekstkleur van een variant oversloeg.

    Een donkere achtergrond krijgt leesbare voorgrond

    • Een achtergrondvariant verklaart nu hoe donker zijn grond is. Wie de tekstkleur van een variant instelt, zegt dat al; de slide draagt nu dezelfde contrastklasse die het beeldachtergrondpad afgeeft, zodat behandelingen per slidetype op de helderheid selecteren in plaats van achtergrondnamen te herkennen. Een donkere variant levert geen witte kaarten met witte tekst meer op.

    Eén achtergrondregelaar per slide

    • De dubbele kiezer “Achtergrondafbeelding” is weg. Een half afgemaakte samenvoeging vouwde het oude beeldveldenpaar per type alleen voor één slidetype in de gedeelde regelaar; elk type dat de ontwikkelaarsdocumentatie volgde kreeg ze allebei. De vouw draait nu voor elk type, heelt een opgeslagen deck bij de eerste bewerking, en een achtergrond wissen zaait niet stilletjes de foto terug die je net weghaalde.

    De editor spreekt overal je taal

    • Keuzeopties en gedeelde veldlabels zijn vertaald in alle twaalf talen. Zesenzestig optielabels en de achttien gedeelde veldlabels - de knopvelden, tekstgrootte, het sluitgedrag van poll en schaal, de uitlijnregelaars - toonden rauw Engels in elke taal; ze dragen nu de woorden die elke taal elders in de interface al gebruikt.

    Het aantal ingebouwde slidetypes blijft 33.

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

  19. v1.27.0

    Beveiligingsrelease

    Een instance-beheerder heeft geen stille macht meer in een werkruimte waar hij alleen lid is: de server scopet de vijf resterende omwegen nu naar de actieve organisatie.

    Draai je Deckyard met meer dan één organisatie, dan is dit een release om te nemen. Een instance-beheerder die overschakelde naar een werkruimte waar zijn lidmaatschap “lid” zegt, hield zes mogelijkheden die de interface hem al niet meer aanbood, want de server volgde de client nooit. Die zijn nu dicht.

    Neem deze update als je met meerdere organisaties werkt. In een instance met één werkruimte verandert er niets: de regel valt terug op de controle die hij altijd al deed.

    De macht van een beheerder stopt bij de grens van de werkruimte

    • De server scopet de vijf resterende beheerdersomwegen naar de actieve organisatie. De vorige release verborg tien beheerdersknoppen die de instance-brede rol lazen in plaats van de rol in de werkruimte waar je daadwerkelijk in zit, maar de verzoeken erachter slaagden nog steeds. In die werkruimte kon een instance-beheerder een publieksvraag verwijderen, een beeld uit de bibliotheek weggooien, andermans reacties oplossen en bewerken, de zichtbaarheid van elk deck wijzigen inclusief van organisatie naar privé, en slides vergrendelen of ontgrendelen op een deck dat hij niet had gemaakt. Alle zes controles vragen nu of je beheerder bent van de organisatie waar je in zit.
    • De tien knoppen in de client volgen de actieve werkruimte ook, dus de knop en het verzoek erachter beantwoorden eindelijk dezelfde vraag. Een geweigerde bevoegdheid rendert bovendien als een gewone weigering in plaats van een kop “Er ging iets mis” boven een stacktrace.
    • De voorbeeldweergave van e-mailsjablonen rendert in een gesandboxte frame. Door een beheerder geschreven opmaak met ingevulde velden werd rechtstreeks in de instellingenpagina geschreven, in dezelfde origin als je sessie. Het was nooit een rechtenescalatie, want schrijver en lezer hebben dezelfde bevoegdheid, maar het was de laatste plek waar dat argument iets overeind hield. Meegenomen: de voorbeeldweergave toont nu de echte mail, want de omhulling met het lettertype, de kleur en de breedte van 600 pixels van de mail zelf werd onderweg weggegooid, waardoor je de opmaak van de instellingenpagina zat te bekijken.

    Opgelost

    • ?limit=abc leegt de pagina niet meer. De publieke v1-API had een eigen kopie van de paginatieparser zonder controle op een waarde die geen getal is, dus een onzinnige limiet leverde een leeg resultaat op en een null als limiet in de envelop. Beide kopieën zijn nu één functie, die terugvalt op de standaardwaarde.
    • Alle drie de Q&A-weergaven lezen hetzelfde veld. De volgpagina, het notitiepaneel van de presentator en de moderatieroute hadden elk een eigen kopie van de vragenlijst, en die waren uit elkaar gelopen op het veld dat de tekst van de vraag draagt. Ze zijn het vandaag eens, dus er was niets zichtbaar mis, maar de moderator was één schemawijziging verwijderd van het verwijderen van een vraag waarvan hij de tekst nooit had gezien. Er is nu één accessor, één feed en één set mutaties.
    • en/ is weer een superset van elke locale. Tweeënzestig keys bestonden alleen in het Nederlands, en de globale slidevelden hadden een aparte key per slidetype in plaats van één gedeelde key per veld. Beide zijn opgelost en vertaald naar alle tien de aanvullende talen, samen met een tekstronde door zes daarvan.

    Breaking, voor wie meebouwt

    Deckyard blijft op 1.x zolang de betabadge erop staat, dus een minor release met breaking changes is de bedoelde vorm en geen vergissing. Deze twee raken de vertaalscripts in de repository, niet een draaiende instance:

    • npm run i18n:validate bestaat niet meer. Elke controle die het deed is nu een test.
    • De i18n-scripts delen één vlagvocabulaire. --dry-run en --report en het kale taalargument zijn vervangen door --apply en --json, met lezen als standaard, zodat een script alleen schrijft als je dat zegt.

    Het aantal ingebouwde slidetypes blijft 33.

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

  20. v1.26.0

    Feature-release

    De interface is nu compleet in twaalf talen, en een poll of schaal bewaart zijn antwoorden in één array in plaats van tien genummerde velden.

    Deckyard leverde tien vertalingen die maar half vertaald waren: de taal was te kiezen, maar ergens tussen een derde en twee derde van elk scherm viel terug op het Engels. Alle tien zijn nu af, dus de interface is compleet in twaalf talen. Daarnaast zijn de laatste genummerde velden uit het deckformaat verdwenen.

    Schrijf je decks via de API of MCP in plaats van via de editor, dan is de poll- en likertwijziging hieronder degene om te lezen; bestaande decks migreren vanzelf.

    De interface is compleet in twaalf talen

    • Duits, Frans, Spaans, Portugees, Italiaans, Pools, Fins, Deens, Zweeds en Noors zijn af. Elk ging van zo’n 1.200 keys, met de rest terugvallend op het Engels, naar de volle set van ongeveer 3.400. Engels en Nederlands waren al compleet, dus twaalf talen tonen nu elk scherm in de taal die je koos, niet alleen de menu’s.

    Polls en schalen bewaren hun antwoorden in één lijst

    • De antwoorden van een poll en de punten van een schaal zijn één options-array. Het waren option1 tot en met option4 op een poll en option1 tot en met option10 op een likertslide, de laatste genummerde veldfamilie in het formaat. Schemastap v8 naar v9 vouwt ze elk samen tot één lijst van { text }-items. Bestaande decks migreren automatisch, en al uitgebrachte stemmen blijven wijzen naar het antwoord waarop ze zijn uitgebracht. Genereer je decks via de API, MCP of de AI-catalogus, schrijf dan voortaan options: [{ text: '...' }].
    • Een antwoord leegmaken tijdens een lopende poll verlegt de stemmen niet meer. Omdat de genummerde vorm gaten kon hebben, telden beide lezers stemmen tegen de ingedikte lijst, dus het tweede antwoord van een lopende poll leegmaken verschoof stilletjes elke stem die op het derde was uitgebracht. Een echte lijst heeft geen gaten, dus dit gebeurt niet meer.
    • Een schaal leest als een geordende lijst, een poll als een ongeordende, in de leesweergave en in exports, want de likertarray verklaart dat zijn volgorde betekenis draagt.

    De leesweergave projecteert structuur, geen configuratie

    • Tabel- en datasetslides volgen hun structuurcontract. Een bijschrift beslaat de sectie in plaats van de breedte van de tabel, en een markdowncel rendert inline in plaats van in een eigen alinea.
    • Configuratie verscheen niet langer als proza. Een iconnaam, een id uit de mediabibliotheek, de doelslide van een poll en een blok zoomcoördinaten zijn allemaal tekenreeksen, dus de leesweergave drukte ze af als tekst. Een veld verklaart nu zelf of het leesbare tekst is. Het zichtbare effect: een raster met iconkaarten had “rocket” als kop in plaats van de eigen titel.
    • Alt-tekst wordt niet meer twee keer gezegd. Het beeld van een item vouwt nu in zijn eigen figuur, zoals beelden op slideniveau altijd al deden, dus de alt-tekst van een teamkaart is de beschrijving van de foto en niet ook de kop van de kaart.

    Opgelost

    • Een deck met een eigen slidetype bewaart weer. De bouwer in de instellingen zet een eigen type in de database, maar het opslagpad controleerde slides tegen de bestandsgebaseerde registry, waar een databaserij nooit in kan staan. De editor voegde de slide dus gewoon toe en elke autosave erna antwoordde 400, waardoor het deck onbewaarbaar was tot je de slide verwijderde. Opslaan valideert nu tegen de registry van de organisatie zelf, dezelfde die de viewers en exports al lazen.
    • Het images-veld is af als uitbreidingspunt, zodat de eigen slidetypes van een fork het meervoudige beeldveld kunnen gebruiken; het dode alt-pad is weg.

    Het aantal ingebouwde slidetypes blijft 33.

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

  21. v1.25.0

    Feature-release

    Een deellink werkt eindelijk voor de mensen voor wie hij bestaat: wie geen account heeft krijgt het deck, het thema erbij, en een antwoord als de verificatie mislukt.

    Het hele publiek van een deellink bestaat uit mensen die niet ingelogd zijn, en voor hen was de viewer op drie manieren tegelijk stuk. Deze release repareert ze alle drie, en zet een CSP-header op de app-shell zelf.

    Stuur je deellinks naar mensen buiten je organisatie, neem deze update dan. Een anonieme bezoeker met een volstrekt geldige link kreeg “Presentatie laden mislukt”.

    • Het deck laadt. De viewer haalde het op via een route die op id wordt aangesproken en achter de inlogpoort zit, dus wie geen account had kreeg een 401. Het rijdt nu mee op de ene aanroep die de link bewijst, POST /api/share/:token/verify, en dat is meteen de enige plek waar een wachtwoord gecontroleerd kan worden. Slides die voor kijkers verborgen zijn verlaten de server nooit, en eigenaarsstempels, organisatie en zichtbaarheid ook niet.
    • Het eigen thema van het deck komt mee. Een eigen thema is een databaserij die via een route achter de inlogpoort wordt opgelost, dus elk anoniem oppervlak liep daar tegen een 401 aan, slikte die in en rendeerde het deck op een neutraal terugvalthema: stilletjes zonder huisstijl. Het thema reist nu mee op de payload waar de bevoegdheid al voor is verleend, en dat dekt de deellinkviewer, het meekijkende publiek en de notitiecompagnon. Ingebouwde thema’s zijn statische bestanden die de client zelf laadt.
    • Een mislukte verificatie zegt iets. Een gast van wie de verificatielink faalde werd teruggestuurd en kreeg helemaal niets te zien. Er is nu een banner tussen de deckchrome en de slide, want de link is geldig en het deck is leesbaar; alleen de identiteitsstap mislukte. Hij draagt de knop om een nieuwe link aan te vragen in plaats van te beschrijven waar die te vinden is. Eén geval krijgt zijn eigen antwoord: een verificatietoken is na één gebruik op, dus wie dezelfde mail twee keer aanklikt terwijl hij al een lopende sessie heeft, krijgt te horen wat er gebeurde en verder niets, in plaats van het advies een link aan te vragen die hij niet nodig heeft.

    Typografie schaalt met de slide

    • De typografische schaal van een slide volgt uit de slide zelf. Het waren tien letterlijke pixelwaarden, en de themavermenigvuldiger die het commentaar erboven aankondigde was nooit gebouwd. Elke stap is nu een aantal referentiepixels dat door de breedte van de slide een lengte wordt, en --t-slide-text-scale werkt. Op het referentiedoek van 1600x900, wat vandaag elk pad is, komt elke stap precies uit op de waarde die hij had; op elk ander formaat is hij evenredig.

    Beveiliging

    • De app-shell stuurt een CSP-header, waarmee het werk af is dat de vorige twee releases voor de renderpaden deden.

    Opgelost

    • Plakken onder een bovenliggende slide landt achter zijn kinderen, niet ertussen. De nesting rendeerde goed, maar de deckvolgorde raakte verweven, dus de nummering las 1 Ouder, 3 Kind, 4 Kind, 2 Geplakt. Dupliceren via het menu in de formulierkop had dezelfde fout.
    • De foutteksten bij deelname als gast hangen aan de machinecode, en de dubbele e-mailcontrole is weg.
    • De auth-omweg voor ontwikkelaars gebruikt een geldig adres (dev@local.test).

    Het aantal ingebouwde slidetypes blijft 33.

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

  22. v1.24.0

    Beveiligingsrelease

    Lead capture is met wortel en tak verwijderd, de CSP wordt een echte header op gepubliceerde pagina's en embeds, en 21 API-foutcodes vallen samen tot één.

    Het slidetype lead capture is weg, samen met alles wat eraan hing. Het was een formulier dat je op een slide kon zetten maar nooit kon versturen: de marketingtoestemming waar het op wachtte is nooit aangesloten, dus het verzamelde niets. De betahouding van Deckyard zegt dat een half gebouwde functie gestript wordt in plaats van geparkeerd, en het plan om bezoekersgegevens fatsoenlijk te verzamelen vervangt de code straks in plaats van hem te bewaren.

    Het aantal ingebouwde slidetypes gaat van 34 naar 33. Een deck met een opgeslagen lead-capture-slide laadt, presenteert en exporteert nog gewoon; de slide rendert als gearchiveerde placeholder die het type noemt en elk veld zichtbaar houdt. Een scan van opgeslagen decks op 22 augustus vond er geen enkele die hem gebruikte.

    Wat er mee weg is

    • De CSS-klassen .slide-lead-capture en .lead-capture-* worden niet meer uitgeschreven. Stileer je slidetypes in een fork, dan bestaan die namen niet meer.
    • De endpoints onder /api/leads zijn verwijderd, samen met de leadopslag, de AVG-tokenopslag en de notificatiemail aan de eigenaar met zijn twee templates.
    • De webhook lead.submitted is weg, en zijn rij in de admin ook. Er blijven zeven instelbare events over.
    • De instelling leads.retentionDays, de mailvoorkeur voor leads en de adminkaart “Lead capture” zijn verwijderd, net als /my-data en het leads-tabblad in analytics.
    • Een migratie verwijdert de tabellen lead_submissions en gdpr_verification_tokens. Niets anders las ze: gasten via een deellink dragen hun eigen verificatiekolommen en het wispad van analytics heeft zijn eigen token, allebei onaangeroerd.

    Dit is geen major release: /api/leads hoorde nooit bij /api/v1, en sinds het type weg is kon geen enkel deck nog een lead opleveren.

    De CSP wordt een header

    • Gepubliceerde pagina’s (/p/) en embeds (/embed/) sturen de document-CSP als echte HTTP-header, niet alleen als meta-tag. Een aantal directives wordt in meta-vorm genegeerd, dus een beleid in een header is het beleid waar een browser volledig naar kan handelen.
    • hls.js zit nu in de repository, waarmee het laatste CDN op het renderpad dicht is. Video afspelen hangt niet meer af van een externe host die het doet.

    Eén code voor verkeerde invoer

    Vertakt jouw API-client op een invalid_<iets>-foutcode, dan moet die aangepast worden. Eenentwintig ervan vallen samen tot error: "invalid" plus details.field, dat het invoerveld noemt dat de code eerder in zijn achtervoegsel verstopte. De status blijft gelijk: overal 400. Weg zijn invalid_category, invalid_colors, invalid_contact, invalid_email, invalid_fonts, invalid_format, invalid_label, invalid_level, invalid_new_owner, invalid_order, invalid_permission, invalid_permissions, invalid_presentation, invalid_registration_mode, invalid_role, invalid_slide_index, invalid_slug, invalid_source, invalid_style, invalid_usage en invalid_weight.

    De vier 401-codes blijven: invalid_password, invalid_token, invalid_or_expired en invalid_or_revoked zeggen dat de credential niet houdt, en dat is een ander antwoord op een andere status.

    Opgelost

    • Zeggenschap over een deck leest het eigenaarsstempel, niet eigenaar-of-maker. Wie een deck maakte en het daarna overdroeg zonder samenwerker te blijven, kon er nog steeds in schrijven, het verwijderen, het opnieuw delen en de samenwerkers beheren. Zo iemand krijgt nu een alleen-lezen editor. Dit was alleen bereikbaar na een eigendomsoverdracht waarbij de vorige eigenaar geen samenwerker bleef.
    • De nooit getoonde cookiebanner is verwijderd. Hij stond in de code en verscheen nooit.

    Het aantal ingebouwde slidetypes gaat van 34 naar 33.

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

  23. v1.23.0

    Beveiligingsrelease

    Elk gerenderd document draagt nu een Content-Security-Policy, de mediaprovider heet S3 in plaats van Scaleway, en mensen worden bij hun naam genoemd in plaats van bij hun adres.

    De vorige twee releases haalden third-party scripts van het renderpad af. Deze vertelt het de browser: elk document dat Deckyard rendert draagt een Content-Security-Policy die de hosts noemt waar hij code van mag laden. Het is de eerste van de drie uitspraken over externe herkomst die de machine die het document draait ook echt kan weigeren.

    Gebruik je opslag op afstand voor media, dan worden je omgevingsvariabelen hernoemd. De oude namen blijven werken tot de eerste release na 2026-11-01, elk met een waarschuwing bij het opstarten. Details hieronder.

    Een beleid dat de browser afdwingt

    • Elk renderpad zendt een CSP uit, op één plek samengesteld en uitgezonden vóór alles wat kan laden. Het is een hostlijst voor code en stijlen, geen XSS-verdediging, en dat staat er ook bij: de renderpaden zetten hun eigen runtime inline, dus script-src en style-src hebben 'unsafe-inline' nodig. Wat hij weigert is een script van een host waar niemand voor gekozen heeft, en default-src 'none' laat elk nieuw soort verzoek dichtvallen.
    • De laatste CDN-ladingen zitten nu in de repository. pdf.js kwam van cdnjs een headless Chrome in; Prism en KaTeX worden op elk renderpad uit de meegeleverde kopie geserveerd, niet alleen in de app.
    • Provider-id’s voor analytics worden gevalideerd in plaats van ge-escaped.

    De mediaprovider heet S3, niet Scaleway

    De mediaprovider op afstand was naar één leverancier vernoemd terwijl hij eronder gewoon S3-compatibel is.

    • MEDIA_STORAGE_MODE=scaleway wordt =s3
    • SCW_ACCESS_KEY / SCW_SECRET_KEY / SCW_BUCKET / SCW_REGION / SCW_ENDPOINT / SCW_CDN_URL worden S3_ACCESS_KEY / S3_SECRET_KEY / S3_BUCKET / S3_REGION / S3_ENDPOINT / S3_PUBLIC_URL

    De oude namen worden gelezen tot de eerste release na 2026-11-01, alleen als hun S3_*-tegenhanger leeg is, en elke naam die gelezen wordt drukt bij het opstarten een waarschuwing af met zijn vervanger erin. S3_ENDPOINT is verplicht onder de nieuwe namen: MEDIA_STORAGE_MODE=s3 weigert zonder te starten. Een onaangeroerde oude installatie is de ene uitzondering, waar een lege endpoint nog steeds wordt afgeleid als https://s3.<regio>.scw.cloud. Een half ingevulde set waarschuwt nu bij het opstarten in plaats van stilletjes op lokale opslag te blijven.

    Mensen hebben een naam, geen adres

    Het identiteitswerk dat in 1.16.0 begon rondt af op de oppervlakken die naar andere mensen wijzen.

    • Reacties en slidevergrendelingen noemen mensen met een id en een weergavenaam. Een reactie draagt een auteurspaar in plaats van een adres plus een naam, en de AI-auteur wordt door de server gemarkeerd in plaats van doordat de client adressen vergelijkt.
    • Stempels voor maker en weggooier zijn ook paren, en de terugval op het e-mailadres in identiteitsherkenning is opgeruimd.
    • /api/v1/slide-library geeft createdById terug in plaats van createdBy. Dat oude veld was het e-mailadres van de maker, dat werd prijsgegeven aan elke API-sleutel met leesrecht op de bibliotheek. De rest van het publieke v1-oppervlak gaf al alleen id’s terug.

    Verwijderd

    • De vergrendeling op presentatieniveau en zijn wachtrij met toegangsverzoeken zijn weg, samen met de routes /api/presentations/:id/lock/*, de tabellen presentation_locks en lock_requests en de variabele USE_DB_LOCKS. De client had vergrendeling op slideniveau vast ingebouwd; dit pad werd nooit bereikt. Vergrendeling op slideniveau blijft zoals hij was, en één echte fout daarin is opgelost: bij het vrijgeven van een vergrendeling werd de rij zonder vervalfilter gelezen, waardoor een verlopen vergrendeling van iemand anders 409 antwoordde op een slot dat niemand vasthield.

    Een eigendomsoverdracht is definitief

    • Wie een deck overdroeg kan het niet terugnemen. POST /api/presentations/:id/transfer-ownership antwoordt 401 voor iemand die alleen het makersstempel heeft; de beslissing hangt aan het eigenaarsstempel in plaats van aan eigenaar-of-maker. Je houdt de vermelding als maker, niet de zeggenschap.

    Voor API-clients

    • Elke opslagfout antwoordt met de status die zijn eigen register noemt, in plaats van standaard 400. parent_not_found is 404, own_question is 403, en de codes voor interne fouten zijn 5xx. Acht codes zijn hernoemd naar snake_case.
    • De synoniemen voor foutredenen vallen samen tot één schrijfwijze elk.

    Opgelost

    • Een download heet naar het deck. De <title> van een print-, PDF-slides- of PNG-exportdocument is nu alleen de decktitel; wat bij jou op het oude achtervoegsel matchte, matcht niet meer.
    • Escape pelt één overlay per keer af en geeft de besturing netjes terug, in plaats van meer te sluiten dan je vroeg.
    • Gekopieerde slides houden hun nesting en krijgen verse instance-id’s.
    • Het meer-menu koppelt elk item één keer, en sluit voordat het handelt, zodat een menu-item niet twee keer kan afgaan.
    • “Toevoegen als tweede slide” zet de uitnodiging op plek twee.
    • De importknoppen voor markdown zeggen niet langer “Importeer JSON”.
    • Codeblokken krijgen op elk renderpad kleur, en de CSS-naad voor forks serveert custom/styles/ en forklettertypes.

    Het aantal ingebouwde slidetypes blijft 34.

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

  24. v1.22.0

    Onderhoudsrelease

    Het ingebouwde thema "Deckyard" heet voortaan "Amethyst", en nog maar één ingebouwd thema draagt het Deckyard-merkteken.

    Een kleine release met één hernoeming erin, het nakijken waard als je decks op het violette ingebouwde thema hebt staan.

    Het ingebouwde thema-id deckyard is nu amethyst, met het label “Amethyst”. Er is geen alias voor het oude id. Een deck dat is opgeslagen met "theme": "deckyard" laadt en rendert nog gewoon, in het standaardthema (brand, Forest), maar valt bij de volgende bewaring door de validatie tot je opnieuw een thema kiest. Eigen thema’s in custom/themes/ merken er niets van.

    • Amethyst draagt het neutrale placeholder-logo, net als de andere archetypethema’s. brand (Forest) is nu het enige ingebouwde thema met het Deckyard-merkteken, en zo hoort een archetype dat als vertrekpunt bedoeld is er ook uit te zien.
    • Het standaardthema wordt door de server bepaald, niet aan de clientkant gekozen. Het samenstelpad van de slidebibliotheek koos er eerder zelf een.

    Verwijderd

    • Twee ongedocumenteerde AI-wizard-endpoints zijn weg. POST /api/ai/wizard-v2 en /api/ai/wizard-v2/outline zijn verwijderd; het streaming-endpoint /api/ai/wizard-v2/stream is het ene pad en blijft zoals het was. Geen van beide stond in de OpenAPI-documentatie, dus dit valt alleen op als je ze rechtstreeks aanriep.

    Opgelost

    • Markdown rendert nu echt in MCP-previews en -exports. Het MCP-proces zette zijn sanitizer nooit op, dus wie een slide via de MCP-server previewde of exporteerde zag lijsten en opmaak als zichtbare <ul>-tekst. Dat is nu opgelost, en ontbreekt er ergens een sanitizer, dan staat er één waarschuwing op stderr in plaats van niets.
    • De follow-API antwoordt 404 op een onbekende presentatie en 503 op een onbereikbare store, waar allebei eerder een 400 was. Matchte je op 400, dan moet dat aangepast.
    • De gaten in de vertaling van de descriptortabellen zijn gevuld, en de dekkingscontrole ziet ze nu, zodat het volgende gat de build laat falen in plaats van als Engels in een Nederlandse interface mee te gaan.

    Het aantal ingebouwde slidetypes blijft 34.

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

  25. v1.21.0

    Feature-release

    Uit Notion geïmporteerde afbeeldingen verlopen niet meer, uitgaande webhooks kunnen ondertekend worden, en een datavraag heeft geen account meer nodig om af te ronden.

    Twee dingen hier repareren beloftes die maar half werden waargemaakt: een geïmporteerd deck waarvan de afbeeldingen een uur later stierven, en een webhook-ontvanger die geen manier had om een echte levering van een vervalste te onderscheiden.

    Draai bij deze update de migraties 075, 076 en 077. Zonder 076 start de slidebibliotheek niet goed, en zonder 077 raakt een ingestelde webhook-URL voor de slidebibliotheek zoek.

    Notion-afbeeldingen overleven de import

    • Afbeeldingen uit Notion worden in je eigen mediabibliotheek opnieuw gehost. Notion geeft ondertekende URL’s uit die na ongeveer een uur verlopen, en zonder geconfigureerde ImageKit bewaarde Deckyard die URL’s letterlijk, dus een geïmporteerd deck raakte kort na de import zijn beeld kwijt. Elke afbeelding wordt nu opgehaald en opgeslagen via je ingestelde mediaprovider, en het blok wijst naar de blijvende kopie. Lukt een losse afbeelding niet, dan blijft de originele URL staan in plaats van dat het beeld verdwijnt. Voor een instance met ImageKit verandert er niets.
    • Die ophaalacties zijn SSRF-beveiligd en houden een maximale grootte aan, want de import doet nu uitgaande verzoeken op een URL uit een document.

    Webhooks

    • Leveringen kunnen ondertekend worden. Zet webhooks.signingSecret en elke levering draagt x-sb-signature: sha256=<hmac-van-de-body> naast de bestaande x-sb-event-header. Zonder secret ontbreekt hij, dus er verandert niets tot je ervoor kiest. Er is een adminveld voor.
    • actor.id draagt het vaste gebruikers-id, niet het adres. Het adres blijft beschikbaar als actor.email, als contactgegeven en niet als identiteit. Ging jouw ontvanger uit van actor.id als adres, dan moet die aangepast worden.
    • Het event slide.added_to_team_library heet nu slide.added_to_organization_library, in de payload en in de x-sb-event-header. Er is geen alias, dus een ontvanger die op de oude tekst matcht herkent hem stilletjes niet meer.
    • De user-agent is Deckyard-Webhook/1, in plaats van presentation-system-webhook/1.

    Datavragen zonder account

    • De zelfbedieningsroutes voor eigen data zijn publiek, met een landingspagina en een blijvende tokenopslag erachter, zodat iemand een inzage- of wisverzoek kan afronden zonder te kunnen inloggen. In 1.20.0 begon de verificatiemail uit te gaan; dit is de andere helft.
    • leads.retentionDays staat in het instellingenscherm van de admin, in plaats van alleen in een configbestand.

    Voor API-clients

    • Publieke API v1 antwoordt met één foutenvelop. Elke route op het v1-oppervlak geeft nu dezelfde foutvorm terug.
    • Publiceren draait op één gedeelde kern, zodat het interne publicatiepad en het v1-endpoint niet uit elkaar kunnen lopen.
    • Het filterargument in MCP heet ownership, niet scope. Het geldt voor list_presentations en list_recent_comments, ook in het antwoord; de waarden blijven gelijk (owned, shared, all). Een oude aanroep valt stilletjes terug op de standaard in plaats van te falen.
    • De slidebibliotheek spreekt van een shelf. De API neemt shelf: 'personal' | 'organization', en de ZIP-entry bij een bulkexport heet slide-library/organization.json waar dat team.json was.

    Opgelost

    • Een lijst in twee kolommen stopt bij zes items wanneer een tussenkop samenvalt met titels van drie regels, in plaats van de slide uit te lopen.
    • Overzichten van de teambibliotheek komen voorbij een sluimerende limiet van 100 rijen, en de autorisatiecontrole erop is opgelost.

    Het aantal ingebouwde slidetypes blijft 34.

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

  26. v1.20.0

    Feature-release

    Functieschakelaars staan allemaal dezelfde kant op: `AI_ENABLED` in plaats van `DISABLE_AI`. De oude namen blijven tot november werken.

    Drie schakelaars waren als ontkenning gespeld, dus iets uitzetten betekende een variabele op true zetten, en een configuratiebestand lezen betekende een dubbele ontkenning ontrafelen. Ze staan nu in de aanzet-vorm, standaard aan.

    Gebruik je een van deze, plan dan een hernoeming vóór 2026-11-01.

    • DISABLE_AI wordt AI_ENABLED
    • DISABLE_UPLOADS wordt UPLOADS_ENABLED
    • DISABLE_IMAGE_LIBRARY wordt IMAGE_LIBRARY_ENABLED

    Alle drie staan standaard aan. De oude spellingen worden nog gehonoreerd, omgekeerd, tot de eerste release na 2026-11-01, en elke ingestelde oude naam drukt bij het opstarten een waarschuwing af met zijn vervanger en de verwijderdatum erin. Staan beide spellingen ingesteld, dan wint de nieuwe. docs/reference/feature-flags.md legt de regel vast, zodat een toekomstige schakelaar ook in de aanzet-vorm aankomt.

    AVG-zelfbediening levert nu echt

    • De verificatielink voor een datavraag wordt per e-mail verstuurd. Het endpoint maakte een token aan en bezorgde het nooit, dus het zei mensen “je ontvangt een verificatielink” terwijl er niets uitging; de zelfbediening voor inzage en wissing was in productie onbereikbaar, precies waar het juridisch telt. Een niet-geconfigureerde mailopzet antwoordt nu een eerlijke 501 in plaats van te doen alsof.

    Verwijderd

    • De verversmodus “bij bekijken” is weg. Hij stond in de instellingen van databronnen en was nooit gebouwd, dus hem kiezen deed niets.

    Opgelost

    • Schrijfacties van MCP-tools gaan langs de onderhoudspoort. Een instance in onderhoudsmodus was via MCP nog steeds beschrijfbaar.

    Beveiliging

    • De onbevoegde datasource:refreshed-uitzending is weg. Een ververs-event ging via SSE naar luisteraars die geen recht op die databron hadden.
    • Wijzigingen aan analytics-rapporten blijven bij hun eigen presentatie. Een rapportmutatie werd niet gecontroleerd tegen het deck waar hij bij hoorde.

    Het aantal ingebouwde slidetypes blijft 34.

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

  27. v1.19.0

    Feature-release

    Elke knop in een thema is nu een roltoken. De tokens per slidetype zijn weg, en dat is het lezen waard als je een eigen thema beheert.

    Een thema kon vroeger tot in losse slidetypes reiken: er waren tokens voor KPI-tegels, voor tabelvarianten, voor het icoonkaartraster, voor citaattekst. Daarmee kon een thema één slidetype stileren en niets zeggen over het volgende, dus een nieuw slidetype arriveerde ongestileerd en elk thema moest worden bijgewerkt om bij te blijven. Thema’s zetten nu rollen, en elk slidetype leidt zijn uiterlijk daaruit af.

    Beheer je een eigen thema, lees dan de lijst hieronder. Onbekende tokens in een bestaand thema zijn onschuldig (ze doen simpelweg niets), dus er breekt niets, maar een thema dat op een verwijderd token leunde rendert voortaan met de opmaak die uit de rollen volgt in plaats van met wat het vroeg.

    Wat er in de tokenwoordenlijst veranderde

    • De KPI-tokens zijn weg. --t-kpi-tile-{1..4}-* en --t-kpi-delta-* bestaan niet meer; tegels krijgen de neutrale standaard, en een gekleurde reeks komt uit --t-chart-*.
    • De tokens voor tabelvarianten zijn weg. --t-table-<variant>-* bestaat niet meer; tabelvlakken volgen --t-color-accent (met zijn contrast) en de mist- en verhoogde vlakken.
    • De tokens voor het icoonkaartraster zijn weg. --t-icon-card-grid-* bestaat niet meer; het icoonvlak volgt uit mist en accent (te overschrijven met --t-color-accent-soft), kaartlichamen lezen --t-color-surface-raised, en koptekst volgt de gradiënt- en op-vlakrollen.
    • De tokens voor citaat- en hoofdstuktekst zijn vervangen. --t-quote-text-color en --t-chapter-text-color worden --t-slide-bg-dark-text; --t-quote-author-color heet nu --t-color-accent-on-dark.
    • --t-list-item-title-letter-spacing is weg.
    • De oude aliassen worden niet meer uitgeschreven. --t-primary, --t-accent, --t-bg-dark en --t-brand-1/-2 zijn weg; de merkplekken --t-color-brand-{1..3} vullen zich uit brandColors.

    Opgelost

    • DELETE /api/leads/my-data komt bij de wisroutine uit in plaats van bij de rij die op id wordt aangesproken. Nam je AVG-wisverzoeken aan, dan landden die op de verkeerde plek.
    • Verse uitnodigingen staan niet meer als “verlopen” in de gebruikerslijst van de admin.
    • Een export in de wachtrij leest zijn type uit de naam van de taak, dus een PDF-taak komt niet in het verkeerde formaat terug.
    • De laatste afwijkende foutmeldingen gebruiken de canonieke envelop, zodat een API-client overal dezelfde foutvorm ziet.
    • Een mislukte sendEmail krijgt een type. Een verkeerde configuratie antwoordt 501 en een fout bovenstrooms blijft 502, zodat “wij kunnen geen mail versturen” en “de mailserver weigerde het” niet meer op elkaar lijken.
    • De ongebruikte transitieve afhankelijkheid image-size is uitgeschakeld, waarmee een ongepatcht pakket uit de boom verdwijnt.

    Het aantal ingebouwde slidetypes blijft 34.

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

  28. v1.18.0

    Feature-release

    Eén woord per betekenis: een deck heeft een zichtbaarheid, de huurder is een organisatie, en de API zegt dat ook. Toegang intrekken wordt nu gelogd en aan de betrokkene gemeld.

    Deckyard gebruikte het woord “scope” voor drie verschillende dingen en “workspace” voor twee. Deze release kiest één woord per betekenis en past de wire, de databasewaarden en de documentatie daarop aan. Gebruik je de API, dan wordt één veld hernoemd; de rest hier is gedrag.

    Gebruik je de publieke API, dan wordt scope voortaan visibility. De waarden zijn private en organization; workspace bestaat niet meer als waarde. De interne PATCH /api/presentations/:id/scope wordt /:id/visibility, en het webhook-event presentation.moved_to_workspace wordt presentation.moved_to_organization, met fromVisibility en toVisibility erin. “Workspace” blijft als woord in de interface staan; het is geen woord meer in de data.

    • Capaciteitenlijsten van API-sleutels heten permissions, precies wat het instellingenscherm er al van maakte.

    Toegang kwijtraken is nu zichtbaar

    • Het toegangslogboek is symmetrisch. Het legde toekenningen vast maar intrekkingen niet, dus een lijst met samenwerkers kon spoorloos veranderen. Intrekkingen en rechtenwijzigingen worden gelogd, en wie zijn toegang verliest krijgt bericht in plaats van het te ontdekken door te klikken.

    Voor API-clients

    • Tag-updates op de slidebibliotheek nemen alleen { tags: [...] }. De andere geaccepteerde vormen zijn weg; stuurde jouw client een kale array of een losse tekst, dan moet dat nu het object worden.
    • Eén JSON-ingang voor elke request body, wat ook betekent dat een body die geen object is overal op dezelfde manier geweigerd wordt in plaats van per route.

    Onder de motorkap

    • Deckversies, slidevergrendelingen en de live SSE-stroom hangen aan het gebruikers-id, in het verlengde van het identiteitswerk uit 1.16.0 en 1.17.0. De prullenbak en de slidebibliotheek lopen met hun autorisatie langs dezelfde identiteitscontrole.
    • Het deckschema gaat naar v6. Uitlijningssleutels per veld die niets meer deden zijn opgevouwen. De migratie draait bij het lezen van een deck en wordt bij de volgende bewaring vastgelegd, dus je hoeft niets te doen.

    Opgelost

    • Analytics houdt zich aan de bewaartermijn, en de dode analytics-tabellen zijn verwijderd.
    • Apparaatlabels werken in bootmodi zonder secret, door een vluchtige sleutel af te leiden in plaats van te falen.
    • De tussenkop van een vergelijkingsslide staat één stap boven de kolomtekst, zoals altijd de bedoeling was.
    • Een lijstslide meet zijn capaciteit opnieuw tegen de actuele maten, zodat items niet meer wegvallen of geperst worden na een maatwijziging.
    • Eén canonieke lijst met e-mailtemplatetypes, en een dood export-klaar-pad is weg.

    Het aantal ingebouwde slidetypes blijft 34.

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

  29. v1.17.0

    Feature-release

    Eigenaarschap wordt bepaald op het gebruikers-id in plaats van op het e-mailadres, anonieme kijkers kunnen hun eigen analytics-data wissen, en de analytics-API deelt geen identifiers meer uit die daar niet horen.

    Het identiteitswerk dat in 1.16.0 begon wordt hier echt: eigenaarschap, werkruimtetoegang en instellingen per gebruiker worden nu bepaald op het vaste gebruikers-id in plaats van op het adres waarmee iemand toevallig inlogt. Wijzig je adres en je houdt je decks.

    Er zitten twee privacyfixes in die het lezen waard zijn, allebei op het analytics-oppervlak, allebei hieronder.

    Identiteit is nu het gebruikers-id

    • Eigenaarschap van een deck vergelijkt gebruikers-id’s. De API draagt ownerId als identiteit en de client vergelijkt die, in plaats van adresteksten naast elkaar te leggen.
    • Een werkruimterecht wordt afgemeten aan de eigen organisatie van de handelende gebruiker, niet afgeleid.
    • Instellingen per gebruiker hangen aan het gebruikers-id, dus ze overleven een adreswijziging.
    • De migratie controleert en vult zichzelf aan, zodat een bestaande instance met alle stempels gevuld eindigt in plaats van halverwege omgezet. Na de upgrade bevestigt node scripts/verify-identity-migration.js dat hij op elke rij geland is.
    • Versiesnapshots dragen geen e-mailadressen van eigenaren meer, en een migratie wist ze ook uit de rijen die je al had.

    Analytics

    • Anonieme kijkers kunnen hun eigen data wissen. Wie een deck bekeek zonder account kan nu wissing van de eigen sessie vragen, door bezit van het sessietoken aan te tonen in plaats van een account nodig te hebben. Presenteer je voor publiek dat nooit inlogt, dan is dit het oppervlak dat een AVG-verzoek van zo iemand beantwoordt.
    • De schakelaar tussen interne en externe tracking is weg. analytics.enabled is de enige schakelaar; de tweede beloofde een onderscheid dat de data nooit droeg. Had je tracking uitstaan via die tweede schakelaar, dan moet je nu analytics.enabled uitzetten, anders begin je weer te verzamelen.
    • De sessielijst geeft het sessietoken niet meer terug. Het zat in het antwoord en niemand las het.
    • Een apparaatlabel per deck vervangt het ruwe apparaat-id. Het dashboard laat zien “dit is dezelfde bezoeker” zonder de identifier waarmee twee decks aan elkaar te knopen zouden zijn.

    Presenteren

    • Via de deelnamelink kunnen de sprekersnotities van de sessie bewerkt worden. Wie de deelnamelink heeft kan tijdens de sessie notities schrijven, en niet meer alleen lezen.

    Opgelost

    • Een mislukte uitnodiging voor een samenwerker antwoordt 500, niet 400. Een opslagfout werd gemeld alsof jij iets verkeerds had gestuurd.
    • DATABASE_URL wint van de losse DATABASE_*-variabelen in db:migrate, net als in de server zelf. Had je allebei ingesteld, dan draaiden migraties op een andere database dan de app.
    • Exports in de wachtrij laden hun thema goed, dus een export op de achtergrond krijgt dezelfde opmaak als een interactieve.
    • Een mislukte uitnodiging kijkt naar de foutcode, niet naar de tekst van de melding.

    Het aantal ingebouwde slidetypes blijft 34.

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

  30. v1.16.0

    Feature-release

    Mensen worden voortaan herkend aan een vast gebruikers-id in plaats van aan hun e-mailadres, en de laatste publieksdata verdwijnt van de schijf.

    Een stille release met één langlopend thema eronder: wie iemand is houdt op zijn e-mailadres te zijn. Deckyard gebruikte het adres als identiteit bij eigenaarschap, samenwerkersrijen en audit-stempels, wat betekende dat je adres wijzigen je identiteit wijzigde. Deze release zet het vaste gebruikers-id ernaast; de releases erna schakelen elk oppervlak erop over.

    Identiteit krijgt een vaste sleutel

    • Decks dragen een eigenaar, maker en laatste bewerker als gebruikers-id, naast de adressen die er al stonden. Voor jou verandert er nog niets; het lezen schakelt in 1.17.0 om.
    • Samenwerkersrijen dragen een gebruikers-id naast het adres.
    • Een eigendomsoverdracht wordt vastgelegd in plaats van het oude stempel te laten staan.

    De rest van de publieksdata gaat naar Postgres

    • Vragen, interacties en feedback zijn databaserijen. Nu 1.15.0 de bestandsopslag heeft verwijderd, sluit dit het laatste pad dat publieksinvoer naar schijf schreef.

    Opgelost

    • Samenwerkersrijen horen bij het deck, niet bij de sessie. De verkeerde afbakening kon een lijst met samenwerkers tonen die bij een andere context hoorde.
    • Een mislukte taalwissel zegt dat ook. De taal van een deck wisselen deed stilletjes niets als het misging; nu meldt hij de fout.

    Beveiliging

    • De publieke wachtwoordcontrole van een deellink heeft een snelheidslimiet. Een met wachtwoord beveiligde link kon worden aangevallen in het tempo dat het netwerk toestond. Publiceer je links met wachtwoord, dan is dit de reden om deze update te nemen.

    Het aantal ingebouwde slidetypes blijft 34.

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

  31. v1.15.0

    Feature-release

    PostgreSQL wordt het enige opslagsysteem. Een instance die zijn decks nog als JSON op schijf bewaart moet ze eerst importeren voordat hij start.

    Deckyard kon alles opslaan als JSON-bestanden in een datamap, met Postgres als optie. Die optie is nu de enige: de bestandsopslag is verwijderd, en elk deck, elke instelling, elke live sessie en elke e-mailtemplate staat in de database.

    Dit is de release waar je een plan voor nodig hebt voordat je update. Draait jouw instance nog op bestandsopslag, dan weigert hij na deze update te starten, in plaats van je een lege werkruimte voor te zetten naast data die hij niet meer kan lezen. De weg erdoorheen is één commando, en die staat hieronder.

    Importeren voordat je herstart

    De bootcheck telt de decks in je datamap. Vindt hij ze terwijl de database leeg is, dan stopt hij en drukt hij allebei de uitwegen af in plaats van te starten.

    • Draai npm run db:import. Die leest de oude datamap en schrijft hem naar Postgres. De bestandsdata wordt alleen gelezen, nooit verplaatst of verwijderd, dus de import kan opnieuw en de oude map blijft je terugvaloptie.
    • Maak een databasebackup en bewaar de datamap tot je een paar decks hebt geopend en hebt gezien dat ze kloppen.
    • STORAGE_MODE heeft nu één schrijfwijze per backend. postgresql was een stille alias voor postgres, en een onbekende waarde viel terug op bestandsopslag. Allebei zijn nu bootfouten, dus je kunt niet meer op een backend belanden waar je niet om vroeg.

    Postgres zit in de stack

    • De compose-stack bevat een Postgres-service, dus een verse installatie heeft geen aparte database-inrichting nodig. .env.example beschrijft het databaseblok als gewone configuratie in plaats van als iets waar je voor kiest.
    • De installer faalt meteen op een verouderde DATABASE_HOST in plaats van te starten en later stuk te gaan.

    Wat er naar de database is verhuisd

    Vier dingen die nog als JSON op schijf stonden zijn nu rijen, en dat is wat een deployment met meerdere instances of in containers laat werken:

    • Vragen, interacties en publieksfeedback.
    • Live sessies en volgcodes.
    • Instellingen van de instance, zodat een adminwijziging niet meer afhangt van een schrijfbaar configbestand.
    • E-mailtemplates.

    Ook de TTL-opruiming en het quotum van de sandbox draaien op Postgres. De compose-sandbox-stack is de ene uitzondering: die heeft geen databaseservice en leest deck-JSON nog van schijf, dus daar staat STORAGE_MODE=file expliciet vastgezet.

    Verder in deze release

    • De interface wordt in twaalf talen aangeboden, waarvan Nederlands en Engels de twee zijn die op volledigheid worden bewaakt; de andere tien zijn best-effort en vallen terug op Engels waar een tekst ontbreekt.
    • Beeldgebruik wordt in de database opgezocht, dus de beeldbibliotheek meldt een afbeelding niet langer als ongebruikt omdat hij op schijf zocht.
    • Zeven CSS-klassen van slidetypes worden niet meer uitgeschreven: team-cards-group-left, kpi-note, quote-author-text, poll-results-main, sfi-header, sfi-card-code, sfi-card-qr. Geen enkel ingebouwd thema gebruikte ze, dus de thema’s van Deckyard zelf merken er niets van. Beheer je een fork die op zo’n naam stileerde, verplaats die regels dan naar de klasse die op hetzelfde element overblijft.
    • De nummering blijft in 1.x. Er is kort een 2.0.0 voorbereid en weer teruggedraaid; de betahouding van Deckyard houdt breaking changes voorlopig op een minor, en daarom is een release als deze geen major.

    Het aantal ingebouwde slidetypes blijft 34.

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

  32. v1.14.0

    Beveiligingsrelease

    De laatste twee bibliotheken die de app bij een CDN ophaalde worden nu door je eigen instance geserveerd, en thema's krijgen een eerste set roltokens.

    De vorige release haalde DOMPurify van een CDN af. Deze maakt dat werk af voor de twee overgebleven third-party scripts, zodat een instance achter een firewall of op een afgesloten netwerk niet langer de server van iemand anders nodig heeft om een codeblok te kleuren of een formule te zetten.

    Syntax highlighting en formules komen van je eigen instance

    Prism (code-highlighting) en KaTeX (wiskundige notatie) werden bij het laden van de pagina van een publiek CDN gehaald. Ze zitten nu in de repository zelf en worden door je eigen instance geserveerd, lazy geladen door de app-shell in plaats van bij elke pagina.

    • Een offline of CDN-geblokkeerde installatie rendert code en formules gewoon goed, waar dat eerder terugviel op ongestileerde tekst.
    • Ze laden alleen als een deck ze nodig heeft. Voor een deck zonder codeblok of formule wordt er niets opgehaald.

    Thema’s krijgen roltokens

    De eerste fase van een langer traject op het themasysteem: slides gaan tokens lezen die een rol benoemen (een vlak, een accent, tekst op een donker vlak) in plaats van een slidetype. Visueel verandert er niets en geen enkel bestaand thema breekt; dit is het voorwerk voor de consolidatie die in 1.19.0 landt.

    • docs/reference/slide-roles.md beschrijft de woordenlijst, als je eigen thema’s schrijft en wilt zien waar dit heen gaat.

    Het aantal ingebouwde slidetypes blijft 34.

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

  33. v1.13.0

    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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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