Skip to content

Instantly share code, notes, and snippets.

@fsubal
Last active August 10, 2025 06:39
Show Gist options
  • Select an option

  • Save fsubal/ac08bba45e9626d7d6c0423770cd05fa to your computer and use it in GitHub Desktop.

Select an option

Save fsubal/ac08bba45e9626d7d6c0423770cd05fa to your computer and use it in GitHub Desktop.
漫画用に、架空のツイートや架空の記事のスクショが作れるジェネレーター( Generated by ChatGPT + GPT-5。利用自由 ) https://fsubal.github.io/fake-sns-screen/
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>note.com風記事モックジェネレータ</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, "Hiragino Kaku Gothic ProN", "Hiragino Sans", sans-serif;
margin: 0;
padding: 20px;
--width: 800px;
}
#app {
max-width: var(--width);
margin: 0 auto;
}
#controls {
margin-bottom: 20px;
}
#controls label {
margin-left: 8px;
font-size: 14px;
vertical-align: middle;
}
/* Article card */
.article {
background: #fff;
padding: 24px;
}
/* Cover image */
.cover-image {
width: 100%;
height: calc(var(--width) * 630 / 1200);
overflow: hidden;
margin-bottom: 20px;
background: #eee;
resize: vertical;
}
.cover-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* Title */
.article .title {
font-size: 28px;
font-weight: bold;
margin-bottom: 12px;
color: #111;
line-height: 1.3;
outline: none;
}
/* Meta row (likes) */
.meta-row {
display: flex;
align-items: center;
font-size: 14px;
color: #888;
margin-bottom: 16px;
}
.meta-row .heart {
font-size: 20px;
margin-right: 6px;
line-height: 1;
}
.meta-row .like-count {
outline: none;
}
/* Author row */
.author-row {
display: flex;
justify-content: space-between;
align-items: middle;
margin-bottom: 20px;
}
.author-left {
display: flex;
align-items: middle;
}
.author-left img {
width: 48px;
height: 48px;
border-radius: 50%;
object-fit: cover;
margin-right: 12px;
background: #eee;
}
.author-details {
display: flex;
flex-direction: column;
justify-content: center;
}
.author-details .author-name {
font-size: 14px;
font-weight: bold;
color: #333;
line-height: 1.2;
margin-bottom: 2px;
outline: none;
}
.author-details .post-date {
font-size: 12px;
color: #666;
outline: none;
}
.subscription-status {
font-size: 14px;
color: #007A41;
font-weight: bold;
outline: none;
}
/* Body text */
.article .body {
font-size: 16px;
color: #333;
line-height: 1.6;
outline: none;
white-space: pre-wrap;
}
</style>
</head>
<body>
<div id="app">
<div id="controls">
<!-- Cover image input -->
<label for="coverInput">カバー画像を選択<input type="file" id="coverInput" accept="image/*" /></label>
<!-- Author icon input -->
<label for="iconInput">著者アイコンを選択<input type="file" id="iconInput" accept="image/*" /></label>
</div>
<div class="article" id="article">
<!-- Cover image area -->
<div class="cover-image">
<img id="coverImage" src="" alt="カバー画像" />
</div>
<!-- Title -->
<div
class="title"
id="articleTitle"
contenteditable="true"
spellcheck="false"
>タイトルをここに入力</div>
<!-- Like count row -->
<div class="meta-row">
<span class="heart">♡</span>
<span
class="like-count"
id="likeCount"
contenteditable="true"
spellcheck="false"
>いいね数を入力</span>
</div>
<!-- Author and date row -->
<div class="author-row">
<div class="author-left">
<img id="authorIcon" src="" alt="著者アイコン" />
<div class="author-details">
<div
class="author-name"
id="authorName"
contenteditable="true"
spellcheck="false"
>著者名をここに入力</div>
<div
class="post-date"
id="postDate"
contenteditable="true"
spellcheck="false"
>投稿日を入力</div>
</div>
</div>
<div
class="subscription-status"
id="subscriptionStatus"
contenteditable="true"
spellcheck="false"
>購読状態を入力</div>
</div>
<!-- Article body -->
<div
class="body"
id="articleBody"
contenteditable="true"
spellcheck="false"
>ここに本文の冒頭を書いてください。\n複数行のテキストが入力できます。</div>
</div>
</div>
<script>
// Cover image upload handler
document.getElementById("coverInput").addEventListener("change", function (e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function (event) {
document.getElementById("coverImage").src = event.target.result;
};
reader.readAsDataURL(file);
});
// Author icon upload handler
document.getElementById("iconInput").addEventListener("change", function (e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function (event) {
document.getElementById("authorIcon").src = event.target.result;
};
reader.readAsDataURL(file);
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>Spotify風ポッドキャストエピソードモックジェネレータ</title>
<style>
/* Base styling (dark mode) */
body {
background: #121212;
margin: 0;
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
color: #fff;
}
#app {
max-width: 480px;
margin: 0 auto;
}
#controls {
margin-bottom: 20px;
font-size: 14px;
color: #fff;
}
#controls input[type="file"] {
margin-right: 4px;
}
#controls label {
margin-right: 12px;
}
/* Episode container */
.episode {
padding: 16px;
}
.header {
display: flex;
align-items: center;
margin-bottom: 16px;
}
.back-icon {
font-size: 24px;
color: #fff;
cursor: default;
}
/* Episode title */
.episode-title {
font-size: 22px;
font-weight: bold;
line-height: 1.4;
margin-bottom: 12px;
outline: none;
}
/* Program info */
.program-info {
display: flex;
align-items: center;
margin-bottom: 8px;
}
.program-info img {
width: 48px;
height: 48px;
border-radius: 8px;
object-fit: cover;
margin-right: 10px;
background: #333;
}
.program-info .program-name {
font-size: 14px;
font-weight: bold;
color: #bbb;
outline: none;
}
/* Meta info (release date and duration) */
.meta {
font-size: 12px;
color: #888;
margin-bottom: 16px;
outline: none;
}
/* Icon row */
.icon-row {
display: flex;
align-items: center;
margin-bottom: 16px;
}
.icon-row__menu {
flex: 1 0;
display: flex;
gap: 28px;
}
.icon-row .icon {
width: 22px;
height: 22px;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
}
.icon-row .icon svg {
width: 22px;
height: 22px;
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
}
.icon-row .icon svg.filled {
fill: currentColor;
stroke: none;
}
.play-button {
width: 56px;
height: 56px;
border-radius: 50%;
background: #1db954;
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
color: #000;
}
/* Description text */
.description {
font-size: 14px;
line-height: 1.6;
color: #ccc;
white-space: pre-wrap;
outline: none;
}
</style>
</head>
<body>
<div id="app">
<div id="controls">
<input type="file" id="thumbnailInput" accept="image/*" />
<label for="thumbnailInput">サムネイル画像を選択</label>
</div>
<div class="episode">
<div class="header">
<span class="back-icon">←</span>
</div>
<div
class="episode-title"
id="episodeTitle"
contenteditable="true"
spellcheck="false"
>エピソード名を入力</div>
<div class="program-info">
<img id="thumbnailImage" src="" alt="サムネイル" />
<div
class="program-name"
id="programName"
contenteditable="true"
spellcheck="false"
>番組名を入力</div>
</div>
<div
class="meta"
id="episodeMeta"
contenteditable="true"
spellcheck="false"
>再生時間を入力</div>
<div class="icon-row">
<div class="icon-row__menu">
<!-- Link icon -->
<span class="icon">
<svg viewBox="0 0 24 24">
<path d="M10 13a5 5 0 0 0 7.07 0l3.11-3.11a5 5 0 1 0-7.07-7.07L10 5"></path>
<path d="M14 11a5 5 0 0 0-7.07 0L3.82 14.11a5 5 0 1 0 7.07 7.07L14 15"></path>
</svg>
</span>
<!-- Share network icon -->
<span class="icon">
<svg viewBox="0 0 24 24">
<circle cx="18" cy="5" r="3"></circle>
<circle cx="6" cy="12" r="3"></circle>
<circle cx="18" cy="19" r="3"></circle>
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line>
<line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>
</svg>
</span>
<!-- More icon (vertical dots) -->
<span class="icon">
<svg viewBox="0 0 24 24" class="filled">
<circle cx="12" cy="5" r="2"></circle>
<circle cx="12" cy="12" r="2"></circle>
<circle cx="12" cy="19" r="2"></circle>
</svg>
</span>
</div>
<!-- Play button -->
<div class="play-button">▶</div>
</div>
<div
class="description"
id="episodeDescription"
contenteditable="true"
spellcheck="false"
>説明文を入力</div>
</div>
</div>
<script>
// サムネイル画像読み込み
document.getElementById("thumbnailInput").addEventListener("change", function (e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function (event) {
document.getElementById("thumbnailImage").src = event.target.result;
};
reader.readAsDataURL(file);
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>ツイートモックジェネレータ(ライトモード)</title>
<style>
/* Base styling for light mode */
body {
background: #f5f8fa;
margin: 0;
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
#app {
max-width: 600px;
margin: 0 auto;
color: #14171a;
}
#controls {
margin-bottom: 20px;
font-size: 14px;
color: #14171a;
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
}
#controls input[type="file"] {
margin-right: 4px;
}
#controls label {
margin-right: 12px;
}
#randomNameBtn {
padding: 6px 12px;
border: none;
border-radius: 4px;
background: #1da1f2;
color: #fff;
cursor: pointer;
}
#randomNameBtn:hover {
background: #0d8bd2;
}
/* Tweet card styling */
.tweet {
background: #ffffff;
border: 1px solid #e1e8ed;
border-radius: 12px;
padding: 16px;
}
.tweet-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.tweet-user {
display: flex;
align-items: center;
}
.tweet-user img {
width: 48px;
height: 48px;
border-radius: 50%;
object-fit: cover;
margin-right: 12px;
background: #eee;
}
.tweet-user .name {
font-weight: bold;
color: #14171a;
margin-right: 4px;
outline: none;
}
.tweet-user .screen-name {
color: #657786;
outline: none;
}
.tweet-menu {
color: #657786;
font-size: 20px;
line-height: 1;
}
.tweet-text {
margin-top: 8px;
font-size: 16px;
line-height: 1.4;
white-space: pre-wrap;
color: #14171a;
outline: none;
}
/* OGP card styling */
.og-card {
margin-top: 12px;
border: 1px solid #e1e8ed;
border-radius: 12px;
overflow: hidden;
display: none; /* toggled by checkbox */
}
.og-card.show {
display: block;
}
.og-card img {
width: 100%;
height: auto;
display: block;
object-fit: cover;
}
.og-card .og-info {
padding: 8px;
background: #f5f8fa;
}
.og-card .og-title {
font-size: 14px;
color: #14171a;
margin-bottom: 4px;
outline: none;
}
.og-card .og-domain {
font-size: 12px;
color: #657786;
outline: none;
}
/* Tweet meta (timestamp) */
.tweet-meta {
margin-top: 8px;
color: #657786;
font-size: 13px;
}
.tweet-meta span {
outline: none;
}
</style>
</head>
<body>
<div id="app">
<div id="controls">
<input type="file" id="iconInput" accept="image/*" />
<label for="iconInput">投稿者アイコン</label>
<input type="file" id="ogImageInput" accept="image/*" />
<label for="ogImageInput">OGP画像</label>
<input type="checkbox" id="toggleOgp" />
<label for="toggleOgp">外部リンクを埋め込む</label>
<button id="randomNameBtn" type="button">ランダム名生成</button>
</div>
<div class="tweet" id="tweet">
<div class="tweet-header">
<div class="tweet-user">
<img id="tweetIcon" src="" alt="アイコン" />
<div>
<span class="name" id="tweetName" contenteditable="true" spellcheck="false">投稿者名</span>
<span class="screen-name" id="tweetScreenName" contenteditable="true" spellcheck="false">@screen_name</span>
</div>
</div>
<div class="tweet-menu">…</div>
</div>
<div class="tweet-text" id="tweetText" contenteditable="true" spellcheck="false">ここに投稿本文を入力してください。</div>
<div class="og-card" id="ogCard">
<img id="ogImage" src="" alt="OGP画像" />
<div class="og-info">
<div class="og-title" id="ogTitle" contenteditable="true" spellcheck="false">外部リンクのタイトルを入力</div>
<div class="og-domain" id="ogDomain" contenteditable="true" spellcheck="false">example.com から</div>
</div>
</div>
<div class="tweet-meta">
<span id="tweetTime" contenteditable="true" spellcheck="false">投稿日時を入力</span>
</div>
</div>
</div>
<script>
// アイコン画像読み込み
document.getElementById("iconInput").addEventListener("change", function (e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function (event) {
document.getElementById("tweetIcon").src = event.target.result;
};
reader.readAsDataURL(file);
});
// OGP画像読み込み
document.getElementById("ogImageInput").addEventListener("change", function (e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function (event) {
document.getElementById("ogImage").src = event.target.result;
};
reader.readAsDataURL(file);
});
// OGPカード表示切替
document.getElementById("toggleOgp").addEventListener("change", function (e) {
const ogCard = document.getElementById("ogCard");
if (this.checked) {
ogCard.classList.add("show");
} else {
ogCard.classList.remove("show");
}
});
// ランダムなひらがな5文字とアルファベット10文字を生成して設定する関数
function generateRandomNames() {
const hiragana = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん";
let name = "";
for (let i = 0; i < 5; i++) {
name += hiragana.charAt(Math.floor(Math.random() * hiragana.length));
}
const letters = "abcdefghijklmnopqrstuvwxyz";
let screen = "";
for (let i = 0; i < 10; i++) {
screen += letters.charAt(Math.floor(Math.random() * letters.length));
}
document.getElementById("tweetName").textContent = name;
document.getElementById("tweetScreenName").textContent = "@" + screen;
}
// ボタン押下でランダム生成
document.getElementById("randomNameBtn").addEventListener("click", function () {
generateRandomNames();
});
// ページロード時にも一度生成しておく
generateRandomNames();
</script>
</body>
</html>
@fsubal
Copy link
Author

fsubal commented Aug 9, 2025

スクリーンショット 2025-08-09 12 04 47

@fsubal
Copy link
Author

fsubal commented Aug 9, 2025

スクリーンショット 2025-08-09 12 15 18

@fsubal
Copy link
Author

fsubal commented Aug 9, 2025

スクリーンショット 2025-08-09 13 11 30

@fsubal
Copy link
Author

fsubal commented Aug 10, 2025

スクリーンショット 2025-08-10 15 38 49

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment