My self portrait consists of a series of videos, which together compose an image of my head, that collectively follow the cursor as it moves left and right across the window. In order to achieve this, I first recorded a video of myself turning from one profile position to the other. The video lasts about 25 seconds. After recording I split the video vertically into 10 even pieces and added them to the DOM as 10 separate <video> elements. Then I used js to map the length of the video in seconds to the width of the window in pixels, and had the video fast-forward or rewind to the time that corresponds to the current mouse position, every time mouse movement is detected.
I split the portrait into several pieces so that I could play around with the variables that determine the number of frames and the time each video transition would take to fast-forward/rewind from one point to another. I like the resulting jumpy effect and the way my face gets abstracted at certain moments and then slowly pieces back together.
The html/css…
<html>
<head>
<script type="text/javascript" src="main.js"></script>
</head>
<body>
<br>
<br>
<div id="2">
<video id="vid11" src="vid/Comp7_1.mp4" width="9%" height="100%" loop></video>
<video id="vid12" src="vid/Comp7_2.mp4" width="9%" height="100%" loop></video>
<video id="vid13" src="vid/Comp7_3.mp4" width="9%" height="100%" loop></video>
<video id="vid14" src="vid/Comp7_4.mp4" width="9%" height="100%" loop></video>
<video id="vid15" src="vid/Comp7_5.mp4" width="9%" height="100%" loop></video>
<video id="vid16" src="vid/Comp7_6.mp4" width="9%" height="100%" loop></video>
<video id="vid17" src="vid/Comp7_7.mp4" width="9%" height="100%" loop></video>
<video id="vid18" src="vid/Comp7_8.mp4" width="9%" height="100%" loop></video>
<video id="vid19" src="vid/Comp7_9.mp4" width="9%" height="100%" loop></video>
<video id="vid20" src="vid/Comp7_10.mp4" width="9%" height="100%" loop></video>
</div>
</body>
<style>
video {
object-fit: fill;
}
#2 video{
display:inline;
position:relative;
float:left;
}
#2{
height:800px;
}
</style>
</html>
…and the JS.
//src:
//[1] https://stackoverflow.com/a/7790764 - capturing mouse pos
//[2] https://stackoverflow.com/a/10756409 - range conversion
//[3] https://stackoverflow.com/a/36731430 - FF/RW video to given time
function init() { //all js that needs to happen after page has loaded
document.onmousemove = handleMouseMove; //[1]
function handleMouseMove(event) {
var dot, eventDoc, doc, body, pageX, pageY;
event = event || window.event; //IE
// If pageX/Y aren't available and clientX/Y are,
// calculate pageX/Y - logic taken from jQuery.
// (For old IE)
if (event.pageX == null && event.clientX != null) {
eventDoc = (event.target && event.target.ownerDocument) || document;
doc = eventDoc.documentElement;
body = eventDoc.body;
event.pageX = event.clientX +
(doc && doc.scrollLeft || body && body.scrollLeft || 0) -
(doc && doc.clientLeft || body && body.clientLeft || 0);
event.pageY = event.clientY +
(doc && doc.scrollTop || body && body.scrollTop || 0) -
(doc && doc.clientTop || body && body.clientTop || 0);
}
// console.log(event.pageX);
var width, vid_length_s, vid_timeToSkipTo;
// width = screen.width;
width = window.innerWidth;
vid_length = 25;
vid_timeToSkipTo = convertToRange(event.pageX, [0, width], [0, vid_length]);
console.log(vid_timeToSkipTo);
goToTime(Math.floor(vid_timeToSkipTo));
}
}
window.addEventListener('load', init);
function convertToRange(value, srcRange, dstRange) { //[2]
// value is outside source range return
if (value < srcRange[0] || value > srcRange[1]) {
return NaN;
}
var srcMax = srcRange[1] - srcRange[0],
dstMax = dstRange[1] - dstRange[0],
adjValue = value - srcRange[0];
return (adjValue * dstMax / srcMax) + dstRange[0];
}
function goToTime(time) { //[3]
var vid11 = document.getElementById('vid11'),
ticks11 = 10, // number of frames during fast-forward
frms11 = 100, // number of milliseconds between frames in fast-forward/rewind
endtime11 = time; // time to fast-forward/rewind to (in seconds)
// fast-forward/rewind video to end time
var tdelta11 = (endtime11 - vid11.currentTime) / ticks11;
var startTime11 = vid11.currentTime;
for (let i = 0; i < ticks11; ++i) {
(function(j) {
setTimeout(function() {
vid11.currentTime = startTime11 + tdelta11 * j;
}, j * frms11);
})(i);
}
var vid12 = document.getElementById('vid12'),
ticks12 = 10, // number of frames during fast-forward
frms12 = 150, // number of milliseconds between frames in fast-forward/rewind
endtime12 = time; // time to fast-forward/rewind to (in seconds)
// fast-forward/rewind video to end time
var tdelta12 = (endtime12 - vid12.currentTime) / ticks12;
var startTime12 = vid12.currentTime;
for (let i = 0; i < ticks12; ++i) {
(function(j) {
setTimeout(function() {
vid12.currentTime = startTime12 + tdelta12 * j;
}, j * frms12);
})(i);
}
var vid13 = document.getElementById('vid13'),
ticks13 = 10, // number of frames during fast-forward
frms13 = 200, // number of milliseconds between frames in fast-forward/rewind
endtime13 = time; // time to fast-forward/rewind to (in seconds)
// fast-forward/rewind video to end time
var tdelta13 = (endtime13 - vid13.currentTime) / ticks13;
var startTime13 = vid13.currentTime;
for (let i = 0; i < ticks13; ++i) {
(function(j) {
setTimeout(function() {
vid13.currentTime = startTime13 + tdelta13 * j;
}, j * frms13);
})(i);
}
var vid14 = document.getElementById('vid14'),
ticks14 = 10, // number of frames during fast-forward
frms14 = 250, // number of milliseconds between frames in fast-forward/rewind
endtime14 = time; // time to fast-forward/rewind to (in seconds)
// fast-forward/rewind video to end time
var tdelta14 = (endtime14 - vid14.currentTime) / ticks14;
var startTime14 = vid14.currentTime;
for (let i = 0; i < ticks14; ++i) {
(function(j) {
setTimeout(function() {
vid14.currentTime = startTime14 + tdelta14 * j;
}, j * frms14);
})(i);
}
var vid15 = document.getElementById('vid15'),
ticks15 = 10, // number of frames during fast-forward
frms15 = 300, // number of milliseconds between frames in fast-forward/rewind
endtime15 = time; // time to fast-forward/rewind to (in seconds)
// fast-forward/rewind video to end time
var tdelta15 = (endtime15 - vid15.currentTime) / ticks15;
var startTime15 = vid15.currentTime;
for (let i = 0; i < ticks15; ++i) {
(function(j) {
setTimeout(function() {
vid15.currentTime = startTime15 + tdelta15 * j;
}, j * frms15);
})(i);
}
var vid16 = document.getElementById('vid16'),
ticks16 = 10, // number of frames during fast-forward
frms16 = 350, // number of milliseconds between frames in fast-forward/rewind
endtime16 = time; // time to fast-forward/rewind to (in seconds)
// fast-forward/rewind video to end time
var tdelta16 = (endtime16 - vid16.currentTime) / ticks16;
var startTime16 = vid16.currentTime;
for (let i = 0; i < ticks16; ++i) {
(function(j) {
setTimeout(function() {
vid16.currentTime = startTime16 + tdelta16 * j;
}, j * frms16);
})(i);
}
var vid17 = document.getElementById('vid17'),
ticks17 = 10, // number of frames during fast-forward
frms17 = 300, // number of milliseconds between frames in fast-forward/rewind
endtime17 = time; // time to fast-forward/rewind to (in seconds)
// fast-forward/rewind video to end time
var tdelta17 = (endtime17 - vid17.currentTime) / ticks17;
var startTime17 = vid17.currentTime;
for (let i = 0; i < ticks17; ++i) {
(function(j) {
setTimeout(function() {
vid17.currentTime = startTime17 + tdelta17 * j;
}, j * frms17);
})(i);
}
var vid18 = document.getElementById('vid18'),
ticks18 = 10, // number of frames during fast-forward
frms18 = 250, // number of milliseconds between frames in fast-forward/rewind
endtime18 = time; // time to fast-forward/rewind to (in seconds)
// fast-forward/rewind video to end time
var tdelta18 = (endtime18 - vid18.currentTime) / ticks18;
var startTime18 = vid18.currentTime;
for (let i = 0; i < ticks18; ++i) {
(function(j) {
setTimeout(function() {
vid18.currentTime = startTime18 + tdelta18 * j;
}, j * frms18);
})(i);
}
var vid19 = document.getElementById('vid19'),
ticks19 = 10, // number of frames during fast-forward
frms19 = 200, // number of milliseconds between frames in fast-forward/rewind
endtime19 = time; // time to fast-forward/rewind to (in seconds)
// fast-forward/rewind video to end time
var tdelta19 = (endtime19 - vid19.currentTime) / ticks19;
var startTime19 = vid19.currentTime;
for (let i = 0; i < ticks19; ++i) {
(function(j) {
setTimeout(function() {
vid19.currentTime = startTime19 + tdelta19 * j;
}, j * frms19);
})(i);
}
var vid20 = document.getElementById('vid20'),
ticks20 = 10, // number of frames during fast-forward
frms20 = 150, // number of milliseconds between frames in fast-forward/rewind
endtime20 = time; // time to fast-forward/rewind to (in seconds)
// fast-forward/rewind video to end time
var tdelta20 = (endtime20 - vid20.currentTime) / ticks20;
var startTime20 = vid20.currentTime;
for (let i = 0; i < ticks20; ++i) {
(function(j) {
setTimeout(function() {
vid20.currentTime = startTime20 + tdelta20 * j;
}, j * frms20);
})(i);
}
}
The code is pretty sloppy and could probably be optimized a lot if given more time. The videos perform horribly on Firefox and Chrome, while working fine in Safari. In general, playing 10 videos at once obviously causes average-performing computers to increase in temperature at an unacceptable rate and would probably eventually cause the browser to crash. Instead, there is probably a way for one video file to be used that can be duplicated and cropped as necessary.