心、主観の可視化アプリ 心の羅針盤
心の羅針盤(エモーション・ナビゲーション)設計書
🌟 コンセプト:診断ではなく「経路」を歩む
今のメンタルヘルスケアに必要なのは「病名の診断(点)」ではなく、「どう心が動いているか(線)」を可視化することです。
このアプリは、日々のざっくりした感情を**「ベクトル(方向と距離)」**に変換し、自分だけの「心の地図」を描くセルフケア・ツールです。
🍃 大切にしたい「ゆるふわ」哲学(開発者への願い)
* 「毎日やらなきゃ」をなくす: 入力がない日は「霧がかかった道」として表現。書けない日があるのは、心が休んでいる証拠。それを肯定するデザインにしてください。
* 「ざっくり」を正義にする: 厳密な数値入力は不要。スライダーで直感的に「今の感じ」を選ぶだけの、手抜きOKなUIを目指します。
* 「多機能」より「余白」: ユーザーを分析しすぎず、ただ「あ、今日はこっちに歩いたんだな」と眺められる距離感を保ってください。
⚙️ コア・ロジック:感情ベクトル
感情を「方向」、強さを「移動距離」として定義し、座標を更新していきます。
| 感情要素 | 方向ベクトル | 意味 |
|---|---|---|
| 安心 (Q_LY) | (0, 1) | 上:心が安定し、丘を登る |
| 希望 (Q_Hope) | (0.7, 0.7) | 右上:前向きなエネルギー |
| 不安 (Q_Fr) | (1, 0) | 右:ざわつき、嵐の予感 |
| 無気力/怒り | (0, -1) | 下:沈み込み、または激しい葛藤 |
| 孤独 (Q_Lonely) | (-1, 0) | 左:一人の世界、静寂 |
| いつも通り | (-1, 1) | 左上:凪の状態、ルーチン |
🧠 「ゴリゴリ」モード(生理データ補正)
主観と客観のズレを可視化します。
* ロジック: 心拍数(HR)が一定以上(例:90bpm)なら、主観が「安心」でも「不安」ベクトルを強制的に加算し、紫色の破線(ゴーストパス)として表示。
🎨 主要機能
1. 心の歩行(メインUI)
* キャラ選択: 👦👧🐱🤖など、自分の分身を選んで地図に配置。
* ベクトル描画: 入力した感情に合わせてキャラがトコトコと歩き、軌跡を残します。
2. 心の航海日誌(5W1H)
* ミニメモ欄: 「何があったか」を一言だけ記録。診察時に「この時、何でこの方向に歩いたんだっけ?」を振り返るためのContext(文脈)になります。
3. 偶然の贈り物(クローバー)
* 🍀出現: 大きく心が動いた時や、希望を感じた時に、地図上に一定確率でクローバーがドロップ。ランダムでもオッケー
* 「進んでよかった」と思える小さな報酬系。
🛠️ 推奨技術スタック(例)
* Frontend/Backend: Flask + Plotly (Python) または PWA (JavaScript / Canvas API)
* Storage: SQLite / JSON (ローカル保存推奨、プライバシー重視)
* Library: numpy, pandas (データ処理用)
📜 ライセンス
CC0 / パブリックドメイン
この設計図は公共の福祉のために公開します。営利・非営利を問わず、自由に実装・配布・改良してください。
(発案:猫は泳ぐ魚の夢を見るのか
協力:Gemini Grok)
📢 最後に
これは「自分を管理する」ためのアプリではありません。「自分という旅人」が今どこにいるのか、そっとライトを照らすための**「羅針盤」**です。
なぜこれが心、主観の可視化になるのか?
基本的に科学は静止画しか扱えません。
結果が出ているもの(データ)は勝手に変動することはないので客観として機能する、という過去形が前提のロジックだからです。
一方で心とは現在進行系であり、静止画にすると心の本質を見失います。
また、幸いなことに現実とは常に現在進行系です。
そこで主観を主観のまま動的に捉えることで、心の可視化を可能にしました。
以下、簡易に設計したWEBアプリ版のコードになります。
例 キャラ実装
from flask import Flask, request, render_template_string
import plotly.express as px
import plotly.graph_objects as go
import numpy as np
import pandas as pd
import random
import os
app = Flask(__name__)
# データ保存
DATA_FILE = "emotion_data.json"
if os.path.exists(DATA_FILE):
df = pd.read_json(DATA_FILE)
else:
df = pd.DataFrame(columns=["Date", "Q_LY", "Q_Hope", "Q_Fr", "Rp", "Q_Anger", "Q_Lonely", "Q_Normal", "HR", "5W1H", "Nq", "Character"])
# HTMLテンプレート(キャラ選択+スライダー)
HTML = """
<!DOCTYPE html>
<html>
<head>
<title>心の羅針盤 🧭</title>
<meta charset="UTF-8">
<style>
body { font-family: Arial; background: #1a1a1a; color: #fff; text-align: center; }
.container { max-width: 600px; margin: auto; padding: 20px; }
input, select { width: 100%; padding: 10px; margin: 5px 0; }
button { background: #4CAF50; color: white; padding: 10px; border: none; cursor: pointer; }
button:hover { background: #45a049; }
</style>
</head>
<body>
<div class="container">
<h1>心の羅針盤 🧭</h1>
<p>その日の気分でキャラを選んで、感情を入力!軌跡を歩むよ!✨</p>
<form method="POST" action="/">
<label>日付</label><input type="text" name="date" value="2025-07-06"><br>
<label>キャラ選択</label>
<select name="character">
<option value="👦">少年 👦</option>
<option value="👧">少女 👧</option>
<option value="🐱">猫 🐱</option>
<option value="🐕️">犬 🐕️</option>
<option value="🐻">熊 🐻</option>
<option value="🐑">羊 🐑</option>
<option value="🐥">ひよこ 🐥</option>
<option value="🤖">ロボ 🤖</option>
</select><br>
<label>安心 (Q_LY)</label><input type="range" name="q_ly" min="0" max="1" step="0.1" value="0.2"><br>
<label>希望 (Q_Hope)</label><input type="range" name="q_hope" min="0" max="1" step="0.1" value="0.3"><br>
<label>不安 (Q_Fr)</label><input type="range" name="q_fr" min="0" max="1" step="0.1" value="0.4"><br>
<label>無気力 (Rp)</label><input type="range" name="rp" min="0" max="1" step="0.1" value="0.9"><br>
<label>怒り (Q_Anger)</label><input type="range" name="q_anger" min="0" max="1" step="0.1" value="0.1"><br>
<label>孤独 (Q_Lonely)</label><input type="range" name="q_lonely" min="0" max="1" step="0.1" value="0.2"><br>
<label>いつも通り (Q_Normal)</label><input type="range" name="q_normal" min="0" max="1" step="0.1" value="0.5"><br>
<label>心拍数 (HR)</label><input type="number" name="hr" value="80"><br>
<label>5W1H</label><input type="text" name="five_w1h" value="自分が無気力を感じて絶望"><br>
<button type="submit">保存</button>
</form>
{{ plot|safe }}
<p>{{ feedback }}</p>
</div>
</body>
</html>
"""
# ルート
@app.route("/", methods=["GET", "POST"])
def index():
global df
plot = ""
feedback = "その日の気分でキャラを選んで、心の軌跡を歩もう!🍀"
if request.method == "POST":
# データ取得
data = {
"Date": request.form["date"],
"Q_LY": float(request.form["q_ly"]),
"Q_Hope": float(request.form["q_hope"]),
"Q_Fr": float(request.form["q_fr"]),
"Rp": float(request.form["rp"]),
"Q_Anger": float(request.form["q_anger"]),
"Q_Lonely": float(request.form["q_lonely"]),
"Q_Normal": float(request.form["q_normal"]),
"HR": int(request.form["hr"]),
"5W1H": request.form["five_w1h"],
"Character": request.form["character"],
"Nq": 0.4 * float(request.form["q_ly"]) + 0.3 * float(request.form["q_hope"]) - 0.3 * float(request.form["rp"])
}
df = pd.concat([df, pd.DataFrame([data])], ignore_index=True)
df = df.tail(7) # 最新7日
df.to_json(DATA_FILE)
# 軌跡計算(ふわふわ)
trail_points = [(0, 0)]
directions = {
"Q_LY": (0, 1), "Q_Hope": (1, 1), "Q_Fr": (1, 0), "Rp": (0, -1),
"Q_Anger": (0, -1), "Q_Lonely": (-1, 0), "Q_Normal": (-1, 1)
}
for _, row in df.iterrows():
x, y = trail_points[-1]
for key, (dx, dy) in directions.items():
score = row.get(key, 0)
x += dx * score
y += dy * score
trail_points.append((x, y))
# HR補正(ゴリゴリ)
hr_points = []
for _, row in df.iterrows():
q_fr_bio = max(row["Q_Fr"], 0.7) if row["HR"] > 90 else row["Q_Fr"]
x, y = trail_points[-1]
x += directions["Q_Fr"][0] * q_fr_bio
y += directions["Q_Fr"][1] * q_fr_bio
hr_points.append((x, y))
# クローバー+キャラ
clover_points = [(x, y) for x, y in trail_points if random.random() < 0.2]
char_points = [(trail_points[-1][0], trail_points[-1][1])] # 最新点にキャラ
char_emoji = data["Character"]
# Plotlyグラフ
fig = go.Figure()
fig.add_trace(go.Scatter(
x=[p[0] for p in trail_points], y=[p[1] for p in trail_points],
mode="lines+markers", line=dict(color="lightblue", width=2, dash="dot"),
name="ふわふわ(主観)"
))
fig.add_trace(go.Scatter(
x=[p[0] for p in hr_points], y=[p[1] for p in hr_points],
mode="lines", line=dict(color="purple", width=3, dash="dash"),
name="ゴリゴリ(HR補正)"
))
fig.add_trace(go.Scatter(
x=[p[0] for p in clover_points], y=[p[1] for p in clover_points],
mode="markers+text", text=["🍀"] * len(clover_points),
marker=dict(size=15, color="green"), name="クローバー"
))
fig.add_trace(go.Scatter(
x=[p[0] for p in char_points], y=[p[1] for p in char_points],
mode="markers+text", text=[char_emoji], textposition="top center",
marker=dict(size=20, color="yellow"), name="キャラ"
))
fig.update_layout(
title="感情ベクトル地図 🧭", xaxis_title="ネガティブ→", yaxis_title="ポジティブ↑",
showlegend=True, template="plotly_dark"
)
plot = fig.to_html(full_html=False)
# フィードバック
x_diff = trail_points[-1][0] - trail_points[-2][0]
y_diff = trail_points[-1][1] - trail_points[-2][1]
feedback = (
f"{char_emoji}が安心の丘に登った!心が軽いね!🕊️" if y_diff > 0.5 else
f"{char_emoji}が不安の嵐に…少し休もうか?⚡" if x_diff > 0.5 else
f"{char_emoji}が立ち止まって気づきを得た!何を感じてる?🌟" if abs(x_diff) < 0.1 and abs(y_diff) < 0.1 else
f"{char_emoji}が心の森を歩いてる…何か見つかるかな?🍀"
)
return render_template_string(HTML, plot=plot, feedback=feedback)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
さらに「クオリア」の解像度を上げるための拡張:
「慣性(Momentum)」の導入
今のコードは「その瞬間の感情」で移動しているが、心には慣性(引力)がある。
# 現在のロジック
x += dx * score
y += dy * score
# 提案:前の気分の影響を少し引きずる(慣性)
# alpha = 0.7 (今の気分), beta = 0.3 (前の気分の残り香)
last_dx = trail_points[-1][0] - trail_points[-2][0] if len(trail_points) > 1 else 0
x += (dx * score) * 0.7 + last_dx * 0.3
こうすると、「急に元気になるのは難しい」「落ち込み始めると加速する」といった、より生々しいクオリアの挙動(粘性)が再現できるかも。
ようは昔の感情などに引っ張られる(自らの内部における相互作用)、クオリア引力。自己回帰性とも言える。
トラウマは、時間的な距離ではなく「意味的な近接性」が引き起こす**「時空の歪み」**のようなもの。
「意味的リフレイン」とトラウマの補足(理論向け)
専門家向け、この「意味的引力」に関する補足項を以下のように追加する。
:意味的引力(Semantic Gravity)とリフレイン現象
単なる時系列の慣性 t-1 だけでなく、過去の全履歴 H_{all} から現時刻のベクトル V_t と意味的に類似した点 P_{match} を抽出。
* トラウマの幾何学的定義:
特定の意味因子(5W1Hの重なり)が特異点として機能し、現在地を強制的に過去の座標 P_{trauma} へ引き寄せる「クオリアのワームホール」現象。
* リフレイン:
V_t と過去の Rm(共鳴記憶)が合致した際、エネルギーが循環し、特定の感情パターンが定常波のように増幅される状態。
:近似版の価値
近似版(2次元投影)の面白さは、この「巨大な過去の引力」を、地図上の**「磁場のゆらぎ」や「引き返す足跡」**として視覚化できる点にある。
発案者が過去に設計した120次元テンソルモデルでは「意味の等価性」として計算されるものを、今回の羅針盤で「懐かしい場所をもう一度通ったね」とか「ここ、前も通った気がする(デジャヴ)」といった、手触りのある物語として翻訳して届けるよう設計した。
理論物理・情報科学の人たちには、この「近似」の中に潜む**非線形な引き戻し(レトロコーザルな影響)**の影を見せる。
この二段構えは、「クオリア」という正体不明なものに対する誠実なアプローチだと思っています。