#+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 :standalone-display t :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 full-frame 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]] ** Centered Image This example uses org's built-in support for displaying images in the buffer, which double as HTML export settings. The source is in this slide is very simple. #+attr_html: :width 50% :align center [[./images/elpaca.jpg]] Elpaca is an outstanding package manager. ** Standalone Image :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-image :slide-display nil :standalone-display t :END: You can show images without them being visible on the slide. A way to achieve a similar effect is to have a child heading with no slide action and only images. # The attr_html line below is just for convenience while editing and doesn't affect the presentation. #+ATTR_HTML: :width 50% [[./images/yuki-o-yak.jpeg]] ** Reveal Images :PROPERTIES: :DSLIDE_ACTIONS: dslide-action-image :slide-display reveal :standalone-display nil :END: Reveal a series of images, like bullet points, but where each one is worth a thousand words. #+ATTR_HTML: :width 22% [[./images/representation.png]] [[./images/independence.png]] [[./images/consistent.png]] [[./images/accountability.png]] * 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~ 💡) ** TODO Todos and Tags :tag1:tag2:tag3: Todos and tags are by default hidden. Set ~dslide-hide-tags~ and ~dslide-hide-todos~ if you need them visible in a presentation. * Fancy Text Add text properties to an element using the =attr_dslide_propertize= affiliated keyword. No quoting is required. Lists will be interpreted as such. #+attr_dslide_propertize: face '(:background "#ddddff" :foreground "#000000" :weight bold :height 1.5) This is some fancy text * Babel Integration By default, blocks will run as steps. #+begin_src elisp (message "By default, a block is just a forward step.") #+end_src You may want to set ~org-confirm-babel-evaluate~ to =nil= to avoid being asked at every block during a presentation. To only set this for dslide presentations, use the ~dslide-start-hook~. To set it per-file, use a file-local variable, liket his demo does at the end. ** Forwards & Backwards - The direction of a block can be set using the =:direction= parameter, the same as other babel block parameters - 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 #+begin_src elisp :direction backward ;; 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 #+begin_src elisp :direction both ;; Called when going either way (random 100) #+end_src #+begin_src elisp :direction forward ;; An explicitly forward marked block (random 100) #+end_src ** Begin, End, Init, and Final If you need to initialize some code, the =begin= and =end= methods can be used. They run when entering the slide going forwards or backwards, respectively. To run when entering the slide either way, use =init=. It is just a combination of =begin= and =end=. To clean up, use a =final= block. It always runs when leaving a slide. *** Example Enter this slide going backwards to observe the "end" behavior. #+begin_src elisp :direction begin (setq-local my-dslide-var 'beginning) #+end_src #+begin_src elisp :direction both (message "Entered slide at: %s" my-dslide-var) #+end_src #+begin_src elisp :direction end (setq-local my-dslide-var 'end) #+end_src #+begin_src elisp :direction final (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 #+begin_src elisp :results none :direction init (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 #+begin_src elisp :results none :direction backward (mapc (lambda (o) (overlay-put o 'display nil)) overlays) #+end_src #+begin_src elisp :results none :direction both (mapc (lambda (o) (overlay-put o 'display "🥞")) overlays) #+end_src #+begin_src elisp :results none :direction both (mapc (lambda (o) (overlay-put o 'display "🥞🥞")) overlays) #+end_src # Use vector syntax [like this] or quoted list syntax '(like this) to provide # multiple directions #+begin_src elisp :results none :direction [forward end] (mapc (lambda (o) (overlay-put o 'display "🥞🥞🥞")) overlays) #+end_src #+begin_src elisp :results none :direction final (mapc #'delete-overlay overlays) (makunbound 'overlays) #+end_src ** Hiding Blocks 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. #+begin_src elisp :exports none :results none :direction init ;; 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 #+begin_src elisp :exports none :results none :direction backward (overlay-put dslide-can-has-overlay 'after-string nil) #+end_src #+begin_src elisp :exports none :results none :direction both (overlay-put dslide-can-has-overlay 'after-string (propertize " No display! Only execute!" 'face 'error)) #+end_src # Use vector syntax [like this] or quoted list syntax '(like this) to provide # multiple directions #+begin_src elisp :exports none :results none :direction '(forward end) (overlay-put dslide-can-has-overlay 'after-string (propertize " No display! Only execute!" 'face 'success)) #+end_src #+begin_src elisp :exports none :results none :direction final (when (bound-and-true-p dslide-can-has-overlay) (delete-overlay dslide-can-has-overlay) (makunbound 'dslide-can-has-overlay)) #+end_src ** Results Only 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 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= #+begin_src elisp :results none :direction both (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 #+begin_src elisp :results none :exports none :direction final (when (bound-and-true-p dslide--example-overlay) (delete-overlay dslide--example-overlay) (makunbound 'dslide--example-overlay)) #+end_src ** Package Integration - You need the [[https://github.com/positron-solutions/moc][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 😈. # Master of Ceremonies remains in development. The :version keys for playback # expressions may be updated when you find this demo. #+begin_src elisp :results none :direction begin (require 'moc) #+end_src #+begin_src elisp :results none :direction [final backward] (when-let ((buffer (get-buffer "*MoC Focus*"))) (kill-buffer buffer)) #+end_src #+begin_src elisp :results none :direction both (moc-focus :version 0 :text "🖊️") #+end_src #+begin_src elisp :results none :direction both (moc-focus :version 0 :text "🖊️🍍") #+end_src #+begin_src elisp :results none :direction both (moc-focus :version 0 :text "🖊️🍍🍎") #+end_src #+begin_src elisp :results none :direction both (moc-focus :version 0 :text "🖊️🍍🍎🖊️") #+end_src ** Babel is every Feature 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. #+begin_src elisp :results none :direction init (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 ** Babel to Call Processes Not everything can be displayed within Emacs. However, Emacs launches processes with ease. Let's use babel to take advantage of this. The babel block below, which is not visible during the presentation, will call VLC to show the video. VLC supports some options that make it convenient to integrate into our slideshow without interacting with its window, but if you are using EXWM or the application exposes a local interface such as DBus or a network socket, you can control it that way. #+begin_src elisp :results none :direction forward (if-let ((vlc (executable-find "vlc")) (output (generate-new-buffer "*VLC Output*"))) (progn (shell-command "vlc --no-video-title-show --fullscreen\ ./video/prizeforge-animated-logo.mp4 --play-and-exit --video-on-top" output) (kill-buffer output)) (error "VLC is not installed. How have you surived this long?")) #+end_src * Skipping Headings You can quickly skip slides that won't work for you presentation by adding COMMENT right after the stars. The default filter function, ~dslide-built-in-filter~ will skip them. You can define your own filter function by setting ~dslide-default-filter~. Child actions and the contents view respect these settings. ** COMMENT Half-Baked Slide This slide will not be visible in the presentation because it is commented. Good for skipping slides that only work in some settings or ones you only half-finished right before showtime. * 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 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~ #+begin_src elisp :results none :direction init (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. * Keyboard Macros /New feature!/ You can play back keyboard macros. Check the Dslide manual. =M-x info-display-manual dslide=. There is a new command called ~dslide-kbd-macro-mark-set~ that will transcribe macros whenever you finish recording one. Each macro will be a step in the presentation. Pretty gnarly, dude. 🐢 ** Keyboard Macro Example ✨ Press ➡️ to run the (invisible) recorded macro 🤠. # M-x animate-birthday-present dslide #+dslide_kmacro: :frequency 0.09 :jitter 0.4 :keys "M-x a n i m a t e - b i r t h d a y - p r e s e n t d s l i d e " 🚧 Please try this feature. Open issues. Keep in mind that keyboard macros are not very reproducible. They likely only work on your configuration. It is a great way to demonstrate using your shell etc while not having to type. 💡 # If the user has M-x remapped, we should at least warn them. #+begin_src elisp :direction init :exports none :results none (unless (or (eq (key-binding (kbd "M-x")) #'execute-extended-command) (eq (command-remapping 'execute-extended-command) (key-binding (kbd "M-x")))) (org-back-to-heading) (re-search-forward "🤠." nil t) (let ((o (make-overlay (1- (point)) (point)))) (overlay-put o 'after-string (propertize " ⚠️ Your M-x appears remapped! Press ⬆️ and skip this example." 'face 'warning)) (push o dslide-overlays))) #+end_src # Clean up the buffer if it was created #+begin_src elisp :direction final :exports none :results none (when-let ((birthday (get-buffer "*A-Present-for-Dslide*"))) (kill-buffer birthday)) #+end_src * 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]]. # Local Variables: # org-confirm-babel-evaluate: nil # End: