■75個目 「シルエット・スタジオ」
こんにちは、AIと作る100のゲーム実験室の みー です。(*^_^*)/
今回は、ノスタルジックな雰囲気の、
影絵風アート制作ゲームを作ってみました。
夜のしじまに浮かぶ、温かいお月様のような光。
背景からの明かりに照らされて、ふんわりと、
そしてくっきりと浮かび上がる影たち…。
そんな優しいお絵描きの時間をイメージしています。
月明かりを浴びながら、まるで魔法の筆で影を描き出すような感覚。
光と影が織りなす、小さな物語の舞台です。
今回こだわったのは、この“夜のしじま”の静かで温かい雰囲気。
その中で、影を描いていく――。
そんな優しい世界を、ゲームを通して感じていただけたら嬉しいです。
どんな影の物語が生まれるのか、お楽しみに。(^^*)
■ AIとのやりとりで面白かった部分
● ゲーム仕様の相談からスタート
みー:(^v^)
今日もゲームを作ります。
HTML形式で動かせる、影絵風アートのお絵描きゲームを作りたいです。
背景からの明かりでふんわり、
そしてくっきりと形が浮かぶノスタルジックな雰囲気にしたいです。
左側の画面で、図形の大きさや向きを変えながら配置したり、
太さの変えられるペンで描いたりします。
右側の画面では、仕上がりの影絵が見られます。
仕上がり確認ボタンで拡大表示もできるようにしたいです。
AI:
いいですね、影絵風のアート制作ゲーム。
光と影のコントラストが美しい、
ノスタルジックな雰囲気のツールをHTML/JavaScriptで作成しました。
昔懐かしいシルエットアートを、自分の感性で組み立ててみてください。
みー:(^o^)
図形の位置は微調整したいので、つかんで動かせるようにできますか?
置いた後でもサイズや角度を変えられると嬉しいです。
図形の変形もできるといいです。
AI:
より本格的な「影絵エディタ」への進化ですね。
図形を「置いて終わり」ではなく、
あとからドラッグで移動、角を掴んでサイズ変更・回転が
できるように改良しました。
影絵の雰囲気を壊さないよう、
操作ガイドは左側のエディタ画面だけに表示し、
右側のプレビューには純粋な影だけが映るようになっています。
みー:(^_^)
図形のコピー&貼り付けと、複数図形のグループ化もできるようになりますか?
AI:
だいぶ本格的なデザインツールになってきましたね!
コピー&ペーストと、複数要素をまとめて扱えるグループ化を実装しました。
影絵では、同じ形の葉っぱを並べたり、
複数の図形で作ったキャラクターをまとめて動かしたりするので、
この機能はとても便利です。
みー:( ̄v ̄)b
図形を枠線だけにすることはできますか?太さも調整できる感じで。
AI:
影絵で「枠線のみ」の表現ができると、
ステンドグラスの枠組みやワイヤーアートのような
繊細な表現が一気に広がりますね。
光の輪郭だけが浮かび上がるのは絶対きれいです。
選択した図形を「塗りつぶし」から
「枠線のみ」に切り替えるチェックボックスと、
太さを調整できるスライダーを追加した完成版を用意しました。
■ 実際の動作
AI が作ってくれたゲーム画面がこちらです。
左側のエディタで描画すると、右側に影絵風の仕上がりが表示されます。

(画像:ゲーム画面)
サイズや角度を変えながら、図形を組み合わせて自由に作れます。

(画像:しょうが君)
マウスだと文字は少し書きづらいですが、
そのぶん手作り感が出て味わいがあります。

(画像:ジターリング)
影絵にすると、どんな図形も一気にファンタジーな世界観になります。

(画像:花と蝶)
■ コードのポイント
今回の記事では、AI と相談しながら作った
「シルエット・スタジオ」 の HTML コードを公開します。
このコードをそのまま保存するだけで、
あなたのPCでもすぐに遊べます。
ブラウザだけで動く、とてもシンプルなゲームなので、
気軽に試してみてくださいね。
▼ 遊ぶまでの手順
①PC の「メモ帳」(※Windowsの場合)や
Mac の「テキストエディット」など、テキストエディタを開きます。
②下のコードをコピーして貼り付けます。
③「kagee.html」など、好きな名前で保存します。
(※拡張子は .html にしてください)
④保存したファイルをブラウザで開けば、すぐに遊べます。
■ 操作方法
「シルエット・スタジオ」の遊び方のご紹介です!(^^*)
画面は大きく2つに分かれています。
左側の「エディタ」で図形を置いたり線を引いたりすると、
右側の「プレビュー」に和紙を通したような
ふんわりとした影がリアルタイムで浮かび上がります。(^_^)
■ 基本の遊び方
- 図形を置く
「四角形」や「円形」のボタンを押すと、
画面に図形がポンッと登場します。 - 移動する
「選択・移動」モードにして
図形をクリックしたまま引っ張る(ドラッグする)と、
好きな場所にスゥーッと動かせます。(=v=*)
■ 形をアレンジする
- くるくる回転
図形を選ぶと、上に小さな「持ち手(ハンドル)」が出現します。
ここをちょこんと摘まんでマウスを動かすと、
手で触っているみたいに直感的にくるくる回せます!
少し角度をつけるだけで、
動物のパーツなんかに命が吹き込まれたように見えますよ。(^^*) - 大きさを変える
メニューにある「幅」と「高さ」のスライダーを動かすと、
細長い形にしたり、平べったくしたり自由自在です。
■ もっとこだわる!特別機能
- ペンで自由にお絵描き
「ペン」モードにすれば、マウスを滑らせて好きな線を描き込めます。 - 枠線モード
図形を選んで「枠線のみにする」にチェックを入れると、
中身がくり抜かれて枠だけになります。
光の輪郭だけが浮かび上がって、
ステンドグラスやワイヤーアートみたいで
とっても綺麗なんですよ。(^_^)
線の太さもスライダーで調整できます。 - グループ化(まとめて操作)
キーボードの「Shift」キーを押しながら図形をいくつかクリックすると、
まとめて選択できます。
そのまま「グループ化」を押せば、
複数の図形を組み合わせて作ったキャラクターも、
1つのまとまりとして一気に動かしたり
大きさを変えたりできるようになります。(=v=*) - コピー&ペースト
同じ形の葉っぱや星をたくさん並べたい時に便利です!
最後に「全画面表示」ボタンを押せば、
画面いっぱいにあなたの作った影絵の世界が広がります!
“コードは長いので折りたたんでいます。必要な方は開いてご覧ください。”
▼ここからコード▼(クリックで開く)
<html lang="ja"><head> <meta charset="UTF-8"> <title>影絵エディタ - Evolution</title> <style> body { background-color: #1a1a1a; color: #e0e0e0; font-family: sans-serif; display: flex; flex-direction: column; align-items: center; margin: 0; } #header { padding: 10px; font-size: 1rem; letter-spacing: 2px; color: #a67c52; } #main-container { display: flex; gap: 15px; padding: 15px; background: #2a2a2a; border-radius: 12px; } .canvas-container { display: flex; flex-direction: column; align-items: center; gap: 5px; } canvas { border: 1px solid #444; background: #fff; touch-action: none; cursor: crosshair; } #previewCanvas { background: radial-gradient(circle, #fff9e6 0%, #e6d5b8 70%, #c2b280 100%); } #controls { width: 230px; display: flex; flex-direction: column; gap: 10px; padding: 15px; background: #333; border-radius: 8px; font-size: 0.85rem; max-height: 500px; overflow-y: auto; } .group-box { border: 1px solid #444; padding: 8px; border-radius: 4px; background: #3a3a3a; } label { font-size: 0.7rem; color: #aaa; display: block; margin-bottom: 3px; } .inline-label { display: inline-flex; align-items: center; gap: 5px; font-size: 0.8rem; color: #e0e0e0; cursor: pointer; margin-bottom: 5px; } button { width: 100%; padding: 6px; margin-bottom: 4px; cursor: pointer; background: #444; color: white; border: none; border-radius: 4px; } button:hover { background: #555; } button.active { background: #a67c52; border: 1px solid #fff; } input[type="range"] { width: 100%; margin-bottom: 5px; } .kbd { background: #222; padding: 2px 4px; border-radius: 3px; color: #fff9e6; } #modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.95); justify-content: center; align-items: center; z-index: 100; } #controls::-webkit-scrollbar { width: 6px; } #controls::-webkit-scrollbar-thumb { background: #555; border-radius: 3px; } </style></head><body><div id="header">SHADOW ART STUDIO EVOLUTION</div><div id="main-container"> <div class="canvas-container"> <label>エディタ(ハンドルを掴んで回転)</label> <canvas id="editorCanvas" width="500" height="500"></canvas> </div> <div id="controls"> <div class="group-box"> <label>描画モード</label> <button id="modePen" class="active" onclick="setMode('pen')">✎ ペン</button> <button id="modeSelect" onclick="setMode('select')">⇪ 選択・移動</button> </div> <div class="group-box"> <label>図形追加</label> <button onclick="addShape('rect')">□ 四角形</button> <button onclick="addShape('circle')">○ 円形</button> </div> <div class="group-box"> <label>編集</label> <button onclick="copyPaste()">コピー&ペースト</button> <button id="btnGroup" onclick="toggleGroup()" style="background:#546e7a;">グループ化 / 解除</button> <button onclick="deleteObjects()" style="background:#633;">削除 (Del)</button> </div> <div id="editParams" class="group-box" style="display:none;"> <label>選択中の変形・装飾</label> <div id="outlineControls"> <label class="inline-label"> <input type="checkbox" id="paramOutline"> 枠線のみにする </label> </div> <label id="lblLineW">線の太さ</label> <input type="range" id="paramLineW" min="1" max="50"> <label>幅 (Width)</label> <input type="range" id="paramW" min="5" max="400"> <label>高さ (Height)</label> <input type="range" id="paramH" min="5" max="400"> <label>回転</label> <input type="range" id="paramR" min="0" max="360"> </div> <button onclick="showFull()" style="background: #a67c52; margin-top:5px;">全画面表示</button> </div> <div class="canvas-container"> <label>影絵プレビュー</label> <canvas id="previewCanvas" width="500" height="500"></canvas> </div></div><div id="modal" onclick="this.style.display='none'"><canvas id="fullCanvas"></canvas></div><script> const eCanvas = document.getElementById('editorCanvas'), eCtx = eCanvas.getContext('2d'); const pCanvas = document.getElementById('previewCanvas'), pCtx = pCanvas.getContext('2d'); let objects = []; let selectedIndices = []; let mode = 'pen', isDragging = false, isRotating = false, dragStart = {x:0, y:0}, currentPath = []; function setMode(m) { mode = m; document.getElementById('modePen').classList.toggle('active', m==='pen'); document.getElementById('modeSelect').classList.toggle('active', m==='select'); eCanvas.style.cursor = m==='pen' ? 'crosshair' : 'default'; if(m === 'pen') selectedIndices = []; updateUI(); render(); } function addShape(type) { objects.push({ type, x: 250, y: 250, w: 80, h: 80, r: 0, isOutline: false, lw: 5 }); selectedIndices = [objects.length - 1]; setMode('select'); } // 図形本体の当たり判定 function isHit(o, mx, my) { let dx = mx - o.x, dy = my - o.y; let rad = -o.r * Math.PI / 180; let lx = dx * Math.cos(rad) - dy * Math.sin(rad); let ly = dx * Math.sin(rad) + dy * Math.cos(rad); let w = o.type === 'group' ? o.w * o.scaleX : o.w; let h = o.type === 'group' ? o.h * o.scaleY : (o.h || o.w); return Math.abs(lx) <= w/2 && Math.abs(ly) <= h/2; } // ★ 回転ハンドルの当たり判定 function isHandleHit(o, mx, my) { let dx = mx - o.x, dy = my - o.y; let rad = -o.r * Math.PI / 180; let lx = dx * Math.cos(rad) - dy * Math.sin(rad); let ly = dx * Math.sin(rad) + dy * Math.cos(rad); let h = o.type === 'group' ? o.h * o.scaleY : (o.h || o.w); // ハンドルの位置はローカル座標で (0, -h/2 - 25) let hy = -h/2 - 25; // 少し広めの判定(半径12px程度) return (lx - 0)**2 + (ly - hy)**2 <= 144; } eCanvas.onmousedown = (e) => { const x = e.offsetX, y = e.offsetY; if (mode === 'pen') { isDrawing = true; currentPath = [{x, y}]; } else { // ★ まず回転ハンドルを触ったかチェック if (selectedIndices.length === 1 && isHandleHit(objects[selectedIndices[0]], x, y)) { isRotating = true; } else { // ハンドルじゃない場合は図形のドラッグ判定 const hitIdx = objects.findLastIndex(o => isHit(o, x, y)); if (hitIdx !== -1) { if (e.shiftKey) { if (selectedIndices.includes(hitIdx)) selectedIndices = selectedIndices.filter(i => i !== hitIdx); else selectedIndices.push(hitIdx); } else { if (!selectedIndices.includes(hitIdx)) selectedIndices = [hitIdx]; } isDragging = true; dragStart = {x, y}; } else { selectedIndices = []; } } updateUI(); } render(); }; window.onmousemove = (e) => { const rect = eCanvas.getBoundingClientRect(); const x = e.clientX - rect.left, y = e.clientY - rect.top; if (mode === 'pen' && isDrawing) { currentPath.push({x, y}); } else if (isRotating) { // ★ マウスの位置から角度を計算して回転させる let o = objects[selectedIndices[0]]; let angle = Math.atan2(y - o.y, x - o.x); // 真上が-90度になるので、+90度補正する let deg = angle * 180 / Math.PI + 90; if (deg < 0) deg += 360; o.r = Math.round(deg); document.getElementById('paramR').value = o.r; // スライダーも同期 } else if (isDragging && selectedIndices.length > 0) { const dx = x - dragStart.x, dy = y - dragStart.y; selectedIndices.forEach(idx => { objects[idx].x += dx; objects[idx].y += dy; }); dragStart = {x, y}; } render(); }; window.onmouseup = () => { if (mode === 'pen' && currentPath.length > 1) { let xs = currentPath.map(p=>p.x), ys = currentPath.map(p=>p.y); let cx = (Math.min(...xs) + Math.max(...xs))/2; let cy = (Math.min(...ys) + Math.max(...ys))/2; let relPts = currentPath.map(p => ({ x: p.x - cx, y: p.y - cy })); objects.push({ type: 'path', points: relPts, x: cx, y: cy, w: Math.max(Math.max(...xs)-Math.min(...xs), 10), h: Math.max(Math.max(...ys)-Math.min(...ys), 10), r: 0, lw: 8 }); } isDrawing = isDragging = isRotating = false; currentPath = []; render(); }; function toggleGroup() { if (selectedIndices.length > 1) { let tgts = selectedIndices.map(i => objects[i]); let minX=Infinity, maxX=-Infinity, minY=Infinity, maxY=-Infinity; tgts.forEach(o => { let w = o.type==='group'?o.w*o.scaleX:o.w, h = o.type==='group'?o.h*o.scaleY:(o.h||o.w); let rad = Math.max(w, h); minX = Math.min(minX, o.x - rad/2); maxX = Math.max(maxX, o.x + rad/2); minY = Math.min(minY, o.y - rad/2); maxY = Math.max(maxY, o.y + rad/2); }); let cx = (minX+maxX)/2, cy = (minY+maxY)/2; tgts.forEach(o => { o.x -= cx; o.y -= cy; }); let grp = { type: 'group', x: cx, y: cy, w: maxX-minX, h: maxY-minY, r: 0, scaleX: 1, scaleY: 1, children: tgts }; objects = objects.filter((_, i) => !selectedIndices.includes(i)); objects.push(grp); selectedIndices = [objects.length - 1]; } else if (selectedIndices.length === 1 && objects[selectedIndices[0]].type === 'group') { let g = objects[selectedIndices[0]]; let rad = g.r * Math.PI / 180, cos = Math.cos(rad), sin = Math.sin(rad); g.children.forEach(c => { let sx = c.x * g.scaleX, sy = c.y * g.scaleY; c.x = g.x + (sx * cos - sy * sin); c.y = g.y + (sx * sin + sy * cos); c.r = (c.r + g.r) % 360; if(c.type === 'group') { c.scaleX *= g.scaleX; c.scaleY *= g.scaleY; } else { c.w *= g.scaleX; if(c.h) c.h *= g.scaleY; c.lw *= (g.scaleX+g.scaleY)/2; } objects.push(c); }); objects.splice(selectedIndices[0], 1); selectedIndices = []; } updateUI(); render(); } function copyPaste() { if (selectedIndices.length === 0) return; const newObjs = selectedIndices.map(idx => { const o = objects[idx]; return { ...JSON.parse(JSON.stringify(o)), x: o.x + 20, y: o.y + 20 }; }); const startIdx = objects.length; objects.push(...newObjs); selectedIndices = newObjs.map((_, i) => startIdx + i); render(); } function deleteObjects() { objects = objects.filter((_, i) => !selectedIndices.includes(i)); selectedIndices = []; updateUI(); render(); } function drawObj(ctx, o, isSelected) { ctx.save(); ctx.translate(o.x, o.y); ctx.rotate(o.r * Math.PI / 180); if (o.type === 'group') { ctx.scale(o.scaleX, o.scaleY); o.children.forEach(c => drawObj(ctx, c, false)); } else { ctx.fillStyle = ctx.strokeStyle = '#000'; ctx.lineCap = ctx.lineJoin = 'round'; if (o.type === 'path') { ctx.lineWidth = o.lw || 5; ctx.beginPath(); o.points.forEach((p, i) => i===0 ? ctx.moveTo(p.x, p.y) : ctx.lineTo(p.x, p.y)); ctx.stroke(); } else if (o.type === 'rect') { if (o.isOutline) { ctx.lineWidth = o.lw || 5; ctx.strokeRect(-o.w/2, -o.h/2, o.w, o.h); } else { ctx.fillRect(-o.w/2, -o.h/2, o.w, o.h); } } else if (o.type === 'circle') { ctx.beginPath(); ctx.ellipse(0, 0, o.w/2, o.h/2, 0, 0, Math.PI*2); if (o.isOutline) { ctx.lineWidth = o.lw || 5; ctx.stroke(); } else { ctx.fill(); } } } ctx.restore(); // 選択時の枠線と ★回転ハンドルの描画 if (isSelected && ctx === eCtx) { ctx.save(); ctx.translate(o.x, o.y); ctx.rotate(o.r * Math.PI / 180); ctx.strokeStyle = '#00ffcc'; ctx.lineWidth = 2; let sw = o.type === 'group' ? o.w * o.scaleX : o.w; let sh = o.type === 'group' ? o.h * o.scaleY : (o.h || o.w); ctx.strokeRect(-sw/2 - 2, -sh/2 - 2, sw + 4, sh + 4); // ハンドルを描画 (上部に飛び出る線と丸) ctx.beginPath(); ctx.moveTo(0, -sh/2 - 2); ctx.lineTo(0, -sh/2 - 25); ctx.stroke(); ctx.beginPath(); ctx.arc(0, -sh/2 - 25, 5, 0, Math.PI*2); ctx.fillStyle = '#fff'; ctx.fill(); ctx.stroke(); ctx.restore(); } } function render() { eCtx.clearRect(0, 0, 500, 500); pCtx.fillStyle = '#fff9e6'; pCtx.fillRect(0, 0, 500, 500); pCtx.save(); pCtx.filter = 'blur(3px) contrast(180%)'; [...objects, {type:'path', points:currentPath, x:0, y:0, r:0, lw:8}].forEach((o, i) => { if(!o || (o.type==='path' && (!o.points || o.points.length===0))) return; drawObj(eCtx, o, selectedIndices.includes(i)); drawObj(pCtx, o, false); }); pCtx.restore(); } function updateUI() { const panel = document.getElementById('editParams'), btnGrp = document.getElementById('btnGroup'); const outlineCtrl = document.getElementById('outlineControls'); const lineWCtrl = document.getElementById('paramLineW'); const lblLineW = document.getElementById('lblLineW'); if (selectedIndices.length === 1) { panel.style.display = 'block'; let o = objects[selectedIndices[0]]; document.getElementById('paramW').value = o.type === 'group' ? o.w * o.scaleX : o.w; document.getElementById('paramH').value = o.type === 'group' ? o.h * o.scaleY : (o.h || o.w); document.getElementById('paramR').value = o.r; if (o.type === 'path') { outlineCtrl.style.display = 'none'; lblLineW.style.display = 'block'; lineWCtrl.style.display = 'block'; lblLineW.innerText = "ペンの太さ"; lineWCtrl.value = o.lw || 8; } else if (o.type === 'group') { outlineCtrl.style.display = 'none'; lblLineW.style.display = 'none'; lineWCtrl.style.display = 'none'; } else { outlineCtrl.style.display = 'block'; lblLineW.style.display = o.isOutline ? 'block' : 'none'; lineWCtrl.style.display = o.isOutline ? 'block' : 'none'; lblLineW.innerText = "枠線の太さ"; document.getElementById('paramOutline').checked = o.isOutline || false; lineWCtrl.value = o.lw || 5; } } else { panel.style.display = 'none'; } if(selectedIndices.length > 1) btnGrp.innerText = "グループ化"; else if(selectedIndices.length === 1 && objects[selectedIndices[0]].type === 'group') btnGrp.innerText = "グループ解除"; else btnGrp.innerText = "グループ化 / 解除"; } document.getElementById('paramOutline').onchange = function() { if(selectedIndices.length !== 1) return; objects[selectedIndices[0]].isOutline = this.checked; updateUI(); render(); }; document.getElementById('paramLineW').oninput = function() { if(selectedIndices.length !== 1) return; objects[selectedIndices[0]].lw = parseInt(this.value); render(); }; document.getElementById('paramW').oninput = function() { if(selectedIndices.length !== 1) return; let o = objects[selectedIndices[0]]; if (o.type === 'group') o.scaleX = parseInt(this.value) / o.w; else o.w = parseInt(this.value); render(); }; document.getElementById('paramH').oninput = function() { if(selectedIndices.length !== 1) return; let o = objects[selectedIndices[0]]; if (o.type === 'group') o.scaleY = parseInt(this.value) / o.h; else if (o.type !== 'path') o.h = parseInt(this.value); render(); }; document.getElementById('paramR').oninput = function() { if(selectedIndices.length !== 1) return; objects[selectedIndices[0]].r = parseInt(this.value); render(); }; window.onkeydown = (e) => { if (e.key === 'Delete' || e.key === 'Backspace') deleteObjects(); }; function showFull() { const m = document.getElementById('modal'), c = document.getElementById('fullCanvas'), ctx = c.getContext('2d'); c.width = c.height = window.innerHeight * 0.9; ctx.scale(c.width/500, c.height/500); ctx.fillStyle = '#fff9e6'; ctx.fillRect(0,0,500,500); ctx.filter = 'blur(4px) contrast(200%)'; objects.forEach(o => drawObj(ctx, o, false)); m.style.display = 'flex'; } render();</script></body></html>
■ 今日の学び
毎回お絵描きゲームを紹介するたびにお話ししていますが、
私は絵を描くことは大好きなものの、決して上手なわけではありません。
だからでしょうか、私が作るツールはどうしても
「なんとなく、いい感じの雰囲気に仕上がる」ものが多い気がします。
白状しますと、今回は
「図形をボヤッとした影絵にしてしまえば、絵のヘタさもボヤッと誤魔化せるのでは?」
という、ちょっとズルい発想もありました。(つv=`)
案の定、ゲーム作りもそこそこに、
テストプレイと称して図形を組み合わせて遊ぶ“作品作り”のほうに
すっかり夢中になってしまいました。
思えば昔から、Excelの図形をパズルのように組み合わせて
オリジナルキャラクターを作るのが大好きでした。
今回のシルエットを組み立てるゲームも、
そんな「図形遊びが好き」という
私自身の原点から来ているんだと気づかされました。
せっかくなので、普段Excelで作っている図形アート作品の一部を
ここで少しだけご紹介しますね。(^^*)
まだ記事には載せていないゲームですが、
少し前に作ったゲームの元になったキャラクター「ブロッコリ君」も紛れ込んでいますよ。

(画像:エクセルで作成)
■ 次回は、
しょうが君のアクションゲームです。
今回のしょうが君は、なんと異世界を冒険します。 どんな場所へ飛ばされても、状況に合わせて先へ進んでいく “臨機応変アクション” がテーマです。 過酷な冒険の途中には、ウィルスのようなお邪魔キャラも登場します。 しょうがパワーで、ピンチを乗り越えていきましょう。
次回もぜひ遊びに来てくださいね。(*^v^)ノシ
✨今日も最後まで読んでくださって、ありがとうございます。
みーの実験室は、みなさんの応援で元気に動いています。(*^v^*)






🌈はじめての方へ
🌳 実験一覧
🌱 このブログについて
🍃 プライバシーポリシー
🐣未記事ゲーム展示室