-
Notifications
You must be signed in to change notification settings - Fork 182
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow resetting the Konami Code effects for Paint
- Loading branch information
Showing
1 changed file
with
187 additions
and
149 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,171 +1,209 @@ | ||
(function () { | ||
var rAF_ID, rotologo, $window, space_phase_key_handler, player; | ||
var vaporwave_active = false; | ||
|
||
// TODO: make this whole thing work multiple times | ||
// (and allow reseting the effect entirely by re-entering the Konami Code) | ||
|
||
var start_movie = function () { | ||
|
||
var rotologo = document.createElement("img"); | ||
rotologo.classList.add("rotologo"); | ||
if (frameElement) { | ||
frameElement.parentElement.appendChild(rotologo); | ||
rotologo.src = "images/logo/98.js.org.svg"; | ||
if (parent && frameElement && parent.$) { | ||
$window = parent.$(frameElement).closest(".window"); | ||
} else { | ||
document.body.appendChild(rotologo); | ||
rotologo.src = "images/98.js.org.svg"; | ||
$window = $(); | ||
} | ||
|
||
$(rotologo).css({ | ||
position: "absolute", | ||
left: "50%", | ||
top: "50%", | ||
pointerEvents: "none", | ||
transformOrigin: "0% 0%", | ||
transition: "opacity 1s ease", | ||
opacity: "0", | ||
}); | ||
|
||
var animate = function () { | ||
var rAF_ID = requestAnimationFrame(animate); | ||
// cleanup = function(){ | ||
// cancelAnimationFrame(rAF_ID); | ||
// }; | ||
var wait_for_youtube_api = function (callback) { | ||
if (typeof YT !== "undefined") { | ||
callback(); | ||
} else { | ||
var tag = document.createElement('script'); | ||
tag.src = "https://www.youtube.com/player_api"; | ||
var firstScriptTag = document.getElementsByTagName('script')[0]; | ||
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); | ||
|
||
// The YouTube API will call this global function when loaded and ready. | ||
window.onYouTubeIframeAPIReady = function () { | ||
callback(); | ||
}; | ||
} | ||
}; | ||
|
||
var stop_vaporwave = function () { | ||
vaporwave_active = false; | ||
|
||
cancelAnimationFrame(rAF_ID); | ||
|
||
$(rotologo).remove(); | ||
$window.css({transform: ""}); | ||
|
||
removeEventListener("keydown", space_phase_key_handler); | ||
if (player) { | ||
player.destroy(); | ||
player = null; | ||
} | ||
// vaporwave is dead. long live vaporwave. | ||
// bepis pepsi isded pepsi isded | ||
}; | ||
|
||
var start_vaporwave = function () { | ||
vaporwave_active = true; | ||
|
||
rotologo = document.createElement("img"); | ||
rotologo.classList.add("rotologo"); | ||
if (frameElement) { | ||
frameElement.parentElement.appendChild(rotologo); | ||
rotologo.src = "images/logo/98.js.org.svg"; | ||
} else { | ||
document.body.appendChild(rotologo); | ||
rotologo.src = "images/98.js.org.svg"; | ||
} | ||
|
||
$(rotologo).css({ | ||
transform: | ||
`perspective(4000px) rotateY(${ | ||
Math.sin(Date.now() / 5000) | ||
}turn) rotateX(${ | ||
0 | ||
}turn) translate(-50%, -50%) translateZ(500px)`, | ||
filter: | ||
`hue-rotate(${ | ||
Math.sin(Date.now() / 4000) | ||
// TODO: slow down and stop when you pause | ||
}turn)`, | ||
position: "absolute", | ||
left: "50%", | ||
top: "50%", | ||
pointerEvents: "none", | ||
transformOrigin: "0% 0%", | ||
transition: "opacity 1s ease", | ||
opacity: "0", | ||
}); | ||
|
||
var $window = parent.$(frameElement).closest(".window"); | ||
if($window.length){ | ||
var el = $window[0]; | ||
var offsetLeft = 0; | ||
var offsetTop = 0; | ||
do { | ||
offsetLeft += el.offsetLeft; | ||
offsetTop += el.offsetTop; | ||
el = el.offsetParent; | ||
} while (el); | ||
|
||
$window.css({ | ||
|
||
var animate = function () { | ||
rAF_ID = requestAnimationFrame(animate); | ||
|
||
$(rotologo).css({ | ||
transform: | ||
`perspective(4000px) rotateY(${ | ||
-(offsetLeft + ($window.outerWidth() - parent.innerWidth) / 2) / parent.innerWidth / 3 | ||
Math.sin(Date.now() / 5000) | ||
}turn) rotateX(${ | ||
(offsetTop + ($window.outerHeight() - parent.innerHeight) / 2) / parent.innerHeight / 3 | ||
0 | ||
}turn) translate(-50%, -50%) translateZ(500px)`, | ||
filter: | ||
`hue-rotate(${ | ||
Math.sin(Date.now() / 4000) | ||
// TODO: slow down and stop when you pause | ||
}turn)`, | ||
transformOrigin: "50% 50%", | ||
transformStyle: "preserve-3d", | ||
// FIXME: interactivity problems (with order elements are considered to have), I think related to preserve-3d | ||
}); | ||
} | ||
}; | ||
animate(); | ||
|
||
var tag = document.createElement('script'); | ||
tag.src = "https://www.youtube.com/player_api"; | ||
var firstScriptTag = document.getElementsByTagName('script')[0]; | ||
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); | ||
|
||
var player; | ||
var player_placeholder = document.createElement("div"); | ||
document.querySelector(".canvas-area").appendChild(player_placeholder); | ||
$(player_placeholder).css({ | ||
position: "absolute", | ||
top: "3px", // TODO: dynamic | ||
left: "3px", | ||
mixBlendMode: "multiply", | ||
pointerEvents: "none", | ||
transition: "opacity 0.4s ease", | ||
width: "100vw", | ||
height: "100vh", | ||
}); | ||
// NOTE: placeholder not a container; the YT API replaces the element passed in the DOM | ||
// but keeps inline styles apparently, and maybe other things, I don't know; it's weird | ||
|
||
// The YouTube API will call this global function when loaded and ready. | ||
window.onYouTubeIframeAPIReady = function () { | ||
player = new YT.Player(player_placeholder, { | ||
height: "390", | ||
width: "640", | ||
videoId: "8TvcyPCgKSU", | ||
playerVars: { | ||
autoplay: 1, | ||
controls: 0, | ||
}, | ||
events: { | ||
onReady: onPlayerReady, | ||
onStateChange: onPlayerStateChange, | ||
}, | ||
|
||
if ($window.length) { | ||
var el = $window[0]; | ||
var offsetLeft = 0; | ||
var offsetTop = 0; | ||
do { | ||
offsetLeft += el.offsetLeft; | ||
offsetTop += el.offsetTop; | ||
el = el.offsetParent; | ||
} while (el); | ||
|
||
$window.css({ | ||
transform: | ||
`perspective(4000px) rotateY(${ | ||
-(offsetLeft + ($window.outerWidth() - parent.innerWidth) / 2) / parent.innerWidth / 3 | ||
}turn) rotateX(${ | ||
(offsetTop + ($window.outerHeight() - parent.innerHeight) / 2) / parent.innerHeight / 3 | ||
}turn)`, | ||
transformOrigin: "50% 50%", | ||
transformStyle: "preserve-3d", | ||
// FIXME: interactivity problems (with order elements are considered to have), I think related to preserve-3d | ||
}); | ||
} | ||
}; | ||
animate(); | ||
|
||
var player_placeholder = document.createElement("div"); | ||
document.querySelector(".canvas-area").appendChild(player_placeholder); | ||
$(player_placeholder).css({ | ||
position: "absolute", | ||
top: "3px", // TODO: dynamic | ||
left: "3px", | ||
mixBlendMode: "multiply", | ||
pointerEvents: "none", | ||
transition: "opacity 0.4s ease", | ||
width: "100vw", | ||
height: "100vh", | ||
}); | ||
// TODO: attribution for this video! | ||
// I mean, you can see the title if you hit spacebar, but | ||
// I could make it wave across the screen behind Paint on the desktop | ||
// I could add a "Song Name?" button that responds "Darude Sandstorm" | ||
// I could add a "Song At 420?" button that actually links to the video | ||
// some number of those things or something like that | ||
}; | ||
// NOTE: placeholder not a container; the YT API replaces the element passed in the DOM | ||
// but keeps inline styles apparently, and maybe other things, I don't know; it's weird | ||
|
||
// The API will call this function when the video player is ready. | ||
function onPlayerReady(event) { | ||
player.playVideo(); | ||
// TODO: unmute if muted? | ||
player.unMute(); | ||
} | ||
wait_for_youtube_api(function () { | ||
player = new YT.Player(player_placeholder, { | ||
height: "390", | ||
width: "640", | ||
videoId: "8TvcyPCgKSU", | ||
playerVars: { | ||
autoplay: 1, | ||
controls: 0, | ||
}, | ||
events: { | ||
onReady: onPlayerReady, | ||
onStateChange: onPlayerStateChange, | ||
}, | ||
}); | ||
// TODO: attribution for this video! | ||
// I mean, you can see the title if you hit spacebar, but | ||
// I could make it wave across the screen behind Paint on the desktop | ||
// I could add a "Song Name?" button that responds "Darude Sandstorm" | ||
// I could add a "Song At 420?" button that actually links to the video | ||
// some number of those things or something like that | ||
}); | ||
|
||
// The API calls this function when the player's state changes. | ||
function onPlayerStateChange(event) { | ||
if (event.data == YT.PlayerState.PLAYING) { | ||
// TODO: pause and resume this timer with the video | ||
setTimeout(function(){ | ||
$(rotologo).css({opacity: 1}); | ||
}, 14150); | ||
// The API will call this function when the video player is ready. | ||
function onPlayerReady(event) { | ||
player.playVideo(); | ||
player.unMute(); | ||
} | ||
if (event.data == YT.PlayerState.ENDED) { | ||
player.destroy(); | ||
// TODO: fade to white instead of black, to work with the multiply effect | ||
// or fade out opacity alternatively | ||
// setTimeout/setInterval and check player.getCurrentTime() for when near the end? | ||
// or we might switch to using soundcloud for the audio and so trigger it with that, with a separate video of just clouds | ||
// also fade out the rotologo earlier | ||
$(rotologo).css({opacity: 0}); | ||
// TODO: destroy rotologo once faded out | ||
|
||
// The API calls this function when the player's state changes. | ||
function onPlayerStateChange(event) { | ||
if (event.data == YT.PlayerState.PLAYING) { | ||
// TODO: pause and resume this timer with the video | ||
setTimeout(function(){ | ||
$(rotologo).css({opacity: 1}); | ||
}, 14150); | ||
} | ||
if (event.data == YT.PlayerState.ENDED) { | ||
player.destroy(); | ||
player = null; | ||
// TODO: fade to white instead of black, to work with the multiply effect | ||
// or fade out opacity alternatively | ||
// setTimeout/setInterval and check player.getCurrentTime() for when near the end? | ||
// or we might switch to using soundcloud for the audio and so trigger it with that, with a separate video of just clouds | ||
// also fade out the rotologo earlier | ||
$(rotologo).css({opacity: 0}); | ||
// destroy rotologo once faded out | ||
setTimeout(stop_vaporwave, 1200); | ||
} | ||
} | ||
} | ||
function stopVideo() { | ||
player.stopVideo(); | ||
} | ||
|
||
var is_theoretically_playing = true; | ||
var space_phase_key_handler = function (e) { | ||
if (e.which === 32) { | ||
// TODO: record player SFX | ||
if (is_theoretically_playing) { | ||
player.pauseVideo(); | ||
is_theoretically_playing = false; | ||
$(player.getIframe()) | ||
.add(rotologo) | ||
.css({opacity: "0"}); | ||
} else { | ||
player.playVideo(); | ||
is_theoretically_playing = true; | ||
$(player.getIframe()) | ||
.add(rotologo) | ||
.css({opacity: ""}); | ||
var is_theoretically_playing = true; | ||
space_phase_key_handler = function (e) { | ||
// press space to phase in and out of space phase スペース相 - windows 98 マイクロソフト 『WINTRAP』 X 将来のオペレーティングシステムサウンド 1998 VAPORWAVE | ||
if (e.which === 32) { | ||
// TODO: record player SFX | ||
if (is_theoretically_playing) { | ||
player.pauseVideo(); | ||
is_theoretically_playing = false; | ||
$(player.getIframe()) | ||
.add(rotologo) | ||
.css({opacity: "0"}); | ||
} else { | ||
player.playVideo(); | ||
is_theoretically_playing = true; | ||
$(player.getIframe()) | ||
.add(rotologo) | ||
.css({opacity: ""}); | ||
} | ||
e.preventDefault(); | ||
// player.getIframe().focus(); | ||
} | ||
e.preventDefault(); | ||
// player.getIframe().focus(); | ||
}; | ||
addEventListener("keydown", space_phase_key_handler); | ||
}; | ||
|
||
var toggle_vaporwave = function () { | ||
if (vaporwave_active) { | ||
stop_vaporwave(); | ||
} else { | ||
start_vaporwave(); | ||
} | ||
}; | ||
addEventListener("keydown", space_phase_key_handler); | ||
}; | ||
|
||
addEventListener("keydown", Konami.code(start_movie)); | ||
addEventListener("keydown", Konami.code(toggle_vaporwave)); | ||
|
||
}()); |