なぜ要るか
ここまでで音は揃いました。でも画面はまだ静かです。
勝っても負けても、文字が変わるだけです。同じ勝敗なのに、返ってくる情報が少ないと手触りが軽くなります。
この術でやるのは3つだけです。跳ねる・揺れる・光る。 それ以上は要りません。
使う道具: なし(CSSとJSだけ)
AIプロンプト
この術の作業をAIへ任せるときは、これをそのまま貼ってください。
index.html に決着の演出を足して。守り切った的だけを少し持ち上げて金色の枠を付け、取られた的は薄くして沈める。動きは0.3秒前後。1手ごとの演出は増やさないで、決着のときだけにして。それ以外は変えないで。
「的」の部分は、自分の企画で勝敗が決まる場所の呼び名に置き換えてください。
演出は「時間」が9割です
先に結論を書きます。何を動かすかより、何秒で動かすかで決まります。
僕が使っている長さです。
| 演出 | 長さ |
|---|---|
| 札が跳ねる | 0.32秒 |
| 画面が揺れる | 0.28秒 |
| 画面が光る | 0.4秒 |
全部0.3秒前後です。 ここが要点です。
0.1秒だと気づかれません。1秒だと待たされます。 待たされる演出は、2回目から邪魔になります。ゲームは同じ動作を何十回も繰り返すので、ここでの0.5秒の差が積み上がります。
迷ったら0.3秒。 そこから短くする方向で調整してください。
やってみる
取った的を持ち上げる
決着したとき、守り切った的だけを浮かせます。CSSはこれだけです。
.target { transition: transform .32s, box-shadow .32s; } .target.won { transform: translateY(-8px); border-color: #ffd479; box-shadow: 0 0 18px rgba(255, 212, 121, .4); } .target.lost { opacity: .55; }transitionは、見た目が変わったときにその差をなめらかに繋ぐ指定です。ここでは0.32秒かけて移り変わります。wonとlostはクラスの名前で、JSからこれを付け外しすると、そのとき初めて見た目が動きます。クラスは、見た目の指定をまとめて名前で呼び出す仕掛けです。取った的を上げるだけでなく、取られた的を沈めます。 片方だけだと差が出ません。上げると下げるを対にすると、同じ動き幅で倍の差が出ます。
実際の見た目がこれです。
どの的を取ったかを、数字を読まずに分かる状態です。3つ並んだうちの2つが浮いている、それだけで勝ちが伝わります。
開いた札だけ動かす
1手ごとの演出は、これ1つに絞ります。伏せた札がひらく瞬間です。
@keyframes hiraku { 0% { transform: rotateY(90deg); } 100% { transform: rotateY(0); } } .card.hiraku { animation: hiraku .26s ease-out; }@keyframesで動きの型を決めて、animationでそれを再生します。横に90度倒れた状態から正面へ戻すので、札がめくれるように見えます。問題はどの札に付けるかです。盤の札は毎回まとめて描き直すので、全部に付けると過去の札まで踊り出します。
fresh[e.key] = true; // reveal() で、いま開いた札だけ印を付ける ... var cls = 'card mini' + (fresh[entry.key] ? ' hiraku' : ''); ... fresh = {}; // render() の最後で印を消す「いま起きたことだけ」を持つ入れ物を1つ用意する。 これが、描き直す型の画面で演出を入れるときの定石です。付けたクラスを消して回る必要がなくなります。
負けたら画面を揺らす
.shake { animation: yure .28s ease-in-out; } @keyframes yure { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-6px); } 75% { transform: translateX(6px); } }function shake() { document.body.classList.remove('shake'); void document.body.offsetWidth; document.body.classList.add('shake'); }JSの側では、クラスを一度外してから付け直しています。真ん中の
void document.body.offsetWidthは、その外した状態をブラウザにいったん確定させるための1行です。これが無いと、外してすぐ付け直したことをブラウザが「何も変わっていない」と判断して、2回目以降の揺れが再生されません。揺れ幅は6pxです。 20px揺らすと画面が壊れたように見えます。気づく最小で足ります。
決着で一瞬光らせる
<div class="flash" id="flash"></div>.flash { position: fixed; inset: 0; pointer-events: none; background: #ffd479; opacity: 0; } .flash.on { animation: hikari .4s ease-out; } @keyframes hikari { 0% { opacity: .28; } 100% { opacity: 0; } }position: fixedとinset: 0で、画面いっぱいに広がる板を1枚置いています。ふだんはopacity: 0なので見えません。決着でonを付けたときだけ、金色がうっすら差してすぐ消えます。pointer-events: noneを忘れないでください。 これが無いと、光の板が画面を覆って何も押せなくなります。光った瞬間がこれです。
静止画だと強く見えますが、0.4秒で消えます。 止めた瞬間だけを切り出しているので、実際に遊ぶとほんの一瞬です。
音と同じタイミングで出す
ここが最後の仕上げです。絵と音をずらさない。
if (myTargets > cpuTargets) { text = myTargets + 'つの的を守って、あなたの勝ちです!'; SE.win(); // 音 el('flash').classList.add('on'); // 絵 }同じ場所で並べて書きます。 音を先に鳴らして絵を0.2秒遅らせる、のようなズレを作ると、それだけで安っぽくなります。
3回遊んで判定する
open index.html「音を出す」を押してから、最後まで打ち切ってください。決着で、的が上下に分かれて、画面が一瞬光るか揺れるはずです。判定はこれだけです。2回目に「早く進みたい」と思ったら過剰です。
1回目は誰でも面白いと感じます。2回目の感じ方が本当の答えです。
保存する
git add . git commit -m "跳ね・揺れ・光の演出をつけた" git push
AIに頼むときの言い方
演出は「何を動かすか」より「何秒で」「どこだけ」が効きます。だから指示にもその2つを入れます。
claude -p "index.html に決着の演出を足して。守り切った的だけを少し持ち上げて金色の枠を付け、取られた的は薄くして沈める。動きは0.3秒前後。1手ごとの演出は増やさないで、決着のときだけにして。それ以外は変えないで。"
「1手ごとの演出は増やさないで」が要点です。 これを言わないと、親切に全部の操作へ演出が付いて返ってきます。演出は足し算ではなく配分なので、増やさない場所を先に指定します。
足すより「引く」方が効きます
僕の失敗を書きます。最初は全部の出来事に演出を付けました。
札を押したら跳ねる、勝ったら光る、負けたら揺れる、引き分けでも点滅する。結果、どれも目立たなくなりました。
演出は相対的です。常に何か動いていると、大事な瞬間が埋もれます。
いま入れているのはこれだけです。
| 出来事 | 演出 | 音 |
|---|---|---|
| 札をえらんだ | 札が少し浮く | 軽い音 |
| 的に置いた | なし | 紙の音 |
| 札がひらいた | ひらいた札だけ回る | 開く音 |
| 勝った | 取った的が浮く+画面が光る | 鈴 |
| 負けた | 取られた的が沈む+画面が揺れる | 低い音 |
的に置いた瞬間に絵の演出を入れていません。 ここを空けているから、0.5秒後にひらく瞬間が立ちます。
これは4-6でキャラの反応を3つに絞ったのと同じ考え方です。空白があるから、動きが見えます。
動きが苦手な人がいます
見落とされやすい話です。画面の揺れや点滅で気分が悪くなる人がいます。
パソコンやスマホには「動きを減らす」設定があって、こちらから読めます。1回入れておけば、以降のすべての作品で効きます。
@media (prefers-reduced-motion: reduce) {
.card.win, .shake, .flash.on, .chara {
animation: none;
}
}
@media は条件を付けた指定で、条件に合う相手にだけ中身が適用されます。prefers-reduced-motion: reduce は「動きを減らす設定にしている人」を表す条件です。
設定した人にだけ演出が止まります。 ほかの人の見え方は変わりません。
3行で済むので、入れておいてください。8章の公開前チェックでも、ここは見る項目に入れています。
つまずきどころ
2回目からアニメーションが動かない
void el.offsetWidth が入っていません。上の手順2をもう一度見てください。これは必ず1回はまります。
揺らしたら画面のレイアウトが崩れた
transform ではなく margin や left で動かしていると崩れます。transform は場所を計算し直さないので崩れません。 動かすものは transform を使ってください。
光が消えずに残る
animation が終わったあとの状態が opacity: 0 になっているか確認してください。animation-fill-mode を forwards にしていると、最後の状態で止まります。今回は止めたくないので指定しません。
何も押せなくなった
pointer-events: none が抜けています。光の板が画面全体を覆っているので、そのままだとクリックを全部吸い込みます。
演出が地味に感じる
数字を大きくする前に、音を確認してください。 演出が地味に感じるときは、たいてい音が足りていません。絵より音の方が効きます。
キャラの呼吸と喧嘩する
4-2で書いたとおり transform は1つしか持てません。呼吸を外側の要素、演出を内側の要素と分けてください。
Windows の場合
コードは同じです。open index.html の代わりに start index.html を使ってください。
次の一歩
跳ねの長さを 0.32秒から1秒に変えて、5回遊んでみてください。
3回目くらいで邪魔になります。 その感覚が「演出は短く」の理由です。数字で説明されるより、1回体験した方が確実に身につきます。
これで5章は終わりです。押せば音が返り、曲が流れ、キャラが喋り、勝った瞬間に画面が動く。ここまでで「遊べるもの」から「触って気持ちいいもの」に変わりました。 次の章では中身を増やして、何度も遊べる形にしていきます!
ここまでの三つの的
この講座は、見本ゲーム「三つの的」を術ごとにすこしずつ育てながら進みます。下にあるのはこの術を終えた時点の実物です。そのまま遊べます。

