Presentation Application Presentation

Hello, my name is Dmitry Karlovsky and I sometimes speak at conferences, meetings, and also recently I myself enter the team of organizers of one of them - PiterJS . Recently, we had an anniversary - 40 meetings held. But instead of relaxing and receiving congratulations, we got tired and ourselves prepared reports from the organizers .







Testing voice control







But this is not enough for us, so we decided to celebrate a big anniversary by organizing a conference on the banks of the Neva PiterJSConf , which will be held this Saturday, September 7, 2019. Hurry to sign up, while there are still vacant seats, because participation in it will be completely free for you.







We do all this not for money, but for the great idea that knowledge should be free. Therefore, everything we do is available in Open Source . We are happy to share our best practices, knowledge and experience with others. And we urge the cooperation of organizers from other cities to create an open platform for organizing technological meetings on a regular basis. Join us as an organizer , partner , speaker , volunteer , patron or just a listener.







In the meantime, I offer you a story about the $hyoo_slides



presentation web application that I use for all my presentations. Video recording is available on YouTube , but not everything is there. You can read this story as an article , or open it in the interface of the application itself . Next I will tell you how much it can do and how it works.







Listener interface



Listening Presentation







Here is the interface that the audience sees during the performance. There is nothing superfluous in it.







The name and number of the slide are displayed at the top. Listeners may have questions. And quickly recording this number, they will be able to name it after the speech and thereby save the audience from tedious waiting, when the speaker will find a slide on which the question is being asked.







Below you can pay attention to the progress bar, showing late listeners how much they missed. And to everyone else - how much is left to the end. It is calculated not by the number of slides, but by the volume of the narrated speech.







Look how i can



The basic idea is to let the speaker concentrate on the content and not worry about the design. The report does not need any special beauties and spectacular animations at all. Otherwise, the design will draw attention to itself. And the content runs the risk of flying past ears.







Because I'm Batman!







But the design should nevertheless be neat so as not to spoil the impression of the report. Therefore, the application design is simple, not catchy, and, most importantly, consistent with the recommendations of program committees.







Speaker Interface



The speaker's interface is divided into two parts.







Presenter Presentation







On the left is what listeners see. And on the right are the speaker’s notes. They will help you remember a lost thought, without turning away from the audience and without straining them for a long ... um ... this is ... a pause.







The main thing is content



Therefore, in our case, the content is written as an article in MarkDown format and laid out on some GitHub Pages. And the web application takes care of the rest.







 #       #      
      
      





After the speech, the text transcript of the report is often laid out in the form of an article on some Habré . They can do it for a month, two, half a year. The task is an ungrateful translation of speech into text. But, due to the fact that the source of the slides is already in markdown format and contains the speaker’s comments, they can be immediately published in this form.







Text styles



Plain text is displayed only to the presenter. And all sorts of pictures, lists, tables, quotes, etc. are visible to everyone.







 - ** - ** ** - ~~~~ - ``````
      
      







Of course, various inline formatting tools are available.







Source code



Blocks of source code, of course, are also supported, and are painted in all colors of the rainbow. Just as you like.







 ```javascript const hello = ()=> <body> Hello, "world"! </body> ```
      
      





 const hello = ()=> <body> Hello, "world"! </body>
      
      





Tables



Comparison of various pieces will help you tables. For example, let's see why $hyoo_slides



better than its closest competitors - shwr.me and google slides







 | | shwr.me | google slides | slides.hyoo.ru | |--------------------------|---------|---------------|----------------| |   MarkDown | - | - | + | |   | - | + | + | |   | - | - | + | |  | - | + | + |
      
      





shwr.me google slides slides.hyoo.ru
Source in MarkDown - - +
Dual panel mode - + +
Auto slide switch - - +
Offline - + +


As you can see, $hyoo_slides



beats competitors on all fronts. Except for those that are not included in the table, of course.







Well lano, tables are boring.







Pictures



Hold the cat.







 ![](https://github.com/nin-jin/slides/raw/master/slides/cat.gif)
      
      





Cat







Notice that the background of the slides is slightly gray. Therefore, it is better to prepare images not on a white background, but with transparency so that there is no unpleasant white rectangle around the pictures. This is done so that the white areas look in contrast, and do not merge with the background.







Video



You can post videos, web pages and any other external content using the same MarkDown syntax as for inserting pictures.







 ![ ](https://www.youtube.com/embed/exfBX2pb7AQ?autoplay=1)
      
      





Target Audience







For example, I inserted a video illustrating that modern interfaces are so simple and convenient that even a monkey can handle them.







Keyboard navigation



You can switch slides with arrows on the keyboard. But in order not to be tied to a laptop, but to walk freely around the stage, a radio extension cord is useful for you. He is a clicker.







Arrows







But what if the clicker is broken?







Code Phrases



You probably think that in the hall here somewhere I have a mishandled Cossack who switches slides instead of me? However, it is not.









Please repeat. A voice from above repeats the last phrase.







Yes, slides can completely control the voice, leaving your hands free for gestures. It uses standard web api for voice recognition and synthesis.







But repeating these code phrases ten times in a row is boring, so $hyoo_slides



can analyze the speaker’s notes and, when you say the last word, switch the slide automatically.







Finger gestures



Okay, complicating the situation. Someone after listening to your speech, decided to see your slides from the tablet while riding home on the subway.







Gestures







There is no keyboard. The trains are noisy. Here, ordinary finger gestures come to the rescue.







Offline



But then he drives into the tunnel and his connection disappears.







No network







It doesn’t matter, we have Web2.0 HTML5 Progressive Web Application with full functionality even when there is no Internet.







PDF printing



But here the organizers come up to you and say: "We want a PDF."







Imprint







Which pdf? We have here a multimedia interactive Web2.0 HTML5 Progressive Web Application. However, they explain to you that the application is today, and tomorrow it is no longer there. And if there is, he wants money. And if you don’t want to, then the slides there can already be changed beyond recognition. And PDF is quietly in the archive with exactly the content that corresponds to the video recorded during the performance.







Well, it doesn’t matter, press Ctrl+P



, select "Print to PDF" and get what you need. This is done simply - the onbeforeprint



event is onbeforeprint



and, when it occurs, instead of just the current slide, all slides are rendered at all. And onafterprint



, all but the current one, the slides are deleted.







On this, the feature lists are now over.







How to create a presentation



Trying $hyoo_slides



really easy. You will need readme.md



with your content and pictures. Also nearby you will need to paste index.html



, which redirects to the web application and opens your presentation in it. And also offline.js for offline support.









Keep in mind that this index.html



will give the application any files that are accessible from the domain where you put the whole thing. GitHub Pages is a very convenient and safe option. I use it myself.







Other applications



If you liked this application, you can take a look at other interesting applications implemented on the $ mol framework. They are so lightweight that even a few dozen are not afraid to load them all at once on one slide.







Application gallery







But about them somehow later ...







Presentation Examples



You can learn more about the framework at a separate presentation. You can dig deeper in a presentation on the PPR. And you can lift the curtain of the future in a presentation on the quantization of computations.









They all use $ hyoo_slides to display. I hope soon there will be more such presentations.







Application structure



And now, let's open the hood a bit and see how the application is arranged, and how to make our own in just one evening.







 $hyoo_slides_page $mol_view sub / <= Listener <= Speaker
      
      





 export class $hyoo_slides_page extends $mol_view { sub() { return [ this.Listener() , this.Speaker() , ] } }
      
      





Here is a top-level description of a single screen in view.tree and equivalent TypeScript code. Here we declare the component $hyoo_slides_page



, which extends the base component of $mol_view



. This component has a sub



property. Everything that returns this property will be rendered inside the component. Therefore, we redefine it, passing as an value an array of two elements: Listener



- a component for outputting a slide to listeners and Speaker



- a component of an additional speaker panel.







Switch page layout



In addition to the description of the structure, we can also apply program logic that allows any properties to be calculated dynamically.







 sub() { const role = this.role() return [ this.Listener() , ... ( role === 'speaker' ) ? [ this.Speaker() ] : [] , ] }
      
      





Here the logic is simple: we always display slides for listeners, but the speaker panel is only shown if the current role is speaker



. If the role changes, then the layout of the application will also change due to the magic of object reactive programming.







Routing



We will take the role from the address parameter, through the special reactive API $mol_state_arg



.







 role() : 'speaker' | 'listener' { return $mol_state_arg.value( 'role' ) || 'speaker' }
      
      





For whatever reason the address has changed - the role will be extracted from it automatically, and passed through to this method.







Listener Interface Structure



Let's describe the listener interface.







 Listener $mol_page title <= title tools / <= Slide_switcher body / <= Listener_content <= Progress
      
      





It uses the standard component $mol_page



which draws a typical page with a header and a body. There is an area in the header where the page name is displayed. Through the title



property, you can specify what to output there. Which we did by associating its title



property with our property of the same name. Now, changing our property, we have full control over what will be displayed on the page as a title.







On the right in the header, there is an output area for additional tools - tools



. We Slides_switcher



- a component for displaying the slide number and switching between adjacent slides.







And finally, as the page body



in body



we display the contents of the slide and the progress bar.







Page Switch Structure



How to implement Slide_switcher



? Just use the standard component $mol_paginator



.







 Slide_switcher $mol_paginator value?val <=> slide?val
      
      





All he has is a mutable value



property, which we bilaterally associate with our property containing the number of the current slide. No imports, callbacks, events and other trash. These two lines are all that is necessary for a working page switch to appear on your page.







Slide content structure



To display the contents of the slide, we again use the standard component $mol_text



.







 Listener_content $mol_text uri_base <= uri_base text <= listener_content
      
      





It takes markdown



and renders it. Since the links in this text will be relative to the source file, and not to our application, we pass the link to the uri_base property, regarding which all paths will resolve.







Progress Indicator Structure



As you may have already guessed, there is also a standard component for displaying progress - $mol_portion



.







 Progress $mol_portion portion <= progress
      
      





 portion: [ 0 .. 1 ]
      
      





We feed him a number from 0 to 1 and get an indicator filled for this share.







Speaker Interface Structure



We have something more interesting in the speaker’s interface. The tools displayed in the header are not attached to the current page in any way - they are common to the entire application. Therefore, instead of hardcoding them here, we will only place the speaker_tools



slot through which we will transfer the list of components from the outside.







 Speaker $mol_page head <= speaker_tools /$mol_view body / <= Speaker_content
      
      





Application structure



Now go up a level and create an application component $hyoo_slides



that uses the page component.







 $hyoo_slides $mol_view Page!index $hyoo_slides_page - ... plugins / <= Nav <= Touch <= Speech_next - ...
      
      





Any $mol_view



component has a plugins



property through which additional logic can be connected to it. Plugin plugins live on the same DOM node as the component itself. The component initiates them during its rendering. And when about ceases to be rendered - plugins are destroyed automatically.







We also announced the Page



property, which for each index returns a separate instance of the $hyoo_slides_page



component we developed earlier.







External page setup



 Page!index $hyoo_slides_page role <= role slide?val <=> page_slide!index?val speaker_tools / <= Speech_toggle <= Speech_text <= Open_listener
      
      





We pass the role



property to the subcomponent as is. The slide



property of the page component is connected by two-way communication with the page_slide



property of the application. Please note that page_slide



accepts not only the optional new value, but also the page index. This allows you to return a number for each page. Finally, in the speaker_tools



slot we announced earlier, we put three components to help manage the slides.







Voice Control Switch Structure



We implement Speech_toggle



through the standard component $mol_check_icon



, which draws an icon. When you click on it, it toggles the checked



flag. And the current state is displayed by changing the color of the icon.







 Speech_toggle $mol_check_icon Icon <= Speech_toggle_icon $mol_icon_microphone checked?flag <=> speech_enabled?flag
      
      





We took the icon from the $mol_icon



, where out of 4000 icons made in the ascetic material design style, it is easy to find the right one.







Slave Window Opening Button Structure



Everything is simple here. This button will be the link $mol_link



. She can set the uri



property with an address, or she can do something more cunning and just patch the current address, replacing some parameters through arg



.







 Listener_open $mol_link target \_blank arg * role \listener slide null sub / <= Listener_open_icon $mol_icon_external
      
      





Here we erased the slide number from the address so that the slave window would take it from the local storage, and not from the address. This will ensure that the windows synchronize with each other. And also indicated that the role should be a "listener". Inside the link, we put an icon instead of text.







Plugins



Plugins can significantly expand the capabilities of the component. We will use them to the maximum.







 plugins / <= Nav <= Touch <= Speech_next <= Speech_prev <= Speech_start <= Speech_end - ...
      
      





All the plugins used by us can be divided into 3 categories: keyboard navigation, gesture control and voice control.







Keyboard navigation



Through $mol_nav



it is easy to implement keyboard navigation both vertically and horizontally. All that is needed is to provide the plug-in with a list of keys by which it will switch, and two-way communication to the current value.







 Nav $mol_nav keys_y <= slide_keys keys_x <= slide_keys current_y?val <=> slide?val current_x?val <=> slide?val
      
      





 slide_keys: [ 0 , 1 , 2 , 3 , ... , 30 ] ^ slide
      
      





Finger gestures



For finger tracking, there is a $mol_touch



. With it, you can zoom, pan and swipe. It is the last opportunity that interests us now.







 Touch $mol_touch swipe_to_left?event <=> go_next?event swipe_to_right?event <=> go_prev?event
      
      





 go_next( event? : Event ) { this.slide( this.slide() + 1 ) }
      
      





There are two types of swipe. For example, swipe left or right from any part of the screen and swipe due to the right or left edge of the screen towards the center. In the presented code, we hung our handlers on the first type of swipe.







Voice control



For voice control, use the $mol_speech



. It is necessary to create an instance of the plugin for each version of the action.







 Sing $mol_speech event_catch?val <=> sing?val patterns / \sing( \S+?)* \( \S+?)*
      
      





The plugin accepts an action handler and a set of patterns, upon detection of which, an event will be triggered. You can use capturing brackets in the patterns to get the words corresponding to their contents in the handler.







Auto slide switch



By default, $mol_speech



requires courteous handling. For example, you should say not “sing,” but “sing, please.” You can override the suffix



property to change or remove this codeword altogether.







 Speech_next_auto $mol_speech event_catch?val <=> go_next?val suffix \ patterns <= speech_next_auto_patterns
      
      





For example, to implement automatic slide switching, we do not need magic words. But we will generate a set of patterns dynamically, based on the analysis of the contents of the speaker’s text.







Application launch



Having an application component, you can instantiate it manually like any ordinary class. But we will use automatic launch through the special attribute mol_view_root



.







 <body mol_view_root="$hyoo_slides"> <script src="web.js" charset="utf-8"></script> </body>
      
      





The attribute name is the name of the component. Rendering in this way, of course, can be absolutely any component.







Offline



To add offline support, just include the mol/offline/install



module in the bundle.







 include \/mol/offline/install
      
      





It automatically raises a ServiceWorker, which caches all requests. And if the network is unavailable, it returns data from the cache. This is not the coolest implementation, but for simple cases when you do not want to bother, it will do.







Print mode



I said earlier that during printing you need to render all pages, but there’s no need to manually monitor onbeforeprint



and onafterprint



, because we have full-reactive programming, so we will use the reactive state $mol_print



, which gives us a reactive flag, which we can tie up rendering.







 sub() { if( !this.$.$mol_print.active() ) { return [ this.Page( this.slide() ) ] } return $mol_range2( index => this.Page( index ) , ()=> this.slide_keys().length , ) }
      
      





Here we return only one page if the active



flag is not raised. Otherwise, we return a lazy array that calculates its length and elements according to the given formulas.







Epilogue



As a result, we got a modern web application with a bunch of functionality and a weight of only 35kb. Add manifest and there will be a full-fledged Progressive Web Application. Of course, many details were not considered. You can see them in the code on the github. For all questions, write telegrams in chat.







These slides are in the app: slides.hyoo.ru

Application sources: hyoo-ru / slides.hyoo.ru

Presentation examples: nin-jin / slides

Telegram chat: @mam_mol

I will be glad if you try to make your presentation with $hyoo_slides



. And I will be very happy if you help make it even better than it is now. Thanks for your attention!








All Articles