Christian Heilmann

You are currently browsing the Christian Heilmann blog archives for December, 2020.

Archive for December, 2020

Back to basics: adding a playback speed control to an audio player

Monday, December 28th, 2020

Currently I am publishing the new Developer Advocacy Handbook chapter by chapter and I also started recording audio versions of each chapter. A common request of people is to be able to control the speed of a audio/video recording. Luckily enough, using basic HTML5 and JavaScript, this is not that hard to achieve, so let’s do it.

You can see and hear the result in the following video:

You can check the final version on Codepen

See the Pen
Audio with speed control
by Christian Heilmann (@codepo8)
on CodePen.

The best start is always sensible HTML.

<div class="speedcontrolcontainer">
  <audio src="https://file-examp…xample_MP3_2MG.mp3" controls></audio>
    <label for="pbrate">Speed:</label>
    <input type="range" id="pbrate" min=.5 max=3 value=1 step=.1>

In this case, using the audio element with a controls attribute already gives us a play button, a scrubber, time display, volume and an overflow menu with download option. For the speed control, we need a slider with a label to keep it accessible and a span element to show the current value of the playback speed. The range control is good for this as it also gives us keyboard access and allows us to limit the speeds we want to allow. In this case, from half speed to four times the speed.

Let’s only go into basic CSS for styling here:

.scc {
  max-width: 30em;
  display: block;
  border: 1px solid #000;
  padding: 10px;
  font-family: Sans-serif;
.scc audio { 
  width: 100%; display: block; 
.scc div {
  display: flex;
  padding: .5em 0;
  gap: 5px;
.scc label { flex: 1; }
.scc input[type="range"] { flex: 5; }
.scc span {
  flex: 1;
  text-align: center;

We give the control a container element and set it to a max-width of 30em. We display the audio element as block and make it use up all the available space. We give the new speed control a bit of padding and use flexbox to lay it out.

The last bit is to use JavaScript to create the rest of the functionality:

const audio = document.querySelector('.scc  audio');
const playbackrate = document.querySelector('.scc input');
const display = document.querySelector('.scc span');
const displayvalue = val => {
  return parseInt(val * 100, 10) + '%'
display.innerText = displayvalue(audio.playbackRate);
playbackrate.addEventListener('change', e => {
  audio.playbackRate = playbackrate.value;
  display.innerText = displayvalue(playbackrate.value);

  • We get references to the audio element, the slider and the span we want to display the current value of the slide in.
  • As the playback speed in the audio API is a number, we need to convert it to a percentage. This is what the displayvalue method does for us.
  • We display the current playbackRate of the audio element in the span next to the slider.
  • We apply an event Listener to the input element that fires every time it changed.
  • When there is a change, we set the playbackRate of the audio element to the value of the slider
  • And we display the percentage in the span

One thing that is missing is that users may want to have their favourite speed stored so they don’t have to set it again chapter by chapter. To do this, we can use localStorage, set the playbackRate and value when we load the document and store it when the slider changed.

const audio = document.querySelector('.scc  audio');
const playbackrate = document.querySelector('.scc input');
const display = document.querySelector('.scc span');
const displayvalue = val => {
  return parseInt(val * 100, 10) + '%'
if (window.localStorage.pbspeed) {
  audio.playbackRate = window.localStorage.pbspeed;
  playbackrate.value = window.localStorage.pbspeed;
display.innerText = displayvalue(audio.playbackRate);
playbackrate.addEventListener('change', e => {
  audio.playbackRate = playbackrate.value;
  display.innerText = displayvalue(playbackrate.value);
  window.localStorage.pbspeed = playbackrate.value;

And that’s it! An audio playback control with playback speed option.

The new and improved Developer Advocacy Handbook is out – Read Chapters 1 & 2 now

Thursday, December 17th, 2020

Eleven years ago I wrote the Developer Evangelism Handbook and since then it helped a lot of of people start a career in Developer Relations. Now a publisher approached me if they could do a print version. The negotiations are still underway, but I was sure that it is not a good plan to release the book in the state it is in. So I spent the last few days cleaning up. I edited the chapters and removed outdated examples or links to defunct products. And I added new content that is more relevant to today’s world of developer advocacy. I will release chapters bit by bit over the next weeks. Once all is live I will open the GitHub repository for contribution and feedback.

For now, head over to and start with chapter one and two.

The book showing in the browser

You can see the whole Table of Contents and the chapters will light up as they become available.

I wrote the new book in Markdown and I am using GitHub Pages to publish and host it. It was a fun exercise to learn Jekyll and I am still in the middle of it. The book has an automatic dark/light theme detection and should be nice to read across all kind of form factors. Once done, I will also add a serviceworker and such to make the book installable. I am also considering generating an ebook version if you are interested.

Quick Tip: How to capture and replace newlines in liquid for Jekyll/GitHub Pages

Thursday, December 17th, 2020

As part of the re-write of The Developer Advocacy Handbook I needed to have blockquotes with different classes.

Fact display in the book

With GitHub Pages markdown you can do that using the > notation:

> **Fact:** There are no bad students or a bad audience --
only bad workshops and talks. Your mood, dedication and
enthusiasm do become those of the audience -- 
if you are not happy, they won\'t be happy.

The problem was that I couldn’t add CSS classes to the blockquote elements so I can show them in different styles. I wanted four of them: example, fact, warning and tip.

The good news is that even without any styling using the strong name should make it obvious. But as there is no text “contains” selector in CSS I couldn’t rely on that to change the blockquote element.

First solution: JavaScript

The first thing I thought was to use JavaScript to apply the classes, which is pretty straight forward:

let bqs = document.querySelectorAll('blockquote');
  bqs.forEach(b => {
  b.className = b.

This, however, felt dirty and I wanted to use the system itself to do that task.

Moving to liquid

So I wrote a liquid include to convert the HTML before rendering. In my layout template, this works by replacing the {{ content }} with {% include blockquotes.html html=content %}.

In the blockquotes.html, I thought it’d be easy to do a search and replace. Alas, there is the issue that liquid only does string replacement and doesn’t know any regular expressions.

The HTML generated from the markdown has a line-break in it:

  <p><strong>Fact:</strong> There are no bad students … </p>

This is where it didn’t get fun. The replace filter doesn’t allow you to concatenate strings and doesn’t know the concept of n. So, I tried to use the newline_to_br together with strip_newlines filters and then replace the br but it was messy.

Turns out, the main trick was to capture a newline in liquid and assemble the string to replace using that one.

{% capture newline %}
{% endcapture %}
{% capture tip %}<blockquote>{{newline}}  <p><strong>Tip:</strong>{% endcapture%}
{% capture example %}<blockquote>{{newline}}  <p><strong>Example:</strong>{% endcapture%}
{% capture warning %}<blockquote>{{newline}}  <p><strong>Warning:</strong>{% endcapture%}
{% capture fact %}<blockquote>{{newline}}  <p><strong>Fact:</strong>{% endcapture%}
{% assign newhtml = include.html | 
  replace: tip, '<blockquote class="tip"><p><strong>Tip:</strong>' |
  replace: example, '<blockquote class="example"><p><strong>Example:</strong>' |
  replace: warning, '<blockquote class="warning"><p><strong>Warning:</strong>' |
  replace: fact, '<blockquote class="fact"><p><strong>Fact:</strong>' 
{{ newhtml }}

This works fine. Seems superfluous, but it is a way. It might be that there is a much simpler way as I am new to this world, having used PHP before the build the old version of the book. Got a better option? Tell me :)

Update to the Developer Evangelism/Advocacy handbook almost complete

Tuesday, December 15th, 2020

Writing Setup

Eleven years ago I wrote the Developer Evangelism Handbook .Last month I was approached by a publisher who is interested to print it in another language. Whilst flattered, I also couldn’t let that happen as there are parts of the book that are quaintly outdated now. Some of the products I promote aren’t available any longer and there are big differences in the way we use social media and the web now compared to 2009.

So I spent a few evenings polishing the book, removing a lot of outdated material and adding new things that are more relevant now.

I added materials about virtual conference participation, code hosting, recording your own videos and screencasts, and incorporated some of the posts and materials I created since first publication. Currently it is at roughly 40000 words and the letter sized Word Doc would me 85 pages.

For now, I will publish the book online again, chapter by chapter and also consider creating some ebooks for those who prefer using readers. There’s a dark and light theme and it will work across all resolutions and platforms. I’m using jekyll/eleventy with GitHub pages and learn a few new things on the way.

Here’s the new table of contents:

  • About this handbook
    • About this version
    • About the author
  • What is Developer Advocacy / Evangelism?
    • Defining Developer Advocacy
    • Start with the right mindset
    • Find your role and play to your strengths
  • Work with your own company
    • Prepare for prejudice
    • Deal with company changes
    • Be there for internal developers
    • Work with PR and marketing
    • Be known as an outward channel
    • Train other advocates and developers
    • Share useful technology
    • Balance your personal and official channels
    • Remove the brand
  • Working with your competition
    • Work with the competition
    • Show respect to the competition
    • Acknowledge when the competition is better
    • Know about the competition
    • Build examples using and try out competitive products
  • Prepare for outreach
    • Get your facts right
    • Know the audience and their needs
    • Have expert backup
    • Choose the right medium
    • Plan for failure
  • Get speaking opportunities
    • Take part in podcasts
    • Take part in panels
    • Go to Grass Roots events
    • Go to Meetups
    • Write articles
    • Offer Brownbags
    • Ask questions at conferences
    • Be a presenter people want to invite – publish your presenter terms
  • Travel and conference participation
    • Getting your travel and accommodation sorted
    • Who pays what?
    • Be at the event
    • Give the event some social media love
    • Use the event to build a network
    • Keep track of your conference participation
    • Work with the conference buzz
    • Be a part of the conference you talk at
    • Release immediately
    • Write about conferences
  • Deliver a talk or workshop
    • Be yourself
    • Invite communication
    • Prepare takeaways
    • Plan time for and own the questions and answers
    • Be honest and real
    • Follow up communication
    • Delivering presentations tips: timekeeping and more
      • How will I fit all of this in X minutes?
      • Less is more
      • Your talk is only extremely important to you
      • Map out more information
      • Live coding?
      • Avoid questions
      • Things to cut
      • Talk fillers
      • Planning Your Talk Summary
    • Things not to say on stage – and what to do instead
      • “This is easy…”
      • “I’ll repeat quickly, for the few of you who don’t know…”
      • “Everybody can do that…”
      • “X solves this problem, so you don’t have to worry about it”
      • “As everybody knows…”
      • “This is just like we learned in school…”
      • “That’s why Y(your product) is much better than (competitor) X”
      • “This can be done in a few lines of code…”
      • “If you want to be professional, do X”
      • A quick check
  • Write great posts and articles
    • Simple is not stupid
    • Say what it is – don’t sugar-coat it
    • Size matters
    • Add media
    • Structure your content
    • Time-stamp your content
    • Cite to prove
    • Pre-emptive writing
    • Ending on an invitation to learn more
  • Write excellent code examples
    • Solve a problem with your example
    • Show a working example
    • Explain the necessary environment
    • Write working copy and paste code
    • Have the example as a download
    • Write clean and clever examples
    • Build code generators
    • Hosting code and demos
      • Version Control is your friend
      • Automated Hosting
      • Code showcases
      • Code Sandboxes
      • Live coding environments
  • Prepare great slide decks for presentations
    • Know your stuff
    • Start with the content – not the slides!
    • Start with a highly portable Format – Text
    • Quick Presentation creation tip: unpacking bullets
    • Pick a presentation tool that helps you present
    • Illustrate, don’t transcribe
    • Use and find images
    • About code examples
    • Sound and videos
    • Don’t bling it up
    • Keep it brief
    • Consider the audience
    • Corporate and conference templates
    • Don’t reuse without personalising
    • Share and enjoy
    • Additional presentation tips
      • Introduce yourself
      • Use humour
      • Build bridges to the real world
      • Pace yourself
      • Avoid “Hello World”
      • Be fresh
    • A checklist for more inclusive, accessible and understandable talks
      • Talk materials
      • Format
      • Content
      • Tracking
      • Insurances
      • Bonus round
  • Keep a record of your work
    • Record the audio of your talks
    • Shoot video
    • Link collections
    • keep a conference participation list
  • Know and use the (social) web
    • Find great web content
    • Redistribute web content
    • Be known on the web
    • Use powerful social web sites and products
    • Use the web for storage, distribution and cross-promotion
    • Hint, tease and preview
    • Track your impact
    • Build a network
    • Create or take part in a newsletter
    • Create or take part in a podcast
  • Working from your own computer
    • Get a decent setup
    • Screencasts and screenshots
    • Streaming
    • Taking part in live online chats
    • Attending live online events
    • Technical issues to prepare for
    • Design limitations to prepare for
    • Personal issues to prepare for
    • Recording your own talks
      • Check your setup and your surroundings
      • Record the different pieces of the talk separately
      • Remember that you need to share the screen with your slides
      • Use accessibility features to add extra video value
      • Record in the highest possible quality
      • Keep originals and make it easy to get your video
  • Final words

Chris Heilmann on his desk writing

Until then, I hope you have a great time and take some time off!

Pluralsight celebrates 25 years of JavaScript – a good opportunity to spruce up your knowledge

Thursday, December 3rd, 2020

To celebrate the 25th birthday of our favourite strange and wonderful language for the web, Pluralsight has ramped up the domain and offers 25 free courses over the month of December. Click the following overview to sign up for free and see them.

Overview of the JavaScript courses offered this December by Pluralsight

In addition to that, on the 10th of December there’ll be a live JavaScript build session with Cassidy Williams.

You can find out more by following Pluralsight on Twitter and the #JavaScript25 hashtag.