Created
May 25, 2013 23:08
-
-
Save edom18/5651095 to your computer and use it in GitHub Desktop.
CSS ShaderでMax OSXのジニーエフェクト
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
#CSS ShaderでMac OSXのジニーエフェクトを実装してみる | |
「-」ボタンを押すことでジニーエフェクトが実行されます。 | |
Shiftキーと同時押しで、Mac同様スローモーションになるようにしてみました。 | |
ただ、とりあえず動きだけそれっぽくしてるので、 | |
アニメーション管理とかだいぶ適当ですw | |
でもShader部分はすごいシンプルなので、 | |
改めてCSS Shaderのすごさを思い知った。 |
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
* { | |
margin: 0; | |
padding: 0; | |
border: 0; | |
} | |
body { | |
background: #111 url(http://jsrun.it/assets/u/C/Y/Y/uCYYj.jpg) center top no-repeat; | |
background-size: 100% 100%; | |
} | |
html, body { | |
width: 100%; | |
height: 100%; | |
} | |
img { | |
vertical-align: top; | |
} | |
.ginny-effect { | |
position: absolute; | |
width: 600px; | |
height: 400px; | |
overflow: hidden; | |
} | |
.ginny-effect .ginny-effect-inner { | |
position: absolute; | |
top: 0; | |
} | |
.window { | |
position: absolute; | |
background: -webkit-linear-gradient(rgba(233, 233, 233, 1.0), rgba(178, 178, 178, 1.0) 21px, #EDEDED, #EDEDED 23px); | |
border-radius: 5px; | |
box-shadow: inset 0 1px 0 rgba(255,255,255,.6), 0 22px 70px 4px rgba(0,0,0,0.56), 0 0 0 1px rgba(0, 0, 0, 0.3); | |
text-align: left; | |
position: absolute; | |
z-index: 0; | |
} | |
.container { | |
border-top: 1px solid #656565; | |
} | |
.control-window { | |
position: absolute; | |
left: 5px; | |
top: 3px; | |
z-index: 10; | |
height: 19px; | |
} | |
.titleInside { | |
position: relative; | |
z-index: 2; | |
color: #3c3c3c; | |
font-size: 13px; | |
line-height: 21px; | |
text-decoration: none; | |
text-shadow: 0 1px 1px #e7e7e7; | |
text-align: center; | |
text-transform: capitalize; | |
} | |
nav.control-window a { | |
display: inline-block; | |
margin: 2px 0px 3px 1px; | |
width: 12px; | |
height: 12px; | |
border-radius: 100%; | |
box-shadow: 0px 1px 0px rgba(255,255,255,.5); | |
text-indent: -9999px; | |
position: relative; | |
} | |
nav.control-window a.close { | |
background: #FD4E4E; | |
} | |
nav.control-window a.minimize { | |
background: #F3BB55; | |
} | |
nav.control-window a.maximize { | |
background: #96D16F; | |
} | |
nav.control-window a:before { | |
content: ''; | |
display: block; | |
position: absolute; | |
border-radius: 100%; | |
box-shadow: inset 0 1px 4px rgba(0, 0, 0, .8); | |
top: 0px; | |
left: 0px; | |
bottom: 0px; | |
right: 0px; | |
} | |
nav.control-window a:after { | |
content: ''; | |
display: block; | |
position: absolute; | |
top: 2px; | |
left: 1px; | |
bottom: 1px; | |
right: 1px; | |
border-radius: 100%; | |
background: -webkit-linear-gradient(white, rgba(255, 255, 255, .9) 2%, white, rgba(255, 255, 255, .4) 16%, rgba(255, 255, 255, 0) 43%, rgba(255, 255, 255, .74), rgba(255, 255, 255, .7) 122%, rgba(255, 255, 255, .7)); | |
box-shadow: inset 0px -3px -5px 3px rgba(255, 255, 255, 0.2), inset 0px 2px -5px 3px rgba(255, 255, 255, 0.2); | |
} | |
nav.control-window:hover a.close { | |
background: #FD4E4E url(http://jsrun.it/assets/f/2/V/P/f2VPE.png) 1px 1px no-repeat; | |
} | |
nav.control-window:hover a.minimize { | |
background: #F3BB55 url(http://jsrun.it/assets/f/2/V/P/f2VPE.png) -9px 1px no-repeat; | |
} | |
nav.control-window:hover a.maximize { | |
background: #96D16F url(http://jsrun.it/assets/f/2/V/P/f2VPE.png) -19px 1px no-repeat; | |
} |
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
<script id="vs" type="x-shader/x-vertex-shader"> | |
//Vertex shader source. | |
//float型を中精度をデフォルトに | |
precision mediump float; | |
//CSSから渡される頂点情報 ([-0.5, 0.5]の範囲) | |
attribute vec4 a_position; | |
//CSSから渡されるテクスチャ(DOM)の座標 ([0.0, 1.0]の範囲) | |
attribute vec2 a_texCoord; | |
//CSSから渡される現在計算中のメッシュ座標 ([0.0, 1.0]の範囲) | |
attribute vec2 a_meshCoord; //今回は未使用 | |
//CSSから渡される透視投影変換行列 | |
uniform mat4 u_projectionMatrix; | |
//CSSから「渡す」任意の値 | |
uniform float u_time; | |
//CSSから渡されるテクスチャサイズ(DOM) | |
uniform vec2 u_textureSize; //今回は未使用 | |
//各種const値 | |
const float PI = 3.1415; | |
void main() { | |
//a_texCoord.yを元に、下に行くほど中心(つまり0)に近付くよう計算 | |
float s = sin((1.0 - a_texCoord.y * u_time) * PI * 0.5); | |
//3乗して変化を顕著化 | |
s = pow(s, 3.0); | |
//頂点位置のx座標位置を、上記で計算した数値を掛けて変形 | |
float x = a_position.x * s; | |
vec4 pos = a_position; | |
pos.x = x; | |
//上記で計算した新しい座標「pos」を適用 | |
gl_Position = u_projectionMatrix * pos; | |
} | |
</script> | |
<script id="fs" type="x-shader/x-fragment-shader"> | |
precision mediump float; | |
const float one = 1.0; | |
void main() { | |
//ここいらないかも。 | |
css_MixColor = vec4(one, one, one, one); | |
} | |
</script> | |
<div class="ginny-effect" style="z-index: 3; bottom: 30px; left: 30px;"> | |
<div class="ginny-effect-inner"> | |
<div class="window share ui-draggable windows-vis"> | |
<nav class="control-window"> | |
<a href="#" class="close">close</a> | |
<a href="#" class="minimize">minimize</a> | |
<a href="#" class="maximize">maximize</a> | |
</nav> | |
<h1 class="titleInside">Ginny-effect sample</h1> | |
<div class="container"> | |
<div class="container-inside"> | |
<p><img src="http://placekitten.com/600/400" width="600" height="400" /></p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> |
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
(function(win, doc) { | |
'use strict'; | |
var ginny_effect; | |
function getSource(id) { | |
var blob, target, text, url; | |
target = doc.getElementById(id); | |
text = target.innerHTML; | |
blob = new Blob([text]); | |
url = webkitURL.createObjectURL(blob); | |
return url; | |
} | |
function easing(a, b, x) { | |
var f = (1.0 - Math.cos(x * Math.PI)) * 0.5; | |
return a * (1.0 - f) + f * b; | |
} | |
function GinnyEffect(el) { | |
this.el = el; | |
this.innerEl = this.el.querySelector('*'); | |
this.style = el.style; | |
this.vsUrl = getSource('vs'); | |
this.fsUrl = getSource('fs'); | |
this.meshSize = 20; | |
this.time = 0.0; | |
this.shown = true; | |
this.updateStyle(); | |
} | |
GinnyEffect.prototype = { | |
speed: 0.042, | |
constructor: GinnyEffect, | |
updateStyle: function () { | |
this.style.webkitFilter = "custom(url(" + this.vsUrl + ") mix(url(" + this.fsUrl + ") multiply source-atop), " + this.meshSize + " " + this.meshSize + ", u_time " + this.time + ")"; | |
}, | |
updateStyle2: function (val) { | |
this.innerEl.style.top = val + '%'; | |
}, | |
start: function (sp) { | |
sp && (this.speed = sp); | |
this._start1(); | |
}, | |
_start1: function () { | |
var that = this; | |
var t = 0.0; | |
var sp = this.speed; | |
(function loop() { | |
var val = easing(0, 1, t); | |
that.time = val; | |
that.updateStyle(); | |
t += sp; | |
if (t > 1.0) { | |
that._start2(); | |
return; | |
} | |
setTimeout(loop, 16); | |
}()); | |
}, | |
_start2: function () { | |
var that = this; | |
var t = 0.0; | |
var sp = this.speed; | |
(function loop() { | |
var val = easing(0, 100, t); | |
that.updateStyle2(val); | |
t += sp; | |
if (t > 1.0) { | |
return; | |
} | |
setTimeout(loop, 16); | |
}()); | |
} | |
}; | |
ginny_effect = new GinnyEffect(doc.querySelector('.ginny-effect')); | |
win.ginny_effect = ginny_effect; | |
doc.querySelector('.minimize').addEventListener('click', function (e) { | |
if (e.shiftKey) { | |
ginny_effect.start(0.0042); | |
e.preventDefault(); | |
return false; | |
} | |
ginny_effect.start(); | |
}, false); | |
})(window, window.document); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment