Zlock Art

portfolio

  • Photo by Mark Thiessen - National Geographic

    The completed packs of “The Explorers Game” cards, pictured at the 2011 Symposium. See the full article about the event from bizbash.com.

  • “The Explorers Game” logo, which started the development of the cards' style.

  • The card box design.

  • An example of one of the Explorers cards, featuring the likeness and information for Aparajita Datta.

  • Aside from the 101 cards featuring Explorers, the collection also has 23 activity cards, including this one.

  • The cards were color-coded to show the status of each Explorer: teal for Emerging Explorers, green for Explorers-in-Residence, and orange for National Geographic Fellows. The activity cards, which did not fall within these distinctions, had a different card-back to match the box and were each designed to be unique.

The Explorers Game

As part of my internship with National Geographic in the Spring of 2011, I created a set of collectable cards featuring the various Explorers associated with National Geographic, called “The Explorers Game.” The objectives of the cards were to create excitement for the 2011 Symposium, to encourage visits to National Geographic's website and social sites, to promote causes advertised by the National Geographic's Missions Department, and of course to promote the Explorers themselves.

In total, there are now 101 “Explorers” cards, each featuring an illustration of the Explorer, his association to National Geographic (as a Fellow, an Explorer-in-Residence, or Emerging Explorer), his field of study, and some facts about him. There are also 23 activity cards which add some interactivity to the collectable cards.

Please note: While I designed the cards from concept to print, the illustrations of the Explorers are Copyright © illustrator Chris Rooney. All other graphics were created by me and the fonts were purchased as a set from www.fontdiner.com.

Technology: Adobe Illustrator, Adobe Photoshop

  • Ads created for the "Cause an Uproar" and Freshwater Missions (and sub-sites) for National Geographic.

  • Ads created for the Little Kitties for Big Cats campaign. Pay $5 to upload a photo of your cat to their site and your money will go to saving Big Cats in the wild.

  • Bookmark created for the Little Kitties for Big Cats campaign. The bookmarks were printed and distributed to vet offices and other businesses.

National Geographic Design Work

When not working on “The Explorers Game” Project, my time was dedicated to creating house ads for the National Geographic Web Services Missions department and for upcoming museum events. The ads were added to the rotation of ads on the top and right sides of the National Geographic website, linking to each Mission's or event's home page.

The Missions promoted by my work:
"Cause an Uproar", dedicated to saving Big Cats.
The Freshwater Initiative, dedicated to informing people about water use and conservation.
Little Kitties for Big Cats, which raises money for the preservation of Big Cats in the wild.

Technology: Adobe Photoshop, Adobe Illustrator

  • The Photoshop mock-up for the Bangkok Bistro home page. The development of the site was very experimental, but can be seen here.

  • The Photoshop mock-up for the Bangkok Bistro menu page. The development of the site was very experimental, but can be seen here.

  • The Photoshop mock-up for the Bangkok Bistro location page, with the contact portion brought up. The development of the site was very experimental, but can be seen here.

  • While designing the site for the Bangkok Bistro, I thought a lot about the interface of the site on different devices. This is the iPhone interface for the menu. It was intended for the user to be able to "flip" through the menu items, which are divided into the different categories in an accordion style. The drop-down menu on the top would be the primary navigation.

  • The interface for the iPad portrait size. Unlike the iPhone, the interface is still scroll-based.

Bangkok Bistro Sample Site

As a class project, I was instructed to design and develop a website for a small local business. The business I chose was Bangkok Bistro, a Thai restaurant in Georgetown, Washington D.C. Since the development of this project, Bangkok Bistro has been bought and has now been converted to a Mai Thai restaurant.

When first starting this project, I thought a lot about the audience which Bangkok Bistro may want to attract. With both Georgetown University and George Washington University nearby, I thought it would be very beneficial to the business to target those college students. So, I made my design more bright and trendy rather than simple and sophisticated. I also put some thought into the devices the students may use, which would primarily be iPhones and Smart Phones and maybe even iPads.

Although I was never able to fully realize the iPad and iPhone designs for the site, I did put a lot of thought into the interface for those platforms and how they would be used. Mostly, I wanted the touch interfaces to be able to "flip" through menu items.

You can see the developed site here. However, the site itself was more of a learning experiment and should be treated as such. For example, it was fun to try making a liquid site, but it was clearly the wrong decision for this design.

Technology: Adobe Illustrator, Adobe Photoshop, HTML, CSS, Javascript, jQuery, PHP

  • HTML Ad for a fictional product.

  • HTML Ad advertising the "Warrior Dash." Unlike the previous ad, this one is for a real event and links to the organization's website. Why not sign up?

  • The Ads, pictured in the gMail interface.

HTML Ads

Created for a class at the BU:CDIA. The ads were designed, sliced, and arranged in a table referencing the hosted images, and then sent by e-mail. A copy of the ads in an e-mail can be sent on request

Technology: Adobe Photoshop, HTML

  • Every year I try to practice my portrait skills by working on a self portrait. This is the result from 2009.

  • "Just Out of Reach." This piece was originally meant to be a t-shirt design. Unfortunately, the ratio makes web-view of this piece awkward. View it a little better in a new window.

  • A commission for a tattoo design based on a piece of graffiti.

  • "All I Know." A personal piece originally drawn in pencil. Color and effects added in Corel Painter and Photoshop.

  • Another pencil piece with some color and texture added in Photoshop.

  • A portrait of Woody Allen created to emulate the style of Philippe Guyenne, a.k.a. HPX or HardcorePixxX. View the source image on his site. Woody Allen was not used in this picture for any reason other than I liked the source picture.

  • Drawing meant to emulate the style of French illustration and comic artist "Bengal." His old site appears to no longer be functional, but you can view his work at www.conceptart.org/?artist=bengal.

  • "Blood Moon Monk." This drawing started as part of the Character of the Week Challenge of the same title on conceptart.org

  • "Take My..." My self-portrait for 2010.

  • "Not Scared."

  • A comic page from an older project. While this project may be dead, I hope to return to comic work in the future.

  • An in-progess commission.

Illustration

Aside from whatever other technical projects I might have going on, I always try to keep my drawing skills sharp and will have a few short or longer-term illustration projects in the works. Corel Painter is my usual go-to for illustration, but some larger projects may start in pencil and then be scanned. In the past, I have freelanced my illustration services to individuals looking for small (11"x17") custom pieces for print.

Technology: Corel Painter, Adobe Photoshop

  • A music player created to take in XML, parse the information, and then manipulate sound files with a number of controls.

  •                         
    ///////////////////////////////////////  Import Files
    import fl.transitions.Tween;
    import fl.transitions.TweenEvent;
    import fl.transitions.easing.*;
    import flash.net.URLRequest;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.utils.ByteArray;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    
    //////////////////////////////////////////VARIABLES and default values
    
    //variables for management of drop down
    var dropDown:Boolean = false;  			// true = drop down is open
    var where:String = "closed";   			// identifies display in the drop down (eye, list, or closed)
    var bottomPosition:Number = player.bottomAndButton.y;	//store original value for easy return to position
    
    var animDropDown:Tween;
    var animDropClose:Tween;
    var screenLarger:Tween;
    var screenSmaller:Tween;
    player.screen.scaleY = .25;
    
    
    //Scroll Bar Controls and Limiters
    player.screen.listScrollBar.visible = false;
    player.volumeBox.volSlider.x = 19;
    
    var scrollLimit:Rectangle = new Rectangle();
    scrollLimit.top = 12;
    scrollLimit.left = 0;
    scrollLimit.right = 0;
    scrollLimit.bottom = 12;
    
    var scrollVolLimit:Rectangle = new Rectangle();
    scrollVolLimit.top = 0;
    scrollVolLimit.left = 0;
    scrollVolLimit.right = 38;
    scrollVolLimit.bottom = 0;
    
    var scrollSongLimit:Rectangle = new Rectangle();
    scrollSongLimit.top = 0;
    scrollSongLimit.left = 0;
    scrollSongLimit.right = 300;
    scrollSongLimit.bottom = 0;
    
    player.loading.visible= false;
    var loadActive:Boolean = false;
    
    
    //Variables for song management
    var songList:Array = new Array();
    var numberOfSongs:int = 0;
    var currentSong:int = 0;
    var songHere:Number = 0;   //song progress in milliseconds
    
    
    //Song and Channel variables
    var song:Sound = new Sound();
    var channel:SoundChannel = new SoundChannel();
    var musicState:String = "off";
    var volTransform:SoundTransform = new SoundTransform();
    volTransform.volume = .5;
    
    
    //Visualizer
    var waveform:ByteArray = new ByteArray();
    player.screen.vizSquare.visible = false;
    
    
    //xml and info management
    var songListXML:XML = new XML();
    var songFile:URLRequest = new URLRequest("playlist.xml");
    var xmlLoader:URLLoader = new URLLoader(songFile);
    
    xmlLoader.addEventListener(Event.COMPLETE, enable);  /// <-- START!
    
    
    
    ///////////////////////////////////////////////////////Start and enabling buttons
    function enable(theEvent:Event){
    	songListXML = XML(theEvent.target.data);
    	numberOfSongs = songListXML.Song.length() -1;
    
    	enableButtons();
    	loadSong();
    	}
    
    function enableButtons(){
    	player.buttonEye.buttonMode = true;
    	player.buttonList.buttonMode = true;
    	player.bottomAndButton.buttonClose.buttonMode = true;
    	player.buttonPlay.buttonMode = true;
    	player.buttons.buttonPause.buttonMode = true;
    	player.buttons.buttonBack.buttonMode = true;
    	player.buttons.buttonForward.buttonMode = true;
    	player.volumeBox.volSlider.buttonMode = true;
    	player.songSlider.buttonSongSlider.buttonMode = true;
    
    	player.buttonEye.addEventListener(MouseEvent.CLICK, onEyeClick);
    	player.buttonList.addEventListener(MouseEvent.CLICK, onListClick);
    	player.bottomAndButton.buttonClose.addEventListener(MouseEvent.CLICK, onCloseClick);
    	player.buttonPlay.addEventListener(MouseEvent.CLICK, onPlayClick);
    	player.buttons.buttonPause.addEventListener(MouseEvent.CLICK, onPauseClick);
    	player.buttons.buttonBack.addEventListener(MouseEvent.CLICK, onBackClick);
    	player.buttons.buttonForward.addEventListener(MouseEvent.CLICK, onForwardClick);
    	player.volumeBox.volSlider.addEventListener(MouseEvent.MOUSE_DOWN, onVolDown);
    	player.songSlider.buttonSongSlider.addEventListener(MouseEvent.MOUSE_DOWN, clickSongSlider);
    
    	player.buttonEye.stop();
    	player.buttonList.stop();
    	player.bottomAndButton.buttonClose.stop();
    	player.buttonPlay.stop();
    	player.buttons.buttonPause.stop();
    	player.buttons.buttonBack.stop();
    	player.buttons.buttonForward.stop();
    	}
    
    function disableButtons(){
    	player.buttonEye.removeEventListener(MouseEvent.CLICK, onEyeClick);
    	player.buttonList.removeEventListener(MouseEvent.CLICK, onListClick);
    	player.bottomAndButton.buttonClose.removeEventListener(MouseEvent.CLICK, onCloseClick);
    	player.buttonPlay.removeEventListener(MouseEvent.CLICK, onPlayClick);
    	player.buttons.buttonPause.removeEventListener(MouseEvent.CLICK, onPauseClick);
    	player.buttons.buttonBack.removeEventListener(MouseEvent.CLICK, onBackClick);
    	player.buttons.buttonForward.removeEventListener(MouseEvent.CLICK, onForwardClick);
    	player.volumeBox.volSlider.removeEventListener(MouseEvent.MOUSE_DOWN, onVolDown);
    	player.songSlider.buttonSongSlider.removeEventListener(MouseEvent.MOUSE_DOWN, clickSongSlider);
    	}
    
    
    
    ////////////////////////////////////////////////////////Drop Down Functions
    ///////// Buttons
    function onEyeClick(theEvent:MouseEvent){
    	if(where != "eye"){
    		if(dropDown == false){
    			where = "closedToEye";
    			}
    		else {
    			where = "listToEye";
    			}
    		openDropDown();
    		where = "eye";
    		}
    	}
    
    function onListClick(theEvent:MouseEvent){
    	if(where != "list"){
    		if(dropDown == false){
    			where = "closedToList";
    			}
    		else {
    			where = "eyeToList";
    			}
    		openDropDown();
    		}
    	}
    
    function onCloseClick(theEvent:MouseEvent){
    	if(where != "closed"){
    		if(where == "eye"){
    			where = "eyeToClosed";
    			}
    		else {
    			where = "listToClosed";
    			}
    		closeDropDown();
    		where = "closed";
    		}
    	}
    
    //////// Open and Closing
    function openDropDown(){
    	disableButtons();
    	if (dropDown == true){
    		emptyDropDown();
    		dropDown = false;
    		closeDropDown();
    		}
    	else {
    		animDropDown = new Tween(player.bottomAndButton, "y", Regular.easeInOut, bottomPosition, 300, 1, true);
    		screenLarger = new Tween(player.screen, "scaleY", Regular.easeInOut, .25, 1, 1, true);
    		dropDown = true;
    		animDropDown.addEventListener(TweenEvent.MOTION_FINISH, dropDownComplete);
    		}
    	}
    
    function dropDownComplete(theEvent:TweenEvent){
    	if((where == "closedToList")||(where == "eyeToList")){
    		displaySongList();
    		setSongData();
    		}
    	else if(where == "eye"){
    		displayViz();
    		}
    		enableButtons();
    	}
    
    function closeDropDown(){
    	disableButtons();
    	if( dropDown == false){
    		screenSmaller = new Tween(player.screen, "scaleY", Regular.easeInOut, 1, .25, 1, true);
    		animDropClose = new Tween(player.bottomAndButton, "y", Regular.easeInOut, 300, bottomPosition, 1, true);
    		animDropClose.addEventListener(TweenEvent.MOTION_FINISH, redirectToOpen);
    		}
    	else{
    		emptyDropDown();
    		screenSmaller = new Tween(player.screen, "scaleY", Regular.easeInOut, 1, .25, 1, true);
    		animDropClose = new Tween(player.bottomAndButton, "y", Regular.easeInOut, 300, bottomPosition, 1, true);
    		dropDown = false;
    		animDropClose.addEventListener(TweenEvent.MOTION_FINISH, dropCloseComplete);
    		}
    	}
    
    function dropCloseComplete(theEvent:TweenEvent){
    	enableButtons();
    	}
    
    function redirectToOpen(theEvent:TweenEvent){
    	openDropDown();
    	}
    
    function emptyDropDown(){
    	if((where == "listToClosed")||(where == "listToEye")){
    		for(var j:int = 0; j<=numberOfSongs; j++){
    			player.screen.maskSquare.removeChild(songList[j]);
    			}
    		player.screen.listScrollBar.visible = false;
    		}
    	else if(where == "eyeToClosed" || where == "eyeToList"){
    		player.screen.vizSquare.visible = false;
    		}
    	}
    
    
    ////////// List
    function displaySongList(){
    	var listItemY:Number = 45;
    	where = "list";
    
    	if(songList[0] == null){
    	for(var i:int = 0; i<=numberOfSongs; i++){
    		var item:songListItem = new songListItem();
    		songList[i] = item;
    		songList[i].name = i.toString();
    		songList[i].buttonListPlay.buttonMode = true;
    		songList[i].buttonListPlay.stop();
    		songList[i].buttonListPlay.addEventListener(MouseEvent.CLICK, onListPlayClick);
    		}
    	}
    
    	for(var k:int = 0; k<=numberOfSongs; k++){
    		songList[k].listSongBox.listSongName.text = songListXML.Song[k].Title;
    		songList[k].listArtistBox.listArtistName.text = songListXML.Song[k].Artist;
    		player.screen.maskSquare.addChild(songList[k]);
    
    		songList[k].buttonListPlaySelected.visible = false;
    
    		songList[k].y = listItemY;
    		listItemY += 20;
    	}
    
    	player.screen.listScrollBar.listScrollBarSlider.scaleY = 6/(numberOfSongs + 1);
    	if((6/(numberOfSongs + 1)) >= 1){
    		player.screen.listScrollBar.visible = false;
    		}
    	else{
    		player.screen.listScrollBar.visible = true;
    		player.screen.listScrollBar.listScrollBarSlider.buttonMode = true;
    		scrollLimit.bottom = 12 + ( 112 - player.screen.listScrollBar.listScrollBarSlider.height);
    		}
    
    	player.screen.listScrollBar.listScrollBarSlider.addEventListener(MouseEvent.MOUSE_DOWN, clickListScroll);
    	}
    
    function clickListScroll(theEvent:MouseEvent){
    	addEventListener(MouseEvent.MOUSE_MOVE, dragListScroll);
    	addEventListener(MouseEvent.MOUSE_UP, unclickListScroll);
    	player.screen.listScrollBar.listScrollBarSlider.startDrag(false, scrollLimit);
    	}
    
    function dragListScroll(theEvent:MouseEvent){
    	player.screen.maskSquare.y = 0 - (((player.screen.listScrollBar.listScrollBarSlider.y - scrollLimit.top)/59) * (45+(numberOfSongs+1)*8.1) )
    	}
    
    function unclickListScroll(theEvent:MouseEvent){
    	removeEventListener(MouseEvent.MOUSE_MOVE, dragListScroll);
    	removeEventListener(MouseEvent.MOUSE_UP, unclickListScroll);
    	player.screen.listScrollBar.listScrollBarSlider.stopDrag();
    	}
    
    ////////////// Visualizer aka "eye"
    function displayViz(){
    	player.screen.vizSquare.visible = true;
    	}
    
    function startWaveViz(){
    	SoundMixer.computeSpectrum(waveform, false, 2);
    	player.screen.vizSquare.graphics.clear();
    	player.screen.vizSquare.graphics.lineStyle(0, 0xFFFFFF);
    	drawChannelWaves();
    	player.screen.vizSquare.graphics.lineStyle(0, 0xBFFF18);
    	drawChannelWaves();
    	}
    
    function drawChannelWaves(){
    	var SAMPLES:Number = 256;
    	var XStep:Number = player.screen.vizSquare.width / SAMPLES;
    
    	player.screen.vizSquare.graphics.moveTo(0, player.screen.vizSquare.height/2);
    
    	for(var i:int = 0, X:Number = 0; i < SAMPLES; i++, X+=XStep){
    		var amplitude:Number = waveform.readFloat();
    		var Y:Number = (player.screen.vizSquare.height / 2) + (amplitude * player.screen.vizSquare.height/2);
    		player.screen.vizSquare.graphics.lineTo(X, Y);
    		}
    	}
    
    
    ///////////////// Loading Songs
    function loadSong(){
    	removeEventListener(Event.ENTER_FRAME, songProgress);
    	player.songSlider.buttonSongSlider.x = 0;
    
    	if(loadActive == true){
    		song.removeEventListener(ProgressEvent.PROGRESS, showProgress);
    		song.removeEventListener(Event.COMPLETE, onSongLoad);
    		player.loading.visible= false;
    		player.loading.loadingMask.scaleX = 0;
    		}
    
    	song = new Sound();
    	songName.text = songListXML.Song[currentSong].Title;
    	artistName.text = songListXML.Song[currentSong].Artist;
    	albumName.text = songListXML.Song[currentSong].Album;
    
    
    	if(where == "list"){
    		setSongData();
    		}
    
    	var soundFile:URLRequest = new URLRequest(songListXML.Song[currentSong].@songURL);
    	song.load(soundFile);
    	loadActive = true;
    	song.addEventListener(ProgressEvent.PROGRESS, showProgress);
    	song.addEventListener(Event.COMPLETE, onSongLoad);
    }
    
    function onSongLoad(theEvent:Event){
    	formatTime();
    	player.loading.visible= false;
    	if(musicState == "playFromList" || musicState == "playFromChange"){
    		playMusic();
    		musicState = "on"
    		loadActive = false;
    		}
    	}
    
    
    ////////////  Music control buttons
    function onPlayClick(theEvent:MouseEvent){
    	if(musicState != "on"){
    		playMusic();
    		}
    	}
    
    function onListPlayClick(theEvent:MouseEvent){     /////// Play button next to song in list
    	stopSong();
    	clearSongData();
    	currentSong = Number(theEvent.target.parent.name);
    
    	musicState = "playFromList";
    	loadSong();
    	}
    
    function onPauseClick(theEvent:MouseEvent){
    	pauseMusic();
    	}
    
    function onBackClick(theEvent:MouseEvent){
    	clearSongData();
    	if (currentSong == 0){
    		currentSong = numberOfSongs;
    		}
    	else{
    		currentSong--;
    		}
    
    	if (musicState == "on"){
    		stopSong();
    		}
    	musicState = "playFromChange"
    	loadSong();
    	}
    
    function onForwardClick(theEvent:MouseEvent){
    	nextSong();
    	}
    
    function onVolDown(theEvent:MouseEvent){
    	addEventListener(MouseEvent.MOUSE_MOVE, dragVolSlider);
    	addEventListener(MouseEvent.MOUSE_UP, unclickVolSlider);
    	player.volumeBox.volSlider.startDrag(false, scrollVolLimit);
    	}
    
    function unclickVolSlider(theEvent:MouseEvent){
    	removeEventListener(MouseEvent.MOUSE_MOVE, dragVolSlider);
    	removeEventListener(MouseEvent.MOUSE_UP, unclickVolSlider);
    	player.volumeBox.volSlider.stopDrag();
    	}
    
    function dragVolSlider(theEvent:MouseEvent){
    	volTransform.volume = (player.volumeBox.volSlider.x/scrollVolLimit.right)
    	channel.soundTransform = volTransform;
    	}
    
    function clickSongSlider(theEvent:MouseEvent){
    	pauseMusic();
    	addEventListener(MouseEvent.MOUSE_MOVE, dragSongSlider);
    	addEventListener(MouseEvent.MOUSE_UP, unclickSongSlider);
    	player.songSlider.buttonSongSlider.startDrag(false, scrollSongLimit);
    	}
    
    function unclickSongSlider(theEvent:MouseEvent){
    	removeEventListener(MouseEvent.MOUSE_MOVE, dragSongSlider);
    	removeEventListener(MouseEvent.MOUSE_UP, unclickSongSlider);
    	player.songSlider.buttonSongSlider.stopDrag();
    
    	if (musicState == "pause"){
    		playMusic();
    		}
    	formatTime();
    	}
    
    function dragSongSlider(theEvent:MouseEvent){
    	songHere = song.length * (player.songSlider.buttonSongSlider.x/300);
    	}
    
    function playMusic(){
    	channel = song.play(songHere);
    	channel.soundTransform = volTransform;
    	musicState = "on";
    	channel.addEventListener(Event.SOUND_COMPLETE, songFinished);
    	addEventListener(Event.ENTER_FRAME, songProgress);
    	}
    
    function pauseMusic(){
    	if(musicState == "on"){
    		songHere = channel.position;
    		channel.stop();
    		removeEventListener(Event.ENTER_FRAME, songProgress);
    		musicState = "pause";
    		}
    	else{
    		musicState = "off";
    		}
    	}
    
    //////////////// Back-end song management
    function stopSong(){
    	channel.stop();
    	musicState = "off";
    	}
    
    function clearSongData(){
    	songHere = 0;
    	if(where == "list"){
    		songList[currentSong].buttonListPlaySelected.visible = false;
    		songList[currentSong].buttonListPlay.visible = true;
    		}
    	}
    
    function setSongData(){
    	songList[currentSong].buttonListPlaySelected.visible = true;
    	songList[currentSong].buttonListPlay.visible = false;
    	}
    
    function songProgress(theEvent:Event){
    	player.songSlider.buttonSongSlider.x = 300 * channel.position/song.length;
    	songHere = channel.position;
    	formatTime();
    	if(where == "eye"){
    		startWaveViz();
    		}
    	}
    
    function showProgress(theEvent:ProgressEvent){
    	player.loading.visible= true;
    	player.loading.loadingMask.scaleX = (theEvent.bytesLoaded/theEvent.bytesTotal);
    	}
    
    function songFinished(theEvent:Event){
    	nextSong();
    	}
    
    function nextSong(){
    	clearSongData();
    	if (currentSong == numberOfSongs){
    		currentSong = 0;
    		}
    	else{
    		currentSong++;
    		}
    
    	if (musicState == "on"){
    		stopSong();
    		}
    	musicState = "playFromChange"
    	loadSong();
    	}
    
    function formatTime(){
    	var minutesNow:Number = 0;
    	var secondsNow:Number = 0;
    	var minutesTotal:Number = 0;
    	var secondsTotal:Number = 0;
    	var milli:Number = 0;		//number of milliseconds
    	var secondsNowString:String = "00";
    	var secondsTotalString:String = "00";
    
    	milli = songHere;
    	minutesNow = milli/60000;
    	minutesNow = Math.floor(minutesNow);
    	secondsNow = (milli/1000) - (minutesNow*60);
    	secondsNow = Math.floor(secondsNow);
    
    	milli = song.length;
    	minutesTotal = milli/60000;
    	minutesTotal = Math.floor(minutesTotal);
    	secondsTotal = (milli/1000) - (minutesTotal*60);
    	secondsTotal = Math.floor(secondsTotal);
    
    	if (secondsNow < 10){
    		secondsNowString = "0" + secondsNow.toString();
    		}
    	else{
    		secondsNowString = secondsNow.toString();
    		}
    
    	if (secondsTotal < 10){
    		secondsTotalString = "0" + secondsTotal.toString();
    		}
    	else{
    		secondsTotalString = secondsTotal.toString();
    		}
    
    	time.text = minutesNow + ":" + secondsNowString + "/" + minutesTotal + ":" + secondsTotalString;
    	}                    

    View the code from the project.

Flash Music Player

The last project for a three week flash class. Created in four days, from design to implementation. I took special care to build it in such a way so that, if more music was added, it would visually adjust where needed and everything would remain functional.

Please note that the code snippet for the visualizer was provided by our instructor. All other code is mine.

Technology: Adobe Flash, Action Script 3, Adobe Illustrator

  • A screen-shot of the finished product. Take a look.

  •                         <!Doctype html>
    
            <head>
                <style type="text/css">
                    .strikeout{
                        text-decoration: line-through;
                    }
    
                    #todo{
                        width: 400px;
                        background-color: #cccccc;
                        margin: 30px auto 30px auto;
                        padding: 30px;
                    }
                    ul{
                        margin-bottom: 40px;
                        list-style-type: none;
                    }
                    li{
                        position: relative;
                    }
                    li p{
                        margin: 0;
                        display: inline;
                        line-height: 130%;
                    }
                    .completeButton{
                        position: absolute;
                        left: -30px;
                    }
                    .priorityButton{
                        float: right;
                    }
                    li>label{
                        float: right;
                    }
    
                </style>
            </head>
    
    <body>
    
    <div id="content">
    
    
                <div id="todo">
                    <h1>To Do List</h1>
                    <form>
    		            <ul>
                            <li>
                                <p>Get an Internship</p>
                            </li>
                            <li>
                                <p>Graduate School</p>
                            </li>
                            <li>
                                <p>Get a Job</p>
                            </li>
                            <li>
                                <p>Make Money</p>
                            </li>
                            <li>
                                <p>Live Happily Ever After</p>
                            </li>
    		            </ul>
    
    		            <label>Add a to-do:</label>
    		            <input type="text" name="textToAdd" value="" />
                        <input type="button" name="addButton" value="Add Item" />
    	            </form>
    
                </div>
            </div>
    
    
    
    
    <!--   ........................................JavaScript ......................................................... -->
    
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript" src="js/jquery-ui-1.8.9.custom.min.js"></script>
    
    <script type="text/javascript">
    
    	function strikeout(){
    		// "this" is a p tag in an li
    		if(!($(this).hasClass("editable"))){
    			$(this).addClass("strikeout");
    		};
    	};
    
    	function removeStrike(){
    		// "this" is a p tag in an li
    		$(this).removeClass("strikeout");
    	};
    
    	function addItem(){
    		// "this" does not exist here because this edits using heirarchy
            if(($("input[name = 'textToAdd']").attr("value") != "")){
    			var holdText = $("input[name = 'textToAdd']").attr("value");
                var itemIDforAttr = 0;
    
                setTimeout(function(){
                    $("#todo ul").append("<li><p>" + holdText +"</p><input class='completeButton' type='button' name='complete' value='X' /><input class='priorityButton' type='checkbox' name='priority' value='" + itemIDforAttr + "' /><label>high priority</label></li>");
    			    $("#todo ul").children().last().children("p").hide().animate({"background-color": "yellow"}, 10).fadeIn().delay(2000).animate({"background-color": "#cccccc"}, 1000);
    
    			    $("input[name='textToAdd']").attr("value", "");
                }, 100);
    		};
    	};
    
    
        function addList(){
    		// "this" does not exist here because this edits using heirarchy
            if(($("input[name = 'listTextToAdd']").attr("value") != "")){
    			var holdText = $("input[name = 'listTextToAdd']").attr("value");
                var listIDforAttr = 0;
    
                $.post("includes/functional/post.php", { send: holdText, "func": "addList", "send2": "userID" }, function(data){
                        listIDforAttr = data;
                });
    
                setTimeout(function(){
                    $("#todo form").last().after(
                            "<h1>" + holdText + "</h1>" +
                            "<form>" +
    		                    "<ul data-listNum='" + listIDforAttr + "'></ul>" +
    
    		                    "<label>Add a to-do:</label>" +
    		                    "<input type='text' name='textToAdd" + listIDforAttr + "' value='' />" +
                                "<input type='button' name='addButton" + listIDforAttr + "' value='Add Item' />" +
    	                    "</form>"
                        );
    			$("#todo form").last().hide().fadeIn(1000);
                $("#todo h1").last().hide().fadeIn(1000);
    
    			$("input[name='listTextToAdd']").attr("value", "");
    
                $("#todo ul").sortable({containment: 'parent'}, {tolerance: 'pointer'});
                        $("#todo ul").bind("sortstop",  function (event, ui){
                            var listID = ui.item.closest("ul").attr("data-listNum");
                            var itemID = ui.item.closest("li").attr("data-id");
                            var listNumberAfter = ui.item.index();
                            listNumberAfter++;
    
                            $.post("includes/functional/post.php", { send: listNumberAfter, send2: listID, send3: itemID , "func": "changePriority" });
                       });
    
    
                }, 100);
    
    
    		};
    	};
    
    
    	function removeItem(){
    		// "this" is the x button, input[name="completeButton"]
    		$(this).parent().fadeOut("slow", function () {
                $(this).remove();
    		});
    	};
    
    	function editItem(){
    		// "this" is the p tag, which is being filled with an input tag
    		if(!($(this).hasClass("editable"))){
    			var holdText = $(this).html();
    			$(this).removeClass("strikeout");
    			$(this).html("<input type='text' name='edit' value='" + holdText + "' />");
    			$(this).addClass("editable");
                $(":focus").focusout();
                $(this).children().focus();
      		};
    	};
    
    
    	function sortItem(){
    			// "this" is the input:checkbox button
            var listID = $(this).closest("ul").attr("data-listNum");
            var itemID = $(this).closest("li").attr("data-id");
    
            if(($(this).is("input:checked")) && ($(this).closest("li").not(":first-child").length) ){
                    $(this).parent().fadeOut("slow", function (){
                        // "this" is the li, which is the parent on the input button
                        $(this).insertBefore($(this).closest("ul").children("li").first());
                        $(this).fadeIn("slow");
                    });
    			} else if (!($(this).closest("li").is(":first-child"))){
    				if(( $(this).closest("li").index() == ($(this).closest("ul").children("li").has("input:checked").last().index() + 1) ) ){
    
                    } else{
                        $(this).closest("li").fadeOut("slow", function (){
                            // "this" is the li, which is the parent on the input button
                            $(this).closest("ul").children("li").has("input:checked").last().after($(this).closest("li"));
                            $(this).closest("li").fadeIn();
                        });
                    };
    
    			} else if((!($(this).is("input:checked"))) && ($(this).closest("li").is(":first-child")) && ($(this).closest("ul").children("li").has("input:checked"))){
    				if(( $(this).closest("li").index() == ($(this).closest("ul").children("li").has("input:checked").last().index() + 1) ) ){
    
                    } else{
                        $(this).closest("li").fadeOut("slow", function (){
                            // "this" is the li, which is the parent on the input button
                            $(this).closest("ul").children("li").has("input:checked").last().after($(this).closest("li"));
                            $(this).closest("li").fadeIn();
                        });
                    };
    			} else{
            };
    
    	};
    
    
    
    	/////////////////////////////////////////////////////////End of Functions
    
    
    	//Add complete ("X") buttons
    	$("#todo li").append("<input class='completeButton' type='button' name='complete' value='X' />");
    
    
    	//Add checkboxes
    	for(var i=0; i < $("#todo li").length ; i++){
    		$("#todo li:eq(" + i + ")").append("<input class='priorityButton' type='checkbox' name='priority' value='" + i + "' /><label>high priority</					label>");
    	};
    
        $("input:checkbox[data-checked='yes']").attr("checked", "checked");
    
    	//Handle Strikeouts
    	$("#todo ul li p").live('click', function (){
    		$(this).addClass("strikeout");
    		$(this).toggle(removeStrike, strikeout);
    	});
    
    
    	//Add items to the list using the text field at the bottom
    	$("input[name^='addButton']").live("click", function(event){
            var listNumber = $(this).closest("ul").attr("data-listNum");
            addItem(listNumber);
        });
    	$("input[name^='textToAdd']").focus().live("keypress", function(event) {
            var listNumber = $(this).siblings("ul").attr("data-listNum");
      	  if(event.keyCode==13){
      		addItem(listNumber);
      		};
      	});
    
    
        $("input[name='addListButton']").click(addList);
    	$("input[name='listTextToAdd']").focus().keypress( function(event) {
            if(event.keyCode==13){
      		addList();
      		};
      	});
    
    
      	// Remove items with complete ("X") button
      	$("input[name='complete']").live("click", removeItem);
    
      	// Enable sorting when checkboxes are clicked
      	$("input:checkbox").live("click", sortItem);
    
    	// Make items editable when doubleclicked
      	$("#todo li p").live("dblclick", editItem);
    
      	//Make list sortable with drag and drop
      	$("#todo ul").sortable({containment: 'parent'}, {tolerance: 'pointer'});
        $("#todo ul").bind("sortstop",  function (event, ui){
            var listID = ui.item.closest("ul").attr("data-listNum");
            var itemID = ui.item.closest("li").attr("data-id");
            var listNumberAfter = ui.item.index();
            listNumberAfter++;
        });
    
      	//Disable the form from submitting when you hit enter
      	$("#todo form").live("submit", function (){
      		return false;
      	});
    
        $("p>input").focus().live("keypress", function(event) {
    	        // "this" is the input tag in the p tag
    		    	if(event.keyCode==13){
                         var holdText = $(this).attr("value");
    		            $(this).parent().removeClass("editable");
    		            $(this).parent().hide().animate({"background-color": "yellow"}, 10).fadeIn("slow").delay(2000).animate({"background-color": 	 					"white"}, 1000);
    
                        var itemID = $(this).closest("li").attr("data-id");
    
                        $(this).parent().html(holdText);
    		  		};
        });
    
        $("p>input").live("blur", function(){
                        var holdText = $(this).attr("value");
    		            $(this).parent().removeClass("editable");
    		            $(this).parent().hide().animate({"background-color": "yellow"}, 10).fadeIn("slow").delay(2000).animate({"background-color": 	 					"white"}, 1000);
    
                        var itemID = $(this).closest("li").attr("data-id");
    
                        $(this).parent().html(holdText);
        });
    
    </script>
    
    </body>
    </html>
                        

    View the code from the project.

To Do List jQuery Project

This project just tested my abilities to stack functionality in jQuery. With this list you can add priority, drag and drop each item, eliminate each item, click it once to strike-out the item and click twice to edit that to-do item. Also, you can add new items with the small form at the bottom.

Technology: HTML, Javascript, jQuery

  • TImeline animation made in Adobe Flash.

  • Interactive piece with timeline animation triggered by Action Script.

Flash Animations

Technology: Adobe Flash, Action Script 3

  • A short text-animation created to complement the Lorine Neidecker poem represented. The concept behind the animation was to emulate leaves falling into the water.

  • A longer animation created to visually complement recorded commentary about the life of Lorine Niedecker from 1931-1935.

Immortal Cupboard Animations

In 2008-2009, I worked for Cinematographer Cathy C. Cook on her project: "Immortal Cupboard: In Search of Lorine Niedecker." I was asked to create a series of small text animations to complement the poems of Lorine Niedecker as well as create a longer sequence to accompany commentary about her life from 1931-1935. The film premiered with the animations in Spring 2009.

Technology: Adobe After Effects

  • A render of the three soldiers created for the "Jumper" project as a promotional image and title screen.

  • My original concept sketch for the orange soldier.

  • View a play-through of the "Jumper" demo.

  • "Super Mario Rehab," a stop-motion animation. Worked with fellow students Tim Brosius and Umar Shakir.

  • "Sole Mates," also stop-motion.

  • After Effects animaton project.

UMBC Animations

Jumper

As my capstone project for UMBC's GAIM program, I and a team of other students built a demo game called "Jumper." The concept of the game centers around a character (or perhaps an "entity" is a better term) with the ability to jump from body to body. The game was meant to be more strategy-based, as the "entity" used the abilities of those he posessed to get passed different obstacles.

So, with the concept in place, we made three "soldier" characters, which had different benefits on posession. The blue woman soldier was the lighter, faster, and more maneuverable character, but with low defense. The orange soldier was more destructive and had moderate defense and speed. Lastly, the red soldier had very high defense, but was very slow.

My role in the project was co-art lead with my teammate Helen Zhang. I also created the model for the orange soldier, did the rigging for the blue and orange soldiers, and made some of the in-game animations for all the soldiers.




Aside from "Jumper," there are a few other animations here from my time at UMBC, showcasing some stop-motion and After Effects work. Although I have transitioned to Web Design and Development, I still enjoy taking part in all kinds of projects, including animation.

Technology: Maya, Final Cut Express, Adobe After Effects

  • Video provided by the IRC's Vimeo channel.

    An experimental animation created using zoetropes. I was involved in the conception, the creation of the zoetropes, and the editing of the video along with 9 other students.

  • An interactive exhibit. I was involved with the organization of the exhibit and the technical production of the interactive pieces. I also designed the postcard-sized invitation for the event shown above.

  • Video provided by the IRC's Vimeo channel.

    Episode 1 of a series of 5 webisodes. I was greatly involved in the organization of the project and talent management. Continue the series with episode 2.

IRC (Imaging Research Center Fellowship)

While attending UMBC, I became a part of the prestigious IRC Fellows program. As a fellow, I took part in three semester-long projects all in different fields of production and animation. Learn more about the program on their website.



Spring 2008

Mentor Eric Dyer led a group of ten students into a fast-paced adventure with experimental animation and a tough deadline. In less than three months, the fellows put together a 5-minute video to go along with Randall Woolf's composition "Try to Believe." The video was then submitted to the Brooklyn Philharmonic's "Believe You Can Win" competition. The video won and was later shown along with the Philharmonic's Traversing the Mushroom Kingdom presentation.



Fall 2008

In September 2008, the Fellows started with an abandoned bowling alley in the Charles North section of Baltimore and by December ended up with an exhibition of mixed audio and visual interactive art. Led by interactive artist Lisa Moren, the students acquired a variety of audio and visual content from the bowling alley. Light and touch sensors were then added to the space and the captured sights and sounds would be triggered as guests were invited to explore. Some elements from the alley were then moved to the December exhibit, titled Video Arcane, for a wider audience to enjoy.



Spring 2009

The Mills Get a Wind Turbine project was designed to make viewers question the benefits and the repercussions behind switching to wind power, the supposedly more "green" solution to our energy crisis. "Are we just being sold on the energy company's next big thing?" This was the message the Fellows had in mind while working with filmmaker Lee Boot. The result was a series of five webisodes. A website was originally created to display the work and encourage discussion, but the site has since been taken down. All of the episodes can now be seen on the IRC's Vimeo channel.

Technology: Full Adobe Suite, Final Cut Express, and more.