1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CSSAdvent Calendar 2024

Day 7

CSSアニメーションとJinja2で実装する表情が変化するキャラクター

Last updated at Posted at 2024-12-24

はじめに

jinja2はPythonのテンプレートエンジンで、HTMLやCSSを動的に生成するのに便利です。本記事では、jinja2を使ってCSSアニメーションを生成し、キャラクターの表情を変化させる方法を紹介します。
アニメーションのパラメータはPython側で調整でき、柔軟な設計が可能です。

image.png

出力例

animation.gif

実装コード

from jinja2 import Template

# HTMLテンプレートの定義
html_template = """
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>キャラクター表情アニメーション</title>
    <style>
        @keyframes eye-transform {
            0%, 15% { transform: scale(1); opacity: 1; }
            35%, 65% { transform: scale(0.5); opacity: 0; }
            85%, 100% { transform: scale(1); opacity: 1; }
        }
        
        @keyframes angry-eye-transform {
            0%, 15% { transform: scale(0.5); opacity: 0; }
            35%, 65% { transform: scale(1); opacity: 1; }
            85%, 100% { transform: scale(0.5); opacity: 0; }
        }

        @keyframes tail-swing {
            0%, 100% { transform: rotate(0deg); }
            50% { transform: rotate({{ tail_swing_degree }}deg); }
        }
        
        .normal-eye {
            animation: eye-transform {{ expression_speed }}s ease-in-out infinite;
        }
        
        .angry-eye {
            animation: angry-eye-transform {{ expression_speed }}s ease-in-out infinite;
        }
        
        #tail {
            transform-origin: 35px 30px;
            animation: tail-swing {{ tail_speed }}s infinite;
        }
    </style>
</head>
<body>
    <svg width="200" height="200" viewBox="-100 -100 200 200" xmlns="http://www.w3.org/2000/svg">
        <ellipse cx="0" cy="0" rx="50" ry="45" fill="#4CAF50" />
        <ellipse cx="0" cy="0" rx="30" ry="25" fill="#FDF1D2" />
        <!-- 耳 -->
        <path d="M -20 -32 C -30 -50, -10 -60, -15 -40 C -18 -35, -18 -35, -20 -32 Z" fill="#4CAF50" />
        <path d="M 20 -32 C 30 -50, 10 -60, 15 -40 C 18 -35, 18 -35, 20 -32 Z" fill="#4CAF50" />
        
        <!-- 普通の目 -->
        <g class="normal-eye">
            <circle cx="-15" cy="-5" r="2.5" fill="#000" />
            <circle cx="15" cy="-5" r="2.5" fill="#000" />
        </g>
        
        <!-- >< の目 -->
        <g class="angry-eye">
            <path d="M -16 -8 L -10 0" stroke="#000" stroke-width="2" fill="none" />
            <path d="M -10 0 L -16 8" stroke="#000" stroke-width="2" fill="none" />
            <path d="M 16 -8 L 10 0" stroke="#000" stroke-width="2" fill="none" />
            <path d="M 10 0 L 16 8" stroke="#000" stroke-width="2" fill="none" />
        </g>
        
        <!-- ヒゲ -->
        <path d="M -35 -4 L -28 -2" stroke="#000" stroke-width="0.5" fill="none" />
        <path d="M -35 0 L -28 1" stroke="#000" stroke-width="0.5" fill="none" />
        <path d="M -35 4 L -28 4" stroke="#000" stroke-width="0.5" fill="none" />
        <path d="M 28 -2 L 35 -4" stroke="#000" stroke-width="0.5" fill="none" />
        <path d="M 28 1 L 35 0" stroke="#000" stroke-width="0.5" fill="none" />
        <path d="M 28 4 L 35 4" stroke="#000" stroke-width="0.5" fill="none" />
        
        <!-- 鼻 -->
        <circle cx="-2" cy="0" r="1" fill="#000" />
        <circle cx="2" cy="0" r="1" fill="#000" />
        
        <!-- 口 -->
        <path d="M -5 5 Q 0 8 5 5" stroke="#000" stroke-width="1" fill="none" />
        
        <!-- 尻尾 -->
        <path id="tail" d="M 35 30 C 45 40, 65 35, 55 20 C 50 10, 40 20, 35 30 Z" fill="#4CAF50" />
    </svg>
</body>
</html>
"""

# テンプレートのレンダリングとファイル出力
def generate_character_html(
    expression_speed=2.0,   # 表情の変化速度
    tail_speed=3.0,         # 尻尾のスイング速度
    tail_swing_degree=20    # 尻尾の振り角度
):
    template = Template(html_template)
    rendered_html = template.render(
        expression_speed=expression_speed,
        tail_speed=tail_speed,
        tail_swing_degree=tail_swing_degree
    )
    
    with open("character_expressions.html", "w", encoding="utf-8") as f:
        f.write(rendered_html)

# HTMLファイルの生成
generate_character_html()

実装のポイント

テンプレートエンジンの活用

  • Jinja2を使用してHTMLとCSSを動的に生成
  • アニメーションのパラメータを変数化して柔軟な調整が可能
    • expression_speed: 表情の切り替え速度
    • tail_speed: 尻尾の動く速度
    • tail_swing_degree: 尻尾の振れ幅

CSSアニメーション設計

  • transformopacityを組み合わせた自然な表情遷移
  • 丸目と><目の切り替えタイミングを微調整
  • ease-in-outタイミング関数で滑らかな動きを実現

カスタマイズ例

# アニメーションをよりゆっくりに
generate_character_html(
    expression_speed=3.0,
    tail_speed=4.0,
    tail_swing_degree=15
)

# より活発な動きに
generate_character_html(
    expression_speed=1.5,
    tail_speed=2.0,
    tail_swing_degree=25
)

まとめ

Jinja2とCSSアニメーションを組み合わせることで、柔軟にカスタマイズ可能なアニメーションキャラクターを実装できました。パラメータを変更することで、キャラクターの表情や動きを簡単に調整できます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?