Skip to content

Instantly share code, notes, and snippets.

@edom18
Created May 25, 2013 23:08
Show Gist options
  • Save edom18/5651095 to your computer and use it in GitHub Desktop.
Save edom18/5651095 to your computer and use it in GitHub Desktop.
CSS ShaderでMax OSXのジニーエフェクト
#CSS ShaderでMac OSXのジニーエフェクトを実装してみる
「-」ボタンを押すことでジニーエフェクトが実行されます。
Shiftキーと同時押しで、Mac同様スローモーションになるようにしてみました。
ただ、とりあえず動きだけそれっぽくしてるので、
アニメーション管理とかだいぶ適当ですw
でもShader部分はすごいシンプルなので、
改めてCSS Shaderのすごさを思い知った。
* {
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;
}
<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>
(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