#+title: Domain Specific sLIDEs #+author: Positron #+email: contact@positron.solutions * Start 1. Run =M-x= ~dslide-deck-start~. 2. Press the right arrow key ➡️ ** Controls :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-item-reveal :END: See the ~dslide-mode-map~ but basically, arrow keys. - right arrow ➡️ ~dslide-deck-forward~ - left arrow ⬅️ ~dslide-deck-backward~ - up arrow ⬆️ ~dslide-deck-start~ (contents) - down arrow ⬇️ ~dslide-deck-stop~ *** Contents View :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-item-reveal :END: After a presentation is started, up arrow ⬆️ goes to the contents view. Inside the contents view: - up arrow ⬆️ goes back to the slides - down arrow ⬇️ will quit the presentation - left arrow ⬅️ navigates to previous root heading - right arrow ➡️ navigates to the next root heading * Follow Along This presentation is shown in an *indirect buffer*. See the mode line. The buffer name should be =deck: demo.org= or something similar. Split the window =C-x 3= or ~split-window-right~ and switch to the base buffer, =demo.org= When you advance with ~dslide-deck-forward~, you can see the presentation's progress point highlighted in the base buffer. This makes it easier to debug babel blocks and other actions. You can start the presentation this way by using ~dslide-deck-develop~ instead. ** Progress Highlights Be sure to customize the faces used for highlighting progress and babel block execution: - ~dslide-highlight~ - ~dslide-babel-sucess-highlight~ - ~dslide-babel-fail-highlight~ You probably want to define these in your theme, using ~set-face-attribute~. * Inline Children :PROPERTIES: :DSLIDE_SLIDE_ACTION: dslide-slide-action-inline :END: - You won't believe these animations - This is the world's greatest presentation software + But mainly because it integrates with all you programming tools ** Pen 🖊️ Information, you have to breathe it in ** Pineapple 🍍 Isn't this animation so cool? ** Apple 🍎 This is a reason to be alive ** Pen 🖊️ [[https://www.youtube.com/watch?v=Ct6BUPvE2sM][In case you live under a rock]] * Breadcrumbs This information goes deep. To customize breadcrumb appearance, check out ~dslide-breadcrumb-face~. ** Deep And it will go deeper still yet *** Deeper The rabbit hole has only the bounds of your imagination **** Deepest? Wow, these breadcrumbs are very high-carb ***** Okay Deep Enough! How many levels of headings could there be? * Flat Slide :PROPERTIES: :DSLIDE_SLIDE_ACTION: dslide-slide-action-flat :END: This slide shows its child headings inline. - The slide action shows the entire contents, not just the section - There is no child action ** Blue Team - Has to do all the work - Must create an air-tight submarine ** Red Team - Uses some metasploit and calls it a day - Failure is an option * Every Child :PROPERTIES: :DSLIDE_SLIDE_ACTION: dslide-slide-action-every-child :END: This is not a test, but a testament to excellence. Note that the item reveal in the child slides is configured with =:inline t= automatically. ** Pen-Pineapple 🖊️🍍 :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-item-reveal :END: - Pen 🖊 is an office utensil used to sign documents - Pineapple is an office utensil used to enhance the water cooler - Long-pen 🖊🖊 is an office utensil that connects fruit ** Apple-Pen 🍎🖊️ :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-item-reveal :END: - Apple is a fruit that grows on a tree - Pen 🖊 is a fruit that grows on paper - Apple-pineapple is a fruit grows on a tree made out of paper * Reveal Items :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-item-reveal :END: Positron is deeply committed to bringing you the finest in: - Pen 🖊️ - Pineapple 🍍 - Apple 🍎 - Pen 🖊️ * Image Slides :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-image :END: - The action will automatically turn on inline images so you don't have to remember to run ~org-toggle-inline-images~. - The image buffer is configured to act as a slide, so it still responds to the keybindings. - See more options, such as fullscreen etc by calling ~describe-symbol~ on ~dslide-action-image~ #+ATTR_HTML: :width 45% [[./images/emacsen4.jpeg]] [[./images/self-care5.jpeg]] #+ATTR_HTML: :width 45% [[./images/before-google3.jpeg]] [[./images/all-software-is-the-same-with-tang.jpeg]] * No Header Slide :PROPERTIES: :DSLIDE_SLIDE_ACTION: dslide-slide-action-child :header nil :END: - The content and heading are still displayed - The slide-in effect still works - But there is no title or other header information - See more options in the ~dslide-action-narrow~ class slots: =M-x describe-symbol dslide-action-narrow= * Markup Hiding See ~dslide-hide-markup-types~. By default, property drawers, comments, comment blocks, and keywords are hidden with overlays. #+begin_comment You can't see this during the presentation. Convenient for reminding yourself to say something but not including it in the presentation. #+end_comment There is a comment block above this paragraph. There is a comment below this paragraph. Neither are visible when using the defaults. # There is a comment after this paragraph too. This is another case where you can use ~dslide-deck-develop~ to see the comments while showing just presentation content in another window. (use ~make-frame~ 💡) * Babel Integration :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-babel :END: To make your blocks interactive, set the =:DSLIDE_ACTIONS:= property to =dslide-action-babel= in the property drawer. #+begin_src elisp (message "By default, a block is just a forward step.") #+end_src ** Forwards & Backwards - Blocks can be marked with the =#+attr_dslide:= affiliated keyword to execute in a certain order. (unmarked default is forward) - Blocks can be marked =forward=, =backward=, or =both= to run via ~dslide-deck-forward~ or ~dslide-deck-backward~. - The markup keywords are hidden during presentation by default. Use ~dslide-deck-develop~ to see both markup and presentation simultaneously. (Executed blocks are highlighted! 💡) - Note, if there is no =backward= block, when entering the slide going backward, the slide will begin as if going forward because there is no backward step. *** Example :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-babel :END: #+attr_dslide: backward #+begin_src elisp ;; Called when going backward (random 100) #+end_src # using the default behavior, going forward #+begin_src elisp ;; Unmarked blocks will run going foward (random 100) #+end_src #+attr_dslide: both #+begin_src elisp ;; Called when going either way (random 100) #+end_src #+attr_dslide: forward #+begin_src elisp ;; An explicitly forward marked block (random 100) #+end_src ** Begin, End, and Final If you need to initialize some code, the =begin= and =end= methods can be used. To clean up, use a =final= block. Enter this slide going backwards to observe the "end" behavior. *** Example :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-babel :END: #+attr_dslide: begin #+begin_src elisp (setq-local my-dslide-var 'beginning) #+end_src #+attr_dslide: both #+begin_src elisp (message "Entered slide at: %s" my-dslide-var) #+end_src #+attr_dslide: end #+begin_src elisp (setq-local my-dslide-var 'end) #+end_src #+attr_dslide: final #+begin_src elisp (kill-local-variable 'my-dslide-var) #+end_src ** Reusing Blocks Multiple blocks can have the =begin=, =end=, and =final= method. They are always executed top to bottom. These blocks can be shared among blocks marked =forward=, =backward=, and =both=. This allows better code re-use. Go 2-3 steps forwards and then backwards. This slide also supports starting at the end. Just go to the next slide and back up. *** Example :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-babel :END: #+attr_dslide: begin end #+begin_src elisp :results none (setq-local overlays nil) (goto-char (point-min)) (while (re-search-forward "overlay" nil t) (let ((overlay (make-overlay (match-beginning 0) (match-end 0)))) (push overlay overlays))) #+end_src #+attr_dslide: backward #+begin_src elisp :results none (mapc (lambda (o) (overlay-put o 'display nil)) overlays) #+end_src #+attr_dslide: both #+begin_src elisp :results none (mapc (lambda (o) (overlay-put o 'display "🥞")) overlays) #+end_src #+attr_dslide: both #+begin_src elisp :results none (mapc (lambda (o) (overlay-put o 'display "🥞🥞")) overlays) #+end_src #+attr_dslide: forward end #+begin_src elisp :results none (mapc (lambda (o) (overlay-put o 'display "🥞🥞🥞")) overlays) #+end_src #+attr_dslide: final #+begin_src elisp :results none (mapc #'delete-overlay overlays) (makunbound 'overlays) #+end_src ** Hiding Blocks :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-babel :END: The babel block header argument =exports= is recognized and controls visibility of the block and its results. The babel blocks in this slide are not visible at all. The blocks find and updates the text below: Can has display? Try forwards and backwards. There are several hidden steps. ⚠️ This example also uses =:results none=, not because they would be visible, but because the return type is an overlay that babel can't serialize as output. #+attr_dslide: end begin #+begin_src elisp :exports none :results none ;; No need to deal with restriction or restore point. (org-back-to-heading t) (if (re-search-forward "\?" nil t) (setq-local dslide-can-has-overlay (make-overlay (match-end 0) (match-end 0))) (error "Ouchie, the document changed!")) #+end_src #+attr_dslide: backward #+begin_src elisp :exports none :results none (overlay-put dslide-can-has-overlay 'after-string nil) #+end_src #+attr_dslide: both #+begin_src elisp :exports none :results none (overlay-put dslide-can-has-overlay 'after-string (propertize " No display! Only execute!" 'face 'error)) #+end_src #+attr_dslide: forward end #+begin_src elisp :exports none :results none (overlay-put dslide-can-has-overlay 'after-string (propertize " No display! Only execute!" 'face 'success)) #+end_src #+attr_dslide: final #+begin_src elisp :exports none :results none (when (bound-and-true-p dslide-can-has-overlay) (delete-overlay dslide-can-has-overlay) (makunbound 'dslide-can-has-overlay)) #+end_src ** Results Only :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-babel :END: The babel in this block will show results after being called but the block itself is never visible. #+begin_src elisp :exports results '(a b c) #+end_src ** Silent Results :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-babel :END: For blocks you want to be visible but are only running for effects, you can use the built-in babel block header argument =results= and set it to =none= #+attr_dslide: both #+begin_src elisp :results none (let* ((block (org-element-at-point)) (overlay (make-overlay (org-element-property :begin block) (org-element-property :end block)))) (overlay-put overlay 'face '(:inverse-video t)) (setq-local dslide--example-overlay overlay)) #+end_src #+attr_dslide: final #+begin_src elisp :results none :exports none (when (bound-and-true-p dslide--example-overlay) (delete-overlay dslide--example-overlay) (makunbound 'dslide--example-overlay)) #+end_src ** Package Integration :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-babel :END: - You need the ~master-of-ceremonies~ package installed to complete this slide. Use the contents navigation to skip this slide if you didn't install it. - Let arbitrary buffers be shown while still completing steps within the slide-show. - Run babel against other buffers 😈. #+attr_dslide: begin #+begin_src elisp :results none (require 'master-of-ceremonies) #+end_src #+attr_dslide: final backward #+begin_src elisp :results none (when-let ((buffer (get-buffer "*MC Focus*"))) (kill-buffer buffer)) #+end_src #+attr_dslide: both #+begin_src elisp :results none (mc-focus "🖊️") #+end_src #+attr_dslide: both #+begin_src elisp :results none (mc-focus "🖊️🍍") #+end_src #+attr_dslide: both #+begin_src elisp :results none (mc-focus "🖊️🍍🍎") #+end_src #+attr_dslide: both #+begin_src elisp :results none (mc-focus "🖊️🍍🍎🖊️") #+end_src ** Babel is every Feature :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-babel :END: If a feature seems like it's missing, it can probably be added. There is a babel block below this paragraph, but if you are viewing this presentation, you won't see it because it has hidden itself with an overlay. File an issue, but don't be held back. A quick hunk of [[info:elisp#Top][elisp]] can solve every problem. #+attr_dslide: begin end #+begin_src elisp :results none (let* ((block (org-element-at-point)) (overlay (make-overlay (org-element-property :begin block) (org-element-property :end block)))) (overlay-put overlay 'display "") (push overlay dslide--overlays)) #+end_src * Customization View customize variables by calling =M-x customize-group RET dslide= ** Slide Actions Slide actions are configured using the heading's property drawer. ** Steezing Org The setup used for the Positron's YouTube demos is not much more complex than this well-documented setup by [[https://systemcrafters.net/emacs-tips/presentations-with-org-present/][System Crafters]]. Also see Prot's [[https://protesilaos.com/codelog/2020-07-17-emacs-mixed-fonts-org/][further]] documentation on customizing org mode faces and fonts. In short, use: - ~org-modern~ - ~org-appear~ - ~nerd-icons~ for more cheesy (Emacs logo) - And set the faces for org headings and document title. Don't forget built-in ~emoji-search~ and searching ~insert-char~. Positron is cheating and also apply custom line-spacing and line-height. While Psionic maintains a custom ~org-modern~, using custom spacing everywhere fights with ~visual-line-mode~ currently. ** Bindings Bind the command ~dslide-deck-start~ in the ~org-mode-map~. Any key will do. ** Custom Actions :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-babel :END: The babel block below is a custom action supporting both forward, each step making a paragraph red when going forward or removing the red when going backward. Key methods you want to use in your custom actions: - ~dslide-section-next~ - ~dslide-section-previous~ - ~dslide-section-marker~ #+attr_dslide: begin end #+begin_src elisp elisp :results none (defclass dslide-action-red-paragraphs (dslide-action) ((overlays :initform nil)) "Paint the paragraphs red, one by one.") ;; Default no-op `dslide-begin' is sufficient ;; Default implementation of `dslide-end', which just plays forward to the end, ;; is well-behaved with this class. ;; Remove any remaining overlays when calling final. (cl-defmethod dslide-final :after ((obj dslide-action-red-paragraphs)) (mapc #'delete-overlay (oref obj overlays))) ;; Find the next paragraph and add an overlay if it exists (cl-defmethod dslide-forward ((obj dslide-action-red-paragraphs)) (when-let ((paragraph (dslide-section-next obj 'paragraph))) (let* ((beg (org-element-property :begin paragraph)) (end (org-element-property :end paragraph)) (new-overlay (make-overlay beg end))) (overlay-put new-overlay 'face 'error) (push new-overlay (oref obj overlays)) ;; Return non-nil to indicate progress was made. This also informs the ;; highlight when following the slides in the base buffer. beg))) (cl-defmethod dslide-backward ((obj dslide-action-red-paragraphs)) (when-let* ((overlay (pop (oref obj overlays)))) (delete-overlay overlay) ;; If there is a preceding overlay, move to its beginning else move to the ;; beginning of the heading. (if-let ((overlay (car (oref obj overlays)))) (dslide-marker obj (overlay-start overlay)) (dslide-marker obj (org-element-property :begin (dslide-heading obj)))))) #+end_src *** Custom Action Demo :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-red-paragraphs :END: Massachusetts, in particular, has always been one of the laboratories of democracy. It's where people try things before they're popular. It's where we experiment. Democracy depends on an informed citizenry and the social cohesion that those citizens can show even when they disagree. The essence of democracy is the resolve of individuals working together to shape our institutions and our society in ways that allow all of us to flourish. * Enjoy! - This package use used to create videos on Positron's own [[https://www.youtube.com/channel/UCqM0zDcFNdAHj7uQkprLszg/][YouTube ]] channel - File issues and request features to give us ideas about usage and need - To participate in our effort to accelerate Emacs into this upcoming era of change, become a contributor one of our [[https://github.com/sponsors/positron-solutions][Github Sponsors]].