Thinking Out Loud About Screencasting Platforms

Written by Pete Corey on Nov 21, 2014.

One of my goals over the past few months has been to start live streaming/screencasting my development sessions. I’ve been watching Izac Filmalter’s Twitch stream for the past few days and I think it’s fantastic! Streaming can benefit both the streamer (me) and the community at large (you). Developing to an audience would force me to polish not only the products I create, but also the process I go through to create them. Explaining what I’m doing to you would reinforce my understanding of the topic, and hopefully provide you with some value as well. Plus, in a pinch I can use you as a rubber ducky.

Current Options

There are a few existing options when it comes to streaming services and platforms, but all of them have their drawbacks.

  • On Air Hangouts - Google’s On Air Hangouts are essentially hangout sessions that you can broadcast to any number of viewers for free. Unfortunately, On Air stream quality maxes out at 720p.

  • Twitch.tv - Twitch.tv is a video game streaming platform with a fantastic community. Twitch supports source resolution streaming, but requires that you stream your content directly to their RTMP servers, which can be a barrier to entry. Their terms of use also state that only video game related streaming is allowed. If it weren’t for this policy, I would say that twitch is currently the best streaming option available.

  • Youtube Live - Youtube Live is the best alternative to Twitch. They support up to 1080p streaming, but like Twitch, they require that you manually stream your content directly to their RTMP server.

While configuring OBS or FMLE to stream to Twitch or Youtube Live’s RTMP ingestion servers is relatively straightforward, it’s an unneeded barrier to entry when technologies like WebRTC exist.

So, what’s a developer to do when he wants to screencast differently?

BYOPWWRTC (Build Your Own Platform With WebRTC)

WebRTC is a newly emerging browser technology that (among a huge number of other things) allows for the capture and streaming of video and audio directly within the browser. Since WebRTC works directly within the browser, no external streaming software is required. WebRTC can set up to peer-to-peer streaming directly to a small number of viewers, or the stream can be routed through a centralized server (MCU) to be broadcast to a wider audience. Building a screencasting platform on WebRTC seems like an obvious choice. We get the ease of use of browser based streaming, up to 1080p quality, and the possibilities of both peer-to-peer and centralized architectures.

Imagining the finalized product, peer-to-peer streaming would always be free as it puts no load on the system (other than page views). Depending on your machine/network capabilities, you will have a limited number of viewers to whom you can effectively peer-to-peer stream. After that limit is reached, the system would suggest you start using a centralized streaming model. This may need to be a paid service to support the MCU infrastructure.

Since this would be a platform targeted towards developers, I can imagine a variety of cool features like Github/Bitbucket integration, similar screencaster discovery (based on stack, framework, language, project, etc…), in-chat syntax highlighting, and many others.

Inspiring Resources

Final Thoughts

At the moment this is nothing more than an idea. I am by no means a WebRTC expert. I’ve only recent started researching this topic, but WebRTC seems like an ideal solution for this problem. In the very near future, I will hopefully start building out a proof of concept of the peer-to-peer streaming system. Once that’s up and running I would be able to stream the continued developement of the project. Stay tuned!

Building Ms. Estelle Marie

Written by Pete Corey on Nov 12, 2014.

I firmly believe that design and development are inseparable. One cannot be done without a thorough understanding of the other. As a developer, I feel that more experience with all kinds of design (visual, interaction, product, etc…) will only do good things for me. Because of this, I’ve spent the past few months trying to work out my design muscle. My most recent design-heavy project was to build a custom WordPress theme for the Ms. Estelle Marie beauty blog. Here’s a quick rundown:

Goals

For this project I was shooting for a very minimal aesthetic. I wanted the theme to be as unobtrusive and undistracting as possible to draw more of the user’s attention to the bright, colorful content. For this reason I went with a mostly achromatic color scheme with a single gold accent and generous amounts of whitespace.

Because the design of Ms. Estelle Marie is so minimal, much of the aesthetic value comes from the typeface selection. After going back and forth between different combinations, I landed on two typefaces: Playfair Display and Raleway. I felt that the heaviness of the Playfair Display contrasted nicely with the lightness of Raleway.

Base Wordpress Template

Before this project, I had zero exposure to WordPress development (although I’m no stranger to PHP). I figured that the best way to quickly get moving with the CMS was to start with a bare bones template. After sifting through a few options, I finally landed on the Underscores (_s) theme. Underscores offered everything I was looking for. Namely, not much at all! A clean Underscores install presented with me with a very minimal theme with next to no superfluous styling or content to get in my way. With the help of the WordPress Codex, I was able to quickly wrap my mind around things like the WordPress file structure, API functionality and the general WordPress way of doing things. I’d highly recommend Underscores to anyone looking for a bare bones starter theme.

Grunt

As with nearly all of my projects, my frontend workflow for this project relied heavily on Grunt. For this project, I was running WordPress out of /var/www, so the only tools I used were SASS and LiveReload. My Gruntfile was relatively thin:

module.exports = function(grunt) {
    grunt.initConfig({
        sass: {
            dist: {
                files: {
                    'style.css': 'scss/style.scss'
                }
            }
        },
        watch: {
            options: {
                livereload: true,
            },
            less: {
                files: ['scss/**/*.scss'],
                tasks: ['sass']
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-sass');
    grunt.loadNpmTasks('grunt-contrib-watch');
};

In previous posts, I described creating scaling SVG text. I used a technique like this to manually create the Ms. Estelle Marie logo. My technique was fairly primitive. I created two text elements, styled them with a Google font and then resized and positioned them until I was happy with the results. Because the SVG element is using a viewBox to define its internal coordinate system, the logo can responsively resize to whatever size is needed.

Google Fonts

From a technicaly standpoint, I’m a huge fan of Google Fonts. Being one line of CSS away from using any font you want is incredibly convenient. However, I did run into issues on this project with flashes of unstyled content (FOUC). The SVG logo would render before the font was loaded, which caused a flash of ugly, misaligned text. As recommended by Google, I used the Web Font Loader to fix these problems. The Web Font Loader synchronously loads the fonts specified, so by placing the provided script tags before any of your content, the script will block rendering until all of the fonts have been loaded, preventing the FOUC!

Chrome LiveReload Extension and Remote Machines

Written by Pete Corey on Nov 5, 2014.

Last night I decided it would be a good idea to join the 21st century and incorporate LiveReload into my frontend workflow. Since I’m already using grunt-contrib-watch to watch my LESS/SASS files, I figured this would be a breeze. grunt-contrib-watch supports LiveReload out of the box! All that was needed was an options block inside of my watch config:

watch: {
    options: {
        livereload: true,
    },
    ...

This option spins up a LiveReload server on my dev machine running on port 35729 by default. In order to leverage LiveReload, your client must include the livereload.js script served by this service. This can be done by either manually adding a script tag to your project, or using the Chrome LiveReload extension. I quickly installed the extension, eagerly pressed the LiveReload button and… got an error!

Could not connect to LiveReload server. Please make sure that a compatible LiveReload server is running. (We recommend guard-livereload, until LiveReload 2 comes to your platform.)

Strange. My dev server was running on a VM on 192.168.0.12, so to verify that the LiveReload server was running I went to http://192.168.0.12:35729/ in the brower. As expected, I received a JSON response from grunt-contrib-watch’s tinylr server:

{
    "tinylr": "Welcome",
    "version": "0.0.5"
}

Very strange. Livereload was running on my dev machine, but the Chrome extension was unable to connect to it. As a sanity check, I decided to forgo connecting with the browser extension and manually added the livereload.js script tag to my project:

<script src=”http://192.168.0.12:35729/livereload.js”></script>

After reloading the page, I noticed that it was able to successfully pull down the livereload.js file and LiveReload changes were taking effect.

While this approach worked, I wasn’t satisfied. I wanted to use the browser extension, not manually include the script in my project. I started digging into the plugin to find out what was going on.

The first thing I did was enable “Developer Mode” in the Chrome extensions window. That allowed me to install and enable the Chrome Apps & Extensions Developer Tool. I fired up the Extension Dev Tools, opened the LiveReload console and once again tried to connect to my dev server. The log messages made it clear what was going on:

Connecting to ws://127.0.0.1:35729/livereload...
Haven't received a handshake reply in time, disconnecting.
WebSocket connection to 'ws://127.0.0.1:35729/livereload' failed: WebSocket is closed before the connection is established.
Web socket error.
Web socket disconnected.

The LiveReload extension was attempting to connect to 127.0.0.1, not 192.168.0.1. A quick look through global.js shows that host is hardcoded to 127.0.0.1 in the initialize function.

After looking through the github issues for the LiveReload extension project, I found an unmerged pull request from 2013 by Greg Allen that fixed the issue. Bigwave in the comments had built a version of the extension with the fix and released on the app store as RemoteLiveReload. After installing this new extension, my LiveReload setup started working without a hitch. Thanks Greg and Bigwave!