Design
Development
Motion
Other
-
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 live site. Take a look the real thing.
-
My original mock-up of the site. Unfortunately, I was unable to fully realize this view technically. Take a look at the real thing.
-
Search Ladder Search Ladder
What words have climbed the ladder today?
View the code from the project.
The Search Ladder AJAX Project
When challenged to make an AJAX site, I decided to use the RSS feed from Google Trends to make a ranking of the top rising searches. The idea was so simple technically, so I put in a lot of effort to style the information in an interesting way. I made the rankings text become sized in order, with the highest ranking starting at a large size and tapering down from there, then the rankings would randomize and be laid out over the page. Of course, my original mock-up was not quite technically possible, so I came to a close solution using the Masonry jQuery plugin and also added a little more information that was within the RSS.
Technology: HTML, CSS, Javascript/PHP (AJAX)
-
A screen-shot of the finished product. Take a look.
-
To Do List

