Aller au contenu

Playground

Écrivez une présentation dans votre navigateur et regardez les diapositives suivre : go-slides compilé en WebAssembly, avec complétion, aide et exemples.

Ouvrir le Playground →

Le Playground (bac à sable en ligne), c’est go-slides lui-même, en v0.20.2, compilé en WebAssembly et exécuté dans votre navigateur. Tapez une présentation à gauche ; les diapositives suivent à droite. Rien n’est envoyé à un serveur : ni la présentation, ni un lien de partage.

L’interface du Playground (ruban, aide, messages) parle la langue de la page : ouvrez /fr/playground/ pour le français, et de même pour les douze langues de ce site. Le sélecteur de langue de la page la change et votre choix est conservé dans ce navigateur ; un lien qui nomme une langue l’emporte toujours. Les présentations d’exemple restent en anglais. L’ukrainien, le russe, le chinois, le japonais et le coréen sont dessinés avec un sous-ensemble de Noto Sans (de 0,06 à 2,3 Mio) que la page ne télécharge que pour ces langues.

Ce qu’il propose

  • Aperçu en direct de chaque diapositive, rendu hors du thread de la page (dans un Web Worker) : la saisie ne l’attend jamais. Cliquez sur une diapositive pour amener l’éditeur à sa ligne ; déplacez le curseur et l’aperçu défile jusqu’à sa diapositive.

  • Diaporama : la présentation elle-même, avec le clavier, le contrôleur à l’écran et les transitions.

  • Mode présentateur : Present (ou p dans le diaporama) l’ouvre dans une seconde fenêtre : la diapositive courante, l’étape suivante, les notes de l’orateur (les <!-- comments --> de la présentation), une horloge et un chronomètre. Les touches fléchées, Espace, Début et Fin fonctionnent dans l’une ou l’autre fenêtre, et chacune suit l’autre, y compris quand vous modifiez la présentation. Si la fenêtre ne s’ouvre pas, autorisez les fenêtres surgissantes pour le site. La vue d’ensemble (o) n’existe que dans la page téléchargée.

  • Complétion pendant la saisie : clés de directive (les ponctuelles, avec _, dans les commentaires), les valeurs de kind, theme, size, paginate, ainsi que les fonctions de gabarit et les champs de données dans {{ }}.

  • Aide sur ce qui se trouve sous le curseur : une directive, un kind (le type d’une diapositive) (ce qu’il définit), une fonction de gabarit. Le volet d’aide renvoie aussi vers ces pages. Depuis la v0.16.0, l’aide sur les directives suit la langue de l’interface, en 11 langues.

  • Problèmes sur leur ligne : les erreurs de gabarit, de YAML et de HCL sont mises en évidence dans l’éditeur et listées en dessous, et l’aperçu conserve la dernière présentation rendue avec succès.

  • Exemples : une présentation d’accueil, des gabarits qui génèrent des diapositives, des kinds, un front matter HCL, des thèmes et des directives ponctuelles, ainsi que des mathématiques, des images et des arrière-plans (![bg], un ![bg left:40%] partagé, des filtres).

  • Fichiers : le panneau à gauche de l’éditeur est le projet de la présentation, organisé comme le lisent la commande et l’extension VS Code : deck.md, slides.yaml, themes/, kinds/, media/.

    • Cliquez sur un fichier pour le modifier. L’éditeur le colore selon son langage (Markdown, YAML, HCL, JSON, CSS) et signale ses problèmes.
    • Clic droit (ou Maj+F10) pour New File, New Folder, Rename (F2), Delete (avec confirmation) et New theme / New kind. Faites glisser un fichier sur un dossier pour l’y déplacer. Le clavier suit le modèle d’arborescence WAI-ARIA, recherche par saisie comprise.
    • Project ▸ New theme crée themes/my-gaia.css (ou à partir de default, uncover) : un @import du thème intégré et les règles que vous ajoutez. Il rejoint la liste Theme. New kind et New data file partent eux aussi de modèles. Chacun est listé dans slides.yaml, si bien que slides build deck.md le trouve.
    • Project ▸ Download project (.zip) enregistre le tout. Une fois décompressé, slides build deck.md le génère. Open project reprend un .zip ou un dossier. Une archive qui sort de son dossier (.., chemins absolus), contient plus de 256 fichiers ou plus de 8 Mio dans un fichier, ou se décompresse à plus de 100 fois sa taille est refusée.
    • Tout est conservé dans ce navigateur avec le brouillon. Un projet peut contenir jusqu’à 64 Mio, et la ligne sous les fichiers indique l’espace utilisé.
  • Médias : déposez ou collez une image, une vidéo ou un son dans l’éditeur : il va dans media/, et la présentation le désigne : ![](media/photo.png). Déposez des fichiers sur un dossier du panneau pour les y placer. La présentation reste légère et lisible, et rien n’est téléversé. Le bac à sable de l’aperçu les charge sans être assoupli (la page lui transmet les octets). Save as ▸ HTML page les intègre à la page. Les images https: fonctionnent aussi, mais le navigateur les récupère sur leur serveur, qui voit alors votre adresse. L’aperçu n’envoie pas de referrer.

  • Volets redimensionnables : le panneau de fichiers, l’éditeur, les vignettes des diapositives, l’aperçu et l’aide sont séparés par des barres que vous pouvez faire glisser (le pointeur prend la forme d’un curseur de redimensionnement au-dessus). Le volet voisin de la barre prend la place, les autres gardent leur taille. Double-cliquez sur une barre, ou appuyez sur Entrée dessus, pour refermer le volet puis le rouvrir. Au clavier, F6 passe d’une barre à l’autre, les touches fléchées déplacent une barre de 16 px, Début et Fin amènent le volet qui la précède à sa taille minimale ou maximale, et Échap revient à l’éditeur. L’onglet View permet toujours de masquer des volets. Les tailles que vous définissez sont conservées dans ce navigateur, avec le brouillon ; les tailles par défaut (190, 168 et 280 px, l’éditeur et l’aperçu se partageant le reste à raison de 6 pour 5) ne sont jamais enregistrées.

  • Fermer un volet : chaque volet a un petit bouton × dans son en-tête, avec une infobulle. Les autres se partagent sa place, et le volet revient à la largeur qu’il avait. Pour le rouvrir, utilisez son interrupteur dans l’onglet View (chaque volet en a un). L’éditeur et l’aperçu peuvent chacun être fermés, jamais les deux : le dernier refuse, son bouton est grisé et son infobulle dit pourquoi. Au clavier, F6 puis Tab ou Maj+Tab mènent à un bouton ×, et Entrée ou Espace ferme le volet ; le clavier retourne à l’éditeur. Les volets ouverts sont conservés dans ce navigateur avec les tailles (Versions, GitHub et l’éditeur de thème, ouverts pour une tâche, démarrent fermés).

  • Mise en forme : l’onglet Format modifie le Markdown à votre place, et chaque clic correspond à une étape d’annulation.

    • Texte : Bold, Italic, Strikethrough et Inline code agissent sur la sélection ou sur le mot sous le curseur, et basculent (Ctrl+B, Ctrl+I, Ctrl+Maj+X et Ctrl+E ; Cmd sur Mac). Un bouton apparaît enfoncé quand le curseur est à l’intérieur de ses marques. Markdown n’a pas de soulignement : Underline (Ctrl+U) entoure le texte de <u>…</u>, une balise que conserve la liste d’autorisation HTML par défaut de Marp : cela fonctionne donc avec le HTML brut désactivé.
    • Paragraphe : Heading 1 à 3 (Ctrl+Alt+1..3), puces (Ctrl+Maj+8), numérotation (Ctrl+Maj+7) et citation agissent sur les lignes sélectionnées et basculent. La règle horizontale est la balise <hr> : ---, *** et ___ commenceraient chacun une nouvelle diapositive dans Marp.
    • Tableau : une grille permet de choisir colonnes et lignes. Avec le curseur dans un tableau, vous ajoutez ou supprimez une ligne ou une colonne et alignez la colonne (:--, :-:, --:) ; le tableau est réécrit aligné après chaque modification.
    • Slide text à gauche, au centre ou à droite écrit un bloc <style scoped> dans la diapositive courante. Marp n’a pas de syntaxe d’alignement, et un attribut style ne passe pas la liste d’autorisation HTML par défaut, mais le bloc scoped si : cela fonctionne donc avec le HTML brut désactivé, et se voit dans l’aperçu, la page HTML et le PDF.
    • Link (Ctrl+K) écrit [text](url) avec l’url sélectionnée.
  • Coloration des clés du front matter à toutes les profondeurs, en YAML (y compris dans les mappings {a: 1}) et en HCL.

  • Sélecteur de thème : default, gaia, uncover, les thèmes du projet (themes/*.css) et les thèmes que définit la présentation (/* @theme name */ dans un <style>). Il écrit theme: dans le front matter, en YAML ou en HCL, si bien qu’un lien partagé le conserve, et il suit le front matter quand vous le modifiez.

  • L’aperçu garde sa position pendant la saisie : seules les diapositives qui ont changé sont remplacées, et un changement de thème rouvre l’aperçu sur la même diapositive.

  • Lien de partage : la présentation voyage dans le lien lui-même (dans sa partie #, compressée), si bien qu’ouvrir le lien ouvre la présentation. Les liens transportent jusqu’à 64 Kio compressés, et la présentation seule : quand le projet contient davantage (thèmes, kinds, médias), Share le signale et propose le .zip.

  • Save as :

    • la page HTML, identique à celle qu’écrit slides deck.md ;
    • un PDF (vectoriel, avec texte sélectionnable et plan) ;
    • une présentation PowerPoint ou OpenDocument modifiable.

    Ils sont produits dans votre navigateur, par le même code que slides --pdf, --pptx et --odp : le PDF de la présentation de référence de 100 diapositives est identique, octet pour octet, à celui de la commande. Le premier export télécharge le moteur d’export (environ 5 Mio, une seule fois ; votre navigateur le conserve jusqu’à la prochaine mise à jour), avec une ligne de progression, et le compile pendant qu’il arrive. Il ne télécharge ensuite que les polices que dessinent vos diapositives. Sur une liaison à 3 Mo/s, le premier PDF de la présentation d’accueil est prêt en moins de 3 secondes. La présentation de 100 diapositives prend ensuite environ 3 secondes. Une image https: n’est incluse que si son serveur l’autorise (CORS) ; les images data: le sont toujours.

  • Votre brouillon est conservé :

    • La présentation est enregistrée dans ce navigateur pendant la saisie (IndexedDB, pour ce site uniquement) et revient quand vous rechargez la page. Rien n’est envoyé nulle part. Les fichiers texte du projet (thèmes, kinds, données, slides.yaml) sont conservés de la même façon, même si vous fermez l’onglet juste après avoir tapé ; les médias sont enregistrés au moment où ils sont déposés.
    • Un lien partagé ouvre sa présentation et conserve votre brouillon : Draft ▸ Restore my draft le fait revenir.
    • Un exemple, Draft ▸ Reset to the example (qui demande confirmation) et un autre onglet ne l’effacent pas non plus : Draft ▸ Restore replaced le rétablit.
    • Draft ▸ Forget my drafts efface tout ce qui est enregistré.

Chaque export fait le rendu du projet qu’affiche l’aperçu : son slides.yaml, ses thèmes, ses kinds, ses fichiers de données et ses médias, les médias étant intégrés au document.

Les images en tant que fichiers (--images de slides) ne sont pas produites dans le navigateur : utilisez la commande ou l’extension VS Code.

Éditeur de thème

Accueil ▸ Apparence ▸ Éditeur de thème ouvre un volet qui modifie l’un des thèmes du projet avec des réglages, et l’aperçu suit. Le thème est conservé sous forme de dossier de paquet, theme-src/<name>/ ; la feuille que lisent l’aperçu et les exports, themes/<name>.css, en est compilée : ce que vous voyez est ce que vous exportez. Un paquet de thème que vous importez (Importer… dans le volet, Ajouter un média…, ou un glisser-déposer) y garde ses fichiers, vous pouvez donc le modifier.

  • Palette : les couleurs du fond, du texte, des titres, d’accent et des liens. Choisissez une couleur ou saisissez-la (#1a2b3c, rgb(), hsl() ou un nom).
  • Typographie : les polices du texte, des titres et du code, avec leurs tailles et leurs graisses. Les polices sont les génériques et les usuelles, et celles que vous ajoutez (Ajouter une police… : .woff2, .woff, .ttf ou .otf).
  • Logo : une image (.svg, .png), son emplacement (un coin, ou tout le fond) et sa taille. Numéro de page et pied de page : où va le numéro de page, et les tailles et l’alignement.
  • Détails : ce que dit theme.hcl : version, description, auteurs, licence, page d’accueil, le thème de base (extends) et la version de go-slides requise.
  • Contraste (WCAG) : pour chaque texte sur son fond, le rapport et son niveau, AA ou AAA, ou « Échec », en direct. Les titres comptent comme du grand texte (3:1 suffit pour AA ; le texte normal demande 4,5:1).

Modifier le CSS montre la feuille du thème dans l’éditeur. Les réglages n’écrivent que dans un bloc délimité par deux commentaires gsta:visual, et le relisent quand vous modifiez ses valeurs à la main. Ce que vous écrivez en dehors du bloc n’est jamais touché. Si vous ajoutez dans le bloc quelque chose que les réglages ne peuvent pas montrer, ils cessent d’écrire et le volet le dit ; Rétablir le bloc le réécrit à partir des valeurs qu’il contient et rien d’autre.

Importer… ouvre un .gsta.xz ou une feuille .css isolée. Un paquet est vérifié comme le vérifie slides theme verify, avec les mêmes limites : un paquet qui n’est pas sûr (un chemin qui en sort, un lien, un script dans un SVG, une url() distante, une somme de contrôle qui ne correspond pas) est refusé avec son code theme.*, dans Problèmes, et rien ne change. Dans une feuille isolée, un @import "gaia"; devient le thème de base (extends), car un paquet y nomme sa base. Une police que vous ajoutez a la licence LicenseRef-unspecified tant que vous ne la dites pas sous Détails.

Exporter .gsta.xz construit le paquet dans votre navigateur et le relit comme le fait slides theme verify, si bien que le fichier le passe ; Exporter le CSS télécharge la feuille compilée. Rien n’est envoyé. Chaque modification est une étape d’Annuler (les modifications d’un même réglage à la suite ne font qu’une étape) et garde ce qu’elle remplace comme version ; Enregistrer une version conserve le thème et sa version, par son nom, dans le volet Versions.

Annuler, rétablir et versions

Undo et Redo (annuler et rétablir) se trouvent dans l’onglet Home et sur Ctrl+Z, Ctrl+Maj+Z ou Ctrl+Y (Cmd sur Mac). Ils annulent la dernière modification du fichier affiché (chaque fichier a son propre historique), puis la dernière opération sur l’ensemble du projet : un exemple choisi, Reset, un .zip ou un dossier ouvert, un brouillon restauré, un fichier ou un dossier supprimé ou renommé, une version restaurée. Redo rétablit tout dans l’état où Undo l’a trouvé.

Les versions conservent tout le projet dans ce navigateur, sans rien envoyer nulle part. Une version est enregistrée peu après que vous avez cessé de taper (au plus toutes les 2 minutes), avant chaque opération sur l’ensemble du projet, et à chaque export et lien de partage. Save version… en enregistre une sous un nom. Home ▸ Versions ouvre le volet Versions :

  • Preview affiche une version dans l’aperçu.
  • Compare with now montre les modifications de chaque fichier ligne par ligne, en ligne ou côte à côte ; F7 et Maj+F7 passent d’une modification à l’autre.
  • Restore remet une version en place ; Undo annule la restauration.
  • Delete supprime une version.

Ce qui est conservé : les 20 versions automatiques les plus récentes, puis une par heure pendant un jour et une par jour pendant un mois. Les versions nommées restent jusqu’à ce que vous les supprimiez (50 au plus). L’ensemble des versions occupe au plus 96 MiB, et les fichiers qui n’ont pas changé ne sont stockés qu’une fois. Quand le stockage du navigateur est plein, les versions automatiques les plus anciennes partent d’abord.

GitHub

Home ▸ History ▸ GitHub ouvre un volet qui charge le dossier d’une présentation depuis un dépôt GitHub et propose vos changements en retour sous forme de pull request. Renseignez :

  • Dépôt (propriétaire/nom) ;
  • Branche (vide: celle par défaut) ;
  • Dossier (vide: la racine) : le dossier doit contenir un deck.md.

Au-dessus de ces champs, le volet affiche le cadre git : un petit panneau où vous choisissez la forge, saisissez le jeton (masqué), cochez Mémoriser sur cet appareil et cliquez sur Se connecter (ou Se connecter avec GitLab) ou Se déconnecter. Le cadre est une page d’un autre site, go-slides-usercontent.github.io, intégrée au playground : la page du playground ne voit jamais votre jeton.

Le jeton est un jeton d’accès personnel à granularité fine (en créer un), limité aux dépôts choisis, avec les permissions Contents en lecture/écriture et Pull requests en lecture/écriture (Metadata en lecture est implicite). Ensuite :

  • Charger remplace le projet par le dossier de GitHub. Undo le reprend, et le projet tel qu’il était est conservé comme version « Depuis GitHub ».
  • Proposer les changements… demande un titre, crée une nouvelle branche slides/<titre>-<date-heure> et ouvre une pull request. Il n’écrit jamais dans une branche existante ni dans la branche par défaut. Ouvrir la pull request vous y conduit.
  • Chercher des changements compare la version plus récente de GitHub à la vôtre dans la vue Compare. Prendre les leurs la charge.

Aucun proxy n’est utilisé pour GitHub : le cadre s’adresse directement à lui.

Le jeton est saisi dans le cadre et reste sur son site. La page du playground ne peut pas le lire (le cadre est une autre origine, avec un stockage à lui), aucune commande que la page peut envoyer ne le renvoie, et la Content Security Policy de la page ne lui permet aucune connexion à GitHub ni à GitLab. Le cadre n’envoie le jeton qu’à api.github.com (ou gitlab.com). Il n’est jamais enregistré dans le brouillon, les versions, les liens de partage ni les exports, et n’atteint jamais l’aperçu des diapositives ni le worker de rendu. Mémoriser sur cet appareil le garde dans le localStorage propre au cadre, sur go-slides-usercontent.github.io, et non dans le stockage du playground, jusqu’à Se déconnecter (ou Forget my drafts).

Si vous avez utilisé une version antérieure : un jeton qu’elle gardait dans le stockage propre de la page du playground est supprimé la première fois que vous ouvrez cette version, et le volet vous le dit. Saisissez-le de nouveau dans le cadre (et cochez Mémoriser si vous voulez qu’il soit gardé).

Proposer les changements… est une écriture, donc le cadre vous demande d’abord : il affiche le titre, le dépôt et le nombre de fichiers, et attend votre clic sur son propre bouton Autoriser (deux minutes au plus, une proposition à la fois). Rien n’est écrit avant votre clic.

Deux risques subsistent, parce qu’ils tiennent à une page qui intègre un cadre. Un script injecté dans la page du playground peut lire le nonce du cadre et envoyer les commandes du cadre : lire le dossier que vous avez chargé, ou demander une proposition (que vous devez quand même autoriser dans le cadre). Et il peut dessiner un faux panneau par-dessus le cadre et vous demander lui-même votre jeton : si le cadre a l’air anormal ou n’est pas où il devrait être, ne saisissez pas le jeton. Ni l’un ni l’autre ne lui permet de lire le jeton que détient le cadre. Préférez un jeton limité aux dépôts dont vous avez besoin. Pour les équipes, le mode serveur auto-hébergé (à venir) garde les jetons sur le serveur.

GitLab.com

Le volet a une liste de forges : GitHub et GitLab.com. Pour GitLab, donnez soit un jeton d’accès personnel de portée api, soit cliquez sur Se connecter avec GitLab (code d’autorisation OAuth avec PKCE, sans secret). La connexion ouvre une petite fenêtre du site du cadre et y revient ; la page du playground dans laquelle vous travaillez n’est pas quittée. Ses jetons restent dans la mémoire du cadre seulement (jamais mémorisés sur l’appareil, même avec Mémoriser sur cet appareil), se renouvellent avant d’expirer, et Se déconnecter les révoque chez GitLab. Une connexion non lancée par le cadre, ou un lien réutilisé, est refusée. La connexion est disponible dès que l’application GitLab du site est enregistrée ; d’ici là, utilisez un jeton d’accès personnel.

Les requêtes ne vont qu’à api.github.com et gitlab.com, et seulement depuis le cadre : la page du playground n’en fait aucune et n’envoie pas de referrer.

Pourquoi api ? La table des portées de GitLab indique que write_repository « Does not support API authentication » : elle ne sert qu’à git sur HTTP, que GitLab sert sans CORS, donc un navigateur ne peut pas l’utiliser. Les propositions passent par l’API REST, qui exige api, « complete read and write access to the API ». Un jeton api volé peut faire tout ce que son utilisateur peut faire par l’API, sur tous les projets que cet utilisateur atteint. Préférez un jeton d’accès de projet ou de groupe limité aux dépôts des présentations, ou un compte GitLab dédié, membre seulement des projets des présentations.

Sécurité

La présentation s’affiche dans une iframe isolée, privée de l’origine de la page : elle ne peut atteindre ni le Playground ni son stockage, ne soumet aucun formulaire et ne navigue nulle part. Sa page porte une Content Security Policy qui n’exécute que ses propres scripts. Le HTML brut de la présentation suit la liste d’autorisation de Marp, comme slides le fait par défaut. Un rendu qui dure plus de 5 secondes (un gabarit qui boucle) est interrompu.

La fenêtre du présentateur conserve ce bac à sable. Elle est ouverte par le Playground lui-même et affiche la présentation dans une iframe isolée de la même façon. Les deux iframes ne peuvent pas partager de stockage : le Playground relaie donc le numéro de diapositive de l’une à l’autre par messages. Aucun cadre qui exécute la présentation ne reçoit l’origine du Playground.

Les médias du projet parviennent aux cadres isolés sous forme d’octets dans un message, et chaque cadre en fait ses propres URL blob:, dans sa propre origine. Une URL blob: créée par le Playground ne s’y charge pas, et la politique des cadres n’ajoute que blob: pour les médias et les polices.

Le Playground peut être servi depuis votre propre machine, derrière une authentification : voir Auto-hébergement.

Taille et vitesse

Le module pèse 8,8 Mio tel que GitHub Pages le sert (gzip ; Pages ne sert pas de brotli). Il est téléchargé une fois avec une barre de progression, puis mis en cache par le navigateur jusqu’au prochain déploiement. Sur un Apple M4 Max avec Chrome 155, mesuré sur la page en ligne, l’éditeur est prêt 2,1 s après l’ouverture de la page, dont 1,5 s de téléchargement, et les premières diapositives apparaissent à 2,4 s. Une modification de la présentation de référence de 100 diapositives atteint l’aperçu en 30 ms environ : go-slides ne rend que les diapositives qui ont changé, et seules celles-ci sont remplacées dans l’aperçu.

Créée le par tannevaled

Modifiée le par tannevaled