光の輪
光の輪の明るい側を1周させる
金の点でできた光の輪の明るい側が、暗い円のふちに沿って動いていく。点は動かず、向きが変わると明るさだけが移る。速さは途中で少し上がってから戻る。ループのつなぎ目では前後の速さがそろい、動きがなめらかにつながる。動かすのは明るい側の向き、ただこれだけだ。
- Published
- 2026年6月15日
- Topics
- Loop · Corona · Eclipse · Canvas
暗い円・金の点・明るい側を用意する
- 暗い円は、何も描かない丸い空白として置き、金の点はその外側だけに散らす
- 金の点の輪は、中心から外へいくほど数を減らし、内側ほど密にする
- 明るい側は、
directionが指す向きに近い点ほど明るく、反対側は暗くなる - 向き
directionの動きは、periodFramesのあいだにTURNだけ回り、baseAngleの向きで速さがいちばん遅くなる
作る関数は2つだ。フレーム番号から明るい側の向きを返す関数と、その向きから点1つの明るさを決める関数だ。点は最初に一度だけ散らし、あとは動かさない。変わるのは明るさだけだ。
// 動かすのは「明るい側の向き」direction の1つだけ。1ループでちょうど1周して戻る。
// 小文字の名前(baseAngle や lobeStrength)は、自分の画面に合わせて決める値 —
// 重要なのは値ではなく、この組み立て方だ。
const TURN = 360;
// 向きは「1周」と「途中の速さの増減」を足したもの。増減は sin の波なので、ループの両端で速さがそろう
function directionAt(local, periodFrames) {
const phase = local / periodFrames; // ループのどこまで進んだか
const turn = TURN * phase; // 一定の速さで1周
const breath = rateDepth * Math.sin(2 * Math.PI * phase); // 途中の速さの増減
return baseAngle + turn + breath; // 速さがいちばん遅くなる向きが baseAngle
}
// 点は動かない。毎フレーム、向きとのズレから明るさだけを計算し直す
function brightnessAt(dotAngle, direction, radial) {
const gap = ((dotAngle - direction) * Math.PI) / 180; // その点が向きからどれだけ離れているか
const lit = 1 + lobeStrength * Math.cos(gap); // 向きに近いほど明るい
return Math.max(0, Math.min(1, radial * lit)); // radial は中心からの距離で決まる元の明るさ
}breath は sin の波なので、ループの最初と最後で同じ値に戻り、両端で速さの変わり方もそろう。だから向きが1周して同じ位置に戻るだけでなく、つなぎ目をまたぐ速さも一致し、動きがなめらかにつながる。rateDepth を大きくすると速さの差が大きくなるが、大きくしすぎると途中の急な加速が目立って不自然に見える。
肝心なのは、点が1つも消えたり現れたりしないことだ。点の位置は向きと関係なく決まり、いちばん暗い側でも明るさは決めた下限までしか下がらない。だから明るい側が動いても、点の集まりはループの間ずっと変わらない。絵全体が回るのではなく、その場で明るさだけが動いていく。生きたプラズマのふちのように見えるのはこのためだ。
点はたくさん用意し、最初に一度だけ散らす。中心の暗い円を避け、内側ほど密にする。あとは最初に決めた座標を画面の大きさへ合わせて拡大するだけだ。配置の計算を毎フレーム回す必要はない。
アニメーションは requestAnimationFrame で動かす。経過した時間にフレームレートを掛け、periodFrames で割った余りが、ループ内の現在位置 local になる。仕上げのグレイン(粒状)と色収差は、明るさを計算し直した絵の上に重ねる。
向きで決まるのは「どちら側が明るいか」だけだ。だから点の配置を変えても、花火でも雪でも、同じ directionAt と brightnessAt で明るい側を動かせる。