/
vitol
/
camera
Обзор
Документация
Войти
/
vitol
/
camera
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
index.html
625 строк
55 KB
vitol
Create: index.html
20 июн 2026, 11:04
Верифицирован
20 июн 2026, 11:04
39cb63f
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="Простой курс: как красиво фотографировать на айфон — свет, экспозиция, фокус и композиция понятным языком."> <meta name="theme-color" content="#2a2632"> <title>Фотошкола на айфоне</title> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,600;0,700;0,800;1,600&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"> <style> :root{ --bg1:#f5f2ea; --bg2:#ece6da; --ink:#262129; --soft:#7c7686; --purple:#a87c3e; --purple2:#c49a58; /* тёплый золотой акцент */ --coral:#b66a4c; --green:#3f7d63; --amber:#b88a3c; --teal:#3f7d7d; --deep:#2a2530; --deep2:#3d3543; /* благородный тёмный */ --card:#fffdf8; --line:#e9e2d4; --shadow:0 22px 54px rgba(54,40,18,.10); --radius:22px; --serif:'Playfair Display',Georgia,'Times New Roman',serif; } *{box-sizing:border-box;-webkit-tap-highlight-color:transparent;} html,body{margin:0;padding:0;} body{ font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif; color:var(--ink); font-size:19px; line-height:1.6; letter-spacing:.004em; background: radial-gradient(1100px 560px at 82% -12%, #fcf7ec 0%, rgba(252,247,236,0) 62%), linear-gradient(162deg,var(--bg1),var(--bg2)); background-attachment:fixed; min-height:100vh; } .wrap{max-width:760px;margin:0 auto;padding:18px 18px 96px;} .topbar{ position:sticky;top:0;z-index:50;display:flex;align-items:center;gap:12px; padding:14px 16px;margin:-18px -18px 18px; background:rgba(250,247,240,.82);backdrop-filter:blur(14px);border-bottom:1px solid var(--line); } .topbar .brand{font-family:var(--serif);font-weight:700;font-size:20px;color:var(--deep);display:flex;align-items:center;gap:9px;letter-spacing:.01em;} .topbar .spacer{flex:1;} .home-btn{border:1px solid #e3dccb;background:#fffdf8;color:var(--deep);font-weight:600;font-family:inherit;font-size:16px;padding:10px 16px;border-radius:12px;cursor:pointer;display:none;align-items:center;gap:7px;} .home-btn:active{transform:scale(.96);} .btn{font-family:inherit;font-weight:600;font-size:19px;cursor:pointer;border:none;border-radius:14px;padding:15px 24px;transition:transform .08s ease, box-shadow .25s, background .2s;display:inline-flex;align-items:center;justify-content:center;gap:10px;letter-spacing:.01em;} .btn:active{transform:scale(.97);} .btn-primary{background:linear-gradient(135deg,var(--deep),var(--deep2));color:#f6efe1;box-shadow:0 14px 30px rgba(42,37,48,.26);} .btn-ghost{background:#fffdf8;color:var(--deep);border:1.5px solid #e1dac8;} .btn-big{width:100%;font-size:21px;padding:18px;} .btn-coral{background:linear-gradient(135deg,#caa162,#a87c3e);color:#fff;box-shadow:0 14px 28px rgba(168,124,62,.28);} /* hero */ .hero{ background: radial-gradient(620px 300px at 78% 6%, rgba(206,164,96,.30), rgba(206,164,96,0) 62%), linear-gradient(152deg,#2a2530 0%, #382f3c 56%, #4a3b3d 100%); color:#f3ebdd;border-radius:var(--radius);padding:42px 30px;margin-bottom:20px; box-shadow:0 26px 64px rgba(38,28,38,.30);position:relative;overflow:hidden;text-align:center; border:1px solid rgba(255,255,255,.06); } .hero h1{font-family:var(--serif);font-size:42px;line-height:1.08;margin:8px 0 14px;font-weight:700;letter-spacing:.01em;} .hero p{font-size:19px;margin:0 auto 26px;opacity:.9;max-width:32ch;line-height:1.55;} .hero .emoji{font-size:26px;display:inline-block;margin-bottom:4px;opacity:.92;letter-spacing:.4em;} .hero .bubbles{position:absolute;inset:0;pointer-events:none;} .hero .bubbles span{position:absolute;border-radius:50%;background:rgba(255,255,255,.05);} .b1{width:170px;height:170px;top:-60px;right:-50px;} .b2{width:100px;height:100px;bottom:-36px;left:-26px;} .b3{width:48px;height:48px;top:28px;left:26px;} /* tabs */ .tabs{display:flex;gap:6px;background:#fffdf8;padding:6px;border-radius:16px;margin-bottom:20px;box-shadow:0 10px 26px rgba(54,40,18,.07);border:1px solid var(--line);} .tab{flex:1;font-family:inherit;font-weight:600;font-size:15.5px;border:none;background:transparent;color:var(--soft);padding:13px 6px;border-radius:12px;cursor:pointer;transition:all .18s;line-height:1.2;} .tab.active{background:linear-gradient(135deg,var(--deep),var(--deep2));color:#f6efe1;box-shadow:0 10px 20px rgba(42,37,48,.22);} .tab .te{display:block;font-size:20px;margin-bottom:2px;} .panel{display:none;} .panel.active{display:block;animation:fade .25s ease;} @keyframes fade{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:none;}} .progress-home{background:#fffdf8;border:1px solid var(--line);border-radius:16px;padding:14px 18px;margin-bottom:18px;display:flex;align-items:center;gap:14px;box-shadow:0 10px 26px rgba(54,40,18,.06);} .progress-home .ring{font-size:22px;} .bar{flex:1;height:11px;background:#ece4d4;border-radius:10px;overflow:hidden;} .bar > i{display:block;height:100%;background:linear-gradient(90deg,var(--purple),var(--coral));width:0;transition:width .5s ease;border-radius:10px;} .progress-home b{font-weight:700;color:var(--deep);white-space:nowrap;} .section-title{font-family:var(--serif);font-size:26px;font-weight:700;margin:8px 4px 12px;letter-spacing:.01em;} .section-sub{color:var(--soft);font-weight:500;font-size:16.5px;margin:-4px 4px 18px;} .lessons{display:grid;grid-template-columns:1fr 1fr;gap:13px;} @media(max-width:560px){.lessons{grid-template-columns:1fr;}} .lcard{background:var(--card);border-radius:18px;padding:18px;cursor:pointer;box-shadow:0 12px 28px rgba(54,40,18,.06);border:1px solid var(--line);transition:transform .1s,border-color .2s,box-shadow .2s;display:flex;gap:14px;align-items:center;position:relative;} .lcard:active{transform:scale(.98);} .lcard:hover{border-color:#ddd3bd;box-shadow:0 18px 36px rgba(54,40,18,.12);} .lcard .num{flex:none;width:46px;height:46px;border-radius:13px;display:grid;place-items:center;font-family:var(--serif);font-weight:700;font-size:21px;background:#f4ecdc;color:var(--purple);} .lcard.done .num{background:linear-gradient(135deg,var(--green),#5c9a7e);color:#fff;} .lcard .l-emoji{font-size:25px;flex:none;} .lcard .l-title{font-weight:700;font-size:17px;line-height:1.28;} .lcard .l-sub{font-size:13.5px;color:var(--soft);font-weight:500;margin-top:2px;} .lcard .check{position:absolute;top:9px;right:11px;font-size:17px;display:none;} .lcard.done .check{display:block;} /* lesson view */ .lesson{display:none;} .lesson.active{display:block;animation:fade .3s ease;} .l-progress{font-weight:600;color:var(--soft);font-size:15px;margin:2px 4px 12px;display:flex;align-items:center;gap:10px;letter-spacing:.02em;} .l-head{background:linear-gradient(140deg,#fbf5ea,#fdf2ec);border-radius:var(--radius);padding:30px 24px;text-align:center;margin-bottom:16px;border:1px solid var(--line);} .l-head .big-emoji{font-size:46px;display:block;line-height:1;margin-bottom:12px;} .l-head h2{font-family:var(--serif);font-size:29px;font-weight:700;margin:0 0 10px;letter-spacing:.01em;} .l-head .intro{font-size:18.5px;color:#4c4756;margin:0;line-height:1.55;} .listen{margin:0 auto 6px;display:flex;justify-content:center;} .listen .btn{font-size:18px;padding:13px 24px;} .listen-hint{text-align:center;color:var(--soft);font-weight:500;font-size:14.5px;margin:9px 0 18px;} .block{background:var(--card);border:1px solid var(--line);border-radius:18px;padding:22px;margin-bottom:14px;box-shadow:0 12px 28px rgba(54,40,18,.05);} .block p{margin:0 0 12px;font-size:19px;} .block p:last-child{margin-bottom:0;} .block-label{font-size:12px;font-weight:700;color:var(--purple);text-transform:uppercase;letter-spacing:.16em;margin-bottom:14px;} .compare{display:grid;gap:12px;} .cmp{border-radius:14px;padding:16px;} .cmp .tag{display:inline-flex;align-items:center;gap:7px;font-weight:700;font-size:13px;text-transform:uppercase;letter-spacing:.06em;padding:5px 12px;border-radius:8px;margin-bottom:10px;} .cmp.bad{background:#faf0ed;border:1px solid #ebd2cb;} .cmp.bad .tag{background:#eed9d2;color:#9c4d3c;} .cmp.good{background:#eef4ee;border:1px solid #cfe2d3;} .cmp.good .tag{background:#d6e7d9;color:#3f7d63;} .cmp .txt{font-size:18px;font-weight:600;} .cmp.good .txt{color:#356a53;} .cmp-note{background:#fbf4e5;border:1px solid #ecdcb4;border-radius:12px;padding:13px 16px;font-size:17px;font-weight:500;margin-top:2px;} .cmp-note b{color:var(--purple);} .formula{display:grid;grid-template-columns:1fr 1fr;gap:11px;} @media(max-width:520px){.formula{grid-template-columns:1fr;}} .fcard{border-radius:14px;padding:15px;border:1px solid var(--line);background:#faf6ed;} .fcard .fe{font-size:25px;} .fcard .ft{font-weight:700;font-size:16px;margin:6px 0 3px;color:var(--purple);} .fcard .fd{font-size:15.5px;color:#5a5566;font-weight:500;} .cards{display:grid;gap:11px;} .icard{display:flex;gap:14px;align-items:flex-start;background:#faf6ed;border:1px solid var(--line);border-radius:14px;padding:16px;} .icard .ie{font-size:25px;flex:none;line-height:1.1;} .icard .it{font-weight:700;font-size:17.5px;margin-bottom:3px;} .icard .id{font-size:16.5px;color:#5a5566;font-weight:500;line-height:1.5;} /* steps */ .steps{display:grid;gap:10px;} .step{display:flex;gap:14px;align-items:flex-start;background:#faf6ed;border:1px solid var(--line);border-radius:14px;padding:15px;} .step .sn{flex:none;width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,var(--deep),var(--deep2));color:#f3ebdd;font-family:var(--serif);font-weight:700;display:grid;place-items:center;font-size:16px;} .step .stx{font-size:17.5px;font-weight:500;color:#3c3845;align-self:center;line-height:1.5;} .quiz .q{font-weight:700;font-size:19px;margin-bottom:14px;} .opt{width:100%;text-align:left;font-family:inherit;font-weight:600;font-size:17.5px;background:#faf6ed;border:1.5px solid var(--line);border-radius:13px;padding:15px 17px;margin-bottom:11px;cursor:pointer;transition:transform .08s,border-color .2s,background .2s;display:flex;gap:11px;align-items:center;} .opt:active{transform:scale(.99);} .opt .mark{font-size:20px;} .opt.correct{background:#eef4ee;border-color:var(--green);} .opt.wrong{background:#faf0ed;border-color:var(--coral);} .quiz-why{display:none;background:#faf4e6;border:1px solid #ecdcb4;border-radius:13px;padding:13px 17px;font-size:16.5px;font-weight:500;margin-top:2px;line-height:1.5;} .quiz-why.show{display:block;} .mini{flex:none;border:1px solid #e7ddc7;background:#f5eedd;color:var(--deep);font-size:16px;height:42px;border-radius:11px;cursor:pointer;display:inline-grid;place-items:center;transition:transform .08s;padding:0 16px;gap:6px;font-weight:600;font-family:inherit;} .mini:active{transform:scale(.92);} /* accordion problems */ .prob{background:#fffdf8;border-radius:16px;margin-bottom:11px;box-shadow:0 10px 26px rgba(54,40,18,.06);overflow:hidden;border:1px solid var(--line);transition:border-color .2s;} .prob.open{border-color:#ddd3bd;} .prob-head{display:flex;align-items:center;gap:12px;padding:17px 18px;cursor:pointer;font-weight:600;font-size:17.5px;} .prob-head .pe{font-size:23px;flex:none;} .prob-head .arrow{margin-left:auto;font-size:17px;color:var(--soft);transition:transform .25s;flex:none;} .prob.open .prob-head .arrow{transform:rotate(180deg);} .prob-body{display:none;padding:0 18px 18px;} .prob.open .prob-body{display:block;animation:fade .25s ease;} .prob-body .cause{background:#faf0ed;border-radius:11px;padding:12px 14px;font-size:16px;font-weight:500;color:#9c4d3c;margin-bottom:9px;line-height:1.5;} .prob-body .fix{background:#eef4ee;border-radius:11px;padding:12px 14px;font-size:16.5px;font-weight:500;color:#356a53;margin-bottom:9px;line-height:1.5;} .prob-body .ex{background:#fbf4e5;border:1px solid #ecdcb4;color:#7a5b24;border-radius:11px;padding:12px 14px;font-size:16px;font-weight:500;line-height:1.5;} .prob-body .ex .copytext{font-weight:600;} .prob-actions{display:flex;gap:8px;margin-top:10px;} .prob-actions .mini{height:40px;font-size:14.5px;} .tip{background:linear-gradient(135deg,#fbf4e5,#fdf2ec);border:1px solid #ecdcb4;border-radius:16px;padding:18px 20px;display:flex;gap:14px;align-items:flex-start;margin-bottom:14px;} .tip .ti{font-size:25px;flex:none;} .tip .tx{font-size:17.5px;font-weight:500;color:#6f5526;line-height:1.55;} .lnav{display:flex;gap:11px;margin-top:8px;} .lnav .btn{flex:1;} .done-btn{margin-bottom:13px;} .finish{text-align:center;color:#f3ebdd;border-radius:var(--radius);padding:38px 26px;box-shadow:0 26px 64px rgba(38,28,38,.30);border:1px solid rgba(255,255,255,.06); background: radial-gradient(560px 280px at 80% 0, rgba(206,164,96,.28), rgba(206,164,96,0) 62%), linear-gradient(150deg,#2a2530,#453a4b);} .finish .big-emoji{font-size:54px;display:block;margin-bottom:10px;} .finish h2{font-family:var(--serif);font-size:31px;margin:0 0 12px;font-weight:700;letter-spacing:.01em;} .finish p{font-size:18px;margin:0 0 8px;opacity:.92;line-height:1.55;} .toast{position:fixed;left:50%;bottom:24px;transform:translateX(-50%) translateY(120px);background:#2a2530;color:#f3ebdd;padding:13px 22px;border-radius:30px;font-weight:600;font-size:16px;box-shadow:0 14px 34px rgba(0,0,0,.32);transition:transform .35s;z-index:100;} .toast.show{transform:translateX(-50%) translateY(0);} .footer-note{text-align:center;color:var(--soft);font-size:13.5px;font-weight:500;margin-top:24px;} #resumeRow{margin:-8px 2px 16px;} .rr-note{background:#fffdf8;border:1px solid #e3dccb;border-radius:13px;padding:12px 16px;font-size:15.5px;font-weight:500;color:#4c4756;box-shadow:0 6px 18px rgba(54,40,18,.05);} .rr-note.warn{background:#fbf4e5;border-color:#ecdcb4;color:#6f5526;} .rr-reset{border:none;background:transparent;color:var(--purple);font-family:inherit;font-weight:700;font-size:15.5px;cursor:pointer;text-decoration:underline;padding:0;} .rr-reset:active{opacity:.6;} .cheat-grid{display:grid;gap:11px;} </style> </head> <body> <div class="topbar"> <span class="brand">📸 Фотошкола на айфоне</span> <span class="spacer"></span> <button class="home-btn" id="homeBtn" onclick="goHome()">🏠 На главную</button> </div> <div class="wrap"> <div id="home"> <div class="hero"> <div class="bubbles"><span class="b1"></span><span class="b2"></span><span class="b3"></span></div> <span class="emoji">📸</span> <h1>Снимай красиво<br>на айфон</h1> <p>Дорогая камера уже у тебя в руках. Научимся снимать так, чтобы фото <b>хотелось показывать</b> — простыми шагами.</p> <button class="btn btn-ghost btn-big" id="heroBtn" onclick="startCourse()" style="color:#2a2530;">▶ Начать</button> </div> <div class="tabs"> <button class="tab active" data-tab="lessons" onclick="showTab('lessons')"><span class="te">🎓</span>Уроки</button> <button class="tab" data-tab="problems" onclick="showTab('problems')"><span class="te">🔧</span>Если не вышло</button> <button class="tab" data-tab="cheat" onclick="showTab('cheat')"><span class="te">📋</span>Шпаргалка</button> </div> <!-- LESSONS --> <div class="panel active" id="panel-lessons"> <div class="progress-home"> <span class="ring">🌟</span> <div class="bar"><i id="homeBarFill"></i></div> <b id="homeProgressText">0 из 9</b> </div> <div id="resumeRow"></div> <div class="lessons" id="lessonList"></div> <div class="footer-note">Можно слушать вместо чтения — на каждом уроке есть кнопка 🔊</div> </div> <!-- PROBLEMS --> <div class="panel" id="panel-problems"> <div class="section-title">🔧 Фото не получилось? Найди свой случай</div> <div class="section-sub">Нажми на проблему — внутри причина и что сделать в следующий раз.</div> <div id="problemList"></div> </div> <!-- CHEATSHEET --> <div class="panel" id="panel-cheat"> <div class="section-title">📋 Шпаргалка</div> <div class="section-sub">Загляни сюда перед съёмкой — и фото будут лучше.</div> <div id="cheatBody"></div> </div> </div> <div id="lessonView"></div> </div> <div class="toast" id="toast"></div> <script> /* ===================== ДАННЫЕ ===================== */ const LESSONS = [ { emoji:"💡", title:"Главный секрет — это свет", sub:"С чего всё начинается", intro:"Красивое фото — это почти всегда хороший свет. Дело не в дорогой камере: она у тебя уже отличная. Дело в том, откуда падает свет.", blocks:[ {type:"text", text:["Свет решает больше, чем что угодно ещё. Поверни человека или предмет лицом к свету — и кадр сразу оживает.","Главная ошибка — снимать против яркого окна или солнца: тогда лицо получается тёмным силуэтом. Свет должен падать на сюжет, а не бить в камеру."]}, {type:"compare", bad:"Человек стоит спиной к окну — лицо тёмное, фон пересвечен", good:"Человек повёрнут лицом к свету от окна — лицо светлое и живое", note:"Свет должен освещать того, кого снимаешь, а не бить в объектив сзади."}, {type:"cards", items:[ {e:"🪟", t:"Свет от окна", d:"Дома лучший свет — мягкий, из большого окна. Поставь человека к нему лицом."}, {e:"☁️", t:"Облачный день", d:"Облака как огромный софтбокс: мягко, без резких теней. Отличное время для портретов."}, {e:"🌅", t:"Золотой час", d:"Час после рассвета и перед закатом — тёплый, мягкий свет. Всё выглядит волшебно."}, {e:"🚫", t:"Резкое солнце в полдень", d:"Жёсткие тени, прищуренные глаза. Уйди в тень или подожди вечера."} ]}, {type:"tip", text:"Перед каждым кадром на секунду спроси себя: «Откуда падает свет?» — и поставь человека лицом к нему."} ] }, { emoji:"☀️", title:"Экспозиция: не темно и не пересвечено", sub:"Управляем яркостью пальцем", intro:"Экспозиция — это просто яркость кадра. Айфон выбирает её сам, но часто можно сделать лучше — одним движением пальца.", blocks:[ {type:"text", text:["Иногда камера делает кадр слишком тёмным (лицо в тени) или слишком светлым (белое небо без деталей). Это легко поправить ещё до съёмки."]}, {type:"steps", title:"Как настроить яркость", items:[ "Коснись пальцем главного в кадре (например, лица)", "Рядом появится жёлтый квадратик и маленькое солнышко ☀️", "Веди палец по экрану вверх — становится светлее, вниз — темнее", "Когда нравится — убери палец и нажми на кнопку съёмки" ]}, {type:"compare", bad:"Снег вышел серым, а лицо в тени — тёмным", good:"Чуть подняла солнышко вверх — снег стал белым, лицо хорошо видно", note:"Светлые сюжеты (снег, небо) часто надо чуть осветлить, тёмные — наоборот, притемнить."}, {type:"quiz", q:"Фото получилось слишком тёмным. Что проще всего сделать?", options:[ {t:"Коснуться экрана и повести солнышко ☀️ вверх", correct:true, why:"Верно! Это и есть управление экспозицией — яркость меняется до съёмки одним пальцем."}, {t:"Каждый раз включать вспышку", correct:false, why:"Вспышка часто делает лица плоскими и неприятными. Сначала попробуй поднять экспозицию или найти свет получше."} ]}, {type:"tip", text:"Солнышко вверх = светлее, вниз = темнее. Это первое, что стоит попробовать, если кадр тёмный."} ] }, { emoji:"🎯", title:"Резкость: куда смотрит фокус", sub:"Чиним размытые кадры", intro:"Размытое фото — почти всегда одно из двух: фокус навёлся не туда или дрогнула рука. И то, и другое легко исправить.", blocks:[ {type:"text", text:["Айфон сам решает, что сделать резким. Но ты можешь указать ему точно — просто коснись того, что главное."]}, {type:"steps", title:"Чтобы было резко", items:[ "Коснись пальцем того, что должно быть чётким (лицо, цветок, предмет)", "Появился квадратик — значит, фокус наведён сюда", "Хочешь, чтобы фокус не сбивался? Задержи палец подольше — вверху появится «Фиксация экспозиции/фокуса»", "Держи телефон двумя руками, локти прижми к телу и плавно нажми на съёмку" ]}, {type:"cards", items:[ {e:"🖐️", t:"Дрожь руки", d:"Держи телефон двумя руками, локти к телу. Можно опереться на стол или стену."}, {e:"🏃", t:"Объект движется", d:"Для детей и животных снимай сериями — зажми кнопку, выберешь лучший кадр потом."}, {e:"🧽", t:"Грязный объектив", d:"Отпечатки пальцев — причина №1 мутных фото. Протри стекло о футболку."}, {e:"🌙", t:"Мало света", d:"В темноте камере труднее навестись. Добавь света или используй ночной режим."} ]}, {type:"tip", text:"Протирай объектив перед съёмкой! Звучит просто, но это спасает половину «мутных» фото."} ] }, { emoji:"📐", title:"Композиция: куда поставить главное", sub:"Кадр «как у блогеров»", intro:"Композиция — это куда в кадре поместить главное. Одна маленькая хитрость превращает обычное фото в красивое.", blocks:[ {type:"text", text:["Новички часто ставят человека ровно по центру — и получается скучно. Профи ставят главное чуть в сторону, по «правилу третей». Чтобы это было легко, включи на экране сетку."]}, {type:"steps", title:"Как включить сетку (один раз)", items:[ "Открой «Настройки» на телефоне", "Пролистай вниз и найди «Камера»", "Включи переключатель «Сетка»", "Теперь в камере появятся линии — ставь главное на их пересечения" ]}, {type:"compare", bad:"Человек ровно по центру, сверху много пустого неба, горизонт завален", good:"Человек по боковой линии сетки, горизонт ровный по линии — кадр живой и аккуратный", note:"Ставь главное на пересечение линий, а линию горизонта держи параллельно сетке."}, {type:"quiz", q:"Зачем включать сетку на камере?", options:[ {t:"Чтобы ровно держать горизонт и красиво размещать главное", correct:true, why:"Верно! Сетка помогает не заваливать горизонт и ставить объект по правилу третей."}, {t:"Чтобы фото получалось разрезанным на части", correct:false, why:"Нет, линии видны только тебе на экране — на самом фото их нет."} ]}, {type:"tip", text:"Заваленный горизонт (косая линия моря или пола) сразу выдаёт новичка. Держи его ровно по линии сетки."} ] }, { emoji:"🧍", title:"Портрет с размытым фоном", sub:"Тот самый красивый эффект", intro:"Когда человек чёткий, а фон мягко размыт — это выглядит дорого и профессионально. На айфоне для этого есть режим «Портрет».", blocks:[ {type:"text", text:["Режим «Портрет» сам размывает фон и оставляет человека резким. Работает не только для людей — но и для предметов, цветов и питомцев."]}, {type:"steps", title:"Как снять портрет", items:[ "В камере листай надписи режимов внизу, пока не встанет «Портрет»", "Наведи на человека и отойди на пару шагов (нужно немного расстояния)", "Дождись, пока подсказка станет жёлтой — значит, телефон готов", "Снимай. Фон размоется сам — красиво и мягко" ]}, {type:"cards", items:[ {e:"🎚️", t:"Можно изменить потом", d:"Силу размытия фона легко поправить уже после съёмки в редакторе фото."}, {e:"🐶", t:"Не только люди", d:"Цветок, чашка, кот — на всём этом портретный размытый фон смотрится отлично."}, {e:"💡", t:"Добавь хороший свет", d:"Мягкий свет сбоку или у окна сделает лицо объёмным и живым."} ]}, {type:"tip", text:"Для портрета нужно немного отойти от человека. Слишком близко — телефон попросит отодвинуться."} ] }, { emoji:"🌆", title:"Съёмка вечером и в темноте", sub:"Чтобы не было смазано", intro:"Айфон отлично снимает в темноте — за это отвечает «Ночной режим». Главное правило простое: в этот момент не двигаться.", blocks:[ {type:"text", text:["В темноте камере нужно несколько секунд, чтобы собрать свет. Поэтому появляется значок луны 🌙 с цифрой — это сколько секунд держать телефон неподвижно."]}, {type:"steps", title:"Как снимать в темноте", items:[ "В темноте сам появляется значок луны 🌙 с числом — это секунды съёмки", "Чем больше число, тем важнее не шевелиться", "Обопри руки или телефон на что-нибудь: стол, перила, стену", "Плавно нажми и держи телефон неподвижно, пока полоска не закончится" ]}, {type:"compare", bad:"Снимаю вечером с рук на ходу — фонари и лица смазаны", good:"Облокотилась на перила, подождала пару секунд — кадр чистый и светлый", note:"В ночном режиме всё решает неподвижность. Любая опора очень помогает."}, {type:"tip", text:"Нет опоры рядом? Прижми локти к телу и задержи дыхание в момент съёмки — телефон дрогнет меньше."} ] }, { emoji:"🔍", title:"Зум без потери качества", sub:"Хороший зум и плохой", intro:"Зум на телефоне — хитрая штука. Есть «хороший» зум, который не портит качество, и «плохой», от которого фото становится мутным.", blocks:[ {type:"text", text:["Кнопки 0.5x, 1x, 2x под кадром — это разные объективы, качество отличное. А вот если растягивать картинку пальцами до большого числа (5x, 10x), телефон просто увеличивает пиксели — и фото мутнеет.","Золотое правило: лучше подойти ближе ногами, чем тянуть зумом. (А если у тебя iPhone Pro — там есть отдельный телеобъектив, он приближает дальше без потери качества.)"]}, {type:"cards", items:[ {e:"🌳", t:"0.5x — широко", d:"Влезает много: пейзаж, большая компания, тесная комната."}, {e:"⭐", t:"1x — обычный", d:"Самый качественный и универсальный. Если сомневаешься — снимай на нём."}, {e:"🙂", t:"2x — крупнее", d:"Удобно для портретов и деталей, качество ещё хорошее."}, {e:"⚠️", t:"Большой зум — мутно", d:"5x–10x пальцами на обычном айфоне делают фото размытым. Избегай."} ]}, {type:"quiz", q:"Хочешь снять что-то далеко и чётко. Как лучше?", options:[ {t:"Подойти ближе ногами", correct:true, why:"Верно! Пара шагов вперёд сохраняет качество. Ноги — самый лучший зум."}, {t:"Растянуть пальцами до 10x", correct:false, why:"На обычном айфоне это сильно ухудшит качество — фото будет мутным и «рассыпется»."} ]}, {type:"tip", text:"Лучше сделать пару шагов вперёд, чем тянуть зумом. Ноги — лучший зум."} ] }, { emoji:"🎨", title:"Чуть-чуть обработки — и вау", sub:"20 секунд прямо в телефоне", intro:"Даже хорошее фото можно сделать ещё лучше — прямо в телефоне, без всяких приложений. И оригинал всегда можно вернуть.", blocks:[ {type:"text", text:["В айфоне уже встроен простой и удобный редактор. Пара движений ползунками — и фото заиграет."]}, {type:"steps", title:"Как улучшить фото", items:[ "Открой фото и нажми «Править» (вверху справа)", "Попробуй значок авто — волшебная палочка ✨ часто сразу делает лучше", "Поиграй ползунками: «Экспозиция», «Яркость», «Теплота»", "Обрежь лишнее по краям и выпрями горизонт", "Нажми «Готово». Не понравилось — открой снова и «Вернуть оригинал»" ]}, {type:"compare", bad:"Фото чуть тёмное, горизонт кривой, по краям лишнее", good:"Подняла яркость, выпрямила горизонт, обрезала лишнее — совсем другое дело", note:"Маленькая правка часто решает больше, чем кажется. И всё обратимо."}, {type:"tip", text:"Не переусердствуй: лёгкая правка выглядит дорого, а кислотные цвета — нет. Оригинал всегда можно вернуть."} ] }, { emoji:"🤳", title:"Селфи и общие фото", sub:"Чтобы все влезли в кадр", intro:"Чтобы попасть в кадр всем сразу и при этом не трясти телефон, есть пара очень удобных приёмов.", blocks:[ {type:"steps", title:"Фото с таймером (все в кадре)", items:[ "Поставь телефон на опору и наведи камеру", "Включи таймер: значок ⏱ (часики) сверху или в меню стрелочкой", "Выбери 3 или 10 секунд и нажми кнопку съёмки", "Успей встать в кадр — телефон снимет сам" ]}, {type:"cards", items:[ {e:"🔊", t:"Кнопка громкости = спуск", d:"Боковая кнопка громкости тоже делает фото. Так удобнее держать и меньше тряски."}, {e:"👥", t:"0.5x для компании", d:"Все не влезают? Переключись на широкий объектив 0.5x — поместится больше."}, {e:"📐", t:"Камера чуть выше", d:"Для селфи держи телефон немного выше уровня глаз — лицо выглядит стройнее и красивее."} ]}, {type:"tip", text:"Кнопка громкости сбоку — это тоже «спуск». Держать телефон двумя руками и нажимать её куда устойчивее."} ] } ]; const PROBLEMS = [ {e:"🌫️", t:"Фото размытое, мутное", cause:"Грязный объектив, дрогнула рука или фокус навёлся не туда.", fix:"Протри объектив, держи телефон двумя руками, коснись пальцем главного, чтобы навести фокус.", ex:"Перед съёмкой: протри стекло → коснись лица → плавно нажми."}, {e:"🌑", t:"Лицо получилось тёмным", cause:"Свет бьёт сзади (окно или солнце за спиной) — камера видит силуэт.", fix:"Поверни человека лицом к свету. Или коснись лица и подними солнышко ☀️ вверх.", ex:"Поставь человека лицом к окну, а не спиной к нему."}, {e:"⚪", t:"Пересвечено, белые пятна", cause:"Слишком много света, экспозиция завышена — небо и светлые места «выгорают».", fix:"Коснись экрана и опусти солнышко ☀️ вниз. Не наводи камеру прямо на солнце.", ex:"Коснись яркого места → веди солнышко вниз, пока не проявятся детали."}, {e:"📐", t:"Горизонт завален (всё косо)", cause:"Телефон держали под наклоном, без ориентира.", fix:"Включи сетку и держи линию горизонта параллельно ей. Кривой кадр выпрями в редакторе.", ex:"Править → выпрямление → подвинь ползунок, пока горизонт не станет ровным."}, {e:"🟡", t:"Цвета неестественные, желтит", cause:"Смешанный или искусственный свет (лампы) сбивает цвет.", fix:"Добавь дневного света, если можно. Или поправь «Теплоту» в редакторе — убери желтизну.", ex:"Править → «Теплота» → сдвинь чуть в синюю сторону."}, {e:"🔍", t:"Далёкое вышло мутным", cause:"Использован большой цифровой зум — телефон растянул пиксели.", fix:"Не тяни зум пальцами. Подойди ближе ногами или сними на 1x и обрежь потом.", ex:"Сделай пару шагов вперёд вместо зума 10x."}, {e:"🌙", t:"Вечером всё смазано", cause:"В ночном режиме дрогнула рука за те секунды, что шла съёмка.", fix:"Обопрись на что-нибудь, держи телефон неподвижно, пока полоска ночного режима не закончится.", ex:"Облокотись на перила/стол и не двигайся пару секунд."} ]; /* ===================== ПРОГРЕСС ===================== */ let store, PERSIST=true; try { localStorage.setItem("_t","1"); localStorage.removeItem("_t"); store=localStorage; } catch(e){ PERSIST=false; const mem={}; store={getItem:k=>k in mem?mem[k]:null,setItem:(k,v)=>mem[k]=String(v),removeItem:k=>delete mem[k]}; } function getDone(){ try{ return JSON.parse(store.getItem("fp_done")||"[]"); }catch(e){ return []; } } function setDone(a){ try{ store.setItem("fp_done", JSON.stringify(a)); }catch(e){} } function markDone(i){ const d=getDone(); if(!d.includes(i)){ d.push(i); setDone(d);} } function getLast(){ const v=store.getItem("fp_last"); return (v===null||v===undefined)?null:parseInt(v,10); } function setLast(i){ try{ store.setItem("fp_last", String(i)); }catch(e){} } function nextUnfinished(){ const d=getDone(); for(let k=0;k<LESSONS.length;k++){ if(!d.includes(k)) return k; } return null; } function resetProgress(){ if(!confirm("Начать курс заново? Отметки о пройденных уроках сбросятся.")) return; setDone([]); try{ store.removeItem("fp_last"); }catch(e){} renderHome(); showToast("Прогресс сброшен — можно начать заново"); } /* ===================== ОЗВУЧКА ===================== */ let speaking=false, currentBtn=null; function getRuVoice(){ const vs=window.speechSynthesis?speechSynthesis.getVoices():[]; return vs.find(v=>v.lang&&v.lang.toLowerCase().startsWith("ru"))||null; } if(window.speechSynthesis){ speechSynthesis.onvoiceschanged=()=>{}; } function speakText(text, btn, labelIdle){ if(!window.speechSynthesis){ showToast("Озвучка недоступна в этом браузере"); return; } const wasSame = (currentBtn===btn && speaking); if(speaking){ speechSynthesis.cancel(); speaking=false; if(currentBtn&¤tBtn.dataset.idle) currentBtn.innerHTML=currentBtn.dataset.idle; } if(wasSame) return; const u=new SpeechSynthesisUtterance(text); u.lang="ru-RU"; u.rate=0.95; const v=getRuVoice(); if(v)u.voice=v; u.onend=()=>{ speaking=false; if(btn.dataset.idle) btn.innerHTML=btn.dataset.idle; }; u.onerror=()=>{ speaking=false; if(btn.dataset.idle) btn.innerHTML=btn.dataset.idle; }; speechSynthesis.speak(u); speaking=true; currentBtn=btn; if(!btn.dataset.idle) btn.dataset.idle=btn.innerHTML; btn.innerHTML = (labelIdle===false) ? "⏸" : "⏸ Остановить"; } function buildReadText(L){ let parts=[L.title+".", L.intro]; L.blocks.forEach(b=>{ if(b.type==="text") parts.push(b.text.join(" ")); else if(b.type==="compare") parts.push("Так себе: "+b.bad+". А вот так — красиво: "+b.good+". "+(b.note||"")); else if(b.type==="cards"||b.type==="formula") b.items.forEach(it=>parts.push(it.t+". "+it.d)); else if(b.type==="steps"){ if(b.title)parts.push(b.title+"."); b.items.forEach((s,i)=>parts.push((i+1)+". "+s+".")); } else if(b.type==="quiz"){ const c=b.options.find(o=>o.correct); parts.push(b.q+" Правильный ответ: "+(c?c.t:"")+". "+(c?c.why:"")); } else if(b.type==="tip") parts.push("Совет. "+b.text); }); return parts.join(" "); } /* ===================== ВКЛАДКИ ===================== */ function showTab(name){ document.querySelectorAll(".tab").forEach(t=>t.classList.toggle("active",t.dataset.tab===name)); document.querySelectorAll(".panel").forEach(p=>p.classList.toggle("active",p.id==="panel-"+name)); if(name==="problems") renderProblems(); if(name==="cheat") renderCheat(); window.scrollTo({top:0,behavior:"instant"}); } /* ===================== ГЛАВНАЯ: УРОКИ ===================== */ function renderHome(){ const list=document.getElementById("lessonList"); const done=getDone(); list.innerHTML=""; LESSONS.forEach((L,i)=>{ const isDone=done.includes(i); const el=document.createElement("div"); el.className="lcard"+(isDone?" done":""); el.onclick=()=>openLesson(i); el.innerHTML=`<span class="check">✅</span><div class="num">${isDone?"✓":(i+1)}</div> <div><div class="l-title"><span class="l-emoji">${L.emoji}</span> ${L.title}</div><div class="l-sub">${L.sub}</div></div>`; list.appendChild(el); }); const pct=Math.round(done.length/LESSONS.length*100); document.getElementById("homeBarFill").style.width=pct+"%"; document.getElementById("homeProgressText").textContent=done.length+" из "+LESSONS.length; const next=nextUnfinished(); const allDone=(next===null); const heroBtn=document.getElementById("heroBtn"); if(heroBtn){ if(done.length===0 && getLast()===null) heroBtn.textContent="▶ Начать"; else if(allDone) heroBtn.textContent="✓ Все уроки пройдены — открыть"; else heroBtn.textContent="▶ Продолжить · Урок "+(next+1); } const rr=document.getElementById("resumeRow"); if(rr){ if(!PERSIST){ rr.innerHTML='<div class="rr-note warn">⚠️ В этом браузере прогресс может не сохраняться после закрытия. Лучше открывать через обычный браузер (Safari или Chrome).</div>'; } else if(allDone && done.length>0){ rr.innerHTML='<div class="rr-note">🎉 Все уроки пройдены! Можно повторить любой или <button class="rr-reset" onclick="resetProgress()">начать сначала</button></div>'; } else if(done.length>0){ rr.innerHTML='<div class="rr-note">👋 С возвращением! Пройдено '+done.length+' из '+LESSONS.length+'. <button class="rr-reset" onclick="resetProgress()">начать сначала</button></div>'; } else { rr.innerHTML=''; } } } /* ===================== БЛОКИ УРОКА ===================== */ function blockHTML(b){ if(b.type==="text") return `<div class="block">${b.text.map(t=>`<p>${t}</p>`).join("")}</div>`; if(b.type==="compare") return `<div class="block"><div class="compare"> <div class="cmp bad"><span class="tag">🙁 Так себе</span><div class="txt">${b.bad}</div></div> <div class="cmp good"><span class="tag">😍 Красиво</span><div class="txt">${b.good}</div></div> ${b.note?`<div class="cmp-note"><b>Почему: </b>${b.note}</div>`:""}</div></div>`; if(b.type==="formula") return `<div class="block">${b.title?`<div class="block-label">${b.title}</div>`:""}<div class="formula">${b.items.map(it=>`<div class="fcard"><div class="fe">${it.e}</div><div class="ft">${it.t}</div><div class="fd">${it.d}</div></div>`).join("")}</div></div>`; if(b.type==="cards") return `<div class="block">${b.title?`<div class="block-label">${b.title}</div>`:""}<div class="cards">${b.items.map(it=>`<div class="icard"><div class="ie">${it.e}</div><div><div class="it">${it.t}</div><div class="id">${it.d}</div></div></div>`).join("")}</div></div>`; if(b.type==="steps") return `<div class="block">${b.title?`<div class="block-label">👉 ${b.title}</div>`:""}<div class="steps">${b.items.map((s,i)=>`<div class="step"><span class="sn">${i+1}</span><div class="stx">${s}</div></div>`).join("")}</div></div>`; if(b.type==="quiz"){ const id="q"+Math.random().toString(36).slice(2,7); return `<div class="block quiz" id="${id}"><div class="q">❓ ${b.q}</div> ${b.options.map((o,oi)=>`<button class="opt" data-correct="${o.correct}" data-why="${(o.why||'').replace(/"/g,'"')}" onclick="answerQuiz('${id}',${oi},${o.correct})"><span class="mark">⬜</span><span>${o.t}</span></button>`).join("")} <div class="quiz-why" id="${id}_why"></div></div>`; } if(b.type==="tip") return `<div class="tip"><div class="ti">💡</div><div class="tx">${b.text}</div></div>`; return ""; } function openLesson(i){ const L=LESSONS[i]; const view=document.getElementById("lessonView"); const pct=Math.round((i+1)/LESSONS.length*100); view.innerHTML=`<div class="lesson active"> <div class="l-progress">Урок ${i+1} из ${LESSONS.length} <span class="bar" style="flex:1;"><i style="width:${pct}%;display:block;height:100%;background:linear-gradient(90deg,var(--purple),var(--coral));border-radius:10px;"></i></span></div> <div class="l-head"><span class="big-emoji">${L.emoji}</span><h2>${L.title}</h2><p class="intro">${L.intro}</p></div> <div class="listen"><button class="btn btn-coral" id="speakBtn">🔊 Прослушать урок</button></div> <div class="listen-hint">Не хочешь читать? Нажми и слушай 👆</div> ${L.blocks.map(blockHTML).join("")} <button class="btn btn-primary btn-big done-btn" onclick="finishLesson(${i})">✅ Понятно, дальше</button> <div class="lnav"> ${i>0?`<button class="btn btn-ghost" onclick="openLesson(${i-1})">← Назад</button>`:`<button class="btn btn-ghost" onclick="goHome()">← К урокам</button>`} ${i<LESSONS.length-1?`<button class="btn btn-ghost" onclick="openLesson(${i+1})">Дальше →</button>`:`<button class="btn btn-ghost" onclick="goHome()">Готово →</button>`} </div></div>`; const sb=document.getElementById("speakBtn"); sb.dataset.idle="🔊 Прослушать урок"; sb.onclick=function(){ speakText(buildReadText(L), this, true); }; setLast(i); document.getElementById("home").style.display="none"; document.getElementById("homeBtn").style.display="inline-flex"; if(speaking){ speechSynthesis.cancel(); speaking=false; } window.scrollTo({top:0,behavior:"instant"}); } function finishLesson(i){ markDone(i); if(speaking){speechSynthesis.cancel();speaking=false;} if(i<LESSONS.length-1){ openLesson(i+1); showToast("Урок пройден! 🎉"); } else showFinish(); } function showFinish(){ const view=document.getElementById("lessonView"); view.innerHTML=`<div class="lesson active"> <div class="finish"><span class="big-emoji">🎉</span><h2>Готово!</h2> <p>Теперь ты знаешь главное: ищи хороший свет, управляй яркостью пальцем, наводи фокус, держи горизонт ровно и не бойся подойти ближе.</p> <p style="opacity:.9;font-size:18px;">Загляни в «Шпаргалку» перед съёмкой — там всё самое важное на одном экране.</p></div> <div class="lnav" style="margin-top:16px;"> <button class="btn btn-ghost" onclick="goHome();showTab('cheat')">📋 Шпаргалка</button> <button class="btn btn-primary" onclick="goHome()">🏠 На главную</button></div></div>`; renderHome(); window.scrollTo({top:0,behavior:"instant"}); showToast("Курс пройден! Ты молодец 🌟"); } function goHome(){ if(speaking){speechSynthesis.cancel();speaking=false;} document.getElementById("lessonView").innerHTML=""; document.getElementById("home").style.display="block"; document.getElementById("homeBtn").style.display="none"; renderHome(); window.scrollTo({top:0,behavior:"instant"}); } function startCourse(){ let next=nextUnfinished(); if(next===null){ const last=getLast(); next=(last===null?0:last); } showTab('lessons'); openLesson(next); } /* ===================== РАЗДЕЛ: ПРОБЛЕМЫ ===================== */ function renderProblems(){ const el=document.getElementById("problemList"); if(el.dataset.ready) return; el.dataset.ready="1"; el.innerHTML=PROBLEMS.map((p,i)=>`<div class="prob" id="prob${i}"> <div class="prob-head" onclick="toggleProb(${i})"><span class="pe">${p.e}</span><span>${p.t}</span><span class="arrow">⌄</span></div> <div class="prob-body"> <div class="cause">🔎 Почему: ${p.cause}</div> <div class="fix">✅ Что сделать: ${p.fix}</div> <div class="ex" data-copybox>💡 На практике: <span class="copytext">${p.ex}</span> <div class="prob-actions"><button class="mini" onclick="speakNear(this)">🔊 Озвучить</button></div> </div></div></div>`).join(""); } function toggleProb(i){ const p=document.getElementById("prob"+i); p.classList.toggle("open"); } /* ===================== РАЗДЕЛ: ШПАРГАЛКА ===================== */ function renderCheat(){ const el=document.getElementById("cheatBody"); if(el.dataset.ready) return; el.dataset.ready="1"; const before=[ {e:"🧽", t:"Протри объектив", d:"Главная причина мутных фото — отпечатки пальцев на стекле."}, {e:"💡", t:"Найди свет", d:"Поставь человека лицом к окну или свету, не спиной."}, {e:"👆", t:"Коснись главного", d:"Тап по экрану наводит фокус и яркость на нужное место."}, {e:"📐", t:"Выровняй горизонт", d:"Включи сетку и держи линию ровно, главное — по линиям трети."}, {e:"🚶", t:"Подойди ближе", d:"Лучше пара шагов вперёд, чем мутный цифровой зум."} ]; const tricks=[ {e:"☀️", t:"Солнышко — это яркость", d:"Коснись экрана и веди палец: вверх — светлее, вниз — темнее."}, {e:"🔒", t:"Задержи палец", d:"Долгое касание фиксирует фокус, чтобы он не сбивался."}, {e:"🔊", t:"Кнопка громкости", d:"Боковая кнопка тоже делает фото — держать удобнее, тряски меньше."}, {e:"🔭", t:"0.5x и 2x", d:"0.5x — чтобы влезло больше, 2x — для портретов без потери качества."}, {e:"🌙", t:"Луна = ночь", d:"Появился значок луны — держи телефон неподвижно пару секунд."} ]; el.innerHTML=` <div class="block"><div class="block-label">📸 Перед каждым кадром</div> <div class="cheat-grid">${before.map(c=>`<div class="icard"><div class="ie">${c.e}</div><div><div class="it">${c.t}</div><div class="id">${c.d}</div></div></div>`).join("")}</div> </div> <div class="block"><div class="block-label">⚡ Приёмы за секунду</div> <div class="cheat-grid">${tricks.map(c=>`<div class="icard"><div class="ie">${c.e}</div><div><div class="it">${c.t}</div><div class="id">${c.d}</div></div></div>`).join("")}</div> </div>`; } /* ===================== КВИЗ ===================== */ function answerQuiz(id,oi,correct){ const box=document.getElementById(id); const opts=box.querySelectorAll(".opt"); const chosen=opts[oi]; opts.forEach(o=>o.style.pointerEvents="none"); if(correct){ chosen.classList.add("correct"); chosen.querySelector(".mark").textContent="✅"; } else { chosen.classList.add("wrong"); chosen.querySelector(".mark").textContent="❌"; opts.forEach(o=>{ if(o.dataset.correct==="true"){ o.classList.add("correct"); o.querySelector(".mark").textContent="✅"; } }); } const w=document.getElementById(id+"_why"); w.textContent=chosen.dataset.why||""; w.classList.add("show"); } /* ===================== ОЗВУЧКА РЯДОМ ===================== */ function speakNear(btn){ const box=btn.closest("[data-copybox]"); const t=box.querySelector(".copytext").innerText.replace(/[«»]/g,"").trim(); if(!btn.dataset.idle) btn.dataset.idle=btn.innerHTML; speakText(t,btn,false); } let toastTimer; function showToast(m){ const el=document.getElementById("toast"); el.textContent=m; el.classList.add("show"); clearTimeout(toastTimer); toastTimer=setTimeout(()=>el.classList.remove("show"),2200); } /* ===================== СТАРТ ===================== */ renderHome(); if(window.speechSynthesis){ speechSynthesis.getVoices(); } </script> </body> </html>