Coding is Awesome

A Creative Blog for Ningbit

HTML5 Boilerplate Explained in Simple Terms

By Ning Yap

HTML5 Boilerplate Get the latest version of HTML5 Boilerplate and read about Rails integration here

What is HTML5 Boilerplate?

A template from which one can more easily build a standards-aware website. It is in the words of one of its creators Paul Irish “a good starting template of HTML and CSS and a folder structure that works… Baked into it is years of best practices from front-end development professionals.” Since 2010, it’s been polished and iterated upon by hundreds of developers.

Here’s a quick list of features:

  • Cross-browser compatibility (Chrome, Firefox, Safari, Opera, IE)
  • Legacy browser support back to IE6
  • Includes common JavaScript libraries jquery.min.js and modernizr.js
  • Includes common CSS library normalize.min.css
  • Google Analytics tracking code snippet
  • CSS common helper classes, media queries for responsive design
  • Customizable! And open-source!

How popular is it?

A Google search for “boilerplate” yields html5boilerplate.com as the first search result over an actual boiler plate.

Actual boiler plate used to make boilersActual boiler plate used to make boilers

A look at the file/folder structure

    .
    ├── css
    │   ├── main.css
    │   └── normalize.css
    ├── doc
    ├── img
    ├── js
    │   ├── main.js
    │   ├── plugins.js
    │   └── vendor
    │       ├── jquery.min.js
    │       └── modernizr.min.js
    ├── .htaccess
    ├── 404.html
    ├── apple-touch-icon-precomposed.png
    ├── index.html
    ├── humans.txt
    ├── robots.txt
    ├── crossdomain.xml
    └── favicon.ico

The structure is fairly straighforward, CSS files belong in css, documentation belongs in doc, image assets in img, and JavaScript files in js. main.css contains boilerplate styles that can be generated via initializr.com, as well as helper classes and media queries.

.htaccess is the default config file for an Apache web server, humans.txt is for listing team members and technologies used, and robots.txt is for pages that should be hidden from search engines. crossdomain.xml is a template for working with cross-domain requests and favicon.ico and the Apple touch icon should be replaced with your own so the user sees a customized icon when he or she bookmarks the site.

404.html is the default “Not Found” page and index.html the default load page.

Examining index.html

Hello world! This is HTML5 Boilerplate.

index.html (index.html) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->

        <link rel="stylesheet" href="css/normalize.css">
        <link rel="stylesheet" href="css/main.css">
        <script src="js/vendor/modernizr-2.6.2.min.js"></script>
    </head>
    <body>
        <!--[if lt IE 7]>
            <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
        <![endif]-->

        <!-- Add your site or application content here -->
        <p>Hello world! This is HTML5 Boilerplate.</p>

        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        <script>window.jQuery || document.write('<script src="js/vendor/jquery-1.10.2.min.js"><\/script>')</script>
        <script src="js/plugins.js"></script>
        <script src="js/main.js"></script>

        <!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
        <script>
            (function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=
            function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;
            e=o.createElement(i);r=o.getElementsByTagName(i)[0];
            e.src='//www.google-analytics.com/analytics.js';
            r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));
            ga('create','UA-XXXXX-X');ga('send','pageview');
        </script>
    </body>
</html>

———


We have our simplified HTML5 doctype declaration:

<!DOCTYPE html>

Conditional commenting only evaluat-able by Internet Explorer browsers. This allows for specifying CSS fixes for specific legacy versions of IE. The “.no-js” class can be used to specify custom styles when JavaScript is disabled.

<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->

Apparently, if the charset isn’t declared within the first 512 bytes of your HTML document, your site is vulnerable to malicious code and hijacking!

<meta charset="utf-8">

Another IE fix to ensure the latest rendering engine version of IE (Internet Exploder) is being used

<meta http-equiv="X-UA-Compatible" content="IE=edge">

If you are NOT coding a responsive site, or site for mobile, take this line out. It’s basically a message to the mobile browser that says, “Render me differently, I’m designed for mobile screens too!”

<meta name="viewport" content="width=device-width, initial-scale=1">

Keep those styles in line with normalize.css! “Normalize.css makes browsers render all elements more consistently and in line with modern standards. It precisely targets only the styles that need normalizing.” How fascist.

<link rel="stylesheet" href="css/normalize.css">

Why is this script loaded at the top (rather than the bottom) of the page, possibly causing the whole page to hang if your servers are slow? That’s because this JavaScript library, Modernizr, helps older browsers handle HTML5 elements; therefore, it must load before any HTML5-specific code can be read.

<script src="js/vendor/modernizr-2.6.2.min.js"></script>

Examining index.html: <body> edition

Kindly inform your site visitor that their choice of browser is antiquated and they have no taste in technology

<!--[if lt IE 7]>
  <p class="browsehappy">You are using an <strong>outdated</strong> browser. 
  Please <a href="http://browsehappy.com/">upgrade your browser</a> 
  to improve your experience.</p>
<![endif]-->

Content is king.

<!-- Add your site or application content here -->
<p>Hello world! This is HTML5 Boilerplate.</p>

Bow down to almighty Google, sourcer of jQuery. Actually, you should use Google CDN (Content Delivery Network) because the visitor’s browser will likely have a cached version of jQuery from their site… and Google’s servers are probably way faster than yours anyway. So yes, bow down to Lord Google.

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.10.2.min.js"><\/script>')</script>
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>

The ever watchful eye

<!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
<script>
    (function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=
    function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;
    e=o.createElement(i);r=o.getElementsByTagName(i)[0];
    e.src='//www.google-analytics.com/analytics.js';
    r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));
    ga('create','UA-XXXXX-X');ga('send','pageview');
</script>

Abbreviated CSS rundown

main.css (main.css) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/*! HTML5 Boilerplate v4.3.0 | MIT License | http://h5bp.com/ */

/*
 * What follows is the result of much research on cross-browser styling.
 * Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
 * Kroc Camen, and the H5BP dev community and team.
 */

/* ==========================================================================
   Base styles: opinionated defaults
   ========================================================================== */

html,
button,
input,
select,
textarea {
    color: #222;
}

html {
    font-size: 1em;
    line-height: 1.4;
}

/*
 * Remove text-shadow in selection highlight: h5bp.com/i
 * These selection rule sets have to be separate.
 * Customize the background color to match your design.
 */

::-moz-selection {
    background: #b3d4fc;
    text-shadow: none;
}

::selection {
    background: #b3d4fc;
    text-shadow: none;
}

/*
 * A better looking default horizontal rule
 */

hr {
    display: block;
    height: 1px;
    border: 0;
    border-top: 1px solid #ccc;
    margin: 1em 0;
    padding: 0;
}

/*
 * Remove the gap between images, videos, audio and canvas and the bottom of
 * their containers: h5bp.com/i/440
 */

audio,
canvas,
img,
video {
    vertical-align: middle;
}

/*
 * Remove default fieldset styles.
 */

fieldset {
    border: 0;
    margin: 0;
    padding: 0;
}

/*
 * Allow only vertical resizing of textareas.
 */

textarea {
    resize: vertical;
}

/* ==========================================================================
   Browse Happy prompt
   ========================================================================== */

.browsehappy {
    margin: 0.2em 0;
    background: #ccc;
    color: #000;
    padding: 0.2em 0;
}

/* ==========================================================================
   Author's custom styles
   ========================================================================== */

















/* ==========================================================================
   Helper classes
   ========================================================================== */

/*
 * Image replacement
 */

.ir {
    background-color: transparent;
    border: 0;
    overflow: hidden;
    /* IE 6/7 fallback */
    *text-indent: -9999px;
}

.ir:before {
    content: "";
    display: block;
    width: 0;
    height: 150%;
}

/*
 * Hide from both screenreaders and browsers: h5bp.com/u
 */

.hidden {
    display: none !important;
    visibility: hidden;
}

/*
 * Hide only visually, but have it available for screenreaders: h5bp.com/v
 */

.visuallyhidden {
    border: 0;
    clip: rect(0 0 0 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px;
}

/*
 * Extends the .visuallyhidden class to allow the element to be focusable
 * when navigated to via the keyboard: h5bp.com/p
 */

.visuallyhidden.focusable:active,
.visuallyhidden.focusable:focus {
    clip: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    position: static;
    width: auto;
}

/*
 * Hide visually and from screenreaders, but maintain layout
 */

.invisible {
    visibility: hidden;
}

/*
 * Clearfix: contain floats
 *
 * For modern browsers
 * 1. The space content is one way to avoid an Opera bug when the
 *    `contenteditable` attribute is included anywhere else in the document.
 *    Otherwise it causes space to appear at the top and bottom of elements
 *    that receive the `clearfix` class.
 * 2. The use of `table` rather than `block` is only necessary if using
 *    `:before` to contain the top-margins of child elements.
 */

.clearfix:before,
.clearfix:after {
    content: " "; /* 1 */
    display: table; /* 2 */
}

.clearfix:after {
    clear: both;
}

/*
 * For IE 6/7 only
 * Include this rule to trigger hasLayout and contain floats.
 */

.clearfix {
    *zoom: 1;
}

/* ==========================================================================
   EXAMPLE Media Queries for Responsive Design.
   These examples override the primary ('mobile first') styles.
   Modify as content requires.
   ========================================================================== */

@media only screen and (min-width: 35em) {
    /* Style adjustments for viewports that meet the condition */
}

@media print,
       (-o-min-device-pixel-ratio: 5/4),
       (-webkit-min-device-pixel-ratio: 1.25),
       (min-resolution: 120dpi) {
    /* Style adjustments for high resolution devices */
}

/* ==========================================================================
   Print styles.
   Inlined to avoid required HTTP connection: h5bp.com/r
   ========================================================================== */

@media print {
    * {
        background: transparent !important;
        color: #000 !important; /* Black prints faster: h5bp.com/s */
        box-shadow: none !important;
        text-shadow: none !important;
    }

    a,
    a:visited {
        text-decoration: underline;
    }

    a[href]:after {
        content: " (" attr(href) ")";
    }

    abbr[title]:after {
        content: " (" attr(title) ")";
    }

    /*
     * Don't show links for images, or javascript/internal links
     */

    .ir a:after,
    a[href^="javascript:"]:after,
    a[href^="#"]:after {
        content: "";
    }

    pre,
    blockquote {
        border: 1px solid #999;
        page-break-inside: avoid;
    }

    thead {
        display: table-header-group; /* h5bp.com/t */
    }

    tr,
    img {
        page-break-inside: avoid;
    }

    img {
        max-width: 100% !important;
    }

    @page {
        margin: 0.5cm;
    }

    p,
    h2,
    h3 {
        orphans: 3;
        widows: 3;
    }

    h2,
    h3 {
        page-break-after: avoid;
    }
}

———


Friends don’t let friends float divs non-clearfixed.

.clearfix:before,
.clearfix:after {
    content: " "; /* 1 */
    display: table; /* 2 */
}

.clearfix:after {
    clear: both;
}    

What are print styles? Print styles are styles for “printing”, which means the transfer of ink to “paper”. Paper is a dried, flat-sheet made from the fibrous pulp of wood, a material that hit its peak popularity at the end of the 20th century. Who prints webpages, seriously? Get a tablet, people!

@media print {
    * {
        background: transparent !important;
        color: #000 !important; /* Black prints faster: h5bp.com/s */
        box-shadow: none !important;
        text-shadow: none !important;
    }

My, what a large, shiny screen you have there! You can come over and query my media anytime…

@media only screen and (min-width: 35em) {
    /* Style adjustments for viewports that meet the condition */
}

Apologies for that last one.

A case against using HTML5 Boilerplate

HTML5 Boilerplate ca. 2010HTML5 Boilerplate ca. 2010

Will the real HTML5 boilerplate please stand up? This guy, Harry Roberts, is into minimalism and questioning assumptions, which is always good. He considers the original to be bloatware, basically.

THIS IS SPARTA!!!!’s version of HTML5 Boilerplate

index.html (the_real_html5_boilerplate.html) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>HTML5 boilerplate – all you really need…</title>
    <link rel="stylesheet" href="css/style.css">
    <!--[if IE]>
        <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
</head>

<body id="home">

    <h1>HTML5 boilerplate</h1>

</body>
</html>

Would have resulted in a much shorter blog post from me. Ah well…

Summary

Now you know why HTML5 Boilerplate exists. It is a beacon of hope in this hostile world of way too many options for browsing. At least with the boilerplate, you have a few crowd-sourced signposts pointing the way.

I must say, front-end development has really come a long way since the good ol’ GeoCities days. So tell me, when will people stop confusing the roles of web designer and web developer?

The Good OlThe Good Ol’ Days, Bless ‘er Heart

Presenting BikeWithFriends at NY Tech Meetup as ‘Hack of the Month’

By Ning Yap

Team BikeWithFriends at NYTM 8/7/13 (Qool Photo)Team BikeWithFriends at NYTM 8/7/13 (Qool Photo)

(Watch the official livestream of our meetup presentation at nytm.org or on YouTube)

Being the Expert

I’ve never had to present in front of such a large group before. Generally, the larger the group, the more you might feel impostor syndrome, thinking “among these peers, I can’t possibly claim to be the expert.” But this time, I didn’t feel that at all.

Here was a unique situation where I was presenting on something my team and I had created. Only we knew of the intricate workings of the app, the genesis of the idea, the struggle and breakthroughs, and (at times) even the doubt of its success and viability. We are the experts on all of that. No one knows more about that than us. We were telling our own story from our point of view. We had lived it and it was ours.

Ownership and Being Brave

Sandi Metz at GORUCO 2011Sandi Metz at GORUCO 2011

Sandi Metz gave a brilliant talk at The Flatiron School two months ago where she shared some of her experiences speaking and consulting in the tech field. She bravely acknowledged that even she had felt like an impostor at times, wondering if she was qualified to author a Ruby guide (Principles of Object Oriented Programing in Ruby) or to consult on a project and claim that things should be done as she recommended. For years, she even avoided giving talks altogether!

Eventually, she realized that sometimes you just have to forget about your anxiety. You have to forget about your ego, and be brave. She told us (and I’m paraphrasing)

You have to own your words and take ownership of your ideas. You have to know that you have a valuable point of view that not only is important for you to share, you must also share it bravely. Don’t step back on your own words. Inspect them, think deeply about them, and then present them like you are the expert. You owe that to your ideas. And it will be far more convincing.

Rehearse, Reduce, Rehearse, Simplify, Rehearse! And Script!

Josh introduces BikeWithFriendsJosh introduces BikeWithFriends

At NYTM, we would be given 5 minutes to talk about Bike With Friends. Our task would be to explain our app — all 4 of us on stage — in a way that was not only clear, concise, and simple, but also conveyed our excitement about the app. The real challenge was not that we were speaking to a large audience, it would be getting our message across in that condensed format. I knew there was a real possibility of us not meeting that mark.

I don’t have to say how poorly our first run-through went the Sunday prior. Each trying to say too much in our individual minute, we reiterated each other’s points, choked on the things we wanted to say, and overall, made an oratorical mess. In a way it was good how bad it was. It was clear we wouldn’t be able to “wing” the presentation the same way we had at our NYC on Rails Meetup at school or at Civic Hack Night/#BetaNYC. By “wing”, I mean “loosely organized” with “things we want to talk about”. We would have to script.

You can read my teammate Anisha’s blog entry on scripting our talk for NYTM (she wrote it before the talk took place). In it she notes how scripting was a challenge for her. She felt it prevented her from expressing her spontaneity and fun personality, limiting her ability to feel out her audience. I agree how scripting limits you. But the limiting is entirely appropriate for this kind of talk. When you have 4 people on stage trying to each get their ideas in, and you only have 5 minutes, you must script!

The Script

There are perhaps many reasons to script, but the most important reason by far is so you condense your thoughts into real words and sentences. Yes, you do want to have the freedom to phrase things how you wish on presentation day. But no matter what, you have to say it some way, and better to hash those options out on the page first.

To clarify: By script I don’t mean just an outline with bullet points. I mean actual, fully-worded sentences like the ones you might see on a teleprompter for a stump speech. Yes, there is an off chance that you may come up with that brilliant line that most expresses what you want to convey on the spot that day. But there is just as likely a chance you try to go off the cuff and say the exact wrong thing (or just confuse the hell out of your audience).

My team quickly saw the value of a script each time we rehearsed. It became very clear that there were certain versions of our explanation that were more — to borrow a Ruby programmer’s phrase — expressive, meaning concise, what you actually want to say, and anyone seeing it knows exactly what it is.

Numbering our points, grouping and condensing related examples (such as the badges we wanted to cover), transitioning to the next speaker or even to a new segment of the talk with that perfect phrase, these were choices that having a script allowed us to make and keep track of. *Special thanks to Google Docs for allowing group collaboration on a single document which is absolutely critical when you try to hammer out something like this in this sort of timeframe :)

Through this slow process of making these decisions jointly, our talk was distilled into a better version of itself after every rehearsal. And since we all knew what each person wanted to say, we could help them with that process and let them do it in their own words.

Getting the Flow Down Pat

What about the downsides of scripting and, subsequently, rehearsing? That our personalities would die through the process, our jokes would be canned, and we would seem totally fake? I’ll hold off on answering that for a minute.

Our next issue in rehearsing the script was that we were still way over. Even with a revised script, it was too long (7+ minutes), and we were still stumbling over certain sections. Some badges were just too difficult to explain (like the Biker Gang badge) and some transitions (“I’ll hand the baton over to Josh now to explain further steps…”) were flow-killing.

Here’s where having a script is a major benefit. You not only can make decisions on what to cut as a group, you visually have a map of how to cut and condense certain sections. I took over some of my teammate Josh’s lines. My transition sentence became Katie’s first line. I could cue Anisha’s line about social media and tweeting the badges you’ve just earned by ending my segment with “and you get a Bridge Crossing badge for that.”

With the script, we achieved last minute efficiencies up till even 30 minutes before the event started because we had something we could all look at and edit. We were never without a roadmap, even as the enormity of the task at hand loomed ever closer.

Rehearsed (to Death), and Ready to Crush It!

Backstage just before the talkBackstage just before the talk

By the time of the event, we were all sick of our script. None of it seemed funny to any of us. Our rehearsals had been earnest, but definitely lacking in personality. Each of us could mouth the words of the other teammates as they were saying their lines since it was mostly verbatim out of the script. Had we drilled enough, or too much? Would we be understood? Would we be able the convey the fun experience that is BikeWithFriends and the passion we put into building it?

Maybe the title of this section is too negative. Because the talk actually went over better than any of us could have dreamed. All of us on the team were more than just a little surprised, we were genuinely shocked we got so many laughs and such a warm response from the NYTM crowd. They are an awesome bunch, by the way!

We felt very comfortable on stage. The script was on the podium, flanked by the presentation laptop, but we didn’t even need it there. The amount of work that went into the script paid off completely. None of us were lost at all during the presentation. We were easily able to keep the flow of the talk going, hand off the mics to each other, and navigate through the app with complete ease.

Though nothing happening on the stage was extemporaneous, with the energy in the room — and our own adrenaline and hearts racing — we could feel our words connecting with the crowd as if they were spontaneous. After the first laughs, right after Josh said “our app does none of these” and waved his hand horizontally, we knew we were going to be fine.

The Code to Crack The Nerves

I know this blog entry has said nothing about our app, BikeWithFriends. Yes, the topic which you choose to speak about needs to be exciting on its own merit. But actually presenting something provides its own specific challenges.

Just like how you might approach a coding problem, breaking down and controlling for as many variables as you can, we approached this presentation in the same manner. The most obvious unknown was probably “how do we handle our nerves?” Would we break down in front of the massive audience at Skirball, unable to form even one coherent sentence? We couldn’t let that be a possibility.

Q&A section, relieved that the presentation part is overQ&A section, relieved that the presentation part is over

Instead, we wrote a code: the script. The rehearsals amounted to refactoring that code to guarantee that it ran smoothly and efficiently. Even if we couldn’t control for the nerves, we prepared and “coded” for all the parts we could control: what we would say and how we would say it. Once we were on stage, I remember stumbling on some words here and there. But that didn’t matter too much. The nerves didn’t knock me off my game because — channeling Sandi Metz — I was the expert on the topic, I had prepared and rehearsed exactly what I was going to say and knew exactly why I wanted to say it.

Conclusions

The event really flew by for us. We had less than a week to prepare for the talk, but all the pieces somehow managed to fall into place. It certainly helped that we had already presented our project twice before the event. I’m sure I’ll have more thoughts about how to structure a talk when I have to do it again, but I am glad that it’s over.

Perhaps the final side note I have is that once you are onstage, near the mics, be careful what you say. Especially if there is a livestream being captured for the event. In our excitement, one of my teammates may have used some colorful language, exclaiming “We’re going to #$%@ crush this!” Oops. But, in the end, I’m so glad we did.

(Watch the official livestream of our meetup presentation at nytm.org or on YouTube)

Building BikeWithFriends

By Ning Yap

BikeWithFriends

I feel like I just gave birth to something. I feel drained, but at least the app is out there in the world now, living and breathing on it’s own… (sort of)

Multiple Starts

The genesis of the app was really more an area of focus than anything specific. After completing Ashley William’s CitiBike excercise for class at The Flatiron School, I really wanted to play more with CitiBike JSON data and maps. I discussed with my group my hope to create some rough proof of concepts about ideas we could turn into projects.

Proof of Concept w/ Bike RouteProof of Concept w/ Bike Route

I turned to my old, trusted friend Google to research what was already out there. There were a good amount of sites visualizing macro data regarding available bikes at all the stations, which was pretty cool, but I knew early on it wasn’t worth trying to replicate that sort of implementation. The available bikes/docks data is available to everyone, and I saw multiple sites using that data in the same ways.

Originally I wanted to make an app that could text/email you if your “home” CitiBike station as out of bikes. It would also allow you to see the viability of a commute based on collected data about your start and end stations and a specified time of departure. It became apparent this would be a data intensive task, though doable.

Another focus for me was playing with map features as I think having a visual component to interact with is always fun and adds interest. The first POC involved getting bike directions to show up between two selected stations. The second POC gave you the ability to type in any address and it would show you the closest bike station to you.

Proof of Concept 2 w/ Address SearchProof of Concept 2 w/ Address Search

Proof of Concept 2 w/ Nearest StationProof of Concept 2 w/ Nearest Station

The proof of concepts were for the most part discarded in the final concept that became BikeWithFriends, but the time spent and knowledge gained through building those two apps gave me a level of confidence about being able to work closely with CitiBike data and creating an interactive user experience. In the meantime, I had signed up for a CitiBike membership and would receive a key by the end of the week.

Major Pivot and Breakthrough

Just a day or two after the POCs were done, my team and a few other classmates were at Shake Shack waiting on line for burgers and shakes and through our discussions, we came up with new ideas for creating a better experience for users of our site: We would make CitiBiking into a sort of game, with leaderboards, the possibility of racing from one station to another station, and using CitiBike’s trip data to calculate durations of your trips and start and end stations, which would put you on a leaderboard.

BikeWithFriends

That idea quickly blossomed and matured. How about awarding badges for completing different kinds of trips and meeting certain game-like conditions? Badges for number of trips taken, stations visited, for crossing a bridge, or even for biking with someone else?

We realized how cool this concept could be, but would we be able to transform it into code? I spent my Sunday biking around Manhattan and to Williamsburg and Brooklyn to generate some data for our app. BTW, generating data for your app has to be one of my most favorite pastimes. I’m learning how much I love good, real seed data as it provides you with a much, much better picture of what your app should be and how it might be used. Biking around the city and across the bridges gave me an idea of getting a badge for crosssing the bridge. Biking along the south tip of Manhattan gave me an idea to award a badge for visiting the stations that give you a view of the Statue of Liberty. Or how about biking on holidays?

BikeWithFriends

Vision Becomes Reality

The experience of seeing something come from nothing has been amazing. And to see that passion recognized by being selected as Hack of the Month for the August NY Tech Meetup is unbelievably rewarding. We will present on August 7th at NYU Skirball Performing Arts Center for an audience of 1,000+. We’re stoked! Look for the follow-up blog post!

BikeWithFriends

Recipe Book UI: Building a Custom JQuery User Interface

By Ning Yap (@ningbit)

RecipeUI Play with the completed UI at recipeui.herokuapp.com!

UI Driven Development

The battle between front-end and back-end continues to be waged. But who cares about that? Let’s make a beautiful UI because it makes us happy!

Relevant JQuery Code:

$("[HTML element])

selects the element, by element id being quite common and efficient.

.click()

captures a click event.

.html()

will write HTML code into your page directly.

.css("display","none")

hides an element by adding the CSS display property.

.fadeIn()

fades in your element.

Also, let’s use FlatUI, a Boostrap-wrapped theme. Download here!

Origin of The Pantry

So in class at the Flatiron School, we were asked to create a Rails app that mimicked the relationship between recipes and ingredients. But, we were not to instantiate new ingredients per recipe. Recipes would share Ingredient objects, only creating new instances if they didn’t already exist. Hence, the idea of a “pantry”:

Idea: The pantry contains all ingredients available to the chef to create her recipe. If she doesn’t have the ingredients handy, she must go shopping at the local marketplace.

UI Concept: How about clicking on visual representations of ingredients in the pantry and “popping” them into the recipe list? Sounds awesome right?

CreateRecipeUI

Death To The Dropdown!

My golden rule for dropdown menus is don’t use them. They suck. Especially if you have more than 10 elements. -Me

How to Achieve The Desired UI and Experience Nirvana

First, suffer deeply through the difficulty of implementing a fun UI interface via a JavaScriptERB partial from scratch. Just kidding! It’ll be much better for you since you can just borrow my template. :)

Here’s what the brute-force code looks like:

RecipeUI (recipeui.js.erb) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script>

  // Adds pantry ingredient to ingredient list
  <% ingredient_array.each do |i| %>
  $("#ingredient-<%=i.gsub(" ","_")%>").click(function(){
    var htmlstring = $("h4#list").html();
    var commastring
    if (htmlstring == ""){commastring = "";}
      else {commastring = ", ";}
    $("h4#list").html(htmlstring + commastring + "<%=i%>");
      $("#ingredient-<%=i.gsub(" ","_")%>").css('display','none');
    });
  <%end%>

  // Reset ingredient list and restores pantry
  $("#reset_ingredients").click(function(){
    $("h4#list").html("");
    <% ingredient_array.each do |i| %>
      if ($("#ingredient-<%=i.gsub(" ","_")%>").css('display')==='none'){
        $("#ingredient-<%=i.gsub(" ","_")%>").fadeIn();
      }
    <%end%>
  });

  // Submit finished recipe by writing value into hidden form-field
  $("#ingredient-submit").click(function(){
    var completed_list = $("h4#list").html();
    $("#submitted-list").val(completed_list);
  });

</script>

There are two actions associated with a click. It must hide the pantry item and append to the recipe. If you don’t hide the pantry item, recipes could have duplicate items. Use ERb each loops to loop through the entire ingredient list and create a JQuery click action for each. A reset action “resets” the recipe and refresh the pantry. A submit action writes the finished recipe to the hidden form field on the page.

Hidden Form (hidden_formfield.html.erb) download
1
2
3
4
5
6
<form action="<%= recipes_path %>" method="POST">
  <input id="submitted-list" type="hidden" name="ingredients_list" value=""/>
.
.
.
</form>

Reference each ingredient element by assigning a dynamically generated id in your view HTML ERb

ID Generator (dynamically_generated_id.html.erb) download
1
2
3
<% @ingredients.each do |i| %>
  <p class="btn" id="ingredient-<%=i.name.gsub(" ","_")%>"><%=i.name%></p>
<%end%>

Pass the render function the js.erb partial and a local variable encapsulating all your ingredients.

Render Partial (render_partial.html.erb) download
1
<%= render :partial => 'jscript', :formats=>[:js], :locals => {:ingredient_array => ingredient_array}%>

And it’s just that simple!

Recycle Your Code (still keepin’ it DRY)

  • Make the necessary adjustments to your Edit view, i.e. hide the elements that are already in the recipe.
  • Add a minor twist and make a garbage disposal! :)
  • Give it some flair by hiding the disposal until the user tries to dispose. Fade out if the user changes his mind and cancels.

Check out the repo for how-to.

Switch Up. Make a Shopping Cart Text Field!

ShoppingCart

Same principles here. Clicking add should pop the typed text into the cart. It takes just a few different lines of code. When you “submit” the form (text field) by clicking the “add” button, it will try to redirect you to a new page. Kill that action by putting this code in the “action” attribute of the form.

<form action="javascript:void(0);">

Add some simple animation. Make the field shake if the user tries to add badly-formatted items.

Shake Animation (shake.js.erb) download
1
2
3
4
if (/^[a-zA-Z -]*$/.test(newitem) && newitem !== ""){
  $("h4#list").html(htmlstring + commastring + newitem);
  $("#cart-item").val("");}
else {$("#shop-cart").effect("shake");}

Polish that UI

How about a cool feature to highlight the new items you just bought? Use the .updated_at method and subtract from Time.now.

Highlight Recently Added (recently_added.html.erb) download
1
<p class="btn <%= "btn-primary" if i.updated_at - Time.now > -600 %>">

Make the colors of the buttons refer to their usage!

RecipeButtons

How about smartly listing the ingredients in the main recipe window? Show the first four ingredients and then append a “…” if there are more ingredients. With ERb, the world is your oyster recipe.

RecipeBook

Now go generate your own ERb.js UI!

How to Integrate Bootstrap CSS Into Your Sinatra Site, and Get More Out of Your Objects Using ERB

By Ning Yap

Bootstrap

Twitter Bootstrap + Sinatra = Beautiful Routes

1) Grab the Bootstrap Package

Visit Bootstrap and download the zip file. Unzip and copy the css, js and img folders into the ‘public’ folder of your Sinatra site directory.

public folder

2) Edit Your Template (layout.erb)

Edit your layout.erb to include bootstrap.css within the <head> tags.

css head

bootstrap.js goes within your <body> tags at the end.

js body

Note the positioning of <%= yield %> ERB tag which will take content from other ERB templates within your views directory. The file layout.erb is a convention of Sinatra that automatically becomes the default “layout” template of your site. This can be changed within your routes manually.

3) Navigation Bar

bootstrap navbar

Consider your nav bar, which will sit on top of every page that uses your default layout. Bootstrap makes it very easy to create drop down menus and also includes a search bar. Use ERB (each loops) to dynamically generate menu items! For example, in the Genres dropdown menu, the list of genres is dynamically calculated, as is the total number of songs in each category.

Navbar CSS and ERB (navbar_example.erb) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
  <div class="navbar navbar-fixed-top">
  <div class="navbar-inner">
    <div class="container">
      <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </a>
      <a class="brand" href="/home">Playlister  <img src="/img/youtube_icon_small.gif"></a>
      <div class="nav-collapse">
        <ul class="nav">
          <li><a href="/artists">Artists</a></li>
          <li><a href="/songs">Songs</a></li>
          <li class="dropdown">
            <a class="dropdown-toggle" data-toggle="dropdown">Genres <b class="caret"></b></a>
            <ul class="dropdown-menu">
              <% @genres = Genre.all.sort_by { |g| g.name }%>
              <% @genres.each do |genre| %>
                <li><a href="/genres/<%=genre.name.gsub(" ","_")%>"><%= "#{genre.name.capitalize} (#{genre.songs.count})" %></a></li>
              <% end %>
            </ul>
          </li>
          <li class="dropdown">
            <a class="dropdown-toggle" data-toggle="dropdown">Library <b class="caret"></b></a>
            <ul class="dropdown-menu">
              <li><a href="/artists/add">Add Artist</a></li>
              <li><a href="/artists/drop">Drop Artist</a></li>
              <li><a href="/songs/add">Add Song</a></li>
              <li><a href="/songs/drop">Drop Song</a></li>
              <li><a href="/genres">Add Genre</a></li>
            </ul>
          </li>
          <li><a href="/random">Shuffle</a></li>
        </ul>
        <form class="navbar-search" action="/search" method="GET">
          <input type="text" class="search-query span4" placeholder="Search" name="search">
        </form>
      </div><!-- /.nav-collapse -->
    </div><!-- /.container -->
  </div><!-- /.navbar-inner -->
</div><!-- /.navbar -->

4) Sinatra Routes

Having a navigation bar means making decisions about your routes! Consider your “main” routes, or the ones that will be accessed most often. Try to make most content on the site accessible from within 3 clicks or so from the home page.

5) Add a background via CSS

Subtle Patterns has free “textured” backgrounds that can spruce up the look of your site. Add the texture files to your ‘public/img’ folder of your site and then add the appropriate css between your <head> tags of your layout.erb.

<style>
body {
background-image:url('/img/escheresque_ste.png');
}
</style>

Ooh, look at that “escheresque” background:

background-example

6) Edit the CSS

Don’t be afraid to edit Bootstrap’s CSS file to suit your needs. For example, I edited the “.btn” class to achieve rounder larger buttons to hold artists and songs. Refer to the Components section of the documentation for more tips and examples of included styles.

btn-example btn-large

7) Know Your Grid

Utilize “container” class and “span#” to take advantage of pre-configured grid/responsive design. Be aware of block elements and inline elements. “Span” classes can collapse responsively as the window resizes.

8) Getting Creative with Href-ing and Routes

Achieve flow by having objects point to each other and organize them both visually and logically. Add/drop features are more advanced and are “hidden” away, drop buttons are given class of danger to highlight destructive nature. Ultimately, dynamic pages/data are more interesting, so if you’ve built robust Classes/Objects in your code, pull the data into the page with ERB and make your site feel alive!

bootstrap-dashboard

Checkout my repository here to see the results!

Quit Playing Games With My Ruby Code

By Ning Yap [@ningbit]

Tetris, c.1986 in a Soviet labTetris, c.1986 in a Soviet lab

I don’t mean to pigeonhole myself and this blog into being all about game development and game design (as my first two posts would seem to indicate), but it is what my beginner mind is gravitating towards, mainly out of curiosity. Maybe because I don’t get to play games anymore and consider them a poor investment of my time these days. But programming games… That’s cerebral and smart! *ahem

So perousing speakerdeck.com for a class assignment alerted me to the fact that I’m not alone at all. See here and here. There are a good number of people interested in utilizing Ruby for game development. And where there is interest — I’m learning — there are always gems! The one I’ll be focusing on (and also using) is called ‘Gosu’.

gem install gosu

So there’s a good amount of documentation about gosu on their site http://www.libgosu.org/, much of which I’m sure I’ll understand better once I try to implement it. But I’ll summarize what gosu is here

  • It’s a 2D game development library
  • It’s C++ based, with a Ruby wrapper
  • Finished game will run on OSX, Linux and Windows platforms
  • OpenGL is used for rendering

So my last game I tried to write, see my last post, was played in the command line, didn’t refresh, and had no sprites or fancy graphics. With gosu, I’ll be able to take advantage of real-time input from the player in the form of any keystroke (I’m thinking of a cool typing game!). It will be able to draw the window and then re-draw (I’m thinking of car-crashes and collisions and block-exploding animations). The Resource Manager allows for images and sprites (time to pay direct homage to my 8-bit and 16-bit past). The Game State Manager allows for win, loss, death, pause conditions (very much like real-life).

(gosu_example.rb) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    require 'gosu'

    class GameWindow < Gosu::Window
      def initialize
        super 640, 480, false
        self.caption = "Gosu Tutorial Game"
      end

      def update
        # game logic goes here
      end

      def draw
        # render logic goes here
      end

      def button_down button_id
        # called when button is pressed
      end
    end

    window = GameWindow.new
    window.show

Not only that, there is even an option for adding sound, which is probably the icing on the cake, since I didn’t tell you this, but I actually studied music/sound production in college.

Mario Teaches TypingMario Teaches Typing

Ruby Typing Game?

Anyway, I recall this game called “Mario Teaches Typing” from the early 90s — back when it was possible to not know how to type (Mavis Beacon, anyone?). That game turned out to be pretty garbage, because speed typing to make Mario jump is horribly unsatisfying. But maybe we should take another look? How about a game that teaches basic Ruby syntax. Can writing nested each loops be a fun game play mechanic? I’ll have an answer to that question in the next few weeks, hopefully.

8-Bit Git: The Challenges of Creating a Git-Based Game

By Ning Yap [@ningbit]

LOZ NES game

I made some games, but I’m pretending like I didn’t because they all turned out weird. — Shigeru Miyamoto (creator of The Legend Of Zelda)

Game Start

After day one of using Git during a lesson @TheFlatironSchool, I developed this fantastic (and insane) idea to write a simple Git-based adventure game loosely based on my favorite video game series of all-time, The Legend of Zelda. My initial idea was to use git branches and branch switching to represent the different “worlds” containing “treasures” to be collected, like

  • Forest branch….. w/ master sword

  • Desert branch…. w/ ocarina

  • Mountain branch…. w/ fairy in a bottle

This “branch-world” idea quickly became preposterous as Git branches are not meant to be completely distinct entities, but rather different versions of a master branch and represent modest changes in files and structures. I realized I’d need a cleaner, more sensible approach.

Tutorial-Based Game

It became apparent that if I wanted to build a sensible game, I would need to actually study Git and understand how it should be used. I would have to acknowledge and draw upon Git’s power as a version control system and create a context to utilize that workflow.

8-Bit Git: The Legend of BASHellda

Thus, The Legend of BASHellda was born. It would be a tutorial — masking as a game — played from the BASH command line. It would use sensible, beginner-friendly git commands, like

git status
git branch
git checkout
git merge
git add .
git commit -am "update files"

And to provide instructions to the player, I would have Princess BASHellda leave notes (in .txt format) to guide the player on what to do next.

Princess's Note

Logistics and Building a Story

The classic story of The Legend of Zelda involves a hero saving a princess from an evil wizard through the use of key items, such as a magical sword. Here is how I mapped those characters and items

Link (Hero)       => $User
Princess Zelda    => Princess BASHellda
Ganon             => Prince of Darkness "BSOD"
Triforce          => Git
Master Sword      => Sword of RM (on "master" branch)
Hyrule Kingdom    => Land of 8-bit
Hyrule Castle     => Bit Palace
Locked Chest/Door => password-protected zip-file

And here are the branches or “worlds”

master            = Bit Palace has been reduced to rubble by BSOD
backup            = Contains "backup" of Bit Palace
cursed_dungeon    = Princess is locked up in zip file

Sample note from the Princess in .txt file accessible by running cat command in BASH

Dear $User,

By the time you read this, BSOD will have already locked me away in the
cursed dungeon remote branch. But no fear, you have been granted the powers
of Git. The first thing to do is find out where you are. Type:

git status

Currently, you are on the master branch. You should see "On branch master"
and more output. To find out additional local branches, type:

git branch
...

Building the Local Repository

Figuring out the gameplay logistics was half the battle. The other half was actually coding and “building the levels” in the repository. Here are some of the major issues I ran into as I built and played through the initial stages of the game:

  • In what finished form should the repository be so, when pushed up to GitHub, it is playable when cloned
  • Will the player have access to the different branches after cloning
  • How to deal with the branch merges so there are no conflicts
  • How to leave clear and concise instructions with moderate difficulty so as not to make the game too easy and boring or unplayable and confusing for a beginner

In building the repository, order of creating branches and adding folders and files was extremely important as to not cross-pollute other branches. For example, I would want

bit_palace/rubble.txt

to be replaced by

bit_palace/bit_palace.txt

after running

git merge backup

on the master branch. Here’s what the palace “looks like” after the player merges from backup.

Bit Palace

Future Ideas

This is an ongoing project that will improve as I continue to learn and use git. I think I will build out different stages of the game to show the more advanced techniques of git that I don’t yet know. Stay tuned!