Compare commits

...

No commits in common. "master" and "gh-pages" have entirely different histories.

24 changed files with 709 additions and 1963 deletions

21
LICENSE
View file

@ -1,21 +0,0 @@
The MIT License
Copyright (c) 2009 - 2011 Ryan McGrath
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,65 +0,0 @@
#!/usr/bin/python
"""
Build-script that brings together all the JS files for wii.js and
takes care of minifying it down to a decent size.
Before you even ask, no, we're not using uglify.js or Closure. Both
of them are simply too aggressive for their own good; while normally this
is an excellent feature to have, the JS engine that the Opera version on the Wii
uses has a really odd set of quirks when you start trying to get smart with code,
and YUI is the only minifier that doesn't appear to totally destroy it all through
obfuscation. We'll forego a few bytes to have the thing working. ;P
Uglify also requires Node.js. While I *love* Node, I'll wait until it's more readily
available on Windows - there are a large amount of Windows-based programmers that I'm
not keen on keeping out of development.
"""
import os
from subprocess import call
currdir = os.getcwd()
# The names of our JS files (minus the .js) that we want to build into the
# final distribution.
DEPENDENCIES = [
'wii',
'util',
'console',
'remote',
]
# What we're going to end up injecting as our core build, into core.js.
inject_build = ''
def minify_code(filename, final_filename):
"""
Dips out to Java/YUI compressor and runs the minifier on the specified file, dumping the
output into the specified final_filename.
"""
#cmd = 'java -jar %s/utilities/yuicompressor-2.4.2.jar %s -o %s' % (currdir, filename, final_filename)
call(['java', '-jar', '%s/utilities/yuicompressor-2.4.2.jar' % currdir, filename, '-o', final_filename])
# Run through each dependency, read it into "inject build", then do a simple split on the
# contents of core.js and wrap it all up.
for dependency in DEPENDENCIES:
f = open('%s/js/src/%s.js' % (currdir, dependency), 'r')
inject_build += f.read()
f.close()
# Open core.js, split it on our build spot, wrap junks.
f = open('%s/js/src/core.js' % currdir, 'r')
core = f.read()
f.close()
core = core.split('/*{{inject_build}}*/')
# Write out a non-minified build.
f = open('%s/js/wii.js' % currdir, 'w')
f.write(core[0])
f.write(inject_build)
f.write(core[1])
f.close()
# Write out a minified build.
minify_code('%s/js/wii.js' % currdir, '%s/js/wii.min.js' % currdir)

1
css/arta.min.css vendored
View file

@ -1 +0,0 @@
pre code{display:block;padding:.5em;background:#222}pre .header,pre .profile .header *,pre .ini .title{color:#fff}pre .comment,pre .javadoc,pre .preprocessor,pre .shebang,pre .profile .summary,pre .diff,pre .pi,pre .doctype,pre .xml .tag,pre .template_comment,pre .css .rules,pre .tex .special{color:#444}pre .string,pre .symbol,pre .diff .change,pre .regexp,pre .xml .attribute,pre .xml .value,pre .smalltalk .char,pre .ini .value{color:#fc3}pre .number,pre .addition{color:#0c6}pre .built_in,pre .literal,pre .vhdl .type,pre .go .constant,pre .go .typename,pre .ini .keyword,pre .lua .title,pre .perl .variable,pre .php .variable,pre .mel .variable,pre .django .variable,pre .css .funtion,pre .smalltalk .method,pre .hexcolor,pre .important,pre .flow,pre .inheritance,pre .parser3 .variable{color:#32aaee}pre .keyword,pre .xml .tag .title,pre .css .tag,pre .css .class,pre .css .id,pre .css .pseudo,pre .css .attr_selector,pre .lisp .title,pre .winutils,pre .tex .command{color:#64a}pre .class .title,pre .ruby .constant,pre .vala .constant,pre .parent,pre .deletion,pre .template_tag,pre .css .keyword,pre .javascript .title,pre .objectivec .class .id,pre .smalltalk .class,pre .lisp .keyword,pre .apache .tag,pre .nginx .variable,pre .envvar,pre .bash .variable,pre .go .built_in,pre .vbscript .built_in,pre .lua .built_in,pre .rsl .built_in,pre .tail,pre .avrasm .label,pre .parser3 .title,pre .tex .formula,pre .tex .formula *{color:#b16}pre .yardoctag,pre .phpdoc,pre .profile .header,pre .ini .title,pre .apache .tag,pre .parser3 .title{font-weight:bold}pre .xml .javascript,pre .xml .css,pre .xml .cdata{opacity:.6}pre code,pre .javascript,pre .css,pre .xml,pre .subst,pre .diff .chunk,pre .css .value,pre .css .attribute,pre .lisp .string,pre .lisp .number,pre .tail .params,pre .container,pre .haskell *,pre .erlang *,pre .erlang_repl *{color:#aaa}

View file

@ -1,52 +0,0 @@
/**
* Wii Demo CSS
*
* Uses a basic CSS reset, and then some very rudimentary styles to make stuff easy
* on the eyes with the Wii console.
*/
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, font, img, kbd, q, s, samp,
small, strike, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0; padding: 0; border: 0; outline: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; }
:focus { outline: 0; }
body { line-height: 1; }
ol, ul { list-style: none; }
table { border-collapse: separate; border-spacing: 0; }
caption, th, td { text-align: left; font-weight: normal; }
blockquote:before, blockquote:after, q:before, q:after { content: ""; }
blockquote, q { quotes: "" ""; }
html {
color: #333;
font: normal 22px/26px helvetica, arial, sans-serif;
padding: 0px;
background: #fff;
overflow: hidden !important;
}
body { overflow: hidden !important; padding: 20px; }
h1 { background-color: #42a2cc; color: #f9f9f9; font-size: 44px; padding: 10px; }
a, a:visited {
background-color: #42a2cc;
color: #f9f9f9;
padding: 3px 5px;
text-decoration: none;
display: inline-block;
}
a:hover { background-color: #147ba8; }
p {
padding: 10px;
margin-bottom: 10px;
}
/* "Players". ;) */
.player { position: absolute; top: 400px; width: 26px; height: 26px; text-align: center; border: 2px solid #010101; padding: 10px; }
.player span { background-color: #f9f9f9; padding: 5px 5px 4px; font-weight: bold; }
#player_1 { background-color: #ef1419; color: #ef1419; left: 500px; }
#player_2 { background-color: #13c32c; color: #13c32c; left: 580px; }
#player_3 { background-color: #e6d01a; color: #e6d01a; left: 660px; }
#player_4 { background-color: #af0bb1; color: #af0bb1; left: 740px; }

View file

@ -1,69 +0,0 @@
/**
* Basic CSS for server sent events demo.
*/
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, font, img, kbd, q, s, samp,
small, strike, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0; padding: 0; border: 0; outline: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit; vertical-align: baseline; }
:focus { outline: 0; }
body { line-height: 1; }
ol, ul { list-style: none; }
table { border-collapse: separate; border-spacing: 0; }
caption, th, td { text-align: left; font-weight: normal; }
blockquote:before, blockquote:after, q:before, q:after { content: ""; }
blockquote, q { quotes: "" ""; }
html {
color: #333;
font: normal 22px/26px helvetica, arial, sans-serif;
padding: 0px;
background: #fff;
overflow: hidden !important;
}
body {
overflow: hidden !important;
padding: 0px;
margin: 0px;
}
h1 {
background-color: #01acca;
padding: 20px 0;
text-indent: 20px;
color: #fff;
font-weight: bold;
font-size: 1.8em;
}
h2 { font-size: 1.5em;background-color: #e9e9e9; border-bottom: 1px solid #c9c9c9; margin: 0; padding: 15px; }
a, a:visited { color: #01acca; font-weight: bold; text-decoration: none; }
ul { margin: 10px 0 0 45px; list-style-type: disc; }
li {
font-size: 1.3em;
line-height: 1.3em;
padding: 10px 0;
color: #555;
}
.slide {
display: none;
border: 1px solid #c9c9c9;
background-color: #f9f9f9;
margin: 30px auto;
padding: 0;
}
pre {
background: #333;
color: #f9f9f9;
font-size: 18px;
line-height: 22px;
font-family: inconsolata, monospace;
width: 92%;
border-radius: 4px;
padding: 10px;
}

BIN
images/checker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

View file

@ -1,108 +1,287 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Wii.js Demo</title>
<link rel="stylesheet" type="text/css" media="screen" href="css/demo.css">
</head>
<body>
<h1>Wii.js Demo</h1>
<p>
This is a demo page meant to show how easy it is to interact with the Nintendo Wii remotes using Javascript. It's
powered by <a href="http://github.com/ryanmcgrath/wii-js/">wii-js</a>, a Javascript library that abstracts the differences
and pain points associated with using the Wii remotes.
</p>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Wii-js by ryanmcgrath</title>
<p>
This demo is really simple, and works best with all Wii remotes (Wiimotes). Hold a Wiimote horizontal (sideways), and use
the directional pad to move a box floating in the bottom right corner around. Wiimote #1 is red, #2 is green, #3 is yellow, #4 is purple.
Have fun!
</p>
<link rel="stylesheet" href="stylesheets/styles.css">
<link rel="stylesheet" href="stylesheets/pygment_trac.css">
<script src="javascripts/scale.fix.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<div id="player_1" class="player"><span>1</span></div>
<div id="player_2" class="player"><span>2</span></div>
<div id="player_3" class="player"><span>3</span></div>
<div id="player_4" class="player"><span>4</span></div>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="wrapper">
<header>
<h1>Wii-js</h1>
<p>A sane, documented, (hopefully) performant event-based library for Wiimote webpage interaction.</p>
<p class="view"><a href="https://github.com/ryanmcgrath/wii-js">View the Project on GitHub <small>ryanmcgrath/wii-js</small></a></p>
<ul>
<li><a href="https://github.com/ryanmcgrath/wii-js/zipball/master">Download <strong>ZIP File</strong></a></li>
<li><a href="https://github.com/ryanmcgrath/wii-js/tarball/master">Download <strong>TAR Ball</strong></a></li>
<li><a href="https://github.com/ryanmcgrath/wii-js">View On <strong>GitHub</strong></a></li>
</ul>
</header>
<section>
<h1>wii-js</h1>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<script src="js/wii.js"></script>
<script>
var wiimote = new Wii.Remote(1, {horizontal: true}),
wiimote2 = new Wii.Remote(2, {horizontal: true}),
wiimote3 = new Wii.Remote(3, {horizontal: true}),
wiimote4 = new Wii.Remote(4, {horizontal: true}),
p1 = $('#player_1'),
p2 = $('#player_2'),
p3 = $('#player_3'),
p4 = $('#player_4');
<p>The Nintendo Wii is an entertainment system with an utterly <em>massive</em> install base, and when
you couple it with the fact that it's got a web browser (mostly) built in, there's a lot of
potential for third party development. Sadly, few have opted to do any sort of development for
it. While it doesn't help that Nintendo pretty much dropped the ball on this opportunity, the
experience of browsing the web on the Wii isn't actually that compelling to begin with.</p>
wiimote.when('pressed_down', function() {
Wii.util.debug({'message': 'You gone and done it now boy!'});
throw new Error('LOL');
p1.css({'top': p1.position().top + 50});
});
<p>That said, I think this can serve one other purpose: it's an ideal environment to teach children
how to program! I created this library to sanitize Wii interaction with webpages in the browser,
as it's notoriously crippled. It aims to offer a solid, documented, performant API that's easy to
understand and pick up. With this library, you can have up to 4 Wii-motes interacting with your
webpage at once, a dynamic not found in other web browsing mediums.</p>
wiimote.when('pressed_right', function() {
p1.css({'left': p1.position().left + 50});
});
<p>You can find a built source file and a <em>minified</em> source file for production use in the <strong>/js/</strong> directory.
To play with a live example, load up the demo (_index.html_) on your own server, or feel free to use mine:</p>
wiimote.when('pressed_left', function() {
p1.css({'left': p1.position().left - 50});
});
<p><strong>wii-js Demo: <a href="http://venodesigns.net/wii/">http://venodesigns.net/wii/</a></strong> </p>
wiimote.when('pressed_up', function() {
p1.css({'top': p1.position().top - 50});
});
<p>Working with the Wii's browser can be odd - it has moderately good support for CSS, so you're never really
as bad off as you'd be with a version of Internet Explorer - that said, if you're looking for a good read
on what's supported, check out <strong><a href="http://www.opera.com/docs/specs/opera9/?platform=wii">this article on Opera Wii supported technologies</a></strong>.</p>
wiimote2.when('pressed_down', function() {
p2.css({'top': p2.position().top + 50});
});
<p>Questions, comments, criticism and praise can be directed to me at the following outlets:</p>
wiimote2.when('pressed_right', function() {
p2.css({'left': p2.position().left + 50});
});
<ul>
<li>You can email me at <strong>ryan [at] venodesigns (dot) net</strong>.<br>
</li>
<li>You can hit me up on Twitter: <strong><a href="http://twitter.com/ryanmcgrath/">@ryanmcgrath</a></strong><br>
</li>
<li>Contact me through <strong><a href="http://venodesigns.net">my website</a></strong><br>
</li>
<li>
<strong>Technical issues can be filed on the <a href="https://github.com/ryanmcgrath/wii-js/issues">wii-js GitHub Issues Tracker</a></strong><br>
</li>
</ul><h2>Example Usage</h2>
wiimote2.when('pressed_left', function() {
p2.css({'left': p2.position().left - 50});
});
<div class="highlight"><pre><span class="kd">var</span> <span class="nx">wiimote</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Wii</span><span class="p">.</span><span class="nx">Remote</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="p">{</span><span class="nx">horizontal</span><span class="o">:</span> <span class="kc">true</span><span class="p">}),</span>
<span class="nx">wiimote2</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Wii</span><span class="p">.</span><span class="nx">Remote</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="p">{</span><span class="nx">horizontal</span><span class="o">:</span> <span class="kc">true</span><span class="p">});</span>
wiimote2.when('pressed_up', function() {
p2.css({'top': p2.position().top - 50});
});
<span class="nx">wiimote</span><span class="p">.</span><span class="nx">when</span><span class="p">(</span><span class="s1">'pressed_a'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">alert</span><span class="p">(</span><span class="s1">'Wiimote #1 pressed the A Button!'</span><span class="p">);</span>
<span class="p">});</span>
wiimote3.when('pressed_down', function() {
p3.css({'top': p3.position().top + 50});
});
<span class="nx">wiimote2</span><span class="p">.</span><span class="nx">when</span><span class="p">(</span><span class="s1">'pressed_a'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">alert</span><span class="p">(</span><span class="s1">'Wiimote #2 pressed the A Button!'</span><span class="p">);</span>
<span class="p">});</span>
wiimote3.when('pressed_right', function() {
p3.css({'left': p3.position().left + 50});
});
<span class="nx">Wii</span><span class="p">.</span><span class="nx">listen</span><span class="p">();</span>
</pre></div>
wiimote3.when('pressed_left', function() {
p3.css({'left': p3.position().left - 50});
});
<h2>Technical Documentation</h2>
wiimote3.when('pressed_up', function() {
p3.css({'top': p3.position().top - 50});
});
<p>The largest issue with making interactive pages that work with the Wii has been that the API has
been nothing short of a black hole. When you actually begin to dig in and figure out what's going on,
it gets even uglier to see - the primary wiimote, for instance, has a totally different set of signals
than the other three.</p>
wiimote4.when('pressed_down', function() {
p4.css({'top': p4.position().top + 50});
});
<p>wii-js abstracts away most of these differences and/or problems, and works on a very simple event-dispatch
system. What this means is that you create an instance of a Wii Remote, subscribe to events, and provide a
function to get called when that event has occurred. The following syntax should explain this:</p>
wiimote4.when('pressed_right', function() {
p4.css({'left': p4.position().left + 50});
});
<div class="highlight"><pre><span class="nx">wiimote</span><span class="p">.</span><span class="nx">when</span><span class="p">(</span><span class="s1">'event_name_here'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span> <span class="cm">/* My callback function */</span> <span class="p">});</span>
</pre></div>
wiimote4.when('pressed_left', function() {
p4.css({'left': p4.position().left - 50});
});
<p>When instantiating a Wii Remote instance, you can choose to have the library interpret directional pad controls
in horizontal or vertical mode. You can change this at any point, if you want, by simply swapping the property.</p>
wiimote4.when('pressed_up', function() {
p4.css({'top': p4.position().top - 50});
});
<div class="highlight"><pre><span class="kd">var</span> <span class="nx">wiimote</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Wii</span><span class="p">.</span><span class="nx">Remote</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="p">{</span><span class="nx">horizontal</span><span class="o">:</span> <span class="kc">true</span><span class="p">});</span> <span class="c1">// Horizontal controls</span>
<span class="kd">var</span> <span class="nx">wiimote</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Wii</span><span class="p">.</span><span class="nx">Remote</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="p">{</span><span class="nx">horizontal</span><span class="o">:</span> <span class="kc">false</span><span class="p">});</span> <span class="c1">// Vertical controls</span>
Wii.listen({'debug': true});
</script>
</body>
<span class="nx">wiimote</span><span class="p">.</span><span class="nx">opts</span><span class="p">.</span><span class="nx">horizontal</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span> <span class="c1">// Change to horizontal scheme.</span>
</pre></div>
<p>The final important piece is to start the Wii-event loop; this manages the event dispatcher internally. To do this, simply...</p>
<div class="highlight"><pre><span class="nx">Wii</span><span class="p">.</span><span class="nx">listen</span><span class="p">();</span>
</pre></div>
<p>You can listen for the following events on all controllers:</p>
<ul>
<li>
<strong>pressed_up</strong> - The up button was pressed.<br>
</li>
<li>
<strong>pressed_down</strong> - The down button was pressed.<br>
</li>
<li>
<strong>pressed_left</strong> - The left button was pressed.<br>
</li>
<li>
<strong>pressed_right</strong> - The right button was pressed.<br>
</li>
<li>
<strong>pressed_a</strong> - The A button was pressed.<br>
</li>
<li>
<strong>pressed_1</strong> - The 1 button was pressed. (_Note: On controller 1, this triggers a menu - work in progress..._)<br>
</li>
<li>
<strong>pressed_2</strong> - The 2 button was pressed.<br>
</li>
<li>
<strong>pressed_plus</strong> - The plus (+) button was pressed.<br>
</li>
<li>
<strong>pressed_minus</strong> - The minus (-) button was pressed.<br>
</li>
<li>
<strong>roll_change</strong> - The roll of the controller (balance) changed. You can get the current roll in radians with <em>"this.roll"</em>; positive is upright, negative is the other.<br>
</li>
<li>
<strong>distance_change</strong> - The distance of the wiimote (in meters) from the TV/sensor bar has changed. This event isn't totally reliable, but should work for most cases.<br>
</li>
</ul><p>You can listen for the following events on <em>extra controllers</em>, but not the primary controller.</p>
<ul>
<li>
<strong>pressed_b</strong> - The B button was pressed.<br>
</li>
<li>
<strong>pressed_c</strong> - The C button (on the Nunchuk) was pressed.<br>
</li>
<li>
<strong>pressed_z</strong> - The Z button (on the Nunchuk) was pressed.<br>
</li>
</ul><p>You can also get the following properties from any Wii Remote instance; they will return "undefined" if the remote
isn't able to see the TV/sensor bar, so be sure to check this!</p>
<ul>
<li>
<strong>x</strong> - The x coordinate where the Wii Remote is pointing to on the screen. Generally between 0 and 800, but can be more on wide pages.</li>
<li>
<strong>y</strong> - The y coordinate where the Wii Remote is pointing to on the screen. Odd one; can be found as low as -48, as high as the height
of the current webpage + toolbar height, if enabled. Tinker with this one for your purposes.</li>
</ul><h2>Extra Tips and Tricks (Debugging)</h2>
<p>One semi-useful trick to point out about this library is that each of your callback functions get passed two
arguments by default - a reference to the Wiimote you're working with, and the raw Wiimote status object that the
Wii reports back to the library. You get this in a normalized fashion, instead of having to deal with the odd polling
issues present in the browser.</p>
<div class="highlight"><pre><span class="kd">var</span> <span class="nx">wiimote</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Wii</span><span class="p">.</span><span class="nx">Remote</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="p">{</span><span class="nx">horizontal</span><span class="o">:</span> <span class="kc">false</span><span class="p">});</span>
<span class="nx">wiimote</span><span class="p">.</span><span class="nx">when</span><span class="p">(</span><span class="s1">'pressed_a'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">wii_remote</span><span class="p">,</span> <span class="nx">wii_remote_status</span><span class="p">)</span> <span class="p">{</span>
<span class="cm">/* Alert an internal confidence level provided by the Wii. */</span>
<span class="nx">alert</span><span class="p">(</span><span class="nx">wii_remote_status</span><span class="p">.</span><span class="nx">dpdValidity</span><span class="p">);</span>
<span class="p">});</span>
</pre></div>
<p>Debugging Javascript on the Wii is also nothing short of incredibly annoying, so I've made some efforts to patch this
up and make life a bit easier. My typical debugging strategy with any Wii-related code would always start with
the following. The first thing to do is set the Wii listener to run in debug mode, like so:</p>
<div class="highlight"><pre><span class="nx">Wii</span><span class="p">.</span><span class="nx">listen</span><span class="p">({</span><span class="nx">debug</span><span class="o">:</span> <span class="kc">true</span><span class="p">});</span>
</pre></div>
<p>With this set, you can log errors with any of the following functions. <code>error</code> can be a string or a complex object.</p>
<ul>
<li>
<strong>console.log(error);</strong> - Tried and true, now supported.<br>
</li>
<li>
<strong>console.debug(error);</strong> - Same as console.log here, but syntax is supported.<br>
</li>
<li>
<strong>throw new Error(error);</strong> - Throw them, they'll be logged.<br>
</li>
<li>
<strong>Wii.util.debug(error);</strong> - The core function that handles logging internally.</li>
</ul><p>If the typical Wii debugging flow isn't enough for you, go aggressive with this - just be aware that you can crash
the Wii's browser if you're using try/catch all over the place, as it's not cheap in Javascript.</p>
<div class="highlight"><pre><span class="k">try</span> <span class="p">{</span>
<span class="c1">// Whatever function to execute</span>
<span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span> <span class="nx">Wii</span><span class="p">.</span><span class="nx">util</span><span class="p">.</span><span class="nx">debug</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span> <span class="p">}</span>
</pre></div>
<h2>Why the button limitations?</h2>
<p>The Nintendo Wii treats the primary controller differently than the other ones, and doesn't report any action
from the Nunchuk, nor does it report when someone has pressed the "B" button on the primary controller (as it's used
for scrolling a page).</p>
<p>The Wii Browser also doesn't report data for Gamecube controllers, the Classic controller, or any other accessories.</p>
<p>It's a work in progress to see what can be done about these, but it's impossible to guarantee anything will come out
of it unless Nintendo and/or Opera can come out with something new.</p>
<h2>Known Issues</h2>
<p><strong>Primary Wiimote is a bit more responsive than the extra 3</strong><br>
This library works by polling the status of the three extra Wii-remotes in 100ms intervals and dispatching events
based on this. Anything lower than 100ms causes the Wii to run into memory limitations, and the single-threaded
nature of the browser doesn't really help this issue.</p>
<p>The primary Wii-remote uses an odd combination of DOM-esque callbacks; due to this, it reports <em>more frequently</em> than
the other Wii-remotes. It's not a showstopper by any means, but for small games it would in theory give a weighted advantage.
I'll probably end up throttling this through the library by means of a flag, e.g "game_mode": true in the initial options.</p>
<h2>Todo List</h2>
<ul>
<li>Build in functionality for multiple button presses at the same time (difficult to get right in this environment)</li>
<li>Determine canceling B-button/scrolling on pages ("app"/"game" style)</li>
<li>Determine feasibility of canceling out "1" press on the primary Wii-remote.</li>
</ul><h2>Building and Developing</h2>
<p>If you'd like to help with this library, you're more than welcome to. Simply fork it on GitHub, work away, then
issue me a pull request. I generally respond within 24 hours.</p>
<p>The build system here is pretty simple - edits and changes go into the /js/src/ files, and you can run</p>
<pre><code>python build.py
</code></pre>
<p>from the main directory to build a new version. The minifier here is YUI; Closure/UglifyJS are more aggressive, and
for some reason throw ridiculous issues in the Wii's browser that I've been unable to track down (and I don't have
more time to throw at it).</p>
<p>In short, the builds require Python/Java, but once you've got them all installed you should only need the command above.</p>
<h2>How is this different from...?</h2>
<p>I sadly did not find out about <a href="http://www.bolinfest.com/wii/overview.php">wii.js</a> until after I released this library;
with respect to the original author, his work only covers the primary Wii Remote and not the extra ones, nor has it
been updated in years. While his approach appears to be the same as mine (or mine the same as his), neither one
influenced the other, and they're totally separate works.</p>
<p>With the exception of wii.js, I do not know of any other (remaining) Wii interaction Javascript libraries. It's for
these reasons (and my desire for a simpler API) that I built this. ;)</p>
<h2>Licensing, etc</h2>
<p>wii-js is released under an MIT license. Just provide credit where need be if you choose to use this, it's taken quite
a bit of my time to decipher the utterly random pieces and intricacies of this Javascript engine. ;)</p>
</section>
</div>
<footer>
<p>Project maintained by <a href="https://github.com/ryanmcgrath">ryanmcgrath</a></p>
<p>Hosted on GitHub Pages &mdash; Theme by <a href="https://github.com/orderedlist">orderedlist</a></p>
</footer>
<!--[if !IE]><script>fixScale(document);</script><![endif]-->
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-40660943-3");
pageTracker._trackPageview();
} catch(err) {}
</script>
</body>
</html>

20
javascripts/scale.fix.js Normal file
View file

@ -0,0 +1,20 @@
fixScale = function(doc) {
var addEvent = 'addEventListener',
type = 'gesturestart',
qsa = 'querySelectorAll',
scales = [1, 1],
meta = qsa in doc ? doc[qsa]('meta[name=viewport]') : [];
function fix() {
meta.content = 'width=device-width,minimum-scale=' + scales[0] + ',maximum-scale=' + scales[1];
doc.removeEventListener(type, fix, true);
}
if ((meta = meta[meta.length - 1]) && addEvent in doc) {
fix();
scales = [.25, 1.6];
doc[addEvent](type, fix, true);
}
};

1
js/highlight.min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -1,33 +0,0 @@
/**
* slides.js
*
* Some incredibly ugly quick code for a slides-esque experience
* on both the Wii and browsers.
*
* @Author: Ryan McGrath <ryan@venodesigns.net>
* @Requires: Nothing
*/
var slides = document.getElementsByTagName('div'),
count = slides.length,
index = 0;
var sizeSlide = function sizeSlide(slide, oldIndex) {
slides[oldIndex].style.display = 'none';
slide.style.width = (window.innerWidth - 40) + 'px';
slide.style.display = 'block';
}
document.addEventListener('keydown', function(e) {
if(e.keyCode === 39 && (index + 1) < count) {
sizeSlide(slides[index + 1], index);
index = index + 1;
}
if(e.keyCode === 37 && (index - 1) >= 0) {
sizeSlide(slides[index - 1], index);
index = index - 1;
}
}, false);
sizeSlide(slides[0], 0);

View file

@ -1,20 +0,0 @@
/**
* console.js
*
* A lightweight wrapper for the now-common "console" object in browsers.
* Really just maps calls over to the wii-js internal Wii.util.debug() call,
* but exists so that if you use this in production code for whatever reason
* it could still be used to debug on the Wii.
*
* Note that for this to work, you must be listening in debug mode!
*
* @Author: Ryan McGrath <ryan@venodesigns.net>
* @Requires: wii.js, util.js
*/
if(typeof window.console === 'undefined') {
window.console = {
log: Wii.util.debug,
debug: Wii.util.debug
};
}

View file

@ -1,27 +0,0 @@
/**
* core.js
*
* This is the main template file for bringing together
* the various libraries that power this entire little eco-system.
*
* Building the releases requires Python (2.5+); simply run...
*
* python build.py
*
* ...from the /js/ directory.
*
* @Author: Ryan McGrath <ryan@venodesigns.net>
* @Requires: Nothing, top-level file.
*/
;(function(running_inside_wii_browser) {
/**
* If we're not running inside the Nintendo Wii browser, bail out.
* In the future, branch here for touch-enabled devices...?
*/
if(!running_inside_wii_browser) return false;
/*{{inject_build}}*/
window.Wii = Wii;
})(window.opera && opera.wiiremote);

View file

@ -1,130 +0,0 @@
/**
* remote.js
*
* Handles the subscribing to events portion of a Wii remote. It's best to think of this
* as a "request" object; it asks to be notified of events, and the actual events are
* dispatched from the main wii.js file.
*
* @Author: Ryan McGrath <ryan@venodesigns.net>
* @Requires: wii.js, util.js
*/
/**
* var wii_remote = new Wii.Remote(1, {...});
*
* Instantiates a Wii Remote object. Events can be set on each of these objects,
* and the internal game loop will fire events based on the properties subscribed
* to here.
*
* @param remote_id - Number, required. 1 - 4, dictates which Wiimote this object
* relates to.
* @param opts - Object, optional. Allows you to override internal settings and such,
* should you want different behavior.
* @returns Wii.Remote instance.
*/
Wii.Remote = function(remote_id, opts) {
this.remote_id = remote_id;
this.opts = opts;
/**
* Default these properties to undefined, since that's what
* the Wii returns anyway, and it's worth it to try and stay (somewhat)
* close to the core tech.
*/
this.x = undefined;
this.y = undefined;
this.roll = undefined;
this.last_known_distance_from_screen = undefined;
/**
* If this is the "main" wii_remote, then the bitwise checks will fail
* because it's treated more as a "browsing" device. For these events,
* we'll just store the current wii_remote that's denoted as the "browsing"
* device and let the normal event/key delegation take care of things.
*
* The rest of the wii_remotes will go through the DISPATCHER checks that
* they've subscribed to.
*/
var startupStatus = this.isEnabled();
if(startupStatus) {
if(!startupStatus.isBrowsing) {
Wii.extraRemotes.push(this);
} else {
Wii.currentBrowsingRemote = this;
}
}
};
Wii.Remote.prototype = {
opts: {
/**
* We default the controller to be in the vertical orientation; if
* it's overridden as "horizontal" (false), we'll catch it for the different key
* events and fire accordingly (e.g, the "up" button is different depending on
* how the player is holding the controller).
*/
horizontal: false
},
/**
* A hash of events that this Wii remote is interested in. Each
* entry should be a key (evtName) with a value (response).
* "evtName" is the event name that corresponds with boolean functions
* in the DISPATCHER above, and the response is a remote-bound function
* to call on that event.
*/
evtsInterestedIn: undefined,
/**
* Wiimote.isEnabled()
*
* Determines the status of the wii_remote this object is curious about. Will return
* an updated kPadStatus object if so, false if it's not responding or the data
* is sent back as "invalid". This makes it so we don't bother sending events
* where they're not applicable.
*
* @returns object or boolean.
*/
isEnabled: function() {
var remote = opera.wiiremote.update(this.remote_id - 1);
return (remote.isEnabled && remote.isDataValid ? remote : false);
},
/**
* Wiimote.on(evtName, fn)
*
* Allows you to listen for an event on a given Wiimote. Call this on an instantiated
* Wiimote; "this" will be scoped to the Wiimote object. ;)
*
* @param evtName - String, a supported wii.js (DISPATCHER) event name.
* @param fn - Function, callback function to be executed on the event firing. Will be scoped to the Wiimote.
* @returns object or undefined - instantiated object this was called on to begin with, undefined if evtName is not supported.
*/
when: function(evtName, fn) {
if(typeof Wii.DISPATCHER[evtName] !== 'undefined') {
/**
* THIS IS INCREDIBLY IMPORTANT, DO NOT REMOVE THIS!.
*
* The Wii's browser has an (odd...?) bug wherein if you have a prototype chain
* set up for a given object, and you default keys on the prototype chain to a blank object ("{}", for instance),
* it will _NOT_ make this a unique object, it keeps pointers to the original object that was created by the system
* for the first instantiated object.
*
* This is, needless to say, unlike just about any other JS environment and threw me for a loop for a good 6 hours.
* This line ensures that the first time this property is ever referenced, we get a fresh _CORRECTLY ALLOCATED_ chunk
* of memory to play with and store things in.
*
* Note that this also happens with Array structures, and conceivably anything else that would be using a copy-by-reference
* technique instead of a full clone. We want an object for this case, though, so we're not doing iterations on event dispatch,
* just a 1:1 lookup instead.
*/
if(this.evtsInterestedIn === undefined) this.evtsInterestedIn = {};
this.evtsInterestedIn[evtName] = Wii.util.bind(this, fn);
return this;
}
return undefined;
}
};

View file

@ -1,92 +0,0 @@
/**
* util.js
*
* A basic utility wrapper; anything extra that's often re-used should
* find its way here (e.g, debuggerDiv, bind, etc).
*
* @Author: Ryan McGrath <ryan@venodesigns.net>
* @Requires: wii.js
*/
Wii.util = {
/**
* A placeholder for the original Error function, since we pretty much overwrite it to actually
* be useful to us. See "Wii.installListeners()" for more information on this.
*/
originalErrFunction: null,
/**
* Upon first call to Wii.util.debug(), this becomes a div that we keep
* a reference to. It's primarily used for logging information to the screen
* on the Wii itself.
*/
msgNode: null,
/**
* Wii.util.debug(err);
*
* The Wii has... such little options for debugging, but we can try and make this a bit nicer.
* This accepts a stack trace (see example code below) and then outputs it to the screen.
*
* try { ... } catch(e) { Wii.util.debug(e); }
*/
debug: function(err) {
if(!Wii.debug) return;
if(Wii.util.msgNode === null) {
Wii.util.msgNode = document.createElement('div');
Wii.util.msgNode.style.cssText = [
'min-width: 780px;',
'padding: 10px;',
'font-size: 28px;',
'line-height: 32px;',
'font-family: monospace;',
'position: absolute;',
'top: 15px;',
'left: 0;',
'color: #f9f9f9;',
'background-color: #010101;',
'border-bottom: 2px solid #42a2cc;',
'opacity: .7;',
'font-weight: bold;'
].join('');
Wii.util.msgNode.addEventListener('click', Wii.util.hideDebugger, false);
document.body.appendChild(Wii.util.msgNode);
}
if(typeof err === 'string') {
Wii.util.msgNode.innerHTML = err;
} else {
var msg = '';
for(var e in err) { msg += '<span style="color: #42a2cc; font-weight: bold;">' + e + '</span>=' + err[e] + '<br>'; }
Wii.util.msgNode.innerHTML = msg;
}
Wii.util.msgNode.style.display = 'block';
},
/**
* Wii.util.hideDebugger()
*
* Keep this around so we've got an easy reference to use for proper unloading
* of event handlers once someone leaves this page.
*/
hideDebugger: function() { this.style.display = 'none'; },
/**
* Wiimote.util.bind(bindReference, fn)
*
* Takes a reference (an object to scope to "this" at a later runtime) and binds it to a function (fn).
*
* @param bindReference - An object to set as the "this" reference for a later function call.
* @param fn - A function to bind the "this" object for.
* @returns fn - A new function to pass around, wherein it's all scoped as you want it.
*/
bind: function(bindReference, fn) {
return function() {
return fn.apply(bindReference, arguments);
};
}
};

View file

@ -1,328 +0,0 @@
/**
* wii.js
*
* Provides a sane, event-based documented wrapper around the Wiimote controls
* and API inside the Opera-based Nintendo Wii web browser.
*
* This is not produced by nor endorsed by Nintendo or Opera. I've written it
* on my own because I see a device that's sitting in millions of living rooms
* but being sorely neglected because a company couldn't get their act together
* in regards to third party development. ;)
*
* @Author: Ryan McGrath <ryan@venodesigns.net>
* @Requires: Nothing.
*/
/* Wii
*
* Top level namespace. Contains information about the main event loop, etc.
*/
var Wii = {
/**
* A "global" reference to the Wiimotes we're currently watching. Lets us run
* through on each loop/iteration and poll for a new status on it.
*/
extraRemotes: [],
/**
* A "global" reference to the (current) primary Wiimote. This can change if the
* primary Wiimote runs out of battery, and the library shoul transparently account
* for this.
*/
currentBrowsingRemote: null,
/**
* Internal flag for whether or not we've actually set some document event listeners.
* A little messy, sure, but not the biggest guffaw in the world.
*/
setListeners: false,
/**
* A global debug flag. If this is enabled/set to true, any errors raised will be thrown
* up on the screen for the Wii. Should be set when the initial .listen() request is fired.
*
* e.g, Wii.listen({debug: true});
*/
debug: false,
/**
* The primary Wiimote depends on typical DOM-esque events to communicate what actions it's
* doing, and the other three use a whole bitmask-esque scenario. This is a "global" Array of
* the events we're interested in for the primary Wiimote.
*
* We catch multiple begin/endpoints for these full event "scopes" for
* future use, as it seems like it'll probably be the most performant way
* to do rapid-quick checks for the primary Wii-mote as to multiple-button
* press scenarios (among some other things).
*/
primaryWiimoteEvts: ['mouseup', 'mousedown', 'keyup', 'keydown', 'keypress']
};
/**
* Wii.installListeners()
*
* Install some basic low-level event listeners to monitor how
* the primary wii_remote is interacting with the browser; it's treated
* differently than the other wii_remotes, more as a "browsing" tool than
* a controller. Doesn't mean we can't try and mend the gap...
*/
Wii.installListeners = function() {
for(var i = 0, j = Wii.primaryWiimoteEvts.length; i < j; i++) {
document.addEventListener(Wii.primaryWiimoteEvts[i], Wii.parsePrimaryWiimote, false);
}
/**
* Since the Wii is already a fairly low-spec system, it's definitely worth
* cleaning up after ourselves if we can get around to it. This should (hopefully)
* take care of most of what we need to worry about.
*/
window.onbeforeunload = function() {
for(var i = 0, j = Wii.primaryWiimoteEvts.length; i < j; i++) {
document.removeEventListener(Wii.primaryWiimoteEvts[i], Wii.parsePrimaryWiimote, false);
}
if(Wii.util.msgNode) Wii.util.msgNode.removeEventListener('click', Wii.util.hideDebugger, false);
};
/**
* If this is all listening in debug mode, we wanna try and catch everything that could
* possibly go wrong in the stack. try/catch is very expensive for the entire program, and can
* crash the Wii pretty easily if you push it too much.
*
* What we'll do instead is just patch the seemingly un-documented window.Error function to suit our
* debugging needs, and only try/catch while in debug mode in critical places (e.g, the constant polling
* section would be... yeah, not a fun idea).
*
* With this, "throw new Error(error)" will actually hit over to what we want, and anything else (outside code)
* using it will get the on-screen Wii debug which is actually useful. That's why we bother doing this, instead
* of just calling Wii.util.debug() everywhere. ;)
*/
if(Wii.debug) {
Wii.util.originalErrFunction = window.Error;
window.Error = function() {
if(arguments.length > 0) Wii.util.debug(arguments[0]);
else Wii.util.originalErrFunction.apply(this, arguments);
}
}
return true;
};
/**
* Wii.listen()
*
* The main game loop. This must stay very performant; try to keep things as absolutely
* low-level as possible here.
*/
Wii.listen = function(optional_opts) {
if(typeof optional_opts !== 'undefined') {
if(typeof optional_opts.debug !== 'undefined' && optional_opts.debug) Wii.debug = true;
}
if(!Wii.setListeners) Wii.setListeners = Wii.installListeners();
var i = Wii.extraRemotes.length;
while(i--) {
/* Check if it's enabled; returns a kPadStatus object if so. */
var wii_remote = Wii.extraRemotes[i],
wii_remoteCurrStatus = wii_remote.isEnabled();
/* If it's enabled, huzzah, do some checks and fire appropriate events. */
if(wii_remoteCurrStatus) {
/**
* Do this check here as well, as the primary wiimote might've changed...
* Note that we don't remove it from the internal remote tracking Array; this is because
* if the remote that _was_ the primary one comes back online, it'll take over as the
* primary one again as it's the lowest ID in terms of all remotes. This check here will
* ensure that whatever remote is the current primary one will default to using other
* dispatched events instead of bitwise checks, but should all default back if another one
* comes online.
*/
if(wii_remoteCurrStatus.isBrowsing) {
Wii.currentBrowsingRemote = wii_remote;
} else {
/* Update these on each poll, since we've got the data anyway. */
wii_remote.x = wii_remoteCurrStatus.dpdScreenX;
wii_remote.y = wii_remoteCurrStatus.dpdScreenY;
for(var evt in wii_remote.evtsInterestedIn) {
var evtHappened = Wii.DISPATCHER[evt](wii_remote, wii_remoteCurrStatus);
if(evtHappened) wii_remote.evtsInterestedIn[evt](wii_remote, wii_remoteCurrStatus);
}
}
}
}
/**
* This is a better choice than working with intervals; it keeps the amount of "spasm" responses
* that one would normally get on the Wii to a bare minimum. This is due to how the two types of
* timers in JS work - intervals will queue up no matter what, and if there's a backlog, rapidly
* fire through all of them. Timeouts are guaranteed to always have their delay, even though at points
* it may end up being more (or less) than 100ms.
*
* Note that this is set to 100ms - any lower, and the Wii becomes very unresponsive for some reason. The
* web browser is... odd, not sure what the deal is. 100ms should be enough for most cases though...
*/
return setTimeout(Wii.listen, 100);
};
/**
* Wii.parsePrimaryWiimote(e)
*
* The Wii browser environment is... quite oddball at times. You see, the
* primary Wii remote is treated differently than the other Wiimotes; it uses
* browser-based events (keydown, mouseup, etc) to communicate which buttons have
* been pressed.
*
* The "primary" Wiimote can also change at any given time (loss of battery in the main, etc).
*
* Luckily, it's not -impossible- to catch this internally. Our main library event loop catches
* if a given Wiimote is marked as the primary one, and will not attempt bitwise operations on it,
* merely wait for standard DOM events to trickle up and handle firing them appropriately.
*
* ...ugh.
*
* This method is a callback for any DOM-event listeners; accepts an event as its argument.
*/
Wii.parsePrimaryWiimote = function(e) {
/* Cancel whatever the default was, because we're going to try and normalize everything. */
e.preventDefault();
var wii_remote = Wii.currentBrowsingRemote,
wii_remoteCurrStatus = wii_remote.isEnabled(),
buttonPressed = Wii.PRIMARY_CONTROLLER_DISPATCHER[wii_remote.opts.horizontal ? 'horizontal' : 'vertical'][e.keyCode];
/* Grab these first, and on every pass. */
wii_remote.x = wii_remoteCurrStatus.dpdScreenX;
wii_remote.y = wii_remoteCurrStatus.dpdScreenY;
/**
* Filter down and figure out which "event" we're really looking at based on code
* matchups; this gets messy pretty quickly...
*/
if(typeof buttonPressed !== 'undefined' && typeof wii_remote.evtsInterestedIn[buttonPressed] === 'function') {
wii_remote.evtsInterestedIn[buttonPressed](wii_remote, wii_remoteCurrStatus);
}
/**
* Due to the difference in how these controls are caught, we need a second set of roll/distance-changes
* run here. Luckily, we can just re-use the dispatcher functions.
*/
if(typeof wii_remote.evtsInterestedIn['roll_change'] === 'function') {
if(Wii.DISPATCHER['roll_change'](wii_remote, wii_remoteCurrStatus)) {
wii_remote.evtsInterestedIn['roll_change'](wii_remote, wii_remoteCurrStatus);
}
}
if(typeof wii_remote.evtsInterestedIn['distance_change'] === 'function') {
if(Wii.DISPATCHER['distance_change'](wii_remote, wii_remoteCurrStatus)) {
wii_remote.evtsInterestedIn['distance_change'](wii_remote, wii_remoteCurrStatus);
}
}
/* Doing this in conjunction with preventDefault() halts an odd clicking bug or two. */
return false;
};
/**
* Wii.PRIMARY_CONTROLLER_DISPATCHER
*
* In order to keep things as performant as possible, we want DOM events (for the primary controller)
* to also be a 1:1 hash map lookup. This is PRIMARILY for the primary ("browsing") controller; all other
* controllers get their operations routed through the DISPATCHER below. The keys below are keyCodes.
*/
Wii.PRIMARY_CONTROLLER_DISPATCHER = {
vertical: {
0: 'pressed_a',
13: 'pressed_a', /* Older versions of the Wii Browser...? */
170: 'pressed_minus',
171: 'pressed_b',
172: 'pressed_1',
173: 'pressed_2',
174: 'pressed_plus',
175: 'pressed_up',
176: 'pressed_down',
177: 'pressed_right',
178: 'pressed_left'
},
horizontal: {
0: 'pressed_a',
13: 'pressed_a', /* Older versions of the Wii Browser...? */
170: 'pressed_minus',
171: 'pressed_b',
172: 'pressed_1',
173: 'pressed_2',
174: 'pressed_plus',
175: 'pressed_left',
176: 'pressed_right',
177: 'pressed_up',
178: 'pressed_down'
}
};
/**
* Wii.DISPATCHER
*
* A table of the supported events that we watch for in our game loop, then fire off for respective
* Wiimotes. Each index is a function that does a check and returns true or false.
*
* Many of these functions use bitwise comparisons. Read up on it if you're not familiar. Note that
* we also take into account the orientation of the device here!
*/
Wii.DISPATCHER = {
/**
* These functions depend on whether or not the controller is meant to be in horizontal mode
* or not. Quite... different.
*/
'pressed_up': function(wii_remote, wii_remoteStatus) {
if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 2;
return wii_remoteStatus.hold & 8;
},
'pressed_right': function(wii_remote, wii_remoteStatus) {
if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 4;
return wii_remoteStatus.hold & 2;
},
'pressed_down': function(wii_remote, wii_remoteStatus) {
if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 1;
return wii_remoteStatus.hold & 4;
},
'pressed_left': function(wii_remote, wii_remoteStatus) {
if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 8;
return wii_remoteStatus.hold & 1;
},
'pressed_plus': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 16; },
'pressed_minus': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 4096; },
'pressed_2': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 256; },
'pressed_1': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 512; },
'pressed_b': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 1024; },
'pressed_a': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 2048; },
'roll_change': function(wii_remote, wii_remoteStatus) {
var roll = Math.atan2(wii_remoteStatus.dpdRollY, wii_remoteStatus.dpdRollX);
if(roll !== wii_remote.roll) {
wii_remote.roll = roll;
return true;
}
return false;
},
'distance_change': function(wii_remote, wii_remoteStatus) {
if(wii_remoteStatus.dpdDistance !== wii_remote.last_known_distance_from_screen) {
wii_remote.last_known_distance_from_screen = wii_remoteStatus.dpdDistance;
return true;
}
return false;
},
/**
* I'm keeping these noted here for legacy reasons, but by and large it's just not even
* worth trying to use the Nunchuk with anything in the browser; the primary controller
* can never read them, so there's a large chunk of functionality missing...
*/
'pressed_z': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 8192; },
'pressed_c': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 16384; }
};

596
js/wii.js
View file

@ -1,596 +0,0 @@
/**
* core.js
*
* This is the main template file for bringing together
* the various libraries that power this entire little eco-system.
*
* Building the releases requires Python (2.5+); simply run...
*
* python build.py
*
* ...from the /js/ directory.
*
* @Author: Ryan McGrath <ryan@venodesigns.net>
* @Requires: Nothing, top-level file.
*/
;(function(running_inside_wii_browser) {
/**
* If we're not running inside the Nintendo Wii browser, bail out.
* In the future, branch here for touch-enabled devices...?
*/
if(!running_inside_wii_browser) return false;
/**
* wii.js
*
* Provides a sane, event-based documented wrapper around the Wiimote controls
* and API inside the Opera-based Nintendo Wii web browser.
*
* This is not produced by nor endorsed by Nintendo or Opera. I've written it
* on my own because I see a device that's sitting in millions of living rooms
* but being sorely neglected because a company couldn't get their act together
* in regards to third party development. ;)
*
* @Author: Ryan McGrath <ryan@venodesigns.net>
* @Requires: Nothing.
*/
/* Wii
*
* Top level namespace. Contains information about the main event loop, etc.
*/
var Wii = {
/**
* A "global" reference to the Wiimotes we're currently watching. Lets us run
* through on each loop/iteration and poll for a new status on it.
*/
extraRemotes: [],
/**
* A "global" reference to the (current) primary Wiimote. This can change if the
* primary Wiimote runs out of battery, and the library shoul transparently account
* for this.
*/
currentBrowsingRemote: null,
/**
* Internal flag for whether or not we've actually set some document event listeners.
* A little messy, sure, but not the biggest guffaw in the world.
*/
setListeners: false,
/**
* A global debug flag. If this is enabled/set to true, any errors raised will be thrown
* up on the screen for the Wii. Should be set when the initial .listen() request is fired.
*
* e.g, Wii.listen({debug: true});
*/
debug: false,
/**
* The primary Wiimote depends on typical DOM-esque events to communicate what actions it's
* doing, and the other three use a whole bitmask-esque scenario. This is a "global" Array of
* the events we're interested in for the primary Wiimote.
*
* We catch multiple begin/endpoints for these full event "scopes" for
* future use, as it seems like it'll probably be the most performant way
* to do rapid-quick checks for the primary Wii-mote as to multiple-button
* press scenarios (among some other things).
*/
primaryWiimoteEvts: ['mouseup', 'mousedown', 'keyup', 'keydown', 'keypress']
};
/**
* Wii.installListeners()
*
* Install some basic low-level event listeners to monitor how
* the primary wii_remote is interacting with the browser; it's treated
* differently than the other wii_remotes, more as a "browsing" tool than
* a controller. Doesn't mean we can't try and mend the gap...
*/
Wii.installListeners = function() {
for(var i = 0, j = Wii.primaryWiimoteEvts.length; i < j; i++) {
document.addEventListener(Wii.primaryWiimoteEvts[i], Wii.parsePrimaryWiimote, false);
}
/**
* Since the Wii is already a fairly low-spec system, it's definitely worth
* cleaning up after ourselves if we can get around to it. This should (hopefully)
* take care of most of what we need to worry about.
*/
window.onbeforeunload = function() {
for(var i = 0, j = Wii.primaryWiimoteEvts.length; i < j; i++) {
document.removeEventListener(Wii.primaryWiimoteEvts[i], Wii.parsePrimaryWiimote, false);
}
if(Wii.util.msgNode) Wii.util.msgNode.removeEventListener('click', Wii.util.hideDebugger, false);
};
/**
* If this is all listening in debug mode, we wanna try and catch everything that could
* possibly go wrong in the stack. try/catch is very expensive for the entire program, and can
* crash the Wii pretty easily if you push it too much.
*
* What we'll do instead is just patch the seemingly un-documented window.Error function to suit our
* debugging needs, and only try/catch while in debug mode in critical places (e.g, the constant polling
* section would be... yeah, not a fun idea).
*
* With this, "throw new Error(error)" will actually hit over to what we want, and anything else (outside code)
* using it will get the on-screen Wii debug which is actually useful. That's why we bother doing this, instead
* of just calling Wii.util.debug() everywhere. ;)
*/
if(Wii.debug) {
Wii.util.originalErrFunction = window.Error;
window.Error = function() {
if(arguments.length > 0) Wii.util.debug(arguments[0]);
else Wii.util.originalErrFunction.apply(this, arguments);
}
}
return true;
};
/**
* Wii.listen()
*
* The main game loop. This must stay very performant; try to keep things as absolutely
* low-level as possible here.
*/
Wii.listen = function(optional_opts) {
if(typeof optional_opts !== 'undefined') {
if(typeof optional_opts.debug !== 'undefined' && optional_opts.debug) Wii.debug = true;
}
if(!Wii.setListeners) Wii.setListeners = Wii.installListeners();
var i = Wii.extraRemotes.length;
while(i--) {
/* Check if it's enabled; returns a kPadStatus object if so. */
var wii_remote = Wii.extraRemotes[i],
wii_remoteCurrStatus = wii_remote.isEnabled();
/* If it's enabled, huzzah, do some checks and fire appropriate events. */
if(wii_remoteCurrStatus) {
/**
* Do this check here as well, as the primary wiimote might've changed...
* Note that we don't remove it from the internal remote tracking Array; this is because
* if the remote that _was_ the primary one comes back online, it'll take over as the
* primary one again as it's the lowest ID in terms of all remotes. This check here will
* ensure that whatever remote is the current primary one will default to using other
* dispatched events instead of bitwise checks, but should all default back if another one
* comes online.
*/
if(wii_remoteCurrStatus.isBrowsing) {
Wii.currentBrowsingRemote = wii_remote;
} else {
/* Update these on each poll, since we've got the data anyway. */
wii_remote.x = wii_remoteCurrStatus.dpdScreenX;
wii_remote.y = wii_remoteCurrStatus.dpdScreenY;
for(var evt in wii_remote.evtsInterestedIn) {
var evtHappened = Wii.DISPATCHER[evt](wii_remote, wii_remoteCurrStatus);
if(evtHappened) wii_remote.evtsInterestedIn[evt](wii_remote, wii_remoteCurrStatus);
}
}
}
}
/**
* This is a better choice than working with intervals; it keeps the amount of "spasm" responses
* that one would normally get on the Wii to a bare minimum. This is due to how the two types of
* timers in JS work - intervals will queue up no matter what, and if there's a backlog, rapidly
* fire through all of them. Timeouts are guaranteed to always have their delay, even though at points
* it may end up being more (or less) than 100ms.
*
* Note that this is set to 100ms - any lower, and the Wii becomes very unresponsive for some reason. The
* web browser is... odd, not sure what the deal is. 100ms should be enough for most cases though...
*/
return setTimeout(Wii.listen, 100);
};
/**
* Wii.parsePrimaryWiimote(e)
*
* The Wii browser environment is... quite oddball at times. You see, the
* primary Wii remote is treated differently than the other Wiimotes; it uses
* browser-based events (keydown, mouseup, etc) to communicate which buttons have
* been pressed.
*
* The "primary" Wiimote can also change at any given time (loss of battery in the main, etc).
*
* Luckily, it's not -impossible- to catch this internally. Our main library event loop catches
* if a given Wiimote is marked as the primary one, and will not attempt bitwise operations on it,
* merely wait for standard DOM events to trickle up and handle firing them appropriately.
*
* ...ugh.
*
* This method is a callback for any DOM-event listeners; accepts an event as its argument.
*/
Wii.parsePrimaryWiimote = function(e) {
/* Cancel whatever the default was, because we're going to try and normalize everything. */
e.preventDefault();
var wii_remote = Wii.currentBrowsingRemote,
wii_remoteCurrStatus = wii_remote.isEnabled(),
buttonPressed = Wii.PRIMARY_CONTROLLER_DISPATCHER[wii_remote.opts.horizontal ? 'horizontal' : 'vertical'][e.keyCode];
/* Grab these first, and on every pass. */
wii_remote.x = wii_remoteCurrStatus.dpdScreenX;
wii_remote.y = wii_remoteCurrStatus.dpdScreenY;
/**
* Filter down and figure out which "event" we're really looking at based on code
* matchups; this gets messy pretty quickly...
*/
if(typeof buttonPressed !== 'undefined' && typeof wii_remote.evtsInterestedIn[buttonPressed] === 'function') {
wii_remote.evtsInterestedIn[buttonPressed](wii_remote, wii_remoteCurrStatus);
}
/**
* Due to the difference in how these controls are caught, we need a second set of roll/distance-changes
* run here. Luckily, we can just re-use the dispatcher functions.
*/
if(typeof wii_remote.evtsInterestedIn['roll_change'] === 'function') {
if(Wii.DISPATCHER['roll_change'](wii_remote, wii_remoteCurrStatus)) {
wii_remote.evtsInterestedIn['roll_change'](wii_remote, wii_remoteCurrStatus);
}
}
if(typeof wii_remote.evtsInterestedIn['distance_change'] === 'function') {
if(Wii.DISPATCHER['distance_change'](wii_remote, wii_remoteCurrStatus)) {
wii_remote.evtsInterestedIn['distance_change'](wii_remote, wii_remoteCurrStatus);
}
}
/* Doing this in conjunction with preventDefault() halts an odd clicking bug or two. */
return false;
};
/**
* Wii.PRIMARY_CONTROLLER_DISPATCHER
*
* In order to keep things as performant as possible, we want DOM events (for the primary controller)
* to also be a 1:1 hash map lookup. This is PRIMARILY for the primary ("browsing") controller; all other
* controllers get their operations routed through the DISPATCHER below. The keys below are keyCodes.
*/
Wii.PRIMARY_CONTROLLER_DISPATCHER = {
vertical: {
0: 'pressed_a',
13: 'pressed_a', /* Older versions of the Wii Browser...? */
170: 'pressed_minus',
171: 'pressed_b',
172: 'pressed_1',
173: 'pressed_2',
174: 'pressed_plus',
175: 'pressed_up',
176: 'pressed_down',
177: 'pressed_right',
178: 'pressed_left'
},
horizontal: {
0: 'pressed_a',
13: 'pressed_a', /* Older versions of the Wii Browser...? */
170: 'pressed_minus',
171: 'pressed_b',
172: 'pressed_1',
173: 'pressed_2',
174: 'pressed_plus',
175: 'pressed_left',
176: 'pressed_right',
177: 'pressed_up',
178: 'pressed_down'
}
};
/**
* Wii.DISPATCHER
*
* A table of the supported events that we watch for in our game loop, then fire off for respective
* Wiimotes. Each index is a function that does a check and returns true or false.
*
* Many of these functions use bitwise comparisons. Read up on it if you're not familiar. Note that
* we also take into account the orientation of the device here!
*/
Wii.DISPATCHER = {
/**
* These functions depend on whether or not the controller is meant to be in horizontal mode
* or not. Quite... different.
*/
'pressed_up': function(wii_remote, wii_remoteStatus) {
if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 2;
return wii_remoteStatus.hold & 8;
},
'pressed_right': function(wii_remote, wii_remoteStatus) {
if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 4;
return wii_remoteStatus.hold & 2;
},
'pressed_down': function(wii_remote, wii_remoteStatus) {
if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 1;
return wii_remoteStatus.hold & 4;
},
'pressed_left': function(wii_remote, wii_remoteStatus) {
if(wii_remote.opts.horizontal) return wii_remoteStatus.hold & 8;
return wii_remoteStatus.hold & 1;
},
'pressed_plus': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 16; },
'pressed_minus': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 4096; },
'pressed_2': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 256; },
'pressed_1': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 512; },
'pressed_b': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 1024; },
'pressed_a': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 2048; },
'roll_change': function(wii_remote, wii_remoteStatus) {
var roll = Math.atan2(wii_remoteStatus.dpdRollY, wii_remoteStatus.dpdRollX);
if(roll !== wii_remote.roll) {
wii_remote.roll = roll;
return true;
}
return false;
},
'distance_change': function(wii_remote, wii_remoteStatus) {
if(wii_remoteStatus.dpdDistance !== wii_remote.last_known_distance_from_screen) {
wii_remote.last_known_distance_from_screen = wii_remoteStatus.dpdDistance;
return true;
}
return false;
},
/**
* I'm keeping these noted here for legacy reasons, but by and large it's just not even
* worth trying to use the Nunchuk with anything in the browser; the primary controller
* can never read them, so there's a large chunk of functionality missing...
*/
'pressed_z': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 8192; },
'pressed_c': function(wii_remote, wii_remoteStatus) { return wii_remoteStatus.hold & 16384; }
};/**
* util.js
*
* A basic utility wrapper; anything extra that's often re-used should
* find its way here (e.g, debuggerDiv, bind, etc).
*
* @Author: Ryan McGrath <ryan@venodesigns.net>
* @Requires: wii.js
*/
Wii.util = {
/**
* A placeholder for the original Error function, since we pretty much overwrite it to actually
* be useful to us. See "Wii.installListeners()" for more information on this.
*/
originalErrFunction: null,
/**
* Upon first call to Wii.util.debug(), this becomes a div that we keep
* a reference to. It's primarily used for logging information to the screen
* on the Wii itself.
*/
msgNode: null,
/**
* Wii.util.debug(err);
*
* The Wii has... such little options for debugging, but we can try and make this a bit nicer.
* This accepts a stack trace (see example code below) and then outputs it to the screen.
*
* try { ... } catch(e) { Wii.util.debug(e); }
*/
debug: function(err) {
if(!Wii.debug) return;
if(Wii.util.msgNode === null) {
Wii.util.msgNode = document.createElement('div');
Wii.util.msgNode.style.cssText = [
'min-width: 780px;',
'padding: 10px;',
'font-size: 28px;',
'line-height: 32px;',
'font-family: monospace;',
'position: absolute;',
'top: 15px;',
'left: 0;',
'color: #f9f9f9;',
'background-color: #010101;',
'border-bottom: 2px solid #42a2cc;',
'opacity: .7;',
'font-weight: bold;'
].join('');
Wii.util.msgNode.addEventListener('click', Wii.util.hideDebugger, false);
document.body.appendChild(Wii.util.msgNode);
}
if(typeof err === 'string') {
Wii.util.msgNode.innerHTML = err;
} else {
var msg = '';
for(var e in err) { msg += '<span style="color: #42a2cc; font-weight: bold;">' + e + '</span>=' + err[e] + '<br>'; }
Wii.util.msgNode.innerHTML = msg;
}
Wii.util.msgNode.style.display = 'block';
},
/**
* Wii.util.hideDebugger()
*
* Keep this around so we've got an easy reference to use for proper unloading
* of event handlers once someone leaves this page.
*/
hideDebugger: function() { this.style.display = 'none'; },
/**
* Wiimote.util.bind(bindReference, fn)
*
* Takes a reference (an object to scope to "this" at a later runtime) and binds it to a function (fn).
*
* @param bindReference - An object to set as the "this" reference for a later function call.
* @param fn - A function to bind the "this" object for.
* @returns fn - A new function to pass around, wherein it's all scoped as you want it.
*/
bind: function(bindReference, fn) {
return function() {
return fn.apply(bindReference, arguments);
};
}
};
/**
* console.js
*
* A lightweight wrapper for the now-common "console" object in browsers.
* Really just maps calls over to the wii-js internal Wii.util.debug() call,
* but exists so that if you use this in production code for whatever reason
* it could still be used to debug on the Wii.
*
* Note that for this to work, you must be listening in debug mode!
*
* @Author: Ryan McGrath <ryan@venodesigns.net>
* @Requires: wii.js, util.js
*/
if(typeof window.console === 'undefined') {
window.console = {
log: Wii.util.debug,
debug: Wii.util.debug
};
}
/**
* remote.js
*
* Handles the subscribing to events portion of a Wii remote. It's best to think of this
* as a "request" object; it asks to be notified of events, and the actual events are
* dispatched from the main wii.js file.
*
* @Author: Ryan McGrath <ryan@venodesigns.net>
* @Requires: wii.js, util.js
*/
/**
* var wii_remote = new Wii.Remote(1, {...});
*
* Instantiates a Wii Remote object. Events can be set on each of these objects,
* and the internal game loop will fire events based on the properties subscribed
* to here.
*
* @param remote_id - Number, required. 1 - 4, dictates which Wiimote this object
* relates to.
* @param opts - Object, optional. Allows you to override internal settings and such,
* should you want different behavior.
* @returns Wii.Remote instance.
*/
Wii.Remote = function(remote_id, opts) {
this.remote_id = remote_id;
this.opts = opts;
/**
* Default these properties to undefined, since that's what
* the Wii returns anyway, and it's worth it to try and stay (somewhat)
* close to the core tech.
*/
this.x = undefined;
this.y = undefined;
this.roll = undefined;
this.last_known_distance_from_screen = undefined;
/**
* If this is the "main" wii_remote, then the bitwise checks will fail
* because it's treated more as a "browsing" device. For these events,
* we'll just store the current wii_remote that's denoted as the "browsing"
* device and let the normal event/key delegation take care of things.
*
* The rest of the wii_remotes will go through the DISPATCHER checks that
* they've subscribed to.
*/
var startupStatus = this.isEnabled();
if(startupStatus) {
if(!startupStatus.isBrowsing) {
Wii.extraRemotes.push(this);
} else {
Wii.currentBrowsingRemote = this;
}
}
};
Wii.Remote.prototype = {
opts: {
/**
* We default the controller to be in the vertical orientation; if
* it's overridden as "horizontal" (false), we'll catch it for the different key
* events and fire accordingly (e.g, the "up" button is different depending on
* how the player is holding the controller).
*/
horizontal: false
},
/**
* A hash of events that this Wii remote is interested in. Each
* entry should be a key (evtName) with a value (response).
* "evtName" is the event name that corresponds with boolean functions
* in the DISPATCHER above, and the response is a remote-bound function
* to call on that event.
*/
evtsInterestedIn: undefined,
/**
* Wiimote.isEnabled()
*
* Determines the status of the wii_remote this object is curious about. Will return
* an updated kPadStatus object if so, false if it's not responding or the data
* is sent back as "invalid". This makes it so we don't bother sending events
* where they're not applicable.
*
* @returns object or boolean.
*/
isEnabled: function() {
var remote = opera.wiiremote.update(this.remote_id - 1);
return (remote.isEnabled && remote.isDataValid ? remote : false);
},
/**
* Wiimote.on(evtName, fn)
*
* Allows you to listen for an event on a given Wiimote. Call this on an instantiated
* Wiimote; "this" will be scoped to the Wiimote object. ;)
*
* @param evtName - String, a supported wii.js (DISPATCHER) event name.
* @param fn - Function, callback function to be executed on the event firing. Will be scoped to the Wiimote.
* @returns object or undefined - instantiated object this was called on to begin with, undefined if evtName is not supported.
*/
when: function(evtName, fn) {
if(typeof Wii.DISPATCHER[evtName] !== 'undefined') {
/**
* THIS IS INCREDIBLY IMPORTANT, DO NOT REMOVE THIS!.
*
* The Wii's browser has an (odd...?) bug wherein if you have a prototype chain
* set up for a given object, and you default keys on the prototype chain to a blank object ("{}", for instance),
* it will _NOT_ make this a unique object, it keeps pointers to the original object that was created by the system
* for the first instantiated object.
*
* This is, needless to say, unlike just about any other JS environment and threw me for a loop for a good 6 hours.
* This line ensures that the first time this property is ever referenced, we get a fresh _CORRECTLY ALLOCATED_ chunk
* of memory to play with and store things in.
*
* Note that this also happens with Array structures, and conceivably anything else that would be using a copy-by-reference
* technique instead of a full clone. We want an object for this case, though, so we're not doing iterations on event dispatch,
* just a 1:1 lookup instead.
*/
if(this.evtsInterestedIn === undefined) this.evtsInterestedIn = {};
this.evtsInterestedIn[evtName] = Wii.util.bind(this, fn);
return this;
}
return undefined;
}
};
window.Wii = Wii;
})(window.opera && opera.wiiremote);

1
js/wii.min.js vendored
View file

@ -1 +0,0 @@
(function(a){if(!a){return false}var b={extraRemotes:[],currentBrowsingRemote:null,setListeners:false,debug:false,primaryWiimoteEvts:["mouseup","mousedown","keyup","keydown","keypress"]};b.installListeners=function(){for(var d=0,c=b.primaryWiimoteEvts.length;d<c;d++){document.addEventListener(b.primaryWiimoteEvts[d],b.parsePrimaryWiimote,false)}window.onbeforeunload=function(){for(var f=0,e=b.primaryWiimoteEvts.length;f<e;f++){document.removeEventListener(b.primaryWiimoteEvts[f],b.parsePrimaryWiimote,false)}if(b.util.msgNode){b.util.msgNode.removeEventListener("click",b.util.hideDebugger,false)}};if(b.debug){b.util.originalErrFunction=window.Error;window.Error=function(){if(arguments.length>0){b.util.debug(arguments[0])}else{b.util.originalErrFunction.apply(this,arguments)}}}return true};b.listen=function(h){if(typeof h!=="undefined"){if(typeof h.debug!=="undefined"&&h.debug){b.debug=true}}if(!b.setListeners){b.setListeners=b.installListeners()}var e=b.extraRemotes.length;while(e--){var g=b.extraRemotes[e],f=g.isEnabled();if(f){if(f.isBrowsing){b.currentBrowsingRemote=g}else{g.x=f.dpdScreenX;g.y=f.dpdScreenY;for(var c in g.evtsInterestedIn){var d=b.DISPATCHER[c](g,f);if(d){g.evtsInterestedIn[c](g,f)}}}}}return setTimeout(b.listen,100)};b.parsePrimaryWiimote=function(g){g.preventDefault();var f=b.currentBrowsingRemote,d=f.isEnabled(),c=b.PRIMARY_CONTROLLER_DISPATCHER[f.opts.horizontal?"horizontal":"vertical"][g.keyCode];f.x=d.dpdScreenX;f.y=d.dpdScreenY;if(typeof c!=="undefined"&&typeof f.evtsInterestedIn[c]==="function"){f.evtsInterestedIn[c](f,d)}if(typeof f.evtsInterestedIn.roll_change==="function"){if(b.DISPATCHER.roll_change(f,d)){f.evtsInterestedIn.roll_change(f,d)}}if(typeof f.evtsInterestedIn.distance_change==="function"){if(b.DISPATCHER.distance_change(f,d)){f.evtsInterestedIn.distance_change(f,d)}}return false};b.PRIMARY_CONTROLLER_DISPATCHER={vertical:{0:"pressed_a",13:"pressed_a",170:"pressed_minus",171:"pressed_b",172:"pressed_1",173:"pressed_2",174:"pressed_plus",175:"pressed_up",176:"pressed_down",177:"pressed_right",178:"pressed_left"},horizontal:{0:"pressed_a",13:"pressed_a",170:"pressed_minus",171:"pressed_b",172:"pressed_1",173:"pressed_2",174:"pressed_plus",175:"pressed_left",176:"pressed_right",177:"pressed_up",178:"pressed_down"}};b.DISPATCHER={pressed_up:function(d,c){if(d.opts.horizontal){return c.hold&2}return c.hold&8},pressed_right:function(d,c){if(d.opts.horizontal){return c.hold&4}return c.hold&2},pressed_down:function(d,c){if(d.opts.horizontal){return c.hold&1}return c.hold&4},pressed_left:function(d,c){if(d.opts.horizontal){return c.hold&8}return c.hold&1},pressed_plus:function(d,c){return c.hold&16},pressed_minus:function(d,c){return c.hold&4096},pressed_2:function(d,c){return c.hold&256},pressed_1:function(d,c){return c.hold&512},pressed_b:function(d,c){return c.hold&1024},pressed_a:function(d,c){return c.hold&2048},roll_change:function(e,d){var c=Math.atan2(d.dpdRollY,d.dpdRollX);if(c!==e.roll){e.roll=c;return true}return false},distance_change:function(d,c){if(c.dpdDistance!==d.last_known_distance_from_screen){d.last_known_distance_from_screen=c.dpdDistance;return true}return false},pressed_z:function(d,c){return c.hold&8192},pressed_c:function(d,c){return c.hold&16384}};b.util={originalErrFunction:null,msgNode:null,debug:function(c){if(!b.debug){return}if(b.util.msgNode===null){b.util.msgNode=document.createElement("div");b.util.msgNode.style.cssText=["min-width: 780px;","padding: 10px;","font-size: 28px;","line-height: 32px;","font-family: monospace;","position: absolute;","top: 15px;","left: 0;","color: #f9f9f9;","background-color: #010101;","border-bottom: 2px solid #42a2cc;","opacity: .7;","font-weight: bold;"].join("");b.util.msgNode.addEventListener("click",b.util.hideDebugger,false);document.body.appendChild(b.util.msgNode)}if(typeof c==="string"){b.util.msgNode.innerHTML=c}else{var f="";for(var d in c){f+='<span style="color: #42a2cc; font-weight: bold;">'+d+"</span>="+c[d]+"<br>"}b.util.msgNode.innerHTML=f}b.util.msgNode.style.display="block"},hideDebugger:function(){this.style.display="none"},bind:function(c,d){return function(){return d.apply(c,arguments)}}};if(typeof window.console==="undefined"){window.console={log:b.util.debug,debug:b.util.debug}}b.Remote=function(e,d){this.remote_id=e;this.opts=d;this.x=undefined;this.y=undefined;this.roll=undefined;this.last_known_distance_from_screen=undefined;var c=this.isEnabled();if(c){if(!c.isBrowsing){b.extraRemotes.push(this)}else{b.currentBrowsingRemote=this}}};b.Remote.prototype={opts:{horizontal:false},evtsInterestedIn:undefined,isEnabled:function(){var c=opera.wiiremote.update(this.remote_id-1);return(c.isEnabled&&c.isDataValid?c:false)},when:function(d,c){if(typeof b.DISPATCHER[d]!=="undefined"){if(this.evtsInterestedIn===undefined){this.evtsInterestedIn={}}this.evtsInterestedIn[d]=b.util.bind(this,c);return this}return undefined}};window.Wii=b})(window.opera&&opera.wiiremote);

1
params.json Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,106 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Introducing Wii.js</title>
<link rel="stylesheet" type="text/css" media="screen" href="css/presentation.css">
<link rel="stylesheet" type="text/css" media="screen" href="css/arta.min.css">
<style>.keyword { color: #ea1fb8 !important; }</style>
</head>
<body>
<h1>Wii-js</h1>
<div class="slide" id="intro">
<h2>Who I am</h2>
<ul>
<li>Senior Engineer, myGengo</li>
<li>Author of MapRejuice, wrench-js, others</li>
<li><a href="http://github.com/ryanmcgrath">github.com/ryanmcgrath</a></li>
</ul>
</div>
<div class="slide" id="why">
<h2>Why did I make this?</h2>
<ul>
<li>No decent API for the Wii Web Browser existed</li>
<li>Nintendo doesn't want it to exist...</li>
<li>Great way to teach children how to program</li>
</ul>
</div>
<div class="slide" id="quirks">
<h2>Wii Browser & Quirks</h2>
<ul id="quirksul">
<li><strong>Opera 9.26</strong> - CSS2.1, &lt;canvas&gt;, SVG, and more...</li>
<li>Annoying memory limits (~88MB entire system, Browser is far less)</li>
<li><strong>Repaint slower</strong>; repeated timeouts less than 100ms causes the Wii to freeze up</li>
<li><strong>Only Wii Remotes work</strong>; no other controller types usable. :(</li>
<li>Leave type="" off &lt;script&gt; tags, or they won't work sometimes</li>
</ul>
</div>
<div class="slide" id="js">
<h2>Wii-js API (Event Based)</h2>
<ul style="list-style-type: none; margin-left: 15px;">
<li id="code1">
<pre>var wiimote = new Wii.Remote(1, {horizontal: true}),
wiimote2 = new Wii.Remote(2, {horizontal: true});
wiimote.when('pressed_a', function() {
alert('A Button on Wiimote 1 Pressed!');
});
wiimote2.when('pressed_a', function() {
alert('Right Button on Wiimote 2 Pressed!');
});
</pre>
</li>
</ul>
</div>
<div class="slide" id="node">
<h2>Opera on Wii has [[[Server-Sent-Events]]]!</h2>
<ul style="list-style-type: none; margin-left: 15px;">
<li id="code2">
<pre>var http = require('http');
function sendEvents(response) {
response.write('id: ' + (new Date()).toLocaleTimeString() + '\n');
response.write('data: ' + (Math.floor(Math.random() * 10000) + 2) + '\n');
setTimeout(function() {
sendEvents(response);
}, 5000);
}
http.createServer(function(request, response) {
response.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
sendEvents(response);
}).listen(8000);
</pre>
</li>
</ul>
</div>
<div class="slide" id="thanks">
<h2>Thanks!</h2>
<ul>
<li><strong>Twitter:</strong> <a href="http://twitter.com/ryanmcgrath">@ryanmcgrath</a></li>
<li><strong>Wii-js on GitHub:</strong> <a href="http://github.com/ryanmcgrath/wii-js">http://github.com/ryanmcgrath/wii-js</a></li>
<li><strong>Demo:</strong> <a href="http://venodesigns.net/wii/">http://venodesigns.net/wii</a>
</ul>
</div>
<script src="js/wii.js"></script>
<script src="js/slides.js"></script>
<script src="js/highlight.min.js"></script>
<script>
hljs.highlightBlock(document.getElementById('code1'), null, false);
hljs.highlightBlock(document.getElementById('code2'), null, false);
</script>
</body>
</html>

211
readme.md
View file

@ -1,211 +0,0 @@
wii-js
==============================================================================================
The Nintendo Wii is an entertainment system with an utterly _massive_ install base, and when
you couple it with the fact that it's got a web browser (mostly) built in, there's a lot of
potential for third party development. Sadly, few have opted to do any sort of development for
it. While it doesn't help that Nintendo pretty much dropped the ball on this opportunity, the
experience of browsing the web on the Wii isn't actually that compelling to begin with.
That said, I think this can serve one other purpose: it's an ideal environment to teach children
how to program! I created this library to sanitize Wii interaction with webpages in the browser,
as it's notoriously crippled. It aims to offer a solid, documented, performant API that's easy to
understand and pick up. With this library, you can have up to 4 Wii-motes interacting with your
webpage at once, a dynamic not found in other web browsing mediums.
You can find a built source file and a _minified_ source file for production use in the **/js/** directory.
To play with a live example, load up the demo (_index.html_) on your own server, or feel free to use mine:
**wii-js Demo: [http://venodesigns.net/wii/](http://venodesigns.net/wii/)**
Working with the Wii's browser can be odd - it has moderately good support for CSS, so you're never really
as bad off as you'd be with a version of Internet Explorer - that said, if you're looking for a good read
on what's supported, check out **[this article on Opera Wii supported technologies](http://www.opera.com/docs/specs/opera9/?platform=wii)**.
Questions, comments, criticism and praise can be directed to me at the following outlets:
- You can email me at **ryan [at] venodesigns (dot) net**.
- You can hit me up on Twitter: **[@ryanmcgrath](http://twitter.com/ryanmcgrath/)**
- Contact me through **[my website](http://venodesigns.net)**
- **Technical issues can be filed on the [wii-js GitHub Issues Tracker](https://github.com/ryanmcgrath/wii-js/issues)**
Example Usage
----------------------------------------------------------------------------------------------
``` javascript
var wiimote = new Wii.Remote(1, {horizontal: true}),
wiimote2 = new Wii.Remote(2, {horizontal: true});
wiimote.when('pressed_a', function() {
alert('Wiimote #1 pressed the A Button!');
});
wiimote2.when('pressed_a', function() {
alert('Wiimote #2 pressed the A Button!');
});
Wii.listen();
```
Technical Documentation
----------------------------------------------------------------------------------------------
The largest issue with making interactive pages that work with the Wii has been that the API has
been nothing short of a black hole. When you actually begin to dig in and figure out what's going on,
it gets even uglier to see - the primary wiimote, for instance, has a totally different set of signals
than the other three.
wii-js abstracts away most of these differences and/or problems, and works on a very simple event-dispatch
system. What this means is that you create an instance of a Wii Remote, subscribe to events, and provide a
function to get called when that event has occurred. The following syntax should explain this:
``` javascript
wiimote.when('event_name_here', function() { /* My callback function */ });
```
When instantiating a Wii Remote instance, you can choose to have the library interpret directional pad controls
in horizontal or vertical mode. You can change this at any point, if you want, by simply swapping the property.
``` javascript
var wiimote = new Wii.Remote(1, {horizontal: true}); // Horizontal controls
var wiimote = new Wii.Remote(1, {horizontal: false}); // Vertical controls
wiimote.opts.horizontal = true; // Change to horizontal scheme.
```
The final important piece is to start the Wii-event loop; this manages the event dispatcher internally. To do this, simply...
``` javascript
Wii.listen();
```
You can listen for the following events on all controllers:
- **pressed_up** - The up button was pressed.
- **pressed_down** - The down button was pressed.
- **pressed_left** - The left button was pressed.
- **pressed_right** - The right button was pressed.
- **pressed_a** - The A button was pressed.
- **pressed_1** - The 1 button was pressed. (_Note: On controller 1, this triggers a menu - work in progress..._)
- **pressed_2** - The 2 button was pressed.
- **pressed_plus** - The plus (+) button was pressed.
- **pressed_minus** - The minus (-) button was pressed.
- **roll_change** - The roll of the controller (balance) changed. You can get the current roll in radians with _"this.roll"_; positive is upright, negative is the other.
- **distance_change** - The distance of the wiimote (in meters) from the TV/sensor bar has changed. This event isn't totally reliable, but should work for most cases.
You can listen for the following events on _extra controllers_, but not the primary controller.
- **pressed_b** - The B button was pressed.
- **pressed_c** - The C button (on the Nunchuk) was pressed.
- **pressed_z** - The Z button (on the Nunchuk) was pressed.
You can also get the following properties from any Wii Remote instance; they will return "undefined" if the remote
isn't able to see the TV/sensor bar, so be sure to check this!
- **x** - The x coordinate where the Wii Remote is pointing to on the screen. Generally between 0 and 800, but can be more on wide pages.
- **y** - The y coordinate where the Wii Remote is pointing to on the screen. Odd one; can be found as low as -48, as high as the height
of the current webpage + toolbar height, if enabled. Tinker with this one for your purposes.
Extra Tips and Tricks (Debugging)
------------------------------------------------------------------------------------------------------------------
One semi-useful trick to point out about this library is that each of your callback functions get passed two
arguments by default - a reference to the Wiimote you're working with, and the raw Wiimote status object that the
Wii reports back to the library. You get this in a normalized fashion, instead of having to deal with the odd polling
issues present in the browser.
``` javascript
var wiimote = new Wii.Remote(1, {horizontal: false});
wiimote.when('pressed_a', function(wii_remote, wii_remote_status) {
/* Alert an internal confidence level provided by the Wii. */
alert(wii_remote_status.dpdValidity);
});
```
Debugging Javascript on the Wii is also nothing short of incredibly annoying, so I've made some efforts to patch this
up and make life a bit easier. My typical debugging strategy with any Wii-related code would always start with
the following. The first thing to do is set the Wii listener to run in debug mode, like so:
``` javascript
Wii.listen({debug: true});
```
With this set, you can log errors with any of the following functions. `error` can be a string or a complex object.
- **console.log(error);** - Tried and true, now supported.
- **console.debug(error);** - Same as console.log here, but syntax is supported.
- **throw new Error(error);** - Throw them, they'll be logged.
- **Wii.util.debug(error);** - The core function that handles logging internally.
If the typical Wii debugging flow isn't enough for you, go aggressive with this - just be aware that you can crash
the Wii's browser if you're using try/catch all over the place, as it's not cheap in Javascript.
``` javascript
try {
// Whatever function to execute
} catch(e) { Wii.util.debug(e); }
```
Why the button limitations?
------------------------------------------------------------------------------------------------------------------
The Nintendo Wii treats the primary controller differently than the other ones, and doesn't report any action
from the Nunchuk, nor does it report when someone has pressed the "B" button on the primary controller (as it's used
for scrolling a page).
The Wii Browser also doesn't report data for Gamecube controllers, the Classic controller, or any other accessories.
It's a work in progress to see what can be done about these, but it's impossible to guarantee anything will come out
of it unless Nintendo and/or Opera can come out with something new.
Known Issues
------------------------------------------------------------------------------------------------------------------
**Primary Wiimote is a bit more responsive than the extra 3**
This library works by polling the status of the three extra Wii-remotes in 100ms intervals and dispatching events
based on this. Anything lower than 100ms causes the Wii to run into memory limitations, and the single-threaded
nature of the browser doesn't really help this issue.
The primary Wii-remote uses an odd combination of DOM-esque callbacks; due to this, it reports _more frequently_ than
the other Wii-remotes. It's not a showstopper by any means, but for small games it would in theory give a weighted advantage.
I'll probably end up throttling this through the library by means of a flag, e.g "game_mode": true in the initial options.
Todo List
------------------------------------------------------------------------------------------------------------------
- Build in functionality for multiple button presses at the same time (difficult to get right in this environment)
- Determine canceling B-button/scrolling on pages ("app"/"game" style)
- Determine feasibility of canceling out "1" press on the primary Wii-remote.
Building and Developing
------------------------------------------------------------------------------------------------------------------
If you'd like to help with this library, you're more than welcome to. Simply fork it on GitHub, work away, then
issue me a pull request. I generally respond within 24 hours.
The build system here is pretty simple - edits and changes go into the /js/src/ files, and you can run
python build.py
from the main directory to build a new version. The minifier here is YUI; Closure/UglifyJS are more aggressive, and
for some reason throw ridiculous issues in the Wii's browser that I've been unable to track down (and I don't have
more time to throw at it).
In short, the builds require Python/Java, but once you've got them all installed you should only need the command above.
How is this different from...?
-------------------------------------------------------------------------------------------------------------------
I sadly did not find out about [wii.js](http://www.bolinfest.com/wii/overview.php) until after I released this library;
with respect to the original author, his work only covers the primary Wii Remote and not the extra ones, nor has it
been updated in years. While his approach appears to be the same as mine (or mine the same as his), neither one
influenced the other, and they're totally separate works.
With the exception of wii.js, I do not know of any other (remaining) Wii interaction Javascript libraries. It's for
these reasons (and my desire for a simpler API) that I built this. ;)
Licensing, etc
-------------------------------------------------------------------------------------------------------------------
wii-js is released under an MIT license. Just provide credit where need be if you choose to use this, it's taken quite
a bit of my time to decipher the utterly random pieces and intricacies of this Javascript engine. ;)

117
server.js
View file

@ -1,117 +0,0 @@
/**
* server.js
*
* An example of a Node.js server that streams a set
* of events to a browser. This is primarily aimed at
* use with wii-js; since the wii's browser has a set of
* quirks like no other, this file can be expected to change.
*
* This is commented possibly more liberally than it should be,
* as it's intended to be easily accessible by those who might not
* have worked with Node.js and/or Server Sent Events before.
*
* @Author: Ryan McGrath <ryan@venodesigns.net>
* @Requires: Nothing, sans a little Node.js
*/
var DEBUG = true,
PORT = 8080,
http = require('http'),
util = require('util'),
fs = require('fs');
/**
* sendEvent()
*
* Sends down a set of events roughly every ~5 seconds. Not that
* many would go so low, but sending more than once every ~500ms is
* not recommended. The Wii's browser has some odd memory limitations
* that aren't too much fun to be caught up in.
*
* @response - response object/stream, where data gets written to.
*/
var sendEvents = function sendEvent(response) {
var id = (new Date()).toLocaleTimeString(),
data = (Math.floor(Math.random() * 10000) + 2);
response.write('id: ' + id + '\n');
response.write('data: ' + data + '\n');
/**
* Set this up to re-send in a few seconds on the
* same request.
*/
setTimeout(function() {
sendEvents(response);
}, 5000);
};
/**
* determineContentType(url)
*
* Given a url, determines one of three content types that we care
* about. I'm an opinionated person and chose not to use Express here,
* but if you'd rather not deal with it the static module there is quite
* possibly your new best friend.
*
* @url - string, url to be tested for content-type
*/
var determineContentType = function determineContentType(url) {
if(/\.js/.test(url)) return 'text/javascript';
if(/\.css/.test(url)) return 'text/css';
return 'text/html';
};
/**
* Now we'll set up a simple server that listens our our port we set
* above, which will either distribute resources or events depending
* on the headers.
*/
http.createServer(function(request, response) {
/**
* All but useless to us...
*/
if(request.url === '/favicon.ico') {
response.writeHead(404);
response.end();
return;
}
/**
* If things don't appear to be working, uncomment this and check out
* what's getting posted over. Certain headers need to be set by the browser;
* it's possible they're not getting set for some reason...
*/
if(DEBUG && request.url !== '/favicon.ico') {
util.puts('\n-----------------------------------------------------');
util.puts('URL: ' + request.url);
for(var key in request.headers) {
util.puts(key + ': ' + request.headers[key]);
}
}
/**
* See the comment about DEBUG/headers above. If we have proper headers, we'll
* start sending down a stream of events; if not, we'll assume it's a normal request
* and serve up some HTML/CSS/JS/etc.
*/
if(request.headers.accept && request.headers.accept === 'text/event-stream') {
response.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
sendEvents(response);
} else {
var file = request.url === '/' ? '/presentation.html' : request.url;
response.writeHead(200, {'Content-Type': determineContentType(request.url)});
fs.readFile(__dirname + file, 'utf-8', function(err, data) {
if(err) throw err;
response.write(data);
response.end();
});
}
}).listen(PORT);
util.puts('\n--------------------------------------------------------------------');
util.puts('Server started and listening on port ' + PORT + '.');

View file

@ -0,0 +1,60 @@
.highlight .hll { background-color: #49483e }
.highlight { background: #3A3C42; color: #f8f8f2 }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */

356
stylesheets/styles.css Normal file
View file

@ -0,0 +1,356 @@
@import url(https://fonts.googleapis.com/css?family=Lato:300italic,700italic,300,700);
html {
background: #6C7989;
background: #6c7989 -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #6c7989), color-stop(100%, #434b55)) fixed;
background: #6c7989 -webkit-linear-gradient(#6c7989, #434b55) fixed;
background: #6c7989 -moz-linear-gradient(#6c7989, #434b55) fixed;
background: #6c7989 -o-linear-gradient(#6c7989, #434b55) fixed;
background: #6c7989 -ms-linear-gradient(#6c7989, #434b55) fixed;
background: #6c7989 linear-gradient(#6c7989, #434b55) fixed;
}
body {
padding: 50px 0;
margin: 0;
font: 14px/1.5 Lato, "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #555;
font-weight: 300;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAeCAYAAABNChwpAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNXG14zYAAAAUdEVYdENyZWF0aW9uIFRpbWUAMy82LzEygrTcTAAAAFRJREFUSIljfPDggZRf5RIGGNjUHsNATz6jXmSL1Kb2GLiAX+USBnrymRgGGDCORgFmoNAXjEbBaBSMRsFoFIxGwWgUjEbBaBSMRsFoFIxGwWgUAABYNujumib3wAAAAABJRU5ErkJggg==') fixed;
}
.wrapper {
width: 640px;
margin: 0 auto;
background: #DEDEDE;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
-ms-border-radius: 8px;
-o-border-radius: 8px;
border-radius: 8px;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px;
box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px;
}
header, section, footer {
display: block;
}
a {
color: #069;
text-decoration: none;
}
p {
margin: 0 0 20px;
padding: 0;
}
strong {
color: #222;
font-weight: 700;
}
header {
-webkit-border-radius: 8px 8px 0 0;
-moz-border-radius: 8px 8px 0 0;
-ms-border-radius: 8px 8px 0 0;
-o-border-radius: 8px 8px 0 0;
border-radius: 8px 8px 0 0;
background: #C6EAFA;
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ddfbfc), color-stop(100%, #c6eafa));
background: -webkit-linear-gradient(#ddfbfc, #c6eafa);
background: -moz-linear-gradient(#ddfbfc, #c6eafa);
background: -o-linear-gradient(#ddfbfc, #c6eafa);
background: -ms-linear-gradient(#ddfbfc, #c6eafa);
background: linear-gradient(#ddfbfc, #c6eafa);
position: relative;
padding: 15px 20px;
border-bottom: 1px solid #B2D2E1;
}
header h1 {
margin: 0;
padding: 0;
font-size: 24px;
line-height: 1.2;
color: #069;
text-shadow: rgba(255, 255, 255, 0.9) 0 1px 0;
}
header.without-description h1 {
margin: 10px 0;
}
header p {
margin: 0;
color: #61778B;
width: 300px;
font-size: 13px;
}
header p.view {
display: none;
font-weight: 700;
text-shadow: rgba(255, 255, 255, 0.9) 0 1px 0;
-webkit-font-smoothing: antialiased;
}
header p.view a {
color: #06c;
}
header p.view small {
font-weight: 400;
}
header ul {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
z-index: 1;
right: 20px;
top: 20px;
height: 38px;
padding: 1px 0;
background: #5198DF;
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #77b9fb), color-stop(100%, #3782cd));
background: -webkit-linear-gradient(#77b9fb, #3782cd);
background: -moz-linear-gradient(#77b9fb, #3782cd);
background: -o-linear-gradient(#77b9fb, #3782cd);
background: -ms-linear-gradient(#77b9fb, #3782cd);
background: linear-gradient(#77b9fb, #3782cd);
border-radius: 5px;
-webkit-box-shadow: inset rgba(255, 255, 255, 0.45) 0 1px 0, inset rgba(0, 0, 0, 0.2) 0 -1px 0;
-moz-box-shadow: inset rgba(255, 255, 255, 0.45) 0 1px 0, inset rgba(0, 0, 0, 0.2) 0 -1px 0;
box-shadow: inset rgba(255, 255, 255, 0.45) 0 1px 0, inset rgba(0, 0, 0, 0.2) 0 -1px 0;
width: auto;
}
header ul:before {
content: '';
position: absolute;
z-index: -1;
left: -5px;
top: -4px;
right: -5px;
bottom: -6px;
background: rgba(0, 0, 0, 0.1);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
-ms-border-radius: 8px;
-o-border-radius: 8px;
border-radius: 8px;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0, inset rgba(255, 255, 255, 0.7) 0 -1px 0;
-moz-box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0, inset rgba(255, 255, 255, 0.7) 0 -1px 0;
box-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0, inset rgba(255, 255, 255, 0.7) 0 -1px 0;
}
header ul li {
width: 79px;
float: left;
border-right: 1px solid #3A7CBE;
height: 38px;
}
header ul li.single {
border: none;
}
header ul li + li {
width: 78px;
border-left: 1px solid #8BBEF3;
}
header ul li + li + li {
border-right: none;
width: 79px;
}
header ul a {
line-height: 1;
font-size: 11px;
color: #fff;
color: rgba(255, 255, 255, 0.8);
display: block;
text-align: center;
font-weight: 400;
padding-top: 6px;
height: 40px;
text-shadow: rgba(0, 0, 0, 0.4) 0 -1px 0;
}
header ul a strong {
font-size: 14px;
display: block;
color: #fff;
-webkit-font-smoothing: antialiased;
}
section {
padding: 15px 20px;
font-size: 15px;
border-top: 1px solid #fff;
background: -webkit-gradient(linear, 50% 0%, 50% 700, color-stop(0%, #fafafa), color-stop(100%, #dedede));
background: -webkit-linear-gradient(#fafafa, #dedede 700px);
background: -moz-linear-gradient(#fafafa, #dedede 700px);
background: -o-linear-gradient(#fafafa, #dedede 700px);
background: -ms-linear-gradient(#fafafa, #dedede 700px);
background: linear-gradient(#fafafa, #dedede 700px);
-webkit-border-radius: 0 0 8px 8px;
-moz-border-radius: 0 0 8px 8px;
-ms-border-radius: 0 0 8px 8px;
-o-border-radius: 0 0 8px 8px;
border-radius: 0 0 8px 8px;
position: relative;
}
h1, h2, h3, h4, h5, h6 {
color: #222;
padding: 0;
margin: 0 0 20px;
line-height: 1.2;
}
p, ul, ol, table, pre, dl {
margin: 0 0 20px;
}
h1, h2, h3 {
line-height: 1.1;
}
h1 {
font-size: 28px;
}
h2 {
color: #393939;
}
h3, h4, h5, h6 {
color: #494949;
}
blockquote {
margin: 0 -20px 20px;
padding: 15px 20px 1px 40px;
font-style: italic;
background: #ccc;
background: rgba(0, 0, 0, 0.06);
color: #222;
}
img {
max-width: 100%;
}
code, pre {
font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal;
color: #333;
font-size: 12px;
overflow-x: auto;
}
pre {
padding: 20px;
background: #3A3C42;
color: #f8f8f2;
margin: 0 -20px 20px;
}
pre code {
color: #f8f8f2;
}
li pre {
margin-left: -60px;
padding-left: 60px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
text-align: left;
padding: 5px 10px;
border-bottom: 1px solid #aaa;
}
dt {
color: #222;
font-weight: 700;
}
th {
color: #222;
}
small {
font-size: 11px;
}
hr {
border: 0;
background: #aaa;
height: 1px;
margin: 0 0 20px;
}
footer {
width: 640px;
margin: 0 auto;
padding: 20px 0 0;
color: #ccc;
overflow: hidden;
}
footer a {
color: #fff;
font-weight: bold;
}
footer p {
float: left;
}
footer p + p {
float: right;
}
@media print, screen and (max-width: 740px) {
body {
padding: 0;
}
.wrapper {
-webkit-border-radius: 0;
-moz-border-radius: 0;
-ms-border-radius: 0;
-o-border-radius: 0;
border-radius: 0;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
width: 100%;
}
footer {
-webkit-border-radius: 0;
-moz-border-radius: 0;
-ms-border-radius: 0;
-o-border-radius: 0;
border-radius: 0;
padding: 20px;
width: auto;
}
footer p {
float: none;
margin: 0;
}
footer p + p {
float: none;
}
}
@media print, screen and (max-width:580px) {
header ul {
display: none;
}
header p.view {
display: block;
}
header p {
width: 100%;
}
}
@media print {
header p.view a small:before {
content: 'at http://github.com/';
}
}

Binary file not shown.