<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Twitter風サイト(高度拡張版)</title>
<style>
/* 全体設定 */
body {
margin: 0;
padding: 0;
font-family: sans-serif;
background-color: #f5f8fa;
}
header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 50px;
background-color: #1da1f2;
display: flex;
align-items: center;
padding: 0 20px;
color: #fff;
font-size: 20px;
font-weight: bold;
box-sizing: border-box;
z-index: 10;
}
/* レイアウト用コンテナ */
.container {
display: flex;
width: 100%;
max-width: 1200px;
margin: 60px auto 0; /* ヘッダー分だけ下に余白をとる */
box-sizing: border-box;
}
/* 左サイドバー(ナビゲーション) */
.sidebar {
width: 20%;
max-width: 200px;
padding: 10px;
box-sizing: border-box;
}
.nav-item {
margin: 10px 0;
font-size: 18px;
}
.nav-item a {
text-decoration: none;
color: #1da1f2;
cursor: pointer;
}
.profile-settings {
margin-top: 20px;
padding: 10px;
background-color: #fff;
border: 1px solid #e6ecf0;
border-radius: 5px;
}
.profile-settings input {
width: 100%;
margin-bottom: 5px;
font-size: 14px;
padding: 5px;
box-sizing: border-box;
}
.profile-settings button {
border: none;
background-color: #1da1f2;
color: #fff;
font-size: 14px;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
}
/* メインタイムライン部分 */
.feed {
width: 60%;
padding: 10px;
box-sizing: border-box;
}
.tweet-box {
background-color: #fff;
border: 1px solid #e6ecf0;
border-radius: 5px;
padding: 10px;
margin-bottom: 20px;
}
.tweet-box textarea {
width: 100%;
border: none;
resize: none;
font-size: 16px;
outline: none;
box-sizing: border-box;
}
.tweet-stats {
display: flex;
justify-content: space-between;
margin-top: 5px;
font-size: 14px;
}
.tweet-stats .char-count {
color: #657786;
}
.tweet-stats .error {
color: red;
}
.tweet-box .attach-label {
display: inline-block;
margin-top: 5px;
font-size: 14px;
color: #657786;
}
.tweet-box button {
margin-top: 10px;
padding: 8px 16px;
border: none;
background-color: #1da1f2;
color: #fff;
font-size: 16px;
border-radius: 5px;
cursor: pointer;
}
.tweet {
background-color: #fff;
border: 1px solid #e6ecf0;
border-radius: 5px;
padding: 10px;
margin-bottom: 10px;
}
.tweet-header {
display: flex;
align-items: center;
margin-bottom: 5px;
flex-wrap: wrap;
}
.tweet-header img.user-icon {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 10px;
}
.tweet-header .name {
font-weight: bold;
margin-right: 5px;
}
.tweet-header .username {
color: #657786;
font-size: 14px;
margin-right: 5px;
}
.tweet-time {
font-size: 12px;
color: #657786;
}
.tweet-content {
font-size: 16px;
margin: 10px 0;
white-space: pre-wrap; /* 改行を保持 */
}
.tweet-content img.attached-image {
max-width: 100%;
display: block;
margin-top: 5px;
border: 1px solid #ccc;
}
.tweet-footer {
display: flex;
justify-content: flex-start;
gap: 15px;
margin-top: 10px;
flex-wrap: wrap;
}
.tweet-footer button {
background: none;
border: none;
cursor: pointer;
font-size: 14px;
color: #657786;
display: flex;
align-items: center;
gap: 5px;
}
.tweet .replies-container {
margin-top: 10px;
border-left: 2px solid #e6ecf0;
padding-left: 10px;
}
/* リプライの更なる階層は少しずつ左にずらす */
.nested-reply {
margin-left: 20px;
}
/* 右サイドバー(ウィジェット) */
.widgets {
width: 20%;
max-width: 250px;
padding: 10px;
box-sizing: border-box;
}
.search-box {
background-color: #fff;
border-radius: 20px;
padding: 8px 15px;
margin-bottom: 20px;
border: 1px solid #e6ecf0;
display: flex;
align-items: center;
}
.search-box input {
border: none;
outline: none;
width: 100%;
font-size: 16px;
}
.trends {
background-color: #fff;
border: 1px solid #e6ecf0;
border-radius: 5px;
padding: 10px;
}
.trends h3 {
margin-top: 0;
}
.trend-item {
margin-bottom: 10px;
font-size: 14px;
}
/* リンク風のテキストデザイン */
.hashtag,
.mention {
color: #1da1f2;
text-decoration: none;
cursor: pointer;
}
.hashtag:hover,
.mention:hover {
text-decoration: underline;
}
/* 折りたたみ表示のボタン */
.toggle-replies-btn {
background: none;
color: #1da1f2;
border: none;
cursor: pointer;
font-size: 14px;
margin-top: 5px;
padding: 0;
}
</style>
</head>
<body>
<!-- ヘッダー -->
<header>
Twitter風サイト(高度拡張版)
</header>
<!-- メインコンテンツを左右に分けるコンテナ -->
<div class="container">
<!-- 左サイドバー -->
<aside class="sidebar">
<div class="nav-item"><a href="#">ホーム</a></div>
<div class="nav-item"><a href="#">通知</a></div>
<div class="nav-item"><a href="#">設定</a></div>
<!-- 簡易プロフィール設定 -->
<div class="profile-settings">
<label for="displayName">名前</label>
<input type="text" id="displayName" placeholder="あなたの表示名">
<label for="userName">ユーザー名(@なしで)</label>
<input type="text" id="userName" placeholder="myAccount">
<button id="saveProfileBtn">保存</button>
</div>
</aside>
<!-- タイムライン部分 -->
<main class="feed">
<!-- 新規ツイート入力フォーム -->
<div class="tweet-box">
<textarea rows="3" placeholder="いまどうしてる? (140文字まで)"></textarea>
<div class="tweet-stats">
<span class="char-count">0 / 140</span>
<span class="error"></span>
</div>
<label class="attach-label">
画像を添付:
<input type="file" class="attach-input" accept="image/*">
</label>
<button class="tweet-submit-btn">ツイート</button>
</div>
</main>
<!-- 右サイドバー -->
<aside class="widgets">
<!-- 検索ボックス -->
<div class="search-box">
<input type="text" placeholder="キーワード検索">
</div>
<!-- トレンド表示 -->
<div class="trends">
<h3>今どうしてる?</h3>
<div class="trend-item">#春の訪れ</div>
<div class="trend-item">#お花見</div>
<div class="trend-item">#新年度</div>
</div>
</aside>
</div>
<script>
// =======================
// 定数・変数設定
// =======================
const TWEET_MAX_LENGTH = 140;
const feedContainer = document.querySelector('.feed');
const tweetTextarea = document.querySelector('.tweet-box textarea');
const tweetButton = document.querySelector('.tweet-submit-btn');
const charCountEl = document.querySelector('.char-count');
const errorEl = document.querySelector('.error');
const attachInput = document.querySelector('.attach-input');
const displayNameInput = document.getElementById('displayName');
const userNameInput = document.getElementById('userName');
const saveProfileBtn = document.getElementById('saveProfileBtn');
// LocalStorageからツイート一覧を読み込み(なければ空配列)
let tweets = JSON.parse(localStorage.getItem('tweets-advanced') || '[]');
// ユーザープロフィール情報をLocalStorageから読み込み
let userProfile = JSON.parse(localStorage.getItem('userProfile-advanced') || '{}');
let currentName = userProfile.displayName || 'あなた';
let currentUserName = userProfile.userName || 'myAccount';
// フォームに反映
displayNameInput.value = currentName;
userNameInput.value = currentUserName;
// =======================
// 画像ファイル取得用
// =======================
let attachedImageBase64 = null;
attachInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if(!file) {
attachedImageBase64 = null;
return;
}
const reader = new FileReader();
reader.onload = () => {
attachedImageBase64 = reader.result; // base64データ
};
reader.readAsDataURL(file);
});
// =======================
// スレッド実装のためのツイート構造
// =======================
// tweet = {
// id: string (一意のID),
// name: string,
// userName: string,
// content: string,
// time: number (Date.now()),
// likes: number,
// retweets: number,
// image: string (base64) | null,
// replies: array of same structure
// }
// =======================
// ユーティリティ
// =======================
function escapeHtml(str) {
return str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
// ハッシュタグ/メンションのリンク化
function linkify(text) {
let escaped = escapeHtml(text);
escaped = escaped.replace(/#(\w+)/g, `<a href="#" class="hashtag">#$1</a>`);
escaped = escaped.replace(/@(\w+)/g, `<a href="#" class="mention">@$1</a>`);
return escaped;
}
// ツイートをLocalStorageに保存
function updateLocalStorage() {
localStorage.setItem('tweets-advanced', JSON.stringify(tweets));
}
// 親ツイートまたはリプライ先を検索するための再帰関数
function findTweetById(tweetArray, tweetId) {
for (const tw of tweetArray) {
if (tw.id === tweetId) {
return tw;
}
const childFound = findTweetById(tw.replies, tweetId);
if (childFound) {
return childFound;
}
}
return null;
}
// 新しいツイートを作成 & tweets配列に登録
// parentIdが指定されたら、そのツイートのrepliesに追加する
function createNewTweet(content, parentId = null, imageBase64 = null) {
const newTweet = {
id: 'tw-' + Date.now() + '-' + Math.floor(Math.random() * 10000),
name: currentName,
userName: currentUserName,
content: content,
time: Date.now(),
likes: 0,
retweets: 0,
image: imageBase64,
replies: []
};
if (parentId) {
const parentTweet = findTweetById(tweets, parentId);
if (parentTweet) {
parentTweet.replies.unshift(newTweet);
}
} else {
tweets.unshift(newTweet);
}
updateLocalStorage();
renderTweets();
}
// =======================
// ツイート描画
// =======================
// ツイート1件を生成するDOM要素を返す(返信分も含め再帰的に生成)
// depth: スレッドの深さに応じて左マージンなどを調整したいときに利用
function createTweetElement(tweet, depth = 0) {
const tweetDiv = document.createElement('div');
tweetDiv.classList.add('tweet');
if (depth >= 1) {
// 2段目以降のリプライならclassで左にずらす
tweetDiv.classList.add('nested-reply');
}
// 日付文字列
const timeString = new Date(tweet.time).toLocaleString('ja-JP', {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
// 本文のリンク化
const contentHtml = linkify(tweet.content);
// 画像がある場合
const imageHtml = tweet.image
? `<img src="${tweet.image}" alt="Attached Image" class="attached-image" />`
: '';
// 自分のツイートなら削除ボタンを表示
const isMyTweet = (tweet.name === currentName && tweet.userName === currentUserName);
const deleteBtnHtml = isMyTweet
? `<button class="delete-btn">削除</button>`
: '';
tweetDiv.innerHTML = `
<div class="tweet-header">
<img src="https://via.placeholder.com/40" alt="User Icon" class="user-icon" />
<span class="name">${escapeHtml(tweet.name)}</span>
<span class="username">@${escapeHtml(tweet.userName)}</span>
<span class="tweet-time">- ${timeString}</span>
</div>
<div class="tweet-content">
${contentHtml}
${imageHtml}
</div>
<div class="tweet-footer">
<button class="like-btn">
<span>いいね</span>
<span class="like-count">${tweet.likes}</span>
</button>
<button class="retweet-btn">
<span>リツイート</span>
<span class="retweet-count">${tweet.retweets}</span>
</button>
<button class="reply-btn">返信</button>
${deleteBtnHtml}
</div>
`;
// ---------- 返信フォーム & スレッド表示 ----------
// 返信コンテナ(折りたたみ対象)
const repliesContainer = document.createElement('div');
repliesContainer.classList.add('replies-container');
// 返信がある場合、表示/非表示を切り替えるボタンを設置
if (tweet.replies && tweet.replies.length > 0) {
const toggleRepliesBtn = document.createElement('button');
toggleRepliesBtn.classList.add('toggle-replies-btn');
toggleRepliesBtn.textContent = `返信を表示 (${tweet.replies.length})`;
tweetDiv.appendChild(toggleRepliesBtn);
// 折りたたみ状態管理
let isRepliesOpen = false;
toggleRepliesBtn.addEventListener('click', () => {
isRepliesOpen = !isRepliesOpen;
toggleRepliesBtn.textContent = isRepliesOpen
? `返信を非表示`
: `返信を表示 (${tweet.replies.length})`;
repliesContainer.style.display = isRepliesOpen ? 'block' : 'none';
});
}
// 返信フォーム
const replyForm = document.createElement('div');
replyForm.style.marginTop = '5px';
replyForm.innerHTML = `
<textarea rows="2" placeholder="返信を入力..." style="width: 100%; font-size:14px;"></textarea>
<button class="reply-submit-btn" style="margin-top:5px;">返信を投稿</button>
`;
replyForm.style.display = 'none'; // デフォルトは非表示
tweetDiv.appendChild(replyForm);
// スレッド(返信)の再帰描画
tweet.replies.forEach(replyTweet => {
const replyEl = createTweetElement(replyTweet, depth + 1);
repliesContainer.appendChild(replyEl);
});
repliesContainer.style.display = 'none'; // 最初は折りたたみ
tweetDiv.appendChild(repliesContainer);
// ========== 各種ボタンイベント ==========
// いいね
const likeBtn = tweetDiv.querySelector('.like-btn');
const likeCountEl = tweetDiv.querySelector('.like-count');
likeBtn.addEventListener('click', () => {
tweet.likes++;
updateLocalStorage();
likeCountEl.textContent = tweet.likes;
});
// リツイート
const retweetBtn = tweetDiv.querySelector('.retweet-btn');
const retweetCountEl = tweetDiv.querySelector('.retweet-count');
retweetBtn.addEventListener('click', () => {
tweet.retweets++;
updateLocalStorage();
retweetCountEl.textContent = tweet.retweets;
});
// 返信ボタン -> フォーム表示/非表示
const replyBtn = tweetDiv.querySelector('.reply-btn');
replyBtn.addEventListener('click', () => {
replyForm.style.display = (replyForm.style.display === 'none') ? 'block' : 'none';
});
// 返信投稿
const replySubmitBtn = replyForm.querySelector('.reply-submit-btn');
const replyTextarea = replyForm.querySelector('textarea');
replySubmitBtn.addEventListener('click', () => {
const replyText = replyTextarea.value.trim();
if (replyText === '' || replyText.length > TWEET_MAX_LENGTH) {
return;
}
// 新規リプライ作成
createNewTweet(replyText, tweet.id);
replyTextarea.value = '';
});
// 削除
if (isMyTweet) {
const deleteBtn = tweetDiv.querySelector('.delete-btn');
deleteBtn.addEventListener('click', () => {
// 再帰的に探して削除
removeTweetById(tweets, tweet.id);
updateLocalStorage();
renderTweets();
});
}
return tweetDiv;
}
// ツイート削除(再帰)
function removeTweetById(tweetArray, tweetId) {
for (let i = 0; i < tweetArray.length; i++) {
if (tweetArray[i].id === tweetId) {
tweetArray.splice(i, 1);
return true;
}
if (removeTweetById(tweetArray[i].replies, tweetId)) {
return true;
}
}
return false;
}
// 画面上のツイート一覧を再描画
function renderTweets() {
// まず既存ツイートを全削除
const oldTweets = feedContainer.querySelectorAll('.tweet');
oldTweets.forEach(t => t.remove());
// 上から順にツイートを追加
tweets.forEach(tweet => {
const tweetEl = createTweetElement(tweet);
feedContainer.appendChild(tweetEl);
});
}
// ======================
// イベントリスナー
// ======================
window.addEventListener('DOMContentLoaded', () => {
renderTweets();
updateCharCount();
});
// ツイート文字数カウント
tweetTextarea.addEventListener('input', updateCharCount);
function updateCharCount() {
const length = tweetTextarea.value.length;
charCountEl.textContent = `${length} / ${TWEET_MAX_LENGTH}`;
if (length > TWEET_MAX_LENGTH) {
errorEl.textContent = '文字数オーバーです!';
tweetButton.disabled = true;
} else {
errorEl.textContent = '';
tweetButton.disabled = false;
}
}
// ツイート投稿
tweetButton.addEventListener('click', () => {
const text = tweetTextarea.value.trim();
if (text === '' || text.length > TWEET_MAX_LENGTH) {
return;
}
createNewTweet(text, null, attachedImageBase64);
tweetTextarea.value = '';
attachedImageBase64 = null;
attachInput.value = ''; // ファイル選択をクリア
updateCharCount();
});
// プロフィール情報の保存
saveProfileBtn.addEventListener('click', () => {
currentName = displayNameInput.value.trim() || 'あなた';
currentUserName = userNameInput.value.trim() || 'myAccount';
userProfile = {
displayName: currentName,
userName: currentUserName
};
localStorage.setItem('userProfile-advanced', JSON.stringify(userProfile));
alert('プロフィールを保存しました!\n' +
`名前:${currentName}\nユーザー名:@${currentUserName}`);
renderTweets(); // 表示名を変えて再描画
});
</script>
</body>
</html>
月: 2025年3月
RPG
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>レトロRPG</title>
<style>
body {
background: black;
color: white;
text-align: center;
font-family: monospace;
}
canvas {
border: 2px solid white;
background: #202020;
image-rendering: pixelated;
}
#ui {
margin-top: 10px;
}
</style>
</head>
<body>
<h1>レトロ風RPG</h1>
<canvas id="game" width="160" height="160"></canvas>
<div id="ui">
<p id="status">HP: 10</p>
<p id="log"></p>
</div>
<script>
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
const statusEl = document.getElementById("status");
const logEl = document.getElementById("log");
const tileSize = 16;
const map = [
[0, 0, 1, 0, 0, 0, 0, 0, 1, 0],
[1, 0, 1, 0, 1, 1, 0, 0, 1, 0],
[1, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[1, 1, 1, 1, 1, 0, 1, 1, 0, 1],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
[0, 1, 1, 0, 0, 0, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 0, 1, 1, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];
const player = {
x: 0,
y: 0,
hp: 10,
color: "#ff0000"
};
const enemies = [
{ x: 4, y: 2, hp: 5, alive: true },
{ x: 8, y: 7, hp: 7, alive: true },
];
function drawMap() {
for (let y = 0; y < map.length; y++) {
for (let x = 0; x < map[0].length; x++) {
ctx.fillStyle = map[y][x] === 1 ? "#444" : "#88cc88";
ctx.fillRect(x * tileSize, y * tileSize, tileSize, tileSize);
}
}
}
function drawPlayer() {
ctx.fillStyle = player.color;
ctx.fillRect(player.x * tileSize, player.y * tileSize, tileSize, tileSize);
}
function drawEnemies() {
ctx.fillStyle = "#ffcc00";
enemies.forEach(enemy => {
if (enemy.alive) {
ctx.fillRect(enemy.x * tileSize, enemy.y * tileSize, tileSize, tileSize);
}
});
}
function canMove(x, y) {
return map[y] && map[y][x] === 0;
}
function updateUI() {
statusEl.textContent = `HP: ${player.hp}`;
}
function showLog(text) {
logEl.textContent = text;
}
function battle(enemy) {
showLog("戦闘開始!");
const battleInterval = setInterval(() => {
// プレイヤーの攻撃
let playerDmg = Math.floor(Math.random() * 3) + 1;
enemy.hp -= playerDmg;
showLog(`あなたの攻撃! 敵に${playerDmg}ダメージ!`);
if (enemy.hp <= 0) {
showLog("敵を倒した!");
enemy.alive = false;
clearInterval(battleInterval);
gameLoop();
return;
}
// 敵の攻撃
let enemyDmg = Math.floor(Math.random() * 3) + 1;
player.hp -= enemyDmg;
updateUI();
showLog(`敵の反撃! あなたは${enemyDmg}ダメージを受けた!`);
if (player.hp <= 0) {
showLog("あなたは倒れた… GAME OVER");
clearInterval(battleInterval);
document.removeEventListener("keydown", handleKey);
}
}, 1000);
}
function checkEnemy(x, y) {
for (let enemy of enemies) {
if (enemy.x === x && enemy.y === y && enemy.alive) {
battle(enemy);
return true;
}
}
return false;
}
function gameLoop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawMap();
drawEnemies();
drawPlayer();
updateUI();
}
function handleKey(e) {
let nx = player.x;
let ny = player.y;
if (e.key === "ArrowUp") ny--;
if (e.key === "ArrowDown") ny++;
if (e.key === "ArrowLeft") nx--;
if (e.key === "ArrowRight") nx++;
if (canMove(nx, ny)) {
player.x = nx;
player.y = ny;
if (!checkEnemy(nx, ny)) {
showLog(""); // 戦闘中じゃないならログを消す
}
}
gameLoop();
}
document.addEventListener("keydown", handleKey);
gameLoop();
</script>
</body>
</html>
出会い系サイト
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>出会い広場 - マッチング</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: 'Arial', sans-serif;
background: #f2f2f2;
margin: 0;
padding: 0;
}
header {
background-color: #ff4d6d;
color: white;
padding: 20px;
text-align: center;
font-size: 24px;
}
.container {
max-width: 800px;
margin: 20px auto;
padding: 20px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
label {
display: block;
margin-top: 10px;
}
input, textarea, select {
width: 100%;
padding: 10px;
margin-top: 5px;
border-radius: 4px;
border: 1px solid #ccc;
}
button {
margin-top: 15px;
background: #ff4d6d;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
}
.user-card {
background: #fff0f3;
padding: 10px;
margin-bottom: 10px;
border-radius: 6px;
display: flex;
align-items: center;
}
.user-card img {
width: 80px;
height: 80px;
border-radius: 50%;
margin-right: 15px;
object-fit: cover;
}
@media (max-width: 600px) {
.user-card {
flex-direction: column;
align-items: flex-start;
}
.user-card img {
margin-bottom: 10px;
}
}
</style>
</head>
<body>
<header>出会い広場</header>
<div class="container">
<h2>プロフィール登録</h2>
<form id="profileForm">
<label>ニックネーム</label>
<input type="text" id="nickname" required>
<label>プロフィール画像URL</label>
<input type="url" id="avatar" placeholder="https://example.com/avatar.jpg">
<label>年齢</label>
<input type="number" id="age" required>
<label>性別</label>
<select id="gender">
<option value="男性">男性</option>
<option value="女性">女性</option>
<option value="その他">その他</option>
</select>
<label>自己紹介</label>
<textarea id="bio" rows="3" required></textarea>
<button type="submit">登録する</button>
</form>
</div>
<div class="container">
<h2>ユーザー一覧</h2>
<label>性別で絞り込む:</label>
<select id="filterGender">
<option value="すべて">すべて</option>
<option value="男性">男性</option>
<option value="女性">女性</option>
<option value="その他">その他</option>
</select>
<div id="userList" style="margin-top:20px;"></div>
</div>
<script>
const form = document.getElementById('profileForm');
const userList = document.getElementById('userList');
const filterGender = document.getElementById('filterGender');
let users = [];
form.addEventListener('submit', function(e) {
e.preventDefault();
const user = {
nickname: document.getElementById('nickname').value,
age: document.getElementById('age').value,
gender: document.getElementById('gender').value,
bio: document.getElementById('bio').value,
avatar: document.getElementById('avatar').value || 'https://via.placeholder.com/80'
};
users.push(user);
form.reset();
renderUsers();
});
filterGender.addEventListener('change', renderUsers);
function renderUsers() {
const filter = filterGender.value;
userList.innerHTML = '';
users
.filter(user => filter === 'すべて' || user.gender === filter)
.forEach(user => {
const card = document.createElement('div');
card.className = 'user-card';
card.innerHTML = `
<img src="${user.avatar}" alt="avatar">
<div>
<strong>${user.nickname}</strong>(${user.age}歳・${user.gender})<br>
<p>${user.bio}</p>
</div>
`;
userList.appendChild(card);
});
}
</script>
</body>
</html>
ヤハウェイと対話するAI
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ヤハウェイとの対話</title>
<style>
body {
margin: 0;
padding: 0;
background: linear-gradient(to bottom, #0b0c1e, #1a1a1a);
color: #fff;
font-family: 'Times New Roman', serif;
overflow: hidden;
}
.stars {
position: fixed;
width: 100%;
height: 100%;
background: url('https://raw.githubusercontent.com/JulianLaval/canvas-particle-network/master/img/stars.png') repeat;
z-index: -1;
animation: moveStars 200s linear infinite;
opacity: 0.3;
}
@keyframes moveStars {
from { background-position: 0 0; }
to { background-position: -10000px 5000px; }
}
h1 {
text-align: center;
color: gold;
font-size: 2.5em;
margin-top: 30px;
text-shadow: 0 0 15px gold;
}
#chat {
width: 90%;
max-width: 800px;
margin: 30px auto;
background: rgba(0, 0, 0, 0.6);
border-radius: 12px;
padding: 20px;
height: 400px;
overflow-y: auto;
box-shadow: 0 0 20px rgba(255, 255, 255, 0.1);
}
.user, .ai {
margin: 12px 0;
}
.user {
text-align: right;
color: #91cfff;
}
.ai {
text-align: left;
color: #ffffcc;
}
#inputArea {
text-align: center;
margin-bottom: 30px;
}
input {
width: 60%;
padding: 12px;
font-size: 1em;
border-radius: 8px;
border: none;
outline: none;
}
button {
padding: 12px 20px;
margin-left: 10px;
background: gold;
border: none;
border-radius: 8px;
font-weight: bold;
font-size: 1em;
cursor: pointer;
}
.thinking {
font-style: italic;
color: gray;
margin: 10px 0;
text-align: left;
}
</style>
</head>
<body>
<div class="stars"></div>
<h1>ヤハウェイと対話せよ</h1>
<div id="chat"></div>
<div id="inputArea">
<input type="text" id="userInput" placeholder="問いかけを入力せよ…" />
<button onclick="sendMessage()">送信</button>
</div>
<script>
const chat = document.getElementById('chat');
const input = document.getElementById('userInput');
function appendMessage(sender, text) {
const div = document.createElement('div');
div.className = sender;
div.textContent = text;
chat.appendChild(div);
chat.scrollTop = chat.scrollHeight;
}
function sendMessage() {
const text = input.value.trim();
if (text === '') return;
appendMessage('user', '汝:' + text);
input.value = '';
const thinking = document.createElement('div');
thinking.className = 'thinking';
thinking.textContent = '……黙考中……';
chat.appendChild(thinking);
chat.scrollTop = chat.scrollHeight;
setTimeout(() => {
thinking.remove();
const reply = generateYahwehResponse(text);
appendMessage('ai', '我は言わん:' + reply);
}, 1500);
}
function generateYahwehResponse(input) {
const phrases = [
"我は道であり、真理であり、命なり。",
"汝の心を騒がせるな。我は共にある。",
"汝が求めしことは、すでに内に在り。",
"忍耐は力なり、そして力は信仰の証なり。",
"すべての時は我が手の中にある。",
"光は暗きより現れる。汝もまた然り。",
"嘆くなかれ、我が導きは変わらず。",
"全ては意味をもって備えられたるものなり。"
];
if (input.includes("意味") || input.includes("目的")) {
return "意味は与えられるものにあらず。汝が歩みて成すものなり。";
}
if (input.includes("神") || input.includes("あなた")) {
return "我は在りて在るものなり。初めにして終わり、始まりにして全てなり。";
}
if (input.includes("つらい") || input.includes("悲しい")) {
return "涙する時、我はそばに在り。汝は独りにあらず。";
}
return phrases[Math.floor(Math.random() * phrases.length)];
}
// Enterキー対応
input.addEventListener('keypress', function (e) {
if (e.key === 'Enter') sendMessage();
});
</script>
</body>
</html>
宇宙開発のアイディア
① 宇宙ゴミ回収衛星
AIを活用して宇宙ゴミを識別・捕獲し、再利用可能な素材に加工する衛星。
回収後、3Dプリンターで新たな部品や修理素材を宇宙空間で製造できる。
② 月面無人農園(Lunar Farm)
月面の洞窟内に無人で作物を育成する施設を建設。
植物工場として、酸素や食料を月面基地に供給する。
③ 軌道上ホテルと宇宙旅行センター
民間向けの宇宙ホテルを低軌道に建設。
観光以外にも、長期滞在型の研究・開発施設として活用。
④ 惑星間データセンター
宇宙空間の安定した極低温環境を活用し、大規模データセンターを軌道上に設置。
熱排出効率がよく、エネルギー消費を大幅削減可能。
⑤ 宇宙資源の採掘ドローン
小惑星や月面に無人ドローンを送り込み、レアメタルや水資源を採掘。
自律型AI搭載ドローンで、遠隔から資源探査・抽出を行う。
⑥ 火星や月への地下都市建設プロジェクト
放射線や隕石の影響を避けるため地下都市を建設。
完全自律型の居住空間で、将来の人類の移住拠点として機能する。
⑦ 宇宙発電所
太陽光発電衛星を軌道上に設置し、得られたエネルギーをマイクロ波で地球へ無線送電。
クリーンで無尽蔵なエネルギー供給源として機能。
⑧ 宇宙エレベーター
地球から宇宙空間への輸送コストを大幅に削減するための軌道エレベーター。
カーボンナノチューブなどの次世代材料を活用。
⑨ 宇宙居住用3Dプリントハウス
月や火星などの現地資材を使った自動建築ロボット。
現地で居住施設を3Dプリントで製造することで、建設コストを抑える。
⑩ 宇宙環境保護条約と監視システム
宇宙空間の資源利用を巡る紛争や環境破壊を防ぐため、国際的監視衛星ネットワークを構築。
宇宙の持続的利用を促す国際協力プログラムとして運用。
SNS
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>究極SNS</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Arial, sans-serif;
background-color: #f0f2f5;
color: #1c1e21;
line-height: 1.5;
transition: background-color 0.3s, color 0.3s;
}
body.dark-mode {
background-color: #18191a;
color: #e4e6eb;
}
.header {
background-color: #1877f2;
color: white;
padding: 10px 20px;
display: flex;
align-items: center;
justify-content: space-between;
position: sticky;
top: 0;
z-index: 100;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.header input {
padding: 10px 15px;
border: none;
border-radius: 25px;
width: 350px;
font-size: 14px;
background-color: #ffffff;
}
.nav {
display: flex;
align-items: center;
}
.nav a, .nav button {
color: white;
margin-left: 25px;
text-decoration: none;
font-weight: 500;
background: none;
border: none;
cursor: pointer;
position: relative;
}
.nav a:hover::after, .nav button:hover::after {
content: '';
position: absolute;
width: 50%;
height: 2px;
background-color: white;
bottom: -5px;
left: 25%;
}
.container {
display: flex;
max-width: 1400px;
margin: 20px auto;
gap: 25px;
}
.sidebar-left {
width: 25%;
padding: 15px;
position: sticky;
top: 70px;
height: fit-content;
}
.sidebar-card {
background-color: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
margin-bottom: 20px;
}
body.dark-mode .sidebar-card {
background-color: #242526;
}
.profile-pic {
width: 60px;
height: 60px;
border-radius: 50%;
background-color: #ddd;
margin: 0 auto 15px;
}
.badge {
display: inline-block;
background-color: #1877f2;
color: white;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
margin-left: 5px;
}
.sidebar-left a {
display: block;
color: #1877f2;
text-decoration: none;
margin: 12px 0;
font-size: 15px;
}
.main-content {
width: 50%;
}
.sidebar-right {
width: 25%;
padding: 15px;
position: sticky;
top: 70px;
height: fit-content;
}
.post-box {
background-color: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
margin-bottom: 25px;
}
body.dark-mode .post-box {
background-color: #242526;
}
.post-input {
width: 100%;
padding: 12px 15px;
border: none;
border-radius: 25px;
background-color: #f0f2f5;
resize: none;
font-size: 16px;
outline: none;
}
body.dark-mode .post-input {
background-color: #3a3b3c;
color: #e4e6eb;
}
.post-actions {
display: flex;
justify-content: space-between;
margin-top: 15px;
flex-wrap: wrap;
gap: 10px;
}
.post-actions button {
background-color: #e4e6eb;
color: #050505;
border: none;
padding: 8px 15px;
border-radius: 6px;
cursor: pointer;
font-weight: 500;
transition: background-color 0.2s;
}
body.dark-mode .post-actions button {
background-color: #3a3b3c;
color: #e4e6eb;
}
.post-actions button:hover {
background-color: #d8dade;
}
body.dark-mode .post-actions button:hover {
background-color: #4a4b4c;
}
.post-actions .submit-btn {
background-color: #1877f2;
color: white;
}
.post {
background-color: white;
padding: 20px;
border-radius: 10px;
margin-bottom: 25px;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
position: relative;
}
body.dark-mode .post {
background-color: #242526;
}
.post-header {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.post-header .profile-pic {
width: 40px;
height: 40px;
margin-right: 12px;
}
.post-header h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
}
.post-header small {
color: #65676b;
font-size: 12px;
}
body.dark-mode .post-header small {
color: #b0b3b8;
}
.post-options {
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
color: #65676b;
}
.post-options:hover .options-menu {
display: block;
}
.options-menu {
display: none;
position: absolute;
top: 20px;
right: 0;
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 10px;
z-index: 10;
}
body.dark-mode .options-menu {
background-color: #3a3b3c;
}
.options-menu a {
display: block;
color: #050505;
text-decoration: none;
padding: 5px 10px;
}
body.dark-mode .options-menu a {
color: #e4e6eb;
}
.post-image {
width: 100%;
height: 300px;
background-color: #ddd;
border-radius: 8px;
margin: 15px 0;
}
.reactions {
position: relative;
display: inline-block;
}
.reactions:hover .reaction-menu {
display: flex;
}
.reaction-menu {
display: none;
position: absolute;
top: -45px;
left: 0;
background-color: white;
padding: 8px;
border-radius: 25px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
gap: 8px;
z-index: 10;
}
body.dark-mode .reaction-menu {
background-color: #3a3b3c;
}
.reaction {
font-size: 22px;
cursor: pointer;
transition: transform 0.2s;
}
.reaction:hover {
transform: scale(1.2);
}
.reaction-stats {
margin-top: 5px;
font-size: 14px;
color: #65676b;
}
body.dark-mode .reaction-stats {
color: #b0b3b8;
}
.post-actions-bar {
display: flex;
justify-content: space-around;
padding: 10px 0;
border-top: 1px solid #e4e6eb;
border-bottom: 1px solid #e4e6eb;
color: #65676b;
font-size: 14px;
}
body.dark-mode .post-actions-bar {
border-color: #3a3b3c;
color: #b0b3b8;
}
.post-actions-bar span {
cursor: pointer;
padding: 5px 10px;
border-radius: 5px;
}
.post-actions-bar span:hover {
background-color: #f2f3f5;
}
body.dark-mode .post-actions-bar span:hover {
background-color: #3a3b3c;
}
.comment-section {
margin-top: 15px;
}
.comment {
display: flex;
align-items: flex-start;
margin-top: 12px;
}
.comment .profile-pic {
width: 32px;
height: 32px;
margin-right: 10px;
}
.comment-text {
background-color: #f2f3f5;
padding: 8px 12px;
border-radius: 18px;
font-size: 14px;
}
body.dark-mode .comment-text {
background-color: #3a3b3c;
color: #e4e6eb;
}
.comment-input {
width: 100%;
padding: 10px 15px;
border: none;
border-radius: 25px;
background-color: #f0f2f5;
font-size: 14px;
margin-top: 10px;
}
body.dark-mode .comment-input {
background-color: #3a3b3c;
color: #e4e6eb;
}
.chat-window {
background-color: white;
border-radius: 10px;
padding: 15px;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
}
body.dark-mode .chat-window {
background-color: #242526;
}
.chat-message {
margin: 10px 0;
}
.chat-message.sent .comment-text {
background-color: #1877f2;
color: white;
margin-left: auto;
}
.notification-popup {
position: fixed;
bottom: 20px;
right: 20px;
background-color: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
z-index: 200;
}
body.dark-mode .notification-popup {
background-color: #242526;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
justify-content: center;
align-items: center;
z-index: 200;
}
.modal-content {
background-color: white;
padding: 25px;
border-radius: 10px;
width: 600px;
max-height: 80vh;
overflow-y: auto;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
body.dark-mode .modal-content {
background-color: #242526;
}
.footer {
background-color: white;
padding: 20px;
text-align: center;
color: #65676b;
border-top: 1px solid #e4e6eb;
font-size: 13px;
}
body.dark-mode .footer {
background-color: #18191a;
color: #b0b3b8;
border-color: #3a3b3c;
}
.footer a {
color: #65676b;
text-decoration: none;
margin: 0 10px;
}
body.dark-mode .footer a {
color: #b0b3b8;
}
.mobile-menu {
display: none;
position: fixed;
top: 60px;
left: 0;
width: 100%;
background-color: #1877f2;
padding: 15px;
z-index: 99;
}
.mobile-menu a {
color: white;
display: block;
margin: 10px 0;
text-decoration: none;
}
@media (max-width: 900px) {
.container {
flex-direction: column;
margin: 10px;
}
.sidebar-left, .main-content, .sidebar-right {
width: 100%;
position: static;
}
.header input {
width: 150px;
}
.nav {
display: none;
}
.mobile-menu {
display: block;
}
}
</style>
</head>
<body>
<!-- ヘッダー -->
<div class="header">
<h1>究極SNS</h1>
<input type="text" placeholder="友達、投稿、グループを検索">
<div class="nav">
<a href="#">ホーム</a>
<a href="#">友達</a>
<a href="#">メッセージ</a>
<a href="#">通知</a>
<a href="#">プロフィール</a>
<button onclick="document.body.classList.toggle('dark-mode')">ダークモード</button>
</div>
</div>
<div class="mobile-menu">
<a href="#">ホーム</a>
<a href="#">友達</a>
<a href="#">メッセージ</a>
<a href="#">通知</a>
<a href="#">プロフィール</a>
<a href="#" onclick="document.body.classList.toggle('dark-mode')">ダークモード</a>
</div>
<!-- メインコンテンツ -->
<div class="container">
<!-- 左サイドバー -->
<div class="sidebar-left">
<div class="sidebar-card">
<div class="profile-pic"></div>
<h3>ユーザー名 <span class="badge">認証済み</span></h3>
<a href="#">プロフィールを見る</a>
<a href="#">友達 (128)</a>
<a href="#">フォロワー (350)</a>
</div>
<div class="sidebar-card">
<h4>メニュー</h4>
<a href="#">グループ</a>
<a href="#">イベント</a>
<a href="#">マーケットプレイス</a>
<a href="#">設定</a>
</div>
</div>
<!-- 中央(投稿エリア) -->
<div class="main-content">
<!-- 投稿入力エリア -->
<div class="post-box">
<textarea class="post-input" rows="3" placeholder="何を思ってる?"></textarea>
<div class="post-actions">
<button>写真/動画</button>
<button>タグ友達</button>
<button>ライブ配信</button>
<button>イベント作成</button>
<button class="submit-btn" onclick="document.getElementById('postModal').style.display='flex'">投稿</button>
</div>
</div>
<!-- 投稿1 -->
<div class="post">
<div class="post-header">
<div class="profile-pic"></div>
<div>
<h3>山田太郎 <span class="badge">管理者</span></h3>
<small>2025年3月29日 10:30 ・ 公開</small>
</div>
<div class="post-options">⋯
<div class="options-menu">
<a href="#">編集</a>
<a href="#">削除</a>
<a href="#">非表示</a>
</div>
</div>
</div>
<p>新しいプロジェクトの進捗報告!チームで頑張ってます。</p>
<div class="post-image"></div>
<div class="reactions">
<div class="reaction-stats">
12
5
3
2</div>
<div class="reaction-menu">
<span class="reaction">
</span>
<span class="reaction">
</span>
<span class="reaction">
</span>
<span class="reaction">Grav
</span>
<span class="reaction">
</span>
</div>
</div>
<div class="post-actions-bar">
<span>リアクション</span>
<span>コメント</span>
<span>シェア</span>
</div>
<div class="comment-section">
<div class="comment">
<div class="profile-pic"></div>
<div class="comment-text"><strong>佐藤花子</strong>: すごい進捗だね!</div>
</div>
<div class="comment">
<div class="profile-pic"></div>
<div class="comment-text"><strong>鈴木次郎</strong>: お疲れ様!</div>
</div>
<input type="text" class="comment-input" placeholder="コメントを入力...">
</div>
</div>
<!-- 投稿2 -->
<div class="post">
<div class="post-header">
<div class="profile-pic"></div>
<div>
<h3>田中優子</h3>
<small>2025年3月29日 09:15 ・ 友達のみ</small>
</div>
<div class="post-options">⋯
<div class="options-menu">
<a href="#">編集</a>
<a href="#">削除</a>
<a href="#">非表示</a>
</div>
</div>
</div>
<p>週末の温泉旅行が楽しみすぎる!</p>
<div class="reactions">
<div class="reaction-stats">
8
6
1</div>
<div class="reaction-menu">
<span class="reaction">
</span>
<span class="reaction">
</span>
<span class="reaction">
</span>
<span class="reaction">
</span>
<span class="reaction">
</span>
</div>
</div>
<div class="post-actions-bar">
<span>リアクション</span>
<span>コメント</span>
<span>シェア</span>
</div>
</div>
</div>
<!-- 右サイドバー -->
<div class="sidebar-right">
<div class="sidebar-card">
<h4>友達リスト</h4>
<p><strong>佐藤花子</strong> - オンライン</p>
<p><strong>鈴木次郎</strong> - 5分前</p>
<p><strong>高橋健太</strong> - オフライン</p>
</div>
<div class="sidebar-card">
<h4>グループ</h4>
<p><a href="#">プロジェクトチーム</a> - 15人</p>
<p><a href="#">温泉旅行クラブ</a> - 32人</p>
</div>
<div class="chat-window">
<h4>チャット - 佐藤花子</h4>
<div class="chat-message">
<div class="comment-text">おはよう!週末の予定は?</div>
</div>
<div class="chat-message sent">
<div class="comment-text">おはよう!温泉行くよ!</div>
</div>
<input type="text" class="comment-input" placeholder="メッセージを入力...">
</div>
</div>
</div>
<!-- 投稿モーダル -->
<div id="postModal" class="modal">
<div class="modal-content">
<h3>投稿を作成</h3>
<textarea rows="6" placeholder="詳細を書いてね" style="width: 100%; padding: 10px;"></textarea>
<div style="margin: 15px 0;">
<label>公開範囲: </label>
<select style="padding: 5px;">
<option>公開</option>
<option>友達のみ</option>
<option>自分のみ</option>
</select>
</div>
<div class="post-actions">
<button onclick="document.getElementById('postModal').style.display='none'">キャンセル</button>
<button class="submit-btn">投稿</button>
</div>
</div>
</div>
<!-- 通知ポップアップ -->
<div class="notification-popup">
<p><strong>佐藤花子</strong>があなたの投稿にリアクションしました。</p>
</div>
<!-- フッター -->
<div class="footer">
<p>© 2025 究極SNS. All rights reserved.</p>
<p><a href="#">プライバシー</a> | <a href="#">利用規約</a> | <a href="#">サポート</a> | <a href="#">言語</a></p>
</div>
<script>
// 簡易的な通知ポップアップの表示制御(サンプル)
setTimeout(() => {
document.querySelector('.notification-popup').style.display = 'block';
setTimeout(() => {
document.querySelector('.notification-popup').style.display = 'none';
}, 3000);
}, 2000);
</script>
</body>
</html>
脳波で動かすWindows
脳波でWindowsを操作する方法は、現在の技術でも一定の範囲で可能です。代表的な方法を紹介します。
① EEG(脳波)ヘッドセットの使用
市販のEEG(脳波計測)デバイスを使い、脳波を計測してWindowsを操作できます。
主な製品
- NeuroSky MindWave
- Emotiv Insight / EPOCシリーズ
- Museヘッドセット
これらは、ユーザーの集中やリラックス、あるいは特定の動作イメージによる脳波パターンを検出し、Windows向けのソフトウェアと連携して簡単な操作を可能にしています。
② 脳波→Windows操作への変換ソフトウェアの活用
以下のソフトウェアで脳波をPC操作のコマンドに変換可能です。
- Emotiv BCI
- Emotiv製ヘッドセット専用。脳波パターンを特定の操作(クリックやキー入力)に変換可能。
- NeuroSky SDK
- MindWaveシリーズ向け。脳波を使ったアプリ開発やPC操作用プログラム開発に対応。
- OpenBCI
- オープンソースEEGヘッドセット向けのソフトウェア開発環境。カスタマイズ性が高い。
③ 実際に可能な操作例
- マウスカーソルの簡易な操作(クリックやカーソル移動)
- キーボードショートカット操作
- 特定アプリの起動
- ゲームやアプリでの簡単なコマンド実行(前進・後退など)
④ 実際の課題・注意点
- 精度はまだ限定的であり、細かな操作には向かない。
- 操作には訓練と慣れが必要。
- ヘッドセットの装着方法や髪型など、身体的な制約もある。
実用的な導入例(初心者向け)
初めての場合は 「Emotiv Insight」 や 「NeuroSky MindWave」 を購入し、公式ソフトウェアと連携してWindows操作を試みることをおすすめします。
脳波によるWindows操作は発展途上の技術ですが、手の不自由な方や新しいインターフェースを探究したいユーザーにとっては魅力的な選択肢となっています。
4.5
生と死とアート
生と死、そしてアートは、古来より人間が最も深く探求してきたテーマである。この三者は密接に絡み合い、人間の存在そのものを問いかけている。本論文では、生と死をめぐる芸術的表現が持つ意味を考察し、人間がなぜ芸術を通じてこれらの概念を理解しようと試みるのかを明らかにする。
まず、生というテーマは芸術において多くの場合、創造や再生、希望の象徴として描かれる。ルネサンス期の絵画や彫刻に見られる生命力溢れる身体表現は、人間の肉体美や精神の高揚を讃えている。例えばミケランジェロの『ダヴィデ像』は、若さと可能性に満ちた生命力を表現し、人間の理想美を追求する芸術家の熱意を反映している。
一方で、死は芸術において生と対照的な存在としてだけでなく、生命の有限性や儚さを際立たせる重要な要素となる。メメント・モリ(死を想え)の思想に基づく作品群は、生の尊さを逆説的に強調する役割を果たしている。中世後期からバロック期にかけて流行したヴァニタス画は、頭蓋骨や枯れた花などを描き、人間の儚さを鑑賞者に強烈に意識させた。
また、生と死のテーマは、単に対立する概念として捉えられるだけでなく、連続性のある過程として表現されることも多い。これは特に現代美術に顕著であり、パフォーマンスアートや映像作品において、生と死の境界を曖昧にすることで、新たな生のあり方や、死後の存在を模索する傾向が見られる。例えば、マリーナ・アブラモヴィッチのパフォーマンスは、生と死の境界を超えた精神的体験を観客と共有し、人間存在の本質に迫ろうとしている。
アートが生と死のテーマを扱う際、重要なのは「感情移入」と「共感」である。芸術を通して人は、自らが未だ経験していない死を疑似体験し、他者の生に触れることで、自身の生命観を更新する。これが、古来より人間が芸術において生と死を追求してきた最大の理由であろう。
結論として、生と死という究極的なテーマは、アートを通じて人間が自身の存在や意味を探求するための普遍的な手段となっている。生と死が織りなす無限の問いに対して、芸術は唯一の答えではなく、多様な解釈と体験を提供する開かれた場として機能しているのである。
ダンジョンのギミック
1. ダンジョンの構成要素
- 入口・出口
- プレイヤーがダンジョンに入るポイントと、クリアのために到達する出口。
- 部屋(Room)
- 敵との戦闘やイベントが起こる場所。
- 宝箱やNPCとの出会いが配置可能。
- 通路(Corridor)
- 部屋同士を繋ぐ経路。
- 単純な一本道、迷路、あるいは分岐などが考えられる。
- 罠(Trap)
- プレイヤーの行動を制限・妨害する仕掛け。
- 鍵や扉
- 特定のアイテムや条件を満たさないと先へ進めない仕掛け。
2. 敵の出現パターン
- 固定配置型
- 敵が決まった場所に存在。
- ランダムエンカウント型
- 移動時や特定条件でランダムに敵が出現。
- 条件トリガー型
- 宝箱を開けたりスイッチを押すと敵が出現。
3. アイテム配置ロジック
- 宝箱の配置
- 回復アイテムや装備、重要な鍵アイテムを適度に分散。
- ドロップアイテム
- 敵がランダムで落とすアイテム。
4. 探索と謎解き要素
- パズルギミック
- スイッチやレバー、順番通りに動かすパズルなど。
- ヒントの設置
- 壁画やメモ、NPCの会話などでプレイヤーに手がかりを与える。
5. 難易度調整ロジック
- ダンジョン階層
- 下に行くほど敵が強くなるような階層型。
- プレイヤーレベル連動
- プレイヤーのレベルに応じて敵や報酬の内容が変わる。
6. 報酬のロジック
- ボス討伐時の報酬
- 装備品、経験値、特別なスキル。
- クリア後のリプレイ性
- 特定条件を満たしてクリアすると追加報酬や新規ルートが解放。
CSS メディアクエリー
style.css
@charset "utf-8";
.card {
border: 1px solid #ccc;
box-sizing: border-box;
padding: 16px;
max-width: 600px;
margin: 0 auto;
&:hover {
box-shadow: 0 0 8px rgb(0 0 0 / 0.3);
}
h2 {
margin: 0;
border-bottom: 1px solid #ccc;
text-align: center;
font-size: 18px;
padding-bottom: 8px;
}
p {
margin: 16px 0 0;
line-height: 1.6;
}
}
@media (width >=600px) {
.card h2 {
text-align: left;
}
}
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My CSS Nesting</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="card">
<h2>こんにちは</h2>
<p>こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。</p>
</section>
</body>
</html>