{"id":999,"date":"2026-03-19T16:18:37","date_gmt":"2026-03-19T16:18:37","guid":{"rendered":"https:\/\/primetoolhub.com\/?page_id=999"},"modified":"2026-07-04T05:59:42","modified_gmt":"2026-07-04T05:59:42","slug":"screen-recorder-studio","status":"publish","type":"page","link":"https:\/\/schoolict.net\/tools\/screen-recorder-studio\/","title":{"rendered":"Screen Recorder Studio | Free offline Video Capture &amp; Trimmer"},"content":{"rendered":"\n<div class=\"pth-hero-section\">\n    <div class=\"pth-hero-content\">\n        <h2>Screen Recorder Studio | Free offline Video Capture &amp; Trimmer<\/h2>\n        <p>Professional offline  screen recorder by Prime Tool Hub. Capture your screen, microphone, system audio, and webcam locally. Includes a built-in video trimmer.<\/p>\n\n        <div id=\"pth-toc-placeholder\"><\/div>\n    <\/div>\n\n  <div class=\"pth-hero-image\">\n    <img data-no-lazy=\"1\"\n         src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/05\/Free-offline-Video-Editor-800x447.jpeg\"\n         width=\"800\"\n         height=\"447\"\n         alt=\"free screen recorder\"\n         fetchpriority=\"high\"\n         loading=\"eager\"\n         decoding=\"async\"\n         style=\"width:100%; height:auto; display:block;\">\n  <\/div>\n<\/div>\n\n\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table of Contents<\/h2><nav><ul><li class=\"\"><a href=\"#\ud83d\udd34-how-browser-based-screen-recording-actually-works\">\ud83d\udd34 How Browser-Based Screen Recording Actually Works<\/a><\/li><li class=\"\"><a href=\"#\ud83d\udfe1-the-f-fmpeg-wasm-trimmer-whats-happening-inside-your-browser\">\ud83d\udfe1 The FFmpeg WASM Trimmer \u2014 What&#8217;s Happening Inside Your Browser<\/a><ul><li class=\"\"><a href=\"#\ud83d\udfe2-webcam-pi-p-positioning-and-stream-handling\">\ud83d\udfe2 Webcam PiP \u2014 Positioning and Stream Handling<\/a><\/li><li class=\"\"><a href=\"#\ud83d\udfe2-resolution-format-and-what-actually-affects-file-size\">\ud83d\udfe2 Resolution, Format, and What Actually Affects File Size<\/a><\/li><\/ul><\/li><li class=\"\"><a href=\"#\ud83d\udfe1-privacy-and-security-what-the-tool-can-and-cannot-access\">\ud83d\udfe1 Privacy and Security \u2014 What the Tool Can and Cannot Access<\/a><\/li><\/ul><\/nav><\/div>\n\n\n<style>\r\n\/* ============================================================\r\n   PTH SCREEN RECORDER STUDIO \u2014 v2.0\r\n   AdSense + PageSpeed + WCAG 2.1 AA + WP\/LiteSpeed Safe\r\n   Zero external CDN (except FFmpeg WASM \u2014 unavoidable 30MB core)\r\n   ============================================================ *\/\r\n\r\n#pth-recorder-wrapper {\r\n    font-family: 'Inter', system-ui, sans-serif;\r\n    width: 100%; max-width: 1400px; margin: 0 auto;\r\n    box-sizing: border-box; background: #f8fafc;\r\n    padding: 20px; border-radius: 16px;\r\n    color: #1e293b; font-weight: 500;\r\n}\r\n#pth-recorder-wrapper * { box-sizing: border-box; min-width: 0; }\r\n#pth-recorder-wrapper h2,\r\n#pth-recorder-wrapper h3,\r\n#pth-recorder-wrapper h4 { color: #0f172a; font-weight: 800; margin-top: 0; }\r\n\r\n\/* \u2500\u2500 Tool Title \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-tool-title {\r\n    font-size: 26px; font-weight: 800; color: #1d4ed8; margin: 0;\r\n}\r\n\r\n\/* \u2500\u2500 Cards \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-card {\r\n    background: #ffffff; border: 1px solid #e2e8f0;\r\n    border-radius: 12px; padding: 24px; margin-bottom: 20px;\r\n    box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05);\r\n}\r\n\r\n\/* \u2500\u2500 Meta bar \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-tool-meta-bar {\r\n    display: flex; align-items: center; gap: 10px;\r\n    flex-wrap: wrap; margin-bottom: 15px;\r\n}\r\n#pth-recorder-wrapper .pth-version-badge {\r\n    background: #eff6ff; color: #1d4ed8; border: 1px solid #bfdbfe;\r\n    font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 4px;\r\n}\r\n#pth-recorder-wrapper .pth-status-offline {\r\n    background: #f0fdf4; color: #15803d; border: 1px solid #bbf7d0;\r\n    font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 4px;\r\n}\r\n#pth-recorder-wrapper .pth-guide-link {\r\n    background: #faf5ff; color: #7c3aed; border: 1px solid #e9d5ff;\r\n    font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 4px;\r\n    text-decoration: none; transition: 0.2s;\r\n}\r\n#pth-recorder-wrapper .pth-guide-link:hover { background: #ede9fe; }\r\n\r\n\/* \u2500\u2500 Layout \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-flex-layout {\r\n    display: grid; grid-template-columns: 1.8fr 1fr;\r\n    gap: 24px; align-items: start;\r\n}\r\n#pth-recorder-wrapper .pth-flex-layout.pth-full-width {\r\n    grid-template-columns: 100%;\r\n}\r\n\r\n\/* \u2500\u2500 Buttons \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-btn {\r\n    padding: 10px 20px; border-radius: 8px; font-weight: 700;\r\n    cursor: pointer; border: none; font-family: 'Inter', sans-serif;\r\n    font-size: 13px; transition: 0.2s; display: inline-flex;\r\n    align-items: center; justify-content: center; gap: 6px;\r\n}\r\n#pth-recorder-wrapper .pth-btn-primary { background: #2563eb; color: #fff; }\r\n#pth-recorder-wrapper .pth-btn-primary:hover { background: #1d4ed8; }\r\n#pth-recorder-wrapper .pth-btn-secondary {\r\n    background: #f1f5f9; color: #0f172a; border: 1px solid #e2e8f0;\r\n}\r\n#pth-recorder-wrapper .pth-btn-secondary:hover { background: #e2e8f0; }\r\n#pth-recorder-wrapper .pth-btn-danger {\r\n    background: #fef2f2; color: #dc2626; border: 1px solid #fecaca;\r\n}\r\n#pth-recorder-wrapper .pth-btn-danger:hover { background: #fee2e2; }\r\n#pth-recorder-wrapper .pth-btn-success {\r\n    background: #059669; color: #fff;\r\n}\r\n#pth-recorder-wrapper .pth-btn-success:hover { background: #047857; }\r\n#pth-recorder-wrapper .pth-btn-warning {\r\n    background: #f59e0b; color: #fff;\r\n}\r\n#pth-recorder-wrapper .pth-btn-warning:hover { background: #d97706; }\r\n\r\n\/* \u2500\u2500 Form elements \u2500\u2500 *\/\r\n#pth-recorder-wrapper label {\r\n    font-weight: 700; color: #0f172a; margin-bottom: 6px;\r\n    display: block; font-size: 13px;\r\n    text-transform: uppercase; letter-spacing: 0.4px;\r\n}\r\n#pth-recorder-wrapper input,\r\n#pth-recorder-wrapper select,\r\n#pth-recorder-wrapper textarea {\r\n    width: 100%; padding: 10px 14px; border: 2px solid #e2e8f0;\r\n    border-radius: 8px; font-family: 'Inter', sans-serif;\r\n    color: #0f172a; background: #ffffff; transition: 0.2s;\r\n    font-size: 14px;\r\n}\r\n#pth-recorder-wrapper input:focus,\r\n#pth-recorder-wrapper select:focus,\r\n#pth-recorder-wrapper textarea:focus {\r\n    border-color: #3b82f6; outline: none;\r\n    box-shadow: 0 0 0 3px rgba(59,130,246,0.1);\r\n}\r\n\r\n\/* \u2500\u2500 Sidebar card header \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-sidebar-card-header {\r\n    background: #f8fafc; margin: -24px -24px 16px -24px;\r\n    padding: 12px 16px; color: #2563eb; font-size: 13px;\r\n    border-bottom: 2px solid #eff6ff; font-weight: 800;\r\n    text-transform: uppercase; border-radius: 12px 12px 0 0;\r\n}\r\n\r\n\/* \u2500\u2500 Video Preview Area \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-preview-container {\r\n    background: #0f172a; border-radius: 12px; overflow: hidden;\r\n    position: relative; width: 100%; aspect-ratio: 16 \/ 9;\r\n    border: 2px solid #334155; margin-bottom: 20px;\r\n}\r\n#pth-recorder-wrapper .pth-preview-video {\r\n    width: 100%; height: 100%; object-fit: contain; display: block;\r\n}\r\n#pth-recorder-wrapper .pth-webcam-pip {\r\n    position: absolute; width: 160px; height: 160px;\r\n    border-radius: 50%; object-fit: cover;\r\n    border: 3px solid #3b82f6;\r\n    box-shadow: 0 8px 24px rgba(0,0,0,0.5);\r\n    background: #1e293b; z-index: 50; display: none;\r\n    transition: top 0.3s, bottom 0.3s, left 0.3s, right 0.3s;\r\n}\r\n#pth-recorder-wrapper .pth-webcam-pip.pth-pip-br { bottom: 16px; right: 16px; }\r\n#pth-recorder-wrapper .pth-webcam-pip.pth-pip-bl { bottom: 16px; left: 16px; }\r\n#pth-recorder-wrapper .pth-webcam-pip.pth-pip-tr { top: 16px; right: 16px; }\r\n#pth-recorder-wrapper .pth-webcam-pip.pth-pip-tl { top: 16px; left: 16px; }\r\n\r\n#pth-recorder-wrapper .pth-watermark-overlay {\r\n    position: absolute; bottom: 16px; right: 16px;\r\n    color: rgba(255,255,255,0.55); font-size: 12px; font-weight: 800;\r\n    text-shadow: 1px 1px 3px rgba(0,0,0,0.8);\r\n    pointer-events: none; z-index: 40; letter-spacing: 1px;\r\n}\r\n#pth-recorder-wrapper .pth-preview-placeholder {\r\n    position: absolute; inset: 0; display: flex;\r\n    flex-direction: column; align-items: center; justify-content: center;\r\n    color: #475569; font-weight: 600; font-size: 15px; gap: 12px;\r\n    pointer-events: none; \/* CRITICAL: allow clicks to pass through to buttons below *\/\r\n}\r\n#pth-recorder-wrapper .pth-preview-placeholder .pth-placeholder-icon {\r\n    font-size: 48px; opacity: 0.4;\r\n}\r\n\r\n\/* \u2500\u2500 Countdown overlay \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-countdown-overlay {\r\n    position: absolute; inset: 0;\r\n    background: rgba(0,0,0,0.82);\r\n    z-index: 60; display: none;\r\n    flex-direction: column; align-items: center; justify-content: center;\r\n    color: #fff;\r\n}\r\n#pth-recorder-wrapper .pth-countdown-overlay.pth-visible { display: flex; }\r\n#pth-recorder-wrapper .pth-count-number {\r\n    font-size: 120px; font-weight: 800; color: #3b82f6; line-height: 1;\r\n    text-shadow: 0 0 40px rgba(59,130,246,0.6);\r\n}\r\n#pth-recorder-wrapper .pth-count-label {\r\n    font-size: 14px; font-weight: 700; letter-spacing: 3px;\r\n    margin-top: 16px; color: #94a3b8; text-transform: uppercase;\r\n}\r\n\r\n\/* \u2500\u2500 REC indicator \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-rec-indicator {\r\n    position: absolute; top: 16px; left: 16px;\r\n    background: #ef4444; color: #fff;\r\n    padding: 5px 14px; border-radius: 20px;\r\n    font-size: 12px; font-weight: 800;\r\n    display: none; align-items: center; gap: 8px;\r\n    z-index: 40; box-shadow: 0 4px 12px rgba(239,68,68,0.4);\r\n}\r\n#pth-recorder-wrapper .pth-rec-indicator.pth-visible { display: flex; }\r\n#pth-recorder-wrapper .pth-rec-dot {\r\n    width: 8px; height: 8px; background: #fff;\r\n    border-radius: 50%; animation: pthRecBlink 1.2s infinite;\r\n}\r\n@keyframes pthRecBlink {\r\n    0%, 100% { opacity: 1; }\r\n    50% { opacity: 0.2; }\r\n}\r\n\r\n\/* \u2500\u2500 Settings grid \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-settings-grid {\r\n    display: grid; grid-template-columns: 1fr 1fr; gap: 16px;\r\n    margin-bottom: 20px;\r\n}\r\n#pth-recorder-wrapper .pth-set-box {\r\n    background: #f8fafc; border: 1px solid #e2e8f0;\r\n    border-radius: 10px; padding: 16px;\r\n}\r\n#pth-recorder-wrapper .pth-set-box h4 {\r\n    margin: 0 0 14px; font-size: 11px; color: #334155;\r\n    text-transform: uppercase; letter-spacing: 0.5px; font-weight: 800;\r\n}\r\n#pth-recorder-wrapper .pth-toggle-row {\r\n    display: flex; justify-content: space-between; align-items: center;\r\n    padding: 8px 0; border-bottom: 1px solid #f1f5f9;\r\n}\r\n#pth-recorder-wrapper .pth-toggle-row:last-child { border-bottom: none; padding-bottom: 0; }\r\n#pth-recorder-wrapper .pth-toggle-row span {\r\n    font-size: 13px; font-weight: 700; color: #1e293b;\r\n}\r\n#pth-recorder-wrapper .pth-checkbox {\r\n    width: 18px; height: 18px; cursor: pointer;\r\n    accent-color: #3b82f6; flex-shrink: 0;\r\n}\r\n\r\n\/* \u2500\u2500 Big action buttons \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-action-bar {\r\n    display: flex; gap: 12px; flex-wrap: wrap; margin-top: 4px;\r\n}\r\n#pth-recorder-wrapper .pth-action-btn {\r\n    flex: 1; padding: 15px 20px; border-radius: 10px;\r\n    font-size: 15px; font-weight: 800; border: none; cursor: pointer;\r\n    display: inline-flex; justify-content: center; align-items: center;\r\n    gap: 8px; transition: all 0.2s; color: #fff;\r\n    min-width: 140px; box-shadow: 0 4px 12px rgba(0,0,0,0.12);\r\n    font-family: 'Inter', system-ui, sans-serif;\r\n}\r\n#pth-recorder-wrapper .pth-action-btn:hover {\r\n    transform: translateY(-2px);\r\n    box-shadow: 0 8px 20px rgba(0,0,0,0.18);\r\n}\r\n#pth-recorder-wrapper .pth-action-btn:disabled {\r\n    opacity: 0.5; cursor: not-allowed; transform: none;\r\n}\r\n#pth-recorder-wrapper .pth-btn-rec-start {\r\n    background: linear-gradient(135deg, #2563eb, #4f46e5);\r\n}\r\n#pth-recorder-wrapper .pth-btn-rec-pause {\r\n    background: linear-gradient(135deg, #f59e0b, #d97706);\r\n}\r\n#pth-recorder-wrapper .pth-btn-rec-resume {\r\n    background: linear-gradient(135deg, #10b981, #059669);\r\n}\r\n#pth-recorder-wrapper .pth-btn-rec-stop {\r\n    background: linear-gradient(135deg, #ef4444, #e11d48);\r\n}\r\n\r\n\/* \u2500\u2500 Timer \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-timer-badge {\r\n    font-size: 20px; font-family: 'Courier New', monospace;\r\n    font-weight: 800; color: #10b981; background: #f0fdf4;\r\n    padding: 6px 16px; border-radius: 8px;\r\n    border: 2px solid #bbf7d0; letter-spacing: 2px; display: none;\r\n}\r\n#pth-recorder-wrapper .pth-timer-badge.pth-visible { display: block; }\r\n\r\n\/* \u2500\u2500 Result area \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-result-area {\r\n    background: #eff6ff; border: 2px dashed #93c5fd;\r\n    border-radius: 12px; padding: 28px; text-align: center;\r\n    margin-top: 20px; display: none;\r\n}\r\n#pth-recorder-wrapper .pth-result-area.pth-visible { display: block; }\r\n#pth-recorder-wrapper .pth-result-title {\r\n    font-size: 20px; font-weight: 800; color: #1e3a8a; margin: 0 0 8px;\r\n}\r\n#pth-recorder-wrapper .pth-result-meta {\r\n    display: inline-block; background: #fff; padding: 6px 16px;\r\n    border-radius: 8px; font-size: 13px; font-weight: 700;\r\n    color: #2563eb; border: 1px solid #bfdbfe; margin-bottom: 18px;\r\n}\r\n#pth-recorder-wrapper .pth-result-actions {\r\n    display: flex; gap: 12px; justify-content: center; flex-wrap: wrap;\r\n}\r\n\r\n\/* \u2500\u2500 Recording history \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-history-item {\r\n    display: flex; justify-content: space-between; align-items: center;\r\n    padding: 10px 12px; background: #f8fafc; border-radius: 8px;\r\n    border: 1px solid #e2e8f0; margin-bottom: 8px; gap: 8px;\r\n}\r\n#pth-recorder-wrapper .pth-history-info {\r\n    font-size: 12px; font-weight: 600; color: #334155; flex: 1;\r\n}\r\n#pth-recorder-wrapper .pth-history-num {\r\n    font-size: 11px; font-weight: 800; color: #2563eb;\r\n    background: #eff6ff; padding: 2px 8px; border-radius: 4px;\r\n}\r\n\r\n\/* \u2500\u2500 Trimmer \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-trimmer-panel {\r\n    background: #f8fafc; border: 1px solid #e2e8f0;\r\n    border-radius: 12px; padding: 24px; margin-top: 20px; display: none;\r\n}\r\n#pth-recorder-wrapper .pth-trimmer-panel.pth-visible { display: block; }\r\n#pth-recorder-wrapper .pth-trim-grid {\r\n    display: grid; grid-template-columns: 1fr 1fr; gap: 16px;\r\n    margin-bottom: 16px;\r\n}\r\n#pth-recorder-wrapper .pth-trim-group label {\r\n    font-size: 11px; font-weight: 800; color: #64748b;\r\n    text-transform: uppercase; margin-bottom: 6px;\r\n}\r\n#pth-recorder-wrapper .pth-trim-group input {\r\n    font-family: 'Courier New', monospace; font-size: 20px;\r\n    font-weight: 700; text-align: center; padding: 12px;\r\n}\r\n#pth-recorder-wrapper .pth-ffmpeg-log {\r\n    background: #0f172a; color: #4ade80; padding: 14px;\r\n    border-radius: 8px; font-family: 'Courier New', monospace;\r\n    font-size: 11px; height: 130px; overflow-y: auto;\r\n    margin-bottom: 16px; border: 2px solid #1e293b; display: none;\r\n}\r\n#pth-recorder-wrapper .pth-ffmpeg-log.pth-visible { display: block; }\r\n\r\n\/* \u2500\u2500 Webcam position picker \u2500\u2500 *\/\r\n#pth-recorder-wrapper .pth-pos-grid {\r\n    display: grid; grid-template-columns: 1fr 1fr;\r\n    gap: 6px; margin-top: 8px;\r\n}\r\n#pth-recorder-wrapper .pth-pos-btn {\r\n    padding: 6px 4px; border-radius: 6px; font-size: 11px;\r\n    font-weight: 700; cursor: pointer; border: 2px solid #e2e8f0;\r\n    background: #f8fafc; color: #334155; transition: 0.15s;\r\n    text-align: center; font-family: 'Inter', system-ui, sans-serif;\r\n}\r\n#pth-recorder-wrapper .pth-pos-btn.pth-pos-active {\r\n    background: #eff6ff; border-color: #3b82f6; color: #1d4ed8;\r\n}\r\n#pth-recorder-wrapper .pth-pos-btn:hover { background: #e2e8f0; }\r\n\r\n\/* \u2500\u2500 Toast system \u2500\u2500 *\/\r\n#pth-recorder-toast {\r\n    position: fixed; bottom: 24px; right: 24px; z-index: 9999;\r\n    display: flex; flex-direction: column; gap: 10px;\r\n    pointer-events: none;\r\n}\r\n#pth-recorder-wrapper .pth-toast-msg {\r\n    padding: 12px 20px; border-radius: 10px; font-size: 14px;\r\n    font-weight: 600; color: #fff; pointer-events: auto;\r\n    box-shadow: 0 4px 15px rgba(0,0,0,0.15);\r\n    font-family: 'Inter', system-ui, sans-serif;\r\n}\r\n.pth-toast-success { background: #059669; }\r\n.pth-toast-error   { background: #dc2626; }\r\n.pth-toast-info    { background: #2563eb; }\r\n\r\n\/* \u2500\u2500 Mobile \u2500\u2500 *\/\r\n@media (max-width: 768px) {\r\n    #pth-recorder-wrapper {\r\n        padding: 10px; border-radius: 0;\r\n        background: transparent; width: 100% !important;\r\n    }\r\n    #pth-recorder-wrapper .pth-card { padding: 14px; margin-bottom: 14px; }\r\n    #pth-recorder-wrapper .pth-flex-layout { grid-template-columns: 100% !important; gap: 14px; }\r\n    #pth-recorder-wrapper .pth-tool-title { font-size: 20px; }\r\n    #pth-recorder-wrapper .pth-settings-grid { grid-template-columns: 1fr; }\r\n    #pth-recorder-wrapper .pth-trim-grid { grid-template-columns: 1fr; }\r\n    #pth-recorder-wrapper .pth-action-btn { font-size: 13px; padding: 12px 14px; min-width: 110px; }\r\n}\r\n<\/style>\r\n\r\n<!-- Toast container \u2014 outside wrapper, fixed position -->\r\n<div id=\"pth-recorder-toast\" role=\"status\" aria-live=\"polite\"><\/div>\r\n\r\n<div id=\"pth-recorder-wrapper\">\r\n    <div class=\"pth-flex-layout\" id=\"pth-recorder-layout\">\r\n\r\n        <!-- \u2550\u2550\u2550 MAIN COLUMN \u2550\u2550\u2550 -->\r\n        <div class=\"pth-main-col\">\r\n            <div class=\"pth-card\">\r\n\r\n                <!-- Header row -->\r\n                <div style=\"display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:14px;flex-wrap:wrap;gap:10px;\">\r\n                    <h2 class=\"pth-tool-title\">\ud83c\udfa5 Screen Recorder Studio<\/h2>\r\n                    <div style=\"display:flex;gap:10px;align-items:center;flex-wrap:wrap;\">\r\n                        <div id=\"pth-sr-timer\" class=\"pth-timer-badge\" aria-live=\"polite\" aria-label=\"Recording timer\">00:00:00<\/div>\r\n                        <button class=\"pth-btn pth-btn-secondary\" id=\"pth-sr-fw-btn\"\r\n                            aria-label=\"Toggle full width layout\">\u26f6 Full Width<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <!-- Meta bar -->\r\n                <div class=\"pth-tool-meta-bar\">\r\n                    <span class=\"pth-version-badge\">v2.0<\/span>\r\n                    <span class=\"pth-status-offline\">\ud83d\udd12 100% Offline<\/span>\r\n                <\/div>\r\n\r\n                <!-- Video preview -->\r\n                <div class=\"pth-preview-container\" id=\"pth-sr-preview-box\">\r\n                    <video id=\"pth-sr-preview\" class=\"pth-preview-video\" autoplay muted\r\n                        aria-label=\"Screen capture preview\" width=\"1920\" height=\"1080\"><\/video>\r\n                    <video id=\"pth-sr-webcam\" class=\"pth-webcam-pip pth-pip-br\" autoplay muted playsinline\r\n                        aria-label=\"Webcam picture-in-picture\" width=\"160\" height=\"160\"><\/video>\r\n                    <div class=\"pth-watermark-overlay\" id=\"pth-sr-watermark\">primetoolhub.com<\/div>\r\n\r\n                    <!-- Placeholder -->\r\n                    <div id=\"pth-sr-placeholder\" class=\"pth-preview-placeholder\">\r\n                        <div class=\"pth-placeholder-icon\">\ud83d\udda5\ufe0f<\/div>\r\n                        <span>Screen preview appears here<\/span>\r\n                        <span style=\"font-size:12px;color:#cbd5e1;\">Click Start Recording to begin<\/span>\r\n                    <\/div>\r\n\r\n                    <!-- Countdown overlay -->\r\n                    <div id=\"pth-sr-countdown\" class=\"pth-countdown-overlay\" aria-live=\"assertive\">\r\n                        <div class=\"pth-count-number\" id=\"pth-sr-count-num\">3<\/div>\r\n                        <div class=\"pth-count-label\">Starting Recording\u2026<\/div>\r\n                    <\/div>\r\n\r\n                    <!-- REC indicator -->\r\n                    <div id=\"pth-sr-rec-indicator\" class=\"pth-rec-indicator\" aria-label=\"Recording in progress\">\r\n                        <div class=\"pth-rec-dot\"><\/div> REC\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <!-- Settings grid -->\r\n                <div class=\"pth-settings-grid\" id=\"pth-sr-settings\">\r\n                    <div class=\"pth-set-box\">\r\n                        <h4>\ud83c\udf99\ufe0f Media Sources<\/h4>\r\n                        <div class=\"pth-toggle-row\">\r\n                            <span>Record Microphone<\/span>\r\n                            <input type=\"checkbox\" id=\"pth-sr-mic\" class=\"pth-checkbox\"\r\n                                aria-label=\"Record microphone audio\">\r\n                        <\/div>\r\n                        <div class=\"pth-toggle-row\">\r\n                            <span>Capture System Audio<\/span>\r\n                            <input type=\"checkbox\" id=\"pth-sr-sys-audio\" class=\"pth-checkbox\"\r\n                                aria-label=\"Capture system audio\">\r\n                        <\/div>\r\n                        <div class=\"pth-toggle-row\">\r\n                            <span style=\"color:#1d4ed8;font-weight:700;\">Webcam PiP Overlay<\/span>\r\n                            <input type=\"checkbox\" id=\"pth-sr-cam\" class=\"pth-checkbox\"\r\n                                aria-label=\"Enable webcam picture-in-picture overlay\">\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div class=\"pth-set-box\">\r\n                        <h4>\u2699\ufe0f Output Quality<\/h4>\r\n                        <label for=\"pth-sr-quality\">Resolution<\/label>\r\n                        <select id=\"pth-sr-quality\" aria-label=\"Select recording resolution\" style=\"margin-bottom:10px;\">\r\n                            <option value=\"1920x1080\" selected>1080p FHD \u2014 Standard<\/option>\r\n                            <option value=\"3840x2160\">4K UHD \u2014 High Quality<\/option>\r\n                            <option value=\"1280x720\">720p HD \u2014 Faster<\/option>\r\n                        <\/select>\r\n                        <label for=\"pth-sr-format\">Format<\/label>\r\n                        <select id=\"pth-sr-format\" aria-label=\"Select recording format\">\r\n                            <option value=\"webm\" selected>WebM VP9 \u2014 Smallest File<\/option>\r\n                            <option value=\"mp4\">MP4 H.264 \u2014 Best Compatibility<\/option>\r\n                        <\/select>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <!-- Action buttons -->\r\n                <div class=\"pth-action-bar\" id=\"pth-sr-action-bar\">\r\n                    <button id=\"pth-sr-start\" class=\"pth-action-btn pth-btn-rec-start\"\r\n                        aria-label=\"Start screen recording\">\u25b6 Start Recording<\/button>\r\n                    <button id=\"pth-sr-pause\" class=\"pth-action-btn pth-btn-rec-pause\"\r\n                        aria-label=\"Pause recording\" style=\"display:none;\">\u23f8 Pause<\/button>\r\n                    <button id=\"pth-sr-resume\" class=\"pth-action-btn pth-btn-rec-resume\"\r\n                        aria-label=\"Resume recording\" style=\"display:none;\">\u25b6 Resume<\/button>\r\n                    <button id=\"pth-sr-stop\" class=\"pth-action-btn pth-btn-rec-stop\"\r\n                        aria-label=\"Stop recording and save\" style=\"display:none;\">\u23f9 Stop &amp; Save<\/button>\r\n                <\/div>\r\n\r\n                <!-- Result area -->\r\n                <div id=\"pth-sr-result\" class=\"pth-result-area\" role=\"region\" aria-label=\"Recording result\">\r\n                    <div style=\"font-size:36px;margin-bottom:8px;\">\ud83c\udf89<\/div>\r\n                    <h3 class=\"pth-result-title\">Recording Complete!<\/h3>\r\n                    <div id=\"pth-sr-meta\" class=\"pth-result-meta\">\u23f1 00:00 | \ud83d\udcbe 0 MB<\/div>\r\n                    <div class=\"pth-result-actions\">\r\n                        <a id=\"pth-sr-dl-raw\" class=\"pth-btn pth-btn-success\"\r\n                            aria-label=\"Download raw recording\" style=\"text-decoration:none;\">\r\n                            \u2b07 Download Video\r\n                        <\/a>\r\n                        <button id=\"pth-sr-open-trim\" class=\"pth-btn pth-btn-primary\"\r\n                            aria-label=\"Open video trimmer\">\u2702 Trim Video<\/button>\r\n                        <button id=\"pth-sr-new-rec\" class=\"pth-btn pth-btn-secondary\"\r\n                            aria-label=\"Start a new recording\">\ud83d\udd04 New Recording<\/button>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n                <!-- Trimmer panel -->\r\n                <div id=\"pth-sr-trimmer\" class=\"pth-trimmer-panel\">\r\n                    <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;padding-bottom:12px;border-bottom:2px solid #e2e8f0;\">\r\n                        <h3 style=\"margin:0;font-size:16px;color:#0f172a;\">\u2702\ufe0f Video Trimmer<\/h3>\r\n                        <button id=\"pth-sr-close-trim\" class=\"pth-btn pth-btn-danger\"\r\n                            style=\"padding:4px 12px;font-size:12px;\" aria-label=\"Close trimmer\">\u2715 Close<\/button>\r\n                    <\/div>\r\n\r\n                    <video id=\"pth-sr-trim-player\" controls\r\n                        style=\"width:100%;border-radius:8px;background:#000;margin-bottom:16px;aspect-ratio:16\/9;display:block;\"\r\n                        aria-label=\"Trim preview player\" width=\"1280\" height=\"720\"><\/video>\r\n\r\n                    <div class=\"pth-trim-grid\">\r\n                        <div class=\"pth-trim-group\">\r\n                            <label for=\"pth-trim-start\">Start Time (MM:SS)<\/label>\r\n                            <input type=\"text\" id=\"pth-trim-start\" value=\"00:00\"\r\n                                aria-label=\"Trim start time in MM:SS format\" placeholder=\"00:00\">\r\n                        <\/div>\r\n                        <div class=\"pth-trim-group\">\r\n                            <label for=\"pth-trim-end\">End Time (MM:SS)<\/label>\r\n                            <input type=\"text\" id=\"pth-trim-end\" value=\"00:00\"\r\n                                aria-label=\"Trim end time in MM:SS format\" placeholder=\"00:00\">\r\n                        <\/div>\r\n                        <div class=\"pth-trim-group\" style=\"grid-column:span 2;\">\r\n                            <label for=\"pth-trim-format\">Export Format<\/label>\r\n                            <select id=\"pth-trim-format\" aria-label=\"Select export format for trimmed video\">\r\n                                <option value=\"mp4\" selected>MP4 H.264 \u2014 Best Compatibility (VLC, Windows)<\/option>\r\n                                <option value=\"webm\">WebM \u2014 Fast, Best for Web<\/option>\r\n                            <\/select>\r\n                        <\/div>\r\n                    <\/div>\r\n\r\n                    <div id=\"pth-sr-ffmpeg-log\" class=\"pth-ffmpeg-log\" aria-live=\"polite\" aria-label=\"FFmpeg processing log\">\r\n                        Waiting for trim command\u2026\r\n                    <\/div>\r\n\r\n                    <div style=\"display:flex;gap:12px;flex-wrap:wrap;\">\r\n                        <button id=\"pth-sr-process-trim\" class=\"pth-btn pth-btn-primary\"\r\n                            style=\"flex:1;padding:12px;\" aria-label=\"Process and trim video\">\r\n                            \u2699 Process Trim\r\n                        <\/button>\r\n                        <a id=\"pth-sr-dl-trim\" class=\"pth-btn pth-btn-success\"\r\n                            style=\"flex:1;padding:12px;text-decoration:none;display:none;\"\r\n                            aria-label=\"Download trimmed video\">\r\n                            \u2b07 Download Trimmed\r\n                        <\/a>\r\n                    <\/div>\r\n                <\/div>\r\n\r\n            <\/div><!-- \/pth-card -->\r\n        <\/div><!-- \/main col -->\r\n\r\n        <!-- \u2550\u2550\u2550 SIDEBAR \u2550\u2550\u2550 -->\r\n        <div class=\"pth-sidebar-col\" id=\"pth-sr-sidebar\">\r\n\r\n            <!-- Webcam PiP position -->\r\n            <div class=\"pth-card\" id=\"pth-sr-pip-card\" style=\"display:none;\">\r\n                <div class=\"pth-sidebar-card-header\">\ud83d\udcf8 Webcam Position<\/div>\r\n                <p style=\"font-size:12px;color:#334155;margin:0 0 10px;\">Choose where the webcam appears on screen:<\/p>\r\n                <div class=\"pth-pos-grid\" role=\"group\" aria-label=\"Webcam position selector\">\r\n                    <button class=\"pth-pos-btn\" id=\"pth-pos-tl\" aria-label=\"Top left position\">\u2196 Top Left<\/button>\r\n                    <button class=\"pth-pos-btn\" id=\"pth-pos-tr\" aria-label=\"Top right position\">\u2197 Top Right<\/button>\r\n                    <button class=\"pth-pos-btn\" id=\"pth-pos-bl\" aria-label=\"Bottom left position\">\u2199 Bottom Left<\/button>\r\n                    <button class=\"pth-pos-btn pth-pos-active\" id=\"pth-pos-br\" aria-label=\"Bottom right position\">\u2198 Bottom Right<\/button>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- Custom watermark -->\r\n            <div class=\"pth-card\">\r\n                <div class=\"pth-sidebar-card-header\">\ud83d\udd8a\ufe0f Watermark<\/div>\r\n                <label for=\"pth-sr-wm-text\">Watermark Text<\/label>\r\n                <input type=\"text\" id=\"pth-sr-wm-text\" value=\"primetoolhub.com\"\r\n                    aria-label=\"Watermark text shown on recording\" placeholder=\"yoursite.com\"\r\n                    style=\"margin-bottom:10px;\">\r\n                <div style=\"display:flex;gap:8px;align-items:center;\">\r\n                    <input type=\"checkbox\" id=\"pth-sr-wm-show\" class=\"pth-checkbox\" checked\r\n                        aria-label=\"Show watermark on recording\">\r\n                    <label for=\"pth-sr-wm-show\" style=\"text-transform:none;font-size:13px;margin:0;font-weight:600;\">\r\n                        Show watermark\r\n                    <\/label>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- Recording history -->\r\n            <div class=\"pth-card\">\r\n                <div class=\"pth-sidebar-card-header\">\ud83d\udccb Session History<\/div>\r\n                <div id=\"pth-sr-history\">\r\n                    <p style=\"font-size:12px;color:#475569;text-align:center;padding:16px 0;margin:0;\">\r\n                        No recordings yet this session.\r\n                    <\/p>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- Pro tips -->\r\n            <div class=\"pth-card\">\r\n                <div class=\"pth-sidebar-card-header\">\ud83d\udca1 Pro Tips<\/div>\r\n                <ul style=\"margin:0;padding-left:18px;font-size:13px;color:#475569;line-height:1.8;\">\r\n                    <li><strong>Best quality:<\/strong> Select \"Entire Screen\" when the browser prompts you.<\/li>\r\n                    <li><strong>Avoid echo:<\/strong> Use headphones when recording both Mic + System Audio.<\/li>\r\n                    <li><strong>VLC won't play?<\/strong> Use the Trimmer \u2192 export as MP4.<\/li>\r\n                    <li><strong>Privacy:<\/strong> Your video never leaves your browser. Zero uploads.<\/li>\r\n                    <li><strong>Long recordings:<\/strong> Timer shows HH:MM:SS. No time limit.<\/li>\r\n                <\/ul>\r\n            <\/div>\r\n\r\n            <!-- Browser support -->\r\n            <div class=\"pth-card\" style=\"background:#fefce8;border-color:#fde68a;\">\r\n                <div class=\"pth-sidebar-card-header\" style=\"color:#92400e;border-color:#fde68a;\">\u26a0\ufe0f Browser Support<\/div>\r\n                <p style=\"font-size:12px;color:#78350f;line-height:1.7;margin:0;\">\r\n                    Screen capture requires <strong>Chrome 72+<\/strong>, <strong>Edge 79+<\/strong>, or <strong>Firefox 66+<\/strong>.\r\n                    Safari on iOS does not support <code>getDisplayMedia<\/code>.<br><br>\r\n                    FFmpeg trimmer requires <strong>Chrome\/Edge<\/strong> with SharedArrayBuffer enabled.\r\n                <\/p>\r\n            <\/div>\r\n\r\n        <\/div><!-- \/sidebar -->\r\n    <\/div><!-- \/flex-layout -->\r\n<\/div><!-- \/wrapper -->\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n(function () {\r\n    'use strict';\r\n\r\n    \/* =======================================================\r\n       PTH SCREEN RECORDER STUDIO \u2014 v2.0\r\n       WP\/LiteSpeed safe | WCAG 2.1 AA | PageSpeed 100\r\n       Zero external CDN except FFmpeg WASM (unavoidable 30MB core)\r\n       ======================================================= *\/\r\n\r\n    window.pthScreenRecorderApp = {\r\n        initialized: false,\r\n\r\n        \/* \u2500\u2500\u2500 State \u2500\u2500\u2500 *\/\r\n        mediaRecorder: null,\r\n        recordedChunks: [],\r\n        combinedStream: null,\r\n        micStream: null,\r\n        webcamStream: null,\r\n        recordedBlob: null,\r\n        recordedBlobUrl: null,\r\n        fileExtension: 'webm',\r\n        timerInterval: null,\r\n        startTime: null,\r\n        elapsedMs: 0,\r\n        recCount: 0,\r\n        pipPosition: 'pth-pip-br',\r\n        isFullWidth: false,\r\n\r\n        \/* \u2500\u2500\u2500 Element cache \u2500\u2500\u2500 *\/\r\n        el: {},\r\n\r\n        \/* \u2500\u2500\u2500 INIT \u2500\u2500\u2500 *\/\r\n        init: function () {\r\n            this.cacheElements();\r\n            this.attachEvents();\r\n            this.syncWatermark();\r\n        },\r\n\r\n        cacheElements: function () {\r\n            var ids = [\r\n                'pth-sr-fw-btn', 'pth-recorder-layout', 'pth-sr-sidebar',\r\n                'pth-sr-timer', 'pth-sr-preview', 'pth-sr-webcam',\r\n                'pth-sr-preview-box', 'pth-sr-placeholder', 'pth-sr-countdown',\r\n                'pth-sr-count-num', 'pth-sr-rec-indicator',\r\n                'pth-sr-mic', 'pth-sr-sys-audio', 'pth-sr-cam',\r\n                'pth-sr-quality', 'pth-sr-format', 'pth-sr-settings',\r\n                'pth-sr-start', 'pth-sr-pause', 'pth-sr-resume', 'pth-sr-stop',\r\n                'pth-sr-result', 'pth-sr-meta', 'pth-sr-dl-raw',\r\n                'pth-sr-open-trim', 'pth-sr-new-rec',\r\n                'pth-sr-trimmer', 'pth-sr-close-trim', 'pth-sr-trim-player',\r\n                'pth-trim-start', 'pth-trim-end', 'pth-trim-format',\r\n                'pth-sr-process-trim', 'pth-sr-dl-trim', 'pth-sr-ffmpeg-log',\r\n                'pth-sr-pip-card', 'pth-sr-wm-text', 'pth-sr-wm-show',\r\n                'pth-sr-watermark', 'pth-sr-history',\r\n                'pth-pos-tl', 'pth-pos-tr', 'pth-pos-bl', 'pth-pos-br'\r\n            ];\r\n            var self = this;\r\n            ids.forEach(function (id) {\r\n                var key = id.replace(\/-([a-z])\/g, function (m, c) { return c.toUpperCase(); });\r\n                self.el[key] = document.getElementById(id);\r\n            });\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 EVENTS \u2014 addEventListener ONLY \u2500\u2500\u2500 *\/\r\n        attachEvents: function () {\r\n            var self = this;\r\n\r\n            \/* Full width *\/\r\n            if (self.el.pthSrFwBtn) {\r\n                self.el.pthSrFwBtn.addEventListener('click', function () { self.toggleFullWidth(); });\r\n            }\r\n\r\n            \/* Format change *\/\r\n            if (self.el.pthSrFormat) {\r\n                self.el.pthSrFormat.addEventListener('change', function () {\r\n                    self.fileExtension = self.el.pthSrFormat.value;\r\n                });\r\n            }\r\n\r\n            \/* Webcam toggle *\/\r\n            if (self.el.pthSrCam) {\r\n                self.el.pthSrCam.addEventListener('change', function () { self.toggleWebcam(); });\r\n            }\r\n\r\n            \/* Watermark live sync *\/\r\n            if (self.el.pthSrWmText) {\r\n                self.el.pthSrWmText.addEventListener('input', function () { self.syncWatermark(); });\r\n            }\r\n            if (self.el.pthSrWmShow) {\r\n                self.el.pthSrWmShow.addEventListener('change', function () { self.syncWatermark(); });\r\n            }\r\n\r\n            \/* Recording controls *\/\r\n            if (self.el.pthSrStart) self.el.pthSrStart.addEventListener('click', function () { self.startSequence(); });\r\n            if (self.el.pthSrPause) self.el.pthSrPause.addEventListener('click', function () { self.pauseRec(); });\r\n            if (self.el.pthSrResume) self.el.pthSrResume.addEventListener('click', function () { self.resumeRec(); });\r\n            if (self.el.pthSrStop) self.el.pthSrStop.addEventListener('click', function () { self.stopRec(); });\r\n\r\n            \/* Result actions *\/\r\n            if (self.el.pthSrOpenTrim) self.el.pthSrOpenTrim.addEventListener('click', function () { self.openTrimmer(); });\r\n            if (self.el.pthSrNewRec) self.el.pthSrNewRec.addEventListener('click', function () { self.newRecording(); });\r\n\r\n            \/* Trimmer controls *\/\r\n            if (self.el.pthSrCloseTrim) {\r\n                self.el.pthSrCloseTrim.addEventListener('click', function () {\r\n                    self.el.pthSrTrimmer.classList.remove('pth-visible');\r\n                    if (self.el.pthSrTrimPlayer) self.el.pthSrTrimPlayer.pause();\r\n                });\r\n            }\r\n            if (self.el.pthSrProcessTrim) {\r\n                self.el.pthSrProcessTrim.addEventListener('click', function () { self.executeTrim(); });\r\n            }\r\n\r\n            \/* Webcam position buttons *\/\r\n            var posMap = {\r\n                pthPosTl: 'pth-pip-tl',\r\n                pthPosTr: 'pth-pip-tr',\r\n                pthPosBl: 'pth-pip-bl',\r\n                pthPosBr: 'pth-pip-br'\r\n            };\r\n            Object.keys(posMap).forEach(function (elKey) {\r\n                if (self.el[elKey]) {\r\n                    self.el[elKey].addEventListener('click', function () {\r\n                        self.setWebcamPosition(posMap[elKey], elKey);\r\n                    });\r\n                }\r\n            });\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 FULL WIDTH TOGGLE \u2500\u2500\u2500 *\/\r\n        toggleFullWidth: function () {\r\n            var layout = this.el.pthRecorderLayout;\r\n            var sidebar = this.el.pthSrSidebar;\r\n            var btn = this.el.pthSrFwBtn;\r\n            if (!layout || !sidebar || !btn) return;\r\n            this.isFullWidth = !this.isFullWidth;\r\n            if (this.isFullWidth) {\r\n                layout.classList.add('pth-full-width');\r\n                sidebar.style.display = 'none';\r\n                btn.textContent = '\\u25e8 Split View';\r\n            } else {\r\n                layout.classList.remove('pth-full-width');\r\n                sidebar.style.display = '';\r\n                btn.textContent = '\\u29c6 Full Width';\r\n            }\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 WATERMARK SYNC \u2500\u2500\u2500 *\/\r\n        syncWatermark: function () {\r\n            if (!this.el.pthSrWatermark) return;\r\n            var show = this.el.pthSrWmShow ? this.el.pthSrWmShow.checked : true;\r\n            var text = this.el.pthSrWmText ? this.el.pthSrWmText.value.trim() : 'primetoolhub.com';\r\n            this.el.pthSrWatermark.textContent = (show && text) ? text : '';\r\n            this.el.pthSrWatermark.style.display = (show && text) ? 'block' : 'none';\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 WEBCAM TOGGLE \u2500\u2500\u2500 *\/\r\n        toggleWebcam: async function () {\r\n            var self = this;\r\n            if (self.el.pthSrCam.checked) {\r\n                try {\r\n                    self.webcamStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false });\r\n                    self.el.pthSrWebcam.srcObject = self.webcamStream;\r\n                    self.el.pthSrWebcam.style.display = 'block';\r\n                    self.el.pthSrPipCard.style.display = 'block';\r\n                    self.showToast('Webcam enabled!', 'success');\r\n                } catch (err) {\r\n                    self.el.pthSrCam.checked = false;\r\n                    self.showToast('Webcam access denied. Check browser permissions.', 'error');\r\n                }\r\n            } else {\r\n                if (self.webcamStream) {\r\n                    self.webcamStream.getTracks().forEach(function (t) { t.stop(); });\r\n                    self.webcamStream = null;\r\n                }\r\n                self.el.pthSrWebcam.srcObject = null;\r\n                self.el.pthSrWebcam.style.display = 'none';\r\n                self.el.pthSrPipCard.style.display = 'none';\r\n            }\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 WEBCAM POSITION \u2500\u2500\u2500 *\/\r\n        setWebcamPosition: function (posClass, elKey) {\r\n            var self = this;\r\n            var allPos = ['pth-pip-tl', 'pth-pip-tr', 'pth-pip-bl', 'pth-pip-br'];\r\n            allPos.forEach(function (cls) {\r\n                self.el.pthSrWebcam.classList.remove(cls);\r\n            });\r\n            self.el.pthSrWebcam.classList.add(posClass);\r\n            self.pipPosition = posClass;\r\n\r\n            \/* Update active button *\/\r\n            ['pthPosTl', 'pthPosTr', 'pthPosBl', 'pthPosBr'].forEach(function (k) {\r\n                if (self.el[k]) self.el[k].classList.remove('pth-pos-active');\r\n            });\r\n            if (self.el[elKey]) self.el[elKey].classList.add('pth-pos-active');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 START SEQUENCE \u2500\u2500\u2500 *\/\r\n        startSequence: async function () {\r\n            var self = this;\r\n            try {\r\n                var parts = self.el.pthSrQuality.value.split('x');\r\n                var w = parseInt(parts[0], 10);\r\n                var h = parseInt(parts[1], 10);\r\n\r\n                var screenStream = await navigator.mediaDevices.getDisplayMedia({\r\n                    video: { width: { ideal: w }, height: { ideal: h }, frameRate: { ideal: 30 }, displaySurface: 'monitor' },\r\n                    audio: self.el.pthSrSysAudio.checked\r\n                });\r\n\r\n                var tracks = Array.prototype.slice.call(screenStream.getTracks());\r\n\r\n                if (self.el.pthSrMic.checked) {\r\n                    try {\r\n                        self.micStream = await navigator.mediaDevices.getUserMedia({\r\n                            audio: { echoCancellation: true, noiseSuppression: true, sampleRate: 48000 }\r\n                        });\r\n                        Array.prototype.push.apply(tracks, self.micStream.getTracks());\r\n                    } catch (micErr) {\r\n                        self.showToast('Microphone access denied \u2014 recording without mic.', 'info');\r\n                    }\r\n                }\r\n\r\n                if (self.webcamStream) {\r\n                    Array.prototype.push.apply(tracks, self.webcamStream.getTracks());\r\n                }\r\n\r\n                self.combinedStream = new MediaStream(tracks);\r\n                self.el.pthSrPreview.srcObject = self.combinedStream;\r\n                self.el.pthSrPlaceholder.style.display = 'none';\r\n                self.fileExtension = self.el.pthSrFormat.value;\r\n\r\n                \/* Stop when user ends share via browser UI *\/\r\n                screenStream.getVideoTracks()[0].addEventListener('ended', function () {\r\n                    if (self.mediaRecorder && self.mediaRecorder.state !== 'inactive') self.stopRec();\r\n                });\r\n\r\n                \/* Pick best supported mime *\/\r\n                var mime = self.getBestMime();\r\n                var options = mime ? { mimeType: mime } : {};\r\n                self.mediaRecorder = new MediaRecorder(self.combinedStream, options);\r\n                self.recordedChunks = [];\r\n\r\n                self.mediaRecorder.addEventListener('dataavailable', function (e) {\r\n                    if (e.data && e.data.size > 0) self.recordedChunks.push(e.data);\r\n                });\r\n                self.mediaRecorder.addEventListener('stop', function () { self.handleStop(); });\r\n\r\n                self.runCountdown(3);\r\n\r\n            } catch (err) {\r\n                console.error('[PTH Recorder]', err);\r\n                self.showToast('Screen capture failed. Grant permissions and try again.', 'error');\r\n            }\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 COUNTDOWN \u2500\u2500\u2500 *\/\r\n        runCountdown: function (sec) {\r\n            var self = this;\r\n            self.el.pthSrStart.style.display = 'none';\r\n            self.el.pthSrSettings.style.display = 'none';\r\n            self.el.pthSrCountdown.classList.add('pth-visible');\r\n\r\n            var c = sec;\r\n            self.el.pthSrCountNum.textContent = String(c);\r\n\r\n            var iv = setInterval(function () {\r\n                c--;\r\n                if (c > 0) {\r\n                    self.el.pthSrCountNum.textContent = String(c);\r\n                } else {\r\n                    clearInterval(iv);\r\n                    self.el.pthSrCountdown.classList.remove('pth-visible');\r\n                    self.mediaRecorder.start(1000);\r\n                    self.startClock();\r\n                    self.showActiveUI();\r\n                    \/* Play beep when recording starts *\/\r\n                    self.playBeep(880, 0.15);\r\n                }\r\n            }, 1000);\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 RECORDING CONTROLS \u2500\u2500\u2500 *\/\r\n        pauseRec: function () {\r\n            if (this.mediaRecorder && this.mediaRecorder.state === 'recording') {\r\n                this.mediaRecorder.pause();\r\n                this.pauseClock();\r\n                this.el.pthSrPause.style.display = 'none';\r\n                this.el.pthSrResume.style.display = 'inline-flex';\r\n                this.el.pthSrRecIndicator.style.background = '#f59e0b';\r\n                this.el.pthSrRecIndicator.innerHTML = '<div class=\"pth-rec-dot\" style=\"background:#fff;animation:none;\"><\/div> PAUSED';\r\n                this.showToast('Recording paused.', 'info');\r\n            }\r\n        },\r\n\r\n        resumeRec: function () {\r\n            if (this.mediaRecorder && this.mediaRecorder.state === 'paused') {\r\n                this.mediaRecorder.resume();\r\n                this.resumeClock();\r\n                this.el.pthSrResume.style.display = 'none';\r\n                this.el.pthSrPause.style.display = 'inline-flex';\r\n                this.el.pthSrRecIndicator.style.background = '#ef4444';\r\n                this.el.pthSrRecIndicator.innerHTML = '<div class=\"pth-rec-dot\"><\/div> REC';\r\n                this.showToast('Recording resumed!', 'success');\r\n            }\r\n        },\r\n\r\n        stopRec: function () {\r\n            if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {\r\n                if (this.mediaRecorder.state === 'recording') {\r\n                    this.elapsedMs += (Date.now() - this.startTime);\r\n                }\r\n                clearInterval(this.timerInterval);\r\n                this.mediaRecorder.stop();\r\n                if (this.combinedStream) {\r\n                    this.combinedStream.getTracks().forEach(function (t) { t.stop(); });\r\n                }\r\n                \/* Play beep when recording stops *\/\r\n                this.playBeep(440, 0.2);\r\n            }\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 HANDLE STOP \/ BUILD RESULT \u2500\u2500\u2500 *\/\r\n        handleStop: function () {\r\n            var self = this;\r\n            var mime = self.fileExtension === 'mp4' ? 'video\/mp4' : 'video\/webm';\r\n            self.recordedBlob = new Blob(self.recordedChunks, { type: mime });\r\n            if (self.recordedBlobUrl) URL.revokeObjectURL(self.recordedBlobUrl);\r\n            self.recordedBlobUrl = URL.createObjectURL(self.recordedBlob);\r\n\r\n            var durSec = Math.floor(self.elapsedMs \/ 1000);\r\n            var durStr = self.formatHMS(durSec);\r\n            var sizeStr = self.formatBytes(self.recordedBlob.size);\r\n\r\n            self.el.pthSrMeta.textContent = '\\u23f1 ' + durStr + ' \\u2502 \\ud83d\\udcbe ' + sizeStr;\r\n            self.el.pthSrDlRaw.href = self.recordedBlobUrl;\r\n            self.el.pthSrDlRaw.download = 'PTH-Recording-' + Date.now() + '.' + self.fileExtension;\r\n            self.el.pthSrResult.classList.add('pth-visible');\r\n\r\n            self.el.pthSrPreview.srcObject = null;\r\n            self.el.pthSrWebcam.style.display = 'none';\r\n            self.el.pthSrPlaceholder.style.display = '';\r\n\r\n            \/* Add to session history *\/\r\n            self.recCount++;\r\n            self.addHistory(self.recCount, durStr, sizeStr, self.recordedBlobUrl, self.fileExtension);\r\n\r\n            self.resetUI();\r\n            self.elapsedMs = 0;\r\n            self.recordedChunks = [];\r\n            self.showToast('Recording saved! \\u2714', 'success');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 SESSION HISTORY \u2500\u2500\u2500 *\/\r\n        addHistory: function (num, dur, size, url, ext) {\r\n            var hist = this.el.pthSrHistory;\r\n            if (!hist) return;\r\n\r\n            \/* Remove placeholder text on first entry *\/\r\n            if (num === 1) hist.innerHTML = '';\r\n\r\n            var item = document.createElement('div');\r\n            item.className = 'pth-history-item';\r\n            item.innerHTML =\r\n                '<span class=\"pth-history-num\">#' + num + '<\/span>' +\r\n                '<span class=\"pth-history-info\">' + dur + ' &bull; ' + size + '<\/span>' +\r\n                '<a href=\"' + url + '\" download=\"PTH-Rec-' + num + '.' + ext + '\" ' +\r\n                'class=\"pth-btn pth-btn-primary\" style=\"font-size:11px;padding:4px 10px;\" ' +\r\n                'aria-label=\"Download recording ' + num + '\">\\u2b07<\/a>';\r\n            hist.insertBefore(item, hist.firstChild);\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 NEW RECORDING \u2500\u2500\u2500 *\/\r\n        newRecording: function () {\r\n            this.el.pthSrResult.classList.remove('pth-visible');\r\n            this.el.pthSrTrimmer.classList.remove('pth-visible');\r\n            this.el.pthSrSettings.style.display = '';\r\n            this.el.pthSrStart.style.display = 'inline-flex';\r\n            this.showToast('Ready for a new recording!', 'info');\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 OPEN TRIMMER \u2500\u2500\u2500 *\/\r\n        openTrimmer: function () {\r\n            if (!this.recordedBlobUrl) { this.showToast('No recording available to trim.', 'error'); return; }\r\n            var self = this;\r\n            self.el.pthSrTrimmer.classList.add('pth-visible');\r\n            self.el.pthSrTrimPlayer.src = self.recordedBlobUrl;\r\n            self.el.pthSrDlTrim.style.display = 'none';\r\n            self.el.pthSrFfmpegLog.classList.remove('pth-visible');\r\n            self.el.pthTrimStart.value = '00:00';\r\n            self.el.pthTrimEnd.value = '00:00';\r\n\r\n            \/* Use both loadedmetadata + canplay as fallback \u2014 blob URLs sometimes skip loadedmetadata *\/\r\n            function setTrimEnd() {\r\n                var dur = self.el.pthSrTrimPlayer.duration;\r\n                if (isFinite(dur) && dur > 0) {\r\n                    var totalSec = Math.floor(dur);\r\n                    var mm = String(Math.floor(totalSec \/ 60)).padStart(2, '0');\r\n                    var ss = String(totalSec % 60).padStart(2, '0');\r\n                    self.el.pthTrimEnd.value = mm + ':' + ss;\r\n                }\r\n            }\r\n            self.el.pthSrTrimPlayer.addEventListener('loadedmetadata', setTrimEnd, { once: true });\r\n            self.el.pthSrTrimPlayer.addEventListener('canplay', setTrimEnd, { once: true });\r\n            self.el.pthSrTrimPlayer.load();\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 EXECUTE TRIM via FFmpeg WASM \u2500\u2500\u2500 *\/\r\n        executeTrim: async function () {\r\n            var self = this;\r\n            try {\r\n                self.el.pthSrFfmpegLog.classList.add('pth-visible');\r\n                self.el.pthSrDlTrim.style.display = 'none';\r\n                self.el.pthSrProcessTrim.disabled = true;\r\n                self.el.pthSrProcessTrim.textContent = '\\u23f3 Processing\u2026';\r\n\r\n                var logEl = self.el.pthSrFfmpegLog;\r\n                logEl.textContent = '> Initializing FFmpeg WASM engine\u2026';\r\n\r\n                var FFmpegLib = window.FFmpeg;\r\n                if (!FFmpegLib || !FFmpegLib.createFFmpeg) {\r\n                    self.showToast('FFmpeg not loaded. Check internet connection.', 'error');\r\n                    self.resetTrimBtn();\r\n                    return;\r\n                }\r\n\r\n                var ffmpeg = FFmpegLib.createFFmpeg({\r\n                    mainName: 'main',\r\n                    corePath: 'https:\/\/unpkg.com\/@ffmpeg\/core-st@0.11.1\/dist\/ffmpeg-core.js',\r\n                    log: false,\r\n                    logger: function (ref) {\r\n                        var message = ref.message;\r\n                        if (message && message.trim()) {\r\n                            logEl.textContent += '\\n> ' + message;\r\n                            logEl.scrollTop = logEl.scrollHeight;\r\n                        }\r\n                    }\r\n                });\r\n\r\n                logEl.textContent += '\\n> Loading FFmpeg core (one-time ~30MB download)\u2026';\r\n                await ffmpeg.load();\r\n\r\n                var inExt = self.fileExtension;\r\n                var outExt = self.el.pthTrimFormat.value;\r\n                var inName = 'input.' + inExt;\r\n                var outName = 'output.' + outExt;\r\n\r\n                logEl.textContent += '\\n> Reading video into memory\u2026';\r\n                var fileData = await FFmpegLib.fetchFile(self.recordedBlob);\r\n                ffmpeg.FS('writeFile', inName, fileData);\r\n\r\n                var startVal = self.el.pthTrimStart.value || '00:00';\r\n                var endVal = self.el.pthTrimEnd.value || '00:00';\r\n\r\n                \/* Normalize MM:SS to HH:MM:SS for FFmpeg *\/\r\n                function toHMS(val) {\r\n                    val = val.trim();\r\n                    return val.split(':').length === 2 ? '00:' + val : val;\r\n                }\r\n\r\n                var args = ['-ss', toHMS(startVal), '-to', toHMS(endVal), '-i', inName];\r\n\r\n                if (outExt === 'mp4') {\r\n                    logEl.textContent += '\\n> Re-encoding to MP4 H.264 \/ YUV420P\u2026';\r\n                    args = args.concat(['-c:v', 'libx264', '-preset', 'ultrafast', '-pix_fmt', 'yuv420p', '-c:a', 'aac']);\r\n                } else {\r\n                    logEl.textContent += '\\n> Trimming WebM (stream copy \u2014 fast)\u2026';\r\n                    args = args.concat(['-c', 'copy']);\r\n                }\r\n                args.push(outName);\r\n\r\n                await ffmpeg.run.apply(ffmpeg, args);\r\n\r\n                logEl.textContent += '\\n> Packaging output file\u2026';\r\n                var outData = ffmpeg.FS('readFile', outName);\r\n                var trimmedBlob = new Blob([outData.buffer], { type: 'video\/' + outExt });\r\n                var trimmedUrl = URL.createObjectURL(trimmedBlob);\r\n\r\n                self.el.pthSrDlTrim.href = trimmedUrl;\r\n                self.el.pthSrDlTrim.download = 'PTH-Trimmed-' + Date.now() + '.' + outExt;\r\n                self.el.pthSrDlTrim.style.display = 'inline-flex';\r\n\r\n                self.el.pthSrTrimPlayer.src = trimmedUrl;\r\n                self.el.pthSrTrimPlayer.load();\r\n                self.el.pthSrTrimPlayer.play().catch(function () {});\r\n\r\n                logEl.textContent += '\\n\\n\\u2713 DONE! Trimmed video ready.';\r\n                logEl.scrollTop = logEl.scrollHeight;\r\n                self.showToast('Trim complete! Video ready to download.', 'success');\r\n\r\n            } catch (err) {\r\n                console.error('[PTH Trimmer]', err);\r\n                self.el.pthSrFfmpegLog.textContent += '\\n\\n\\u2717 ERROR: ' + (err.message || 'FFmpeg failed.');\r\n                self.showToast('Trim failed. See log for details.', 'error');\r\n            } finally {\r\n                self.resetTrimBtn();\r\n            }\r\n        },\r\n\r\n        resetTrimBtn: function () {\r\n            this.el.pthSrProcessTrim.disabled = false;\r\n            this.el.pthSrProcessTrim.textContent = '\\u2699 Process Trim';\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 TIMER \u2500\u2500\u2500 *\/\r\n        startClock: function () {\r\n            this.elapsedMs = 0;\r\n            this.startTime = Date.now();\r\n            this.timerInterval = setInterval(this.updateClock.bind(this), 500);\r\n            this.el.pthSrTimer.classList.add('pth-visible');\r\n        },\r\n        pauseClock: function () {\r\n            clearInterval(this.timerInterval);\r\n            this.elapsedMs += Date.now() - this.startTime;\r\n        },\r\n        resumeClock: function () {\r\n            this.startTime = Date.now();\r\n            this.timerInterval = setInterval(this.updateClock.bind(this), 500);\r\n        },\r\n        updateClock: function () {\r\n            var ms = this.elapsedMs + (Date.now() - this.startTime);\r\n            this.el.pthSrTimer.textContent = this.formatHMS(Math.floor(ms \/ 1000));\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 UI STATE HELPERS \u2500\u2500\u2500 *\/\r\n        showActiveUI: function () {\r\n            this.el.pthSrPause.style.display = 'inline-flex';\r\n            this.el.pthSrStop.style.display = 'inline-flex';\r\n            this.el.pthSrRecIndicator.classList.add('pth-visible');\r\n            this.el.pthSrResult.classList.remove('pth-visible');\r\n        },\r\n\r\n        resetUI: function () {\r\n            this.el.pthSrStart.style.display = 'inline-flex';\r\n            this.el.pthSrPause.style.display = 'none';\r\n            this.el.pthSrResume.style.display = 'none';\r\n            this.el.pthSrStop.style.display = 'none';\r\n            this.el.pthSrRecIndicator.classList.remove('pth-visible');\r\n            this.el.pthSrTimer.classList.remove('pth-visible');\r\n            this.el.pthSrTimer.textContent = '00:00:00';\r\n            this.el.pthSrSettings.style.display = '';\r\n            this.el.pthSrPlaceholder.style.display = '';\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 AUDIO BEEP (Web Audio API \u2014 100% offline) \u2500\u2500\u2500 *\/\r\n        playBeep: function (freq, duration) {\r\n            try {\r\n                var ctx = new (window.AudioContext || window.webkitAudioContext)();\r\n                var osc = ctx.createOscillator();\r\n                var gain = ctx.createGain();\r\n                osc.connect(gain);\r\n                gain.connect(ctx.destination);\r\n                osc.frequency.value = freq;\r\n                osc.type = 'sine';\r\n                gain.gain.setValueAtTime(0.3, ctx.currentTime);\r\n                gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + duration);\r\n                osc.start(ctx.currentTime);\r\n                osc.stop(ctx.currentTime + duration);\r\n            } catch (e) { \/* Audio not supported \u2014 fail silently *\/ }\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 BEST MIME TYPE \u2500\u2500\u2500 *\/\r\n        getBestMime: function () {\r\n            var ext = this.fileExtension;\r\n            var candidates = [\r\n                'video\/' + ext + '; codecs=h264',\r\n                'video\/' + ext + '; codecs=vp9',\r\n                'video\/' + ext + '; codecs=vp8',\r\n                'video\/' + ext\r\n            ];\r\n            for (var i = 0; i < candidates.length; i++) {\r\n                if (MediaRecorder.isTypeSupported(candidates[i])) return candidates[i];\r\n            }\r\n            return '';\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 UTILS \u2500\u2500\u2500 *\/\r\n        formatHMS: function (secTotal) {\r\n            var h = Math.floor(secTotal \/ 3600);\r\n            var m = Math.floor((secTotal % 3600) \/ 60);\r\n            var s = Math.floor(secTotal % 60);\r\n            return (h > 0 ? String(h).padStart(2, '0') + ':' : '') +\r\n                String(m).padStart(2, '0') + ':' +\r\n                String(s).padStart(2, '0');\r\n        },\r\n        formatBytes: function (bytes) {\r\n            if (!bytes) return '0 B';\r\n            var units = ['B', 'KB', 'MB', 'GB'];\r\n            var i = Math.floor(Math.log(bytes) \/ Math.log(1024));\r\n            return parseFloat((bytes \/ Math.pow(1024, i)).toFixed(2)) + ' ' + units[i];\r\n        },\r\n\r\n        \/* \u2500\u2500\u2500 TOAST \u2014 bottom-right, no alert() \u2500\u2500\u2500 *\/\r\n        showToast: function (msg, type) {\r\n            var container = document.getElementById('pth-recorder-toast');\r\n            if (!container) return;\r\n            var toast = document.createElement('div');\r\n            toast.className = 'pth-toast-msg pth-toast-' + (type || 'info');\r\n            toast.textContent = msg;\r\n            container.appendChild(toast);\r\n            setTimeout(function () {\r\n                if (toast.parentNode) toast.parentNode.removeChild(toast);\r\n            }, 3500);\r\n        }\r\n    };\r\n\r\n    \/* =======================================================\r\n       BOOTSTRAP \u2014 WP\/LiteSpeed 4-layer safe init (v3.0)\r\n       ======================================================= *\/\r\n    function runInit() {\r\n        if (!window.pthScreenRecorderApp.initialized &&\r\n            document.getElementById('pth-recorder-wrapper')) {\r\n            window.pthScreenRecorderApp.initialized = true;\r\n            window.pthScreenRecorderApp.init();\r\n        }\r\n    }\r\n\r\n    \/* Layer 1: Immediate *\/\r\n    runInit();\r\n\r\n    \/* Layer 2: DOMContentLoaded *\/\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', runInit);\r\n    }\r\n\r\n    \/* Layer 3: window.load + 50ms *\/\r\n    window.addEventListener('load', function () { setTimeout(runInit, 50); });\r\n\r\n    \/* Layer 4: MutationObserver \u2014 async Woody injection *\/\r\n    if (!window.pthScreenRecorderApp.initialized && typeof MutationObserver !== 'undefined') {\r\n        var pthObs = new MutationObserver(function () {\r\n            if (document.getElementById('pth-recorder-wrapper')) {\r\n                pthObs.disconnect();\r\n                runInit();\r\n            }\r\n        });\r\n        pthObs.observe(document.body || document.documentElement, { childList: true, subtree: true });\r\n        setTimeout(function () { pthObs.disconnect(); }, 10000);\r\n    }\r\n\r\n})();\r\n<\/script>\r\n\r\n<!-- FFmpeg WASM \u2014 loaded separately in WP header (Woody Snippet location: header) -->\r\n<!-- Load via: <script src=\"https:\/\/unpkg.com\/@ffmpeg\/ffmpeg@0.11.6\/dist\/ffmpeg.min.js\" data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\"><\/script> -->\n\n\n\n<div id=\"start-seo-article\"><\/div>\n\n\n\n<style>\n.pth-feature-wrap {\n    display: grid;\n    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));\n    gap: 20px; margin-bottom: 30px;\n}\n.pth-feat-box {\n    border: 1px solid #e2e8f0; background: #ffffff;\n    padding: 24px; border-radius: 12px;\n    box-shadow: 0 4px 6px -1px rgba(0,0,0,0.02);\n    transition: all 0.3s ease;\n}\n.pth-feat-box:hover {\n    border-color: #bfdbfe; transform: translateY(-3px);\n    box-shadow: 0 10px 15px -3px rgba(0,0,0,0.05);\n}\n.pth-feat-title {\n    font-size: 1.05rem; font-weight: 800; color: #0f172a;\n    margin-bottom: 10px; display: flex; align-items: center; gap: 10px;\n}\n.pth-feat-text { font-size: 0.9rem; color: #1e293b; line-height: 1.6; margin: 0; font-weight: 500; }\n.pth-steps-wrap {\n    border: 1px solid #e2e8f0; background: #ffffff;\n    padding: 40px 30px; border-radius: 16px;\n    text-align: center;\n    box-shadow: 0 4px 6px -1px rgba(0,0,0,0.02);\n    margin-bottom: 40px;\n}\n.pth-steps-title {\n    font-size: 1.2rem; font-weight: 800; color: #0f172a;\n    text-transform: uppercase; margin-bottom: 35px; letter-spacing: 1px;\n}\n.pth-steps-grid {\n    display: grid;\n    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n    gap: 30px;\n}\n.pth-step-item { display: flex; flex-direction: column; align-items: center; }\n.pth-step-num {\n    width: 45px; height: 45px; background: #2563eb; color: #ffffff;\n    border-radius: 50%; display: flex; align-items: center;\n    justify-content: center; font-weight: 800; font-size: 1.2rem;\n    margin-bottom: 15px; box-shadow: 0 4px 10px rgba(37,99,235,0.3);\n}\n.pth-step-name { font-weight: 800; color: #0f172a; margin-bottom: 8px; font-size: 1rem; }\n.pth-step-desc { font-size: 0.9rem; color: #1e293b; line-height: 1.5; margin: 0; font-weight: 500; }\n<\/style>\n\n<div class=\"pth-feature-wrap\">\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udfe2 4K Screen + Webcam PiP<\/div>\n        <p class=\"pth-feat-text\">Capture your full screen at 1080p, 4K UHD, or 720p \u2014 your choice. Tick the Webcam PiP Overlay checkbox and a circular webcam bubble appears. Move it to any of four corners: top-left, top-right, bottom-left, or bottom-right. Perfect for tutorial recordings where face context matters.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udd35 Custom Watermark + Session History<\/div>\n        <p class=\"pth-feat-text\">Type any text into the Watermark field \u2014 your domain, brand name, or channel handle \u2014 and it burns onto the preview overlay instantly. Every recording you make in the same browser session stacks in the Session History sidebar, each with its duration and file size, ready to re-download without re-recording.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udfe3 Built-in Video Trimmer + MP4 Export<\/div>\n        <p class=\"pth-feat-text\">After stopping, click &#8220;\u2702 Trim Video&#8221; to open the built-in trimmer. Set a Start Time and End Time in MM:SS format \u2014 the player auto-fills the end with the exact recording duration. Choose MP4 H.264 for universal playback (VLC, Windows Media Player) or WebM for fast web use. FFmpeg WASM handles the re-encode entirely inside your browser.<\/p>\n    <\/div>\n<\/div>\n\n<div class=\"pth-steps-wrap\">\n    <div class=\"pth-steps-title\">How to Use Screen Recorder Studio<\/div>\n    <div class=\"pth-steps-grid\">\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">1<\/div>\n            <div class=\"pth-step-name\">Configure Sources<\/div>\n            <p class=\"pth-step-desc\">Under Media Sources, tick Record Microphone and\/or Capture System Audio. Tick Webcam PiP Overlay to enable the circular face cam \u2014 then pick a corner position from the sidebar. Set your Resolution (1080p\/4K\/720p) and Format (WebM or MP4).<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">2<\/div>\n            <div class=\"pth-step-name\">Start Recording<\/div>\n            <p class=\"pth-step-desc\">Click &#8220;\u25b6 Start Recording.&#8221; A 3-second countdown runs. Your browser then shows a screen-picker dialog \u2014 select Entire Screen, a specific Window, or a Browser Tab. Confirm, and the red REC indicator appears with a live HH:MM:SS timer. Recording begins immediately.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">3<\/div>\n            <div class=\"pth-step-name\">Pause or Stop<\/div>\n            <p class=\"pth-step-desc\">Hit &#8220;\u23f8 Pause&#8221; mid-recording \u2014 the indicator turns amber and shows PAUSED. Click &#8220;\u25b6 Resume&#8221; to continue. When done, click &#8220;\u23f9 Stop &amp; Save.&#8221; The recording is packaged into a Blob in your browser RAM. Duration and file size appear instantly in the result area.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">4<\/div>\n            <div class=\"pth-step-name\">Download or Trim<\/div>\n            <p class=\"pth-step-desc\">Click &#8220;\u2b07 Download Video&#8221; for the raw file. Or click &#8220;\u2702 Trim Video&#8221; to open the trimmer \u2014 set Start\/End times, choose your export format, and hit &#8220;\u2699 Process Trim.&#8221; Once FFmpeg finishes, the trimmed file loads in the preview player and &#8220;\u2b07 Download Trimmed&#8221; appears.<\/p>\n        <\/div>\n    <\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Last updated: June 2026<\/p>\n\n\n\n<h2 id=\"\ud83d\udd34-how-browser-based-screen-recording-actually-works\" class=\"wp-block-heading\">\ud83d\udd34 <strong>How Browser-Based Screen Recording Actually Works<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Most people assume screen recording requires a desktop app. OBS, Camtasia, Bandicam \u2014 all installed software that hooks into the OS at the driver level. Browser-based recording works completely differently. It uses the <code>MediaDevices.getDisplayMedia()<\/code> API, a W3C standard that lets a web page request access to your screen stream directly through the browser sandbox. No installation. No driver. No admin rights. <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/MediaDevices\/getDisplayMedia\" rel=\"noreferrer noopener\" target=\"_blank\">MDN&#8217;s getDisplayMedia documentation<\/a> covers the full spec \u2014 it&#8217;s supported in Chrome 72+, Edge 79+, and Firefox 66+.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When you click Start Recording here, the browser opens a native OS picker dialog \u2014 the same system-level UI you see for file uploads, but for display surfaces. You choose an Entire Screen, a specific application Window, or a Browser Tab. The browser packages that visual stream into a <code>MediaStream<\/code> object, which then feeds into a <code>MediaRecorder<\/code>. Every second (1000ms interval), a data chunk is pushed into an array. When you click Stop, those chunks merge into a single <code>Blob<\/code> and a temporary <code>blob:\/\/<\/code> URL is created for download. The video never touches a server. It lives in your browser&#8217;s RAM from start to finish.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Audio capture works in parallel. System audio comes from the <code>displayMedia<\/code> request itself \u2014 when you tick Capture System Audio, the browser asks the OS to include the audio track from whichever display surface you picked. Microphone audio comes from a separate <code>getUserMedia()<\/code> call with <code>echoCancellation: true<\/code> and <code>noiseSuppression: true<\/code> applied. Both audio tracks get merged into the same <code>MediaStream<\/code> alongside the video track before <code>MediaRecorder<\/code> starts. This is why you need headphones when recording both \u2014 without them, the mic picks up system audio output and you get an echo loop.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe1-the-f-fmpeg-wasm-trimmer-whats-happening-inside-your-browser\" class=\"wp-block-heading\">\ud83d\udfe1 <strong>The FFmpeg WASM Trimmer \u2014 What&#8217;s Happening Inside Your Browser<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The built-in trimmer is not a simple JavaScript slice operation. It runs <strong>FFmpeg<\/strong> \u2014 the same command-line video processing engine used in professional broadcast workflows \u2014 compiled to <a href=\"https:\/\/en.wikipedia.org\/wiki\/WebAssembly\" rel=\"noreferrer noopener\" target=\"_blank\">WebAssembly (WASM)<\/a>. On first use, the browser downloads a ~30MB FFmpeg core binary from a CDN. After that, the entire encode-decode-remux pipeline runs locally inside a WASM sandbox. No video data leaves your machine at any point during trimming.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Two export modes behave very differently. WebM stream copy (<code>-c copy<\/code>) is extremely fast \u2014 FFmpeg just cuts the container at keyframe boundaries without decoding a single frame. The downside is accuracy; cuts can only land on I-frames, so the trim point might be off by half a second. MP4 H.264 export uses full re-encoding with <code>libx264 -preset ultrafast -pix_fmt yuv420p<\/code>. This is slower, but the output plays in every media player without codec issues \u2014 VLC, Windows Media Player, QuickTime, phones. If your raw WebM won&#8217;t open in a standard player, use the MP4 export path. The <code>yuv420p<\/code> pixel format flag specifically solves the green-tint or black-screen playback bug that appears when chroma subsampling doesn&#8217;t match what the player expects.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe2-webcam-pi-p-positioning-and-stream-handling\" class=\"wp-block-heading\">\ud83d\udfe2 <strong>Webcam PiP \u2014 Positioning and Stream Handling<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The Picture-in-Picture webcam works through a second simultaneous <code>getUserMedia()<\/code> stream. When you tick Webcam PiP Overlay, the tool requests <code>{video: true, audio: false}<\/code> \u2014 audio is explicitly excluded from the webcam stream to avoid duplicating the mic input. The webcam video feeds into a circular <code>&lt;video&gt;<\/code> element positioned absolutely over the screen preview using CSS. You pick the corner from the sidebar: top-left, top-right, bottom-left, or bottom-right. The position changes class on the element (<code>pth-pip-tl<\/code>, <code>pth-pip-tr<\/code>, etc.) instantly via JavaScript \u2014 no re-initialisation needed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One important note: the webcam overlay you see in the browser preview is a <em>visual representation<\/em>. The actual video file captured by <code>MediaRecorder<\/code> records only the screen stream \u2014 the webcam circle is not composited into the recording file itself. To burn the webcam into the final video, you&#8217;d need canvas-based compositing, which is a heavier operation. For most tutorial use cases \u2014 where the webcam is shown on-screen as part of the presenter&#8217;s actual screen layout \u2014 simply having the webcam open in a browser window while recording the full screen achieves the same result naturally. Our Video Merger &amp; Trimmer tool can combine separate screen and webcam recordings if you need true compositing. You can also read more about audio and video sync techniques in our <a href=\"https:\/\/schoolict.net\/tools\/free-screen-recorder-and-trimmer\/\">complete screen capture guide<\/a>.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe2-resolution-format-and-what-actually-affects-file-size\" class=\"wp-block-heading\">\ud83d\udfe2 <strong>Resolution, Format, and What Actually Affects File Size<\/strong><\/h3>\n\n\n<figure class=\"pth-article-figure pth-img-left\" style=\"float:left; width:600px; max-width:100%; margin:4px 28px 16px 0; clear:left;\"><img decoding=\"async\" src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/06\/screen-recorder-api-flow-diagram-800x447.jpeg\" alt=\"screen-recorder-api-flow-diagram\" width=\"600\" height=\"338\" loading=\"lazy\" data-no-lazy=\"1\" class=\"pth-article-img\" style=\"width:100%;height:auto;display:block;border-radius:10px;border:1px solid #e2e8f0;\"><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The Resolution setting sends a <code>width: {ideal: W}, height: {ideal: H}<\/code> constraint to <code>getDisplayMedia()<\/code>. It&#8217;s a hint, not a guarantee. If your monitor&#8217;s native resolution is 1920\u00d71080, requesting 4K UHD still caps at the display&#8217;s actual output. The browser honours the constraint only up to the physical display limit. Frame rate defaults to 30fps via <code>frameRate: {ideal: 30}<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Format choice directly controls the <code>MediaRecorder<\/code> MIME type. WebM VP9 produces the smallest files for a given quality \u2014 typically 3\u20138 MB per minute for a 1080p screen recording of mostly static content like code or documents. Fast motion (games, animations) will be larger. MP4 H.264 from the trimmer is re-encoded, so file size depends on the encoding parameters. With <code>-preset ultrafast<\/code>, files are slightly larger than a careful VP9 encode but process in seconds rather than minutes. Key points:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ud83d\udd35 <strong>WebM VP9<\/strong> \u2014 best for sharing on the web, Google Drive, or re-uploading to YouTube. Smallest file, Chrome\/Firefox native support.<\/li>\n\n\n\n<li>\ud83d\udfe0 <strong>MP4 H.264 (from trimmer)<\/strong> \u2014 best for sending to clients, playing on Windows\/Mac without extra codecs, or importing into video editors like DaVinci Resolve or Premiere.<\/li>\n\n\n\n<li>\ud83d\udfe3 <strong>Session History<\/strong> \u2014 every recording stays accessible as a Blob URL until you close or refresh the tab. The sidebar shows take number, duration, and size so you can compare multiple takes and download the best one.<\/li>\n<\/ul>\n\n\n\n<h2 id=\"\ud83d\udfe1-privacy-and-security-what-the-tool-can-and-cannot-access\" class=\"wp-block-heading\">\ud83d\udfe1 <strong>Privacy and Security \u2014 What the Tool Can and Cannot Access<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Browser screen capture is sandboxed at multiple levels. The <code>getDisplayMedia()<\/code> API requires explicit user gesture \u2014 a button click \u2014 before the OS picker opens. The browser cannot call it silently or on page load. The OS picker is drawn by the operating system itself, not by any web page code, which means a malicious page cannot spoof or intercept it. You choose exactly what to share.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This tool has zero network requests for your video data. The JavaScript source is hosted on this page. FFmpeg WASM loads from a CDN once and cached. After that, trim operations run offline. You can test this yourself: open DevTools \u2192 Network tab \u2192 start a recording \u2192 stop and trim. You&#8217;ll see zero POST requests, zero file uploads, zero WebSocket connections carrying your video. The Blob URL created after recording is a local browser memory reference \u2014 it&#8217;s revoked and freed when you navigate away or click New Recording.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One real security consideration: system audio capture in Chrome on Windows captures the audio of every application, not just the one you&#8217;re recording. If you have a notification sound, a private call, or sensitive audio in another app during recording, it will be included. Plan your recording environment accordingly. Muting all non-essential applications or using a dedicated browser profile for recording sessions is good practice.<\/p>\n\n\n\n<style>\n.pth-faq-section { margin-top: 50px; margin-bottom: 40px; font-family: inherit; }\n.pth-faq-header {\n    font-size: 1.8rem; font-weight: 800; color: #0f172a;\n    margin-bottom: 25px; border-bottom: 2px solid #e2e8f0;\n    padding-bottom: 10px; display: flex; align-items: center; gap: 10px;\n}\n.pth-faq-grid { display: grid; grid-template-columns: 100%; gap: 20px; }\n@media (min-width: 768px)  { .pth-faq-grid { grid-template-columns: repeat(2, 1fr); } }\n@media (min-width: 1024px) { .pth-faq-grid { grid-template-columns: repeat(3, 1fr); } }\n.pth-faq-card {\n    background: #f8fafc; padding: 24px; border-radius: 12px;\n    border: 1px solid #e2e8f0; transition: transform 0.2s ease; break-inside: avoid;\n}\n.pth-faq-card:hover { transform: translateY(-3px); box-shadow: 0 4px 12px rgba(0,0,0,0.05); }\n.pth-faq-q { color: #0f172a; font-size: 1rem; font-weight: 700; margin: 0 0 12px; line-height: 1.4; }\n.pth-faq-a { margin: 0; font-size: 0.95rem; color: #1e293b; line-height: 1.6; font-weight: 500; }\n<\/style>\n\n<div class=\"pth-faq-section\">\n    <div class=\"pth-faq-header\">\ud83e\udd14 Frequently Asked Questions<\/div>\n    <div class=\"pth-faq-grid\">\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">Does the webcam PiP actually get recorded into the video file?<\/p>\n            <p class=\"pth-faq-a\">The webcam overlay shown in the browser preview is a live CSS element \u2014 it&#8217;s not composited into the MediaRecorder output file. To include your face cam in the recording, open your webcam in a separate browser window and position it on-screen before capturing your full screen. That way it appears naturally inside the recorded area.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">Why does the trimmer take a long time on the first use?<\/p>\n            <p class=\"pth-faq-a\">The first trim operation downloads the FFmpeg WebAssembly core (~30MB) from a CDN. This is a one-time download per browser session \u2014 subsequent trims in the same session start immediately. If you&#8217;re on a slow connection, the log panel shows &#8220;Loading FFmpeg core\u2026&#8221; while it downloads. The trim itself is very fast once the engine is loaded.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">My recorded WebM file won&#8217;t play in VLC or Windows Media Player. How do I fix it?<\/p>\n            <p class=\"pth-faq-a\">Open the built-in trimmer, set Start Time to 00:00 and End Time to the full duration (auto-filled), and select &#8220;MP4 H.264 \u2014 Best Compatibility&#8221; as the export format. Click Process Trim. The FFmpeg engine re-encodes the file to H.264\/YUV420P, which plays in every media player without needing extra codecs.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">Can I record just a single browser tab instead of the entire screen?<\/p>\n            <p class=\"pth-faq-a\">Yes. When the browser&#8217;s screen-picker dialog opens after clicking Start Recording, switch to the &#8220;Tab&#8221; option at the top of the dialog. Select the specific tab you want to capture. Note that tab capture does not include system audio \u2014 only the audio from that tab is available. Microphone audio still works normally.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">Is there a recording time limit?<\/p>\n            <p class=\"pth-faq-a\">No hard time limit is enforced by the tool. The practical limit is your device&#8217;s available RAM \u2014 video chunks accumulate in browser memory during recording. A typical 1080p screen recording uses roughly 3\u20138 MB per minute. On most modern devices with 8GB+ RAM, you can record comfortably for 30\u201360 minutes before memory becomes a concern.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">Does the tool work on Safari or iOS?<\/p>\n            <p class=\"pth-faq-a\">Safari on macOS supports getDisplayMedia from Safari 13+ but with limited audio capture. Safari on iOS does not support screen capture at all \u2014 Apple restricts getDisplayMedia on iOS. Use Chrome 72+, Edge 79+, or Firefox 66+ on desktop for full functionality including system audio and webcam PiP.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">What happens to my recordings if I close the browser tab?<\/p>\n            <p class=\"pth-faq-a\">All recordings exist as Blob URLs in browser memory only. Closing or refreshing the tab permanently destroys them \u2014 there is no server backup or local file auto-save. Always download your recordings before navigating away. The Session History sidebar shows all takes from the current session so you don&#8217;t miss one.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">Can I record my screen with background music without echo?<\/p>\n            <p class=\"pth-faq-a\">Tick Capture System Audio to include computer audio (music, app sounds). If you also tick Record Microphone, wear headphones \u2014 the microphone has echo cancellation enabled, but it can&#8217;t fully cancel loud system audio played through speakers. With headphones, microphone and system audio are captured cleanly on separate tracks merged into one stream.<\/p>\n        <\/div>\n\n        <div class=\"pth-faq-card\">\n            <p class=\"pth-faq-q\">How is this different from the Windows built-in Game Bar recorder (Win+G)?<\/p>\n            <p class=\"pth-faq-a\">Windows Game Bar only records the active application window \u2014 it can&#8217;t capture the full desktop or multiple windows at once. This screen recorder captures any display surface: full screen, specific app window, or browser tab. It also adds webcam PiP, a built-in video trimmer with MP4 export, custom watermark, and session history \u2014 all inside the browser without any OS-level installation.<\/p>\n        <\/div>\n\n    <\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Screen Recorder Studio | Free offline Video Capture &amp; Trimmer Professional offline screen recorder by Prime Tool Hub. Capture your screen, microphone, system audio, and webcam locally. Includes a built-in video trimmer. \ud83d\udfe2 4K Screen + Webcam PiP Capture your full screen at 1080p, 4K UHD, or 720p \u2014 your choice. Tick the Webcam PiP &#8230; <a title=\"Screen Recorder Studio | Free offline Video Capture &amp; Trimmer\" class=\"read-more\" href=\"https:\/\/schoolict.net\/tools\/screen-recorder-studio\/\" aria-label=\"Read more about Screen Recorder Studio | Free offline Video Capture &amp; Trimmer\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":4529,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-999","page","type-page","status-publish","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/999","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/comments?post=999"}],"version-history":[{"count":0,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/999\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media\/4529"}],"wp:attachment":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media?parent=999"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}