<body>
<div id="origin"></div>
<form id="mtxform" name="mtxform">
<div>
<button id="play" type="button" onclick="mtx.show();">Play Your Own</button>
<br/>
<span id="inputext" class="hidden">
<textarea rows="100" cols="100" id="text" name="text">
"The Computer Programmer Is
A Creator Of Universes For Which
(S)He Alone Is The Lawgiver.
No Playwright,
No Stage Director,
No Emperor
- However Powerful -
Has Ever Exercised Such Absolute
Authority To Arrange A Stage,
Or Field Of Battle, And To Command
Such Unswervingly Dutiful Actors Or Troops."
-Joseph Weizenbaum
</textarea>
<br/>
<button type="button" class='playMine' onclick="mtx.changeText();">Play</button>
</span>
</div>
</body>
@import url(https://fonts.googleapis.com/css?family=Cinzel:700);
html {
overflow: hidden;
}
body {
background:rgba(236, 240, 241,1.0);
font-family: 'Cinzel', serif;
width: 100%;
height: 100%;
user-select:none;
user-select:none;
user-select:none;
}
#origin {
position: absolute;
height: 100vh;
width: 100vw;
left:12vw;
font-size: 2.5vw;
font-family: 'Cinzel', serif;
overflow: hidden;
border: none;
color: #FFF;
letter-spacing:3px;
text-shadow:1px 1px hsla(0,0%,0%,0.4),
2px 1px hsla(0,0%,0%,0.3),
3px 1px hsla(0,0%,0%,0.2);
}
#origin span {
position: relative;
z-index: 1;
}
#mtxform {
position: relative;
z-index: 10;
color:#000;
}
.hidden {
visibility: hidden;
}
#play{
width:10em;
height:3em;
border:none;
background:#fff;
font-size:1.5em;
font-weight:boldl
box-shadow:1px 1px 1px 1px hsla(0,0%,0%,0.2);
box-shadow:1px 1px 1px 1px hsla(0,0%,0%,0.2);
outline:none;
}
.playMine{
display:inline-block;
width:13vw;
height:auto;
border:none;
padding:.5em;
background:#fff;
font-size:1.5em;
font-weight:bold;
box-shadow:1px 1px 1px 1px hsla(0,0%,0%,0.05);
box-shadow:1px 1px 1px 1px hsla(0,0%,0%,0.05);
outline:none;
}
textarea{
background:rgba(149, 165, 166,.5);
border:none;
color:rgba(52, 73, 94,1.0);
box-shadow:1px 1px 1px 1px hsla(0,0%,0%,0.05);
box-shadow:1px 1px 1px 1px hsla(0,0%,0%,0.05);
height:20vh;
width:15vw;
outline:none;
cursor:grab;
}
::scrollbar {
width: 12px;
}
::scrollbar-track {
box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
border-radius: 2px;
}
::scrollbar-thumb {
border-radius: 2px;
box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
}
/*original author: Gerard Ferrandez - [Ge1doot]
http://www.dhteumeuleu.com
I manipulated the script a little bit to allow the option of playing your own text snippet && have the colors of the letters change to red when being reused from the previous line to form the new line, and lime when dropped from previous line.
*/
var mtx = function () {
/* ==== private variables & methods ==== */
var stop = false;
var origin, lineDelay, charDelay;
var colorText, colorMatch, colorGhost, elapsedTime;
var lineIndex = 0;
var lineChar = [];
var animStack = [];
var colorStack = [];
/* ==== rgb color ==== */
function colorRGB (c) {
return 'rgb('
+Math.round(Math.min(225, Math.max(0, c[0])))+','
+Math.round(Math.min(255, Math.max(0, c[1])))+','
+Math.round(Math.min(120, Math.max(0, c[2])))+')';
}
/* ==== Easing functions ==== */
function Ease () {}
Ease.prototype = {
ease : function () {
this.m += this.s;
this.x0 += (this.d * this.m * .0025);
if (this.m == 20) this.s = -1;
return this.x0;
},
init : function (x0, x1) {
this.m = 0;
this.s = 1;
this.d = x1 - x0;
this.x0 = x0;
}
}
/* ==== Load Lines ==== */
function loadLines () {
// read text from HTML form
text = document.forms.mtxform.text.value.split("\n");
// loop through all lines
for (var j = 0; j < text.length; j++) {
var t = text[j];
if (t) {
var n = t.length;
lineChar[j] = [];
// first pass: create characters capture RELATIVE offset coordinates
for (var i = 0; i < n; i++)
lineChar[j][i] = new Character(t.charAt(i), j);
// second pass: convert to absolute position
for (var i = 0, o; o = lineChar[j][i]; i++) {
if (o.c == "|") {
// remove spaces
lineChar[j].splice(i, 1);
origin.removeChild(o.o);
i--;
} else {
// convert to absolute position and render
o.o.style.position = "absolute";
o.moveHTML();
// push first line in animation stack
if (j == 0) pushAnim (o, charDelay * i);
}
}
}
}
}
/* ==== Character Constructor ==== */
function Character (c, line) {
if (c == " ") c = "|";
this.c = c;
// create HTML element and append the the container
this.o = document.createElement("span");
this.o.innerHTML = c;
this.o.style.zIndex = 2;
origin.appendChild(this.o);
// capture relative offset positions !
this.x0 = this.o.offsetLeft;
this.y0 = -this.o.offsetHeight * 1.5;
this.x1 = this.x0;
this.x2 = this.x0;
this.y1 = (line + 1) * this.o.offsetHeight;
this.y2 = origin.offsetHeight;
this.mx = new Ease();
this.my = new Ease();
this.c0 = [colorText[0], colorText[1], colorText[2]];
}
/* ==== Character functions ==== */
Character.prototype = {
// ---- character animation ----
anim : function (i) {
// temporization
if (this.delay > 0) {
if (elapsedTime)
this.delay -= new Date().getTime() - elapsedTime;
} else {
// moving
this.x0 = this.mx.ease();
this.y0 = this.my.ease();
this.moveHTML();
if (!this.my.m && !this.mx.m) {
// remove from stack
animStack.splice(i, 1);
// remove dead characters
if (this.off) origin.removeChild(this.o);
}
}
},
// ----- color fading ------
color : function (i) {
this.c0[0] += this.cr[0];
this.c0[1] += this.cr[1];
this.c0[2] += this.cr[2];
this.ci++;
this.o.style.color = colorRGB(this.c0);
if (this.ci >= this.cs)
colorStack.splice(i, 1);
},
// ----- HTML positioning -----
moveHTML : function () {
this.o.style.left = Math.round(this.x0) + "px";
this.o.style.top = Math.round(this.y0) + "px";
},
// ----- init color fading ------
colorFade : function (c1, steps) {
this.cs = steps;
this.cr = [(c1[0] - this.c0[0]) / steps, (c1[1] - this.c0[1]) / steps, (c1[2] - this.c0[2]) / steps];
if (this.cr[0] != 0 || this.cr[1] != 0 || this.cr[2] != 0){
this.ci = 0;
colorStack.push (this);
}
}
}
/* ==== push character in the animation stack ==== */
function pushAnim (o, delay) {
// init ease
o.mx.init(o.x0, o.x1);
o.my.init(o.y0, o.y1);
o.delay = delay;
// push stack
animStack.push(o);
}
/* ==== next line ==== */
function nextLine () {
if (lineIndex < lineChar.length - 1) {
// display shadow text
for (var i = 0, o; o = lineChar[lineIndex][i]; i++) {
var s = o.o.cloneNode(true);
s.style.zIndex = 1;
s.style.color = colorRGB(colorGhost);
origin.appendChild(s);
}
// matching next line characters
for (var i = 0, t; t = lineChar[lineIndex + 1][i]; i++) {
for (var j = 0, o; o = lineChar[lineIndex][j]; j++) {
if (o.c == t.c) {
// colors
t.colorFade(colorMatch, o.match ? 1 : 20);
t.match = true;
// swap characters
t.x0 = o.x0;
t.y0 = o.y0;
t.moveHTML();
// remove redundant character
origin.removeChild(o.o);
lineChar[lineIndex].splice(j, 1);
break;
}
}
}
// take off redundant characters
for (var i = 0, o; o = lineChar[lineIndex][i]; i++) {
// set target position (off frame)
o.y1 = origin.offsetHeight;
o.off = true;
o.match = false;
o.colorFade (colorText, 20);
// push in animation stack
pushAnim (o, (lineDelay * .8) + charDelay * i);
}
}
// push next line in animation stack
lineIndex++;
if (lineIndex < lineChar.length) {
for (var i = 0, o; o = lineChar[lineIndex][i]; i++)
pushAnim (o, lineDelay + charDelay * i);
}
}
/* ==== main animation loop ==== */
function main() {
// characters
var n = animStack.length;
if (n) {
var i = n;
while (i--)
animStack[i].anim(i);
} else nextLine ();
// colors
var i = colorStack.length;
while (i--)
colorStack[i].color(i);
// get elapsed time and loop
elapsedTime = new Date().getTime();
setTimeout(main, 32);
}
/* //////////// ==== public methods ==== //////////// */
return {
/* ==== initialize script ==== */
init : function (cont, t1, t2, c1, c2, c3) {
// container
origin = document.getElementById(cont);
lineDelay = t1;
charDelay = t2;
colorText = c1;
colorMatch = c2;
colorGhost = c3;
loadLines();
main();
},
changeText : function () {
document.getElementById("play").className = "";
document.getElementById("inputext").className = "hidden";
lineChar = [];
animStack = [];
colorStack = [];
origin.innerHTML = "";
lineIndex = 0;
elapsedTime = 0;
loadLines();
origin.focus();
},
show : function () {
document.getElementById("play").className = "hidden";
document.getElementById("inputext").className = "";
document.getElementById("text").focus();
}
}
}();
/* ==== init text ==== */
onload = function () {
// mtx.init( el, linesDelay, charsDelay, cText, cMatch, cGhost);
mtx.init("origin", 1500, 150, [220,220,220], [220,40,40], [40,110,220]);
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.