Flash: tracking rightclicks from Flash with Google Analytics
for a long time, I’ve been adding my own custom context menu to almost everything I’ve created in Flash.
this means, that when someone rightclicks my Flash, they will see this menu:

and what good has this rightclick menu done me..
well, it links to my blog, right, but has anyone ever come to my blog from this rightclick menu?
actually, I don’t know, but now I’ve decided to do something about it!
setting up a link that will be trackable in Google Analytics:
I’ve changed the link in my right click menu from
“http://campjohn.dk/wp/” to
“http://campjohn.dk/wp/?utm_source=Sanita&utm_medium=flash&utm_campaign=rightclick”
by doing this, I can now use Google Analytics to actually track how many gets to my blog from my rightclick menu.

as you can see, the only rightclick I have so far is the one I’ve generated myself – for the sake of this blogpost.
but in the future I will be able to actually see how many use my rightclick menu.
sorting the tracking of clicks in Google Analytics by using the source parameter:
AND, if using the parameter source (on the picture marked with a red circle) I can filter where the rightclicks come from.
the one I’ve tracked so far comes from this link:
“http://campjohn.dk/wp/?utm_source=Sanita&utm_medium=flash&utm_campaign=rightclick”
because the rightclick comes from a Flash made for Sanita.
but if I were to make Flash for i. e. casino.dk, I could use this link
“http://campjohn.dk/wp/?utm_source=Casino&utm_medium=flash&utm_campaign=rightclick”
and the I would be able to filter all my rightclicks by either the parameter Sanita or Casino and see how many rightclicks each of the Flash’s has generated.
quite nice!
related post on Google Analytics:
ActionScript 3.0: tracking video progress using JavaScript and Google Analytics
showcase: Sanita workwear Flash, part 2
the assignment:
having made an intro for Sanita in Flash, they luckily liked it so much, that they actually requested a variation of the Flash.
this time the Flash-file should be smaller in file size (the original was 262kb) and have almost no text, just statements and pictures.
what we did to keep the file size down was to actually create not 1 but 2 variations of the intro.
each of the variations holds 3 pictures that they loop through.
using only 3 pictures in each variation keeps the file size of the variations at 110kb and 115kb, and by creating 2 different variations, it not only makes the use of the variations more flexible, it also still uses the 6 desired pictures for the variations.

click here to see the result of the first Sanita workwear Flash variation
click here to see the result of the second Sanita workwear Flash variation
the intro:
here is the original intro that the variations are created from:
click here to see the original Sanita workwear Flash intro assignment
After Effects: Catwalk TV ad demo for BON’A PARTE
twice a year or more, I edit catwalk video for BON’A PARTE.
the main work is to color correct the video and make small videos of each set of clothes.
having done this in january, I decided to make a small TV ad-like demo:
I wanted to use only existing material, and I wanted to set it up template based, so it would be fairly easy to reproduce next time catwalk video was shot.
here’s what I ended up with:
related post:
TV ad demo for Fleur in After Effects:
ActionScript 3.0: zoom module for Priess
I was asked to create a product zoom module for Priess, that would load one picture. when loaded I should create a small version of the picture, and when moving the mouse around on the small version of the picture, I should show that area in a zoom window.
first of all, check out the zoom module for Priess made in Flash and ActionScript 3.0 here

here is the flow on how I’ve set the module up in ActionScript:
1) I set up a preloader and a right click menu
2) I load the picture
3) when loaded I create a Bitmap version of the picture, that I scale and smooth so it will fit the scaled version window nicely
4) then I add the big picture to the zoom window and and eventlisteners, that react, if the mouse moves around the scaled version window
5) finally I set up the script that moves the big picture in the zoom window. the math for this is the tricky part, but keeping your head cool, it’s actually quite straight forward.
here’s the entire script for the flow in ActionScript:
import caurina.transitions.Tweener;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.net.URLRequest;
import MonsterDebugger;
public class PriessZoomContent extends Sprite {
private var _thePicture:String;
private var _md:MonsterDebugger;
private var _bigHolderWidth:Number = 374;
private var _loader:Loader = new Loader();
private var _interact:Boolean = false;
private var _myPreloader:MyPreloader;
public function PriessZoomContent() {
//init();
}
public function init(somePic:String):void {
_thePicture = somePic;
_md = new MonsterDebugger(this);
trace("_thePicture passed to the loaded flash = "+_thePicture);
loadThePicture();
}
private function loadThePicture():void {
_myPreloader = new MyPreloader();
_myPreloader.x = 399;
_myPreloader.y = 176;
addChild(_myPreloader);
_loader = new Loader();
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, pictureLoaded, false, 0, true);
_loader.load(new URLRequest(_thePicture));
}
private function pictureLoaded(e:Event):void {
trace("pictureLoaded");
_myPreloader.x = 599;
removeChild(_myPreloader);
_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, pictureLoaded);
var bmd:BitmapData = Bitmap(e.target.content).bitmapData;
var bm:Bitmap = new Bitmap(bmd);
bm.scaleX = bm.scaleY = _bigHolderWidth / 2000;
bm.smoothing = true;
trace("bm.width = "+bm.width+" & bm.height = "+bm.height);
BigHolder.addChild(bm);
ZoomHolder.zoomed.addChild(e.target.content);
BigHolder.addEventListener(Event.ENTER_FRAME, bigHolderEvent, false, 0, true);
BigHolder.addEventListener(MouseEvent.ROLL_OVER, bigHolderOver, false, 0, true);
BigHolder.addEventListener(MouseEvent.ROLL_OUT, bigHolderOut, false, 0, true);
}
private function bigHolderOver(e:MouseEvent):void {
_interact = true;
}
private function bigHolderOut(e:MouseEvent):void {
_interact = false;
}
private function bigHolderEvent(e:Event){
if(_interact){
ZoomHolder.zoomed.getChildAt(0).x = -((ZoomHolder.zoomed.width - ZoomHolder.theMask.width) / BigHolder.width * BigHolder.mouseX);
ZoomHolder.zoomed.getChildAt(0).y = -((ZoomHolder.zoomed.height - ZoomHolder.theMask.height) / BigHolder.height * BigHolder.mouseY);
}
}
}
}
credits:
Scott Snyder for the great guitar shot
Alfred Priess A/S: http://www.priess.dk/
showcase: Sanita workwear Flash
just a quick post on this Sanita Flash.
the assignment:
- create a Flash that combines these pictures with the Sanita workwear needed in the situation.
- add an animated sequence besides the pictures.
- have it ready within 2 hours.

click here to see the result of the Sanita workwear Flash assignment
other recent showcases:
University College Mordjylland tabbed informationbar in Flash
New Years Eve 2009 invitation
Xmas 2009, invitation and greeting
showcase: UCN tabbed informationbar in Flash
I’ve just finished a big Flash for University College Nordjylland.
this Flash was to be an alternative menu, a different version of a site-tree, to bring focus to certain areas of the website.

the Flash is made up of 4 tabs that can be chosen by the user.
3 of these tabs contain some kind of interactive element.
the tab “Studieliv” contains some moveable polaroids.
the tab “Karriere” contains 10 cases, each case describing a former student now with a nice career.
the tab “Download” contains downloadable brochures, setup of these inspired by coverflow and the Mac OS X menu.
check out the Flash for University College Nordjylland here:
update: to make sure all content of the informationbar is shown, I’ve added a auto-rotate feature, that changes the tab shown every 5th second, until one of the tabs is clicked.
ActionScript 3.0: Pixel Bender filter used in Flash gallery
having written my last post on using Pixel Bender filters in Flash, I got a lot on comments asking me to do some more demo’s on how to actually use the Pixel Bender filters in real cases. so I decided to start out with a gallery of 3 images. in the gallery the transition between each image is animated in and out using the AngledBWHalftone filter by Gus Campbell to make it a bit different.
![]()
check out the gallery using the AngledBWHalftone Pixel Bender filter here:
the original blog post on Pixel Bender:
click here to read the “amazing examples of Pixel Benders filters used in Flash.”
credits:
Gus Campbell for the AngledBWHalftone Pixel Bender filter.
Rasmus Andersen for the nice pictures from Cuba.
ActionScript 3.0: fullscreen backgroundpicture in Flash
through the last year, I’ve been asked to do 3 different versions of proportionally correctly scalable images that would fill the entire browser. even if the browser window would later be scaled. so here’s the three different versions:
the static version of a fullscreen backgroundpicture in Flash:
fill 100%, rescale if size of browserwindow changes.
check out the static version of a fullscreen backgroundpicture in Flash here
the animated version of a fullscreen backgroundpicture in Flash:
fill 100%, animate to new rescaled size and position if size of browserwindow changes.
check out the animated version of a fullscreen backgroundpicture in Flash here
the version of several fullscreen backgroundpictures in Flash:
fill 100%, rescale if size of browserwindow changes, repeatedly change the backgroundpicture.
check out the version of several fullscreen backgroundpictures in Flash here

the ActionScript for all 3 versions;
static:
import caurina.transitions.Tweener;
import NewCustomContextMenu;
//import flash.external.ExternalInterface;
//vars
//----------------------------------------------------------------------------------------------------
var menuData:Array = [];
menuData.push( {caption:"© 2010 Felix Sanchez", url:"http://www.campjohn.dk/wp"} );
var ncm:NewCustomContextMenu = new NewCustomContextMenu(menuData, this);
var _stageWidth:Number; //width of the stage
var _stageHeight:Number; //height of the stage
var _BGloader:Loader; //loader to hold my picture
var _tBB:BlackBar;
var _tWB:WhiteBar;
var ratio:Number; //to make sure the picture and video is scaled correctly
//LOCAL
var _theFeed:String = "image_bg.jpg";
//ONLINE
//var _theFeed:String = String(root.loaderInfo.parameters.whatFeed);
var _white:String = String(root.loaderInfo.parameters.white);
/*
var theParams:String = "_theFeed = "+_theFeed+" & _white = "+_white;
ExternalInterface.call("alert", theParams);
*/
//----------------------------------------------------------------------------------------------------
//init
stageInit();
function stageInit():void {
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.BEST;
stage.frameRate = 30;
stage.showDefaultContextMenu = true;
stage.addEventListener(Event.RESIZE, onResize);
setUpForPicture(); //
}
//----------------------------------------------------------------------------------------------------
//PICTURE
//this all has to do with the picture
//----------------------------------------------------------------------------------------------------
function setUpForPicture():void {
_BGloader = new Loader();
_BGloader.alpha = 0;
addChild(_BGloader);
_BGloader.load(new URLRequest(_theFeed));
_BGloader.contentLoaderInfo.addEventListener(Event.INIT, onResize);
_BGloader.contentLoaderInfo.addEventListener(Event.COMPLETE, pictureFullyLoaded);
}
function pictureFullyLoaded(e:Event){
Tweener.addTween(_BGloader, {alpha:1, time:0.4});
myResize(stage.stageWidth, stage.stageHeight);
}
//----------------------------------------------------------------------------------------------------
//this handles the resizing of the video or the picture
function onResize(event:Event):void {
myResize(stage.stageWidth, stage.stageHeight);
}
//this handles the resizing of the video or the picture
function myResize(stageWidth:Number, stageHeight:Number):void {
_stageWidth = stageWidth;
_stageHeight = stageHeight;
ratio = _BGloader.width / _BGloader.height;
if ((_stageWidth / ratio) >= _stageHeight) {
_BGloader.width = _stageWidth;
_BGloader.height = (_stageWidth / ratio);
}
else {
_BGloader.height = _stageHeight;
_BGloader.width = (_stageHeight * ratio);
}
}
animated:
import caurina.transitions.Tweener;
import NewCustomContextMenu;
//import flash.external.ExternalInterface;
//vars
//----------------------------------------------------------------------------------------------------
var menuData:Array = [];
menuData.push( {caption:"© 2010 Felix Sanchez", url:"http://www.campjohn.dk/wp"} );
var ncm:NewCustomContextMenu = new NewCustomContextMenu(menuData, this);
var _stageWidth:Number; //width of the stage
var _stageHeight:Number; //height of the stage
var _BGloader:Loader; //loader to load my picture
var _BGholder:Sprite; //sprite to hold my picture
var _tBB:BlackBar;
var ratio:Number; //to make sure the picture and video is scaled correctly
//LOCAL
var _theFeed:String = "flytbar.jpg";
//ONLINE
//var _theFeed:String = String(root.loaderInfo.parameters.whatFeed);
//----------------------------------------------------------------------------------------------------
//init
stageInit();
function stageInit():void {
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.BEST;
stage.frameRate = 30;
stage.showDefaultContextMenu = true;
stage.addEventListener(Event.RESIZE, onResize, false, 0, true);
setUpForPicture(); //
}
//----------------------------------------------------------------------------------------------------
//PICTURE
//this all has to do with the picture
//----------------------------------------------------------------------------------------------------
function setUpForPicture():void {
_BGloader = new Loader();
_BGloader.alpha = 0;
_BGloader.load(new URLRequest(_theFeed));
_BGloader.contentLoaderInfo.addEventListener(Event.COMPLETE, pictureFullyLoaded, false, 0, true);
}
function pictureFullyLoaded(e:Event){
var bitmap:Bitmap = Bitmap(e.target.content);
bitmap.smoothing = true;
_BGholder = new Sprite();
_BGholder.addChild(bitmap);
addChild(_BGholder);
//addBars();
Tweener.addTween(_BGholder, {alpha:1, time:0.4});
myResize(stage.stageWidth, stage.stageHeight);
}
//----------------------------------------------------------------------------------------------------
//this handles the resizing of the video or the picture
function onResize(event:Event):void {
myResize(stage.stageWidth, stage.stageHeight);
}
//this handles the resizing of the video or the picture
function myResize(stageWidth:Number, stageHeight:Number):void {
_stageWidth = stageWidth;
_stageHeight = stageHeight;
ratio = _BGholder.width / _BGholder.height;
if ((_stageWidth / ratio) >= _stageHeight) {
_BGholder.width = _stageWidth * 1.1;
_BGholder.height = (_stageWidth / ratio) * 1.1;
}
else {
_BGholder.height = _stageHeight * 1.1;
_BGholder.width = (_stageHeight * ratio) * 1.1;
}
var newX = Math.floor(-((_BGholder.width - _stageWidth) / 2));
var newY = Math.floor(-((_BGholder.height - _stageHeight) / 2));
Tweener.addTween(_BGholder, {x:newX, y:newY, time:7});
}
several:
import caurina.transitions.Tweener;
import NewCustomContextMenu;
import flash.external.ExternalInterface;
//vars
//----------------------------------------------------------------------------------------------------
var menuData:Array = [];
menuData.push( {caption:"© 2010 Felix Sanchez", url:"http://www.campjohn.dk/wp"} );
var ncm:NewCustomContextMenu = new NewCustomContextMenu(menuData, this);
var _stageWidth:Number; //width of the stage
var _stageHeight:Number; //height of the stage
var _BGloader:Loader; //loader to hold my picture
var _BGloader2:Loader; //loader to hold my picture
var _ratio:Number; //to make sure the picture and video is scaled correctly
var _picArray:Array;
var _number:Number = 0;
var _timer:Timer = new Timer(5000, 0);
//LOCAL
var _theFeed:String = "image_bg1.jpg,image_bg2.jpg,image_bg3.jpg";
//ONLINE
//var _theFeed:String = String(root.loaderInfo.parameters.whatFeed);
//----------------------------------------------------------------------------------------------------
//init
//addEventListener(Event.ADDED_TO_STAGE, stageInit, false, 0, true);
_timer.addEventListener(TimerEvent.TIMER, timerHandler);
stageInit(null);
//----------------------------------------------------------------------------------------------------
function stageInit(e:Event):void {
trace("function stageInit");
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.BEST;
stage.frameRate = 30;
stage.showDefaultContextMenu = true;
stage.addEventListener(Event.RESIZE, onResize, false, 0, true);
createPictureArray();
}
//CREATE ARRAY OF PICTURES
//this all has to do with the picture
//----------------------------------------------------------------------------------------------------
function createPictureArray():void {
_picArray = _theFeed.split(",");
setUpForPicture();
}
//PICTURE
//this all has to do with the picture
//----------------------------------------------------------------------------------------------------
function setUpForPicture():void {
stage.removeEventListener(Event.RESIZE, onResize);
_BGloader = new Loader();
_BGloader.alpha = 0;
addChild(_BGloader);
_BGloader.load(new URLRequest(_picArray[_number]));
_BGloader.contentLoaderInfo.addEventListener(Event.COMPLETE, pictureFullyLoaded);
}
function pictureFullyLoaded(e:Event){
stage.addEventListener(Event.RESIZE, onResize, false, 0, true);
Tweener.addTween(_BGloader, {alpha:1, time:1.4});
_number++;
checkNumber();
myResize(stage.stageWidth, stage.stageHeight);
_timer.start();
}
function checkNumber():void {
if(_number == _picArray.length) {
_number = 0;
}
}
//----------------------------------------------------------------------------------------------------
//this handles the resizing of the video or the picture
function onResize(event:Event):void {
myResize(stage.stageWidth, stage.stageHeight);
}
//this handles the resizing of the video or the picture
function myResize(stageWidth:Number, stageHeight:Number):void {
_stageWidth = stageWidth;
_stageHeight = stageHeight;
_ratio = this.getChildAt(this.numChildren -1).width / this.getChildAt(this.numChildren -1).height;
if ((_stageWidth / _ratio) >= _stageHeight) {
this.getChildAt(this.numChildren -1).width = _stageWidth;
this.getChildAt(this.numChildren -1).height = (_stageWidth / _ratio);
} else {
this.getChildAt(this.numChildren -1).height = _stageHeight;
this.getChildAt(this.numChildren -1).width = (_stageHeight * _ratio);
}
}
//----------------------------------------------------------------------------------------------------
function timerHandler(e:TimerEvent):void {
_timer.stop();
setUpForPicture();
}
—
credits:
Rikke Madsen for the photos
ActionScript 3.0: logobanner for MCH Messecenter Herning / Porsche 911 Carrera 4/4S Cabriolet gallery
about the logobanner:
for MCH Messecenter Herning I recently did a logobanner, that would show up to 5 different logos from a collection of several logos. the logobanner should randomly select 5 logos, slide them in, await a randomized amount of time, and then slide out again. before sliding in once again, a new logo should be selected, so that new logos would constantly be shown.
the logos should be fed to the logobanner using XML.

the ActionScript for the logobanner:
import ArrayStuff;
import caurina.transitions.Tweener;
import com.gskinner.motion.GTween;
import fl.motion.easing.*;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import MonsterDebugger;
public class LogoContent extends Sprite {
private var _theXML:String;
private var _md:MonsterDebugger;
private var _loadedXML:XML;
private var _XMLLogoArray:Array = [];
private var _arrayStuff:ArrayStuff;
private var _yPlacement:Array = [0, 120, 240, 360, 480, 600];
private var _itemToStageNumber:Number = 0;
private var _tween:GTween;
private var _holder:Sprite;
public function LogoContent() {
//init();
}
public function init(someXML:String):void {
_theXML = someXML;
_md = new MonsterDebugger(this);
//trace("_theXML passed to the loaded flash = "+_theXML);
loadXML();
}
private function loadXML():void {
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest(_theXML);
loader.addEventListener(Event.COMPLETE, xmlLoaded, false, 0, true);
loader.addEventListener(IOErrorEvent.IO_ERROR, xmlError, false, 0, true);
loader.load(request);
}
private function xmlLoaded(e:Event):void {
_loadedXML = new XML(e.target.data);
traceStuff();
XMLcontentToArray();
}
private function xmlError(e:Event):void {
trace("error loading");
}
private function traceStuff():void {
//trace("_loadedXML = "+_loadedXML); //output: complete XML
//trace("_loadedXML.logo.length() = "+_loadedXML.logo.length()); //output: number of logos
//trace("_loadedXML.logo.thePicture[0] = "+_loadedXML.logo.thePicture[0]); //output: name of first logo
}
private function XMLcontentToArray():void {
var i:Number = 0;
while(i < _loadedXML.logo.length()){
_XMLLogoArray.push(_loadedXML.logo.thePicture[i]);
i++;
}
_arrayStuff = new ArrayStuff();
_arrayStuff.convertToLoaders(_XMLLogoArray);
_arrayStuff.addEventListener("loaderArrayReady", loaderArrayReady);
}
private function loaderArrayReady(e:Event):void {
_XMLLogoArray = e.currentTarget._loaderArray;
trace(_XMLLogoArray);
var i:Number = 0;
while(i < 6){
placeOnStage();
i++;
}
}
private function placeOnStage():void {
_holder = new Sprite();
_holder.name = "holder"+_itemToStageNumber;
addChild(_holder);
//trace("_XMLLogoArray.length = "+_XMLLogoArray.length);
var i:Number = Math.floor(Math.random()*_XMLLogoArray.length);
var dispObj:DisplayObject = _XMLLogoArray[i];
_XMLLogoArray.splice(i, 1);
_holder.addChild(dispObj);
_holder.x = -dispObj.width;
_holder.y = _yPlacement[_itemToStageNumber];
//trace("_XMLLogoArray.length = "+_XMLLogoArray.length);
var myDelay:Number = Math.random()*2;
//trace("dispObj.width = "+dispObj.width);
//_tween = new GTween(_holder, 1, {x:-10}, {ease:Sine.easeIn, delay:myDelay, reflect:false, repeatCount:1});
_tween = new GTween(_holder, 1.2, {x:(215-dispObj.width)/2}, {ease:Back.easeOut, delay:myDelay, reflect:false, repeatCount:1});
_tween = new GTween(_holder, 1.2, {x:215}, {ease:Back.easeIn, delay:myDelay+4, reflect:false, repeatCount:1, onComplete:handleComplete});
_itemToStageNumber++;
}
private function handleComplete(e:GTween):void {
trace("handleComplete");
_XMLLogoArray.push(e.target.getChildAt(0));
e.target.removeChild(e.target.getChildAt(0));
//trace("_XMLLogoArray.length = "+_XMLLogoArray.length);
//trace("e.target.name = "+e.target.name);
var i:Number = Math.floor(Math.random()*_XMLLogoArray.length);
var dispObj:DisplayObject = _XMLLogoArray[i];
_XMLLogoArray.splice(i, 1);
//trace("_XMLLogoArray.length = "+_XMLLogoArray.length);
e.target.addChild(dispObj);
e.target.x = -dispObj.width;
var myDelay:Number = Math.random()*3;
_tween = new GTween(e.target, 1.2, {x:(215-dispObj.width)/2}, {ease:Back.easeOut, delay:myDelay, reflect:false, repeatCount:1});
_tween = new GTween(e.target, 1.2, {x:215}, {ease:Back.easeIn, delay:myDelay+4, reflect:false, repeatCount:1, onComplete:handleComplete});
}
}
}
other recent galleries:
ActionScript 3.0: the Fransa Collection Flash with photos by Flemming Scully
ActionScript 3.0: using FIVe3D for a picture gallery
JavaScript: using jQuery for a picture gallery
other stuff made for MCH Messecenter Herning:
showcase: 2 simple banners for MCH Messecenter Herning
showcase: different stuff for MCH Messecenter Herning
Premiere: the documentary; Denmark at WorldSkills 2005, Helsinki
yesterday I found this DVD Christian Mortensen and I made back in 2005.
we went 10 days to Helsinki and filmed the danish participation in WorldSkills 2005.
we had a wonderful time, and when we came home, we made this documentary, that later was bought by the danish company DKSkills and reproduced to certain levels of the danish ministry of education.

the documentary can been seen in 3 parts here:
Part 1 of the documentary, WorldSkills 2005, made in Premiere
Part 2 of the documentary, WorldSkills 2005, made in Premiere
Part 3 of the documentary, WorldSkills 2005, made in Premiere
the documentary is mainly in danish, but parts of english and swedish also appear.
enjoy.
interested in other video-projects, be sure to check out:
the laid back jazz video project
an acoustic version of Map of your mind, by Muse
tracking progress of a video with Google Analytics
girl just screaming her lungs out
credits:
co-partner in video-crime Christian Mortensen