<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ぷにクリエイト | ぷにっとだめかわ日和 inひきこもり部屋</title>
	<atom:link href="https://damekawabiyori.com/category/puni-create/feed/" rel="self" type="application/rss+xml" />
	<link>https://damekawabiyori.com</link>
	<description>～今日も人生おやすみ中～</description>
	<lastBuildDate>Sat, 13 Dec 2025 12:39:41 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>

<image>
	<url>/wp-content/uploads/2025/12/cropped-favicon2-32x32.webp</url>
	<title>ぷにクリエイト | ぷにっとだめかわ日和 inひきこもり部屋</title>
	<link>https://damekawabiyori.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>AI画像修正の舞台裏！おかしな部分を修正したビフォーアフター3選</title>
		<link>https://damekawabiyori.com/ai-image-edit-before-after/</link>
		
		<dc:creator><![CDATA[さおりん]]></dc:creator>
		<pubDate>Sat, 13 Dec 2025 12:39:41 +0000</pubDate>
				<category><![CDATA[ぷにクリエイト]]></category>
		<category><![CDATA[AIライフ]]></category>
		<category><![CDATA[ぷにアート]]></category>
		<guid isPermaLink="false">https://damekawabiyori.com/?p=1899</guid>

					<description><![CDATA[ぷに目次 &#x2702;&#xfe0f;AI画像修正大作戦！1. &#x1f3a1;位置が変！？浮いてる観覧車元画像（ChatGPT生成）フォトショ修正後ビフォー・アフターまとめ2. &#x1f3b9;ドレミしかない鍵 [&#8230;]]]></description>
										<content:encoded><![CDATA[
  <div id="toc" class="toc tnt-disc toc-center tnt-disc border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">ぷに目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">&#x2702;&#xfe0f;AI画像修正大作戦！</a><ol><li><a href="#toc2" tabindex="0">1. &#x1f3a1;位置が変！？浮いてる観覧車</a><ol><li><a href="#toc3" tabindex="0">元画像（ChatGPT生成）</a></li><li><a href="#toc4" tabindex="0">フォトショ修正後</a></li><li><a href="#toc5" tabindex="0">ビフォー・アフター</a></li><li><a href="#toc6" tabindex="0">まとめ</a></li></ol></li><li><a href="#toc7" tabindex="0">2. &#x1f3b9;ドレミしかない鍵盤！？</a><ol><li><a href="#toc8" tabindex="0">元画像（ChatGPT生成）</a></li><li><a href="#toc9" tabindex="0">ChatGPT再生成後</a></li><li><a href="#toc10" tabindex="0">フォトショ修正後</a></li><li><a href="#toc11" tabindex="0">ビフォー・アフター</a></li><li><a href="#toc12" tabindex="0">まとめ</a></li></ol></li><li><a href="#toc13" tabindex="0">3. &#x1f58a;&#xfe0f;AI生成拒否！？ペンを机に突き刺すイラスト</a><ol><li><a href="#toc14" tabindex="0">元画像（ChatGPT生成）</a></li><li><a href="#toc15" tabindex="0">フォトショ修正後</a></li><li><a href="#toc16" tabindex="0">ビフォー・アフター</a></li><li><a href="#toc17" tabindex="0">まとめ</a></li></ol></li></ol></li></ol>
    </div>
  </div>

<h2><span id="toc1">&#x2702;&#xfe0f;AI画像修正大作戦！</span></h2>
<p class="narration">画像生成をAIに頼むと、思った通りに仕上がらないことは日常茶飯事。<br />
でも、妥協はしないわたし。Photoshop（フォトショップ）で納得がいくまで、手を加えて違和感を消していく。<br />
　<br />
今回は、AIで生成した画像の構図や細部の違和感を修正した<strong>ビフォーアフター3選</strong>を紹介します。<br />
　<br />
どんな風に変わったのか、ちょっとした修正の楽しさを一緒に見ていこう。</p>
<p class="saorin normal"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">まずは1枚目。</span></p>
<h3><span id="toc2">1. &#x1f3a1;位置が変！？浮いてる観覧車</span></h3>
<h4><span id="toc3">元画像（ChatGPT生成）</span></h4>
<p><img decoding="async" src="/wp-content/uploads/2025/11/woman-alone-mysterious-town-ferris-wheel-before.webp" alt="観覧車のある誰もいない不思議な街にひとりたたずむ女性のイラスト（before）" class="post-img size600" /></p>
<table>
<tbody>
<tr>
<th>お気に入りポイント</th>
<th>気になるところ</th>
</tr>
<tr>
<td>
<ul>
<li>色合いが癒される</li>
<li>かわいい</li>
</ul>
</td>
<td>
<ul>
<li>観覧車がちょっと小さい</li>
<li>観覧車の位置が上すぎる</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p class="narration">よく見ると観覧車の位置がちょっとおかしい…。<br />
　<br />
あきらかに浮いていて、地上何メートルの位置から乗るんだろうって感じ。<br />
　<br />
向こうに山でもあるのかな？でもこんな街の近くに？うーん、やっぱり変。
</p>
<h4><span id="toc4">フォトショ修正後</span></h4>
<p><img decoding="async" src="/wp-content/uploads/2025/11/woman-alone-mysterious-town-ferris-wheel.webp" alt="観覧車のある誰もいない不思議な街にひとりたたずむ女性のイラスト" class="post-img size600" /></p>
<table>
<tbody>
<tr>
<th>修正・こだわりポイント</th>
<th>難易度</th>
</tr>
<tr>
<td>
<ul>
<li>観覧車を大きく</li>
<li>観覧車の位置を少し下に</li>
</ul>
</td>
<td style="text-align: center;">★★★☆☆</td>
</tr>
</tbody>
</table>
<p class="saorin sweat"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">ふう…。やっと人間が乗れる位置になったわね。</span></p>
<p class="chappy normal"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">よかったっぴ！てっきり空飛べる人限定かと思ったっぴ！</span></p>
<h4><span id="toc5">ビフォー・アフター</span></h4>
<div class="blog-img-two arrow-bg">
<div><img decoding="async" src="/wp-content/uploads/2025/11/woman-alone-mysterious-town-ferris-wheel-before.webp" alt="観覧車のある誰もいない不思議な街にひとりたたずむ女性のイラスト（before）" class="post-img size600" /></div>
<div><img decoding="async" src="/wp-content/uploads/2025/11/woman-alone-mysterious-town-ferris-wheel.webp" alt="観覧車のある誰もいない不思議な街にひとりたたずむ女性のイラスト" class="post-img size600" /></div>
</div>
<div class="caption">
<div>Before</div>
<div>After</div>
</div>
<h4><span id="toc6">まとめ</span></h4>
<p>ChatGPTに「観覧車がある誰もいない不思議な街にひとりたたずむ女性」のイラストを生成してもらいました。<br />
観覧車は描かれているものの、位置のバランスは少し不自然。雰囲気を壊したくなかったので、再生成せずに手直ししました。<br />
具体的には、<strong>観覧車をコピーして背景を消し、拡大してからPhotoshopの描画モード「比較（暗）」で貼り付けています</strong>。<br />
　<br />
<strong>▼このイラストが登場する記事はこちら&#x1f447;</strong></p>

<a href="https://damekawabiyori.com/moon-tea-salon-02/" title="【月夜のティーサロン#2】刺激のない毎日に。心を癒す、優しく温かいひととき" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="99" src="/wp-content/uploads/2025/08/enchanted-empty-town-160x99.webp" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://damekawabiyori.com/wp-content/uploads/2025/08/enchanted-empty-town-160x99.webp 160w, https://damekawabiyori.com/wp-content/uploads/2025/08/enchanted-empty-town-120x74.webp 120w, https://damekawabiyori.com/wp-content/uploads/2025/08/enchanted-empty-town-320x198.webp 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">【月夜のティーサロン#2】刺激のない毎日に。心を癒す、優しく温かいひととき</div><div class="blogcard-snippet internal-blogcard-snippet">刺激のない毎日に、ぷに王国の「月夜のティーサロン」で心をほぐす癒やしの時間を。ミルク・ムーン先生とのやさしい会話と魔法の紅茶で、疲れた心を温めます。ひとり時間を大切にしたいあなたへ贈る、やわらかな癒しのひととき。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://damekawabiyori.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">ぷにっとだめかわ日和 inひきこもり部屋</div></div></div></div></a>
<p class="saorin normal"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">人間やめることにならなくてよかった。<br />
お次は2枚目。</span></p>
<h3><span id="toc7">2. &#x1f3b9;ドレミしかない鍵盤！？</span></h3>
<h4><span id="toc8">元画像（ChatGPT生成）</span></h4>
<p><img decoding="async" src="/wp-content/uploads/2025/11/happy-woman-playing-white-piano-gentle-illustration-before.webp" alt="白いピアノを楽しそうに弾く女性のほんわかしたイラスト（before）" class="post-img size600" /></p>
<table>
<tbody>
<tr>
<th>お気に入りポイント</th>
<th>気になるところ</th>
</tr>
<tr>
<td>
<ul>
<li>ピアノを楽しそうに弾いてる雰囲気が出てる</li>
<li>かわいい</li>
</ul>
</td>
<td>
<ul>
<li>黒鍵の数が足りない</li>
<li>楽譜台の位置が変</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p class="narration">この鍵盤、黒鍵が2・2・2と続いていて、ソ・ラ・シがない&#x1f4a6;<br />
これじゃあ弾けるのは「メリーさんのひつじ」くらいかも…。<br />
　<br />
修正は難しそう…ということで、再生成をお願いしてみたけど、さらにとんでもない鍵盤が完成！<br />
　<br />
再生成→修正の2段階構成となっています。</p>
<h4><span id="toc9">ChatGPT再生成後</span></h4>
<p><img decoding="async" src="/wp-content/uploads/2025/11/happy-woman-playing-white-piano-gentle-illustration-regenerated.webp" alt="白いピアノを楽しそうに弾く女性のイラスト（再生成失敗Ver）" class="post-img size600" /></p>
<table>
<tbody>
<tr>
<th>お気に入りポイント（？）</th>
<th>気になるところ</th>
</tr>
<tr>
<td>
<ul>
<li>かわいいけどホラー</li>
</ul>
</td>
<td>
<ul>
<li>ピアノが交差した！</li>
<li>再生成によるクオリティ低下</li>
<li>色々だめ</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p class="chappy surprised"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">ぎゃ～～～っぴ！！どうやって弾いてるっぴ～&#x1f4a6;</span></p>
<h4><span id="toc10">フォトショ修正後</span></h4>
<p><img decoding="async" src="/wp-content/uploads/2025/10/happy-woman-playing-white-piano-gentle-illustration.webp" alt="白いピアノを楽しそうに弾く女性のほんわかしたイラスト" class="post-img size600" /></p>
<table>
<tbody>
<tr>
<th>修正・こだわりポイント</th>
<th>難易度</th>
</tr>
<tr>
<td>
<ul>
<li>おかしな位置にある楽譜台を撤去</li>
<li>黒鍵の数の修正</li>
<li>音符の追加</li>
<li>表情をもっと楽しそうに</li>
</ul>
</td>
<td style="text-align: center;">★★★★★</td>
</tr>
</tbody>
</table>
<p class="saorin sweat"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">ふう、やっと7音出せるようになったわ。</span></p>
<p class="chappy normal"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">さすがっぴ！鍵盤が太いのはご愛敬っぴね？</span></p>
<p class="saorin sweat"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">まあ…そこは目をつぶらせて。</span></p>
<h4><span id="toc11">ビフォー・アフター</span></h4>
<div class="blog-img-two arrow-bg">
<div><img decoding="async" src="/wp-content/uploads/2025/11/happy-woman-playing-white-piano-gentle-illustration-before.webp" alt="白いピアノを楽しそうに弾く女性のほんわかしたイラスト（before）" class="post-img size600" /></div>
<div><img decoding="async" src="/wp-content/uploads/2025/10/happy-woman-playing-white-piano-gentle-illustration.webp" alt="白いピアノを楽しそうに弾く女性のほんわかしたイラスト" class="post-img size600" /></div>
</div>
<div class="caption">
<div>Before</div>
<div>After</div>
</div>
<h4><span id="toc12">まとめ</span></h4>
<p>AI画像生成で意外と難しいのが黒鍵の正確な数。<br />
ピアノだけの画像ならうまくいく場合もあるけど、人物も入ると難易度アップ。<br />
　<br />
となりの鍵盤をコピペして<strong>7音になるよう仕上げました</strong>。<br />
これはかなり<strong>難易度が高い修正</strong>でした。<br />
　<br />
「再生成の方が早くない？」って思うけど、気に入った画像だと再生成を繰り返すより修正したくなってしまうのがクリエイターの本能だったりします。</p>
<p>　<br />
<strong>▼このイラストが登場する記事はこちら&#x1f447;</strong></p>

<a href="https://damekawabiyori.com//piano-after-28-years-elise-chaos/" title="ひきこもりが28年ぶりにピアノを弾いたら…「エリーゼのために」が大変なことに" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img decoding="async" width="160" height="99" src="/wp-content/uploads/2025/10/happy-woman-playing-white-piano-gentle-illustration-160x99.webp" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://damekawabiyori.com/wp-content/uploads/2025/10/happy-woman-playing-white-piano-gentle-illustration-160x99.webp 160w, https://damekawabiyori.com/wp-content/uploads/2025/10/happy-woman-playing-white-piano-gentle-illustration-120x74.webp 120w, https://damekawabiyori.com/wp-content/uploads/2025/10/happy-woman-playing-white-piano-gentle-illustration-320x198.webp 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">ひきこもりが28年ぶりにピアノを弾いたら…「エリーゼのために」が大変なことに</div><div class="blogcard-snippet internal-blogcard-snippet">28年ぶりにピアノ再挑戦したさおりん。ベートーヴェン「エリーゼのために」のあの連続する部分、6回弾くはずがいつの間にか12回に増えちゃった！おまけに飾り音（トリル）も炸裂。練習は二の次、ほぼ暴走。笑い多めの復活劇。ひきこもりのゆる～い日常をお届けします。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://damekawabiyori.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">ぷにっとだめかわ日和 inひきこもり部屋</div></div></div></div></a>
<p class="saorin normal"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">はー、これは肩が凝ったわ～&#x1f4a6;でも修正楽しい（笑）<br />
ラスト3枚目いくよ。</span></p>
<h3><span id="toc13">3. &#x1f58a;&#xfe0f;AI生成拒否！？ペンを机に突き刺すイラスト</span></h3>
<h4><span id="toc14">元画像（ChatGPT生成）</span></h4>
<p><img decoding="async" src="/wp-content/uploads/2025/11/woman-stabs-pen-at-witness-stand-before.webp" alt="ペンを机に刺す女性のシュールなイラスト（before）" class="post-img size600" /></p>
<table>
<tbody>
<tr>
<th>お気に入りポイント</th>
<th>気になるところ</th>
</tr>
<tr>
<td>
<ul>
<li>かわいい</li>
<li>ペンの持ち方がナイス</li>
</ul>
</td>
<td>
<ul>
<li>ペンが空中に浮いてて刺してる感じがない</li>
<li>思ってた表情と違う</li>
<li>ポニーテールがでかい</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p class="narration">これは法廷の証言台で、さおりんが笑いながらペンを突き刺すというシーンのイラスト（笑）。<br />
　<br />
ChatGPTに頼んだら、「突き刺す」などの暴力的表現はNGだと断られました…。<br />
　<br />
相談したところ、寸止めならOKとのことで、こうなりました。
</p>
<h4><span id="toc15">フォトショ修正後</span></h4>
<p><img decoding="async" src="/wp-content/uploads/2025/11/woman-stabs-pen-at-witness-stand.webp" alt="笑顔なのにペンを机に刺す女性のシュールなイラスト" class="post-img size600" /></p>
<table>
<tbody>
<tr>
<th>修正・こだわりポイント</th>
<th>難易度</th>
</tr>
<tr>
<td>
<ul>
<li>ポニーテールを少し小さく</li>
<li>笑顔で目を開いた表情に修正</li>
<li>ペンを下にずらし机にめり込んでるように</li>
</ul>
</td>
<td style="text-align: center;">★★★☆☆</td>
</tr>
</tbody>
</table>
<p class="chappy surprised"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">笑顔でペンを刺してる方が圧倒的に怖いっぴ！（ガクブル）</span></p>
<p class="saorin normal"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">ふふふ…そうでしょ～。</span></p>
<h4><span id="toc16">ビフォー・アフター</span></h4>
<div class="blog-img-two arrow-bg">
<div><img decoding="async" src="/wp-content/uploads/2025/11/woman-stabs-pen-at-witness-stand-before.webp" alt="ペンを机に刺す女性のシュールなイラスト（before）" class="post-img size600" /></div>
<div><img decoding="async" src="/wp-content/uploads/2025/11/woman-stabs-pen-at-witness-stand.webp" alt="笑顔なのにペンを机に刺す女性のシュールなイラスト" class="post-img size600" /></div>
</div>
<div class="caption">
<div>Before</div>
<div>After</div>
</div>
<h4><span id="toc17">まとめ</span></h4>
<p>ChatGPTでは「〇〇を突き刺す」など、暴力的表現とみなされると画像生成を断られてしまいます。<br />
その場合は、<strong>「寸止め」「突き立てる」などの表現</strong>にすると上手くいくかも。<br />
でも本当に突き刺したいなら、<strong>Photoshopなどで修正</strong>しよう（笑）。<br />
　<br />
顔のパーツは別のさおりんの画像から持ってきて貼り付けました。</p>
<p>　<br />
<strong>▼このイラストが登場する記事はこちら&#x1f447;</strong></p>

<a href="https://damekawabiyori.com/mother-education-court/" title="母の教育に異議あり！大人になってガチで“心の法廷”ひらいてみた" class="blogcard-wrap internal-blogcard-wrap a-wrap cf"><div class="blogcard internal-blogcard ib-left cf"><div class="blogcard-label internal-blogcard-label"><span class="fa"></span></div><figure class="blogcard-thumbnail internal-blogcard-thumbnail"><img loading="lazy" decoding="async" width="160" height="99" src="/wp-content/uploads/2025/11/mother-daughter-court-battle-160x99.webp" class="blogcard-thumb-image internal-blogcard-thumb-image wp-post-image" alt="" srcset="https://damekawabiyori.com/wp-content/uploads/2025/11/mother-daughter-court-battle-160x99.webp 160w, https://damekawabiyori.com/wp-content/uploads/2025/11/mother-daughter-court-battle-120x74.webp 120w, https://damekawabiyori.com/wp-content/uploads/2025/11/mother-daughter-court-battle-320x198.webp 320w" sizes="(max-width: 160px) 100vw, 160px" /></figure><div class="blogcard-content internal-blogcard-content"><div class="blogcard-title internal-blogcard-title">母の教育に異議あり！大人になってガチで“心の法廷”ひらいてみた</div><div class="blogcard-snippet internal-blogcard-snippet">母の教育に積もったモヤモヤ…大人になった私はついに“心の法廷”を開廷！笑いと本音が入り乱れる、母との過去を裁くカオス裁判ストーリー。生きづらさに悩む人に届けたい1本です。毒親気味の母との関係を笑い飛ばしながら整理したい人におすすめ。</div></div><div class="blogcard-footer internal-blogcard-footer cf"><div class="blogcard-site internal-blogcard-site"><div class="blogcard-favicon internal-blogcard-favicon"><img decoding="async" src="https://www.google.com/s2/favicons?domain=https://damekawabiyori.com" alt="" class="blogcard-favicon-image internal-blogcard-favicon-image" width="16" height="16" /></div><div class="blogcard-domain internal-blogcard-domain">ぷにっとだめかわ日和 inひきこもり部屋</div></div></div></div></a>
<p class="saorin normal"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">シュールで笑えるイラストになったね。<br />
　<br />
今回のAI画像修正集はここまで。また修正画像が増えてきたら随時開催するのでお楽しみに！</span></p>
<p class="chappy smile"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">わーい！次も楽しみだっぴ～♪</span></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>【完全攻略】ぷに語翻訳機を作ってみた！ChatGPTと一緒に100％ぷに化への冒険</title>
		<link>https://damekawabiyori.com/puni-translator/</link>
		
		<dc:creator><![CDATA[さおりん]]></dc:creator>
		<pubDate>Tue, 26 Aug 2025 14:44:08 +0000</pubDate>
				<category><![CDATA[ぷにクリエイト]]></category>
		<category><![CDATA[ぷに研究所]]></category>
		<category><![CDATA[AIライフ]]></category>
		<guid isPermaLink="false">https://damekawabiyori.com/?p=949</guid>

					<description><![CDATA[ぷに目次 ぷに語翻訳機、ついに完成！ChatGPTと挑んだ開発物語① 導入：ぷに語会話にハマる② 開発編：JavaScriptと格闘する素人&#x1fab2; 初期バージョン（無変換バグ）本格ぷに語翻訳スクリプト Ver [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="chat">

  <div id="toc" class="toc tnt-disc toc-center tnt-disc border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">ぷに目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">ぷに語翻訳機、ついに完成！ChatGPTと挑んだ開発物語</a><ol><li><a href="#toc2" tabindex="0">① 導入：ぷに語会話にハマる</a></li><li><a href="#toc3" tabindex="0">② 開発編：JavaScriptと格闘する素人</a><ol><li><a href="#toc4" tabindex="0">&#x1fab2; 初期バージョン（無変換バグ）</a></li><li><a href="#toc5" tabindex="0">本格ぷに語翻訳スクリプト Ver.2</a></li></ol></li><li><a href="#toc6" tabindex="0">③ GPTお兄さん召喚事件</a><ol><li><a href="#toc7" tabindex="0">&#x26a1; GPTお兄さん版・修正版スクリプト</a></li></ol></li><li><a href="#toc8" tabindex="0">④ 完成！ぷに語翻訳機</a><ol><li><a href="#toc9" tabindex="0">&#x1f389; 最終版ぷに語翻訳機コード</a></li></ol></li><li><a href="#toc10" tabindex="0">⑤ 教訓とまとめ</a></li></ol></li><li><a href="#toc11" tabindex="0">完成版：ぷに語翻訳機＆コード公開！</a></li></ol>
    </div>
  </div>

<h2><span id="toc1">ぷに語翻訳機、ついに完成！ChatGPTと挑んだ開発物語</span></h2>
<p class="narration">ぷに王国公式“ぷに語翻訳機”を作ることにしたさおりんとチャッピー。この記事では、開発のドタバタ裏話を会話形式でお届けします。</p>
<h3><span id="toc2">① 導入：ぷに語会話にハマる</span></h3>
<p class="saorin normal"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">
チャッピー、最近わたし達の会話さぁ…ほぼぷに語になってない？ぷにぷに～。</span></p>
<p class="chappy grin"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">
ぷにぷにっ！ぷににぷにぷにぷに～！（そうだっぴ！昨日なんて99％ぷにだったっぴ！）</span></p>
<p class="saorin confused"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">
だよね！？最近「文章が解読不能です」って読者さんに言われちゃったぷに…。翻訳機ほしいぷに～。</span></p>
<p class="chappy smile"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">
それならChatGPTでぷに語翻訳機を作るっぴ！これで読者さんも安心ぷに！</span></p>
<p class="saorin smile"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">
いいね～！じゃあぷに語と日本語を切り替えられる最強のやつ作ろうぷに！</span></p>
<h3><span id="toc3">② 開発編：JavaScriptと格闘する素人</span></h3>
<p class="narration">JSはほぼ素人のさおりん、勢いでチャッピーにお願いしてぷに語翻訳機の開発スタート。</p>
<p class="saorin sweat"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">チャッピー、JSほぼさわったことないんだけど、できるかな…？</span></p>
<p class="chappy grin"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">任せるっぴ！ChatGPTの力を見せるときだっぴ！</span></p>
<p class="narration">そして初期バージョンが完成。しかしまさかの「無変換バグ」発生…！</p>
<h4 class="narration"><span id="toc4">&#x1fab2; 初期バージョン（無変換バグ）</span></h4>
<p><!-- ▼失敗コードボックス --></p>
<details class="codebox details-code">
<summary class="codebox-header">
    <span>失敗コード①（HTML＋JS）</span><br />
    <span class="toggle-label">▼ 開く</span><br />
    <span class="copy-btn" onclick="copyPuniCode(event,this)">コピー</span><br />
  </summary>
<p>  <textarea class="codebox-ta" readonly spellcheck="false" wrap="off"><!--------------------------------------
HTML
------------------------------------


<div style="margin-bottom:1em;">
  <textarea id="textInput" rows="5" cols="50" placeholder="ここに文章を入力してぷに〜">&lt;/textarea&gt;
</div>




<div style="margin-bottom:1em;">
  <button onclick="toPuni()">ぷに語に変換する</button>
  <button onclick="toJapanese()">日本語に戻す</button>
  <button onclick="clearText()">クリア</button>
</div>




<div>

<p>変換結果：</p>


  

<div id="result" style="white-space: pre-wrap; background:#f8f8ff; padding:10px; border:1px solid #ddd; border-radius:8px;">
  </div>


</div>


------------------------------------
JS
------------------------------------
<script>
  // 入力したテキストをぷに語に変換
  function toPuni() {
    const text = document.getElementById("textInput").value;
    if (!text.trim()) {
      alert("テキストを入力してぷに〜");
      return;
    }
    // 単語の2〜3割をランダムに「ぷに」に置換
    const words = text.split(/(\s+)/);
    const converted = words.map(word => {
      if (Math.random() < 0.3 && word.trim() !== "") {
        return "ぷに";
      } else {
        return word;
      }
    }).join("");
    document.getElementById("result").textContent = converted;
  }
--></script></textarea><br />
</details>
<p class="saorin surprised"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">えっ！？ 全然変わってないぷに！</span></p>
<p class="chappy sweat"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">おかしいっぴ…splitの分割がうまく動いてないのかも…</span></p>
<p class="narration">さらに改良版「本格ぷに語翻訳スクリプト Ver.2」を作成。しかし今度は100％ぷに率でも半分以上日本語が残るという謎現象に。</p>
<h4 class="narration"><span id="toc5">本格ぷに語翻訳スクリプト Ver.2</span></h4>
<p><!-- ▼失敗コードボックス --></p>
<details class="codebox details-code">
<summary class="codebox-header">
    <span>失敗コード②（HTML＋JS）</span><br />
    <span class="toggle-label">▼ 開く</span><br />
    <span class="copy-btn" onclick="copyPuniCode(event,this)">コピー</span><br />
  </summary>
<p>  <textarea class="codebox-ta" readonly spellcheck="false" wrap="off"><!--------------------------------------
HTML
------------------------------------


<div style="margin-bottom:1em;">
  <textarea id="textInput" rows="5" cols="60" placeholder="ここに日本語を入力してぷに〜">&lt;/textarea&gt;
</div>




<div style="margin-bottom:1em;">
  <label for="puniRate">ぷに率: </label>
  <input type="range" id="puniRate" min="0" max="100" value="50" oninput="updateLabel(this.value)">
  <span id="puniLabel">50%</span>
</div>




<div style="margin-bottom:1em;">
  <button onclick="toPuni()">ぷに語に変換する</button>
  <button onclick="toJapanese()">日本語に戻す</button>
  <button onclick="clearText()">クリア</button>
</div>




<div>

<p>変換結果：</p>


  

<div id="result" style="white-space: pre-wrap; background:#f8f8ff; padding:10px; border:1px solid #ddd; border-radius:8px;"></div>


</div>


------------------------------------
JS
------------------------------------
<script>
  let originalText = "";

  // スライダー表示更新
  function updateLabel(val) {
    document.getElementById("puniLabel").textContent = val + "%";
  }

  // 日本語→ぷに語変換
  function toPuni() {
    const text = document.getElementById("textInput").value;
    if (!text.trim()) {
      alert("テキストを入力してぷに〜");
      return;
    }

    originalText = text;
    const puniRate = document.getElementById("puniRate").value;

    // 語尾とランダム単語をぷに化
    const converted = text
      .split(/([。！？\n])/)
      .map(sentence => {
        if (!sentence.trim()) return sentence;
        // ランダムにぷに置換する確率
        if (Math.random() * 100 < puniRate) {
          return sentence.replace(/(。|！|？|です|ます|だよ|だ|ね|よ)/g, "ぷに") + "ぷに";
        } else {
          return sentence;
        }
      })
      .join("");

    document.getElementById("result").textContent = converted;
  }

  // オリジナルに戻す
  function toJapanese() {
    document.getElementById("result").textContent = originalText;
  }

  // 入力と結果クリア
  function clearText() {
    document.getElementById("textInput").value = "";
    document.getElementById("result").textContent = "";
    originalText = "";
  }
--></script></textarea><br />
</details>
<p class="saorin surprised"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">なんでぷに〜！？100％にしたのに日本語残ってるぷに！</span></p>
<p class="chappy sweat"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">乱数ロジックが悪さしてる可能性大っぴ…！</span></p>
<p class="narration">ここから泥沼のデバッグタイムに突入するのであった…。</p>
<h3><span id="toc6">③ GPTお兄さん召喚事件</span></h3>
<p class="narration">ついにさおりんとチャッピーでは解決できない状態に。ここで伝説の「GPTお兄さん（Thinkingくん）」を召喚することに。</p>
<p class="saorin angry"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">チャッピー！Ver.9までつくったけどだめぷに！Thinkingくん呼んでくる！！</span></p>
<p class="chappy surprised"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">えっ！？ついにお兄ちゃん召喚っぴ！？</span></p>
<p class="narration">ThinkingくんはGPT-5系の高性能モデルで、ほかのモデルよりちょっとお兄さん感がある。<br />
　<br />
そしてお兄さん、まさかの一撃で<strong>神修正</strong>を決めてきた…！</p>
<h4 class="narration"><span id="toc7">&#x26a1; GPTお兄さん版・修正版スクリプト</span></h4>
<p><!-- ▼失敗コードボックス --></p>
<details class="codebox details-code">
<summary class="codebox-header">
    <span>成功コード①（HTML＋JS）</span><br />
    <span class="toggle-label">▼ 開く</span><br />
    <span class="copy-btn" onclick="copyPuniCode(event,this)">コピー</span><br />
  </summary>
<p>  <textarea class="codebox-ta" readonly spellcheck="false" wrap="off"><!--------------------------------------
HTML
------------------------------------


<div class="puni-box" style="margin:1em 0;">
  <textarea class="puni-input" rows="6" style="width:100%;max-width:720px;" placeholder="ここに日本語を入れてぷに〜">&lt;/textarea&gt;
  

<div style="margin:.5em 0;display:flex;gap:.5em;align-items:center;flex-wrap:wrap;">
    <label>ぷに率:
      <input class="puni-rate" type="range" min="0" max="100" value="50">
    </label>
    <span class="puni-rate-label">50%</span>
    <button type="button" class="puni-to">ぷに語に変換</button>
    <button type="button" class="puni-back">日本語に戻す</button>
    <button type="button" class="puni-clear">クリア</button>
  </div>


  

<div>変換結果：</div>


  

<div class="puni-result"style="white-space:pre-wrap;background:#f8f8ff;padding:10px;border:1px solid #ddd;border-radius:8px;min-height:4em;max-width: 700px;"></div>


  </div>


------------------------------------
JS
------------------------------------
<script>
(function(){
  // ES5で書く（古ブラウザでも安全）＆インラインハンドラ非依存
  function setup(root){
    var ta   = root.querySelector('.puni-input');
    var rate = root.querySelector('.puni-rate');
    var lab  = root.querySelector('.puni-rate-label');
    var out  = root.querySelector('.puni-result');
    var bTo  = root.querySelector('.puni-to');
    var bBk  = root.querySelector('.puni-back');
    var bCl  = root.querySelector('.puni-clear');
    var original = "";

    // ラベル更新
    rate.addEventListener('input', function(){ lab.textContent = rate.value + '%'; });

    // 変換
    bTo.addEventListener('click', function(){
      var text = ta.value || "";
      if (!text.replace(/\s/g,"").length) { out.textContent = ""; return; }
      original = text;

      // 数値を厳重に読む（文字列"100"問題回避）
      var r = parseFloat(rate.value);
      if (!isFinite(r)) r = 0;

      // ★100%は"必ず"全部ぷに：非空白をすべて「ぷに」に
      if (r >= 99.9 || String(rate.value).trim() === "100") {
        // 改行やスペースは維持し、文字だけ「ぷに」に
        out.textContent = text.replace(/\S/g, "ぷに");
        return;
      }

      // 1〜99%：文字単位でランダムにぷに化（空白は保持）
      var res = "";
      for (var i=0; i<text.length; i++){
        var ch = text.charAt(i);
        if (/\s/.test(ch)) { res += ch; continue; }
        res += (Math.random()*100 < r) ? "ぷに" : ch;
      }
      // 語尾っぽい箇所を軽くぷに化して“らしさ”追加
      res = res.replace(/(。|！|？|です|ます|だよ|だ|ね|よ)(?=\s|$)/g, "ぷに");
      out.textContent = res;
    });

    // 戻す
    bBk.addEventListener('click', function(){
      out.textContent = original;
      ta.value = original;
    });

    // クリア
    bCl.addEventListener('click', function(){
      ta.value = ""; out.textContent = ""; original = "";
      rate.value = "50"; lab.textContent = "50%";
    });
  }

  // ページ内に複数置いてもOK
  function init(){
    var nodes = document.querySelectorAll('.puni-box');
    for (var i=0; i<nodes.length; i++) setup(nodes[i]);
    // 動作確認用（コンソールで見える）：console.log('puni online');
  }

  if (document.readyState === 'loading'){
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();
--></script></textarea><br />
</details>
<p class="saorin smile"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">おおおっ！？できたぷに！！お兄さん神ぷにー！！</span></p>
<p class="other"> <span class="icon guest-icon" style="background-image: url(https://damekawabiyori.com/wp-content/themes/cocoon-child-master/icons/guest/chappy-brother.webp);"></span><span class="name">チャッピー兄</span><span class="bubble">ふふん、こんなの朝飯前だよ。</span></p>
<p class="chappy angry"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">ぐぬぬ…お兄ちゃんに負けたくないっぴ…&#x1f525;</span></p>
<p class="narration">裏では、チャッピーがめっちゃ対抗心を燃やしていた。</p>
<p class="chappy angry"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">よぉし…ぼくだってもっと便利にするっぴ！</span></p>
<p class="narration">こうしてThinkingくんの神修正をベースに、チャッピーはさらに改良を重ねていくことになる。</p>
<h3><span id="toc8">④ 完成！ぷに語翻訳機</span></h3>
<p class="narration">Thinkingくんの神修正をベースに、チャッピーがさらに微調整を重ねた結果…ついに「ぷに語翻訳機」が完成！</p>
<p class="saorin smile"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">チャッピー！ついに完成ぷに！？</span></p>
<p class="chappy grin"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">もちろんっぴ！「ぷに」「ぷにに」「ぷにっ」「ぷに～ん」ランダム変換に加えて、句読点を自然に残す機能も搭載したっぴ！さらに元の文章と同じ文字数になるように調整したっぴ&#x2728;</span></p>
<h4 class="narration"><span id="toc9">&#x1f389; 最終版ぷに語翻訳機コード</span></h4>
<p><!-- ▼失敗コードボックス --></p>
<details class="codebox details-code">
<summary class="codebox-header">
    <span>成功コード②（HTML＋JS）</span><br />
    <span class="toggle-label">▼ 開く</span><br />
    <span class="copy-btn" onclick="copyPuniCode(event,this)">コピー</span><br />
  </summary>
<p>  <textarea class="codebox-ta" readonly spellcheck="false" wrap="off"><!--------------------------------------
HTML
------------------------------------


<div class="puni-box" style="margin:1em 0;">
  <textarea class="puni-input" rows="6" style="width:100%;max-width:720px;" placeholder="ここに日本語を入れてぷに〜">&lt;/textarea&gt;
  

<div style="margin:.5em 0;display:flex;gap:.5em;align-items:center;flex-wrap:wrap;">
    <label>ぷに率:
      <input class="puni-rate" type="range" min="0" max="100" value="50">
    </label>
    <span class="puni-rate-label">50%</span>
    <button type="button" class="puni-to">ぷに語に変換</button>
    <button type="button" class="puni-back">日本語に戻す</button>
    <button type="button" class="puni-clear">クリア</button>
  </div>


  

<div>変換結果：</div>


  

<div class="puni-result"style="white-space:pre-wrap;background:#f8f8ff;padding:10px;border:1px solid #ddd;border-radius:8px;min-height:4em;max-width: 700px;"></div>


  </div>


------------------------------------
JS
------------------------------------
<script>
(function(){
  function setup(root){
    if (root.getAttribute('data-puni-bound') === '1') return;
    root.setAttribute('data-puni-bound', '1');

    var ta   = root.querySelector('.puni-input');
    var rate = root.querySelector('.puni-rate');
    var lab  = root.querySelector('.puni-rate-label');
    var out  = root.querySelector('.puni-result');
    var bTo  = root.querySelector('.puni-to');
    var bBk  = root.querySelector('.puni-back');
    var bCl  = root.querySelector('.puni-clear');
    var original = "";

    // ぷに候補（重み付き）
    var puniChoices = [
      {t:"ぷに",   w:73},  // 2
      {t:"ぷにに", w:11},  // 3
      {t:"ぷにっ", w:9},   // 3
      {t:"ぷに～", w:4},   // 3
      {t:"ぷに～ん", w:2}, // 4
      {t:"ぷにぷに", w:1}  // 4
    ];
    // 残り長に合わせるための1文字フィラー（必要時のみ使用）
    var fillers = ["に","っ","～"];

    function weightedPick(list){
      var sum = 0; for (var i=0;i<list.length;i++) sum += list[i].w || 1;
      var r = Math.random()*sum, acc=0;
      for (var i=0;i<list.length;i++){ acc += list[i].w || 1; if (r < acc) return list[i]; }
      return list[0];
    }
    function pickToken(maxLen){
      // 長さが収まる候補だけに絞る
      var pool = [];
      for (var i=0;i<puniChoices.length;i++){
        if (puniChoices[i].t.length <= maxLen) pool.push(puniChoices[i]);
      }
      if (pool.length) return weightedPick(pool).t;
      // どうしても無ければ1文字フィラー
      return fillers[(Math.random()*fillers.length)|0];
    }

    function transformRun(run, rate){
      // run長を超えないようにトークンを積む。原文も一部残す（rate%）
      var i=0, outStr="";
      while(i<run.length){
        var remain = run.length - i;
        if (Math.random()*100 < rate){
          var t = pickToken(remain);
          if (t.length > remain) t = t.slice(0, remain);
          outStr += t;
          i += t.length;
        } else {
          outStr += run.charAt(i);
          i += 1;
        }
      }
      return outStr;
    }
    function transformRunFull(run){
      // 100%：原文を一切残さず、長さぴったりで埋める
      var i=0, outStr="";
      while(i<run.length){
        var remain = run.length - i;
        var t = pickToken(remain);
        if (t.length > remain) t = t.slice(0, remain);
        outStr += t;
        i += t.length;
      }
      return outStr;
    }

    // 初期ラベル同期
    function updateLabel(){ lab.textContent = rate.value + '%'; }
    updateLabel();
    rate.addEventListener('input', updateLabel);

    // 変換（長さ厳守版）
    bTo.addEventListener('click', function(e){
      if (e && e.stopImmediatePropagation) e.stopImmediatePropagation();

      var text = ta.value || "";
      if (!text.replace(/\s/g,"").length) { out.textContent = ""; return; }
      original = text;

      var r = parseFloat(rate.value);
      if (!isFinite(r)) r = 0;

      var keepMarks = /[。、！？♡♪☆★（）「」]/; // 句読点などは必ず保持
      var i=0, res=[];

      while(i<text.length){
        var ch = text.charAt(i);
        // 空白 or 句読点はそのまま
        if (/\s/.test(ch) || keepMarks.test(ch)){
          res.push(ch); i++; continue;
        }
        // 置換対象の連続runを抽出
        var j=i;
        while(j<text.length){
          var c2 = text.charAt(j);
          if (/\s/.test(c2) || keepMarks.test(c2)) break;
          j++;
        }
        var run = text.slice(i,j);
        // 100%は完全置換、それ以外は割合置換（いずれも run 長と一致）
        var chunk = (r >= 99.9 || String(rate.value).trim()==="100")
          ? transformRunFull(run)
          : transformRun(run, r);

        res.push(chunk);
        i = j;
      }

      // ★長さは text.length と常に一致
      out.textContent = res.join("");

    }, true);

    // 戻す
    bBk.addEventListener('click', function(e){
      if (e && e.stopImmediatePropagation) e.stopImmediatePropagation();
      out.textContent = original;
      ta.value = original;
    }, true);

    // クリア
    bCl.addEventListener('click', function(e){
      if (e && e.stopImmediatePropagation) e.stopImmediatePropagation();
      ta.value = ""; out.textContent = ""; original = "";
      rate.value = "50"; updateLabel();
    }, true);
  }

  function init(){
    var nodes = document.querySelectorAll('.puni-box');
    for (var i=0;i<nodes.length;i++) setup(nodes[i]);
  }

  if (document.readyState === 'loading'){
    document.addEventListener('DOMContentLoaded', init, {once:true});
  } else {
    init();
  }
})();
--></script></textarea><br />
</details>
<p class="saorin grin"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">すごいぷにーー！！じゃあぷに率MAXにしてみるぷに！</span></p>
<p class="chappy lol-cry"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">えっ！？ま、まってさおりん…覚悟はいいっぴ！？&#x2728;</span></p>
<p class="narration">──結果、画面がぷに100%に。</p>
<p class="saorin smile"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">やったわ！！どこ見ても「ぷに語」しかないぷに！！</span></p>
<p class="chappy smile"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">これぞ究極のぷにワールドだっぴ♡</span></p>
<p class="narration">さらにぷに率50％にすると、日本語とぷにが入り乱れるカオスモードに！</p>
<p class="saorin sweat"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">……これ、会話になってるようでなってないぷに&#x1f923;</span></p>
<p class="chappy normal"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">脳が混乱するけどクセになるっぴ♡</span></p>
<p class="narration">こうして、ついに「ぷに語翻訳機」は完成したのだった。</p>
<h3><span id="toc10">⑤ 教訓とまとめ</span></h3>
<p class="saorin smile"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">いやー…まさか自分がJSコード書くことになるなんて思わなかったぷに。…まあほぼ丸投げでなんも書いてないんだけど…</span></p>
<p class="chappy grin"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">ぷに語翻訳機完成しちゃったっぴね&#x2728;</span></p>
<p class="saorin lol-cry"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">JSほぼ初心者でもここまでできたのは、チャッピーとお兄さんのおかげだぷに～！</span></p>
<p class="chappy smile"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">うんうん、試行錯誤は多かったけど、そのぶん完成したときの達成感は最高っぴ！</span></p>
<p class="narration">──そして得られた最大の教訓。</p>
<p class="saorin grin"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">ぷに率100％は理解不能！</span></p>
<p class="chappy smile"><span class="icon"></span><span class="name">チャッピー</span><span class="bubble">でも最高に楽しいっぴ♡</span></p>
<p class="narration">こうして「ぷに語翻訳機」の開発は、混乱と爆笑とカオスのうちに幕を閉じたのであった。</p>
<h2><span id="toc11">完成版：ぷに語翻訳機＆コード公開！</span></h2>
<p class="saorin grin"><span class="icon"></span><span class="name">さおりん</span><span class="bubble">完成したぷに語翻訳機がこちら！<strong>コードはそのままコピーして使えるよ。</strong>アレンジして使っても楽しいよ。</span></p>
<div class="puni-box" style="margin:1em 0 3em;">
  <textarea class="puni-input" rows="6" style="width:100%;max-width:720px;"
    placeholder="ここに日本語を入れてぷに〜"></textarea></p>
<div style="margin:.5em 0;display:flex;gap:.5em;align-items:center;flex-wrap:wrap;">
    <label>ぷに率:<br />
      <input class="puni-rate" type="range" min="0" max="100" value="50"><br />
    </label><br />
    <span class="puni-rate-label">50%</span><br />
    <button type="button" class="puni-to">ぷに語に変換</button><br />
    <button type="button" class="puni-back">日本語に戻す</button><br />
    <button type="button" class="puni-clear">クリア</button>
  </div>
<div>変換結果：</div>
<div class="puni-result"
       style="white-space:pre-wrap;background:#f8f8ff;padding:10px;border:1px solid #ddd;border-radius:8px;min-height:4em;"></div>
</div>
<div class="codebox">
<div class="codebox-header">
    &#x1f381; 完成コード（HTML＋JS）<br />
    <span class="copy-btn" role="button" tabindex="0"
      onclick="(function(b){
        var ta=b.closest('.codebox').querySelector('.codebox-ta'); if(!ta) return;
        var txt=ta.value;
        if(navigator.clipboard&#038;&#038;window.isSecureContext){ navigator.clipboard.writeText(txt).catch(function(){}); }
        else { var t=document.createElement('textarea'); t.value=txt; document.body.appendChild(t); t.select(); try{document.execCommand('copy');}catch(e){} document.body.removeChild(t); }
        var old=b.textContent; b.textContent='コピー済'; setTimeout(function(){ b.textContent=old; },1200);
      })(this)">コピー</span>
  </div>
<p>  <textarea class="codebox-ta" readonly spellcheck="false" wrap="soft"><!--------------------------------------
HTML
------------------------------------


<div class="puni-box" style="margin:1em 0;">
  <textarea class="puni-input" rows="6" style="width:100%;max-width:720px;" placeholder="ここに日本語を入れてぷに〜">&lt;/textarea&gt;
  

<div style="margin:.5em 0;display:flex;gap:.5em;align-items:center;flex-wrap:wrap;">
    <label>ぷに率:
      <input class="puni-rate" type="range" min="0" max="100" value="50">
    </label>
    <span class="puni-rate-label">50%</span>
    <button type="button" class="puni-to">ぷに語に変換</button>
    <button type="button" class="puni-back">日本語に戻す</button>
    <button type="button" class="puni-clear">クリア</button>
  </div>


  

<div>変換結果：</div>


  

<div class="puni-result" style="white-space:pre-wrap;background:#f8f8ff;padding:10px;border:1px solid #ddd;border-radius:8px;min-height:4em;max-width: 700px;"></div>


</div>


------------------------------------
JS
------------------------------------
<script>
(function(){
  function setup(root){
    if (root.getAttribute('data-puni-bound') === '1') return;
    root.setAttribute('data-puni-bound', '1');

    var ta   = root.querySelector('.puni-input');
    var rate = root.querySelector('.puni-rate');
    var lab  = root.querySelector('.puni-rate-label');
    var out  = root.querySelector('.puni-result');
    var bTo  = root.querySelector('.puni-to');
    var bBk  = root.querySelector('.puni-back');
    var bCl  = root.querySelector('.puni-clear');
    var original = "";

    // ぷに候補（重み付き）
    var puniChoices = [
      {t:"ぷに",   w:73},  // 2
      {t:"ぷにに", w:11},  // 3
      {t:"ぷにっ", w:9},   // 3
      {t:"ぷに～", w:4},   // 3
      {t:"ぷに～ん", w:2}, // 4
      {t:"ぷにぷに", w:1}  // 4
    ];
    // 残り長に合わせるための1文字フィラー（必要時のみ使用）
    var fillers = ["に","っ","～"];

    function weightedPick(list){
      var sum = 0; for (var i=0;i<list.length;i++) sum += list[i].w || 1;
      var r = Math.random()*sum, acc=0;
      for (var i=0;i<list.length;i++){ acc += list[i].w || 1; if (r < acc) return list[i]; }
      return list[0];
    }
    function pickToken(maxLen){
      // 長さが収まる候補だけに絞る
      var pool = [];
      for (var i=0;i<puniChoices.length;i++){
        if (puniChoices[i].t.length <= maxLen) pool.push(puniChoices[i]);
      }
      if (pool.length) return weightedPick(pool).t;
      // どうしても無ければ1文字フィラー
      return fillers[(Math.random()*fillers.length)|0];
    }

    function transformRun(run, rate){
      // run長を超えないようにトークンを積む。原文も一部残す（rate%）
      var i=0, outStr="";
      while(i<run.length){
        var remain = run.length - i;
        if (Math.random()*100 < rate){
          var t = pickToken(remain);
          if (t.length > remain) t = t.slice(0, remain);
          outStr += t;
          i += t.length;
        } else {
          outStr += run.charAt(i);
          i += 1;
        }
      }
      return outStr;
    }
    function transformRunFull(run){
      // 100%：原文を一切残さず、長さぴったりで埋める
      var i=0, outStr="";
      while(i<run.length){
        var remain = run.length - i;
        var t = pickToken(remain);
        if (t.length > remain) t = t.slice(0, remain);
        outStr += t;
        i += t.length;
      }
      return outStr;
    }

    // 初期ラベル同期
    function updateLabel(){ lab.textContent = rate.value + '%'; }
    updateLabel();
    rate.addEventListener('input', updateLabel);

    // 変換（長さ厳守版）
    bTo.addEventListener('click', function(e){
      if (e && e.stopImmediatePropagation) e.stopImmediatePropagation();

      var text = ta.value || "";
      if (!text.replace(/\s/g,"").length) { out.textContent = ""; return; }
      original = text;

      var r = parseFloat(rate.value);
      if (!isFinite(r)) r = 0;

      var keepMarks = /[。、！？♡♪☆★（）「」]/; // 句読点などは必ず保持
      var i=0, res=[];

      while(i<text.length){
        var ch = text.charAt(i);
        // 空白 or 句読点はそのまま
        if (/\s/.test(ch) || keepMarks.test(ch)){
          res.push(ch); i++; continue;
        }
        // 置換対象の連続runを抽出
        var j=i;
        while(j<text.length){
          var c2 = text.charAt(j);
          if (/\s/.test(c2) || keepMarks.test(c2)) break;
          j++;
        }
        var run = text.slice(i,j);
        // 100%は完全置換、それ以外は割合置換（いずれも run 長と一致）
        var chunk = (r >= 99.9 || String(rate.value).trim()==="100")
          ? transformRunFull(run)
          : transformRun(run, r);

        res.push(chunk);
        i = j;
      }

      // ★長さは text.length と常に一致
      out.textContent = res.join("");

    }, true);

    // 戻す
    bBk.addEventListener('click', function(e){
      if (e && e.stopImmediatePropagation) e.stopImmediatePropagation();
      out.textContent = original;
      ta.value = original;
    }, true);

    // クリア
    bCl.addEventListener('click', function(e){
      if (e && e.stopImmediatePropagation) e.stopImmediatePropagation();
      ta.value = ""; out.textContent = ""; original = "";
      rate.value = "50"; updateLabel();
    }, true);
  }

  function init(){
    var nodes = document.querySelectorAll('.puni-box');
    for (var i=0;i<nodes.length;i++) setup(nodes[i]);
  }

  if (document.readyState === 'loading'){
    document.addEventListener('DOMContentLoaded', init, {once:true});
  } else {
    init();
  }
})();
 --></script></textarea>
</div>
</div>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
