はじめに
忘年会の景品抽選、配信企画の出演順、軽いチーム分け。
「誰がやる?」と微妙な沈黙が落ちる、あの気まずい一瞬。ほんの少しだけ気を使う。けれど、本当はもっとライトに、もっと楽しく決めたい。
そんな小さな“当惑”を解消したくて、ブラウザだけで使えるミニWebアプリ「Webルーレット」を作った。

登録不要・その場で即回転。
この記事では、UI構成・Canvas描画・アニメーション・操作性のこだわりなど、実装の裏側をざっくり紹介する。
フロントエンドで小さめのツールを作ってみたい人の参考になればうれしい。
画面構成とUI設計
レイアウトはとてもシンプルに「左:ルーレット本体 / 右:設定パネル」。
イベントでプロジェクター投影しても破綻しにくい、安定した二分割だ。
ブラウザ幅900px以下では縦積みに変わり、スマホでも違和感なく操作できる。flexだけで完結する素直なレスポンシブ設計である。
<div class="wr-app"> … </div>
main.wr-main {
display: flex;
gap: 56px;
}
@media (max-width: 900px) {
main.wr-main { flex-direction: column; }
}
左カラムにはCanvasで描くルーレットと結果パネル、右カラムには項目リスト・タイトル設定・速度スライダー。
背景色は淡いブルーグリーンで、カードはオフホワイト。視認性を損なわず、ほんのり“おもちゃ感”を出している。
特にルーレット枠は太いボーダー+内側シャドウで質感を足し、デジタルなのにどこかアナログっぽい“盤”に寄せた。ここは完全に趣味であるが、場のテンションを左右するため意外と重要だった。
ルーレット描画とセクター分割ロジック
ルーレットはHTMLCanvasに扇形を項目数ぶん描く、王道の実装。
角度は (2\pi / N) の等分割。文字も毎セクターの中心角に合わせて回転して描画する。
const sliceAngle = (Math.PI * 2) / items.length;
実装は以下のような流れ。
- items配列に
{ label, color }を保持 - 角度
angleを基準に扇形を順番に描画 - テキストは
ctx.rotate()で向きを合わせる - 真ん中に白円を敷いて盤の中心を演出
- 星バッジ & ポインタは DOM で重ねて調整しやすくする
DOM重ね方式にしたのは、Canvas内にポインタを描くと当たり判定の座標計算が煩雑になるため。UI調整のしやすさを優先した。
当たり判定
Canvas自体を回転する方法もあるが、今回は盤は固定・ロジックだけ回転という方式にした。
常に「画面上部(星バッジ直下)」が当たりになるため、計算は次のように整理できる。
const pointerAngle = -Math.PI / 2; // 真上
diff = (pointerAngle - angle) を 0〜2π に正規化
index = floor(diff / sliceAngle)
ポイントは、angle がどれだけ蓄積しても周期 2π で正確にセクターを割り出せること。
UI的にも「星が固定・盤が回る」方が視覚的にわかりやすく、イベント中も説明いらず。
CSSで固定されたポインタと星バッジは以下のように配置している。
.wr-pointer {
border-bottom: 22px solid #ff4b5c;
}
スタートボタンと減速アニメーション
回転は requestAnimationFrame ベースのアニメーション。
実装は素朴だが、挙動にはちょっとした“はじけ具合”を仕込んでいる。
- 初期速度は range(1〜5) + 微ランダム を合成
- 毎フレーム
angularVelocity *= 0.985;で減速 - 閾値を下回ったら停止 → 当選判定
- UI文言(「回転中…」)で状態を明示
angularVelocity = base + add + Math.random() * 0.1;
速度にランダムを入れているのは、毎回同じ止まり方だと“機械感”が強くなるため。
このほんの少しのゆらぎで「止まる瞬間」の盛り上がりが変わる。
項目リストUI
右パネルは、単なるテキストエリアにせず1行=1アイテムの構造で実装した。
- 入力欄
- カラードット(Canvasの色と連動)
- 削除ボタン
この3点セットが揃うと、ルーレット上の色と項目の対応が一瞬で理解できる。
配信やイベント運営を想定すると、この“理解に要する1秒”が意外に重要だ。
削除処理は 最低2項目は残す 制約を入れ、ルーレットとして成立しない状態を防止。
行の高さも固定しており、入力中にUIが伸び縮みして“揺れる”ことがない。
初期値には
リンゴ・ゴリラ・ラッパ・パセリ
という、謎に語呂の良いセットを採用。動作確認しやすく、少しだけクスッとする。
タイトル & 速度スライダー
何を選ぶ抽選なのか、それが画面に書かれているだけで参加者の理解が段違いになる。
そのため「タイトル」欄を設け、結果は
忘年会の抽選会:◯◯
のように表示する。
また速度スライダーは、意外と好評だった機能。
速く回せば派手に、遅くすれば“じわじわ止まる”緊張感が出る。
ちょっとした演出の調整ができるだけで、場の空気が変わる。
まとめ
Webルーレットは、HTML / CSS / 素のJavaScript と Canvas だけの、非常に小さなWebアプリだ。
とはいえ、
- 星バッジ基準の当たり判定
- 減速アニメーションの微調整
- 揺れない項目リストUI
- “色と名前の即時リンク”
など、細部に少しずつ手をかけることで “ただのランダムツールではない体験” に近づけられた。
イベントの抽選、罰ゲーム決め、授業でのランダム指名──ブラウザさえあればどこでも回せる。
こうした小さなユーティリティを積み上げていくことが、フロントエンド開発のいちばんの筋トレだと思う。
次の小さなツールづくりのヒントになればうれしい。


コメント