Hi! I'm a software developer currently based in Los Angeles and a graduate of Loyola Marymount University. I have a wide variety of development interests and experience including web apps, games and desktop applications. I also have a strong interest in user-interface development and design.

This is a portfolio of some of my work. It contains descriptions and sometimes images, links, and code snippets of some of my more recent projects.

Originally from Houston, I grew up tinkering with web development and game design. I moved out to Los Angeles to pursue my degree in computer science, and I now work as a front-end web developer on a Facebook advertising platform at GraphEffect in Santa Monica. I'm also working on a number of personal projects outside of work, many of which can be seen here.

When I'm not working I'm likely to be found playing guitar, cooking delicious food, playing games or being a fan of Apple products.

Keyboard controls: [← →] Scroll pages

This Site

https://github.com/jlong64/resume/

This site contains some of my most recent front-end development, and, although simple, it is a pretty good example of my current capabilities. It's a very straightforward site -- it works as a completely static single page which is managed with JavaScript. This seemed to be the best fit for such a simple site. It does run through a very simple Sinatra-based back-end, though, mostly so that we can easily use HAML and SASS.

I've made fairly liberal use of some HTML5 and CSS3 features throughout the site, but I believe the site should still be somewhat functional on old browsers. I haven't really tested it yet though (it's on the todo list).

Soul Tax

https://github.com/jlong64/death_and_taxes/

Soul Tax is an open-source Flash game I worked on with a few friends for the Something Awful Game Dev VI event. The competition was held during the month of July 2011, so all development took place within one month, other than a couple minor additions and bug fixes since then.

The game dev event is held once a year, and each year has a different theme that the games need to adhere to. This year the theme was "Death and Taxes". The premise of the game is that you're a ghost who has been caught avoiding his taxes, so you need to get rid of your debt by paying back everything you owe...in souls! The game has an arcade-style feel with a progression of 30 timed levels. In each level, you use the ghost to possess people and send them and those around them to their untimely demise.

There are 10 different character types that you can possess, and each one has a unique special ability. For example, a maintenance guy can drill holes through the floor, and a supervillain can shoot people with his shrink ray. Each level requires you to figure out how to utilize the given character types to complete your objectives.

Voting for the competition is still ongoing, but currently Soul Tax is in the lead. The game is also hosted on Kongregate where it has, as of this writing, about 140,000 plays, and numerous articles have been written about the game in the indie gaming community.

The game was built using the Flixel framework, and I used my level editor Flevel to create the levels.

Iokat

http://iokat.com/

Iokat is the name of a website I created to host my released projects and my blog. It was created from scratch with a Rails back-end. It features user authentication with roles, content management for projects and blog posts, image and video galleries with JavaScript front-ends for projects, commentable blog posts, email notifications and more.

With more experience I now realize that the site is a bit of a mess, but creating it was a very good learning experience. I've realized that I don't really need many of the features I built into the site, and so pretty soon I'll be redesigning the site into something much simpler. Depending on when you're reading this (and when I remember to update this), the live site may not be indicative of the site that's described here.

eTab

eTab is a Mac application for editing and managing guitar tablature documents. It's currently under heavy development, but should be ready for release by the end of the year. The app began as my senior project during my final semester of college, and I have continued working on it since graduating with the goal of releasing it on the Mac App Store. The main features that set the app apart from similar apps are ease of input, a native Mac look and feel, a built-in iTunes-like document library, and comprehensive import and export functionality.

eTab is a pretty standard Mac app built in Objective-C with Cocoa, but it encompasses a very wide range of functionality that has given me a great deal of experience in many areas of application development. It makes use of a few standard Apple libraries including Core Audio and Core Animation.

Here's a slightly truncated implementation file for one of the application's main controller classes. Honestly, there's nothing in particular inside of it that's terribly interesting on its own, but it should show that I can write some decent Objective-C code. Note that this is a very early, unedited (except to remove some boring bits) chunk of code, so this isn't necessarily indicative at all of the code that will actually be released.

@implementation ScoreController

#pragma mark Selection methods

- (void) selectAll {
    [[[[NSApp delegate] activeTrack] selection] selectAllWithUndo: NO];

    [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreSelectionID, LCDBarViewID, TrackViewID, nil] withUndo: NO];
}

- (void) moveSelection: (Direction)direction withInsert: (BOOL)insert undo: (BOOL)undo {
    Selection* selection = [[[NSApp delegate] activeTrack] selection];
    
    // Possibly insert a division or measure and move the selection.
    if (insert && (direction == Left || direction == Right) && selection.mode == NoteSelectionMode) {
        // Check if we're moving out of the measure.
        BOOL leavingMeasure = ((direction == Right && [selection.start isLastDivisionInMeasure]) ||
                               (direction == Left  && [selection.start isFirstDivisionInMeasure]));
        
        // Insert a new division or measure if necessary.
        if (selection.start.measure.relativeDuration < 1.0) {
            [self insertDivisionAtSelectionWithDirection: direction];
        }
        else if (leavingMeasure && [selection.start.measure isLastMeasureInTrack]) {
            [self insertMeasureAtSelectionWithDirection: direction];
        }
        else {
            [selection move: direction withUndo: undo];
        }
    }
    else {
        [selection move: direction withUndo: undo];
    }
    
    // Scroll the score.
    [scoreView scrollSoMeasureIsVisible: selection.start.measure overTime: SelectionMoveScrollTime];
    
    [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreSelectionID, LCDBarViewID, TrackViewID, nil] withUndo: undo];
}

- (void) moveSelectionByMeasure: (Direction)direction withUndo: (BOOL)undo {
    Selection* selection = [[[NSApp delegate] activeTrack] selection];
    NSArray* measures    = [[[NSApp delegate] activeTrack] measures];
    Measure* start       = selection.start.measure;
    
    // Figure out which measure we want.
    Measure* newMeasure;
    
    switch (direction) {
        case Right: newMeasure = (start == measures.lastObject) ? [measures objectAtIndex: 0] : start.nextMeasure;     break;
        case Left:  newMeasure = (start == [measures objectAtIndex: 0]) ? measures.lastObject : start.previousMeasure; break;
        default:    return;
    }
    
    // Set the selection.
    [selection moveToMeasure: newMeasure withUndo: undo];
    
    // Scroll the score.
    [scoreView scrollSoMeasureIsVisible: selection.start.measure overTime: SelectionMoveScrollTime];
    
    [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreSelectionID, LCDBarViewID, TrackViewID, nil] withUndo: undo];
}

- (void) selectCurrentDivision {
    Selection* selection = [[[NSApp delegate] activeTrack] selection];
    
    // Beep and return if we're already in division selection mode.
    // TODO: Disable the menu item so that this can't happen.
    if (selection.mode == DivisionSelectionMode) {
        NSBeep();
        return;
    }
    
    // Select the current division.
    [selection selectFrom: selection.start to: selection.start withUndo: NO];
    
    [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreSelectionID, TrackViewID, nil] withUndo: NO];
}

- (void) selectDivisionAt: (NSPoint)p {
    DivisionLayout* divisionLayout = [scoreView.layout divisionLayoutAt: p];
    
    // If we clicked a division, select it.
    if (divisionLayout) {
        RowLayout* rowLayout = divisionLayout.measureLayout.rowLayout;
        
        // Keep track of the anchor division.
        anchorDivision = divisionLayout.division;
        
        // Figure out which string we selected.
        int string = (p.y - rowLayout.tabPosition + TabSpaceHeight / 2.0) / TabSpaceHeight;
        string     = clampToRange(string, 0, [[[NSApp delegate] activeTrack] stringCount] - 1);
        
        // Make the selection and scroll the score.
        [[[[NSApp delegate] activeTrack] selection] selectString: string ofDivision: anchorDivision withUndo: NO];
        [scoreView scrollSoMeasureIsVisible: anchorDivision.measure overTime: SelectionMoveScrollTime];
        
        [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreSelectionID, LCDBarViewID, TrackViewID, nil] withUndo: NO];
    }
}

- (void) jumpToString: (int)string {
    Track* track = [[NSApp delegate] activeTrack];
    
    // Beep if we're trying to jump to a non-existant string.
    if (string < track.stringCount) {
        [track.selection selectString: string withUndo: NO];
    }
    else {
        NSBeep();
    }
    
    [[NSApp delegate] redisplayView: ScoreSelectionID withUndo: NO];
}

- (void) startDragSelect {
    // Just set the flag.
    isPerformingDragSelect = YES;
}

- (void) updateDragSelectAt: (NSPoint)p {
    // Update the selection.
    Selection* selection = [[[NSApp delegate] activeTrack] selection];
    [selection selectFrom: anchorDivision to: [scoreView.layout divisionLayoutAt: p].division withUndo: NO];
    
    [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreSelectionID, LCDBarViewID, TrackViewID, nil] withUndo: NO];
}

- (void) endDragSelect {
    isPerformingDragSelect = NO;
}

- (void) resizeSelectionWithDirection: (Direction)direction {
    [[[[NSApp delegate] activeTrack] selection] resizeSelectionInDirection: direction withUndo: NO];
    
    [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreSelectionID, LCDBarViewID, TrackViewID, nil] withUndo: NO];
}

#pragma mark Selection operations

- (void) setSelectionDuration: (NoteDuration)duration {
    NSUndoManager* undoManager = [[NSApp delegate] undoManager];
    
    // Keep track of whether we modified anything.
    __block BOOL modified = NO;
    
    [[[[NSApp delegate] activeTrack] selection] collectDivisionsWithBlock: ^(Division* division) {
        // Skip notes that already have this duration.
        if (division.baseDuration != duration) {
            if (!modified) {
                [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreViewID, LCDBarViewID, nil] withUndo: YES];
                modified = YES;
            }
            
            // Set up undo.
            [[undoManager prepareWithInvocationTarget: division] setBaseDuration: division.baseDuration];
            
            // Set the division's duration.
            [division setBaseDurationWithUndo: duration];
        }
    }];
    
    // Beep if we didn't modify anything.
    if (!modified) {
        NSBeep();
        return;
    }
    
    // Set undo action name.
    [[NSApp delegate] setUndoActionName: @"Set Note Durations" withMessage: NO];
}

- (void) modifySelectionDuration: (int)difference {
    // TODO: Refactor so that this method calls setSelectionDuration.
    NSUndoManager* undoManager = [[NSApp delegate] undoManager];
    
    // Keep track of whether we actually modified any divisions.
    __block BOOL modified = NO;
    
    [[[[NSApp delegate] activeTrack] selection] collectDivisionsWithBlock: ^(Division* division) {
        int oldDuration = (int)division.baseDuration;
        int newDuration = clampToRange(oldDuration + difference, SixtyFourthNote, WholeNote);
        
        // Make sure the new duration is different so we can keep track of whether we modified any divisions.
        if (oldDuration != newDuration) {
            if (!modified) {
                [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreViewID, LCDBarViewID, nil] withUndo: YES];
                modified = YES;
            }
            
            // Set up undo.
            [[undoManager prepareWithInvocationTarget: division] setBaseDuration: oldDuration];
            
            // Set the duration.
            [division setBaseDurationWithUndo: newDuration];
        }
    }];
    
    // Beep if they can't modify the duration.
    if (!modified) {
        NSBeep();
        return;
    }
    
    // Set undo action name.
    NSString* actionName = (difference > 0) ? @"Increase Note Durations" : @"Decrease Note Durations";
    [[NSApp delegate] setUndoActionName: actionName withMessage: NO];
}

- (void) setSelectionToRests {
    [[[[NSApp delegate] activeTrack] selection] collectDivisionsWithBlock: ^(Division* division) {
        [division makeRestWithUndo: YES];
    }];
    
    [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreViewID, LCDBarViewID, TrackViewID, nil] withUndo: YES];
}

- (void) insertDivisionAtSelectionWithDirection: (Direction)direction {
    Selection* selection = [[[NSApp delegate] activeTrack] selection];
    int currentIndex     = [selection.start.measure.divisions indexOfObject: selection.start];
    
    // Beep and return if we're in division-selection mode.
    if (selection.mode == DivisionSelectionMode) {
        NSBeep();
        return;
    }
    
    // Add the division.
    int newIndex;
    
    switch (direction) {
        case Left:  newIndex = fmax(0, currentIndex - 1); break;
        case Right: newIndex = currentIndex + 1;          break;
        default:    return;
    }
    
    [selection.start.measure addDivisionAtIndex: newIndex withUndo: YES];
    
    // Select the new division.
    [selection selectDivision: [selection.start.measure.divisions objectAtIndex: newIndex] withUndo: YES];
    
    // Set up undo.
    [[NSApp delegate] setUndoActionName: @"Create Division" withMessage: NO];
    
    [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreViewID, LCDBarViewID, PaletteID, nil] withUndo: YES];
}

- (void) insertMeasureAtSelectionWithDirection: (Direction)direction {
    Selection* selection = [[[NSApp delegate] activeTrack] selection];
    NSArray* measures    = [[[NSApp delegate] activeTrack] measures];
    int currentIndex     = [measures indexOfObject: selection.start.measure];
    
    // Beep and return if we're in division-selection mode.
    if (selection.mode == DivisionSelectionMode) {
        NSBeep();
        return;
    }
    
    // Add the measure.
    int newIndex;
    
    switch (direction) {
        case Left:  newIndex = fmax(0, currentIndex - 1); break;
        case Right: newIndex = currentIndex + 1;          break;
        default:    return;
    }
    
    [[[NSApp delegate] activeScore] addMeasureAtIndex: newIndex withUndo: YES];
    
    // Select the new measure.
    [selection moveToMeasure: [measures objectAtIndex: newIndex] withUndo: YES];
    
    // Set up undo.
    [[NSApp delegate] setUndoActionName: @"Create Measure" withMessage: NO];
    
    [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreViewID, LCDBarViewID, TrackViewID, PaletteID, nil] withUndo: YES];
}

- (void) removeSelection {
    Selection* selection = [[[NSApp delegate] activeTrack] selection];
    
    // Perform the deletion based on the selection mode.
    if (selection.mode == DivisionSelectionMode) {
        [self removeSelectedDivisions];
    }
    else if (selection.mode == NoteSelectionMode) {
        // Delete the current note.
        [selection removeSelectedNoteWithUndo: YES];
        
        // Set the undo action name.
        [[NSApp delegate] setUndoActionName: @"Delete Note" withMessage: NO];
        
        [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreViewID, LCDBarViewID, TrackViewID, nil] withUndo: YES];
    }
}

- (void) removeSelectedDivisions {
    Selection* selection            = [[[NSApp delegate] activeTrack] selection];
    BOOL selectingMultipleDivisions = (selection.start != selection.end);
    
    // Delete the selected divisions.
    [selection removeSelectedDivisionsWithUndo: YES];
    
    // Set the undo action name.
    NSString* actionName = (selectingMultipleDivisions) ? @"Delete Divisions" : @"Delete Division";
    [[NSApp delegate] setUndoActionName: actionName withMessage: YES];
    
    [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreViewID, LCDBarViewID, TrackViewID, nil] withUndo: YES];
}

- (void) removeSelectedMeasures {
    Selection* selection           = [[[NSApp delegate] activeTrack] selection];
    BOOL selectingMultipleMeasures = (selection.start.measure != selection.end.measure);
    
    // Delete the selected measures and redisplay.
    [selection removeSelectedMeasuresWithUndo: YES];
    
    // Set the undo action name.
    NSString* actionName = (selectingMultipleMeasures) ? @"Delete Measures" : @"Delete Measure";
    [[NSApp delegate] setUndoActionName: actionName withMessage: YES];
    
    [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreViewID, LCDBarViewID, TrackViewID, nil] withUndo: YES];
}

- (void) transposeSelectionBy: (int)semitones {
    Selection* selection = [[[NSApp delegate] activeTrack] selection];
    
    // First we need to check if we're able to transpose every note in the selection.
    __block BOOL canTranspose     = YES;
    __block BOOL isEmptySelection = YES;
    
    [selection collectNonEmptyNotesWithBlock: ^(Note* note, int string) {
        // We are a non-empty selection if we reach this point.
        isEmptySelection = NO;
        
        // We can't transpose open notes downwards, and we can't transpose notes above the max fret number.
        if (!isInRange([note.division fretOnString: string] + semitones, 0, MaxFretNumber)) {
            canTranspose = NO;
        }
    }];
    
    // Beep and return if we can't transpose.
    if (!canTranspose || isEmptySelection) {
        NSBeep();
        return;
    }
    
    // We can transpose, so let's do it.
    [selection collectDivisionsWithBlock: ^(Division* division) {
        for (int i = 0; i < division.notes.count; i++) {
            Note* note = [division.notes objectAtIndex: i];
            
            // Make sure we're transposing a note within the selection, and that the note isn't empty.
            if ((selection.mode == DivisionSelectionMode || i == selection.selectedString) && ![note isEmpty]) {
                // Transpose.
                // TODO: Pass in the actual key.
                [note transposeBy: semitones inKey: nil withUndo: YES];
            }
        }
    }];
    
    // Set undo action name.
    [[NSApp delegate] setUndoActionName: @"Transpose Selection" withMessage: NO];
    
    [[NSApp delegate] redisplay: [NSSet setWithObjects: ScoreViewID, LCDBarViewID, nil] withUndo: YES];
}

#pragma mark Miscellaneous methods

- (void) scrollToSelection {
    Selection* selection = [[[NSApp delegate] activeTrack] selection];
    [scoreView scrollToMeasure: selection.start.measure overTime: SelectionMoveScrollTime];
}

- (BOOL) validateMenuItem: (NSMenuItem*)item {
    // All of our menu items should only be active if there is an open document.
    return ([[NSApp delegate] activeDocument] != nil);
}

@end

Flevel

http://iokat.com/flevel/

Flevel (Flixel Level Editor) is a barebones, web-based level editor for 2D, tile-based games. It was created primarily for use with Flixel games, and is built in Flixel itself. I began the project when I needed a simple level editor for one of my games and found nothing suitable that already existed.

Like all Flixel applications, the app is built in pure ActionScript 3.0 without use of the Flash IDE. It also interfaces with the web app that hosts it via an external interface to some JavaScript Ajax calls. The back-end is written in Rails and provides authentication as well as storage of all of the users' levels.

There are currently 191 registered users of the application.

M3

http://code.google.com/p/manicmonkeymadness/

M3 (Manic Monkey Madness) is a multiplayer Angry Birds-like browser game built entirely in JavaScript using HTML5's canvas element. It was a group-based senior project, and created entirely in one semester. We used Box2D as our physics engine, and much of my more advanced JavaScript experience started out here.

The game has two players placed on opposite ends of a terrain, each of which has a fort with some monkeys in it and a cannon. The players take turns launching projectiles back and forth at each other until all of a player's monkeys are eliminated. The game also features a level editor in which players can create their own fortresses.

The Google Code project page is available through the link above, but if you browse the code, keep in mind that all of the students (including myself) who worked on the project were fairly new to JavaScript. Since we were learning as we went, the code is basically a total mess. You have been warned!

During the development of the game, I found myself wanting to utilize object inheritance, but that it was not very straightforward to implement in JavaScript. I ended up creating a nice solution to the problem, which I wrote about in my blog.

Back to the Portfolio
Download: PDF · Plain Text
Click an item in the resume to get more information about it.

Languages

  • JavaScript

    I am very proficient in JavaScript due to my experience with web-based projects. I have considerable experience in front-end web development through work, school, and personal projects, including this website itself.

    During the development of an HTML5 canvas-based game built entirely with JavaScript, I came up with a useful prototypal inheritance pattern, which I wrote about in my blog.

  • Ruby

    Most of my back-end web development experience is in Ruby using Ruby on Rails. I used the language extensively in school, and it is my go-to scripting language.

  • C

    I gained a solid foundation in C during school, and have since expanded upon that knowledge mostly while working on projects in C++ and Objective-C. The audio programming in my project eTab is done in C, and I used C during my internship at Insomniac Games.

  • Objective-C

    I have a great deal of experience with Objective-C from developing my Cocoa app eTab.

  • C++

    My experience in C++ comes mostly from my internship as a gameplay programmer at Insomniac Games. I used C++ and C to implement gameplay features in their upcoming PS3 game Resistance 3.

  • ActionScript

    I've developed several small Flash games using ActionScript 3.0. Most of my ActionScript work has been done using the Flixel framework.

  • Java

    Most of my early programming in school was done in Java. I don't use it as much these days, although I did use it to implement a compiler during my final semester of college.

  • Perl

    A few years ago I did some back-end web development with Perl, though I haven't used it in a few years since switching to Ruby.

  • PHP

    My first experience in back-end web development several years ago was in PHP, and I continued to use it for a few years before switching to Perl.

  • LUA

    LUA was the primary scripting language used during my internship at Insomniac Games.

Skills

  • Web development

    I have a great deal of experience in web development. I am most skilled in front-end development, but I have plenty of experience with the back-end as well. I prefer to use JavaScript and jQuery for front-end work and Rails for back-end work, though I can easily adapt as necessary.

    This site itself, though simple, is a pretty good basic example of my front-end capabilities.

  • Gameplay programming

    Much of my experience in gameplay programming is from working on personal 2D game projects. I also have professional experience working on 3D console games from my internship at Insomniac Games.

  • App development

    I have quite a bit of experience in developing desktop applications from working on my project eTab. I am particularly interested and skilled in creating applications for the Mac platform.

  • Object-oriented programming

    I feel like this should be a given, but just in case, I'll clarify that I am an expert in both class-based and prototypal object-oriented programming.

  • UI design and implementation

    I have particular skill and interest in creating professional, usable interfaces. I can create great web interfaces, and I have a particular interest in the look and feel of interfaces for Apple platforms.

  • Tool development

    I enjoy tool development -- I developed a 2D, tile-based level editing tool to help me develop a game that I'm working on.

  • Server administration

    I have experience in running and maintaining Linux servers. This website itself is hosted on a virtual private server that I configured and set up myself.

Frameworks and Technologies

  • jQuery / jQueryUI

    I am an expert in jQuery, and I generally use it for almost all of my front-end web apps. This site makes extensive use of jQuery. That said, I am not dependent on it -- I am also very experienced in plain JavaScript.

  • Ruby on Rails

    Rails is my server-side framework of choice. I prefer to use it for all of my large-scale web projects.

  • Sinatra

    I use Sinatra for my small-scale web projects. This site is implemented using Sinatra.

  • HTML5 / CSS3

    I'm familiar with the latest HTML and CSS specs, including considerable experience with Canvas. This site uses a few HTML5 and CSS3 features including some of the new tags, data attributes, rounded corners, gradients and shadows.

  • HAML and SASS

    I'm very experienced with both HAML and SASS, and I find them to be really fun to work with. All of my recent major web projects use them.

  • AJAX

    The web app I work on at Medaxis makes heavy use of Ajax, and I've used it in my own web projects, mainly with jQuery.

  • Cocoa

    I have a great deal of experience in Cocoa from developing my Mac app eTab.

  • Flixel

    I have developed several games, as well as a tile-based level editing tool, in Flash with the Flixel framework.

Software

  • Xcode, Eclipse, Microsoft Visual Studio

    I have experience using all of these IDEs, though I personally prefer Xcode to the other two. I also do a lot of work in TextMate.

  • Git, Subversion, Perforce, CVS

    I have experience using all of these version control systems. My personal favorite is git.

  • Photoshop and Illustrator

    I have used Photoshop, and to a lesser extent, Illustrator, for many years.

  • Devtrack

    In the gaming industry I had extensive experience with Devtrack, and I can easily pick up other issue tracking software as needed. I personally use Github's issue tracker for my own projects.

  • LaTeX

    I have a great deal of experience creating documents with LaTeX. The PDF version of my resume was created with LaTeX.

  • OS X, Linux, Windows

    I am comfortable with all of the major modern operating systems, though I personally prefer doing work on a Mac.

Education

B.S. in Computer Science
May 2011
Loyola Marymount University — Los Angeles, CA

Employment

Web Developer

I was a front-end web developer at Medaxis on a contractual basis during my senior year of college and for a while afterwards. Duties included:

  • Working with the small development team at Medaxis as the front-end specialist on a large-scale web app used in the medical field
  • Designing and implementing features and fixing bugs in JavaScript
October 2010 - Present
Medaxis Corporation — Santa Monica, CA
Gameplay Programming Intern

I had a summer internship at Insomniac Games during the summer of 2010 as a gameplay programmer. Duties included:

  • Working with the gameplay programming team at Insomniac Games on their upcoming PlayStation 3 title Resistance 3
  • Implementing features and fixing bugs in C++ and LUA under the guidance of a senior member of the programming team
May 2010 - August 2010
Insomniac Games — Burbank, CA
Quality Assurance Tester

I worked as a QA tester at Neversoft Entertainment during the summers of 2008 and 2009. Duties included:

  • Working on a small team to perform tests for Neversoft's Guitar Hero: World Tour, Guitar Hero 5, and Band Hero games
  • Finding and logging bugs in a database and verifying implemented fixes
Summers 2008, 2009
Volt Technical Resources — Woodland Hills, CA