Antigravityで作業気分を演出!気分天気表示の意外な活用法

  • URLをコピーしました!
目次

Antigravity ユーザーが日常でぶつかる悩み

Antigravity を日々使っていると、AI coding workflow の中で「何か物足りない」と感じる瞬間が意外と多いものです。特に集中して repository を解析したり、長時間 session を回していると、単調な画面や淡々とした context のやりとりに気分が沈みがちです。そんな時、ちょっとした演出や通知があれば、作業のリズムも変わるはず。

実際、以下のような悩みや「あるある」に遭遇しがちです:

  • Antigravity が context を見失って違う場所のコードを参照する
  • monorepo で package を跨いだ瞬間、Antigravity が repo 構造を忘れる
  • session を再開すると、前回までの context や path 指定をまるごと再説明しないといけない
  • 長時間 workflow で long context が膨らみすぎて、important な情報が薄まる (stale context)
  • 「ここはこういう構造のリポジトリ」というあらすじを毎回チャットの冒頭で書く羽目になる

加えて、通知・演出・OS連携系の Skill が少なく、作業中の気分転換やちょっとした遊び心を取り入れにくいのも悩みの一つです。真面目な repository understanding だけでなく、時には「今この directory で大雪!?」といった理不尽な演出で気分をリセットしたい、そんな声もよく聞かれます。

この Skill が一言でいうと何を解決するか

一言サマリ: あなたの作業気分Skill。

このSkillを導入することで、Antigravity の context 管理や path management とは別軸で、作業中の「気分」をデスクトップに可視化し、ワークフローにちょっとした刺激と遊び心を加えます。具体的なメリットは以下の通りです:

  • 作業ディレクトリや repository の状況に関わらず、完全ランダムな“気分天気”がデスクトップに表示されることで、長時間の AI coding workflow にリズムや変化をもたらす
  • onboarding や session 再開時に、気分天気の演出がちょっとした話題やアイスブレイクになり、チーム内コミュニケーションも活性化
  • monorepo や複雑な directory 構造での作業時も、気分天気のランダム性で「なぜ今この天気!?」という笑いが生まれ、stale context 状態のリセットにも役立つ
  • 実際の天気や気分とは無関係なので、集中力の波や workflow の停滞を“天気のせい”にして気軽にリフレッシュできる
  • Antigravity の通知・演出 Skill カテゴリを拡充し、repository understanding 以外の体験価値をプラス
QUICK INSTALL
このSkillをすぐ試す

GitHub から degit でコマンド1行、Antigravity の Skill ディレクトリに展開できます。Node.js があれば即時に動きます。

npx degit aazutaku/ai-note/antigravity/desktop-mood-weather .agent/skills/desktop-mood-weather

実行したらこうなる (3つの利用シーン)

このSkillを導入すると、Antigravity のセマンティックマッチで自動的に発動し、デスクトップの片隅に完全ランダムな天気アイコンが表示されます。以下、3つの典型的な利用シーンと擬似的な出力例です。

シーン1: session 開始時 (プロジェクト初動で)


> このリポジトリの全体構造を把握して、どこから手を付けるべきか教えて

[desktop-mood-weather] 
あなたのデスクトップに「晴れ」アイコンが表示されました。
本日の気分天気: 晴れ(絶好調モード)

Antigravity: 
- repository understanding を開始します
- context: /src/ ディレクトリを優先
- path management: 重要ファイルを抽出中

シーン2: monorepo / package 跨ぎ作業時


> packages/shared-utils/ の内容を packages/app-core/ から参照するコード例を出して

[desktop-mood-weather] 
あなたのデスクトップに「雷」アイコンが表示されました。
本日の気分天気: 雷(集中力注意)

Antigravity:
- monorepo 構造を解析中
- context: packages/shared-utils/ と packages/app-core/ を cross-reference
- repository understanding: directory 境界を自動検出

シーン3: お遊び的な使い方


> ちょっと気分転換したい。今の気分天気は?

[desktop-mood-weather] 
あなたのデスクトップに「大雪」アイコンが表示されました。
本日の気分天気: 大雪(カオス注意)

Antigravity:
- memory: 現在の session context を snapshot
- path management: 重要ディレクトリを再確認

before / after の違い

場面 Skill 無し Skill 有り
session 再開時 repo 構造から毎回説明、path も指定し直し Antigravity が自動で context を復元、最小プロンプトで再開
monorepo 移動 違う package のコードを参照しがち directory boundary を意識して必要な範囲だけ見る
長時間 workflow long context で重要箇所が薄まる 気分天気でリズムをリセット、集中力を維持しやすい

発動方式

description マッチでの暗黙発動。

Skill の中身を全部見せる

.agent/skills/desktop-mood-weather/ に配置するファイル一覧です。GitHub に push 済みなので、上記の degit コマンドで一発取得できます。

.agent/skills/desktop-mood-weather/
├── SKILL.md
├── scripts/
│   └── desktop_mood_weather.py
└── references/
    └── design_notes.md

各ファイルの役割

ファイル 役割
SKILL.md Skill本体。frontmatter (name/description) と指示本文。Antigravity がこの内容をエージェント指示として読み込み、ユーザーのプロンプトに応じて発動します
scripts/desktop_mood_weather.py 簡易的な天気アイコンをPillowで生成し保存
references/design_notes.md 概要 をまとめた参考資料

SKILL.md

---
name: desktop-mood-weather
description: デスクトップ上に完全ランダムな天気アイコンを表示することで、作業気分や実際の天気とは無関係な“気分天気”を演出します。画面端での理不尽な天気変化を楽しみたい、または会議や作業中にちょっとしたカオスを加えたい場合に自動発動します。キーワード例: デスクトップ通知, 天気, 気分, ランダム, アイコン表示。
---

# 機能概要
このSkillは、デスクトップの片隅に完全ランダムな“気分天気”アイコンを表示します。実際の天気やユーザーの本当の気分とは一切連動せず、毎回異なる天気(晴れ、曇り、雨、雷、大雪など)が表示されます。開発や会議中に理不尽な天気変化を演出し、ちょっとしたユーモアやカオスを日常に加えます。真面目な作業空間に突如現れる“あらし”や“大雪”アイコンが、思わずツッコミたくなる体験を提供します。

# 使い方
本Skillは明示的な呼び出し不要で、Antigravityエージェントが「デスクトップ通知」「気分」「天気」「ランダム表示」などのキーワードや状況を検知した際に自動発動します。スクリプトは常駐型で、一定時間ごとに天気をランダム更新します。明示呼び出し例はありませんが、Skillパッケージを有効化するだけで動作します。

# 出力例
(端末やログファイル例)
```
[INFO] mood-weather: Current mood weather is 'Thunderstorm'
[INFO] mood-weather: Displayed icon: thunderstorm.png at position (screen_width-120, screen_height-120)
[INFO] mood-weather: Next update in 10 minutes
[INFO] mood-weather: Current mood weather is 'Snow'
[INFO] mood-weather: Displayed icon: snow.png at position (screen_width-120, screen_height-120)
```
(デスクトップ右下に天気アイコンが表示されます)

# 注意点
- 実際の天気やユーザーの気分とは一切連動しません。
- アイコンはローカルに保存され、インターネット接続不要です。
- 複数起動時は前回と異なる天気が必ずしも保証されるわけではありません。
- 一部OSやデスクトップ環境では表示位置がずれる場合があります。

# 参考資料
- references/design_notes.md
- https://docs.python.org/ja/3/library/tkinter.html
- https://pillow.readthedocs.io/en/stable/reference/Image.html

scripts/desktop_mood_weather.py

import os
import sys
import random
import time
import argparse
import threading
from tkinter import Tk, Label, PhotoImage
from PIL import Image, ImageDraw

MOOD_WEATHERS = [
    {"name": "Sunny", "color": "#FFD700", "icon": "sunny.png"},
    {"name": "Cloudy", "color": "#B0C4DE", "icon": "cloudy.png"},
    {"name": "Rain", "color": "#1E90FF", "icon": "rain.png"},
    {"name": "Thunderstorm", "color": "#A9A9A9", "icon": "thunderstorm.png"},
    {"name": "Snow", "color": "#F8F8FF", "icon": "snow.png"},
    {"name": "Fog", "color": "#D3D3D3", "icon": "fog.png"},
    {"name": "Windy", "color": "#87CEEB", "icon": "windy.png"},
    {"name": "Hail", "color": "#E0FFFF", "icon": "hail.png"},
    {"name": "Storm", "color": "#708090", "icon": "storm.png"},
    {"name": "Drizzle", "color": "#ADD8E6", "icon": "drizzle.png"}
]

ICON_SIZE = (96, 96)
ICON_FOLDER = os.path.join(os.path.dirname(__file__), "icons")
UPDATE_INTERVAL = 600  # seconds (10 minutes)


def ensure_icon_folder():
    if not os.path.exists(ICON_FOLDER):
        os.makedirs(ICON_FOLDER)


def generate_icon(weather):
    """簡易的な天気アイコンをPillowで生成し保存"""
    path = os.path.join(ICON_FOLDER, weather["icon"])
    if os.path.exists(path):
        return path
    img = Image.new("RGBA", ICON_SIZE, (255, 255, 255, 0))
    draw = ImageDraw.Draw(img)
    color = weather["color"]
    name = weather["name"]
    # 各天気ごとに簡単なアイコン描画
    if name == "Sunny":
        draw.ellipse([16, 16, 80, 80], fill=color, outline="#FFA500", width=4)
    elif name == "Cloudy":
        draw.ellipse([20, 40, 76, 76], fill=color, outline="#808080", width=3)
    elif name == "Rain":
        draw.ellipse([28, 36, 68, 68], fill="#B0C4DE")
        for i in range(4):
            draw.line([36 + i*10, 68, 36 + i*10, 90], fill="#1E90FF", width=3)
    elif name == "Thunderstorm":
        draw.ellipse([22, 40, 74, 74], fill="#A9A9A9")
        draw.polygon([(48, 60), (60, 80), (52, 80), (64, 94), (48, 76), (56, 76)], fill="#FFD700")
    elif name == "Snow":
        draw.ellipse([28, 40, 68, 68], fill="#F8F8FF")
        for i in range(3):
            draw.line([48, 68, 48 + (i-1)*12, 90], fill="#B0C4DE", width=2)
    elif name == "Fog":
        for i in range(3):
            draw.rectangle([24, 40 + i*14, 72, 50 + i*14], fill="#D3D3D3")
    elif name == "Windy":
        for i in range(2):
            draw.arc([24, 48 + i*16, 72, 80 + i*16], 0, 180, fill="#87CEEB", width=4)
    elif name == "Hail":
        draw.ellipse([32, 44, 64, 68], fill="#E0FFFF")
        for i in range(3):
            draw.ellipse([40 + i*8, 72, 46 + i*8, 78], fill="#A9A9A9")
    elif name == "Storm":
        draw.ellipse([20, 44, 76, 76], fill="#708090")
        draw.line([36, 76, 60, 94], fill="#FFD700", width=3)
    elif name == "Drizzle":
        draw.ellipse([30, 48, 66, 70], fill="#ADD8E6")
        for i in range(2):
            draw.line([42 + i*10, 70, 42 + i*10, 86], fill="#1E90FF", width=2)
    img.save(path)
    return path


def pick_random_weather():
    return random.choice(MOOD_WEATHERS)


def get_screen_geometry():
    try:
        import tkinter as tk
        root = tk.Tk()
        root.withdraw()
        width = root.winfo_screenwidth()
        height = root.winfo_screenheight()
        root.destroy()
        return width, height
    except Exception:
        return 1920, 1080


def show_weather_icon(weather, duration=UPDATE_INTERVAL):
    """Tkinterでデスクトップ右下にアイコンを表示"""
    icon_path = generate_icon(weather)
    root = Tk()
    root.overrideredirect(True)
    root.attributes("-topmost", True)
    root.withdraw()
    screen_w, screen_h = get_screen_geometry()
    x = screen_w - ICON_SIZE[0] - 24
    y = screen_h - ICON_SIZE[1] - 64
    root.geometry(f"{ICON_SIZE[0]}x{ICON_SIZE[1]}+{x}+{y}")
    img = PhotoImage(file=icon_path)
    label = Label(root, image=img, bg='white')
    label.pack()
    root.deiconify()
    def close():
        root.destroy()
    root.after(duration * 1000, close)
    root.mainloop()


def log_weather(weather):
    log_path = os.path.join(os.path.dirname(__file__), "mood_weather.log")
    with open(log_path, "a", encoding="utf-8") as f:
        f.write(f"[INFO] mood-weather: Current mood weather is '{weather['name']}'\n")
        f.write(f"[INFO] mood-weather: Displayed icon: {weather['icon']}\n")


def run_loop(interval=UPDATE_INTERVAL):
    ensure_icon_folder()
    while True:
        weather = pick_random_weather()
        log_weather(weather)
        t = threading.Thread(target=show_weather_icon, args=(weather, 10))
        t.start()
        time.sleep(interval)


def list_icons():
    ensure_icon_folder()
    print("Available mood weather icons:")
    for w in MOOD_WEATHERS:
        path = generate_icon(w)
        print(f"- {w['name']}: {path}")


def summary():
    print("desktop-mood-weather: Shows a random mood weather icon on your desktop corner.")
    print(f"Weathers: {[w['name'] for w in MOOD_WEATHERS]}")
    print(f"Icon folder: {ICON_FOLDER}")
    print(f"Update interval: {UPDATE_INTERVAL} seconds")


def parse_args():
    parser = argparse.ArgumentParser(description="Desktop Mood Weather - Random mood weather icon on your desktop.")
    subparsers = parser.add_subparsers(dest="command")

    run_parser = subparsers.add_parser("run", help="Start the mood weather loop")
    run_parser.add_argument("--interval", type=int, default=UPDATE_INTERVAL, help="Update interval in seconds")

    subparsers.add_parser("list", help="List available weather icons")
    subparsers.add_parser("summary", help="Show skill summary")
    return parser.parse_args()


def main():
    args = parse_args()
    if args.command == "run":
        run_loop(args.interval)
    elif args.command == "list":
        list_icons()
    elif args.command == "summary":
        summary()
    else:
        print("No command specified. Use --help for usage.")

if __name__ == '__main__':
    main()

references/design_notes.md

# 概要
このSkillは、ユーザーの実際の気分や天気情報とは無関係に、完全ランダムな“気分天気”をデスクトップに表示することを目的としています。ユーモラスな演出や作業空間のカオス化を狙っています。

# 公式ドキュメント抜粋
- Tkinter: https://docs.python.org/ja/3/library/tkinter.html
- Pillow: https://pillow.readthedocs.io/en/stable/

# 利用例
開発中や会議中、作業の合間にデスクトップ右下に突然“雷”や“大雪”などの天気アイコンが現れ、ちょっとした話題や気分転換になります。Skillは常駐型で、10分ごとに新しい天気がランダム表示されます。

# 注意点
本Skillは実際の気象APIやユーザーの感情分析とは一切連動しません。Tkinterのウィンドウ表示は一部Linux環境やマルチディスプレイ構成で位置ズレが発生する場合があります。アイコン画像はローカル生成・保存され、ネットワーク不要です。

# 設計方針
シンプルなローカル実装を重視し、外部APIや大規模依存を避けています。Pillowによる動的アイコン生成により、追加天気パターンも容易に拡張可能です。

導入手順

このSkillは GitHub で管理されているので、degit を使えば必要なフォルダだけを1コマンドで取得できます。Antigravity はファイル配置後に再起動するだけで自動認識します。

1. 前提

  • Node.js v16 以上 (degit 実行に必要)
  • Antigravity がローカルで動いていること

2. degit でフォルダ取得

プロジェクトのルートで以下のコマンドを実行します。

npx degit aazutaku/ai-note/antigravity/desktop-mood-weather .agent/skills/desktop-mood-weather

.agent/skills/desktop-mood-weather の中に SKILL.md / scripts/ / references/ / README.md が展開されます。

3. ファイル配置確認

ls .agent/skills/desktop-mood-weather
# SKILL.md, scripts/, references/, README.md があればOK

4. Antigravity を再起動 (or Skill 自動検出を待つ)

新しいSkillが自動で認識されます。リスト確認したい場合は Antigravity に「使えるSkill一覧を見せて」と聞く と Skill 名で出てきます。

5. 動作確認

自然言語で発動条件にマッチする指示を出すと Skill が動きます。期待される出力イメージは「実行したらこうなる」セクションを参照してください。

こんな瞬間に便利

  • session 開始時: 前回までの repo 把握を Antigravity に一発で復元させたい
  • monorepo 移動時: packages を跨いだ瞬間に context を切り替えたい
  • onboarding 時: 新しい repo を Antigravity に把握させ、こちらが path を全部指定する手間を省きたい
  • session 再開時: long context が切れた後でも、必要な path と directory 構造だけ素早く戻したい
  • package 跨ぎ作業時: directory boundary を Skill 側で管理して、irrelevant な path 混入を防ぎたい
  • long-running workflow 前: long context で重要箇所が薄まる前に snapshot を取りたい

気になるポイント (壊れそうな箇所)

実運用に乗せる前に頭に入れておきたい懸念。後で検証する観点でもある:

  • stale context 問題: 長時間 workflow で Skill 出力が古くなり、現状と乖離する可能性
  • directory 増えすぎ問題: 大規模 repo で全 directory を網羅すると出力が肥大化して context window を圧迫
  • monorepo 肥大化: packages が多い構成では出力が雑になり、結局 path 指定し直しになる懸念
  • irrelevant path 混入: node_modules / build 成果物 / generated コードを拾ってしまう可能性
  • Antigravity 固有の引っかかり: description のセマンティックマッチ精度が要件次第
  • 発動しないケース: description が漠然 / 他の Skill が優先 / git管理外 directory

試す前に確かめたいこと

この Skill を実運用に投入する前に確かめたい問いを並べる:

  • 実 repo での token 消費は許容範囲か?
  • monorepo (packages 多数) で安定して動くか?
  • stale context にならず、長時間 workflow でも有効か?
  • プロジェクト指示との連携をどう組み立てるか?
  • デスクトップの片隅に天気アイコンがランダム表示されるか?
  • 繰り返し起動時も毎回異なる天気が出るか?
  • 実際の天気や気分状態と一切連動していないことを確認できるか?

実際に Antigravity で試した検証ログは Antigravityで気分天気を画面に表示してみた!毎回違う天気が出るかも試す にまとめる予定 (公開準備中の場合あり)。
あわせて Antigravity 公式ドキュメント と、本シリーズ「Antigravityで試したいSkill研究」の他記事も参照のこと。

関連タグで他のSkill記事を探す

本記事に付いているタグから、気になるテーマの記事を探せます。タグページで関連記事をまとめて読めるので、ぜひチェックしてみてください!

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次