<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>GitHub風 - SampleRepo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap & FontAwesome -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" rel="stylesheet">
<style>
body {
background: #f6f8fa;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
.repo-header { background: #fff; padding: 20px; border: 1px solid #ddd; margin-bottom: 10px; }
.nav-tabs .nav-link.active { border-color: #ddd #ddd #fff; background: #fff; }
.file-list li { border-bottom: 1px solid #eee; padding: 8px 0; display: flex; align-items: center; }
.file-list i { margin-right: 10px; }
.readme-box, .issues-box, .commits-box { background: #fff; padding: 20px; border: 1px solid #ddd; margin-top: 10px; }
#editor { height: 400px; width: 100%; border: 1px solid #ccc; }
</style>
</head>
<body>
<!-- ヘッダー -->
<nav class="navbar navbar-dark bg-dark px-3">
<a class="navbar-brand" href="#"><i class="fab fa-github"></i> GitHub風サイト</a>
<span class="text-white"><i class="fas fa-user-circle"></i> yuhei</span>
</nav>
<div class="container mt-3">
<!-- リポジトリヘッダー -->
<div class="repo-header">
<h3><i class="fas fa-book"></i> yuhei / <strong>SampleRepo</strong></h3>
<p class="text-muted">最終更新: 2025年5月26日</p>
<button class="btn btn-sm btn-outline-secondary"><i class="fas fa-star"></i> Star</button>
<button class="btn btn-sm btn-outline-secondary"><i class="fas fa-code-branch"></i> Fork</button>
</div>
<!-- タブ -->
<ul class="nav nav-tabs" id="repoTabs">
<li class="nav-item"><a class="nav-link active" href="#" onclick="switchTab('code')"><i class="fas fa-code"></i> Code</a></li>
<li class="nav-item"><a class="nav-link" href="#" onclick="switchTab('issues')"><i class="fas fa-exclamation-circle"></i> Issues</a></li>
<li class="nav-item"><a class="nav-link" href="#" onclick="switchTab('commits')"><i class="fas fa-history"></i> Commits</a></li>
</ul>
<!-- Codeタブ -->
<div id="tab-code" class="tab-content">
<ul class="file-list list-unstyled bg-white p-3 border">
<li><i class="fas fa-folder"></i> src/</li>
<li><i class="fas fa-file-code"></i> index.js</li>
<li><i class="fas fa-file-alt"></i> README.md</li>
<li><i class="fas fa-file-alt"></i> LICENSE</li>
</ul>
<div class="readme-box">
<h4><i class="fas fa-book-open"></i> README.md</h4>
<hr>
<div id="readme-content"></div>
</div>
<div class="mt-4">
<h5><i class="fas fa-code"></i> コード編集 (Monaco Editor)</h5>
<div id="editor"></div>
<button id="saveCode" class="btn btn-success mt-2"><i class="fas fa-save"></i> 保存</button>
<button id="themeToggle" class="btn btn-secondary mt-2"><i class="fas fa-adjust"></i> テーマ切替</button>
</div>
</div>
<!-- Issuesタブ -->
<div id="tab-issues" class="tab-content" style="display:none;">
<div class="issues-box">
<h4><i class="fas fa-exclamation-circle"></i> Open Issues</h4>
<ul class="list-group">
<li class="list-group-item">
<strong>#1</strong> READMEの翻訳が必要です<br>
<small class="text-muted">posted by yuhei - 1日前</small>
</li>
<li class="list-group-item">
<strong>#2</strong> index.jsにテストコードを追加してください<br>
<small class="text-muted">posted by yuhei - 2日前</small>
</li>
</ul>
</div>
</div>
<!-- Commitsタブ -->
<div id="tab-commits" class="tab-content" style="display:none;">
<div class="commits-box">
<h4><i class="fas fa-history"></i> Commits</h4>
<ul class="list-group">
<li class="list-group-item">
<strong>Initial commit</strong> - 2025-05-25<br>
<small class="text-muted">by yuhei</small>
</li>
<li class="list-group-item">
<strong>README updated</strong> - 2025-05-26<br>
<small class="text-muted">by yuhei</small>
</li>
</ul>
</div>
</div>
</div>
<!-- ライブラリ -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs/loader.min.js"></script>
<!-- タブ切替・Markdown表示・Monaco起動 -->
<script>
const markdown = `
# SampleRepo
ようこそ!これはGitHub風サイトのデモです。
## 特徴
- Monaco Editorでコード編集
- Markdown表示(README)
- ダークモード対応
- Issue・コミットのUI
## 技術
- HTML/CSS/JS
- Bootstrap5
- Monaco Editor
- Marked.js
`;
document.getElementById('readme-content').innerHTML = marked.parse(markdown);
function switchTab(tab) {
['code', 'issues', 'commits'].forEach(id => {
document.getElementById('tab-' + id).style.display = (id === tab) ? 'block' : 'none';
});
document.querySelectorAll('#repoTabs .nav-link').forEach(link => link.classList.remove('active'));
document.querySelector(`#repoTabs .nav-link[onclick*="${tab}"]`).classList.add('active');
}
// Monaco起動
require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs' }});
require(['vs/editor/editor.main'], function () {
window.editor = monaco.editor.create(document.getElementById('editor'), {
value: localStorage.getItem('savedCode') || `function hello() {\n console.log("Hello from Monaco Editor!");\n}`,
language: 'javascript',
theme: 'vs-light',
automaticLayout: true
});
document.getElementById('saveCode').onclick = function () {
const code = editor.getValue();
localStorage.setItem('savedCode', code);
alert('保存しました!');
};
document.getElementById('themeToggle').onclick = function () {
const theme = monaco.editor.getTheme() === 'vs-dark' ? 'vs-light' : 'vs-dark';
monaco.editor.setTheme(theme);
};
});
</script>
</body>
</html>
タグ: programming
MyCSSGrid
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My CSS Grid</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<ul>
<li>item 1</li>
<li>item 2 item 2 item 2 item 2 item 2</li>
<li>item 3</li>
<li>item 4</li>
</ul>
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3 item 3 item 3 item 3</li>
<li>item 4</li>
</ul>
</div>
</body>
</html>
style.css
@charset "utf-8";
.container {
display: grid;
grid-template-columns: 200px 200px;
grid-template-rows: repeat(4, auto);
}
ul {
grid-row: span 4;
display: grid;
grid-template-rows: subgrid;
}
ドメイン検索&購入(フロントエンド)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>ドメイン検索&購入</title>
<style>
body {
font-family: sans-serif;
background: #f9f9f9;
padding: 2rem;
margin: 0;
display: flex;
justify-content: center;
}
.container {
max-width: 600px;
width: 100%;
background: white;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
}
h1 {
color: #e60033;
text-align: center;
margin-bottom: 1.5rem;
}
.form {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
}
input {
flex: 1;
padding: 0.8rem;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 1rem;
}
button {
padding: 0.8rem 1rem;
background-color: #e60033;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
}
.result {
margin-top: 1rem;
}
.item {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #eee;
padding: 0.5rem 0;
}
.available {
color: green;
font-weight: bold;
}
.unavailable {
color: red;
font-weight: bold;
}
.buy-btn {
background-color: #0070f3;
color: white;
padding: 0.3rem 0.7rem;
border-radius: 6px;
text-decoration: none;
font-size: 0.9rem;
}
</style>
</head>
<body>
<div class="container">
<h1>ドメイン検索</h1>
<div class="form">
<input type="text" id="domainInput" placeholder="例: mydomain" />
<button onclick="search()">検索</button>
</div>
<div class="result" id="resultArea"></div>
</div>
<script>
const takenDomains = ["example.com", "mydomain.net", "taken.jp"];
const tlds = [".com", ".net", ".jp"];
function search() {
const name = document.getElementById("domainInput").value.trim().toLowerCase();
const area = document.getElementById("resultArea");
area.innerHTML = "";
if (!name) {
area.innerHTML = "<p>⚠ ドメイン名を入力してください。</p>";
return;
}
tlds.forEach(tld => {
const domain = name + tld;
const available = !takenDomains.includes(domain);
const item = document.createElement("div");
item.className = "item";
item.innerHTML = `
<span>${domain}</span>
${available
? `<span class="available">取得可能</span>
<a href="https://buy.stripe.com/test_checkout_link" class="buy-btn" target="_blank">購入する</a>`
: `<span class="unavailable">登録済み</span>`}
`;
area.appendChild(item);
});
}
</script>
</body>
</html>
ゲームBGM自動生成サービス.html
<!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;
}
ロックマン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
Unity C# SaveManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class SaveManager
{
const string location = "Assets/Resources/Data";
public static void SaveData<T>(string fileName, T template)
{
if (!Directory.Exists(location))
{
Directory.CreateDirectory(location);
}
string data = JsonUtility.ToJson(template);
string path = Path.Combine(location, fileName);
using (FileStream stream = new FileStream(path, FileMode.Create))
{
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(data);
}
stream.Close();
}
Debug.Log("game saved");
}
public static T LoadData<T>(string fileName) where T : class
{
T load = null;
string read = "";
string path = Path.Combine(location, fileName);
if(!File.Exists(path))
{
return null;
}
using (FileStream stream=new FileStream(path,FileMode.Open))
{
using (StreamReader reader=new StreamReader(stream))
{
read = reader.ReadToEnd();
}
stream.Close();
}
load = JsonUtility.FromJson<T>(read);
return load;
}
}
Unity C# Stats.cs
using UnityEngine;
[System.Serializable]
public class Stats // ← MonoBehaviourを削除
{
public int Level = 1;
public int maxHp = 1;
public int atk = 1;
public int def = 1;
public int mana = 1;
public int manaXSecond = 5;
public CharacterClass charClass = CharacterClass.warrior;
}
public enum CharacterClass
{
warrior,
maga,
priest,
paladin,
shamano,
druid,
rogue,
ranger
}
