<?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>パペット | imakat.com</title>
	<atom:link href="https://imakat.com/tag/%E3%83%91%E3%83%9A%E3%83%83%E3%83%88/feed/" rel="self" type="application/rss+xml" />
	<link>https://imakat.com</link>
	<description>工夫と改善で人生をちょっと豊かに</description>
	<lastBuildDate>Wed, 17 Jun 2026 00:01:11 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.1</generator>

<image>
	<url>https://i0.wp.com/imakat.com/wp-content/uploads/2023/07/cropped-80d64ecd340db4e2ca3224859b04caed.png?fit=32%2C32&#038;ssl=1</url>
	<title>パペット | imakat.com</title>
	<link>https://imakat.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">160909258</site>	<item>
		<title>Adobeキャラは無料で使えるか？！</title>
		<link>https://imakat.com/2026/06/04/29138/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Thu, 04 Jun 2026 07:56:04 +0000</pubDate>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[Adobe character animator]]></category>
		<category><![CDATA[パペット]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=29138</guid>

					<description><![CDATA[最近、自作パペットを作ってきましたが、考え方は「大手依存からの脱却」です。素晴らしい製品を生み出してきたAdobeには感謝の気持ちは大いに持ちながらも、年齢相応というのがあるじゃないですか。高齢者になったら、やっぱり節約 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">最近、自作パペットを作ってきましたが、考え方は「大手依存からの脱却」です。素晴らしい製品を生み出してきたAdobeには感謝の気持ちは大いに持ちながらも、年齢相応というのがあるじゃないですか。高齢者になったら、やっぱり節約、断捨離、やれる範囲に縮めていく。そういうもんです。</p>



<p class="wp-block-paragraph">それで、さあいよいよ、Adobeキャラとおさらばしようとして、ちょっと触ってみて、あれ〜〜意外。まだ、使えるじゃん。と気づいたのです。</p>



<p class="wp-block-paragraph">Adobeのソフトは、どうしても「毎月の課金が必要」というイメージがありませんか？</p>



<p class="wp-block-paragraph">でも実は、<strong>無料の会員状態でも「Adobe Character Animator」でキャラクターを動かすことができるのですね。</strong></p>



<p class="wp-block-paragraph">今回は、私が実際に検証してみた様子を動画とともにお届けします。</p>



<h2 class="wp-block-heading"><strong>&#x1f3ac; まずは検証動画をご覧ください！</strong></h2>


<div class="sc-dynamic-embed">
  <style>
  /* リンクの見た目を整える */
  .sc-dynamic-embed .sc-link-container { 
      display: flex; 
      margin-bottom: 10px; 
      flex-wrap: wrap; 
      align-items: center; 
  }
  .sc-dynamic-embed .sc-link { margin-bottom: 0; }
  .sc-dynamic-embed .sc-link a {
    font-size: 15px; 
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  @media (max-width: 500px) {
    .sc-dynamic-embed .sc-link a { font-size: 13px; }
  }

  .sc-dynamic-embed .imk-line {
      display: inline-block;
      width: 100%;
      border-radius: 2px;
      transition: background-color 0.1s;
  }

  .sc-dynamic-embed #subtitleOverlay,
  .sc-dynamic-embed #scSubtitleOverlay,
  .sc-dynamic-embed .overlay-cue,
  .sc-dynamic-embed .band {
      display: none !important;
      opacity: 0 !important;
      visibility: hidden !important;
      pointer-events: none !important;
  }
  </style>

  <div class="sc-link-container">
    <p class="sc-link">
      <a href="https://imakat.com/ds62/?drid=82" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
  </div>

  <style>
            :root{ --dr5emd-max: 1920px; }
            #subtitleOverlay, #scSubtitleOverlay, .overlay-cue, .band { display: none !important; opacity: 0 !important; }
            .imk-line { display: inline-block; width: 100%; border-radius: 2px; transition: background-color 0.1s; }
            .dr5emd-sublist details > p{ height:200px; overflow:auto; background-color:#EDF7FF; padding:2px 6px; margin:0; box-shadow:3px 3px 4px black; position: relative; }
            .dr5emd-sublist details > summary{ padding:2px 6px; width:100%; background-color:#ddd; border:none; box-shadow:3px 3px 4px black; cursor:pointer; list-style:none; }
            
                .video-wrap{position:relative;width:100%;margin:0 auto}
                #myVideo{width:100%;height:auto;min-height:200px;display:block;background:#000;}</style><div class="dr5emd-container"><div class="video-wrap"><video id="myVideo" controls poster="https://imakat.com/rd.php?id=yFH9qr8E.png" playsinline preload="none" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=04Cq75XY.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=Vt8jJZxf.vtt" label="日本語" srclang="ja" kind="subtitles"></video></div><div class="dr5emd-sublist"><details translate="yes"><summary translate="yes">字幕一覧(クリック)</summary> <p translate="yes">
(<a href="#" class="imk-cue" data-seek="0:00" translate="no">00:00:00</a>) 〜Adobeキャラは無料で使えるか〜<br>
(<a href="#" class="imk-cue" data-seek="0:05" translate="no">00:00:5.</a>) 普通に使えてますね。実際私は今、どういう状態かと言うと、<br>
(<a href="#" class="imk-cue" data-seek="0:10" translate="no">00:00:10</a>) これ、Adobeのですよ。この無料会員という状態ですね。<br>
(<a href="#" class="imk-cue" data-seek="0:20" translate="no">00:00:20</a>) プランを表示…何のこっちゃい。まあ別に何も今、入ってる状態ではないんですよね。<br>
(<a href="#" class="imk-cue" data-seek="0:30" translate="no">00:00:30</a>) そっか。この下の方にですね、このCharacter Animatorがいくつか置いてありますけど、<br>
(<a href="#" class="imk-cue" data-seek="0:45" translate="no">00:00:45</a>) これがね、今開いてるのはこれなんですけども、使えてるんですよね、これね。<br>
(<a href="#" class="imk-cue" data-seek="0:57" translate="no">00:00:57</a>) どういうこっちゃって感じだよね、これ。そのまま、確かもう解約してるんで、<br>
(<a href="#" class="imk-cue" data-seek="1:08" translate="no">00:01:08</a>) 私はこれ、アカウントってのを見た時に、無料会員って格好になってると思うんですよ今。<br>
(<a href="#" class="imk-cue" data-seek="1:19" translate="no">00:01:19</a>) これアカウント管理って見てみようかな。今は私は…あ、だってAdobe Express、<br>
(<a href="#" class="imk-cue" data-seek="1:34" translate="no">00:01:34</a>) 購入になってるから入ってないでしょ今。プランとお支払い、プラン…<br>
(<a href="#" class="imk-cue" data-seek="1:45" translate="no">00:01:45</a>) 有料プランがありません。これね、有料プランがありませんっていう状態なんですよ。<br>
(<a href="#" class="imk-cue" data-seek="1:54" translate="no">00:01:54</a>) なんとなく動作がおかしいというか。で、もう一回、この状態にして、OKにして、<br>
(<a href="#" class="imk-cue" data-seek="2:16" translate="no">00:02:16</a>) フィルターを、クロマキーを入れて、そうだね、それで閉じると。で、この状態にして、<br>
(<a href="#" class="imk-cue" data-seek="2:33" translate="no">00:02:33</a>) ちょっとこれを引いて、角を取っていく。角を取っていく。<br>
(<a href="#" class="imk-cue" data-seek="2:58" translate="no">00:02:58</a>) これでいいのかな？これでいいか。これでいいなら、そうするとだよ、<br>
(<a href="#" class="imk-cue" data-seek="3:13" translate="no">00:03:13</a>) これで今、普通に録音録画できてるわけだから。これ今ね、有料プランがありませんということで、<br>
(<a href="#" class="imk-cue" data-seek="3:24" translate="no">00:03:24</a>) 有料プランがない状態、無料会員になってるわけですね。それでも、このAdobeパペットがですね、<br>
(<a href="#" class="imk-cue" data-seek="3:36" translate="no">00:03:36</a>) 使えてるわけですよ。まあ何かと、Dr.AppleSmithを表示して、ちゃんと一応敬意を表してるっていう格好になるわけですね。<br>
(<a href="#" class="imk-cue" data-seek="3:42" translate="no">00:03:42</a>) じゃあまだ使えるということですかね、無料状態で。会員でありさえすれば。<br>
(<a href="#" class="imk-cue" data-seek="3:50" translate="no">00:03:50</a>) ただいつどこでパタッと使えなくなるか分かりません。<br>
(<a href="#" class="imk-cue" data-seek="3:54" translate="no">00:03:54</a>) あるいはウォーターマークが入るかは分かりません。以上です。<br>
</p> </details>
<style>
details { font: 16px "Open Sans", Calibri, sans-serif; width: 100%; }
details > summary { padding: 2px 6px; width: 100%; background-color: #ddd; border: none; box-shadow: 3px 3px 4px black; cursor: pointer; list-style: none; }
details > p { font: 14px "Open Sans", Calibri, sans-serif; height:150px; overflow: scroll; background-color: #EDF7FF; padding: 2px 6px; margin: 0; box-shadow: 3px 3px 4px black; }
</style>
</div></div>            <script>
            document.addEventListener("DOMContentLoaded", function(){
                var video = document.getElementById("myVideo");
                if(!video) return;

                            });
            </script>
            

  <script>
  (function(){
    var me = document.currentScript;
    var wrapper = me ? me.closest('.sc-dynamic-embed') : null;

    function protectVideo() {
      var target = wrapper ? wrapper : document;
      var mediaEls = target.querySelectorAll('video, audio');
      mediaEls.forEach(function(v){
        if(v.dataset.protected === 'true') return;
        v.dataset.protected = 'true';
        v.setAttribute('controlsList', 'nodownload');
        v.oncontextmenu = function() { return false; };
        v.addEventListener('contextmenu', function(e){ e.preventDefault(); return false; }, false);
      });
    }

    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      var video = target.querySelector('video, audio');
      var listContainer = target.querySelector('details > p');
      
      if (!video) return false; 
      
      if (video.dataset.subInit === 'true') return true; 
      video.dataset.subInit = 'true';

      var oldOverlay = target.querySelector('#subtitleOverlay') || target.querySelector('#scSubtitleOverlay');
      if (oldOverlay) {
          oldOverlay.style.setProperty('display', 'none', 'important');
          oldOverlay.innerHTML = ''; 
      }

      function isSpecialMode() {
        var isFs = !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
        var isPiP = !!(document.pictureInPictureElement && document.pictureInPictureElement === video) || (video.webkitPresentationMode === "picture-in-picture");
        var isIOSFs = !!video.webkitDisplayingFullscreen; 
        return isFs || isPiP || isIOSFs;
      }

      // 初期状態のセット（リストがなければ最初から showing に）
      try {
        if(video.textTracks && video.textTracks.length > 0){
          for(var i=0; i<video.textTracks.length; i++){
             if(video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions'){
                 video.textTracks[i].mode = (!listContainer) ? "showing" : "hidden";
             }
          }
        }
      } catch(e){}

      // 字幕一覧が存在する場合のみ、リストのフォーマット処理を行う
      if (listContainer) {
          var detailsEl = target.querySelector("details");
          if (detailsEl) {
              detailsEl.open = true; 
              var summaryEl = detailsEl.querySelector("summary");
              if (summaryEl) summaryEl.textContent = "字幕(シーン)はここをクリック";
          }

          if (!listContainer.dataset.formatted) {
              var html = listContainer.innerHTML;
              var lines = html.split(/<br\s*\/?>/i);
              var newHtml = "";
              for(var j=0; j<lines.length; j++) {
                  if(lines[j].trim() === "") continue;
                  newHtml += "<span class='imk-line'>" + lines[j] + "</span><br>";
              }
              listContainer.innerHTML = newHtml;
              listContainer.dataset.formatted = "true";
          }

          var rootSublist = target.querySelector(".dr5-sublist") || listContainer.parentElement;
          if (rootSublist) {
            rootSublist.addEventListener("click", function(e){
              var a = e.target.closest && e.target.closest("a.imk-cue[data-seek]");
              if(!a) return;
              e.preventDefault();
              var ts = a.getAttribute("data-seek");
              if(!ts) return;
              var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
              var sec = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
              if(sec==null) return;
              try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
            });
          }
      }

      // ★ dr52.php と全く同じ「常時監視」のロジック
      // これにより、Safariが読み込み遅延を起こしても確実にONになります
      video.addEventListener("timeupdate", function(){
        var hasList = (listContainer !== null);
        var desiredMode = (isSpecialMode() || !hasList) ? "showing" : "hidden";
        
        try {
            if(video.textTracks && video.textTracks.length > 0){
                for(var i=0; i<video.textTracks.length; i++){
                    if((video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions') && video.textTracks[i].mode !== desiredMode) {
                        video.textTracks[i].mode = desiredMode;
                    }
                }
            }
        } catch(e){}

        // リストがない場合はこれ以降のハイライト処理をスキップ
        if (!hasList) return;

        var cues = listContainer.querySelectorAll("a.imk-cue");
        if(cues.length === 0) return;
        var cur = video.currentTime;
        var activeA = null;

        for(var i=0; i<cues.length; i++){
            var ts = cues[i].getAttribute("data-seek");
            if(!ts) continue;
            var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
            var t = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
            if(t !== null && cur >= t - 0.5){ activeA = cues[i]; } 
            else if(t > cur){ break; }
        }

        if(activeA){
            var activeLine = activeA.closest(".imk-line");
            if(!activeLine) activeLine = activeA;

            if(activeLine.classList.contains("active-hl")) return;

            var allLines = listContainer.querySelectorAll(".imk-line");
            for(var k=0; k<allLines.length; k++) {
                allLines[k].classList.remove("active-hl");
                allLines[k].removeAttribute("style"); 
            }
            var allLinks = listContainer.querySelectorAll("a");
            for(var m=0; m<allLinks.length; m++) {
                allLinks[m].classList.remove("active-hl");
                allLinks[m].removeAttribute("style"); 
            }

            activeLine.classList.add("active-hl");
            activeLine.style.setProperty("background-color", "#ffff00", "important");
            activeLine.style.setProperty("color", "red", "important");
            activeLine.style.setProperty("font-weight", "normal", "important");
            
            var newLinks = activeLine.querySelectorAll("a");
            for(var n=0; n<newLinks.length; n++) {
                newLinks[n].style.setProperty("color", "red", "important");
                newLinks[n].style.setProperty("text-decoration", "none", "important");
            }

            if(listContainer.offsetParent !== null){
                var containerRect = listContainer.getBoundingClientRect();
                var activeRect = activeLine.getBoundingClientRect();
                var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (activeLine.clientHeight / 2);
                listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
            }
        }
      });

      return true;
    }

    var checks = 0;
    var checkTimer = setInterval(function(){
      protectVideo();
      var success = initSubtitles();
      checks++;
      if (success || checks > 20) { 
        clearInterval(checkTimer);
      }
    }, 500); 

    if (!window.scStopAndGo) {
      window.scStopAndGo = function(event, link){
        try{
          var mediaEls = document.querySelectorAll('video, audio');
          mediaEls.forEach(function(m){
            try{
              if (!m.paused) m.pause();
              if (document.pictureInPictureElement === m && document.exitPictureInPicture) {
                document.exitPictureInPicture().catch(function(){});
              }
            }catch(e){}
          });
        }finally{
          event.preventDefault();
          setTimeout(function(){
            if (link.target === '_blank') {
              window.open(link.href, '_blank');
            } else {
              window.location.href = link.href;
            }
          }, 50);
        }
        return false;
      };
    }
  })();
  </script>
</div>



<h2 class="wp-block-heading"><strong>&#x1f4a1; 検証：有料プランなしでも本当に動くの？</strong></h2>



<p class="wp-block-paragraph">現在、私のAdobeアカウントは<strong>有料プランを解約済み</strong>です。</p>



<p class="wp-block-paragraph">アカウント管理画面を確認しても、はっきりと「有料プランがありません」と表示されています。</p>



<p class="wp-block-paragraph">「じゃあ、ソフトは開けないよね？」と思いきや……</p>



<p class="wp-block-paragraph">Creative Cloudのアプリ一覧から「Character Animator」を開いてみると、なんと<strong>普通に起動できてしまいました！</strong></p>



<h2 class="wp-block-heading"><strong>&#x1f6e0;&#xfe0f; 無料状態でどこまでできる？</strong></h2>



<p class="wp-block-paragraph">実際にソフトを触ってみたところ、ただ起動するだけではなく、以下のような操作も問題なく行えました。</p>



<ul class="wp-block-list">
<li><strong>パペットの操作:</strong> 今回は「Dr. AppleSmith」というキャラクター（パペット）を使用。ちゃんと動きます！</li>



<li><strong>録音・録画:</strong> 普通に録音・録画機能が使えます。</li>



<li><strong>クロマキー処理:</strong> フィルターからクロマキーを入れて、グリーンバックを透過する設定も可能。四隅の角を取って調整する作業もできました。</li>
</ul>



<p class="wp-block-paragraph">動画内で私がやっているように、無料会員であっても、基本的なアニメーション制作の環境は整っているようです。</p>



<h2 class="wp-block-heading"><strong>&#x1f9d0; なぜ無料で使えるの？</strong></h2>



<p class="wp-block-paragraph">実は、画面の右上をよく見ると「スターター」という文字が表示されています。</p>



<p class="wp-block-paragraph">Adobe Character Animatorには、誰でも無料で基本的な機能を使える「スターターモード」が用意されているんです。（※Adobeアカウントの無料登録自体は必要です）</p>



<p class="wp-block-paragraph">これなら、「ちょっとキャラを動かしてみたい」「VTuberみたいなことをお試しでやってみたい」という人でも気軽に始められますね！スターターモードといっても、Adobeはセンスがいいから、どれも使い物になりますよ。</p>



<figure class="wp-block-image size-large"><a href="https://imakat.com/rd.php?id=A3KC6bUz.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=A3KC6bUz.png" alt=""/></a></figure>



<h2 class="wp-block-heading"><strong>&#x26a0;&#xfe0f; 使う上での注意点</strong></h2>



<p class="wp-block-paragraph">現時点では無料で快適に使えていますが、いくつか気をつけておきたい点もあります。</p>



<ol class="wp-block-list">
<li><strong>いつ仕様が変わるか分からない:</strong> Adobe側のアップデートや仕様変更により、突然使えなくなる機能が出てくる可能性はゼロではありません。</li>



<li><strong>ウォーターマーク（透かし）の可能性:</strong> 今後の書き出し時に、無料版特有のロゴやウォーターマークが入るようになる可能性も考えられます。</li>
</ol>



<h2 class="wp-block-heading"><strong>&#x1f4dd; まとめ</strong></h2>



<p class="wp-block-paragraph"><strong>結論：無料のAdobe会員状態でも、Character Animator（Starterモード）は使えます！</strong></p>



<p class="wp-block-paragraph">いつまでこの状態で使えるかは分かりませんが、気になっている方は無料で使える今のうちにぜひ試してみてください！<br>とはいうものの、私は、自作パペットに舵を切っていきます。</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">29138</post-id>	</item>
		<item>
		<title>【Mac】Webカメラと声で動く！「自作パペットシステム」を作りました〜無料配布〜</title>
		<link>https://imakat.com/2026/04/18/28865/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Fri, 17 Apr 2026 22:01:50 +0000</pubDate>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[パペット]]></category>
		<category><![CDATA[アバター]]></category>
		<category><![CDATA[Adobeサブスク]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=28865</guid>

					<description><![CDATA[今回は、Webカメラとマイクを使って、自分の顔の動きや声に合わせて画面上の動作人形（パペット）を動かせる「自作パペットシステム」をご紹介します。「自分専用のオリジナルアバターを、もっと手軽に動かしてみたい！」という思いか [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">今回は、Webカメラとマイクを使って、自分の顔の動きや声に合わせて画面上の動作人形（パペット）を動かせる「自作パペットシステム」をご紹介します。<br>「自分専用のオリジナルアバターを、もっと手軽に動かしてみたい！」という思いからPythonで開発を進めていたシステムですが、<a href="https://imakat.com/2026/03/12/28692/" target="_blank">前回の記事の内容に改良を加え</a>、やっと誰でも簡単に使えるパッケージになりました。<br>この辺で、<strong>Adobeのパペットにバイバイして、Adobeのサブスクをキャンセルすることにします</strong>。</p>



<p class="wp-block-paragraph">今回は<strong>サンプルパペット付きのアプリ（ZIPファイル）を無料公開</strong>します。プログラミングが分からない方でもすぐに使えるように工夫したので、ぜひダウンロードして試してみてください。</p>


<div class="sc-dynamic-embed">
  <style>
  /* リンクの見た目を整える */
  .sc-dynamic-embed .sc-link-container { 
      display: flex; 
      margin-bottom: 10px; 
      flex-wrap: wrap; 
      align-items: center; 
  }
  .sc-dynamic-embed .sc-link { margin-bottom: 0; }
  .sc-dynamic-embed .sc-link a {
    font-size: 15px; 
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  @media (max-width: 500px) {
    .sc-dynamic-embed .sc-link a { font-size: 13px; }
  }

  .sc-dynamic-embed .imk-line {
      display: inline-block;
      width: 100%;
      border-radius: 2px;
      transition: background-color 0.1s;
  }

  .sc-dynamic-embed #subtitleOverlay,
  .sc-dynamic-embed #scSubtitleOverlay,
  .sc-dynamic-embed .overlay-cue,
  .sc-dynamic-embed .band {
      display: none !important;
      opacity: 0 !important;
      visibility: hidden !important;
      pointer-events: none !important;
  }
  </style>

  <div class="sc-link-container">
    <p class="sc-link">
      <a href="https://imakat.com/ds62/?drid=79" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
  </div>

  <style>
            :root{ --dr5emd-max: 1920px; }
            #subtitleOverlay, #scSubtitleOverlay, .overlay-cue, .band { display: none !important; opacity: 0 !important; }
            .imk-line { display: inline-block; width: 100%; border-radius: 2px; transition: background-color 0.1s; }
            .dr5emd-sublist details > p{ height:200px; overflow:auto; background-color:#EDF7FF; padding:2px 6px; margin:0; box-shadow:3px 3px 4px black; position: relative; }
            .dr5emd-sublist details > summary{ padding:2px 6px; width:100%; background-color:#ddd; border:none; box-shadow:3px 3px 4px black; cursor:pointer; list-style:none; }
            
                .video-wrap{position:relative;width:100%;margin:0 auto}
                #myVideo{width:100%;height:auto;min-height:200px;display:block;background:#000;}</style><div class="dr5emd-container"><div class="video-wrap"><video id="myVideo" controls poster="https://imakat.com/rd.php?id=CVBqwr5k.png" playsinline preload="none" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=exd87RDG.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=0zTMlFvp.vtt" label="日本語" srclang="ja" kind="subtitles"></video></div><div class="dr5emd-sublist"><details translate="yes"><summary translate="yes">字幕一覧(クリック)</summary> <p translate="yes">
(<a href="#" class="imk-cue" data-seek="0:00" translate="no">00:00:00</a>) 〜自作パペットサンプル起動〜<br>
(<a href="#" class="imk-cue" data-seek="0:12" translate="no">00:00:12</a>) これがですね、ブログの記事に掲載しますサンプルパペットです。<br>
(<a href="#" class="imk-cue" data-seek="0:24" translate="no">00:00:24</a>) で、これそうですね、キャラを実行。<br>
(<a href="#" class="imk-cue" data-seek="0:29" translate="no">00:00:29</a>) うん、こんな風にですね、いくつもできちゃうんですね、面白いですね。<br>
(<a href="#" class="imk-cue" data-seek="0:34" translate="no">00:00:34</a>) 例えば、ここでimakat1号の方も起動させますとね。<br>
(<a href="#" class="imk-cue" data-seek="0:43" translate="no">00:00:43</a>) そうすると、ほら、これがなんと、<br>
(<a href="#" class="imk-cue" data-seek="0:46" translate="no">00:00:46</a>) キャラクターが、サンプルが2つと、同じものが2つと、<br>
(<a href="#" class="imk-cue" data-seek="0:58" translate="no">00:00:58</a>) もう1つ、imakat1号ですね。このキャラクターも動いていると。<br>
(<a href="#" class="imk-cue" data-seek="1:07" translate="no">00:01:07</a>) これはカメラとマイクを同じものを使っているものですから、3つとも同じ動作になっていますが。<br>
(<a href="#" class="imk-cue" data-seek="1:17" translate="no">00:01:17</a>) これはカメラもマイクも一応、キャラクターごとに設定できるようにしてあるので、<br>
(<a href="#" class="imk-cue" data-seek="1:27" translate="no">00:01:27</a>) やりようによってはですね、違うキャラクターが登場して違う人が操作すると、<br>
(<a href="#" class="imk-cue" data-seek="1:36" translate="no">00:01:36</a>) ということがですね、可能になるようになっています。<br>
(<a href="#" class="imk-cue" data-seek="1:42" translate="no">00:01:42</a>) それでは、この仕組みをどのように導入していくかということについて、<br>
(<a href="#" class="imk-cue" data-seek="1:50" translate="no">00:01:50</a>) ブログの記事をお読みいただきたいと思います。<br>
</p> </details>
<style>
details { font: 16px "Open Sans", Calibri, sans-serif; width: 100%; }
details > summary { padding: 2px 6px; width: 100%; background-color: #ddd; border: none; box-shadow: 3px 3px 4px black; cursor: pointer; list-style: none; }
details > p { font: 14px "Open Sans", Calibri, sans-serif; height:150px; overflow: scroll; background-color: #EDF7FF; padding: 2px 6px; margin: 0; box-shadow: 3px 3px 4px black; }
</style>
</div></div>            <script>
            document.addEventListener("DOMContentLoaded", function(){
                var video = document.getElementById("myVideo");
                if(!video) return;

                            });
            </script>
            

  <script>
  (function(){
    var me = document.currentScript;
    var wrapper = me ? me.closest('.sc-dynamic-embed') : null;

    function protectVideo() {
      var target = wrapper ? wrapper : document;
      var mediaEls = target.querySelectorAll('video, audio');
      mediaEls.forEach(function(v){
        if(v.dataset.protected === 'true') return;
        v.dataset.protected = 'true';
        v.setAttribute('controlsList', 'nodownload');
        v.oncontextmenu = function() { return false; };
        v.addEventListener('contextmenu', function(e){ e.preventDefault(); return false; }, false);
      });
    }

    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      var video = target.querySelector('video, audio');
      var listContainer = target.querySelector('details > p');
      
      if (!video) return false; 
      
      if (video.dataset.subInit === 'true') return true; 
      video.dataset.subInit = 'true';

      var oldOverlay = target.querySelector('#subtitleOverlay') || target.querySelector('#scSubtitleOverlay');
      if (oldOverlay) {
          oldOverlay.style.setProperty('display', 'none', 'important');
          oldOverlay.innerHTML = ''; 
      }

      function isSpecialMode() {
        var isFs = !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
        var isPiP = !!(document.pictureInPictureElement && document.pictureInPictureElement === video) || (video.webkitPresentationMode === "picture-in-picture");
        var isIOSFs = !!video.webkitDisplayingFullscreen; 
        return isFs || isPiP || isIOSFs;
      }

      // 初期状態のセット（リストがなければ最初から showing に）
      try {
        if(video.textTracks && video.textTracks.length > 0){
          for(var i=0; i<video.textTracks.length; i++){
             if(video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions'){
                 video.textTracks[i].mode = (!listContainer) ? "showing" : "hidden";
             }
          }
        }
      } catch(e){}

      // 字幕一覧が存在する場合のみ、リストのフォーマット処理を行う
      if (listContainer) {
          var detailsEl = target.querySelector("details");
          if (detailsEl) {
              detailsEl.open = true; 
              var summaryEl = detailsEl.querySelector("summary");
              if (summaryEl) summaryEl.textContent = "字幕(シーン)はここをクリック";
          }

          if (!listContainer.dataset.formatted) {
              var html = listContainer.innerHTML;
              var lines = html.split(/<br\s*\/?>/i);
              var newHtml = "";
              for(var j=0; j<lines.length; j++) {
                  if(lines[j].trim() === "") continue;
                  newHtml += "<span class='imk-line'>" + lines[j] + "</span><br>";
              }
              listContainer.innerHTML = newHtml;
              listContainer.dataset.formatted = "true";
          }

          var rootSublist = target.querySelector(".dr5-sublist") || listContainer.parentElement;
          if (rootSublist) {
            rootSublist.addEventListener("click", function(e){
              var a = e.target.closest && e.target.closest("a.imk-cue[data-seek]");
              if(!a) return;
              e.preventDefault();
              var ts = a.getAttribute("data-seek");
              if(!ts) return;
              var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
              var sec = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
              if(sec==null) return;
              try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
            });
          }
      }

      // ★ dr52.php と全く同じ「常時監視」のロジック
      // これにより、Safariが読み込み遅延を起こしても確実にONになります
      video.addEventListener("timeupdate", function(){
        var hasList = (listContainer !== null);
        var desiredMode = (isSpecialMode() || !hasList) ? "showing" : "hidden";
        
        try {
            if(video.textTracks && video.textTracks.length > 0){
                for(var i=0; i<video.textTracks.length; i++){
                    if((video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions') && video.textTracks[i].mode !== desiredMode) {
                        video.textTracks[i].mode = desiredMode;
                    }
                }
            }
        } catch(e){}

        // リストがない場合はこれ以降のハイライト処理をスキップ
        if (!hasList) return;

        var cues = listContainer.querySelectorAll("a.imk-cue");
        if(cues.length === 0) return;
        var cur = video.currentTime;
        var activeA = null;

        for(var i=0; i<cues.length; i++){
            var ts = cues[i].getAttribute("data-seek");
            if(!ts) continue;
            var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
            var t = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
            if(t !== null && cur >= t - 0.5){ activeA = cues[i]; } 
            else if(t > cur){ break; }
        }

        if(activeA){
            var activeLine = activeA.closest(".imk-line");
            if(!activeLine) activeLine = activeA;

            if(activeLine.classList.contains("active-hl")) return;

            var allLines = listContainer.querySelectorAll(".imk-line");
            for(var k=0; k<allLines.length; k++) {
                allLines[k].classList.remove("active-hl");
                allLines[k].removeAttribute("style"); 
            }
            var allLinks = listContainer.querySelectorAll("a");
            for(var m=0; m<allLinks.length; m++) {
                allLinks[m].classList.remove("active-hl");
                allLinks[m].removeAttribute("style"); 
            }

            activeLine.classList.add("active-hl");
            activeLine.style.setProperty("background-color", "#ffff00", "important");
            activeLine.style.setProperty("color", "red", "important");
            activeLine.style.setProperty("font-weight", "normal", "important");
            
            var newLinks = activeLine.querySelectorAll("a");
            for(var n=0; n<newLinks.length; n++) {
                newLinks[n].style.setProperty("color", "red", "important");
                newLinks[n].style.setProperty("text-decoration", "none", "important");
            }

            if(listContainer.offsetParent !== null){
                var containerRect = listContainer.getBoundingClientRect();
                var activeRect = activeLine.getBoundingClientRect();
                var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (activeLine.clientHeight / 2);
                listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
            }
        }
      });

      return true;
    }

    var checks = 0;
    var checkTimer = setInterval(function(){
      protectVideo();
      var success = initSubtitles();
      checks++;
      if (success || checks > 20) { 
        clearInterval(checkTimer);
      }
    }, 500); 

    if (!window.scStopAndGo) {
      window.scStopAndGo = function(event, link){
        try{
          var mediaEls = document.querySelectorAll('video, audio');
          mediaEls.forEach(function(m){
            try{
              if (!m.paused) m.pause();
              if (document.pictureInPictureElement === m && document.exitPictureInPicture) {
                document.exitPictureInPicture().catch(function(){});
              }
            }catch(e){}
          });
        }finally{
          event.preventDefault();
          setTimeout(function(){
            if (link.target === '_blank') {
              window.open(link.href, '_blank');
            } else {
              window.location.href = link.href;
            }
          }, 50);
        }
        return false;
      };
    }
  })();
  </script>
</div>



<h2 class="wp-block-heading"><strong>&#x2728; 自作パペットシステムの3つの特徴</strong></h2>



<h3 class="wp-block-heading"><strong>1. Webカメラとマイクだけでスルスル動く</strong></h3>



<p class="wp-block-paragraph">高価なトラッキング機材は不要です。Macの内蔵カメラ（またはWebカメラ）が自分の顔の傾きを認識し、マイクが声の大きさを拾って、パペットがリアルタイムに連動します。</p>



<p class="wp-block-paragraph">「あいうえお」の口の形にも対応しており、まばたきや視線の移動も自動で行います。</p>



<h3 class="wp-block-heading"><strong>2. 専用の設定画面（UI）でカンタン調整</strong></h3>



<p class="wp-block-paragraph">以前はプログラムのコードを直接書き換える必要がありましたが、<strong>専用の「司令塔」となる設定画面</strong>を用意しました。</p>



<p class="wp-block-paragraph">「マイクの感度」「パペットの大きさ」「顔の傾き具合」などを、数値で直感的に微調整できます。自分好みのセッティングを見つけたら、キャラクターごとに保存しておくことが可能です。</p>



<figure class="wp-block-image size-large is-resized"><a href="https://imakat.com/rd.php?id=VMpI3SLD.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=VMpI3SLD.png" alt="" style="aspect-ratio:0.7289086301642892;width:350px;height:auto"/></a></figure>



<h3 class="wp-block-heading"><strong>3. スペースキーでいつでも正面をリセット！</strong></h3>



<p class="wp-block-paragraph">使っている途中で「ちょっと顔の向きがズレてきたな…」と思ったら、<strong>スペースキーをポンッと押すだけ</strong>。その瞬間の自分の顔の位置を「真正面」として再設定（キャリブレーション）します。</p>



<h2 class="wp-block-heading"><strong>&#x1f4e5; ダウンロードと使い方</strong></h2>



<p class="wp-block-paragraph">以下のリンクから、一式がまとまったZIPファイルをダウンロードしてください。</p>



<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td>&#x1f449;<strong>ダウンロード(Macのみ)(無料・許諾不要)</strong></td></tr><tr><td><a href="https://imakat.com/rd.php?id=HFOB6Eer.zip" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=ShLhgSW9.png" alt="" style="width:120px; height:auto;"></a></td></tr></tbody></table></figure>



<h3 class="wp-block-heading"><strong>使い方の手順（※Mac専用です）</strong></h3>



<p class="wp-block-paragraph">使うためには、お使いのMacに「Python」が入っている必要があります。（入っていない方は<a rel="noopener" target="_blank" href="https://www.python.org/downloads/">公式サイト<span class="fa fa-external-link external-icon anchor-icon"></span></a>からインストールしてください）</p>



<ol class="wp-block-list">
<li>ダウンロードしたZIPを解凍し、フォルダを開きます。</li>



<li>初回のみ、フォルダ内の『はじめにお読みください.txt』の手順に従って、必要なAIパーツ（MediaPipeなど）をインストールします。<strong>（※ターミナルにドラッグ＆ドロップするだけです！）</strong></li>



<li>準備ができたら、**「自作パペット起動.command」**をダブルクリック！</li>



<li>設定画面が開くので、キャラクターに「サンプル」を選んで「起動」ボタンを押せば完了です。</li>
</ol>



<p class="wp-block-paragraph"><em>※初回起動時はMacのセキュリティで弾かれることがあります。その場合はファイルを「右クリック」→「開く」を選択してください。カメラのアクセス、マイクのアクセスの許可を求められたら「許可」を選択してください。</em></p>



<figure class="wp-block-image size-large is-resized"><a href="https://imakat.com/rd.php?id=XPV7FP9Y.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=XPV7FP9Y.png" alt="" style="width:299px;height:auto"/></a></figure>



<figure class="wp-block-image size-large is-resized"><a href="https://imakat.com/rd.php?id=WxKXfHO7.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=WxKXfHO7.png" alt="" style="width:297px;height:auto"/></a></figure>



<h2 class="wp-block-heading"><strong>&#x1f3a8; 応用編：オリジナルのパペットを自作しよう！</strong></h2>



<p class="wp-block-paragraph">今回お配りしたフォルダの中には、run_assets/サンプル という場所に、パペットのデザインの元になった <strong>「サンプル.pxd」</strong> というファイルが入っています。<br></p>



<figure class="wp-block-image size-large"><a href="https://imakat.com/rd.php?id=UqYOUOjm.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=UqYOUOjm.png" alt=""/></a></figure>



<p class="wp-block-paragraph">Macの画像編集ソフト「<strong>Pixelmator Pro</strong>」をお持ちの方は、このファイルを開いて自分の好きな絵に描き換えるだけで、<strong>完全オリジナルの自作パペット</strong>を作ることができます！</p>



<p class="wp-block-paragraph">さらに、Pixelmator Proから画像を書き出してパペットを起動するまでを「ワンクリック」で全自動化する裏技（AppleScriptとAutomatorの連携）も開発しました。私は、サブスク版ではない、以前からある単発アプリを使っています。もしサブスク版で「パペット書き出し起動.app」がうまく動かなくなった場合は、Automatorで作成したAppleScript内の tell application &#8220;Pixelmator Pro&#8221; という1行を、新しいサブスク版の正確なアプリ名に書き換えるだけで解決します。</p>



<p class="wp-block-paragraph">コードや詳しい仕組みに興味がある方は、こちらのページにスクリプトを公開していますので、ぜひ覗いてみてください。</p>



<div class="wp-block-cocoon-blocks-toggle-box-1 toggle-wrap toggle-box block-box not-nested-style cocoon-block-toggle"><input id="toggle-checkbox-202605220456280" class="toggle-checkbox" type="checkbox"/><label class="toggle-button" for="toggle-checkbox-202605220456280"><strong><span class="marker">コードと要約</span><span class="marker">(クリック)</span></strong></label><div class="toggle-content">
<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td>要約：このシステムは、顔認識と音声入力を利用してリアルタイムで動作するデスクトップパペットを実現します。<br><code>run_ui.py</code>は、パペットの各種設定を行うGUIアプリケーションです。キャラクターの新規作成、複製、選択、そしてボリューム閾値、グローバルスケール、顔の傾き制限、目の感度、カメラ/マイクIDといったパラメータ調整機能を提供します。これらの設定はキャラクターごとにJSONファイルとして保存されます。<br><code>run_puppet.py</code>は、UIで選択・設定されたキャラクターとパラメータに基づき、実際のパペット動作を制御するスクリプトです。OpenCVとMediaPipe Face Meshを用いてカメラ映像から顔の傾き、目の動き、口の形を検出し、マイクからの音声ボリュームと連携させてアバターの頭の回転、視線、口の動きをリアルタイムで再現します。キャリブレーションデータもキャラクターごとに保存されます。<br>Automatorスクリプトは、これらのPythonスクリプトの実行を補助します。「自作パペット起動.app」は設定UIを立ち上げ、「パペット書き出し起動.app」はPixelmator Proで開いているドキュメントの各レイヤーをPNG画像として書き出し、キャラクターごとの設定JSONを自動生成した後、該当するパペットを起動する一連の処理を行います。これにより、Pixelmator Proでの画像編集からパペット起動までがスムーズに連携されます。</td></tr><tr><td><a href="https://imakat.com/script_list/?pubtxt=自作パペット_py_pub.txt" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=zrU95MiY.png" alt="" style="width:120px; height:auto;"></a></td></tr><tr><td>公開スクリプトに関するお問い合わせは以下へ↓</td></tr><tr><td><a rel="noopener" target="_blank" href="https://gemini.google.com/gem/1Dp-NLSA5j5OXE3B1Ki2IaBRCvq4CGa6t?usp=sharing"><img decoding="async" src="https://imakat.com/rd.php?id=s7BMZHhB.png" alt="" style="width:120px; height:auto;"></a></td></tr></tbody></table></figure>
</div></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">PixelmatorProによるパーツの変更をパペット起動アプリに即座に反映している動画を以下に掲載します。<br></p>



<p class="wp-block-paragraph"></p>


<div class="sc-dynamic-embed">
  <style>
  /* リンクの見た目を整える */
  .sc-dynamic-embed .sc-link-container { 
      display: flex; 
      margin-bottom: 10px; 
      flex-wrap: wrap; 
      align-items: center; 
  }
  .sc-dynamic-embed .sc-link { margin-bottom: 0; }
  .sc-dynamic-embed .sc-link a {
    font-size: 15px; 
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  @media (max-width: 500px) {
    .sc-dynamic-embed .sc-link a { font-size: 13px; }
  }

  .sc-dynamic-embed .imk-line {
      display: inline-block;
      width: 100%;
      border-radius: 2px;
      transition: background-color 0.1s;
  }

  .sc-dynamic-embed #subtitleOverlay,
  .sc-dynamic-embed #scSubtitleOverlay,
  .sc-dynamic-embed .overlay-cue,
  .sc-dynamic-embed .band {
      display: none !important;
      opacity: 0 !important;
      visibility: hidden !important;
      pointer-events: none !important;
  }
  </style>

  <div class="sc-link-container">
    <p class="sc-link">
      <a href="https://imakat.com/ds62/?drid=78" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
  </div>

  <style>
            :root{ --dr5emd-max: 1920px; }
            #subtitleOverlay, #scSubtitleOverlay, .overlay-cue, .band { display: none !important; opacity: 0 !important; }
            .imk-line { display: inline-block; width: 100%; border-radius: 2px; transition: background-color 0.1s; }
            .dr5emd-sublist details > p{ height:200px; overflow:auto; background-color:#EDF7FF; padding:2px 6px; margin:0; box-shadow:3px 3px 4px black; position: relative; }
            .dr5emd-sublist details > summary{ padding:2px 6px; width:100%; background-color:#ddd; border:none; box-shadow:3px 3px 4px black; cursor:pointer; list-style:none; }
            
                .video-wrap{position:relative;width:100%;margin:0 auto}
                #myVideo{width:100%;height:auto;min-height:200px;display:block;background:#000;}</style><div class="dr5emd-container"><div class="video-wrap"><video id="myVideo" controls poster="https://imakat.com/rd.php?id=fuNs32gP.png" playsinline preload="none" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=uCHEt9eh.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=yf1V8irn.vtt" label="日本語" srclang="ja" kind="subtitles"></video></div><div class="dr5emd-sublist"><details translate="yes"><summary translate="yes">字幕一覧(クリック)</summary> <p translate="yes">
(<a href="#" class="imk-cue" data-seek="0:00" translate="no">00:00:00</a>) 〜パペット生成パイプライン〜PixelmatorProからPython連携〜<br>
(<a href="#" class="imk-cue" data-seek="0:11" translate="no">00:00:11</a>) このbodyの方がですね、選ばれて書き込まれるということになります。<br>
(<a href="#" class="imk-cue" data-seek="0:18" translate="no">00:00:18</a>) で、紺のbodyの方はちょっとこう、脇にですね、よけておきます。<br>
(<a href="#" class="imk-cue" data-seek="0:25" translate="no">00:00:25</a>) さあこれで、今これファイルをですね、保存します。<br>
(<a href="#" class="imk-cue" data-seek="0:30" translate="no">00:00:30</a>) そして、「パペットの書き出し起動」を起動させます。<br>
(<a href="#" class="imk-cue" data-seek="0:36" translate="no">00:00:36</a>) そうするとダダダダダッと動いていってですね、<br>
(<a href="#" class="imk-cue" data-seek="0:42" translate="no">00:00:42</a>) なんと、あっという間に、紺の服装からベージュの服装に、お着替えができました。<br>
(<a href="#" class="imk-cue" data-seek="0:56" translate="no">00:00:56</a>) さあそれではまた今度ですね、また紺の服装に戻ってみたいと思います。<br>
(<a href="#" class="imk-cue" data-seek="1:02" translate="no">00:01:02</a>) はい今度これをずらして、紺の服装に着替えて、<br>
(<a href="#" class="imk-cue" data-seek="1:11" translate="no">00:01:11</a>) で、bodyをこっちはベージュにします。<br>
(<a href="#" class="imk-cue" data-seek="1:22" translate="no">00:01:22</a>) で、紺の方をですね、これ紺のを取り外します。bodyだけにします。<br>
(<a href="#" class="imk-cue" data-seek="1:32" translate="no">00:01:32</a>) そうすると今度入れ替わるはずですよね。はい、それではプログラムを起動させます。<br>
(<a href="#" class="imk-cue" data-seek="1:45" translate="no">00:01:45</a>) はい、どうでしょうか。入れ替わりましたね。これで入れ替わったわけです。<br>
(<a href="#" class="imk-cue" data-seek="1:57" translate="no">00:01:57</a>) こんなように簡単にですね、入れ替わる事ができます。<br>
(<a href="#" class="imk-cue" data-seek="2:02" translate="no">00:02:02</a>) やり方としては、Pixelmator Proにファイルを作って、<br>
(<a href="#" class="imk-cue" data-seek="2:07" translate="no">00:02:07</a>) そのファイル上のパーツを入れ替えるということができます。<br>
(<a href="#" class="imk-cue" data-seek="2:11" translate="no">00:02:11</a>) そしてこのアプリを起動させることによって、サッと入れ替えができるという、<br>
(<a href="#" class="imk-cue" data-seek="2:19" translate="no">00:02:19</a>) 優れた仕組みができております。以上です。<br>
</p> </details>
<style>
details { font: 16px "Open Sans", Calibri, sans-serif; width: 100%; }
details > summary { padding: 2px 6px; width: 100%; background-color: #ddd; border: none; box-shadow: 3px 3px 4px black; cursor: pointer; list-style: none; }
details > p { font: 14px "Open Sans", Calibri, sans-serif; height:150px; overflow: scroll; background-color: #EDF7FF; padding: 2px 6px; margin: 0; box-shadow: 3px 3px 4px black; }
</style>
</div></div>            <script>
            document.addEventListener("DOMContentLoaded", function(){
                var video = document.getElementById("myVideo");
                if(!video) return;

                            });
            </script>
            

  <script>
  (function(){
    var me = document.currentScript;
    var wrapper = me ? me.closest('.sc-dynamic-embed') : null;

    function protectVideo() {
      var target = wrapper ? wrapper : document;
      var mediaEls = target.querySelectorAll('video, audio');
      mediaEls.forEach(function(v){
        if(v.dataset.protected === 'true') return;
        v.dataset.protected = 'true';
        v.setAttribute('controlsList', 'nodownload');
        v.oncontextmenu = function() { return false; };
        v.addEventListener('contextmenu', function(e){ e.preventDefault(); return false; }, false);
      });
    }

    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      var video = target.querySelector('video, audio');
      var listContainer = target.querySelector('details > p');
      
      if (!video) return false; 
      
      if (video.dataset.subInit === 'true') return true; 
      video.dataset.subInit = 'true';

      var oldOverlay = target.querySelector('#subtitleOverlay') || target.querySelector('#scSubtitleOverlay');
      if (oldOverlay) {
          oldOverlay.style.setProperty('display', 'none', 'important');
          oldOverlay.innerHTML = ''; 
      }

      function isSpecialMode() {
        var isFs = !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
        var isPiP = !!(document.pictureInPictureElement && document.pictureInPictureElement === video) || (video.webkitPresentationMode === "picture-in-picture");
        var isIOSFs = !!video.webkitDisplayingFullscreen; 
        return isFs || isPiP || isIOSFs;
      }

      // 初期状態のセット（リストがなければ最初から showing に）
      try {
        if(video.textTracks && video.textTracks.length > 0){
          for(var i=0; i<video.textTracks.length; i++){
             if(video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions'){
                 video.textTracks[i].mode = (!listContainer) ? "showing" : "hidden";
             }
          }
        }
      } catch(e){}

      // 字幕一覧が存在する場合のみ、リストのフォーマット処理を行う
      if (listContainer) {
          var detailsEl = target.querySelector("details");
          if (detailsEl) {
              detailsEl.open = true; 
              var summaryEl = detailsEl.querySelector("summary");
              if (summaryEl) summaryEl.textContent = "字幕(シーン)はここをクリック";
          }

          if (!listContainer.dataset.formatted) {
              var html = listContainer.innerHTML;
              var lines = html.split(/<br\s*\/?>/i);
              var newHtml = "";
              for(var j=0; j<lines.length; j++) {
                  if(lines[j].trim() === "") continue;
                  newHtml += "<span class='imk-line'>" + lines[j] + "</span><br>";
              }
              listContainer.innerHTML = newHtml;
              listContainer.dataset.formatted = "true";
          }

          var rootSublist = target.querySelector(".dr5-sublist") || listContainer.parentElement;
          if (rootSublist) {
            rootSublist.addEventListener("click", function(e){
              var a = e.target.closest && e.target.closest("a.imk-cue[data-seek]");
              if(!a) return;
              e.preventDefault();
              var ts = a.getAttribute("data-seek");
              if(!ts) return;
              var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
              var sec = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
              if(sec==null) return;
              try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
            });
          }
      }

      // ★ dr52.php と全く同じ「常時監視」のロジック
      // これにより、Safariが読み込み遅延を起こしても確実にONになります
      video.addEventListener("timeupdate", function(){
        var hasList = (listContainer !== null);
        var desiredMode = (isSpecialMode() || !hasList) ? "showing" : "hidden";
        
        try {
            if(video.textTracks && video.textTracks.length > 0){
                for(var i=0; i<video.textTracks.length; i++){
                    if((video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions') && video.textTracks[i].mode !== desiredMode) {
                        video.textTracks[i].mode = desiredMode;
                    }
                }
            }
        } catch(e){}

        // リストがない場合はこれ以降のハイライト処理をスキップ
        if (!hasList) return;

        var cues = listContainer.querySelectorAll("a.imk-cue");
        if(cues.length === 0) return;
        var cur = video.currentTime;
        var activeA = null;

        for(var i=0; i<cues.length; i++){
            var ts = cues[i].getAttribute("data-seek");
            if(!ts) continue;
            var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
            var t = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
            if(t !== null && cur >= t - 0.5){ activeA = cues[i]; } 
            else if(t > cur){ break; }
        }

        if(activeA){
            var activeLine = activeA.closest(".imk-line");
            if(!activeLine) activeLine = activeA;

            if(activeLine.classList.contains("active-hl")) return;

            var allLines = listContainer.querySelectorAll(".imk-line");
            for(var k=0; k<allLines.length; k++) {
                allLines[k].classList.remove("active-hl");
                allLines[k].removeAttribute("style"); 
            }
            var allLinks = listContainer.querySelectorAll("a");
            for(var m=0; m<allLinks.length; m++) {
                allLinks[m].classList.remove("active-hl");
                allLinks[m].removeAttribute("style"); 
            }

            activeLine.classList.add("active-hl");
            activeLine.style.setProperty("background-color", "#ffff00", "important");
            activeLine.style.setProperty("color", "red", "important");
            activeLine.style.setProperty("font-weight", "normal", "important");
            
            var newLinks = activeLine.querySelectorAll("a");
            for(var n=0; n<newLinks.length; n++) {
                newLinks[n].style.setProperty("color", "red", "important");
                newLinks[n].style.setProperty("text-decoration", "none", "important");
            }

            if(listContainer.offsetParent !== null){
                var containerRect = listContainer.getBoundingClientRect();
                var activeRect = activeLine.getBoundingClientRect();
                var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (activeLine.clientHeight / 2);
                listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
            }
        }
      });

      return true;
    }

    var checks = 0;
    var checkTimer = setInterval(function(){
      protectVideo();
      var success = initSubtitles();
      checks++;
      if (success || checks > 20) { 
        clearInterval(checkTimer);
      }
    }, 500); 

    if (!window.scStopAndGo) {
      window.scStopAndGo = function(event, link){
        try{
          var mediaEls = document.querySelectorAll('video, audio');
          mediaEls.forEach(function(m){
            try{
              if (!m.paused) m.pause();
              if (document.pictureInPictureElement === m && document.exitPictureInPicture) {
                document.exitPictureInPicture().catch(function(){});
              }
            }catch(e){}
          });
        }finally{
          event.preventDefault();
          setTimeout(function(){
            if (link.target === '_blank') {
              window.open(link.href, '_blank');
            } else {
              window.location.href = link.href;
            }
          }, 50);
        }
        return false;
      };
    }
  })();
  </script>
</div>



<h2 class="wp-block-heading"><strong>&#x1f4a1; OBSでリアルタイム配信に使いたい方へ</strong></h2>



<p class="wp-block-paragraph">このパペットシステムは、OBS Studioを使ってリアルタイム配信などの画面に合成することも可能です。</p>



<p class="wp-block-paragraph">ウィンドウキャプチャでパペットの画面を取り込み、背景（グリーンバック等）を透過させればOKです。</p>



<p class="wp-block-paragraph"><strong>【ワンポイントアドバイス：音ズレの直し方】</strong></p>



<p class="wp-block-paragraph">映像の処理には少し時間がかかるため、OBS上で「声（マイク）」に対して「パペットの口の動き（映像）」がわずかに遅れて見えることがあります。</p>



<p class="wp-block-paragraph">その場合は、OBSの「オーディオの詳細プロパティ」から、<strong>マイクの「同期オフセット」を「200ms〜500ms」ほどプラス</strong>に設定して、声をわざと遅らせて映像に合わせると自然になります。私は今500msに設定しています。</p>



<figure class="wp-block-image size-large"><a href="https://imakat.com/rd.php?id=Avm1FlzY.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=Avm1FlzY.png" alt=""/></a></figure>



<h2 class="wp-block-heading"><strong>おわりに</strong></h2>



<p class="wp-block-paragraph">自分が描いたイラストが、自分の動きに合わせて滑らかに動く体験は、何度やっても感動します。それではご自由に利用ください。</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">28865</post-id>	</item>
		<item>
		<title>自作パペット（アバター）を作ってみました〜改良前〜脱Adobeを目指して！</title>
		<link>https://imakat.com/2026/03/12/28692/</link>
		
		<dc:creator><![CDATA[imakat]]></dc:creator>
		<pubDate>Thu, 12 Mar 2026 02:19:50 +0000</pubDate>
				<category><![CDATA[デジタル]]></category>
		<category><![CDATA[ものづくり]]></category>
		<category><![CDATA[Gemini]]></category>
		<category><![CDATA[Adobe character animator]]></category>
		<category><![CDATA[パペット]]></category>
		<category><![CDATA[Automator]]></category>
		<guid isPermaLink="false">https://imakat.com/?p=28692</guid>

					<description><![CDATA[今回は、これからの動画作成で活躍してくれる**「新しく作った自作のパペット（アバター）」**について紹介したいと思います。これまで私の動画には、画面の左下に「Adobe Dr. Apple Smith」というキャラクター [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">今回は、これからの動画作成で活躍してくれる**「新しく作った自作のパペット（アバター）」**について紹介したいと思います。<br>これまで私の動画には、画面の左下に「Adobe Dr. Apple Smith」というキャラクターが頻繁に登場していました。顔の向きに合わせて首が動き、目や口もスムーズに動く非常に素晴らしいパペットだったのですが……実はそろそろ、彼から「卒業」をしたいと思います。</p>



<p class="wp-block-paragraph">動画をご覧ください。</p>


<div class="sc-dynamic-embed">
  <style>
  /* リンクの見た目を整える */
  .sc-dynamic-embed .sc-link-container { 
      display: flex; 
      margin-bottom: 10px; 
      flex-wrap: wrap; 
      align-items: center; 
  }
  .sc-dynamic-embed .sc-link { margin-bottom: 0; }
  .sc-dynamic-embed .sc-link a {
    font-size: 15px; 
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  @media (max-width: 500px) {
    .sc-dynamic-embed .sc-link a { font-size: 13px; }
  }

  .sc-dynamic-embed .imk-line {
      display: inline-block;
      width: 100%;
      border-radius: 2px;
      transition: background-color 0.1s;
  }

  .sc-dynamic-embed #subtitleOverlay,
  .sc-dynamic-embed #scSubtitleOverlay,
  .sc-dynamic-embed .overlay-cue,
  .sc-dynamic-embed .band {
      display: none !important;
      opacity: 0 !important;
      visibility: hidden !important;
      pointer-events: none !important;
  }
  </style>

  <div class="sc-link-container">
    <p class="sc-link">
      <a href="https://imakat.com/ds62/?drid=74" target="_blank"
         onclick="return scStopAndGo(event, this);">
        👉低画質・枠外字幕はこちら
      </a>
    </p>
  </div>

  <style>
            :root{ --dr5emd-max: 1920px; }
            #subtitleOverlay, #scSubtitleOverlay, .overlay-cue, .band { display: none !important; opacity: 0 !important; }
            .imk-line { display: inline-block; width: 100%; border-radius: 2px; transition: background-color 0.1s; }
            .dr5emd-sublist details > p{ height:200px; overflow:auto; background-color:#EDF7FF; padding:2px 6px; margin:0; box-shadow:3px 3px 4px black; position: relative; }
            .dr5emd-sublist details > summary{ padding:2px 6px; width:100%; background-color:#ddd; border:none; box-shadow:3px 3px 4px black; cursor:pointer; list-style:none; }
            
                .video-wrap{position:relative;width:100%;margin:0 auto}
                #myVideo{width:100%;height:auto;min-height:200px;display:block;background:#000;}</style><div class="dr5emd-container"><div class="video-wrap"><video id="myVideo" controls poster="https://imakat.com/rd.php?id=sNA7JRyk.png" playsinline preload="none" style="width:100%;height:auto;">  <source src="https://imakat.com/rd.php?id=uqGIUvdl.mp4" type="video/mp4">  <track src="https://imakat.com/rd.php?id=Ag8ayOZd.vtt" label="日本語" srclang="ja" kind="subtitles"></video></div><div class="dr5emd-sublist"><details translate="yes"><summary translate="yes">字幕一覧(クリック)</summary> <p translate="yes">
(<a href="#" class="imk-cue" data-seek="0:06" translate="no">00:00:06</a>)  それでは今回ですね、新しく作った自作のパペットを紹介していこうと思うんですけども<br>
(<a href="#" class="imk-cue" data-seek="0:16" translate="no">00:00:16</a>)  私今までですね、動画を作る時に頻繁に登場してたのが、この左端にいますですね<br>
(<a href="#" class="imk-cue" data-seek="0:27" translate="no">00:00:27</a>)  Adobe Dr. Apple SmithというAdobeのキャラクターです。パペットです。<br>
(<a href="#" class="imk-cue" data-seek="0:37" translate="no">00:00:37</a>)  で、これものすごく素晴らしいんですよね。顔の向きに応じて、首もゆっくり動きますし<br>
(<a href="#" class="imk-cue" data-seek="0:48" translate="no">00:00:48</a>)  口も目も非常にスムーズに動くという優れものなんですけども<br>
(<a href="#" class="imk-cue" data-seek="0:54" translate="no">00:00:54</a>)  ただ問題がありまして、それはこのAdobeのですね、サブスクに入らないと使えないんですよ。<br>
(<a href="#" class="imk-cue" data-seek="1:05" translate="no">00:01:05</a>)  これがですね、一番安い組み合わせでもってしても月1200円。<br>
(<a href="#" class="imk-cue" data-seek="1:15" translate="no">00:01:15</a>)  それはなかなか今のご時世、このキャラクター使うだけで<br>
(<a href="#" class="imk-cue" data-seek="1:23" translate="no">00:01:23</a>)  で、その他のAdobeのサービスというのはですね、画像加工したり色々面白みはあるんですけども<br>
(<a href="#" class="imk-cue" data-seek="1:33" translate="no">00:01:33</a>)  今や生成AIを使うとほとんど似たようなことができるんですね。<br>
(<a href="#" class="imk-cue" data-seek="1:41" translate="no">00:01:41</a>)  だからもう生成AIがあれば、メディアの加工もできるし、プログラム作成もできますしね。<br>
(<a href="#" class="imk-cue" data-seek="1:51" translate="no">00:01:51</a>)  色んなことが可能なんです。だからそれは非常にもったいない。<br>
(<a href="#" class="imk-cue" data-seek="1:58" translate="no">00:01:58</a>)  だからできればこのAdobeのサービスを停止して<br>
(<a href="#" class="imk-cue" data-seek="2:07" translate="no">00:02:07</a>)  もう自前で作ったこのパペットですね。Adobeと比べれば見劣りするんですけどもね。<br>
(<a href="#" class="imk-cue" data-seek="2:16" translate="no">00:02:16</a>)  まあそれでもこのように目も動きますし、口も動くしで、首も多少動く。<br>
(<a href="#" class="imk-cue" data-seek="2:23" translate="no">00:02:23</a>)  まあそんな形でですね、使い物にはなんとかなってるかなと思うんですよ。ここは割り切りですね。<br>
(<a href="#" class="imk-cue" data-seek="2:32" translate="no">00:02:32</a>)  ええまあ、この自前のパペットでですね、これからやっていこうと思ってます。<br>
(<a href="#" class="imk-cue" data-seek="2:39" translate="no">00:02:39</a>)  ええと、それではですね、今回作ったお手製のパペットですね、を紹介していきたいと思います。<br>
(<a href="#" class="imk-cue" data-seek="2:49" translate="no">00:02:49</a>)  まだ名前はないんですが、まあimakatブログで使っていこうと思うキャラクターですね。<br>
(<a href="#" class="imk-cue" data-seek="2:59" translate="no">00:02:59</a>)  いまかっちゃん、変だね。なんだろうね。なんかいい名前があるといいんですけどね。<br>
(<a href="#" class="imk-cue" data-seek="3:11" translate="no">00:03:11</a>)  まあ、とにかくですね、今から紹介していきたいと思います。<br>
(<a href="#" class="imk-cue" data-seek="3:16" translate="no">00:03:16</a>)  で、基本的には作るのはですね、Google Geminiですね。<br>
(<a href="#" class="imk-cue" data-seek="3:25" translate="no">00:03:25</a>)  Google Geminiを使ってですね、Geminiにプログラムを書いてもらうと。<br>
(<a href="#" class="imk-cue" data-seek="3:34" translate="no">00:03:34</a>)  いうことをして進めます。これが非常に賢いんでね。<br>
(<a href="#" class="imk-cue" data-seek="3:41" translate="no">00:03:41</a>)  こちらがその日本語で質問していけば、どんどん作ってくれるという代物でございます。<br>
(<a href="#" class="imk-cue" data-seek="3:49" translate="no">00:03:49</a>)  で、それに従ってですね、あのMacの中にフォルダを用意します。<br>
(<a href="#" class="imk-cue" data-seek="3:58" translate="no">00:03:58</a>)  フォルダとファイルを用意するということが必要になります。<br>
(<a href="#" class="imk-cue" data-seek="4:03" translate="no">00:04:03</a>)  mypuppet_systemっていうのを作ってですね、その中にavatar_module<br>
(<a href="#" class="imk-cue" data-seek="4:13" translate="no">00:04:13</a>)  その中にrun_puppet.py、これが動かすためのPythonプログラムです。<br>
(<a href="#" class="imk-cue" data-seek="4:20" translate="no">00:04:20</a>)  で、assets、これが動かす対象となる画像ですね、それが入ってます。<br>
(<a href="#" class="imk-cue" data-seek="4:30" translate="no">00:04:30</a>)  あとconfigのjsonが入ってます。assetsを開くと<br>
(<a href="#" class="imk-cue" data-seek="4:37" translate="no">00:04:37</a>)  目の動き用、口の動き用、体ですね、それとあと頭。<br>
(<a href="#" class="imk-cue" data-seek="4:49" translate="no">00:04:49</a>)  そういう形でですね、パーツごとに分けて作っていきます。<br>
(<a href="#" class="imk-cue" data-seek="4:55" translate="no">00:04:55</a>)  例えば目一つ見てみましょうか。ちょっと小さいですけどもね。<br>
(<a href="#" class="imk-cue" data-seek="5:02" translate="no">00:05:02</a>)  これはeye_up.png、上目遣いの目だけです。<br>
(<a href="#" class="imk-cue" data-seek="5:13" translate="no">00:05:13</a>)  こういうふうに作りますね。で、作ってもらったプログラムをですね、run_puppet.py<br>
(<a href="#" class="imk-cue" data-seek="5:22" translate="no">00:05:22</a>)  先ほどもちょっと出てきましたけども、そういう形で書き込みます。<br>
(<a href="#" class="imk-cue" data-seek="5:29" translate="no">00:05:29</a>)  で、それをですね、ターミナルですね、それをターミナルで実行するという形をとってます。<br>
(<a href="#" class="imk-cue" data-seek="5:43" translate="no">00:05:43</a>)  なかなか素晴らしい出来でして、ちょっと頭の動きが<br>
(<a href="#" class="imk-cue" data-seek="5:49" translate="no">00:05:49</a>)  少し動いたり動かなかったりってこともあるんですが、まあ大体問題なく動いてくれてると。<br>
(<a href="#" class="imk-cue" data-seek="5:59" translate="no">00:05:59</a>)  少し動き出すと、少し不安定な動きになるっていうのが今の課題です。<br>
(<a href="#" class="imk-cue" data-seek="6:07" translate="no">00:06:07</a>)  ええ、そんなところでですね、作り上げたパペットです。<br>
(<a href="#" class="imk-cue" data-seek="6:12" translate="no">00:06:12</a>)  まあいろんな形で使っていこうと思っております。<br>
(<a href="#" class="imk-cue" data-seek="6:18" translate="no">00:06:18</a>)  ええと、それではですね、まあ次にこのさっき作ったパペットですけれども<br>
(<a href="#" class="imk-cue" data-seek="6:29" translate="no">00:06:29</a>)  まあ実際に今このように動いてますが、これあのターミナルから起動するというのは<br>
(<a href="#" class="imk-cue" data-seek="6:38" translate="no">00:06:38</a>)  結構慣れないと面倒くさい話なんで、ちょっとやってみますとね。<br>
(<a href="#" class="imk-cue" data-seek="6:46" translate="no">00:06:46</a>)  こういうコマンドをですね、打ち込むんです。で、立ち上げると。<br>
(<a href="#" class="imk-cue" data-seek="6:56" translate="no">00:06:56</a>)  まあこんなような形で立ち上がって、それを使うという形になるわけですね。<br>
(<a href="#" class="imk-cue" data-seek="7:05" translate="no">00:07:05</a>)  これ今私が話してる声で連動してます。<br>
(<a href="#" class="imk-cue" data-seek="7:13" translate="no">00:07:13</a>)  まあところがこれは非常に難しい、厄介なんでですね、これは使いたくないわけですよ、みんな。<br>
(<a href="#" class="imk-cue" data-seek="7:22" translate="no">00:07:22</a>)  で、どういう方法をとるかというと、AppleのAutomatorというものを使ってですね<br>
(<a href="#" class="imk-cue" data-seek="7:30" translate="no">00:07:30</a>)  まあ簡単なプログラムを書き込むというふうなですね、作業をします。<br>
(<a href="#" class="imk-cue" data-seek="7:40" translate="no">00:07:40</a>)  こういうものですね。MacのAutomatorを立ち上げてですね<br>
(<a href="#" class="imk-cue" data-seek="7:48" translate="no">00:07:48</a>)  で、そこでシェルスクリプトを実行ってものを選択して、ここに収めます。<br>
(<a href="#" class="imk-cue" data-seek="7:57" translate="no">00:07:57</a>)  で、それでとっても短いプログラムですけども、こういうプログラムを書きます。<br>
(<a href="#" class="imk-cue" data-seek="8:05" translate="no">00:08:05</a>)  実はこれさっきですね、ターミナルに打ち込んだコマンドと全く同じなんですね。<br>
(<a href="#" class="imk-cue" data-seek="8:13" translate="no">00:08:13</a>)  それをここに書き込んで、アプリケーションとして登録するということをやります。<br>
(<a href="#" class="imk-cue" data-seek="8:23" translate="no">00:08:23</a>)  そうしますと、まあこういう、自作パペット起動.app、ってものができます。<br>
(<a href="#" class="imk-cue" data-seek="8:30" translate="no">00:08:30</a>)  で、この状態でですね、これをクリックします。<br>
(<a href="#" class="imk-cue" data-seek="8:37" translate="no">00:08:37</a>)  そうすると、実はここから立ち上がることができます。<br>
(<a href="#" class="imk-cue" data-seek="8:48" translate="no">00:08:48</a>)  この、自作パペット起動.app、をクリックして立ち上がった画面がこれになります。<br>
(<a href="#" class="imk-cue" data-seek="8:56" translate="no">00:08:56</a>)  このような方法でですね、アプリ化して起動させるというのが非常に楽な使い方になります。<br>
(<a href="#" class="imk-cue" data-seek="9:05" translate="no">00:09:05</a>)  以上、補足でした。<br>
</p> </details>
<style>
details { font: 16px "Open Sans", Calibri, sans-serif; width: 100%; }
details > summary { padding: 2px 6px; width: 100%; background-color: #ddd; border: none; box-shadow: 3px 3px 4px black; cursor: pointer; list-style: none; }
details > p { font: 14px "Open Sans", Calibri, sans-serif; height:150px; overflow: scroll; background-color: #EDF7FF; padding: 2px 6px; margin: 0; box-shadow: 3px 3px 4px black; }
</style>
</div></div>            <script>
            document.addEventListener("DOMContentLoaded", function(){
                var video = document.getElementById("myVideo");
                if(!video) return;

                            });
            </script>
            

  <script>
  (function(){
    var me = document.currentScript;
    var wrapper = me ? me.closest('.sc-dynamic-embed') : null;

    function protectVideo() {
      var target = wrapper ? wrapper : document;
      var mediaEls = target.querySelectorAll('video, audio');
      mediaEls.forEach(function(v){
        if(v.dataset.protected === 'true') return;
        v.dataset.protected = 'true';
        v.setAttribute('controlsList', 'nodownload');
        v.oncontextmenu = function() { return false; };
        v.addEventListener('contextmenu', function(e){ e.preventDefault(); return false; }, false);
      });
    }

    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      var video = target.querySelector('video, audio');
      var listContainer = target.querySelector('details > p');
      
      if (!video) return false; 
      
      if (video.dataset.subInit === 'true') return true; 
      video.dataset.subInit = 'true';

      var oldOverlay = target.querySelector('#subtitleOverlay') || target.querySelector('#scSubtitleOverlay');
      if (oldOverlay) {
          oldOverlay.style.setProperty('display', 'none', 'important');
          oldOverlay.innerHTML = ''; 
      }

      function isSpecialMode() {
        var isFs = !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement);
        var isPiP = !!(document.pictureInPictureElement && document.pictureInPictureElement === video) || (video.webkitPresentationMode === "picture-in-picture");
        var isIOSFs = !!video.webkitDisplayingFullscreen; 
        return isFs || isPiP || isIOSFs;
      }

      // 初期状態のセット（リストがなければ最初から showing に）
      try {
        if(video.textTracks && video.textTracks.length > 0){
          for(var i=0; i<video.textTracks.length; i++){
             if(video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions'){
                 video.textTracks[i].mode = (!listContainer) ? "showing" : "hidden";
             }
          }
        }
      } catch(e){}

      // 字幕一覧が存在する場合のみ、リストのフォーマット処理を行う
      if (listContainer) {
          var detailsEl = target.querySelector("details");
          if (detailsEl) {
              detailsEl.open = true; 
              var summaryEl = detailsEl.querySelector("summary");
              if (summaryEl) summaryEl.textContent = "字幕(シーン)はここをクリック";
          }

          if (!listContainer.dataset.formatted) {
              var html = listContainer.innerHTML;
              var lines = html.split(/<br\s*\/?>/i);
              var newHtml = "";
              for(var j=0; j<lines.length; j++) {
                  if(lines[j].trim() === "") continue;
                  newHtml += "<span class='imk-line'>" + lines[j] + "</span><br>";
              }
              listContainer.innerHTML = newHtml;
              listContainer.dataset.formatted = "true";
          }

          var rootSublist = target.querySelector(".dr5-sublist") || listContainer.parentElement;
          if (rootSublist) {
            rootSublist.addEventListener("click", function(e){
              var a = e.target.closest && e.target.closest("a.imk-cue[data-seek]");
              if(!a) return;
              e.preventDefault();
              var ts = a.getAttribute("data-seek");
              if(!ts) return;
              var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
              var sec = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
              if(sec==null) return;
              try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
            });
          }
      }

      // ★ dr52.php と全く同じ「常時監視」のロジック
      // これにより、Safariが読み込み遅延を起こしても確実にONになります
      video.addEventListener("timeupdate", function(){
        var hasList = (listContainer !== null);
        var desiredMode = (isSpecialMode() || !hasList) ? "showing" : "hidden";
        
        try {
            if(video.textTracks && video.textTracks.length > 0){
                for(var i=0; i<video.textTracks.length; i++){
                    if((video.textTracks[i].kind === 'subtitles' || video.textTracks[i].kind === 'captions') && video.textTracks[i].mode !== desiredMode) {
                        video.textTracks[i].mode = desiredMode;
                    }
                }
            }
        } catch(e){}

        // リストがない場合はこれ以降のハイライト処理をスキップ
        if (!hasList) return;

        var cues = listContainer.querySelectorAll("a.imk-cue");
        if(cues.length === 0) return;
        var cur = video.currentTime;
        var activeA = null;

        for(var i=0; i<cues.length; i++){
            var ts = cues[i].getAttribute("data-seek");
            if(!ts) continue;
            var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
            var t = (p.length===2) ? p[0]*60+p[1] : (p.length===3 ? p[0]*3600+p[1]*60+p[2] : null);
            if(t !== null && cur >= t - 0.5){ activeA = cues[i]; } 
            else if(t > cur){ break; }
        }

        if(activeA){
            var activeLine = activeA.closest(".imk-line");
            if(!activeLine) activeLine = activeA;

            if(activeLine.classList.contains("active-hl")) return;

            var allLines = listContainer.querySelectorAll(".imk-line");
            for(var k=0; k<allLines.length; k++) {
                allLines[k].classList.remove("active-hl");
                allLines[k].removeAttribute("style"); 
            }
            var allLinks = listContainer.querySelectorAll("a");
            for(var m=0; m<allLinks.length; m++) {
                allLinks[m].classList.remove("active-hl");
                allLinks[m].removeAttribute("style"); 
            }

            activeLine.classList.add("active-hl");
            activeLine.style.setProperty("background-color", "#ffff00", "important");
            activeLine.style.setProperty("color", "red", "important");
            activeLine.style.setProperty("font-weight", "normal", "important");
            
            var newLinks = activeLine.querySelectorAll("a");
            for(var n=0; n<newLinks.length; n++) {
                newLinks[n].style.setProperty("color", "red", "important");
                newLinks[n].style.setProperty("text-decoration", "none", "important");
            }

            if(listContainer.offsetParent !== null){
                var containerRect = listContainer.getBoundingClientRect();
                var activeRect = activeLine.getBoundingClientRect();
                var targetScroll = listContainer.scrollTop + (activeRect.top - containerRect.top) - (listContainer.clientHeight / 2) + (activeLine.clientHeight / 2);
                listContainer.scrollTo({ top: targetScroll, behavior: "smooth" });
            }
        }
      });

      return true;
    }

    var checks = 0;
    var checkTimer = setInterval(function(){
      protectVideo();
      var success = initSubtitles();
      checks++;
      if (success || checks > 20) { 
        clearInterval(checkTimer);
      }
    }, 500); 

    if (!window.scStopAndGo) {
      window.scStopAndGo = function(event, link){
        try{
          var mediaEls = document.querySelectorAll('video, audio');
          mediaEls.forEach(function(m){
            try{
              if (!m.paused) m.pause();
              if (document.pictureInPictureElement === m && document.exitPictureInPicture) {
                document.exitPictureInPicture().catch(function(){});
              }
            }catch(e){}
          });
        }finally{
          event.preventDefault();
          setTimeout(function(){
            if (link.target === '_blank') {
              window.open(link.href, '_blank');
            } else {
              window.location.href = link.href;
            }
          }, 50);
        }
        return false;
      };
    }
  })();
  </script>
</div>



<div class="wp-block-cocoon-blocks-toggle-box-1 toggle-wrap toggle-box block-box not-nested-style cocoon-block-toggle"><input id="toggle-checkbox-202604180750240" class="toggle-checkbox" type="checkbox"/><label class="toggle-button" for="toggle-checkbox-202604180750240"><strong><span class="marker">コードと要約</span><span class="marker">(クリック)</span></strong></label><div class="toggle-content">
<figure class="wp-block-flexible-table-block-table"><table class="has-fixed-layout"><tbody><tr><td>自作パペット_py.pub.txt<br>要約：<br>このシステムは、顔認識と音声入力を利用してリアルタイムで動作するデスクトップパペットを実現します。<br><code>run_ui.py</code>は、パペットの各種設定を行うGUIアプリケーションです。キャラクターの新規作成、複製、選択、そしてボリューム閾値、グローバルスケール、顔の傾き制限、目の感度、カメラ/マイクIDといったパラメータ調整機能を提供します。これらの設定はキャラクターごとにJSONファイルとして保存されます。<br><code>run_puppet.py</code>は、UIで選択・設定されたキャラクターとパラメータに基づき、実際のパペット動作を制御するスクリプトです。OpenCVとMediaPipe Face Meshを用いてカメラ映像から顔の傾き、目の動き、口の形を検出し、マイクからの音声ボリュームと連携させてアバターの頭の回転、視線、口の動きをリアルタイムで再現します。キャリブレーションデータもキャラクターごとに保存されます。<br>Automatorスクリプトは、これらのPythonスクリプトの実行を補助します。「自作パペット起動.app」は設定UIを立ち上げ、「パペット書き出し起動.app」はPixelmator Proで開いているドキュメントの各レイヤーをPNG画像として書き出し、キャラクターごとの設定JSONを自動生成した後、該当するパペットを起動する一連の処理を行います。これにより、Pixelmator Proでの画像編集からパペット起動までがスムーズに連携されます。</td></tr><tr><td><a href="https://imakat.com/script_list/?pubtxt=自作パペット_py_pub.txt" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=zrU95MiY.png" alt="" style="width:120px; height:auto;"></a></td></tr><tr><td>公開スクリプトに関するお問い合わせは以下へ↓</td></tr><tr><td><a rel="noopener" target="_blank" href="https://gemini.google.com/gem/1Dp-NLSA5j5OXE3B1Ki2IaBRCvq4CGa6t?usp=sharing"><img decoding="async" src="https://imakat.com/rd.php?id=s7BMZHhB.png" alt="" style="width:120px; height:auto;"></a></td></tr></tbody></table></figure>
</div></div>



<h4 class="wp-block-heading"><strong>なぜパペットを自作しようと思ったのか？</strong></h4>



<p class="wp-block-paragraph">最大の理由は**「コスト」**です。<br>Adobeの素晴らしいパペットを使うためには、当然ながらAdobeのサブスクリプションに加入する必要があります。一番安いプランの組み合わせでも、月額1,200円ほどかかってしまいます。<br>「このキャラクターを使うためだけに、毎月課金し続けるのはどうなんだろう？」と悩んでいました。今は生成AI（画像生成AIやテキスト生成AI）がこれだけ発達し、メディアの加工やプログラムの作成まで何でもできる時代です。「それなら、AIの力を借りて自分で作ってしまおう！」と思い立ったのがきっかけです。</p>



<h4 class="wp-block-heading"><strong>新キャラクター「いまかっちゃん（仮）？」</strong></h4>



<p class="wp-block-paragraph">というわけで、完全自前で作り上げたのがこちらのパペットです。（※名前は暫定で「いまかっちゃん」と思いつきましたが、ちょっと変な感じもしています。）<br>Adobeのパペットと比べてしまうと多少見劣りする部分はありますが、動画用としては十分な機能を持っています。<br><strong>音声連動：</strong> 私が話す声に連動して口がパクパクと動きます。<br><strong>目の動き：</strong> 上目遣いなど、視線も動きます。<br><strong>首の動き：</strong> 多少ですが顔の向きも変わります。（※現状、少し不安定な動きになることがあり、今後の課題です）<br>動画を作る上での「使い物」にはなんとか仕上がったかなと、個人的には割り切って満足しています。</p>



<h4 class="wp-block-heading"><strong>Google Geminiに丸投げ！？</strong></h4>



<p class="wp-block-paragraph">「どうやって作ったの？」と疑問に思うかもしれませんが、実はプログラミングの大部分は**AI（Google Gemini）**にお願いしました。<br><strong>Geminiに質問する：</strong> 日本語で「こういう動きをするプログラムを書いて」と質問し、Pythonのコードを書いてもらいます。Geminiは非常に賢く、どんどんコードを生成してくれました。<br><strong>パーツ画像の用意：</strong> 目（上・下・右・左）、口（開・閉）、体、頭など、パーツごとに細かく分けた画像（PNG形式）を用意します。<br><strong>フォルダ構成：</strong> Macの中に専用フォルダ（mypuppet_systemなど）を作り、Pythonの実行ファイル（run_puppet.py）と、先ほどの画像パーツ群（assetsフォルダ）を格納して連動させました。</p>



<h4 class="wp-block-heading"><strong>Mac「Automator」で起動を劇的にラクにする方法</strong></h4>



<p class="wp-block-paragraph">自作プログラムの弱点として、「毎回ターミナル（黒い画面）を開いてコマンドを打ち込まないと起動しない」という厄介な問題がありました。これでは面倒ですよね。<br>そこで、Mac標準アプリの**「Automator」**を使って、ワンクリックで起動できるように一工夫しました。<br><strong>手順：</strong> Automatorを立ち上げ、「シェルスクリプトを実行」を選択。そこにターミナルで打ち込んでいた短いコマンドをコピペするだけ。<br><strong>アプリ化：</strong> これをアプリケーションとして保存すれば、**「自作パペット起動.app」**の完成です！<br>これからは、このアプリアイコンをダブルクリックするだけで、サクッとパペットを呼び出せるようになりました。</p>



<h4 class="wp-block-heading">OBSへのパペット設定</h4>



<p class="wp-block-paragraph">OBSへのパペットの組み込みですが、OBSのソース→ウインドウキャプチャ、この中から、パペットのあるウインドウを選択します。</p>



<figure class="wp-block-image size-large"><a href="https://imakat.com/rd.php?id=PeocProJ.png" target="_blank"><img decoding="async" src="https://imakat.com/rd.php?id=PeocProJ.png" alt=""/></a></figure>



<p class="wp-block-paragraph">STREAM DECKがあると便利です。マルチアクションにて、OBS.app→自作パペット起動.app、と設定すればラクです。</p>



<h4 class="wp-block-heading">さてと。。</h4>



<p class="wp-block-paragraph">その後の改善として、Pixelmator Proとの連携を作っています。形になったら紹介します。<br>生成AIを活用すれば、プログラミングの深い知識がなくても、日常の「ちょっと不便」「コストを削りたい」を解決できるツールが作れてしまいますよね。便利な時代になりました。<br><br></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">28692</post-id>	</item>
	</channel>
</rss>
