John Bintz's Blog

 

ClojureScript + AngularJS: Run-in-place edition

So in working on a mobile version of Can't Catch Me, Olivia!, I've found the nicest way to do the game logic is by storing the game data in ClojureScript objects, passing that game data object through various functions to handle player actions, re-storing that modified game data back onto an Angular scope, and having Angular convert that data into JavaScript objects that Angular can then use to fire off UI events. Simple. And the data in Can't Catch Me, Olivia! is pretty straightforward. Not many big ng-repeats (anymore, now that I've broken the board into its own directive), not may other things that Angular won't like because I'm constantly feeding it new Objects and Arrays to generate new scopes for.

Yeah, this process is destructive to the original JavaScript data. (aset $rootScope gameData (clj->js updated-game-data)) is basically what I'm doing, and that dumping in of an object that definitely has new Arrays and Objects in it forces Angular to create new scopes all the time. For another app I'm working on, with lots of Objects in Arrays, this just won't fly.

You can see an example of what happens with this Fiddle. The "reset" button mimics (aset $rootScope gameData (clj->js updated-game-data)). The "update" button uses my new approach:

So in this app, instead of that straight (aset $rootScope gameData (clj->js updated-game-data)), I take my existing $rootScope.gameData and my new ClojureScript object and I selectively update the existing JavaScript Objects-in-Arrays in place. The flat properties just get written over with new data. The number of items in the lists will not change, so I don't have to worry about checking for changes, but that wouldn't be too hard to code up if needed. My code looks something like this:

And finally, I place this object back onto the scope with (aset $rootScope gameData (clj->into->js updated-game-data (.-gameData $rootScope)))Pretty simple. For this app, it should work nicely and cut down on the constant rebuilding of ng-repeats.

 

Some more AngularJS + ClojureScript findings

Here's a brain dump of more tricks I've discovered while writing the mobile version of Can't Catch Me, Olivia! in ClojureScript and AngularJS:

atom makes caching data really easy. I wish I knew about it sooner. It sure beats sticking data on a $scope, especially if you want to keep that data in Clojure-land. One performance issue I had was redrawing the game board, which has an HTML structure built of <ul>s, <li>s for rows & columns, and <span>s for the clickable, color-changing squares themselves. Originally this was a bunch of ng-repeats and ng-classes, just to get it working (like you do with Angular), but on mobile devices it was a real performance killer. So I rewrote it to be a custom directive (like you also do with Angular when performance becomes an issue) that builds the board via jQuery and then $watches the board data for changes and re-renders on its own. I end up building the board within the directive with a nested set of doseq for y and x, then I re-enumerate the board and fill an (atom []) with [x y {reference to that coordinate's <span>}] for each coordinate (it's a 5x5 grid so it isn't a lot). Then, when I need to re-set all the classes on the <span>s, I can doseq through the atom and use the same function I wrote for ng-class to calculate the CSS class data very quickly and apply it to all of my referenced <span>s. This way I don't need nested doseqs to handle the x and y coords, either. I can also quickly set up $.fn.on touchstart handlers for each <span> this way. The directive looks kinda like this:

memoize is a neat trick. I profiled the program code and found a few functions that were being called a lot, mainly ones that calculate CSS classes, and memoized them. Their inputs were limited enough that I don't have to worry about memoizing too many inputs, and I got a nice speed boost out of it, too.

If I find any more cool frontend things with ClojureScript and AngularJS, I'll definitely blog about them. But next I'm going to try my hand at writing a node.js server in ClojureScript for another mobile project I'm working on. It will basically just synchronize data, but that's a lot more node.js than I've ever written, so it'll be an experience. :)

 

GPD G5A mini freakout - no orange LED, won't boot up

The hardware and software in the GPD G5A are still...a little flaky. It's OK, I understand. This morning, for some reason, I couldn't get my G5A to turn back on. No orange LED while charging by either DC, USB data cable or USB power cable. Resetting it by poking the reset hole with a paper clip for 5 seconds did the trick. Phew. Future John, remember this next time.

 

(= :awesome (merge :cljourescript :angularjs))

A few weeks ago I wrote about how I started messing with ClojureScript and AngularJS. I'm very good at JavaScript, and pretty good at Angular, but my ClojureScript was not as good. That has changed. I want to write about some general observations with using ClojureScript before I talk about some of the AngularJS-related things I've found.

First, it's super-nice to refactor. Most of my functions in this game I'm working on look a lot like this:

Writing the variable definitions in the let as small as I can makes it easy to see where I can refactor out code to other functions, public or private. And since I'm only ever dealing with inputs and outputs, it's so much easier to test. Unless it's a big function that integrates lots of little ones, usually via ->, I should only need a small handful of tests to make it work.

Second, Karma and ClojureScript play pretty nicely together. Since ClojureScript compilation creates big concatenated JavaScript output files, you just have to point Karma at the file defined in project.clj that represents your tests. Because I'm working in two environments (browser and tests), I have two different build targets in my project.clj:

I normally rely on integration tests to make sure my apps work, but with the fact that ClojureScript functions are designed to be super-small and work with entire states, I don't feel like it's as big a problem to refactor test code while working on app code, which is my biggest complaint with unit tests. Rarely will a function get bigger, unless it's an integration function. Also, I'm still learning ClojureScript, so I just wanted to beat on some code.

Speaking of integration functions, I've found the most Angular way to interoperate between ClojureScript and Angular states is two-fold: store the app's state in a ClojureScript map, on a property or whatever scope I want to keep it (for this app, I just put it on $rootScope, I don't care). That's the game state that ClojureScript works with directly. I have a $watch that watches for changes on that ClojureScript map and, when they occur, it performs a (clj->js watch-value) and dumps it onto another property on the state. That's the game state Angular uses for rendering content. Any manipulation of the game state is done via methods on the scope that call ClojureScript methods to manipulate and re-store that ClojureScript map, firing off the rest of the $watches.

This seems to fit in pretty well with the idea of functional programming -- to ClojureScript, it's all stateless, except at the very beginning and very end when it interacts with Angular. Once the state is set this way, Angular then kicks in and fires off all of the app-level events in directives and such. You don't get to set properties directly on game objects with ng-click, but it's a small price to pay. (I do have an additional uiState property I used entirely for non-game state UI things, like showing menus, so there is still some direct property setting going on).

I have two macros that work with the game state via Angular methods: one that expects to return a Plain Old JavaScript Object for Angular to use, and one that re-saves the game state after the method fires:

set-game-state does its magic for saving things, and interop was eventually boiled down to #(% (.-gameState $rootScope)). So I still have some cleanup work to do.

Here's some other random things I've found during my travels in parenthesis land:

  • I was trying to loop over two axes, x and y. doseq was the only way I could coax ClojureScript into actually performing the loop now, as opposed to lazily doing it later. Probably just me not knowing how to do it right, I'm sure.
  • This is more an Angular thing, but if you're saving states to local store on every change to the state, use Underscore and throttle the save operation, but do the save after a 1 tick $timeout to do it out of the $digest cycle. Something like (.debounce js/_ (fn [] $timeout #(.add localStorageService "gameState" my-pojo-game-state) 1) 50). For a mobile app, this level of latency I can totally live with, and if it stomps on itself once in a while, it'll stomp back eventually.
  • Here's one that is stupid obvious but I couldn't find a solid answer to anywhere: If you want to ensure a file is loaded before you load another one, because you've, for example, factored out an Angular directive into its own .cljs file, to make sure your directive is loaded after the other file, the directive needs to (:require [your-cool-project.main-browser-file]). I know, really obvious in hindsight, but it tripped me up for a good ten minutes.

Once this project is ready to go I'll share some more lessons learned. Until then (have :fun).

 

GPD G5A Update - Plugging all the crap into it update

After I posted my last GPD G5A update about the Monoprice USB OTG cable, I decided to order a different one from Amazon: Micro USB to USB OTG Adapter Cable (affiliate link). This one worked much better:

However, I still wouldn't want to do a ton of high-action long term play with both plugged in. That HDMI cable is pretty heavy, and I don't trust it in that thin little port. So I may end up ordering one of these pricy little guys to get around that. A nice, thin HDMI cable (or three, since my cat likes to chew cables) would make the multiplayer gaming experience with the G5A pretty much perfect.

 

GPD G5A Update - Plugging more crap into it edition

The next step in making my GPD G5A awesome, after updating it and installing the latest reicast and a copy of aFBA to get around the buggy Happy Chick emulators, is to get my friends in on the fun. This involved getting two things: a USB OTG cable and an HDMI -> HDMI-C adapter. Luckily, Monoprice carries both of these, but the combination of the two is not without its problems.

First off, individually, each component works great. Observe me using a keyboard with my tablet via the OTG adapter:

And using a USB controller along with the tabet's built-in controller to play some two player THPS2. It worked great, except for the craaaazy two player rendering glitches:

Next, the HDMI adapter. Except for being kind of bulky hanging off of the front of the GPD G5A, it worked perfectly, audio and video. Here's me kicking some computer ass at Marvel Vs. Capcom. Screw you, Mega Man:

The only problem is that the right angle of the Monoprice USB OTG cable hooks right over the GPD G5A's HDMI port, so you can't plug in both at the same time. Oops. I would have made a new OTG cable, but I would need to modify the pins on a different cable's micro USB plug to ground it properly, and I'm not that good at soldering yet. I'll just get a micro USB extension cable and be done with it.

And here's another tip: if the tablet's not charging well over USB, reboot it. Something (and I'm guessing it's Happy Chick) hangs around in the background, sucking down a lot of CPU. A clean reboot makes charging over USB go a lot faster.

 

(adventure ClojureScript (person "John")) - Rewrite your Brain Edition

For reasons, I've decided to finally head down the academic path of learning a Lisp. Clojure is the big boy for that right now, and while running stuff on the JVM is neat, I live most of my programming life writing some flavor of JavaScript. So, to (hopefully) make the transition a lot easier, I've decided to try my hand at converting a small mobile application from CoffeeScript to ClojureScript.

First of all, I had to learn how the darn language even worked. Thankfully, since the last time I tried to learn a functional programming language (which was Scheme in about 2004), the resources are a good bit better. I still feel like I'm not Computer Science-y enough to get everything, but I'm good at hitting things with hammers to make them work. Here's the best of the best that I used to figure out how the basics worked:

  • lein-cljsbuild
    Basically a one-stop shop for building ClojureScript projects and watching ClojureScript files for changes. I found a way to get lein cljsbuild auto to work nicely with Grunt, so it fits in well with the rest of my workflow. Very easy to set up and get working.
  • vim-fireplace
    Sorry emacs folks, I like vim, and this gets me lots of nice things for dealing with Clojure.
  • 4Clojure
    This site broke my brain and put it back together all Lisp-y and stuff. From getting the syntax to figuring out how the heck I was going to do a bunch of complicated loops and crap and get everything down to one return value was a real challenge. I'd blow through a dozen problems in 5 minutes, then take three days to get through the next one. Here's my user page if you're interested. As you can see, I have a ways to go.
  • Modern ClojureScript
    After I got comfortable with Clojure in general, I found this. This was perfect to get me enough knowledge with the language, the build system, and the JS output to get moving on my own project.
  • Anatomy of a Clojure Macro
    Macros are the black magic of Lisp. While I don't think there was a really good article that basically said "write this to make this", this one came super close. What's nice about ClojureScript is, once it's set up and you have autocompiling working, it's super-easy to see if your macro is translating you code right, since it turns it all into JavaScript.
  • The gyr library
    Speaking of macros, this is what I read (or attempted to read in the early days) to figure out how to turn random Lisp code into familiar Angular directives. This, plus the actual purnam library, made the transition from Java/CoffeeScript + AngularJS to ClojureScript + AngularJS a lot easier.

Once I had all of this stuff in place, I was able to actually start writing some ClojureScript code. And I decided to pick doing the hardest thing first, Lisp-wise. gyr doesn't come with a nice macro for angular.Module.run, which I needed for this project, so I wanted to learn how to write one. After nearly punching my little old laptop multiple times for three days, I got it working by dropping this in a .clj file in my project. I gave some line comments so you can get an idea of what JavaScript code will be produced when you use it:

I think the hardest problem I've had so far with learning ClojureScript is that some of the documentation doesn't give a lot of practical examples for things like this. It took hours of poking at this macro, recompiling the JavaScript (which requires recompiling the Java, because ClojureScript macros are Clojure, therefore they run in the JVM), looking at the output, cursing, changing a thing, wash, rinse, repeat. I know that Lips-y languages are intense and require brain rewiring, and I know this problem is a little weirder than some (AngularJS dependency injection ensurance, yay) but it's tough, even for someone with years of programming experience.

My first project is a private one, but I think I'm going to do another, more public, project in ClojureScript, AngularJS, and PhoneGap, just to get better at all of it. Should be interesting. Now that I'm over the bigger humps of using ClojureScript, it's just JavaScript to me (that sounds familiar) albeit with really neat looping constructs and Computer Science-y stuff (and a string library!). (stick-with (person "John") :clojurescript)

 

SVGGVS Updates: PDF prepending, crop marks, sheet identifiers

In working on the unnamed Dawn's Dictionary Drama microgame, I ended up making some much needed improvements to my Ruby-and-SVG-based card game card generator, SVGGVS.

Crop marks!

This was one of the biggest oversights in the original versions. Now, when creating a print'n'play PDF, you get crop marks added to the output. The neat thing about the code for this is that the method for generating the crop is very Lisp-y, since I've been spending some time learning Clojure:

PDF prepending

You can now have a PDF file prepended to your print'n'play PDF file with the prepend_pdf option. This is great for adding rules to the PDF so you don't need two downloads.

Data source sheet identifiers

Normally, sheets with the phrase "Card Data" in the title will be read for data. If you're going to have a game where the backs of some cards are different, and want all the data in a single spreadsheet, this won't fly. You can change the string SVGGVS looks for in the sheet titles with the card_sheet_identifier option.

Prerequisite checking

Run svggvs prereqs to see what else you need installed.

If you want to take the new features for a spin, gem install svggvs. Then, read through my SVGGVS articles that I wrote last year.

 

Some PhoneGap + AngularJS on Android notes

I made a small app for myself using PhoneGap and AngularJS. It's an environment I'm already pretty comfortable in. I have the beginnings of a good workflow in Grunt for doing everything (which I'll go into more detail about later), but I wanted to go over a few general things I discovered in making this little app:

I haven't gotten super-deep into development with PhoneGap and AngularJS, but as I do, I'll post more notes as I do so.

 

Unless otherwise indicated, all content is © 2009-2013 John Bintz. All rights reserved.