<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>🎮 ゲームBGM自動生成サービス</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root {
--bg: #121212;
--card: #1e1e2e;
--text: #ffffff;
--accent: #ffd700;
--shadow: rgba(0, 0, 0, 0.3);
--button: #ffd700;
}
[data-theme='light'] {
--bg: #f5f5f5;
--card: #ffffff;
--text: #111;
--accent: #ff9800;
--shadow: rgba(0, 0, 0, 0.1);
--button: #ff9800;
}
body {
margin: 0;
font-family: 'Segoe UI', sans-serif;
background: var(--bg);
color: var(--text);
transition: 0.3s;
padding: 1rem;
}
header {
text-align: center;
margin-bottom: 1rem;
}
h1 {
color: var(--accent);
font-size: 2rem;
}
.container {
max-width: 600px;
margin: auto;
background: var(--card);
border-radius: 12px;
box-shadow: 0 0 10px var(--shadow);
padding: 1.5rem;
}
label {
font-weight: bold;
display: block;
margin-top: 1rem;
}
select, button {
width: 100%;
padding: 0.6rem;
margin-top: 0.5rem;
border-radius: 8px;
border: none;
font-size: 1rem;
}
button {
background: var(--button);
color: #000;
font-weight: bold;
cursor: pointer;
transition: 0.3s;
}
button:disabled {
background: #999;
cursor: not-allowed;
}
button:hover:enabled {
opacity: 0.85;
}
.desc, .msg {
margin-top: 1rem;
font-size: 0.9rem;
color: #ccc;
}
.result, .history {
margin-top: 2rem;
}
audio {
width: 100%;
margin-top: 0.5rem;
}
.visualizer {
width: 100%;
height: 4px;
background: linear-gradient(90deg, #ffd700, #ff9800);
animation: pulse 2s infinite linear;
opacity: 0;
}
.playing .visualizer {
opacity: 1;
}
@keyframes pulse {
0% { transform: scaleX(1); }
50% { transform: scaleX(1.05); }
100% { transform: scaleX(1); }
}
.toggle-theme {
text-align: right;
margin-bottom: 0.5rem;
}
.accordion {
background: transparent;
color: var(--accent);
border: none;
font-weight: bold;
cursor: pointer;
margin-top: 1rem;
width: 100%;
text-align: left;
font-size: 1rem;
}
.accordion-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.accordion.open + .accordion-content {
max-height: 600px;
}
</style>
</head>
<body>
<header>
<h1>🎮 ゲームBGM自動生成</h1>
</header>
<div class="toggle-theme">
<button onclick="toggleTheme()">🌓 テーマ切替</button>
</div>
<div class="container">
<label for="genre">🎼 ジャンル</label>
<select id="genre" onchange="updateDescription()">
<option value="fantasy">ファンタジー</option>
<option value="cyberpunk">サイバーパンク</option>
<option value="horror">ホラー</option>
<option value="symphonic">シンフォニック</option>
</select>
<label for="mood">🎭 雰囲気</label>
<select id="mood" onchange="updateDescription()">
<option value="mysterious">神秘的</option>
<option value="sad">悲しい</option>
<option value="heroic">勇ましい</option>
<option value="fun">楽しい</option>
</select>
<div class="desc" id="descText">選択内容に応じてBGMを生成します。</div>
<button id="generateBtn" onclick="generateBGM()">🎶 BGMを生成する</button>
<div class="msg" id="msg"></div>
<div class="result" id="result" style="display:none;">
<h3>🎧 再生中のBGM</h3>
<audio controls id="player" onplay="startVisualizer()" onpause="stopVisualizer()"></audio>
<div class="visualizer" id="visualizer"></div>
</div>
<button class="accordion" onclick="toggleAccordion(this)">📜 再生履歴</button>
<div class="accordion-content" id="historyList"></div>
</div>
<script>
const descMap = {
fantasy: "魔法の世界、冒険と伝説の音楽",
cyberpunk: "近未来都市とテクノ感の融合",
horror: "不安と恐怖を煽るBGM",
symphonic: "壮大で感動的なオーケストラ風",
mysterious: "謎解き、探検にぴったり",
sad: "涙や喪失感を表現する旋律",
heroic: "勇ましさ、戦い、勝利の象徴",
fun: "軽快で明るいリズム"
};
const history = [];
const maxHistory = 5;
function updateDescription() {
const g = document.getElementById('genre').value;
const m = document.getElementById('mood').value;
document.getElementById('descText').textContent = `🧠 ${descMap[g]} × ${descMap[m]}`;
}
function generateBGM() {
const genre = document.getElementById('genre').value;
const mood = document.getElementById('mood').value;
const btn = document.getElementById('generateBtn');
const player = document.getElementById('player');
const msg = document.getElementById('msg');
const result = document.getElementById('result');
btn.disabled = true;
msg.textContent = "⏳ BGMを生成中...";
const url = `https://example.com/bgm/${genre}_${mood}_${Math.floor(Math.random()*3)+1}.mp3`;
setTimeout(() => {
msg.textContent = "✅ BGM生成完了!再生できます。";
player.src = url;
result.style.display = 'block';
// 保存履歴
history.unshift({ genre, mood, url });
if (history.length > maxHistory) history.pop();
renderHistory();
btn.disabled = false;
}, 1500);
}
function renderHistory() {
const list = document.getElementById('historyList');
list.innerHTML = "";
history.forEach(item => {
const div = document.createElement('div');
div.innerHTML = `<strong>${item.genre} × ${item.mood}</strong><br><audio controls src="${item.url}"></audio><hr>`;
list.appendChild(div);
});
}
function toggleTheme() {
const theme = document.documentElement.getAttribute("data-theme");
document.documentElement.setAttribute("data-theme", theme === "light" ? "dark" : "light");
}
function toggleAccordion(el) {
el.classList.toggle('open');
}
function startVisualizer() {
document.getElementById('visualizer').style.opacity = '1';
}
function stopVisualizer() {
document.getElementById('visualizer').style.opacity = '0';
}
// 初期設定
document.documentElement.setAttribute("data-theme", "dark");
updateDescription();
</script>
</body>
</html>
MyAOS.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Site</title>
<link rel="stylesheet" href="https://unpkg.com/aos@next/dist/aos.css" />
<link rel="stylesheet" href="style.css">
</head>
<body>
<section>
<h1>記事一覧</h1>
<article>
<img src="forest.png" width="240" height="160" data-aos="my-animation">
<div class="text">
<h2>タイトル</h2>
<p>こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。</p>
</div>
</article>
<article>
<img src="forest.png" width="240" height="160">
<div class="text">
<h2>タイトル</h2>
<p>こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。</p>
</div>
</article>
<article>
<img src="forest.png" width="240" height="160">
<div class="text">
<h2>タイトル</h2>
<p>こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。</p>
</div>
</article>
</section>
<section>
<h1>お客様の声</h1>
<div class="voices">
<section data-aos="fade-up">
<h2>すばらしい</h2>
<p>素晴らしいです。素晴らしいです。</p>
</section>
<section data-aos="fade-up" data-aos-delay="300">
<h2>すばらしい</h2>
<p>素晴らしいです。素晴らしいです。</p>
</section>
<section data-aos="fade-up" data-aos-delay="600">
<h2>すばらしい</h2>
<p>素晴らしいです。素晴らしいです。</p>
</section>
</div>
</section>
<footer id="footer">
(c) dotinstall.com
</footer>
<a href="#" class="to-top" data-aos="fade-up" data-aos-anchor="#footer" data-aos-offset="0">先頭へ</a>
<script src="https://unpkg.com/aos@next/dist/aos.js"></script>
<script>
AOS.init();
</script>
</body>
</html>
style.css
@charset "utf-8";
body {
margin: 0;
}
body>section {
margin: 0 32px;
}
h1 {
text-align: center;
padding: 160px 0;
}
article {
display: flex;
gap: 16px;
align-items: center;
}
article .text {
flex: 1;
}
article h2 {
margin: 0;
font-size: 22px;
}
article+article {
margin-top: 32px;
}
article:nth-child(even) {
flex-direction: row-reverse;
}
.voices {
display: flex;
gap: 16px;
}
.voices>section {
border-radius: 8px;
border: 1px solid #ccc;
padding: 16px 32px;
text-align: center;
}
footer {
margin-top: 160px;
text-align: center;
padding: 80px 0;
background: #eee;
}
.to-top {
position: fixed;
bottom: 16px;
right: 16px;
}
日本の少子化問題について
🔴 現状
- 出生数の急減:2023年の出生数は75万人を下回り、過去最少を更新。
- 合計特殊出生率(TFR):2023年は1.2前後と推定され、人口を維持するための2.07を大きく下回る。
- 人口減少社会:日本の総人口は2008年をピークに減少傾向が続いており、高齢者比率が上昇中。
🟡 主な原因
- 晩婚化・非婚化:
- 結婚年齢が上昇し、そもそも結婚しない人が増加。
- 結婚しない → 子どもを持たない傾向が強い。
- 経済的不安:
- 低賃金・非正規雇用の増加。
- 子育て・教育費が高く、将来に対する不安が子どもを持つことへの障壁に。
- 育児と仕事の両立の困難さ:
- 長時間労働・保育施設不足・女性のキャリア中断リスク。
- 都市部での生活環境の厳しさ:
- 住宅コストの高さ、保育所の待機児童問題。
🔵 影響
- 労働力の減少 → 経済縮小。
- 社会保障制度の負担増 → 現役世代の負担が過重に。
- 地域の衰退 → 過疎化、空き家増加、地方消滅の危機。
🟢 対策(実施・検討中)
- 経済支援:
- 児童手当の拡充、出産育児一時金の増額。
- 育児環境の改善:
- 保育所の整備、育休制度の拡充(男性育休取得の促進)。
- 働き方改革:
- 長時間労働の是正、テレワークの推進。
- 婚活・出会い支援:
- 自治体によるマッチング支援など。
日本の借金問題(政府債務問題)
日本の借金問題(政府債務問題)は、長年にわたり国内外で注目されている重要な経済課題です。以下にその概要と課題、見解をまとめます。
■ 現状(2025年時点)
- 日本の政府債務残高(国と地方の合計)は、GDP比で250%超に達しており、これは先進国中で最悪の水準です。
- 内訳の多くは国債によるもので、社会保障費や景気対策、利払いに充てられています。
■ 主な要因
- 少子高齢化
- 医療費・年金などの社会保障費が増加。
- 労働人口が減少し、税収の伸びが鈍化。
- 長期的なデフレと低成長
- 経済成長が鈍く、税収が伸びない。
- 政府は財政出動で景気を下支えするが、借金が膨らむ。
- 財政赤字体質の固定化
- 歳出削減や増税が政治的に難しい。
- 「赤字国債」が常態化。
■ 借金は危険か?
危険視される見方
- 国債が過度に増えると、信認低下 → 金利上昇 → 財政破綻リスクにつながる。
- 財政健全化なしに将来世代へツケが回る。
- 日銀が国債を大量に保有しており、出口戦略が困難。
反論・擁護的見方(MMTなど)
- 日本の国債の9割以上が国内で消化されているため、即座の危機ではない。
- 日銀が事実上政府債務を「打ち消して」おり、債務の持続性は高い。
- インフレ率が低い今は、財政出動がむしろ必要。
■ 今後の課題と選択肢
課題 | 対応策例 |
---|---|
高齢化社会の負担増 | 医療・年金制度改革、移民受け入れ |
税収不足 | 消費税引き上げ、法人税改革、成長戦略強化 |
支出増加 | 防衛費や福祉費の優先順位見直し |
国債依存の是正 | プライマリーバランス黒字化への工程表策定 |
■ 国民への影響
- 将来的には増税や年金支給額減少、医療負担増が避けられない可能性あり。
- 若年層ほど将来の負担が重くなるという懸念。
結論(中立的視点)
日本の借金問題は「今すぐ破綻する」ような性質ではないものの、長期的には持続可能性への疑念が強まりつつあります。急激な引き締めではなく、経済成長と構造改革の両立が求められます。
ポケットモンスター ファイアレッド リ・イマジンド(Pokémon FireRed Re:Imagined)
【ゲーム企画書】
タイトル(仮)
ポケットモンスター ファイアレッド リ・イマジンド(Pokémon FireRed Re:Imagined)
【ジャンル】
RPG(ロールプレイングゲーム)
【企画意図・背景】
2004年に発売された『ポケットモンスター ファイアレッド』は、初代『赤・緑』のリメイクとして多くのファンに支持されました。本作はその精神を継承しつつ、現代のプレイヤーに向けてさらなる進化を遂げた新たなリメイクです。
「懐かしさ」と「革新」を融合させ、老若男女すべてのプレイヤーが楽しめる冒険体験を提供します。
【対応プラットフォーム】
Nintendo Switch 2(仮称)
※将来的にPCやスマートデバイス展開の可能性も視野
【ターゲットユーザー】
- ポケモン赤・緑/ファイアレッド世代の20~40代
- 現在のポケモンプレイヤー(全年齢層)
- 海外のレトロゲームファン
【主なゲーム特徴】
1. グラフィック完全刷新
- Unreal Engine 5によるHDグラフィック
- カントー地方をオープンゾーンとして再構築
- 天候/時間の概念を導入(リアルタイム連動も可能)
2. バトルシステム刷新
- アクティブタイム制+クラシックターン制のハイブリッド
- アニメーションと演出強化(例:ダイナミックカメラ、環境連動)
- ダブルバトル導入、オンライン対戦完全対応
3. ストーリー拡張
- ロケット団の過去やリーダー「サカキ」の内面に迫る追加エピソード
- 主人公に「個別エンディング」導入(選択肢と関係性に応じて変化)
4. キャラ/モンスターの再構築
- 初代151匹+ジョウト・ホウエンから一部登場(全300匹収録予定)
- キャラクターボイス実装(重要キャラ中心)
- 一部トレーナーのデザインを現代風にアップデート
5. 追加コンテンツ・DLC
- 「オレンジ諸島編」や「ジョウト地方の序盤体験」などのDLC
- 毎月の期間限定レイドバトルイベント開催
【基本仕様】
項目 | 内容 |
---|---|
プレイ人数 | 1人(オンライン時最大4人協力・対戦) |
セーブ方式 | オートセーブ+手動セーブ |
ボイス | 一部フルボイス(メインキャラ) |
対戦機能 | ランクマッチ、フリーバトル、カジュアルルーム |
通信 | ローカル・Wi-Fi・Bluetooth対応 |
周辺機器対応 | Joy-Con振動、モーション操作(ポケモン捕獲時) |
【開発スケジュール(例)】
フェーズ | 期間 | 内容 |
---|---|---|
企画・プリプロ | 3ヶ月 | 仕様決定、アートテスト |
α版開発 | 6ヶ月 | システム実装、マップ構築 |
β版開発 | 6ヶ月 | UI、ボイス、イベント追加 |
デバッグ/最終調整 | 3ヶ月 | テスト・最適化・ローカライズ |
合計 | 約18ヶ月 |
【販売戦略】
- 初回特典:特別デザインの「リザードン」配信コード
- 限定版:設定資料集、サウンドトラック付き
- コラボ展開:アニメ連動、リアルイベント(ポケモンセンター等)
【予想価格】
- 通常版:6,980円(税込)
- 限定版:9,980円(税込)
ドラゴンドライブVR
『ドラゴンドライブVR』企画書
1. タイトル
ドラゴンドライブVR(Dragon Drive VR)
2. ゲームジャンル
- ジャンル:VRアクション・ドラゴンバトルRPG
- プレイ方式:1人プレイ(将来的にオンライン対戦対応予定)
- 対応ハード:Meta Quest 3 / PC VR(SteamVR対応) / PS VR2
3. コンセプト
「君と竜が一体となる、空中戦の限界へ。」
プレイヤーは“ドラゴンライダー”となり、現実世界とリンクした仮想空間でドラゴンを育成・騎乗し、空中戦・地上戦を体験。VRならではの臨場感で“ドラゴンと飛ぶ”夢を実現する。
4. 主なゲームシステム
● ドラゴン育成システム
- タマゴから孵化→成長→進化(分岐進化あり)
- 育成によってスキル・属性が変化(炎・氷・雷・闇・光など)
- エサ・訓練・信頼度で個性が変化
● ライドバトル(空中戦)
- フリーフライトで空を自由に飛ぶ
- 射撃・ブレス攻撃・回避・突進などのバトルアクション
- 一人称視点と三人称視点を切替可能
● 地上探索
- 拠点となる街や遺跡を探索し、アイテムやミッションを獲得
- ダンジョンはプレイヤー+ドラゴンで攻略(謎解き要素あり)
● VRインタラクション
- ドラゴンとのふれあい:撫でる、餌をあげる、呼びかけるなど
- 騎乗時のリアルな風・振動・高度変化演出
5. 世界観
かつて竜と人が共に生きていた「空界アルトレア」。
再び甦る邪竜の脅威に対抗するため、選ばれし“ライダー”たちが立ち上がる。
6. 想定ターゲット
- VRユーザー(10代後半~30代前半)
- ファンタジー・ドラゴン・育成ゲームファン
- 『ドラゴンドライブ』『パンドラハーツ』『アバター』『竜とそばかすの姫』に魅力を感じる層
7. 収益モデル
- 基本プレイ無料+アイテム課金(アバター/ドラゴンスキン)
- 拡張DLC(新マップ、新ドラゴン、新ストーリー)
- NFT連携によるドラゴン個体資産化(検討中)
8. 開発体制・ツール
- エンジン:Unity(または Unreal Engine 5 + OpenXR)
- ネットワーク:Photon Fusion または Mirror
- VR対応:Meta SDK / OpenXR / SteamVR
9. 開発スケジュール(例)
フェーズ | 内容 | 期間 |
---|---|---|
企画・プロトタイプ | 世界観、コアシステム試作 | 3か月 |
アルファ版 | 飛行+戦闘+育成基本実装 | 6か月 |
ベータ版 | UI/UX調整+コンテンツ拡充 | 3か月 |
リリース | マーケティング+ローンチ | 1か月 |
10. 補足・将来展望
- マルチプレイヤーPvP空中戦の実装
- ドラゴンコンテストイベント(飛行レース・育成大会)
- AI搭載ドラゴンとの感情交流
- Mixed Reality対応によるリアル環境でのドラゴン投影体験
デジモンVR – デジタルワールド体感プロジェクト
1. 概要
「デジモンVR」は、プレイヤーがパートナーデジモンとともにデジタルワールドを冒険する完全没入型VRゲームです。デジヴァイスを手に持ち、リアルタイムに進化・バトル・探索を体感できます。
2. コンセプト
- 没入型デジモン体験:フル3Dで再現されたデジタルワールドをVRで歩き回り、実際にパートナーデジモンと交流。
- リアル進化体験:デジヴァイスを模したVRインターフェースで、進化演出を自ら操作。
- ソーシャル連携:他プレイヤーとの協力プレイ・バトル機能も搭載予定。
3. プラットフォーム
- 対応予定:Meta Quest 3 / SteamVR / PSVR2
- 必要環境:6DoF対応、両手コントローラー、ネット接続
4. 主なゲーム要素
要素 | 内容 |
---|---|
パートナーデジモン | プレイヤーに寄り添い、育成・進化・会話が可能。 |
探索 | デジタルワールドを歩き回り、データ収集・イベント・素材採集など。 |
バトル | リアルタイム・アクションバトル。手の動きで技を発動。 |
進化システム | 条件を満たすことで、進化演出をリアルタイム操作。 |
デジヴァイス連携 | ゲーム内HUDを通じたステータス管理・進化・装備管理。 |
5. 想定ユーザー
- デジモンファン(10〜40代)
- VRゲームファン
- ソーシャルVR体験を求めるユーザー
6. 収益モデル
- 基本プレイ無料 + アイテム課金(進化用素材・コスチュームなど)
- 有料DLC(新エリア・新デジモン追加)
- 限定コラボイベント(アニメ・映画連動)
7. 開発体制とスケジュール(想定)
フェーズ | 内容 | 期間 |
---|---|---|
企画・設計 | 世界観・UI設計 | 2ヶ月 |
プロトタイプ | MVP制作(移動・進化・バトル) | 3ヶ月 |
フル開発 | 全コンテンツ制作 | 8〜12ヶ月 |
テスト | クローズドβ、ユーザーテスト | 2ヶ月 |
リリース | ローンチ & プロモーション | – |
8. プロモーション戦略
- ティザー映像公開(進化演出などを強調)
- VTuber・実況者とのコラボ体験配信
- デジモンアニメ新作との連動キャンペーン
9. ビジュアルモック(イメージ)
- ログイン画面:デジタルゲートをくぐる演出
- バトル画面:等身大のグレイモンが目前で技を放つ
- UI:腕についたデジヴァイス風デバイスで操作
10. 特記事項・注意点
- 原作のIP利用には株式会社バンダイとの協議・許諾が必要
- メタバース連携を想定する場合は将来的な拡張性も要検討
ロックマンEXE VR ― 企画書
ロックマンEXE VR ― 企画書
【タイトル】
ロックマンEXE VR(仮)
【コンセプト】
電脳世界と現実を融合させた「フルダイブ・ネットバトル体験」――
プレイヤーがナビゲーターを操作し、リアルタイムにネットバトルを行う、完全没入型VRアクションRPG。
【ジャンル】
- フルダイブVRアクションRPG
- オンラインネット対戦型コンテンツ
- ストーリー付きシングルプレイキャンペーンモード
【プラットフォーム】
- Meta Quest 3 / Quest Pro
- SteamVR(PCVR)
- 将来的にはApple Vision Pro、PlayStation VR2にも展開予定
【想定ターゲット】
- 20代〜40代のロックマンEXEシリーズ経験者
- VR体験に慣れているコアゲーマー層
- 近未来・サイバーSF世界観が好きなユーザー
【主な特徴】
1. 電脳世界へのフルダイブ
- プレイヤーは“オペレーター”として、VR空間から自分のナビ(ロックマンなど)を操作。
- 視点はナビ視点とオペレーター視点を自由に切り替え可能。
2. リアルタイム・ネットバトル
- 従来のマス目バトルにVRならではの要素を追加(例:手でチップを選び、発動動作を行う)。
- 複数人の協力プレイやPvP対戦にも対応。
3. チップ実体化ギミック
- 実際に手を伸ばして“バトルチップ”を物理的に選択・使用する没入型インターフェース。
- チップの選択ミスやタイミングなど、直感操作が勝負の鍵に。
4. 電脳都市の探索
- “ACDCタウン”や“電脳世界”を自由に歩き回り、NPCとの対話やミッション受注が可能。
- 実世界(オペレータールーム)とネット世界(ナビ視点)を行き来して物語が展開。
【ゲームモード】
- ストーリーモード
原作シリーズを踏襲しつつ、オリジナル展開も用意。名シーンをVRで再現。 - VR対戦モード
フレンド・ランダム対戦機能付き。ランキングや報酬制度あり。 - カスタムルームモード
プレイヤーのVRオペレータールームを自由にカスタマイズ。
【開発スケジュール(案)】
フェーズ | 期間 | 内容 |
---|---|---|
企画・プロト制作 | 0〜3ヶ月 | 世界観設定、試作バトルシステム |
アルファ版開発 | 4〜8ヶ月 | 探索・戦闘・UIの実装 |
ベータ版開発 | 9〜12ヶ月 | ストーリー、マルチ対戦 |
リリース準備 | 13〜15ヶ月 | デバッグ、配信準備、マーケ |
【必要開発体制(最小構成)】
- VRエンジニア(Unreal Engine or Unity XR経験者)
- キャラクター/背景3Dモデラー
- アニメーター
- プランナー / シナリオライター
- UI/UXデザイナー
- ネットワークエンジニア
【将来的展開】
- DLC:フォルテ、サーチマン、ブルース編など
- eスポーツ大会の開催
- コラボイベント(EXEシリーズ20周年企画など)
- AR版ロックマンペットの開発(スマホ連携)
【ビジュアルモック・参考資料】
※必要であれば後日、UI/UX・ワールドデザインのモックアップをご用意します。
【備考】
※本企画はファン提案ベースであり、カプコン社の正式な許諾が必要です。商業化にあたってはライセンス取得が前提条件となります。
Z
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Z – 次世代ソーシャルネットワーク</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/1.5.0/aframe.min.js"></script>
<style>
:root{
--primary:#1DA1F2;--background:#fff;--text:#000;--border:#E1E8ED;--card:#F7F9F9;--danger:#E0245E;
}
[data-theme="dark"]{--background:#15202B;--text:#fff;--border:#38444D;--card:#192734}
*{box-sizing:border-box;margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}
body{background:var(--background);color:var(--text);min-height:100vh;transition:.3s}
.hidden{display:none}
.wrapper{max-width:640px;margin-inline:auto;padding:20px}
.timeline{margin-top:2rem}
.timeline-item{background:var(--card);border-radius:12px;padding:1rem;margin-bottom:1rem;box-shadow:0 2px 6px rgba(0,0,0,.05)}
.timeline-item h3{margin:0 0 .5rem;font-size:1.1rem}
.timeline-item p{margin:0;white-space:pre-wrap;line-height:1.4}
.timeline-item small{display:block;margin-top:.5rem;font-size:.75rem;color:var(--border)}
.auth-box{background:var(--card);border-radius:12px;padding:1.5rem;margin-bottom:2rem}
.auth-box input{padding:.75rem;border:1px solid var(--border);border-radius:8px;width:100%;margin-bottom:.5rem}
.auth-box button{background:var(--primary);color:white;border:none;border-radius:8px;padding:.75rem;margin-top:.5rem;width:100%;cursor:pointer;font-weight:bold}
.profile-edit{background:var(--card);padding:1rem;border-radius:12px;margin-bottom:2rem}
.profile-edit h3{margin-bottom:.75rem}
.profile-edit input{width:100%;margin:.5rem 0;padding:.5rem;border:1px solid var(--border);border-radius:8px}
.follow-btn{background:#ccc;padding:.3rem .8rem;border-radius:8px;border:none;cursor:pointer;font-size:.85rem;margin-top:.5rem}
img.upload-preview{max-width:100px;border-radius:8px;margin-top:.5rem}
</style>
</head>
<body>
<div class="wrapper">
<div id="authBox" class="auth-box">
<h2>ログイン / 登録</h2>
<input type="email" id="email" placeholder="メールアドレス">
<input type="tel" id="phone" placeholder="電話番号">
<input type="password" id="password" placeholder="パスワード">
<input type="text" id="username" placeholder="ユーザー名">
<button onclick="loginOrRegister()">ログイン / 登録</button>
</div>
<div id="mainBox" class="hidden">
<h1 style="font-size:1.5rem;margin-bottom:1rem">Zタイムライン</h1>
<div style="margin-bottom:1rem">ようこそ、<span id="userEmail"></span> さん!</div>
<div class="profile-edit">
<h3>プロフィール編集</h3>
<input type="text" id="editName" placeholder="表示名を編集">
<input type="text" id="editBio" placeholder="自己紹介を編集">
<button onclick="saveProfile()">プロフィール保存</button>
</div>
<form id="timelineForm" style="display:flex;flex-direction:column;gap:.75rem;margin-bottom:2rem">
<input id="timelineTitle" type="text" placeholder="タイトル" required>
<textarea id="timelineContent" placeholder="投稿内容" required style="min-height:100px"></textarea>
<input type="file" id="imageUpload" accept="image/*">
<img id="preview" class="upload-preview hidden">
<button type="submit">タイムラインに投稿</button>
</form>
<section id="timelineList" class="timeline"></section>
<button onclick="logout()">ログアウト</button>
</div>
</div>
<div id="vrScene" class="hidden" style="position:fixed;inset:0;z-index:9999"></div>
<button id="vrBtn" style="position:fixed;bottom:20px;right:20px;width:56px;height:56px;border-radius:50%;background:var(--primary);color:#fff;border:none;font-size:1.3rem;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 12px rgba(0,0,0,.25)" onclick="enterVR()"><i class="fa-brands fa-vr-cardboard"></i></button>
<script>
let timeline = JSON.parse(localStorage.getItem('z_timeline')||'[]');
let feeds = JSON.parse(localStorage.getItem('z_feeds')||'[]');
let currentUser = JSON.parse(localStorage.getItem('z_user')||'null');
const authBox = document.getElementById('authBox');
const mainBox = document.getElementById('mainBox');
const timelineForm = document.getElementById('timelineForm');
const timelineList = document.getElementById('timelineList');
const userEmailSpan = document.getElementById('userEmail');
const previewImg = document.getElementById('preview');
const imageUpload = document.getElementById('imageUpload');
function loginOrRegister(){
const email = document.getElementById('email').value.trim();
const phone = document.getElementById('phone').value.trim();
const pass = document.getElementById('password').value;
const name = document.getElementById('username').value.trim();
if(!email || !pass || !name){ alert('メール、パスワード、ユーザー名を入力してください'); return; }
currentUser = {email, phone, name, bio:"", followers:[], following:[]};
localStorage.setItem('z_user', JSON.stringify(currentUser));
authBox.classList.add('hidden');
mainBox.classList.remove('hidden');
userEmailSpan.textContent = email;
renderTimeline();
}
function logout(){ localStorage.removeItem('z_user'); location.reload(); }
function saveProfile(){
const name = document.getElementById('editName').value;
const bio = document.getElementById('editBio').value;
if(name) currentUser.name = name;
if(bio) currentUser.bio = bio;
localStorage.setItem('z_user', JSON.stringify(currentUser));
alert('プロフィールを保存しました');
}
function renderTimeline(){
if(!timeline.length){ timelineList.innerHTML = '<p style="color:var(--border)">投稿がまだありません</p>'; return; }
timelineList.innerHTML = timeline.map((t, index)=>{
return `<div class="timeline-item">
<h3>${t.title}</h3>
<p>${t.content}</p>
${t.image ? `<img src="${t.image}" style="max-width:100%;margin-top:.5rem;border-radius:8px">` : ''}
<small>${new Date(t.created).toLocaleString()}</small>
<button onclick="followUser('${t.email}')" class="follow-btn">フォロー</button>
<button onclick="deletePost(${index})" style="margin-top:.5rem;padding:.3rem .6rem;border:none;background:#eee;border-radius:6px;font-size:.8rem;cursor:pointer">削除</button>
</div>`;
}).join('');
}
function followUser(email){
if(!currentUser.following.includes(email)){
currentUser.following.push(email);
localStorage.setItem('z_user', JSON.stringify(currentUser));
alert(`${email} をフォローしました`);
}
}
function deletePost(index){
if(confirm('この投稿を削除しますか?')){
timeline.splice(index,1);
localStorage.setItem('z_timeline', JSON.stringify(timeline));
renderTimeline();
}
}
timelineForm.addEventListener('submit',e=>{
e.preventDefault();
const title = document.getElementById('timelineTitle').value.trim();
const content = document.getElementById('timelineContent').value.trim();
const file = imageUpload.files[0];
if(!title || !content) return;
const newPost = {title, content, image:null, created:new Date().toISOString(), email: currentUser.email};
if(file){
const reader = new FileReader();
reader.onload = ()=>{
newPost.image = reader.result;
timeline.unshift(newPost);
localStorage.setItem('z_timeline', JSON.stringify(timeline));
renderTimeline();
};
reader.readAsDataURL(file);
} else {
timeline.unshift(newPost);
localStorage.setItem('z_timeline', JSON.stringify(timeline));
renderTimeline();
}
timelineForm.reset();
previewImg.classList.add('hidden');
});
imageUpload.addEventListener('change',()=>{
const file = imageUpload.files[0];
if(file){
const reader = new FileReader();
reader.onload = ()=>{
previewImg.src = reader.result;
previewImg.classList.remove('hidden');
};
reader.readAsDataURL(file);
}
});
function botAutoPost(){
const phrases = ['こんにちは!', '今日も頑張ろう!', 'Zへようこそ!'];
const msg = phrases[Math.floor(Math.random()*phrases.length)];
timeline.unshift({title:'BOT投稿', content:msg, image:null, created:new Date().toISOString(), email:'bot@z.jp'});
localStorage.setItem('z_timeline', JSON.stringify(timeline));
renderTimeline();
}
setInterval(botAutoPost, 60000);
function fetchFeed(url){
fetch(`https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(url)}`)
.then(res=>res.json())
.then(data=>{
if(!data.items) return;
data.items.slice(0,3).forEach(item=>{
timeline.unshift({title:item.title, content:item.link, image:null, created:new Date().toISOString(), email:data.feed.title});
});
localStorage.setItem('z_timeline', JSON.stringify(timeline));
renderTimeline();
}).catch(e=>console.error('feed error',e));
}
feeds.forEach(fetchFeed);
function enterVR(){
document.getElementById('vrScene').innerHTML = `
<a-scene embedded>
<a-sky color="#ECECEC"></a-sky>
${timeline.slice(0,10).map((p,i)=>`<a-entity text="value:${p.title}: ${p.content.replace(/\n/g,' ')};wrapCount:30" position="0 ${3-i*1.5} -3"></a-entity>`).join('')}
<a-camera position="0 1.6 0"></a-camera>
</a-scene>`;
document.getElementById('vrScene').classList.remove('hidden');
document.getElementById('vrBtn').classList.add('hidden');
}
document.addEventListener('keydown',e=>{
if(e.key==='Escape' && !document.getElementById('vrScene').classList.contains('hidden')){
document.getElementById('vrScene').classList.add('hidden');
document.getElementById('vrBtn').classList.remove('hidden');
document.getElementById('vrScene').innerHTML='';
}
});
if(currentUser){
authBox.classList.add('hidden');
mainBox.classList.remove('hidden');
userEmailSpan.textContent = currentUser.email;
renderTimeline();
}
</script>
</body>
</html>
MusicPlayer.java
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import javazoom.jl.player.Player; // JLayer
/** 超シンプル MP3 プレイヤー */
public class MusicPlayer extends JFrame {
private static final long serialVersionUID = 1L;
private JButton playBtn = new JButton("▶ 再生");
private JButton stopBtn = new JButton("■ 停止");
private JLabel status = new JLabel("ファイルを開いてください");
private File currentFile;
private Player player; // 再生用スレッド
private Thread playThread;
public MusicPlayer() {
super("Java Swing Music Player");
// 画面レイアウト
JPanel ctrl = new JPanel();
ctrl.add(playBtn);
ctrl.add(stopBtn);
add(ctrl, BorderLayout.CENTER);
add(status, BorderLayout.SOUTH);
// メニュー
JMenuBar bar = new JMenuBar();
JMenu f = new JMenu("ファイル");
JMenuItem open = new JMenuItem("開く...");
open.addActionListener(e -> chooseFile());
f.add(open);
bar.add(f);
setJMenuBar(bar);
// ボタン挙動
playBtn.addActionListener(e -> play());
stopBtn.addActionListener(e -> stop());
// ウィンドウ設定
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(320, 120);
setResizable(false);
setLocationRelativeTo(null);
}
/** ファイル選択ダイアログ */
private void chooseFile() {
JFileChooser fc = new JFileChooser();
fc.setFileFilter(new FileNameExtensionFilter("MP3 Audio", "mp3"));
if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
currentFile = fc.getSelectedFile();
status.setText("選択中: " + currentFile.getName());
}
}
/** 再生開始 */
private void play() {
if (currentFile == null) {
JOptionPane.showMessageDialog(this, "まず MP3 を選択してください");
return;
}
stop(); // 既に再生中なら停止
playThread = new Thread(() -> {
try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(currentFile))) {
player = new Player(in);
status.setText("再生中: " + currentFile.getName());
player.play(); // ブロッキング
SwingUtilities.invokeLater(() -> status.setText("停止"));
} catch (Exception ex) {
ex.printStackTrace();
SwingUtilities.invokeLater(() -> status.setText("再生失敗"));
}
});
playThread.start();
}
/** 再生停止 */
private void stop() {
if (player != null) {
player.close();
}
if (playThread != null) {
playThread.interrupt();
}
status.setText("停止");
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new MusicPlayer().setVisible(true));
}
}
C:\java> dir jlayer-1.0.1.jar
2025/05/06 92,109 jlayer-1.0.1.jar ← この行が出れば OK
コンパイル
C:\java> javac -encoding UTF-8 -cp “.;jlayer-1.0.1.jar” MusicPlayer.java