git ssb

1+

Matt McKegg / jsconfasia-talk-2016-livejs



Commit fdc99693d597db195828a60363373b6278be377f

updated for jsconf.asia 2016

Matt McKegg committed on 11/21/2016, 8:38:53 PM

Files changed

.gitignoreadded
README.mdadded
build.jsadded
heart.pngadded
images/jsconf.asia.pngadded
images/just-press-play.jpgadded
lib/markdown.jsadded
logo.pngadded
npm-debug.logadded
output.htmladded
package.jsonadded
slides.html.ejsadded
.gitignoreView
@@ -1,0 +1,1 @@
1 +node_modules
README.mdView
@@ -1,0 +1,91 @@
1 +# I make **music** with **computers**.
2 +
3 +💥~🤖~💥
4 +
5 +# I also make **_software_** to make **music** with **computers**.
6 +
7 +https://www.youtube.com/watch?v=01_udUeZ2GU
8 +
9 +# _Why would you do that?_
10 +
11 +# Playing computer music **live** is ... uh... _complicated_.
12 +
13 +> For most bands and musicians this is not a problem. If you are a guitarist, it makes no difference whether you are playing on stage or recording in a studio. In both cases, you are playing the guitar. In most cases with music, the album is just a recording of what the musicians would do anyway. The great thing about this is the musician can intuitively pick up on the feeling in the room and change the way the are playing to accommodate this. They might not even notice they're doing it. There is this amazing feeling that comes from a band jamming with each other, and vibing off the audience.
14 +
15 +> But this is not the case with most computer music. I was creating music on a timeline.
16 +
17 +### **Painted**, not played.
18 +
19 +[![](http://www.arsov.net/SoundBytes/Images/2014-03/Ableton-main.jpg)](https://www.youtube.com/watch?v=9SH4g4FHZHw)
20 +
21 +> This leaves only a few options.
22 +
23 +## _Option 1_: Recruit some musicians and **play it for real**!
24 +
25 +> This is actually something that would be a lot of fun, but it is not representative of my musical process. I'd be doing completely different things in the studio to what I'm doing on stage. It would be treating the album like a score, things would get very complicated very quick with the amount of sounds I use.
26 +
27 +[![](http://blogs.kcrw.com/musicnews/wp-content/uploads/2013/04/full-band-21-sm.jpg)](http://www.npr.org/event/music/185510193/james-blake-live-in-concert)
28 +
29 +## _Option 2_: **DJ it!** (_just press play..._)
30 +
31 +> The performance would be more like an exhibition, much like how a painter would present their work. But I don't find this very fun. I want to perform, share and be in the moment with the audience, able to easily adapt to the room vibe. Not just a boring and predictable exhibit.
32 +
33 +[![](images/just-press-play.jpg)](https://youtu.be/j6WY8L0wLTM?t=33)
34 +
35 +## _Option 3_: Play **everything** yourself!
36 +
37 +[![](http://www.freeweekly.com/wp-content/uploads/2014/10/HenryInvisibles.jpg)](https://www.youtube.com/watch?v=GIzq8-gSz-0)
38 +
39 +> https://www.youtube.com/watch?v=iHSMnWpyIeM
40 +
41 +> This was the option I wanted to go with. But my songs are already sequenced. How to go about destructuring and playing?
42 +
43 +> I had this crazy idea that I'd take my existing songs, and learn how to play all the individual parts and then build them up one loop at a time.
44 +
45 +### **Recording anxiety**
46 +
47 +[![](https://c1.staticflickr.com/1/58/168150955_40c7db0172_z.jpg?zz=1)](https://www.youtube.com/watch?v=q0HVo6M3w64)
48 +
49 +> I suffer from acute recording anxiety. This was always a problem. I’d be jamming away a cool riff, and it sounds awesome, then I hit record and my figures turn to jelly, and it comes out all wrong. I looked long and hard for a solution, but couldn't find anything reliable. It was time to build my own solution.
50 +
51 +## **Time travel** with Node.js
52 +
53 +> I created a Node.js script that allowed me more control over input, storing all MIDI in a buffer, and then allowing me to go back in time and create loops after I played them, along with some realtime loop transform controls.
54 +
55 +> In the process of trying to learn my songs, and failing kind of miserably, I managed to develop a lot of the core looping concepts that still exist in Loop Drop today.
56 +
57 +## _Previously on JSConf.asia_...
58 +
59 +[![](images/jsconf.asia.png)](https://www.youtube.com/watch?v=NL0nb8A8FDM)
60 +
61 +``youtu.be/NL0nb8A8FDM``
62 +
63 +## **Loop Drop** — loopjs.com
64 +
65 +[![](logo.png)](http://loopjs.com)
66 +
67 +>> [Play some tunes](https://www.youtube.com/watch?v=5zutWpFG8pk) and give a quick overview of how it works.
68 +
69 +>> Sample the audience and make a song!
70 +
71 +## Loop Drop is **JavaScript**!
72 +
73 +> Loop Drop is a desktop application that you can install on your computer. But it is actually 100% JavaScript! This is achieved using Electron (made by Github), which combines Node.js with Chromium giving you everything you'd ever want!
74 +
75 +Electron - **Chromium + Node.js**
76 +
77 +http://electron.atom.io
78 +
79 +# Contributing
80 +
81 +- github.com/mmckegg/loop-drop-app
82 +- patreon.com/MattMcKegg
83 +
84 +![](heart.png)
85 +
86 +# DESTROY WITH SCIENCE
87 +
88 +Loop Drop R&D **super secret\*** laboratory!
89 +
90 +- soundcloud.com/destroy-with-science
91 +- destroywithscience.bandcamp.com/album/droptivist
build.jsView
@@ -1,0 +1,11 @@
1 +var fs = require('fs')
2 +var ejs = require('ejs')
3 +var markdown = require('./lib/markdown')
4 +var additionalStyles = fs.readFileSync(require.resolve('highlight.js/styles/monokai.css'), 'utf8')
5 +var raw = fs.readFileSync('README.md', 'utf8')
6 +var template = ejs.compile(fs.readFileSync('slides.html.ejs', 'utf8'))
7 +
8 +fs.writeFileSync('output.html', template({
9 + body: markdown.render(raw),
10 + additionalStyles: additionalStyles
11 +}))
heart.png
heart.png
images/jsconf.asia.png
images/jsconf.asia.png
images/just-press-play.jpg
images/just-press-play.jpg
lib/markdown.jsView
@@ -1,0 +1,21 @@
1 +var hljs = require('highlight.js')
2 +var iterator = require('markdown-it-for-inline')
3 +
4 +module.exports = require('markdown-it')({
5 + linkify: true,
6 + highlight: function (str, lang) {
7 + if (lang && hljs.getLanguage(lang)) {
8 + try {
9 + return hljs.highlight(lang, str).value
10 + } catch (__) {}
11 + }
12 +
13 + try {
14 + return hljs.highlightAuto(str).value
15 + } catch (__) {}
16 +
17 + return ''
18 + }
19 +}).use(iterator, 'url_new_win', 'link_open', function (tokens, idx) {
20 + tokens[idx].attrPush([ 'target', '_blank' ])
21 +})
logo.png
logo.png
npm-debug.logView
@@ -1,0 +1,24 @@
1 +0 info it worked if it ends with ok
2 +1 verbose cli [ '/usr/local/bin/node', '/usr/local/bin/npm', 'start' ]
3 +2 info using npm@3.10.3
4 +3 info using node@v6.4.0
5 +4 verbose stack Error: missing script: start
6 +4 verbose stack at run (/usr/local/lib/node_modules/npm/lib/run-script.js:151:19)
7 +4 verbose stack at /usr/local/lib/node_modules/npm/lib/run-script.js:61:5
8 +4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:356:5
9 +4 verbose stack at checkBinReferences_ (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:320:45)
10 +4 verbose stack at final (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:354:3)
11 +4 verbose stack at then (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:124:5)
12 +4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:311:12
13 +4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:78:16
14 +4 verbose stack at tryToString (fs.js:455:3)
15 +4 verbose stack at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:442:12)
16 +5 verbose cwd /Users/matt/Code/jsconfasia-talk-2016-livejs
17 +6 error Darwin 15.6.0
18 +7 error argv "/usr/local/bin/node" "/usr/local/bin/npm" "start"
19 +8 error node v6.4.0
20 +9 error npm v3.10.3
21 +10 error missing script: start
22 +11 error If you need help, you may report this error at:
23 +11 error <https://github.com/npm/npm/issues>
24 +12 verbose exit [ 1, true ]
output.htmlView
@@ -1,0 +1,470 @@
1 +<!DOCTYPE html>
2 +<html lang='en'>
3 +<head>
4 + <meta charset="utf-8" />
5 + <title>Slides</title>
6 + <style>
7 + body, html {
8 + height: 100%;
9 + background: #222;
10 + margin: 0;
11 + font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
12 + overflow: hidden;
13 + color: #CCC;
14 + font-size: 40px;
15 + letter-spacing: 1px;
16 + }
17 +
18 + h1, h2, h3 {
19 + font-weight: normal;
20 + text-align: center;
21 + color: white;
22 + margin: 20px 0;
23 + max-width: 80%;
24 + }
25 +
26 + p {
27 + max-width: 80%;
28 + text-align: center;
29 + margin-bottom: 20px
30 + }
31 +
32 + p + p {
33 + margin-top: 20px
34 + }
35 +
36 + a {
37 + color: #ff8bef;
38 + text-decoration: none;
39 + font-weight: normal;
40 + }
41 +
42 + ul {
43 + max-width: 70%;
44 + }
45 +
46 + strong {
47 + color: white;
48 + }
49 +
50 + h1 strong {
51 + font-weight: normal;
52 + color: #6AFF00;
53 + }
54 +
55 + h2 strong {
56 + color: #FFB500;
57 + }
58 +
59 + h1 {
60 + font-weight: normal;
61 + font-size: 300%;
62 + }
63 +
64 + h2 {
65 + font-weight: normal;
66 + font-size: 200%;
67 + }
68 +
69 + img {
70 + max-height: 65vh;
71 + margin: -10px 0;
72 + }
73 +
74 + .coffeescript .javascript, .javascript .xml, .tex .hljs-formula, .xml .javascript, .xml .vbscript, .xml .css, .xml .hljs-cdata {
75 + opacity: 0.9 !important;
76 + }
77 +
78 + .Viewer {
79 + display: flex;
80 + flex-direction: column;
81 + align-items: center;
82 + height: 100%;
83 + justify-content: center;
84 + }
85 +
86 + .Viewer > * {
87 + display: none
88 + }
89 +
90 + .Viewer > .-active {
91 + display: block
92 + }
93 +
94 + .Viewer > blockquote {
95 + display: none !important
96 + }
97 +
98 + pre {
99 + min-width: 60%;
100 + max-height: 80%;
101 + overflow: auto;
102 + padding: 10px;
103 + background: #111;
104 + border: 1px solid #333;
105 + color: #DDD;
106 + }
107 +
108 + pre > code {
109 + display: block;
110 + font: 20px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
111 + padding: 10px;
112 + padding-bottom: 100px;
113 + }
114 +
115 + p code, ul code {
116 + padding: 0 10px;
117 + background: #111;
118 + color: #EEE;
119 + border: 1px solid #333;
120 + font: 80% 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
121 + }
122 +
123 + .Overlay {
124 + position: absolute;
125 + top: 20px;
126 + right: 20px;
127 + font-size: 90%;
128 + opacity: 0.8;
129 + }
130 +
131 + ::selection {
132 + background: #AAA;
133 + }
134 +
135 + /*
136 +Monokai style - ported by Luigi Maselli - http://grigio.org
137 +*/
138 +
139 +.hljs {
140 + display: block;
141 + overflow-x: auto;
142 + padding: 0.5em;
143 + background: #272822;
144 + -webkit-text-size-adjust: none;
145 +}
146 +
147 +.hljs-tag,
148 +.hljs-tag .hljs-title,
149 +.hljs-keyword,
150 +.hljs-literal,
151 +.hljs-strong,
152 +.hljs-change,
153 +.hljs-winutils,
154 +.hljs-flow,
155 +.nginx .hljs-title,
156 +.tex .hljs-special {
157 + color: #f92672;
158 +}
159 +
160 +.hljs {
161 + color: #ddd;
162 +}
163 +
164 +.hljs .hljs-constant,
165 +.asciidoc .hljs-code,
166 +.markdown .hljs-code {
167 + color: #66d9ef;
168 +}
169 +
170 +.hljs-code,
171 +.hljs-class .hljs-title,
172 +.hljs-header {
173 + color: white;
174 +}
175 +
176 +.hljs-link_label,
177 +.hljs-attribute,
178 +.hljs-symbol,
179 +.hljs-symbol .hljs-string,
180 +.hljs-value,
181 +.hljs-regexp {
182 + color: #bf79db;
183 +}
184 +
185 +.hljs-link_url,
186 +.hljs-tag .hljs-value,
187 +.hljs-string,
188 +.hljs-bullet,
189 +.hljs-subst,
190 +.hljs-title,
191 +.hljs-emphasis,
192 +.hljs-type,
193 +.hljs-preprocessor,
194 +.hljs-pragma,
195 +.ruby .hljs-class .hljs-parent,
196 +.hljs-built_in,
197 +.django .hljs-template_tag,
198 +.django .hljs-variable,
199 +.smalltalk .hljs-class,
200 +.django .hljs-filter .hljs-argument,
201 +.smalltalk .hljs-localvars,
202 +.smalltalk .hljs-array,
203 +.hljs-attr_selector,
204 +.hljs-pseudo,
205 +.hljs-addition,
206 +.hljs-stream,
207 +.hljs-envvar,
208 +.apache .hljs-tag,
209 +.apache .hljs-cbracket,
210 +.tex .hljs-command,
211 +.hljs-prompt,
212 +.hljs-name {
213 + color: #a6e22e;
214 +}
215 +
216 +.hljs-comment,
217 +.hljs-annotation,
218 +.smartquote,
219 +.hljs-blockquote,
220 +.hljs-horizontal_rule,
221 +.hljs-decorator,
222 +.hljs-pi,
223 +.hljs-doctype,
224 +.hljs-deletion,
225 +.hljs-shebang,
226 +.apache .hljs-sqbracket,
227 +.tex .hljs-formula {
228 + color: #75715e;
229 +}
230 +
231 +.hljs-keyword,
232 +.hljs-literal,
233 +.css .hljs-id,
234 +.hljs-doctag,
235 +.hljs-title,
236 +.hljs-header,
237 +.hljs-type,
238 +.vbscript .hljs-built_in,
239 +.rsl .hljs-built_in,
240 +.smalltalk .hljs-class,
241 +.diff .hljs-header,
242 +.hljs-chunk,
243 +.hljs-winutils,
244 +.bash .hljs-variable,
245 +.apache .hljs-tag,
246 +.tex .hljs-special,
247 +.hljs-request,
248 +.hljs-status {
249 + font-weight: bold;
250 +}
251 +
252 +.coffeescript .javascript,
253 +.javascript .xml,
254 +.tex .hljs-formula,
255 +.xml .javascript,
256 +.xml .vbscript,
257 +.xml .css,
258 +.xml .hljs-cdata {
259 + opacity: 0.5;
260 +}
261 +
262 +
263 + </style>
264 +</head>
265 +<body>
266 + <div class='Viewer'>
267 + <h1>I make <strong>music</strong> with <strong>computers</strong>.</h1>
268 +<p>💥~🤖~💥</p>
269 +<h1>I also make <strong><em>software</em></strong> to make <strong>music</strong> with <strong>computers</strong>.</h1>
270 +<p><a href="https://www.youtube.com/watch?v=01_udUeZ2GU" target="_blank">https://www.youtube.com/watch?v=01_udUeZ2GU</a></p>
271 +<h1><em>Why would you do that?</em></h1>
272 +<h1>Playing computer music <strong>live</strong> is ... uh... <em>complicated</em>.</h1>
273 +<blockquote>
274 +<p>For most bands and musicians this is not a problem. If you are a guitarist, it makes no difference whether you are playing on stage or recording in a studio. In both cases, you are playing the guitar. In most cases with music, the album is just a recording of what the musicians would do anyway. The great thing about this is the musician can intuitively pick up on the feeling in the room and change the way the are playing to accommodate this. They might not even notice they're doing it. There is this amazing feeling that comes from a band jamming with each other, and vibing off the audience.</p>
275 +</blockquote>
276 +<blockquote>
277 +<p>But this is not the case with most computer music. I was creating music on a timeline.</p>
278 +</blockquote>
279 +<h3><strong>Painted</strong>, not played.</h3>
280 +<p><a href="https://www.youtube.com/watch?v=9SH4g4FHZHw" target="_blank"><img src="http://www.arsov.net/SoundBytes/Images/2014-03/Ableton-main.jpg" alt=""></a></p>
281 +<blockquote>
282 +<p>This leaves only a few options.</p>
283 +</blockquote>
284 +<h2><em>Option 1</em>: Recruit some musicians and <strong>play it for real</strong>!</h2>
285 +<blockquote>
286 +<p>This is actually something that would be a lot of fun, but it is not representative of my musical process. I'd be doing completely different things in the studio to what I'm doing on stage. It would be treating the album like a score, things would get very complicated very quick with the amount of sounds I use.</p>
287 +</blockquote>
288 +<p><a href="http://www.npr.org/event/music/185510193/james-blake-live-in-concert" target="_blank"><img src="http://blogs.kcrw.com/musicnews/wp-content/uploads/2013/04/full-band-21-sm.jpg" alt=""></a></p>
289 +<h2><em>Option 2</em>: <strong>DJ it!</strong> (<em>just press play...</em>)</h2>
290 +<blockquote>
291 +<p>The performance would be more like an exhibition, much like how a painter would present their work. But I don't find this very fun. I want to perform, share and be in the moment with the audience, able to easily adapt to the room vibe. Not just a boring and predictable exhibit.</p>
292 +</blockquote>
293 +<p><a href="https://youtu.be/j6WY8L0wLTM?t=33" target="_blank"><img src="images/just-press-play.jpg" alt=""></a></p>
294 +<h2><em>Option 3</em>: Play <strong>everything</strong> yourself!</h2>
295 +<p><a href="https://www.youtube.com/watch?v=GIzq8-gSz-0" target="_blank"><img src="http://www.freeweekly.com/wp-content/uploads/2014/10/HenryInvisibles.jpg" alt=""></a></p>
296 +<blockquote>
297 +<p><a href="https://www.youtube.com/watch?v=iHSMnWpyIeM" target="_blank">https://www.youtube.com/watch?v=iHSMnWpyIeM</a></p>
298 +</blockquote>
299 +<blockquote>
300 +<p>This was the option I wanted to go with. But my songs are already sequenced. How to go about destructuring and playing?</p>
301 +</blockquote>
302 +<blockquote>
303 +<p>I had this crazy idea that I'd take my existing songs, and learn how to play all the individual parts and then build them up one loop at a time.</p>
304 +</blockquote>
305 +<h3><strong>Recording anxiety</strong></h3>
306 +<p><a href="https://www.youtube.com/watch?v=q0HVo6M3w64" target="_blank"><img src="https://c1.staticflickr.com/1/58/168150955_40c7db0172_z.jpg?zz=1" alt=""></a></p>
307 +<blockquote>
308 +<p>I suffer from acute recording anxiety. This was always a problem. I’d be jamming away a cool riff, and it sounds awesome, then I hit record and my figures turn to jelly, and it comes out all wrong. I looked long and hard for a solution, but couldn't find anything reliable. It was time to build my own solution.</p>
309 +</blockquote>
310 +<h2><strong>Time travel</strong> with Node.js</h2>
311 +<blockquote>
312 +<p>I created a Node.js script that allowed me more control over input, storing all MIDI in a buffer, and then allowing me to go back in time and create loops after I played them, along with some realtime loop transform controls.</p>
313 +</blockquote>
314 +<blockquote>
315 +<p>In the process of trying to learn my songs, and failing kind of miserably, I managed to develop a lot of the core looping concepts that still exist in Loop Drop today.</p>
316 +</blockquote>
317 +<h2><em>Previously on <a href="http://JSConf.asia" target="_blank">JSConf.asia</a></em>...</h2>
318 +<p><a href="https://www.youtube.com/watch?v=NL0nb8A8FDM" target="_blank"><img src="images/jsconf.asia.png" alt=""></a></p>
319 +<p><code>youtu.be/NL0nb8A8FDM</code></p>
320 +<h2><strong>Loop Drop</strong><a href="http://loopjs.com" target="_blank">loopjs.com</a></h2>
321 +<p><a href="http://loopjs.com" target="_blank"><img src="logo.png" alt=""></a></p>
322 +<blockquote>
323 +<blockquote>
324 +<p><a href="https://www.youtube.com/watch?v=5zutWpFG8pk" target="_blank">Play some tunes</a> and give a quick overview of how it works.</p>
325 +</blockquote>
326 +</blockquote>
327 +<blockquote>
328 +<blockquote>
329 +<p>Sample the audience and make a song!</p>
330 +</blockquote>
331 +</blockquote>
332 +<h2>Loop Drop is <strong>JavaScript</strong>!</h2>
333 +<blockquote>
334 +<p>Loop Drop is a desktop application that you can install on your computer. But it is actually 100% JavaScript! This is achieved using Electron (made by Github), which combines Node.js with Chromium giving you everything you'd ever want!</p>
335 +</blockquote>
336 +<p>Electron - <strong>Chromium + Node.js</strong></p>
337 +<p><a href="http://electron.atom.io" target="_blank">http://electron.atom.io</a></p>
338 +<h1>Contributing</h1>
339 +<ul>
340 +<li><a href="http://github.com/mmckegg/loop-drop-app" target="_blank">github.com/mmckegg/loop-drop-app</a></li>
341 +<li><a href="http://patreon.com/MattMcKegg" target="_blank">patreon.com/MattMcKegg</a></li>
342 +</ul>
343 +<p><img src="heart.png" alt=""></p>
344 +<h1>DESTROY WITH SCIENCE</h1>
345 +<p>Loop Drop R&amp;D <strong>super secret*</strong> laboratory!</p>
346 +<ul>
347 +<li><a href="http://soundcloud.com/destroy-with-science" target="_blank">soundcloud.com/destroy-with-science</a></li>
348 +<li><a href="http://destroywithscience.bandcamp.com/album/droptivist" target="_blank">destroywithscience.bandcamp.com/album/droptivist</a></li>
349 +</ul>
350 +
351 + </div>
352 + <div class='Overlay'>
353 + <a href='https://twitter.com/MattMcKegg'>@MattMcKegg</a> | <strong>github.com/mmckegg</strong>
354 + </div>
355 + <script>
356 + var viewer = document.querySelector('.Viewer')
357 + var firstElement = viewer.firstElementChild
358 + firstElement.classList.add('-active')
359 + more(firstElement)
360 +
361 + Array.from(document.querySelectorAll('p')).forEach(function (element) {
362 + if (element.childNodes.length === 1 && element.childNodes[0].nodeName === 'IMG') {
363 + element.parentNode.replaceChild(element.childNodes[0], element)
364 + }
365 + })
366 +
367 + function copyAll (element) {
368 + var range = document.createRange();
369 + range.selectNodeContents(element);
370 + var sel = window.getSelection();
371 + sel.removeAllRanges();
372 + sel.addRange(range)
373 + document.execCommand('copy')
374 + sel.removeAllRanges();
375 + }
376 +
377 + function next () {
378 + var active = viewer.querySelectorAll('.-active')
379 + var nextElement = getNext(last(active))
380 + if (nextElement) {
381 + nextElement.classList.add('-active')
382 + each(active, function (el) {
383 + el.classList.remove('-active')
384 + })
385 + more(nextElement)
386 + }
387 + }
388 +
389 + function prev () {
390 + var active = viewer.querySelectorAll('.-active')
391 + var prevElement = getPrev(first(active))
392 + if (prevElement) {
393 + prevElement.classList.add('-active')
394 + each(active, function (el) {
395 + el.classList.remove('-active')
396 + })
397 + more(prevElement)
398 + }
399 + }
400 +
401 + function getNext (current) {
402 + if (current) {
403 + var nextElement = current.nextElementSibling
404 + while (nextElement && !isHeading(nextElement)) {
405 + nextElement = nextElement.nextElementSibling
406 + }
407 + return nextElement
408 + }
409 +
410 + }
411 +
412 + function getPrev (current) {
413 + if (current) {
414 + var prevElement = current.previousElementSibling
415 + while (prevElement && !isHeading(prevElement)) {
416 + prevElement = prevElement.previousElementSibling
417 + }
418 + return prevElement
419 + }
420 + }
421 +
422 + function more (current) {
423 + if (current) {
424 + var nextElement = current.nextElementSibling
425 + while (nextElement && !isHeading(nextElement)) {
426 + nextElement.classList.add('-active')
427 + if (nextElement.tagName === 'PRE') {
428 + nextElement.tabIndex = 0
429 + nextElement.focus()
430 + copyAll(nextElement)
431 + }
432 + nextElement = nextElement.nextElementSibling
433 + }
434 + }
435 + }
436 +
437 + function each (elements, fn) {
438 + for (var i = 0; i < elements.length; i++) {
439 + fn(elements[i])
440 + }
441 + }
442 +
443 + function first (elements) {
444 + if (elements.length) {
445 + return elements[0]
446 + }
447 + }
448 +
449 + function isHeading (element) {
450 + return !!element.tagName.match(/^H[0-9]$/)
451 + }
452 +
453 + function last (elements) {
454 + if (elements.length) {
455 + return elements[elements.length-1]
456 + }
457 + }
458 +
459 + document.onkeydown = function (e) {
460 + if (e.keyCode === 39) { // right arrow
461 + next()
462 + } else if (e.keyCode === 37) { // left arrow
463 + prev()
464 + } else if (e.keyCode === 40) { // left arrow
465 + more()
466 + }
467 + }
468 + </script>
469 +</body>
470 +</html>
package.jsonView
@@ -1,0 +1,25 @@
1 +{
2 + "name": "web-audio-conf-talk-2016",
3 + "version": "0.0.0",
4 + "private": true,
5 + "main": "build.js",
6 + "scripts": {
7 + "test": "echo \"Error: no test specified\" && exit 1"
8 + },
9 + "repository": {
10 + "type": "git",
11 + "url": "https://github.com/mmckegg/jsconfasia-talk-2015"
12 + },
13 + "author": "Matt McKegg",
14 + "license": "MIT",
15 + "bugs": {
16 + "url": "https://github.com/mmckegg/jsconfasia-talk-2015/issues"
17 + },
18 + "homepage": "https://github.com/mmckegg/jsconfasia-talk-2015",
19 + "dependencies": {
20 + "ejs": "~2.3.3",
21 + "highlight.js": "~8.7.0",
22 + "markdown-it": "~4.4.0",
23 + "markdown-it-for-inline": "~0.1.1"
24 + }
25 +}
slides.html.ejsView
@@ -1,0 +1,261 @@
1 +<!DOCTYPE html>
2 +<html lang='en'>
3 +<head>
4 + <meta charset="utf-8" />
5 + <title>Slides</title>
6 + <style>
7 + body, html {
8 + height: 100%;
9 + background: #222;
10 + margin: 0;
11 + font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
12 + overflow: hidden;
13 + color: #CCC;
14 + font-size: 40px;
15 + letter-spacing: 1px;
16 + }
17 +
18 + h1, h2, h3 {
19 + font-weight: normal;
20 + text-align: center;
21 + color: white;
22 + margin: 20px 0;
23 + max-width: 80%;
24 + }
25 +
26 + p {
27 + max-width: 80%;
28 + text-align: center;
29 + margin-bottom: 20px
30 + }
31 +
32 + p + p {
33 + margin-top: 20px
34 + }
35 +
36 + a {
37 + color: #ff8bef;
38 + text-decoration: none;
39 + font-weight: normal;
40 + }
41 +
42 + ul {
43 + max-width: 70%;
44 + }
45 +
46 + strong {
47 + color: white;
48 + }
49 +
50 + h1 strong {
51 + font-weight: normal;
52 + color: #6AFF00;
53 + }
54 +
55 + h2 strong {
56 + color: #FFB500;
57 + }
58 +
59 + h1 {
60 + font-weight: normal;
61 + font-size: 300%;
62 + }
63 +
64 + h2 {
65 + font-weight: normal;
66 + font-size: 200%;
67 + }
68 +
69 + img {
70 + max-height: 65vh;
71 + margin: -10px 0;
72 + }
73 +
74 + .coffeescript .javascript, .javascript .xml, .tex .hljs-formula, .xml .javascript, .xml .vbscript, .xml .css, .xml .hljs-cdata {
75 + opacity: 0.9 !important;
76 + }
77 +
78 + .Viewer {
79 + display: flex;
80 + flex-direction: column;
81 + align-items: center;
82 + height: 100%;
83 + justify-content: center;
84 + }
85 +
86 + .Viewer > * {
87 + display: none
88 + }
89 +
90 + .Viewer > .-active {
91 + display: block
92 + }
93 +
94 + .Viewer > blockquote {
95 + display: none !important
96 + }
97 +
98 + pre {
99 + min-width: 60%;
100 + max-height: 80%;
101 + overflow: auto;
102 + padding: 10px;
103 + background: #111;
104 + border: 1px solid #333;
105 + color: #DDD;
106 + }
107 +
108 + pre > code {
109 + display: block;
110 + font: 20px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
111 + padding: 10px;
112 + padding-bottom: 100px;
113 + }
114 +
115 + p code, ul code {
116 + padding: 0 10px;
117 + background: #111;
118 + color: #EEE;
119 + border: 1px solid #333;
120 + font: 80% 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
121 + }
122 +
123 + .Overlay {
124 + position: absolute;
125 + top: 20px;
126 + right: 20px;
127 + font-size: 90%;
128 + opacity: 0.8;
129 + }
130 +
131 + ::selection {
132 + background: #AAA;
133 + }
134 +
135 + <%= additionalStyles %>
136 +
137 + </style>
138 +</head>
139 +<body>
140 + <div class='Viewer'>
141 + <%- body %>
142 + </div>
143 + <div class='Overlay'>
144 + <a href='https://twitter.com/MattMcKegg'>@MattMcKegg</a> | <strong>github.com/mmckegg</strong>
145 + </div>
146 + <script>
147 + var viewer = document.querySelector('.Viewer')
148 + var firstElement = viewer.firstElementChild
149 + firstElement.classList.add('-active')
150 + more(firstElement)
151 +
152 + Array.from(document.querySelectorAll('p')).forEach(function (element) {
153 + if (element.childNodes.length === 1 && element.childNodes[0].nodeName === 'IMG') {
154 + element.parentNode.replaceChild(element.childNodes[0], element)
155 + }
156 + })
157 +
158 + function copyAll (element) {
159 + var range = document.createRange();
160 + range.selectNodeContents(element);
161 + var sel = window.getSelection();
162 + sel.removeAllRanges();
163 + sel.addRange(range)
164 + document.execCommand('copy')
165 + sel.removeAllRanges();
166 + }
167 +
168 + function next () {
169 + var active = viewer.querySelectorAll('.-active')
170 + var nextElement = getNext(last(active))
171 + if (nextElement) {
172 + nextElement.classList.add('-active')
173 + each(active, function (el) {
174 + el.classList.remove('-active')
175 + })
176 + more(nextElement)
177 + }
178 + }
179 +
180 + function prev () {
181 + var active = viewer.querySelectorAll('.-active')
182 + var prevElement = getPrev(first(active))
183 + if (prevElement) {
184 + prevElement.classList.add('-active')
185 + each(active, function (el) {
186 + el.classList.remove('-active')
187 + })
188 + more(prevElement)
189 + }
190 + }
191 +
192 + function getNext (current) {
193 + if (current) {
194 + var nextElement = current.nextElementSibling
195 + while (nextElement && !isHeading(nextElement)) {
196 + nextElement = nextElement.nextElementSibling
197 + }
198 + return nextElement
199 + }
200 +
201 + }
202 +
203 + function getPrev (current) {
204 + if (current) {
205 + var prevElement = current.previousElementSibling
206 + while (prevElement && !isHeading(prevElement)) {
207 + prevElement = prevElement.previousElementSibling
208 + }
209 + return prevElement
210 + }
211 + }
212 +
213 + function more (current) {
214 + if (current) {
215 + var nextElement = current.nextElementSibling
216 + while (nextElement && !isHeading(nextElement)) {
217 + nextElement.classList.add('-active')
218 + if (nextElement.tagName === 'PRE') {
219 + nextElement.tabIndex = 0
220 + nextElement.focus()
221 + copyAll(nextElement)
222 + }
223 + nextElement = nextElement.nextElementSibling
224 + }
225 + }
226 + }
227 +
228 + function each (elements, fn) {
229 + for (var i = 0; i < elements.length; i++) {
230 + fn(elements[i])
231 + }
232 + }
233 +
234 + function first (elements) {
235 + if (elements.length) {
236 + return elements[0]
237 + }
238 + }
239 +
240 + function isHeading (element) {
241 + return !!element.tagName.match(/^H[0-9]$/)
242 + }
243 +
244 + function last (elements) {
245 + if (elements.length) {
246 + return elements[elements.length-1]
247 + }
248 + }
249 +
250 + document.onkeydown = function (e) {
251 + if (e.keyCode === 39) { // right arrow
252 + next()
253 + } else if (e.keyCode === 37) { // left arrow
254 + prev()
255 + } else if (e.keyCode === 40) { // left arrow
256 + more()
257 + }
258 + }
259 + </script>
260 +</body>
261 +</html>

Built with git-ssb-web