const root = document.documentElement; const header = document.querySelector(".site-header"); const nav = document.querySelector(".site-nav"); const navToggle = document.querySelector(".nav-toggle"); const themeToggle = document.querySelector(".theme-toggle"); const typingLine = document.querySelector("#typing-line"); const selectedPrompt = document.querySelector("#selected-prompt"); const prefersReduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches; const media = { researchVideo: new URL("../assets/showcase-research.mp4", import.meta.url).href, researchPoster: new URL("../assets/showcase-research.jpg", import.meta.url).href, imageVideo: new URL("../assets/showcase-ai-image.mp4", import.meta.url).href, imagePoster: new URL("../assets/showcase-ai-image.jpg", import.meta.url).href, videoVideo: new URL("../assets/showcase-ai-video.mp4", import.meta.url).href, videoPoster: new URL("../assets/showcase-ai-video.jpg", import.meta.url).href, avatarVideo: new URL("../assets/showcase-avatar.mp4", import.meta.url).href, avatarPoster: new URL("../assets/showcase-avatar.jpg", import.meta.url).href, clipVideo: new URL("../assets/showcase-clip.mp4", import.meta.url).href, clipPoster: new URL("../assets/showcase-clip.jpg", import.meta.url).href, publishVideo: new URL("../assets/showcase-publish.mp4", import.meta.url).href, publishPoster: new URL("../assets/showcase-publish.jpg", import.meta.url).href }; const featureData = { research: { kicker: "万象智枢", title: "从全网信号里找到今天值得做的内容战役", text: "聚合网页、视频、社区和开源项目,把趋势、用户痛点和内容机会转成脚本、分镜和提示词。", video: media.researchVideo, poster: media.researchPoster, points: ["趋势研究与需求洞察", "脚本、分镜、提示词生成", "结果可保存到知识与资产链路"] }, image: { kicker: "AI 图片生成", title: "从一句方向到一组可筛选、可复用的视觉资产", text: "支持文生图、图生图、多图参考、局部重绘和批量提示词,适合产品图、封面、视觉风格探索。", video: media.imageVideo, poster: media.imagePoster, points: ["单图与批量出图", "参考图和参数统一管理", "结果进入资产中心与画布"] }, video: { kicker: "AI 视频生成", title: "把选题、脚本和分镜快速推到镜头生产", text: "支持文生视频、图生视频、首尾帧和爆款视频流程,让一人团队也能连续产出内容素材。", video: media.videoVideo, poster: media.videoPoster, points: ["脚本到镜头连续生成", "热门视频与 MV 模式", "多结果对比与二次编辑"] }, avatar: { kicker: "数字人口播", title: "让创始人形象、声音和脚本成为可调度资产", text: "形象、音色、文案和背景组合生成口播视频,适合课程、产品讲解、私域种草和批量答疑。", video: media.avatarVideo, poster: media.avatarPoster, points: ["形象与音色管理", "TTS 配音和字幕生成", "本地模型状态可检查"] }, clip: { kicker: "AI 剪辑中心", title: "把长素材拆成高密度短视频发布弹药", text: "长视频拆条、文字剪辑、说话人选段、字幕和商业短视频包装集中在同一个剪辑工作台。", video: media.clipVideo, poster: media.clipPoster, points: ["长视频智能拆条", "字幕、封面和包装建议", "任务历史与资产中心同步"] }, publish: { kicker: "自动发布", title: "让内容从资产中心直接进入渠道排程", text: "选择图片视频资产,授权多平台账号,批量发布到社交渠道,并把发布动作沉淀回下一轮复盘。", video: media.publishVideo, poster: media.publishPoster, points: ["多平台账号与排程", "素材库批量选择", "发布结果回流到增长复盘"] } }; const typingPhrases = [ "读取全网趋势,拆成可执行内容战役...", "正在为一人公司生成选题、脚本、分镜和发布排程...", "图片、视频、声音、数字人任务已进入统一队列...", "资产中心已同步生成结果,等待下一轮复盘..." ]; function setHeaderState() { header?.setAttribute("data-elevated", String(window.scrollY > 24)); } window.addEventListener("scroll", setHeaderState, { passive: true }); setHeaderState(); navToggle?.addEventListener("click", () => { const isOpen = nav?.classList.toggle("is-open") ?? false; navToggle.setAttribute("aria-expanded", String(isOpen)); }); nav?.addEventListener("click", (event) => { if (event.target instanceof HTMLAnchorElement) { nav.classList.remove("is-open"); navToggle?.setAttribute("aria-expanded", "false"); } }); const savedTheme = localStorage.getItem("truegrowth-official-theme"); if (savedTheme === "light" || savedTheme === "dark") { root.dataset.siteTheme = savedTheme; } themeToggle?.addEventListener("click", () => { const next = root.dataset.siteTheme === "dark" ? "light" : "dark"; root.dataset.siteTheme = next; localStorage.setItem("truegrowth-official-theme", next); }); const revealObserver = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { entry.target.classList.add("is-visible"); revealObserver.unobserve(entry.target); } }); }, { threshold: 0.14 } ); document.querySelectorAll(".reveal").forEach((element) => revealObserver.observe(element)); const counters = document.querySelectorAll("[data-count-to]"); const counterObserver = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (!entry.isIntersecting) return; const element = entry.target; const target = Number(element.getAttribute("data-count-to") || "0"); const start = performance.now(); const duration = prefersReduced ? 1 : 900; const tick = (time) => { const progress = Math.min(1, (time - start) / duration); element.textContent = String(Math.round(target * progress)); if (progress < 1) requestAnimationFrame(tick); }; requestAnimationFrame(tick); counterObserver.unobserve(element); }); }, { threshold: 0.4 } ); counters.forEach((counter) => counterObserver.observe(counter)); let phraseIndex = 0; let charIndex = 0; let deleting = false; function typeNext() { if (!typingLine || prefersReduced) return; const phrase = typingPhrases[phraseIndex]; typingLine.textContent = phrase.slice(0, charIndex); if (!deleting && charIndex < phrase.length) { charIndex += 1; window.setTimeout(typeNext, 34); return; } if (!deleting && charIndex === phrase.length) { deleting = true; window.setTimeout(typeNext, 1300); return; } if (deleting && charIndex > 0) { charIndex -= 1; window.setTimeout(typeNext, 18); return; } deleting = false; phraseIndex = (phraseIndex + 1) % typingPhrases.length; window.setTimeout(typeNext, 220); } typeNext(); const featureVideo = document.querySelector("#feature-video"); const featureKicker = document.querySelector("#feature-kicker"); const featureTitle = document.querySelector("#feature-title"); const featureText = document.querySelector("#feature-text"); const featurePoints = document.querySelector("#feature-points"); function setFeatureVideo(data) { if (!featureVideo || !data) return; featureVideo.setAttribute("poster", data.poster); if (featureVideo.currentSrc !== data.video) { featureVideo.setAttribute("src", data.video); featureVideo.load(); } featureVideo.play().catch(() => {}); } setFeatureVideo(featureData.research); document.querySelectorAll(".feature-tab").forEach((button) => { button.addEventListener("click", () => { const key = button.getAttribute("data-feature"); const data = key ? featureData[key] : null; if (!data) return; document.querySelectorAll(".feature-tab").forEach((tab) => { const active = tab === button; tab.classList.toggle("is-active", active); tab.setAttribute("aria-selected", String(active)); }); if (featureKicker) featureKicker.textContent = data.kicker; if (featureTitle) featureTitle.textContent = data.title; if (featureText) featureText.textContent = data.text; if (featurePoints) { featurePoints.innerHTML = data.points.map((point) => `