Node.js

server.js

var http = require('http');
var settings = require('./settings');
console.log(settings);
var server = http.createServer();
server.on('request', function(req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.write('hello world !!!');
    res.end();
});
server.listen(settings.port, settings.host);
console.log("server listening ...");

settings.js

exports.port = 1337;
exports.host = '192.168.33.72';

MyCSSVariables

index.html

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="utf-8">
    <title>CSS変数</title>
    <link rel="stylesheet" href="css/styles.css">
</head>

<body>
    <h1>タイトル</h1>
    <p>こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。</p>
    <div class="btn">OK</div>
</body>

</html>

C:\MyCSSVariables\css

style.css

:root {
    /* --my-hue: 100; */
    /* --my-hue: 200; */
    --my-hue: 50;
}

body {
    background: hsl(var(--my-hue), 40%, 95%);
}

h1,
p {
    color: hsl(var(--my-hue), 35%, 55%);
}

.btn {
    color: #fff;
    width: 100px;
    padding: 8px;
    border-radius: 4px;
    text-align: center;
    /* background: hsl(var(--my-hue), 50%, 50%); */
    /* background: hsl(calc(var(--my-hue) + 180), 50%, 50%); */
    background: hsl(calc(var(--my-hue) + 60), 50%, 50%); }

C# コンストラクタ

using System;

// コンストラクタ

class User {
  public string name;
  // public User() {
  //   this.name = "ME";
  // }
  public User(string name) {
    this.name = name;
  }
  // public User() { // オーバーロード
  //   this.name = "nobody";
  // }
  public User(): this("nobody") {
  }
  public void SayHi() {
    Console.WriteLine($"hi {name}");
  }
}

class MyApp {

  static void Main() {
    // User user = new User();
    // user.SayHi();
    User tom = new User("Tom");
    tom.SayHi();
    User user = new User();
    user.SayHi();
  }

}

C# List

using System;
using System.Collections.Generic;

// Collection
// - List
// - HashSet
// - Dictionary

class MyApp {

  static void Main() {
    // List<int> scores = new List<int>();
    // scores.Add(30);
    // scores.Add(80);
    // scores.Add(60);
    List<int> scores = new List<int>() { 30, 80 , 60 };
    scores[1] = 100;
    Console.WriteLine(scores.Count);
    foreach (var score in scores) {
      Console.WriteLine(score);
    }
  }

}

人間の記憶を記録するサイト

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Memory Recorder Pro</title>
  <!-- Bootstrap CSS & Icons -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
  <!-- Chart.js for statistics -->
  <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
  <style>
    :root{
      --bg-main:#ffffff;
      --bg-gradient:linear-gradient(135deg,#f8f9fa 0%,#e9ecef 100%);
      --text-main:#212529;
      --accent:#0d6efd;
    }
    :root.dark{
      --bg-main:#1e1e1e;
      --bg-gradient:linear-gradient(135deg,#2b2b2b 0%,#1e1e1e 100%);
      --text-main:#f8f9fa;
    }
    body{
      background:var(--bg-gradient);
      color:var(--text-main);
      min-height:100vh;
      display:flex;
      align-items:center;
      justify-content:center;
      font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;
      transition:background .3s ease,color .3s ease;
    }
    .memory-app{
      width:100%;
      max-width:920px;
      background:var(--bg-main);
      padding:2rem 2.5rem;
      border-radius:1.5rem;
      box-shadow:0 4px 20px rgba(0,0,0,.1);
      transition:background .3s ease;
    }
    .memory-card{
      border-left:4px solid var(--accent);
      padding-left:1rem;
      margin-bottom:1rem;
    }
    .tag-badge{
      background:var(--accent);
      color:#fff;
      margin-right:.25rem;
      cursor:pointer;
    }
    .btn-accent{
      background:var(--accent);
      border-color:var(--accent);
      color:#fff;
    }
  </style>
</head>
<body>
  <div class="memory-app">
    <!-- Header -->
    <div class="d-flex justify-content-between align-items-center mb-4">
      <h1 class="m-0">📝 Memory Recorder <small class="h6 fw-light">Pro</small></h1>
      <div class="d-flex align-items-center gap-3">
        <button id="statsBtn" class="btn btn-outline-secondary btn-sm"><i class="bi bi-bar-chart"></i></button>
        <div class="form-check form-switch m-0">
          <input class="form-check-input" type="checkbox" id="darkModeSwitch">
        </div>
      </div>
    </div>

    <!-- Search & Stats row -->
    <div class="row g-3 align-items-end mb-4">
      <div class="col-md-8">
        <label for="searchInput" class="form-label">検索(テキスト / タグ)</label>
        <input type="text" id="searchInput" class="form-control" placeholder="キーワードで検索...">
      </div>
      <div class="col-md-4 text-md-end">
        <p id="stats" class="mb-0 small text-muted"></p>
      </div>
    </div>

    <!-- Input Area -->
    <div class="mb-3">
      <label for="memoryText" class="form-label">新しい記憶</label>
      <textarea class="form-control" id="memoryText" rows="3" placeholder="出来事・思い出など..."></textarea>
    </div>
    <div class="mb-4 row g-2 align-items-end">
      <div class="col-md-8">
        <label for="memoryTags" class="form-label">タグ(カンマ区切り)</label>
        <input type="text" id="memoryTags" class="form-control" placeholder="例: 仕事, 家族, 趣味">
      </div>
      <div class="col-md-4 d-flex gap-2 mt-md-4">
        <button id="saveBtn" class="btn btn-primary flex-grow-1"><i class="bi bi-save"></i> 保存</button>
        <button id="voiceBtn" class="btn btn-outline-secondary" title="音声入力"><i class="bi bi-mic"></i></button>
      </div>
    </div>

    <!-- File / Clear row -->
    <div class="d-flex flex-wrap gap-2 mb-4">
      <button id="exportBtn" class="btn btn-outline-secondary"><i class="bi bi-download"></i> エクスポート</button>
      <button id="importBtn" class="btn btn-outline-secondary"><i class="bi bi-upload"></i> インポート</button>
      <button id="clearAllBtn" class="btn btn-outline-danger ms-auto"><i class="bi bi-trash"></i> 全削除</button>
      <input type="file" id="importFile" accept="application/json" class="d-none">
    </div>

    <hr>
    <h2 class="h5 mb-3">📚 保存された記憶</h2>
    <div id="memoryList"></div>
  </div>

  <!-- Statistics Modal -->
  <div class="modal fade" id="statsModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-lg modal-dialog-centered">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title"><i class="bi bi-graph-up"></i> 記憶統計</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          <canvas id="statsChart" height="120"></canvas>
        </div>
      </div>
    </div>
  </div>

  <!-- Edit Modal -->
  <div class="modal fade" id="editModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title">記憶を編集</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          <div class="mb-3">
            <label for="editText" class="form-label">内容</label>
            <textarea id="editText" class="form-control" rows="4"></textarea>
          </div>
          <div class="mb-3">
            <label for="editTags" class="form-label">タグ(カンマ区切り)</label>
            <input id="editTags" class="form-control">
          </div>
        </div>
        <div class="modal-footer">
          <button class="btn btn-secondary" data-bs-dismiss="modal">キャンセル</button>
          <button id="editSaveBtn" class="btn btn-primary">保存</button>
        </div>
      </div>
    </div>
  </div>

  <!-- Bootstrap JS -->
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
  <script>
    // --------- Constants ---------
    const STORAGE_KEY = "memories";
    const THEME_KEY   = "prefers-dark";

    // --------- Helpers ---------
    const $ = sel => document.querySelector(sel);
    const modal = id => new bootstrap.Modal($(id));

    const memories = {
      list() { return JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]"); },
      save(arr) { localStorage.setItem(STORAGE_KEY, JSON.stringify(arr)); },
      add(obj){ const arr = this.list(); arr.push(obj); this.save(arr);} ,
      remove(id){ this.save(this.list().filter(m=>m.id!==id));},
      update(id,data){ const arr=this.list().map(m=>m.id===id?{...m,...data}:m); this.save(arr);} ,
    };

    const fmtDate = d => new Intl.DateTimeFormat("ja-JP",{dateStyle:"medium",timeStyle:"short"}).format(d);

    // --------- Rendering ---------
    function renderMemories(filter=""){
      const listEl = $("#memoryList");
      listEl.innerHTML="";
      const all = memories.list();
      const lower = filter.toLowerCase();
      const visible = all.filter(m=>{
        const tagMatch = m.tags.some(t=>t.toLowerCase().includes(lower));
        const textMatch= m.text.toLowerCase().includes(lower);
        return !lower || tagMatch || textMatch;
      }).reverse();

      // stats
      $("#stats").textContent=`合計: ${all.length} 件`;

      if(!visible.length){listEl.innerHTML='<p class="text-muted">該当する記憶がありません。</p>';return;}

      visible.forEach(m=>{
        const card=document.createElement("div");
        card.className="memory-card card";
        card.innerHTML=`<div class="card-body p-3">
          <div class="d-flex justify-content-between align-items-start flex-wrap">
            <h5 class="card-title mb-1">${fmtDate(new Date(m.date))}</h5>
            <div class="btn-group btn-group-sm">
              <button class="btn btn-link text-primary" title="編集" onclick="openEditor('${m.id}')"><i class="bi bi-pencil"></i></button>
              <button class="btn btn-link text-danger" title="削除" onclick="deleteMemory('${m.id}')"><i class="bi bi-trash"></i></button>
            </div>
          </div>
          <p class="card-text" style="white-space:pre-wrap;">${m.text}</p>
          <div class="mt-2">${m.tags.map(t=>`<span class=\"badge tag-badge\" onclick=\"filterTag('${t}')\">${t}</span>`).join(" ")}</div>
        </div>`;
        listEl.appendChild(card);
      });
    }

    // --------- CRUD ---------
    function saveMemory(){
      const text=$("#memoryText").value.trim();
      const tagRaw=$("#memoryTags").value.trim();
      if(!text)return;
      const tags=tagRaw?tagRaw.split(/\s*,\s*/).filter(Boolean):[];
      memories.add({id:crypto.randomUUID(),text,tags,date:new Date().toISOString()});
      $("#memoryText").value="";
      $("#memoryTags").value="";
      renderMemories($("#searchInput").value);
    }
    function deleteMemory(id){
      if(!confirm("削除しますか?"))return;
      memories.remove(id);
      renderMemories($("#searchInput").value);
    }

    // --------- Edit ---------
    let editingId=null;
    function openEditor(id){
      editingId=id;
      const m=memories.list().find(x=>x.id===id);
      $("#editText").value=m.text;
      $("#editTags").value=m.tags.join(", ");
      modal('#editModal').show();
    }
    $("#editSaveBtn").addEventListener("click",()=>{
      const text=$("#editText").value.trim();
      const tags=$("#editTags").value.trim().split(/\s*,\s*/).filter(Boolean);
      memories.update(editingId,{text,tags});
      modal('#editModal').hide();
      renderMemories($("#searchInput").value);
    });

    // --------- Filter helper ---------
    function filterTag(tag){
      $("#searchInput").value=tag;
      renderMemories(tag);
    }

    // --------- Export / Import ---------
    function exportMemories(){
      const blob=new Blob([JSON.stringify(memories.list(),null,2)],{type:"application/json"});
      const url=URL.createObjectURL(blob);
      const a=document.createElement("a");
      a.href=url;a.download="memories.json";a.click();URL.revokeObjectURL(url);
    }
    function importMemories(file){
      const reader=new FileReader();
      reader.onload=e=>{try{const arr=JSON.parse(e.target.result);if(Array.isArray(arr)){memories.save([...memories.list(),...arr]);renderMemories($("#searchInput").value);}else throw 0;}catch{alert("無効なファイルです");}};
      reader.readAsText(file);
    }

    // --------- Statistics ---------
    let chartInstance=null;
    function openStats(){
      const data=memories.list();
      const counts={};
      data.forEach(m=>{
        const key=m.date.slice(0,7); // YYYY-MM
        counts[key]=(counts[key]||0)+1;
      });
      const labels=Object.keys(counts).sort();
      const values=labels.map(l=>counts[l]);
      const ctx=$("#statsChart");
      if(chartInstance)chartInstance.destroy();
      chartInstance=new Chart(ctx,{type:'bar',data:{labels,datasets:[{label:'記憶数',data:values}]},options:{plugins:{legend:{display:false}}}});
      modal('#statsModal').show();
    }

    // --------- Dark Mode ---------
    function applyTheme(dark){
      document.documentElement.classList.toggle('dark',dark);
      localStorage.setItem(THEME_KEY,dark?'1':'0');
      $("#darkModeSwitch").checked=dark;
    }

    // --------- Voice Input (Experimental) ---------
    let rec=null;
    async function startVoice(){
      if(!('webkitSpeechRecognition'in window||'SpeechRecognition'in window)){alert('音声認識非対応');return;}
      const Speech=window.SpeechRecognition||window.webkitSpeechRecognition;
      rec=new Speech();
      rec.lang='ja-JP';
      rec.continuous=false;
      rec.interimResults=false;
      rec.onresult=e=>{$('#memoryText').value=e.results[0][0].transcript;};
      rec.start();
    }

    // --------- Init ---------
    document.addEventListener('DOMContentLoaded',()=>{
      // Theme
      applyTheme(localStorage.getItem(THEME_KEY)==='1');

      // Render memories
      renderMemories();

      // Listeners
      $('#saveBtn').addEventListener('click',saveMemory);
      $('#clearAllBtn').addEventListener('click',()=>{if(confirm('すべて削除しますか?')){localStorage.removeItem(STORAGE_KEY);renderMemories();}});
      $('#exportBtn').addEventListener('click',exportMemories);
      $('#importBtn').addEventListener('click',()=>$('#importFile').click());
      $('#importFile').addEventListener('change',e=>{if(e.target.files[0])importMemories(e.target.files[0]);e.target.value='';});
      $('#darkModeSwitch').addEventListener('change',e=>applyTheme(e.target.checked));
      $('#searchInput').addEventListener('input',e=>renderMemories(e.target.value));
      $('#memoryText').addEventListener('keydown',e=>{if(e.key==='Enter'&&(e.ctrlKey||e.metaKey))saveMemory();});
      $('#statsBtn').addEventListener('click',openStats);
      $('#voiceBtn').addEventListener('click',startVoice);
    });
  </script>
</body>
</html>

Googleの人気記事を拾ってくるサイト

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <title>Googleニュース 人気記事アグリゲーター</title>
  <!-- Bootstrap CSS -->
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
  <style>
    body { background: #f8f9fa; padding-top: 20px; font-family: 'Arial', sans-serif; transition: background .3s, color .3s; }
    .dark-mode { background: #2c2c2c; color: #f1f1f1; }
    #controls { margin-bottom: 20px; }
    .card { border-radius: 10px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); margin-bottom: 15px; transition: transform .2s, background .3s, color .3s; }
    .dark-mode .card { background: #3a3a3a; color: #f1f1f1; }
    .card:hover { transform: translateY(-3px); }
    .card-title { font-size: 1.25rem; margin-bottom: .5rem; }
    .meta { font-size: 0.85rem; color: #6c757d; margin-bottom: .5rem; }
    .dark-mode .meta { color: #ccc; }
    .thumbnail { width: 100%; height: auto; border-top-left-radius: 10px; border-top-right-radius: 10px; }
    #loading { display: none; font-size: 2rem; text-align: center; margin-top: 40px; }
    #error { display: none; color: red; text-align: center; margin-top: 20px; }
    @media (min-width: 768px) {
      #articles .col-md-6 { flex: 0 0 50%; max-width: 50%; }
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="d-flex justify-content-between align-items-center mb-3">
      <h1>Googleニュース 人気記事</h1>
      <button id="darkModeToggle" class="btn btn-outline-secondary">ダークモード</button>
    </div>
    <div id="controls" class="d-flex flex-wrap justify-content-between align-items-end">
      <div class="form-group mb-2 mr-2">
        <label for="categorySelect">カテゴリ:</label>
        <select id="categorySelect" class="form-control">
          <option value="WORLD">世界</option>
          <option value="BUSINESS">ビジネス</option>
          <option value="TECHNOLOGY">テクノロジー</option>
          <option value="ENTERTAINMENT">エンタメ</option>
          <option value="SPORTS">スポーツ</option>
          <option value="SCIENCE">科学</option>
          <option value="HEALTH">健康</option>
        </select>
      </div>
      <div class="form-group mb-2 mr-2 flex-grow-1">
        <label for="searchInput">キーワード:</label>
        <input id="searchInput" type="text" class="form-control" placeholder="タイトルで絞り込み">
      </div>
      <div class="form-group mb-2 mr-2">
        <label for="maxItems">表示数:</label>
        <input id="maxItems" type="number" class="form-control" value="20" min="1" max="100">
      </div>
      <button id="refreshBtn" class="btn btn-primary mb-2">更新</button>
    </div>
    <div id="loading"><i class="fas fa-spinner fa-spin"></i> 読み込み中...</div>
    <div id="error"></div>
    <div id="articles" class="row"></div>
  </div>

  <!-- FontAwesome & jQuery & Bootstrap JS -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/js/all.min.js"></script>
  <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.bundle.min.js"></script>
  <script>
    const controls = {
      category: document.getElementById('categorySelect'),
      search: document.getElementById('searchInput'),
      maxItems: document.getElementById('maxItems'),
      refresh: document.getElementById('refreshBtn'),
      darkToggle: document.getElementById('darkModeToggle')
    };
    const articlesContainer = document.getElementById('articles');
    const loading = document.getElementById('loading');
    const errorMsg = document.getElementById('error');
    const body = document.body;

    function getFeedUrl(topic) {
      return `https://news.google.com/rss/headlines/section/topic/${topic}?hl=ja&gl=JP&ceid=JP:ja`;
    }
    async function fetchArticles() {
      articlesContainer.innerHTML = '';
      errorMsg.style.display = 'none';
      loading.style.display = 'block';
      const topic = controls.category.value;
      const apiUrl = `https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(getFeedUrl(topic))}`;
      try {
        const res = await fetch(apiUrl);
        const data = await res.json();
        if (data.status !== 'ok') throw new Error('取得失敗');
        let items = data.items.map(item => ({
          title: item.title,
          link: item.link,
          date: new Date(item.pubDate),
          thumbnail: item.thumbnail || ''
        }));
        const kw = controls.search.value.trim();
        if (kw) items = items.filter(i => i.title.includes(kw));
        items = items.slice(0, parseInt(controls.maxItems.value) || items.length);
        render(items);
      } catch (e) {
        console.error(e);
        errorMsg.textContent = '記事の取得に失敗しました。';
        errorMsg.style.display = 'block';
      } finally {
        loading.style.display = 'none';
      }
    }
    function render(items) {
      if (!items.length) {
        articlesContainer.innerHTML = '<p class="text-center w-100">該当する記事がありません。</p>';
        return;
      }
      items.forEach(i => {
        const col = document.createElement('div'); col.className = 'col-12 col-md-6';
        const thumb = i.thumbnail ? `<img src="${i.thumbnail}" class="thumbnail" alt="サムネイル">` : '';
        col.innerHTML = `
          <div class="card">
            ${thumb}
            <div class="card-body">
              <h2 class="card-title"><a href="${i.link}" target="_blank">${i.title}</a></h2>
              <p class="meta">公開: ${i.date.toLocaleString()}</p>
            </div>
          </div>`;
        articlesContainer.appendChild(col);
      });
    }
    controls.refresh.addEventListener('click', fetchArticles);
    controls.darkToggle.addEventListener('click', () => {
      body.classList.toggle('dark-mode');
    });
    document.addEventListener('DOMContentLoaded', fetchArticles);
  </script>
</body>
</html>

Eternal.html 画像投稿サイト

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Eternal</title>
  <style>
    body {
      font-family: sans-serif;
      background: #f5f5f5;
      margin: 0;
      padding: 0;
    }

    header {
      background: #e60023;
      color: white;
      padding: 1em;
      text-align: center;
      font-size: 1.8em;
    }

    .controls {
      padding: 1em;
      background: #fff;
      text-align: center;
    }

    .controls input, .controls button {
      margin: 0.5em;
      padding: 0.5em;
      font-size: 1em;
    }

    .grid {
      column-count: 4;
      column-gap: 1em;
      padding: 1em;
    }

    .pin {
      background: white;
      display: inline-block;
      margin-bottom: 1em;
      width: 100%;
      box-sizing: border-box;
      border-radius: 10px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
      overflow: hidden;
      position: relative;
    }

    .pin img {
      width: 100%;
      cursor: pointer;
    }

    .description, .tags {
      padding: 0.5em;
    }

    .favorite {
      position: absolute;
      top: 8px;
      right: 8px;
      font-size: 22px;
      color: gray;
      cursor: pointer;
      user-select: none;
    }

    .favorite.active {
      color: gold;
    }

    .likes {
      font-size: 0.9em;
      text-align: right;
      padding: 0 0.5em 0.5em 0;
      color: #888;
    }

    .tag {
      display: inline-block;
      background: #eee;
      padding: 0.2em 0.5em;
      border-radius: 5px;
      margin: 0.2em;
      cursor: pointer;
    }

    .tag:hover {
      background: #ccc;
    }

    @media screen and (max-width: 1024px) {
      .grid {
        column-count: 3;
      }
    }

    @media screen and (max-width: 768px) {
      .grid {
        column-count: 2;
      }
    }

    @media screen and (max-width: 480px) {
      .grid {
        column-count: 1;
      }
    }

    #modal {
      position: fixed;
      top: 0; left: 0; right: 0; bottom: 0;
      background: rgba(0,0,0,0.7);
      display: none;
      justify-content: center;
      align-items: center;
      z-index: 1000;
    }

    #modal img {
      max-width: 90%;
      max-height: 80vh;
      border-radius: 10px;
    }
  </style>
</head>
<body>

<header>Pintorrest 完全版</header>

<div class="controls">
  <input type="file" id="imageInput" accept="image/*">
  <input type="text" id="descInput" placeholder="説明">
  <input type="text" id="tagInput" placeholder="タグ(カンマ区切り)">
  <button onclick="addPin()">投稿</button>
  <br>
  <input type="text" id="searchBox" placeholder="検索..." oninput="filterPins()">
</div>

<div class="grid" id="grid"></div>

<div id="modal" onclick="this.style.display='none'">
  <img id="modalImg" src="">
</div>

<script>
  let pins = JSON.parse(localStorage.getItem("pins") || "[]");

  function renderPins() {
    const grid = document.getElementById("grid");
    grid.innerHTML = '';
    pins.forEach((pin, index) => {
      const pinElem = document.createElement("div");
      pinElem.className = "pin";
      pinElem.innerHTML = `
        <span class="favorite ${pin.favorited ? 'active' : ''}" onclick="toggleFavorite(${index}, this)">★</span>
        <img src="${pin.image}" onclick="showModal('${pin.image}')">
        <div class="description">${pin.desc}</div>
        <div class="tags">${pin.tags.map(tag => `<span class="tag" onclick="filterByTag('${tag}')">${tag}</span>`).join(' ')}</div>
        <div class="likes">♥ ${pin.likes}</div>
      `;
      grid.appendChild(pinElem);
    });
  }

  function addPin() {
    const imageInput = document.getElementById("imageInput");
    const desc = document.getElementById("descInput").value.trim();
    const tags = document.getElementById("tagInput").value.split(',').map(t => t.trim()).filter(Boolean);
    const file = imageInput.files[0];
    if (!file || !desc) return alert("画像と説明を入力してください");

    const reader = new FileReader();
    reader.onload = function(e) {
      pins.unshift({
        image: e.target.result,
        desc: desc,
        tags: tags,
        likes: 0,
        favorited: false
      });
      savePins();
      renderPins();
      document.getElementById("descInput").value = '';
      document.getElementById("tagInput").value = '';
      document.getElementById("imageInput").value = '';
    };
    reader.readAsDataURL(file);
  }

  function showModal(src) {
    document.getElementById("modalImg").src = src;
    document.getElementById("modal").style.display = 'flex';
  }

  function toggleFavorite(index, elem) {
    pins[index].favorited = !pins[index].favorited;
    pins[index].likes += pins[index].favorited ? 1 : -1;
    savePins();
    renderPins();
  }

  function savePins() {
    localStorage.setItem("pins", JSON.stringify(pins));
  }

  function filterPins() {
    const keyword = document.getElementById("searchBox").value.toLowerCase();
    document.querySelectorAll(".pin").forEach(pin => {
      const text = pin.textContent.toLowerCase();
      pin.style.display = text.includes(keyword) ? "inline-block" : "none";
    });
  }

  function filterByTag(tag) {
    document.getElementById("searchBox").value = tag;
    filterPins();
  }

  renderPins();
</script>

</body>
</html>

『SDガンダム ジージェネレーション エターナル』レビュー

『SDガンダム ジージェネレーション エターナル』レビュー

ジャンル:シミュレーション / 開発・運営:バンダイナムコエンターテインメント

概要

『Gジェネエターナル』は、ガンダムシリーズのモビルスーツとキャラクターを集めて、自軍を編成し、様々なステージを攻略していくモバイル向け戦略シミュレーションゲームです。『SDガンダム Gジェネレーション』シリーズのスマートフォン向け最新作で、シリーズファンの期待を背負ってリリースされました。


■良かった点

◎歴代ガンダム作品を網羅したボリューム

『機動戦士ガンダム』から『鉄血のオルフェンズ』、さらには外伝系作品やゲームオリジナルまで、数多くの機体やキャラが登場。ファンなら思わずニヤリとする場面も多く、図鑑埋めの楽しさは健在。

◎戦略性の高いユニット編成

部隊の編成やスキルの組み合わせによって難関ステージも突破可能。自分だけのドリームチームを作るのは、やはりGジェネならではの醍醐味。

◎フルボイス&原作再現シナリオ

ストーリー面では原作の名シーンがしっかり再現されており、アニメを追体験するような気持ちで楽しめます。フルボイス演出も没入感を高めています。


■気になった点

△課金バランスとガチャの厳しさ

ガチャの排出率が厳しめで、好きな機体やキャラを手に入れるにはかなりの課金が必要な印象。「お気に入りの機体で戦いたい」というシリーズの魅力を活かしきれていない部分があります。

△UIが重く、動作が不安定なことも

端末によってはロードが長く、操作がもたつくシーンもあります。改善アップデートに期待。

△オート戦闘頼りになりがち

戦闘のテンポや演出の派手さはやや地味で、結局「オートで周回して素材集め」が主なプレイスタイルになりがち。戦略性を楽しめるモードがもっと欲しいところ。


■総評

Gジェネファンにはたまらない「ガンダムのお祭りゲーム」であり、機体収集や編成の楽しさは健在。ただし、課金面や周回の作業感、UIなどスマホゲームとしての快適さには改善の余地がある。

評価:★★★☆☆(3.5/5)
ファン向けにはおすすめ。ただしガチャ運と根気も必要。


任天堂Switch 2ブレスオブザワイルドのグラフィック

任天堂Switch 2でブレスオブザワイルドのグラフィックは大幅に向上し、より美しく滑らかな表現が期待できます。具体的には、解像度が2倍以上になり、フレームレートも30fpsから60fpsに向上すると予想されます。

詳細な改善点:

  • 解像度:初代Switchの1080pから、Switch 2では約1440p(2.5K相当)まで向上。
  • フレームレート:初代Switchの30fpsから、Switch 2では60fpsに向上。
  • ローディング時間:初代Switchで25秒ほどかかっていたローディング時間が、Switch 2では15秒ほどに短縮されると予想されています。

その他:

  • Switch 2は、最大120fpsのフレームレートをサポートしますが、4K出力時は最大60fpsに制限されると 任天堂のよくあるご質問 に記載されています。
  • Switch 2ではHDR対応も期待できるため、より鮮やかな色彩表現も可能になると考えられます。

これらの向上により、ブレスオブザワイルドのグラフィックは、より美しく、より滑らかで、より快適なプレイ体験を提供すると期待されます。