猫の手ツール

Geometry & Performance

ベジェ曲線による花びら描画と
キャッシュ戦略の最適化

「桜の花びら」を外部画像を使わずにCanvas上で生成。一見単純なフィルタに見えますが、スライダー操作を滑らかにし、かつ「エモい」質感を損なわないためのフロントエンド特有の工夫が詰まっています。

1. ベジェ曲線によるプロセジャル・シェイプ生成

桜の花びら特有の「ハート型の切れ込み」を再現するために、外部のPNG画像を使用するのではなく、Canvasの bezierCurveTo を用いた動的な描画アルゴリズムを採用しています。

メリット: 画像アセットのロード待ちが発生せず、何百枚と散らしてもメモリ消費を最小限に抑えられます。また、描画時に解像度が劣化しないため、4Kクラスの高解像度写真に対しても常にシャープな質感を維持できるのが強みです。

// 花びらの形状を生成するパス計算ロジック
function drawSakuraPetal(ctx, cx, cy, size, angle, color, alpha) {
    ctx.save();
    ctx.translate(cx, cy);
    ctx.rotate(angle);
    // 独自の比率でスケール調整
    ctx.scale(size / // 独自の基準値, size / // 独自の基準値);
    
    ctx.beginPath();
    ctx.moveTo(0, 0);
    // ベジェ曲線を用いて「切れ込み」のある可憐な曲線を構築
    // ここに独自の制御点座標が入ります
    ctx.bezierCurveTo(/* 制御点1 */, /* 制御点2 */, /* 終点 */);
    ctx.lineTo(0, /* 切れ込みの深さ補正 */);
    // ...反対側の曲線も同様に構築
    ctx.fill();
    ctx.restore();
}

2. 決定論的ランダム(キャッシュ配列)による安定性向上

花びらの「量」をスライダーで調整する際、描画のたびに Math.random() を呼んでしまうと、スライダーを動かすたびに既存の花びらの位置まで激しく入れ替わり、不快な「チカチカ(フリッカー)」が発生します。本ツールでは、起動時に数百点分のデータを「キャッシュ配列」として事前生成しています。

メリット: スライダーで「量」を増やしても、既にある花びらは元の位置に固定されたまま「新しい花びらが追加される」という自然なUI体験を提供できます。ランダムでありながら「配置の固定」を実現するための必須テクニックです。

// 起動時に1回だけ実行されるデータ生成処理
let petalsData = [];
for(let i = 0; i < 200; i++) {
    petalsData.push({
        x: Math.random(), // 0〜1の相対座標
        y: Math.random(),
        baseSize: // 独自のサイズ範囲,
        angle: Math.random() * Math.PI * 2,
        color: // 独自のカラーパレットからランダム選択
    });
}

// 描画時:スライダーの値(amount)だけループを回す
function render() {
    for (let i = 0; i < amount; i++) {
        const p = petalsData[i]; // キャッシュから取り出すため配置が不変
        // ...描画実行
    }
}

3. GlobalCompositeOperation による光の質感調整

単に花びらを「上に置く」だけでは、写真となじまず浮いて見えてしまいます。本ツールでは、背景写真の明るさ調整(露出補正)を行う際に、Canvasの合成モード lightermultiply を使い分けています。

メリット: ピクセル単位の重い重畳演算をブラウザのネイティブな合成エンジンに委ねることで、スマホでもカクつくことなくリアルタイムなプレビューを実現しています。これにより「春の光が差し込むような暖かさ」や「夕暮れの切なさ」をスライダー一つで表現可能にしました。

// 明るさ調整の合成ロジック
if (brightVal > 0) {
    // 加算合成により「光が溢れる」エフェクトをシミュレート
    ctx.globalCompositeOperation = 'lighter';
    ctx.globalAlpha = // 独自の重み付け;
    ctx.fillStyle = '#ffffff';
} else {
    // 乗算合成により「影を落とす」深みのある表現をシミュレート
    ctx.globalCompositeOperation = 'multiply';
    ctx.globalAlpha = // 独自の重み付け;
    ctx.fillStyle = '#000000';
}
ctx.fillRect(dx, dy, dw, dh);

Developer's Note

このツールで最も時間をかけたのは、実は花びらの「色味」の調整です。

単色だとベタ塗り感が出てしまうため、キャッシュ生成時にわずかに色相と透明度の異なる5色のサクラ色を混ぜています。これにより、写真の上に重なった時、複雑な奥行き感が生まれます。

また、iPhoneユーザーの方がHEIC形式の写真をそのまま使えるよう、ブラウザ完結で変換する仕組みを導入したのもこだわりの一つです。大切な思い出の写真を「一瞬たりとも外部サーバーへ送信しない」という安心感の上で、春の魔法を楽しんでいただければ幸いです。