光るボタンは好き。でも、ボタンも背景もカードも全部光っていると、どこを見ればいいのか分からなくなる。
そこで「ボタンを明るくしたぶん、周りが暗くなったらどうだろう」と考えて、作ってみました。名前は Charge the Room。長押しで周囲のネオンから光を集めて、離すと放電します。
満タンになると、ボタンだけ景気がいい。周りの看板はほぼ休業です。
Yabi Labsに新しく作ったUI Labの、最初の実験作品です。
まずは押してみる
中央の丸いボタンを3秒ほど長押しして、離してみてください。「動きを見る」でも1回だけ再生できます。
キーボードなら、Tabで中央のボタンに移動してSpaceを長押し。Enterは自動再生です。音は出ません。仕事中でも、周りの電気までは消えません。
光を増やすより、移動させる
仕組みの中心にあるのは、0〜1の値ひとつです。
let charge = 0;
chargeが0なら、周りの看板が明るい状態。1に近づくほど中央に光が集まり、周囲は暗くなります。画面下のROOMとCOREも、足すと常に100になるようにしました。
JavaScriptから渡すCSS変数は、こんな形です。実際の描画処理から抜き出しています。
root.style.setProperty("--charge", charge.toFixed(4));
root.style.setProperty("--ambient", (1 - charge).toFixed(4));
root.style.setProperty("--degrees", `${charge * 360}deg`);
ボタンの光量は--charge、周りの明るさは--ambient、円周のゲージは--degreesを見ています。別々にアニメーションを始めるより、ひとつの値を共有するほうが「光を持っていかれた」感じを合わせやすい。
ただし、これは物理シミュレーションではありません。画面上の電力メーターと明るさを連動させる、見た目のルールです。
真っ暗にはしない
周りの看板を完全に消すと、何が暗くなったのかも分かりにくい。そこで、最低限の輪郭は残しています。
.supply {
opacity: calc(.17 + var(--ambient) * .83);
}
満タンでも17%は残る計算。中央だけ明るい状態と、暗い看板の存在を両方見せたかったので、この加減にしました。
中央の円周はconic-gradientで塗り、真ん中をマスクしてリングにしています。発光はCSS、放電時に飛ぶ粒子と広がる輪はCanvasの担当です。
長押しは「離した場所」も考える
押し始めはpointerdown、離すときはpointerupで受け取ります。ここで入れたのがsetPointerCapture()です。
button.addEventListener("pointerdown", event => {
if (!event.isPrimary || event.button !== 0) return;
if (start(event.pointerId)) {
button.setPointerCapture(event.pointerId);
button.focus({ preventScroll: true });
}
});
指やマウスがボタンの外に移動しても、同じポインターのイベントをボタンで受け取れるようにします。押す場所は中央でも、離す場所まで中央とは限らないので。MDNの説明
操作が中断されたpointercancel、ウィンドウからフォーカスが外れたとき、タブが非表示になったときはリセット。戻ってきたら勝手に充電が終わっていた、という状態は避けています。
3秒は、フレーム数で数えない
蓄電はrequestAnimationFrameで更新します。1フレームごとに固定の量を足すと、画面の更新頻度によって満タンまでの時間が変わってしまうので、前回からの経過時間を使いました。
const dt = Math.min((now - previous) / 1000, .05);
charge = Math.min(1, charge + dt / 3);
通常の描画間隔なら約3秒で満タンです。長く処理が止まったときは、1回の更新を最大0.05秒ぶんに制限しています。そのため、極端に重い環境では3秒より長くかかります。requestAnimationFrameの時間の扱い
放電後、粒子が消えたら更新ループも止めます。何も操作していない間まで、ずっと描き続ける必要はありません。
派手にしたいけど、動きを減らす入口も置く
「動きを控えめに」を入れると、粒子と拡大する光を止めます。蓄電量、周囲の明るさ、操作結果の文章は残すので、何が起きたかは分かる状態です。
最初の設定にはOS側のprefers-reduced-motionを使っています。派手な版を作ることと、控えめに見られることは両立させたい。MDNの設定例
自分のサイトで使うなら
ソース一式をダウンロードできます。HTML・CSS・JavaScriptだけで、ライブラリやビルドは不要。展開してindex.htmlを開けば動きます。
色はCSSの--accent、蓄電時間はJSのdt / 3で調整できます。時間を変えるときは、自動再生側の待ち時間も合わせて変更してください。詳しくは同梱のREADMEに書いています。
MIT Licenseで公開します。商用利用・改変可。配布するコードには、同梱の著作権表示と許諾文を残してください。
普通の送信ボタンに毎回3秒の長押しを求めるのは、ちょっと待たせすぎ。ゲームのチャージ操作や、作品サイトの起動演出あたりなら、この大げささを楽しめそうです。今回のソースには送信処理は入れていません。
まずは、光を借りて返すところまで。UI Labには、こういう「使いどころを考える前に、触ってみたくなるもの」も増やしていきます。
