E-book

<!DOCTYPE html>
<html lang="th">
<head>
<!-- Playables SDK -->
<script>// Playables SDK v1.0.0
// Game lifecycle bridge: rAF-based game-ready detection + event communication
(function() {
  'use strict';

  // Idempotency: skip if already initialized (e.g., server-side injection
  // followed by client-side inject-javascript via the Bloks webview component).
  if (window.playablesSDK) return;

  var HANDLER_NAME = 'playablesGameEventHandler';
  var ANDROID_BRIDGE_NAME = '_MetaPlayablesBridge';
  var RAF_FRAME_THRESHOLD = 3;

  var gameReadySent = false;
  var firstInteractionSent = false;
  var errorSent = false;
  var frameCount = 0;
  var originalRAF = window.requestAnimationFrame;

  // --- Transport Layer ---

  function hasIOSBridge() {
    return !!(window.webkit &&
              window.webkit.messageHandlers &&
              window.webkit.messageHandlers[HANDLER_NAME]);
  }

  function hasAndroidBridge() {
    return !!(window[ANDROID_BRIDGE_NAME] &&
              typeof window[ANDROID_BRIDGE_NAME].postEvent === 'function');
  }

  function isInIframe() {
    return !!(window.parent && window.parent !== window);
  }

  function sendEvent(eventName, payload) {
    var message = {
      type: eventName,
      payload: payload || {},
      timestamp: Date.now()
    };

    if (hasIOSBridge()) {
      try {
        window.webkit.messageHandlers[HANDLER_NAME].postMessage(message);
      } catch (e) { /* ignore */ }
      return;
    }

    if (hasAndroidBridge()) {
    try {
      var p = payload || {};
      p.__secureToken = window.__fbAndroidBridgeAuthToken || '';
      p.timestamp = message.timestamp;
      window[ANDROID_BRIDGE_NAME].postEvent(
        eventName,
        JSON.stringify(p)
      );
    } catch (e) { /* ignore */ }
    return;
  }

    if (isInIframe()) {
      try {
        window.parent.postMessage(message, '*');
      } catch (e) { /* ignore */ }
      return;
    }
  }

  // --- rAF Game-Ready Detection ---

  function onFrame() {
    if (gameReadySent) return;

    frameCount++;
    if (frameCount >= RAF_FRAME_THRESHOLD) {
      gameReadySent = true;
      sendEvent('game_ready', {
        frame_count: frameCount,
        detected_at: Date.now()
      });
      return;
    }

    originalRAF.call(window, onFrame);
  }

  if (originalRAF) {
    window.requestAnimationFrame = function(callback) {
      if (!gameReadySent) {
        return originalRAF.call(window, function(timestamp) {
          frameCount++;
          if (frameCount >= RAF_FRAME_THRESHOLD && !gameReadySent) {
            gameReadySent = true;
            sendEvent('game_ready', {
              frame_count: frameCount,
              detected_at: Date.now()
            });
          }
          callback(timestamp);
        });
      }
      return originalRAF.call(window, callback);
    };
  }

  // --- First User Interaction Detection ---

  function setupFirstInteractionDetection() {
    var events = ['touchstart', 'mousedown', 'keydown'];

    function onFirstInteraction() {
      if (firstInteractionSent) return;
      firstInteractionSent = true;
      sendEvent('user_interaction_start', null);

      for (var i = 0; i < events.length; i++) {
        document.removeEventListener(events[i], onFirstInteraction, true);
      }
    }

    for (var i = 0; i < events.length; i++) {
      document.addEventListener(events[i], onFirstInteraction, true);
    }
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', setupFirstInteractionDetection);
  } else {
    setupFirstInteractionDetection();
  }

  // --- Auto Error Capture ---

  window.addEventListener('error', function(event) {
    if (errorSent) return;
    errorSent = true;
    sendEvent('error', {
      message: event.message || 'Unknown error',
      source: event.filename || '',
      lineno: event.lineno || 0,
      colno: event.colno || 0,
      auto_captured: true
    });
  });

  window.addEventListener('unhandledrejection', function(event) {
    if (errorSent) return;
    errorSent = true;
    var reason = event.reason;
    sendEvent('error', {
      message: (reason instanceof Error) ? reason.message : String(reason),
      type: 'unhandled_promise_rejection',
      auto_captured: true
    });
  });

  // --- Public API ---

  window.playablesSDK = {
    complete: function(score) {
      sendEvent('game_ended', {
        score: score,
        completed: true
      });
    },

    error: function(message) {
      if (errorSent) return;
      errorSent = true;
      sendEvent('error', {
        message: message || 'Unknown error',
        auto_captured: false
      });
    },

    sendEvent: function(eventName, payload) {
      if (!eventName || typeof eventName !== 'string') return;
      sendEvent(eventName, payload);
    }
  };

  // Kick off rAF detection in case no game code calls rAF immediately
  if (originalRAF) {
    originalRAF.call(window, onFrame);
  }
})();</script>
<!-- PLAYABLE_TOUCH_PATCH_V1 --><script>
(function() {
  if (window.__playableTouchPatchInstalled) return;
  window.__playableTouchPatchInstalled = true;
  var origAdd = EventTarget.prototype.addEventListener;
  var blockedTypes = { touchstart: 1, touchmove: 1, wheel: 1 };
  EventTarget.prototype.addEventListener = function(type, listener, options) {
    if (blockedTypes[type]) {
      if (options === undefined || options === null) {
        options = { passive: true };
      } else if (typeof options === 'boolean') {
        options = { capture: options, passive: true };
      } else {
        options = Object.assign({}, options, { passive: true });
      }
    }
    return origAdd.call(this, type, listener, options);
  };
})();
</script><script>window.Intl=window.Intl||{};Intl.t=function(s){return(Intl._locale&&Intl._locale[s])||s;};</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>คู่มือทำคอนเทนต์ท่องเที่ยวเชียงใหม่ด้วยมือถือ</title>
<style>
body { font-family: 'Sarabun', system-ui, sans-serif; line-height: 1.8; max-width: 800px; margin: 40px auto; padding: 0 20px; color: #222; background: #faf9f7; }
h1 { color: #b45309; border-bottom: 3px solid #f59e0b; padding-bottom: 10px; }
h2 { color: #92400e; margin-top: 40px; }
h3 { color: #78350f; }
blockquote { background: #fffbeb; border-left: 4px solid #f59e0b; padding: 12px 16px; margin: 20px 0; }
</style>
</head>
<body>
<h1>คู่มือทำคอนเทนต์ท่องเที่ยวเชียงใหม่ด้วยมือถือ</h1>
<p><strong>สำหรับครีเอเตอร์ท้องถิ่น ร้านค้า และคนรักเชียงใหม่ | ฉบับ 30 หน้า</strong></p>
<blockquote>ทำด้วยมือถือเครื่องเดียว ถ่าย เล่า ตัด โพสต์ จบ</blockquote>

<h2>สารบัญ (ย่อ)</h2>
<ul>
<li>บทที่ 1 - วางแผนก่อนออกกอง</li>
<li>บทที่ 2 - เซ็ตมือถือให้พร้อม</li>
<li>บทที่ 3 - ถ่ายภาพและวิดีโอให้น่าหยุดดู</li>
<li>บทที่ 4 - เล่าเรื่องแบบคนเหนือ</li>
<li>บทที่ 5 - ตัดต่อบนมือถือให้ไว</li>
<li>บทที่ 6 - โพสต์ให้ปัง วัดผลให้เป็น</li>
</ul>

<h2>บทที่ 1 - วางแผนก่อนออกกอง</h2>
<p>เชียงใหม่มีร้านกาแฟมากกว่า 2,000 ร้าน วัดเก่า 300 แห่ง และดอยรอบเมือง แต่คอนเทนต์ที่คนจำได้ไม่ใช่ที่สวยที่สุด แต่คือเรื่องที่เล่าง่ายที่สุด</p>
<h3>1.1 หาแก่นเรื่อง: 3 มุม</h3>
<p>1) มุมกินแบบคนท้องถิ่น - ข้าวซอย, ก๋วยเตี๋ยวช้างม่อย 2) มุมหลบคน - แม่กำปองเช้า, แม่ริมหน้าฝน 3) มุมวัฒนธรรมสั้น - ตุง, โคมยี่เป็ง</p>
<h3>1.2 เลือกกลุ่มคนดู</h3>
<p>นักท่องเที่ยวไทย / Digital Nomad / คนเชียงใหม่ เลือก 1 กลุ่มก่อน</p>
<h3>1.3 Content Pillars</h3>
<p>พาไปกิน, พาไปหลบ, พาไปรู้, พาไปทำ - วน 4 เสานี้ 7 วัน</p>

<p><em>ดูไฟล์ Markdown ฉบับเต็มด้านล่างสำหรับเนื้อหาครบทั้ง 6 บท</em></p>
</body>
</html>

ครูเค รักล้านนา

รักอิสระ รักสุขภาพ รักฟ้อนเจิงล้านนา

ใหม่กว่า เก่ากว่า