<?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>Adobeサブスク | imakat.com</title>
	<atom:link href="https://imakat.com/tag/adobe%E3%82%B5%E3%83%96%E3%82%B9%E3%82%AF/feed/" rel="self" type="application/rss+xml" />
	<link>https://imakat.com</link>
	<description>工夫と改善で人生をちょっと豊かに</description>
	<lastBuildDate>Tue, 12 May 2026 23:47:14 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</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>Adobeサブスク | 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>【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></p>



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



<p>今回は<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; /* dynamicと合わせた基本サイズ */
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  /* ★スマホ画面（幅500px以下）の時は文字を縮小して統一感を出す */
  @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="metadata" 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" default></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;

    /* -----------------------------------------------
       1. 動画・音声の保護機能（右クリック禁止・DL防止）
       ----------------------------------------------- */
    function protectVideo() {
      var target = wrapper ? wrapper : document;
      // ★修正箇所：videoだけでなくaudioも保護の対象に含めました
      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);
      });
    }

    /* -----------------------------------------------
       2. 字幕制御＆ハイライト機能
       ----------------------------------------------- */
    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      // ★修正箇所：videoだけでなくaudioも取得できるようにしました
      var video = target.querySelector('video, audio');
      var listContainer = target.querySelector('details > p');
      
      if (!video || !listContainer) 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;
      }

      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 = "hidden";
             }
          }
        }
      } catch(e){}

      video.addEventListener("webkitbeginfullscreen", function() {
          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 = "showing";
                  }
              }
          } catch(e){}
      });
      video.addEventListener("webkitendfullscreen", function() {
          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 = "hidden";
                  }
              }
          } catch(e){}
      });

      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";
      }

      function parseTs(ts){
        if(!ts) return null;
        var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
        if(p.length===2) return p[0]*60 + p[1];
        if(p.length===3) return p[0]*3600 + p[1]*60 + p[2];
        return null;
      }

      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 sec = parseTs(a.getAttribute("data-seek"));
          if(sec==null) return;
          try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
        });
      }

      video.addEventListener("timeupdate", function(){
        var desiredMode = isSpecialMode() ? "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){}

        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 t = parseTs(cues[i].getAttribute("data-seek"));
            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); 

    /* -----------------------------------------------
       3. 画面遷移時の停止機能
       ----------------------------------------------- */
    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>高価なトラッキング機材は不要です。Macの内蔵カメラ（またはWebカメラ）があなたの顔の傾きを認識し、マイクが声の大きさを拾って、パペットがリアルタイムに連動します。</p>



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



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



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



<p>「マイクの感度」「パペットの大きさ」「顔の傾き具合」などを、数値で直感的に微調整できます。自分好みのセッティングを見つけたら、キャラクターごとに保存しておくことが可能です。</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>使っている途中で「ちょっと顔の向きがズレてきたな…」と思ったら、<strong>スペースキーをポンッと押すだけ</strong>。その瞬間のあなたの顔の位置を「真正面」として再設定（キャリブレーション）します。</p>



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



<p>以下のリンクから、一式がまとまった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>使うためには、お使いの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><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>今回お配りしたフォルダの中には、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>Macの画像編集ソフト「<strong>Pixelmator Pro</strong>」をお持ちの方は、このファイルを開いて自分の好きな絵に描き換えるだけで、<strong>完全オリジナルの自作パペット</strong>を作ることができます！</p>



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



<p>コードや詳しい仕組みに興味がある方は、こちらのページにスクリプトを公開していますので、ぜひ覗いてみてください。</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-202605130844340" class="toggle-checkbox" type="checkbox"/><label class="toggle-button" for="toggle-checkbox-202605130844340"><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></p>



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



<p></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; /* dynamicと合わせた基本サイズ */
    font-weight: normal;
    text-decoration: underline;
    color: #0073aa;
  }
  .sc-dynamic-embed .sc-link a:hover { text-decoration: none; color: #000; }
  
  /* ★スマホ画面（幅500px以下）の時は文字を縮小して統一感を出す */
  @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="metadata" 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" default></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;

    /* -----------------------------------------------
       1. 動画・音声の保護機能（右クリック禁止・DL防止）
       ----------------------------------------------- */
    function protectVideo() {
      var target = wrapper ? wrapper : document;
      // ★修正箇所：videoだけでなくaudioも保護の対象に含めました
      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);
      });
    }

    /* -----------------------------------------------
       2. 字幕制御＆ハイライト機能
       ----------------------------------------------- */
    function initSubtitles() {
      var target = wrapper ? wrapper : document;
      // ★修正箇所：videoだけでなくaudioも取得できるようにしました
      var video = target.querySelector('video, audio');
      var listContainer = target.querySelector('details > p');
      
      if (!video || !listContainer) 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;
      }

      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 = "hidden";
             }
          }
        }
      } catch(e){}

      video.addEventListener("webkitbeginfullscreen", function() {
          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 = "showing";
                  }
              }
          } catch(e){}
      });
      video.addEventListener("webkitendfullscreen", function() {
          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 = "hidden";
                  }
              }
          } catch(e){}
      });

      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";
      }

      function parseTs(ts){
        if(!ts) return null;
        var p = ts.trim().split(":").map(function(x){return parseInt(x,10)||0;});
        if(p.length===2) return p[0]*60 + p[1];
        if(p.length===3) return p[0]*3600 + p[1]*60 + p[2];
        return null;
      }

      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 sec = parseTs(a.getAttribute("data-seek"));
          if(sec==null) return;
          try{ video.currentTime = sec; if(video.paused) video.play(); }catch(_){}
        });
      }

      video.addEventListener("timeupdate", function(){
        var desiredMode = isSpecialMode() ? "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){}

        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 t = parseTs(cues[i].getAttribute("data-seek"));
            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); 

    /* -----------------------------------------------
       3. 画面遷移時の停止機能
       ----------------------------------------------- */
    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>このパペットシステムは、OBS Studioを使ってリアルタイム配信などの画面に合成することも可能です。</p>



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



<p><strong>【ワンポイントアドバイス：音ズレの直し方】</strong></p>



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



<p>その場合は、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>自分が描いたイラストが、自分の動きに合わせて滑らかに動く体験は、何度やっても感動します。それではご自由に利用ください。</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">28865</post-id>	</item>
	</channel>
</rss>
