Files
TrueGrowth/apps/web/index.html

2383 lines
72 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<!-- 权限策略:禁止 unload 事件(不影响 beforeunload -->
<!-- 基本 SEO Meta 标签 -->
<title>TrueGrowth | 让 AI 接管增长</title>
<meta
name="description"
content="TrueGrowth 是一个以应用中心为入口的桌面 AI 创作平台,统一图片、视频、数字人、声音、素材、任务和无限画布。"
/>
<meta
name="keywords"
content="TrueGrowth,AI创作平台,AI图片生成,AI视频生成,数字人,声音克隆,无限画布,素材库,任务中心,本地模型"
/>
<meta name="application-name" content="TrueGrowth" />
<meta name="author" content="TrueGrowth Team" />
<meta name="theme-color" content="#ff5b00" />
<meta
name="robots"
content="index,follow,max-image-preview:large,max-snippet:-1,max-video-preview:-1"
/>
<!-- Open Graph Meta 标签 -->
<meta property="og:title" content="TrueGrowth | 桌面 AI 创作平台" />
<meta
property="og:description"
content="以应用中心进入图片、视频、数字人、声音、素材、任务和无限画布。"
/>
<meta property="og:type" content="website" />
<meta property="og:url" content="https://truegrowth.ai" />
<meta property="og:site_name" content="TrueGrowth" />
<meta property="og:locale" content="zh_CN" />
<meta property="og:image" content="/icons/icon-512x512.png" />
<meta
property="og:image:alt"
content="TrueGrowth 桌面 AI 创作平台界面预览"
/>
<!-- Twitter Card Meta 标签 -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="TrueGrowth | 桌面 AI 创作平台" />
<meta
name="twitter:description"
content="一个把 AI 图片、视频、数字人、声音、素材、任务和无限画布统一到应用中心的 AI 工作台。"
/>
<meta name="twitter:image" content="/icons/icon-512x512.png" />
<meta
name="twitter:image:alt"
content="TrueGrowth 桌面 AI 创作平台界面预览"
/>
<link rel="canonical" href="https://truegrowth.ai" />
<!-- 语言替代链接 -->
<link rel="alternate" hreflang="zh-CN" href="https://truegrowth.ai" />
<link rel="alternate" hreflang="x-default" href="https://truegrowth.ai" />
<!-- 结构化数据 (JSON-LD) -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "WebSite",
"@id": "https://truegrowth.ai/#website",
"url": "https://truegrowth.ai",
"name": "TrueGrowth",
"inLanguage": "zh-CN",
"description": "TrueGrowth 是一个以应用中心为入口的桌面 AI 创作平台。"
},
{
"@type": "Organization",
"@id": "https://truegrowth.ai/#organization",
"name": "TrueGrowth Team",
"url": "https://truegrowth.ai",
"logo": "https://truegrowth.ai/icons/icon-512x512.png"
},
{
"@type": "SoftwareApplication",
"@id": "https://truegrowth.ai/#app",
"name": "TrueGrowth",
"alternateName": [
"TrueGrowth AI 创作平台",
"TrueGrowth Canvas Workspace"
],
"description": "TrueGrowth 集成图片、视频、数字人、声音、统一素材库、任务队列和无限画布,将生成、编辑与交付串联在一个工作台里。",
"url": "https://truegrowth.ai",
"image": "https://truegrowth.ai/icons/icon-512x512.png",
"applicationCategory": "DesignApplication",
"operatingSystem": "Any",
"offers": {
"@type": "Offer",
"price": "0",
"priceCurrency": "USD"
},
"publisher": {
"@id": "https://TrueGrowth.ai/#organization"
},
"keywords": [
"TrueGrowth",
"AI应用平台",
"AI图片生成",
"流程图",
"思维导图",
"画布工作区",
"AI工作流",
"素材库",
"知识库",
"任务队列"
],
"inLanguage": "zh-CN"
},
{
"@type": "FAQPage",
"@id": "https://TrueGrowth.ai/#faq",
"mainEntity": [
{
"@type": "Question",
"name": "TrueGrowth 适合做什么?",
"acceptedAnswer": {
"@type": "Answer",
"text": "TrueGrowth 适合做 AI 图片生成、流程图、思维导图、画布整理、素材管理和任务推进。你可以在同一块画布里完成创意生成、编辑、整理与交付。"
}
},
{
"@type": "Question",
"name": "TrueGrowth 和普通白板工具有什么区别?",
"acceptedAnswer": {
"@type": "Answer",
"text": "TrueGrowth 不只是白板,还把 AI 生成、素材库、知识与任务队列整合到同一个工作区,减少在多个应用间来回切换。"
}
},
{
"@type": "Question",
"name": "TrueGrowth 是否支持流程图和思维导图?",
"acceptedAnswer": {
"@type": "Answer",
"text": "支持。TrueGrowth 提供流程图、思维导图、文本和图形编辑能力,也支持通过自然语言或 Mermaid 语法快速生成结构化图示。"
}
}
]
}
]
}
</script>
<!-- base href 由构建工具处理CDN 模式下使用相对路径 -->
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
/>
<meta name="app-version" content="0.9.1" />
<style>
:root {
--app-boot-bg: #000000;
--app-boot-text: #f8fafc;
--app-boot-muted: rgba(248, 250, 252, 0.58);
--app-boot-quiet: rgba(248, 250, 252, 0.22);
--app-boot-accent: #ff5b00;
--app-boot-accent-soft: rgba(255, 91, 0, 0.18);
--app-boot-line: rgba(255, 255, 255, 0.065);
--app-boot-panel: rgba(14, 14, 15, 0.78);
--app-boot-shadow: 0 22px 70px rgba(0, 0, 0, 0.48);
--app-boot-progress: 0%;
--app-boot-flight-speed: 3.2s;
--app-boot-flight-blur: 1px;
--app-boot-flight-opacity: 0.62;
}
html,
body {
width: 100%;
height: 100%;
min-width: 100%;
min-height: 100%;
margin: 0;
background: #000 !important;
overflow: hidden;
}
#app-boot-loading {
position: fixed;
inset: 0;
width: 100vw;
height: 100vh;
height: 100dvh;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
overflow: hidden;
background: radial-gradient(
ellipse at 50% 50%,
rgba(255, 91, 0, 0.2) 0,
rgba(255, 91, 0, 0.13) 12%,
rgba(77, 135, 255, 0.1) 30%,
rgba(180, 87, 255, 0.055) 48%,
rgba(0, 0, 0, 0.68) 76%,
#000 100%
),
linear-gradient(180deg, #000 0%, #020203 44%, #000 100%), #000;
transition: opacity 0.28s ease, visibility 0.28s ease;
opacity: 1;
visibility: visible;
pointer-events: auto;
}
#app-boot-loading::before,
#app-boot-loading::after {
content: '';
position: absolute;
inset: -18%;
pointer-events: none;
}
#app-boot-loading::before {
background: radial-gradient(
circle at 50% 50%,
transparent 0 8%,
rgba(255, 255, 255, 0.12) 8.2% 8.35%,
transparent 8.7% 18%,
rgba(255, 91, 0, 0.08) 18.2% 18.35%,
transparent 18.8% 100%
),
linear-gradient(var(--app-boot-line) 1px, transparent 1px),
linear-gradient(90deg, var(--app-boot-line) 1px, transparent 1px);
background-position: center;
background-size: 100% 100%, 58px 58px, 58px 58px;
mask-image: radial-gradient(
circle at 50% 50%,
transparent 0 7%,
#000 13% 70%,
transparent 92%
);
transform: perspective(680px) rotateX(62deg) scale(0.82);
transform-origin: center;
animation: appBootGridForward calc(var(--app-boot-flight-speed) * 1.22)
cubic-bezier(0.22, 0.04, 0.12, 1) infinite;
opacity: 0.5;
}
#app-boot-loading::after {
inset: 0;
background: radial-gradient(
circle at 50% 50%,
transparent 0 38%,
rgba(0, 0, 0, 0.22) 66%,
rgba(0, 0, 0, 0.9) 100%
),
linear-gradient(
180deg,
rgba(0, 0, 0, 0.76) 0%,
transparent 22%,
transparent 70%,
rgba(0, 0, 0, 0.92) 100%
);
opacity: 1;
}
.app-boot-tunnel {
position: absolute;
inset: 0;
z-index: 0;
overflow: hidden;
opacity: var(--app-boot-flight-opacity);
filter: saturate(1.18) blur(var(--app-boot-flight-blur));
pointer-events: none;
}
.app-boot-tunnel::before {
content: '';
position: absolute;
inset: -10%;
background: radial-gradient(
circle at 50% 50%,
rgba(255, 255, 255, 0.2) 0 1px,
transparent 2px 5%,
rgba(255, 91, 0, 0.18) 5.6% 6.1%,
transparent 6.8% 12%,
rgba(86, 153, 255, 0.11) 12.4% 12.8%,
transparent 13.6% 100%
),
radial-gradient(
ellipse at 50% 50%,
transparent 0 10%,
rgba(255, 91, 0, 0.1) 16%,
rgba(79, 143, 255, 0.055) 31%,
transparent 62%
);
mask-image: radial-gradient(
ellipse at 50% 50%,
transparent 0 9%,
#000 15% 72%,
transparent 94%
);
opacity: 0.88;
pointer-events: none;
transform: scale(0.72);
animation: appBootTunnelDepth calc(var(--app-boot-flight-speed) * 1.08)
cubic-bezier(0.22, 0.04, 0.12, 1) infinite;
}
.app-boot-tunnel::after {
content: '';
position: absolute;
left: 50%;
top: 50%;
width: min(24vw, 280px);
aspect-ratio: 1;
border-radius: 50%;
background: radial-gradient(
circle at 50% 50%,
rgba(255, 255, 255, 0.16) 0,
rgba(255, 91, 0, 0.12) 22%,
rgba(71, 117, 255, 0.08) 46%,
transparent 74%
);
box-shadow: 0 0 70px rgba(255, 91, 0, 0.22),
0 0 110px rgba(71, 117, 255, 0.12);
transform: translate(-50%, -50%);
opacity: 0.68;
pointer-events: none;
}
.app-boot-tunnel span {
--angle: 0deg;
--ray-height: 1.4px;
--delay: 0s;
--ray: rgba(255, 255, 255, 0.78);
position: absolute;
left: 50%;
top: 50%;
width: min(50vw, 860px);
height: var(--ray-height);
border-radius: 999px;
background: linear-gradient(
90deg,
transparent 0,
rgba(255, 255, 255, 0.12) 8%,
var(--ray) 40%,
rgba(255, 255, 255, 0.38) 72%,
transparent 100%
);
box-shadow: 0 0 22px var(--ray);
transform-origin: left center;
animation: appBootWarpRay var(--app-boot-flight-speed)
cubic-bezier(0.24, 0.02, 0.16, 1) infinite;
animation-delay: var(--delay);
opacity: 0;
}
.app-boot-tunnel span:nth-child(3n) {
width: min(62vw, 1080px);
}
.app-boot-tunnel span:nth-child(4n) {
width: min(40vw, 720px);
}
.app-boot-tunnel span:nth-child(5n) {
opacity: 0.12;
animation-duration: calc(var(--app-boot-flight-speed) * 0.78);
}
#app-boot-loading.is-visible {
opacity: 1;
visibility: visible;
pointer-events: auto;
}
#app-boot-loading.is-leaving {
opacity: 0;
visibility: hidden;
pointer-events: none;
}
.app-boot-card {
position: relative;
z-index: 2;
width: min(720px, calc(100vw - 48px));
padding: 0;
border: 0;
background: transparent;
box-shadow: none;
text-align: center;
}
.app-boot-card::before {
content: '';
position: absolute;
left: 50%;
top: 50%;
width: min(720px, 88vw);
height: min(520px, 68vw);
border: 0;
border-radius: 50%;
background: radial-gradient(
circle at 50% 50%,
rgba(255, 91, 0, 0.16) 0,
rgba(255, 91, 0, 0.075) 20%,
rgba(71, 117, 255, 0.04) 36%,
transparent 68%
);
transform: translate(-50%, -52%);
opacity: 0.74;
pointer-events: none;
}
.app-boot-card::after {
content: '';
position: absolute;
left: 50%;
top: -4%;
width: min(520px, 78vw);
height: 1px;
background: linear-gradient(
90deg,
transparent,
rgba(255, 91, 0, 0.38),
rgba(255, 255, 255, 0.34),
transparent
);
filter: none;
transform: translateX(-50%);
animation: appBootScan 4.2s ease-in-out infinite;
opacity: 0.28;
pointer-events: none;
}
.app-boot-mark {
position: relative;
z-index: 1;
width: 76px;
height: 76px;
padding: 0;
margin: 0 auto 30px;
border-radius: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
overflow: hidden;
text-decoration: none;
background: linear-gradient(
180deg,
rgba(255, 255, 255, 0.1),
rgba(255, 255, 255, 0.025)
),
var(--app-boot-panel);
border: 1px solid rgba(255, 255, 255, 0.12);
box-shadow: 0 16px 42px rgba(0, 0, 0, 0.34),
0 0 34px rgba(255, 91, 0, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.16);
animation: appBootCorePulse 4.8s ease-in-out infinite;
}
.app-boot-mark::before {
content: '';
position: absolute;
inset: 8px;
border-radius: 14px;
border: 1px solid rgba(255, 91, 0, 0.22);
background: linear-gradient(
135deg,
rgba(255, 91, 0, 0.08),
transparent 48%,
rgba(255, 255, 255, 0.05)
);
opacity: 0.9;
}
.app-boot-mark__base,
.app-boot-mark__fill {
position: absolute;
inset: 14px;
width: 48px;
height: 48px;
display: block;
object-fit: contain;
transition: clip-path 0.24s ease, filter 0.24s ease;
}
.app-boot-mark__base {
filter: grayscale(1) brightness(1.9);
opacity: 0.22;
}
.app-boot-mark__fill {
filter: saturate(1.12) drop-shadow(0 0 12px rgba(255, 91, 0, 0.3));
clip-path: inset(0 calc(100% - var(--app-boot-progress)) 0 0);
}
.app-boot-mark::after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: linear-gradient(
90deg,
rgba(255, 91, 0, 0.16) 0 var(--app-boot-progress),
transparent var(--app-boot-progress) 100%
);
pointer-events: none;
transition: background 0.24s ease;
}
.app-boot-title {
position: relative;
z-index: 1;
margin: 0;
font-size: clamp(36px, 4.8vw, 66px);
font-weight: 820;
line-height: 1.02;
letter-spacing: 0;
}
.app-boot-slogan {
position: relative;
z-index: 1;
margin: 16px 0 0;
font-size: clamp(38px, 5.8vw, 76px);
font-weight: 860;
line-height: 1.06;
letter-spacing: 0;
}
.app-boot-fill-text {
display: inline-block;
color: transparent;
background: linear-gradient(
90deg,
var(--app-boot-accent) 0 var(--app-boot-progress),
var(--app-boot-quiet) var(--app-boot-progress) 100%
);
background-clip: text;
-webkit-background-clip: text;
text-shadow: 0 0 22px rgba(255, 91, 0, 0.16);
transition: background 0.24s ease;
}
.app-boot-status {
position: relative;
z-index: 1;
margin: 28px auto 0;
color: var(--app-boot-muted);
font-size: 13px;
line-height: 1.6;
}
.app-boot-status-title {
display: block;
color: rgba(248, 250, 252, 0.72);
font-weight: 700;
}
.app-boot-tip {
display: block;
margin-top: 6px;
}
.app-boot-progress {
position: relative;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 14px;
margin: 24px auto 0;
padding: 0;
border-radius: 999px;
background: transparent;
color: var(--app-boot-accent);
font-size: 11px;
font-weight: 720;
}
.app-boot-progress-track {
position: relative;
width: min(420px, 62vw);
height: 4px;
overflow: hidden;
border-radius: 999px;
background: rgba(255, 255, 255, 0.12);
border: 0;
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.055),
0 14px 34px rgba(0, 0, 0, 0.32);
}
.app-boot-progress-track::before {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
90deg,
transparent 0 46px,
rgba(255, 255, 255, 0.18) 46px 47px,
transparent 47px 92px
);
opacity: 0.28;
}
.app-boot-progress-fill {
position: absolute;
inset: 0 auto 0 0;
width: 0%;
border-radius: inherit;
background: linear-gradient(90deg, #ff5b00, #ff7a24);
box-shadow: 0 0 14px rgba(255, 91, 0, 0.34);
transition: width 0.24s ease;
}
.app-boot-progress-fill::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.34),
transparent
);
transform: translateX(-100%);
animation: appBootProgressSweep 2.2s ease-in-out infinite;
}
.app-boot-progress-value {
min-width: 34px;
text-align: right;
font-variant-numeric: tabular-nums;
color: rgba(248, 250, 252, 0.72);
text-shadow: none;
}
.app-boot-note {
position: relative;
z-index: 1;
margin-top: 12px;
color: rgba(248, 250, 252, 0.28);
font-size: 11px;
line-height: 1.5;
}
.app-boot-node-row {
position: relative;
z-index: 1;
display: flex;
justify-content: center;
gap: 8px;
margin: 18px auto 0;
}
.app-boot-node-row span {
width: 32px;
height: 1px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.16);
box-shadow: 0 0 0 rgba(255, 91, 0, 0);
animation: appBootNodePulse 3.6s ease-in-out infinite;
}
.app-boot-node-row span:nth-child(2) {
animation-delay: 0.18s;
}
.app-boot-node-row span:nth-child(3) {
animation-delay: 0.36s;
}
.app-boot-node-row span:nth-child(4) {
animation-delay: 0.54s;
}
.app-boot-node-row span:nth-child(5) {
animation-delay: 0.72s;
}
@keyframes appBootGridForward {
0% {
transform: perspective(680px) rotateX(62deg) scale(0.72);
opacity: 0;
}
16% {
opacity: 0.56;
}
100% {
transform: perspective(680px) rotateX(62deg) scale(1.62);
opacity: 0;
}
}
@keyframes appBootTunnelDepth {
0% {
transform: scale(0.66);
opacity: 0;
}
18% {
opacity: 0.82;
}
100% {
transform: scale(1.18);
opacity: 0;
}
}
@keyframes appBootWarpRay {
0% {
transform: rotate(var(--angle)) translateX(1vw) scaleX(0.02);
opacity: 0;
}
8% {
opacity: 1;
}
62% {
opacity: 0.68;
}
100% {
transform: rotate(var(--angle)) translateX(72vw) scaleX(1.5);
opacity: 0;
}
}
@keyframes appBootScan {
0% {
transform: translateX(-50%) scaleX(0.84);
opacity: 0.18;
}
50% {
transform: translateX(-50%) scaleX(1);
opacity: 0.44;
}
100% {
transform: translateX(-50%) scaleX(0.84);
opacity: 0.18;
}
}
@keyframes appBootCorePulse {
0%,
100% {
transform: translateY(0) scale(1);
box-shadow: 0 16px 42px rgba(0, 0, 0, 0.34),
0 0 34px rgba(255, 91, 0, 0.16),
inset 0 1px 0 rgba(255, 255, 255, 0.16);
}
50% {
transform: translateY(-1px) scale(1.006);
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.38),
0 0 42px rgba(255, 91, 0, 0.22),
inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
}
@keyframes appBootNodePulse {
0%,
100% {
background: rgba(255, 255, 255, 0.16);
box-shadow: 0 0 0 rgba(255, 91, 0, 0);
transform: scaleX(1);
}
42% {
background: rgba(255, 91, 0, 0.72);
box-shadow: 0 0 12px rgba(255, 91, 0, 0.32);
transform: scaleX(1.08);
}
}
@keyframes appBootProgressSweep {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
#seo-content {
max-width: 1120px;
margin: 0 auto;
padding: 48px 24px 88px;
color: #1f2937;
}
#seo-content a {
color: #5a4fcf;
text-decoration: none;
}
#seo-content a:hover {
text-decoration: underline;
}
.seo-hero {
display: grid;
grid-template-columns: minmax(0, 1.2fr) minmax(280px, 0.8fr);
gap: 24px;
align-items: start;
margin-bottom: 36px;
}
.seo-hero-copy h1 {
margin: 0 0 16px;
font-size: clamp(32px, 5vw, 54px);
line-height: 1.05;
color: #121826;
}
.seo-hero-copy p {
margin: 0 0 14px;
font-size: 16px;
line-height: 1.8;
color: #3f4a5a;
}
.seo-badges,
.seo-card-links,
.seo-faq-list {
list-style: none;
margin: 0;
padding: 0;
}
.seo-badges {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 18px;
}
.seo-badges li {
padding: 8px 12px;
border-radius: 999px;
background: #fff4df;
color: #ad6800;
font-size: 14px;
font-weight: 600;
}
.seo-panel {
border: 1px solid rgba(90, 79, 207, 0.14);
border-radius: 24px;
padding: 24px;
background: linear-gradient(180deg, #ffffff 0%, #faf8ff 100%);
box-shadow: 0 18px 40px rgba(90, 79, 207, 0.08);
}
.seo-panel h2,
.seo-section h2 {
margin: 0 0 14px;
font-size: 24px;
color: #121826;
}
.seo-panel p,
.seo-section p {
margin: 0 0 12px;
line-height: 1.8;
color: #475569;
}
.seo-card-links li + li,
.seo-faq-list li + li {
margin-top: 12px;
}
.seo-card-links a {
display: block;
padding: 14px 16px;
border-radius: 16px;
background: #ffffff;
border: 1px solid rgba(90, 79, 207, 0.12);
}
.seo-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 18px;
margin-bottom: 36px;
}
.seo-grid article,
.seo-faq-list li {
border-radius: 20px;
border: 1px solid #e8ebf3;
background: #ffffff;
padding: 20px;
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.04);
}
.seo-grid h3,
.seo-faq-list h3 {
margin: 0 0 10px;
font-size: 18px;
color: #121826;
}
.seo-section {
margin-bottom: 36px;
}
.seo-inline-links {
display: flex;
flex-wrap: wrap;
gap: 10px 16px;
}
html.app-ready #seo-content {
display: none;
}
html.app-boot-error .app-boot-progress {
background: rgba(233, 30, 99, 0.1);
color: #e91e63;
}
html.app-boot-error .app-boot-progress-track {
background: rgba(233, 30, 99, 0.16);
}
html.app-boot-error .app-boot-progress-fill {
background: linear-gradient(
90deg,
rgba(233, 30, 99, 0.72),
rgba(233, 30, 99, 1)
);
box-shadow: 0 0 16px rgba(233, 30, 99, 0.22);
}
html.app-boot-error {
--app-boot-accent: #e91e63;
}
@media (prefers-reduced-motion: reduce) {
#app-boot-loading::before,
#app-boot-loading::after,
.app-boot-tunnel,
.app-boot-tunnel::before,
.app-boot-tunnel::after,
.app-boot-tunnel span,
.app-boot-card::after,
.app-boot-mark,
.app-boot-mark::before,
.app-boot-progress-fill::after,
.app-boot-node-row span {
animation: none;
}
}
@media (max-width: 640px) {
.app-boot-card {
width: min(100%, calc(100vw - 40px));
}
.app-boot-mark {
width: 72px;
height: 72px;
margin-bottom: 22px;
border-radius: 20px;
}
.app-boot-mark__base,
.app-boot-mark__fill {
inset: 13px;
width: 46px;
height: 46px;
}
.app-boot-status {
margin-top: 24px;
}
.app-boot-progress {
gap: 10px;
}
.app-boot-progress-track {
width: min(280px, 62vw);
}
.seo-hero,
.seo-grid {
grid-template-columns: 1fr;
}
#seo-content {
padding: 32px 20px 64px;
}
}
</style>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="./icons/favicon-16x16.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="./icons/favicon-32x32.png"
/>
<link rel="icon" type="image/png" href="./icons/TrueGrowth-logo.png" />
<!-- PWA Manifest -->
<link rel="manifest" href="./manifest.json?v=0.1.0" />
<!-- PWA Meta Tags -->
<meta name="theme-color" content="#ff5b00" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="apple-mobile-web-app-title" content="TrueGrowth" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="msapplication-TileColor" content="#ff5b00" />
<meta name="msapplication-tap-highlight" content="no" />
<!-- Apple Touch Icons -->
<link
rel="apple-touch-icon"
sizes="192x192"
href="./icons/icon-192x192.png"
/>
<!-- Windows Tiles -->
<meta name="msapplication-TileImage" content="./icons/icon-192x192.png" />
<meta
name="msapplication-square310x310logo"
content="./icons/icon-512x512.png"
/>
<link rel="stylesheet" href="./src/styles.scss" />
</head>
<body>
<div
id="app-boot-loading"
role="status"
aria-live="polite"
aria-label="应用正在加载"
>
<div class="app-boot-tunnel" aria-hidden="true">
<span
style="
--angle: -178deg;
--delay: -0.1s;
--ray-height: 1.6px;
--ray: rgba(255, 91, 0, 0.82);
"
></span>
<span
style="
--angle: -154deg;
--delay: -1.4s;
--ray-height: 1.2px;
--ray: rgba(255, 196, 87, 0.64);
"
></span>
<span
style="
--angle: -132deg;
--delay: -0.7s;
--ray-height: 1px;
--ray: rgba(88, 156, 255, 0.54);
"
></span>
<span
style="
--angle: -109deg;
--delay: -2.3s;
--ray-height: 1.4px;
--ray: rgba(207, 116, 255, 0.48);
"
></span>
<span
style="
--angle: -88deg;
--delay: -1s;
--ray-height: 1px;
--ray: rgba(255, 255, 255, 0.58);
"
></span>
<span
style="
--angle: -63deg;
--delay: -2.8s;
--ray-height: 1.7px;
--ray: rgba(255, 91, 0, 0.74);
"
></span>
<span
style="
--angle: -38deg;
--delay: -0.4s;
--ray-height: 1.1px;
--ray: rgba(94, 217, 255, 0.5);
"
></span>
<span
style="
--angle: -14deg;
--delay: -1.9s;
--ray-height: 1.5px;
--ray: rgba(255, 146, 84, 0.68);
"
></span>
<span
style="
--angle: 11deg;
--delay: -0.9s;
--ray-height: 1px;
--ray: rgba(255, 255, 255, 0.5);
"
></span>
<span
style="
--angle: 34deg;
--delay: -2.5s;
--ray-height: 1.6px;
--ray: rgba(255, 91, 0, 0.78);
"
></span>
<span
style="
--angle: 57deg;
--delay: -1.2s;
--ray-height: 1.2px;
--ray: rgba(96, 133, 255, 0.56);
"
></span>
<span
style="
--angle: 82deg;
--delay: -3.1s;
--ray-height: 1px;
--ray: rgba(255, 211, 120, 0.6);
"
></span>
<span
style="
--angle: 108deg;
--delay: -0.2s;
--ray-height: 1.4px;
--ray: rgba(184, 91, 255, 0.5);
"
></span>
<span
style="
--angle: 136deg;
--delay: -1.7s;
--ray-height: 1.7px;
--ray: rgba(255, 91, 0, 0.82);
"
></span>
<span
style="
--angle: 163deg;
--delay: -2.1s;
--ray-height: 1px;
--ray: rgba(255, 255, 255, 0.52);
"
></span>
<span
style="
--angle: -169deg;
--delay: -2.9s;
--ray-height: 0.9px;
--ray: rgba(92, 152, 255, 0.5);
"
></span>
<span
style="
--angle: -122deg;
--delay: -1.1s;
--ray-height: 1.3px;
--ray: rgba(255, 91, 0, 0.68);
"
></span>
<span
style="
--angle: -76deg;
--delay: -2.6s;
--ray-height: 0.9px;
--ray: rgba(255, 255, 255, 0.48);
"
></span>
<span
style="
--angle: -24deg;
--delay: -0.6s;
--ray-height: 1.2px;
--ray: rgba(255, 174, 92, 0.62);
"
></span>
<span
style="
--angle: 24deg;
--delay: -2.2s;
--ray-height: 0.9px;
--ray: rgba(116, 211, 255, 0.48);
"
></span>
<span
style="
--angle: 71deg;
--delay: -1.6s;
--ray-height: 1.3px;
--ray: rgba(255, 91, 0, 0.72);
"
></span>
<span
style="
--angle: 119deg;
--delay: -3.3s;
--ray-height: 0.9px;
--ray: rgba(191, 103, 255, 0.46);
"
></span>
<span
style="
--angle: 151deg;
--delay: -0.8s;
--ray-height: 1.2px;
--ray: rgba(255, 255, 255, 0.5);
"
></span>
</div>
<div class="app-boot-card">
<span class="app-boot-mark" data-official-site-link>
<img
class="app-boot-mark__base"
src="./icons/icon-96x96.png"
alt=""
aria-hidden="true"
/>
<img
class="app-boot-mark__fill"
src="./icons/icon-96x96.png"
alt="TrueGrowth logo"
/>
</span>
<p class="app-boot-title">
<span class="app-boot-fill-text">TrueGrowth</span>
</p>
<p class="app-boot-slogan">
<span class="app-boot-fill-text">让 AI 接管增长</span>
</p>
<p class="app-boot-status">
<span class="app-boot-status-title" data-app-boot-title
>正在唤起 AI 工作台</span
>
<span class="app-boot-tip" data-app-boot-tip
>正在加载桌面端创作引擎...</span
>
</p>
<div
class="app-boot-progress"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0"
data-app-boot-progress
>
<span class="app-boot-progress-track" aria-hidden="true">
<span
class="app-boot-progress-fill"
data-app-boot-progress-fill
></span>
</span>
<span class="app-boot-progress-value" data-app-boot-progress-value>
0%
</span>
</div>
<div class="app-boot-node-row" aria-hidden="true">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<div class="app-boot-note" data-app-boot-note>TrueGrowth Studio</div>
</div>
</div>
<main id="seo-content">
<section class="seo-hero">
<div class="seo-hero-copy">
<h1>TrueGrowth 桌面 AI 创作工作台</h1>
<p>
TrueGrowth 是一个面向图片、视频、数字人和声音创作的 AI
应用平台。你可以在同一个工作台里调度云端模型、管理素材与任务,并把结果继续送入无限画布。
</p>
<p>
相比把提示词、素材库、知识卡片和任务列表拆散在多个工具里TrueGrowth
更适合需要边生成、边编辑、边整理的人。首页即工作台,打开就能开始产出。
</p>
<ul class="seo-badges">
<li>AI 图片生成</li>
<li>流程图</li>
<li>思维导图</li>
<li>画布工作区</li>
<li>素材管理</li>
</ul>
</div>
<aside class="seo-panel">
<h2>从这些入口开始</h2>
<p>
如果你想先了解产品能力,可以查看 TrueGrowth
介绍页;如果已经准备创作,直接进入工作台即可。
</p>
<ul class="seo-card-links">
<li>
<a href="/home.html"
>TrueGrowth 介绍页:了解 AI 画布、作品流和核心能力</a
>
</li>
<li>
<a href="/user-manual/index.html"
>用户手册:查看完整功能与操作路径</a
>
</li>
</ul>
</aside>
</section>
<section class="seo-section">
<h2>为什么适合搜索用户</h2>
<div class="seo-grid">
<article>
<h3>不是单点工具</h3>
<p>
TrueGrowth
把生成、编辑、整理和交付放在一起,适合需要持续推进任务,而不是只做一次性生成的人。
</p>
</article>
<article>
<h3>图文结构兼容</h3>
<p>
既能做 AI
图片生成,也能用流程图和思维导图承接方案、脑图、产品结构和知识整理。
</p>
</article>
<article>
<h3>更少切换</h3>
<p>
素材、知识、任务和画布相互打通,减少从聊天窗口、白板、网盘和文档来回跳转的摩擦。
</p>
</article>
</div>
</section>
<section class="seo-section">
<h2>常见使用场景</h2>
<p>
适合做营销海报、社媒配图、灵感整理、产品方案梳理、业务流程图、项目脑图,以及需要边生成边归档的工作流。
</p>
<p class="seo-inline-links">
<a href="/user-manual/ai-generation-image-generation.html"
>AI 图片生成指南</a
>
<a href="/user-manual/ai-generation-video-generation.html"
>AI 视频生成指南</a
>
<a href="/user-manual/drawing-flowchart.html">流程图指南</a>
<a href="/user-manual/drawing-mindmap.html">思维导图指南</a>
<a href="/versions.html">版本日志</a>
</p>
</section>
<section class="seo-section">
<h2>常见问题</h2>
<ul class="seo-faq-list">
<li>
<h3>TrueGrowth 是什么?</h3>
<p>
它是一个以画布工作区为核心的 AI 应用平台,支持 AI
图片生成、流程图、思维导图、素材管理与任务推进。
</p>
</li>
<li>
<h3>TrueGrowth 适合谁?</h3>
<p>
适合需要把创意生成、结构整理和任务交付放在一起的人,比如内容创作者、产品经理、运营、设计和独立开发者。
</p>
</li>
<li>
<h3>TrueGrowth 支持哪些图示能力?</h3>
<p>
支持流程图、思维导图、文本、形状、自由绘制,也支持通过自然语言或
Mermaid 语法快速生成结构化图示。
</p>
</li>
</ul>
</section>
</main>
<script>
(function () {
var bootReady = false;
var bootProgress = 0;
var simulationStartAt = Date.now();
var simulationTimer = 0;
var slowTipTimer = window.setTimeout(function () {
var tip = document.querySelector('[data-app-boot-tip]');
if (tip) {
tip.textContent =
'首次打开或网络较慢时会多等一会,正在努力准备中...';
}
}, 4000);
var removeTimer = 0;
var cdnConfigLoadStarted = false;
var resolveMainEntryReady = null;
var BOOT_CDN_PACKAGE_NAME = 'aitu-app';
var BOOT_CDN_BASE_URL = 'https://cdn.jsdelivr.net/npm/';
var BOOT_LOCAL_RETRY_STORAGE_KEY = '__OPENTU_BOOT_LOCAL_RETRY_AT__';
var BOOT_IMPORT_RETRY_STORAGE_KEY = '__OPENTU_BOOT_IMPORT_RETRY_AT__';
var BOOT_LOCAL_RETRY_TTL_MS = 2 * 60 * 1000;
var forceLocalBootAssets = false;
window.__OPENTU_START_MAIN_ENTRY__ = new Promise(function (resolve) {
resolveMainEntryReady = resolve;
});
(function initializeBootLocalRetryFlag() {
try {
var retryAtRaw = window.sessionStorage.getItem(
BOOT_LOCAL_RETRY_STORAGE_KEY
);
if (!retryAtRaw) {
return;
}
var retryAt = Number(retryAtRaw);
if (
!isFinite(retryAt) ||
Date.now() - retryAt > BOOT_LOCAL_RETRY_TTL_MS
) {
window.sessionStorage.removeItem(BOOT_LOCAL_RETRY_STORAGE_KEY);
return;
}
forceLocalBootAssets = true;
} catch (_error) {
forceLocalBootAssets = false;
}
})();
function clearBootLocalRetryFlag() {
forceLocalBootAssets = false;
try {
window.sessionStorage.removeItem(BOOT_LOCAL_RETRY_STORAGE_KEY);
window.sessionStorage.removeItem(BOOT_IMPORT_RETRY_STORAGE_KEY);
} catch (_error) {
// ignore sessionStorage cleanup failures
}
}
function scheduleBootSelfHealReload() {
if (isBootLocalDevelopment() || forceLocalBootAssets) {
return false;
}
try {
window.sessionStorage.setItem(
BOOT_LOCAL_RETRY_STORAGE_KEY,
String(Date.now())
);
} catch (_error) {
return false;
}
var tip = document.querySelector('[data-app-boot-tip]');
if (tip) {
tip.textContent = '首屏资源回退中,正在自动重试...';
}
window.location.reload();
return true;
}
function isRecoverableBootImportError(error) {
var message =
error && typeof error.message === 'string'
? error.message
: String(error || '');
return (
/Failed to fetch dynamically imported module/i.test(message) ||
/Importing a module script failed/i.test(message) ||
/Loading chunk [\w-]+ failed/i.test(message) ||
/ChunkLoadError/i.test(message)
);
}
function hasBootImportRetryParam() {
try {
return new URLSearchParams(window.location.search).has(
'_lazy_chunk_retry'
);
} catch (_error) {
return window.location.search.indexOf('_lazy_chunk_retry=') !== -1;
}
}
function createBootImportRecoveryUrl() {
var recoveryUrl = new URL(window.location.href);
recoveryUrl.searchParams.set('_lazy_chunk_retry', '1');
recoveryUrl.searchParams.set('_t', String(Date.now()));
return recoveryUrl.toString();
}
function prepareBootImportRecovery() {
var tasks = [];
try {
if (navigator.serviceWorker && navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage({
type: 'RECOVER_DYNAMIC_IMPORT_FAILURE',
appVersion: getBootAppVersion(),
moduleKey: 'boot-main-entry',
});
}
} catch (_error) {
// ignore best-effort SW notification failures
}
try {
if (window.caches && typeof window.caches.keys === 'function') {
tasks.push(
window.caches.keys().then(function (cacheNames) {
return Promise.all(
cacheNames
.filter(function (name) {
return name.indexOf('drawnix-static-v') === 0;
})
.map(function (name) {
return window.caches.delete(name);
})
);
})
);
}
} catch (_error) {
// ignore cache cleanup failures
}
return Promise.allSettled(tasks);
}
window.__OPENTU_BOOT_DYNAMIC_IMPORT_RECOVERY__ = function (error) {
if (
!isRecoverableBootImportError(error) ||
isBootLocalDevelopment()
) {
return false;
}
try {
var lastRetryAt = Number(
window.sessionStorage.getItem(BOOT_IMPORT_RETRY_STORAGE_KEY)
);
if (
isFinite(lastRetryAt) &&
Date.now() - lastRetryAt <= BOOT_LOCAL_RETRY_TTL_MS
) {
return false;
}
window.sessionStorage.setItem(
BOOT_IMPORT_RETRY_STORAGE_KEY,
String(Date.now())
);
} catch (_error) {
if (hasBootImportRetryParam()) {
return false;
}
}
var recoveryUrl = createBootImportRecoveryUrl();
var didReload = false;
var reload = function () {
if (didReload) {
return;
}
didReload = true;
window.location.replace(recoveryUrl);
};
var tip = document.querySelector('[data-app-boot-tip]');
if (tip) {
tip.textContent = '启动资源已更新,正在自动刷新恢复...';
}
window.setTimeout(reload, 700);
prepareBootImportRecovery().then(reload, reload);
return true;
};
function clearBootTimers() {
if (slowTipTimer) {
window.clearTimeout(slowTipTimer);
slowTipTimer = 0;
}
if (removeTimer) {
window.clearTimeout(removeTimer);
removeTimer = 0;
}
if (simulationTimer) {
window.clearInterval(simulationTimer);
simulationTimer = 0;
}
}
function getBootRoot() {
return document.getElementById('app-boot-loading');
}
function getBootAppVersion() {
var versionMeta = document.querySelector('meta[name="app-version"]');
return versionMeta
? versionMeta.getAttribute('content') || '0.0.0'
: '0.0.0';
}
function isBootLocalDevelopment() {
return (
window.location.hostname === 'localhost' ||
window.location.hostname === '127.0.0.1' ||
window.location.hostname.endsWith('.localhost') ||
window.location.protocol === 'file:' ||
window.__OPENTU_DESKTOP__ === true ||
!!window.trueGrowthRuntime
);
}
function toPreferredBootAssetUrl(localPath) {
if (!localPath || isBootLocalDevelopment() || forceLocalBootAssets) {
return localPath;
}
var normalizedPath = String(localPath).trim();
if (/^https?:\/\//i.test(normalizedPath)) {
return normalizedPath;
}
normalizedPath = normalizedPath
.replace(/^\.?\//, '')
.replace(/^npm\/aitu-app@[^/]+\//, '')
.replace(/^aitu-app@[^/]+\//, '');
return (
BOOT_CDN_BASE_URL +
BOOT_CDN_PACKAGE_NAME +
'@' +
getBootAppVersion() +
'/' +
normalizedPath
);
}
function isManagedBootFallbackTarget(target) {
return !!(
target &&
typeof target.getAttribute === 'function' &&
target.getAttribute('data-cdn-fallback-managed') === '1'
);
}
function pinManagedBootAssetsToLocal() {
if (!isBootLocalDevelopment()) {
return;
}
var targets = document.querySelectorAll(
'[data-cdn-fallback-managed="1"]'
);
targets.forEach(function (target) {
var localSrc = target.getAttribute('data-local-src');
var localHref = target.getAttribute('data-local-href');
if (localSrc && target.getAttribute('src') !== localSrc) {
target.setAttribute('src', localSrc);
}
if (localHref && target.getAttribute('href') !== localHref) {
target.setAttribute('href', localHref);
}
});
}
function createLocalBootAssetNode(target, localUrl) {
var replacement = target.cloneNode(false);
replacement.setAttribute('data-fallback-attempted', '1');
replacement.removeAttribute('onerror');
var failureMessage =
target.tagName === 'SCRIPT'
? '首屏脚本加载失败,请刷新页面后重试。'
: target.getAttribute('rel') === 'stylesheet'
? '首屏样式加载失败,请刷新页面后重试。'
: '首屏资源加载失败,请刷新页面后重试。';
if (target.tagName === 'SCRIPT') {
replacement.setAttribute('src', localUrl);
replacement.onerror = function () {
markError(failureMessage);
};
return replacement;
}
replacement.setAttribute('href', localUrl);
replacement.onerror = function () {
markError(failureMessage);
};
return replacement;
}
window.__OPENTU_BOOT_ASSET_FALLBACK__ = function (target) {
if (!target) {
return false;
}
var localUrl =
target.getAttribute('data-local-src') ||
target.getAttribute('data-local-href');
if (!localUrl) {
return false;
}
if (target.getAttribute('data-fallback-attempted') === '1') {
markError(
target.tagName === 'SCRIPT'
? '首屏脚本加载失败,请刷新页面后重试。'
: target.getAttribute('rel') === 'stylesheet'
? '首屏样式加载失败,请刷新页面后重试。'
: '首屏资源加载失败,请刷新页面后重试。'
);
return true;
}
if (
target.tagName === 'SCRIPT' &&
target.getAttribute('type') === 'module' &&
scheduleBootSelfHealReload()
) {
return true;
}
var replacement = createLocalBootAssetNode(target, localUrl);
if (target.parentNode) {
target.parentNode.replaceChild(replacement, target);
}
return true;
};
function appendManagedBootScript(localPath, onload, onfinalerror) {
var preferredUrl = toPreferredBootAssetUrl(localPath);
var script = document.createElement('script');
script.async = true;
script.setAttribute('data-cdn-fallback-managed', '1');
script.setAttribute('data-local-src', localPath);
var handleFinalFailure = function () {
if (typeof onfinalerror === 'function') {
onfinalerror();
}
};
if (!preferredUrl || preferredUrl === localPath) {
script.src = localPath;
script.onload = onload;
script.onerror = handleFinalFailure;
document.head.appendChild(script);
return;
}
script.src = preferredUrl;
script.onload = onload;
script.onerror = function () {
var localScript = document.createElement('script');
localScript.async = true;
localScript.src = localPath;
localScript.setAttribute('data-cdn-fallback-managed', '1');
localScript.setAttribute('data-fallback-attempted', '1');
localScript.onload = onload;
localScript.onerror = handleFinalFailure;
if (script.parentNode) {
script.parentNode.removeChild(script);
}
document.head.appendChild(localScript);
};
document.head.appendChild(script);
}
pinManagedBootAssetsToLocal();
function clampProgress(value) {
if (!isFinite(value)) {
return bootProgress;
}
return Math.max(0, Math.min(100, value));
}
function renderProgress() {
var progressRoot = document.querySelector('[data-app-boot-progress]');
var progressFill = document.querySelector(
'[data-app-boot-progress-fill]'
);
var progressValue = document.querySelector(
'[data-app-boot-progress-value]'
);
var safeProgress = Math.round(clampProgress(bootProgress));
if (progressRoot) {
progressRoot.setAttribute('aria-valuenow', String(safeProgress));
}
document.documentElement.style.setProperty(
'--app-boot-progress',
safeProgress + '%'
);
document.documentElement.style.setProperty(
'--app-boot-flight-speed',
Math.max(0.52, 3.2 - safeProgress * 0.027).toFixed(2) + 's'
);
document.documentElement.style.setProperty(
'--app-boot-flight-blur',
(2 + safeProgress * 0.018).toFixed(2) + 'px'
);
document.documentElement.style.setProperty(
'--app-boot-flight-opacity',
Math.min(0.9, 0.48 + safeProgress * 0.004).toFixed(2)
);
if (progressFill) {
progressFill.style.width = safeProgress + '%';
}
if (progressValue) {
progressValue.textContent = safeProgress + '%';
}
}
function startSimulatedProgress() {
if (simulationTimer) {
return;
}
simulationTimer = window.setInterval(function () {
if (bootReady) {
window.clearInterval(simulationTimer);
simulationTimer = 0;
return;
}
var elapsed = Date.now() - simulationStartAt;
var simulatedProgress = Math.min(82, (elapsed / 4200) * 82);
if (simulatedProgress > bootProgress) {
bootProgress = simulatedProgress;
renderProgress();
}
if (simulatedProgress >= 82) {
window.clearInterval(simulationTimer);
simulationTimer = 0;
}
}, 60);
}
function setProgress(value, options) {
if (bootReady) {
return;
}
if (typeof value === 'number' && isFinite(value)) {
bootProgress = Math.max(bootProgress, clampProgress(value));
}
var title = document.querySelector('[data-app-boot-title]');
var tip = document.querySelector('[data-app-boot-tip]');
var note = document.querySelector('[data-app-boot-note]');
if (options && typeof options.title === 'string' && title) {
title.textContent = options.title;
}
if (options && typeof options.tip === 'string' && tip) {
tip.textContent = options.tip;
}
if (options && typeof options.note === 'string' && note) {
note.textContent = options.note;
}
renderProgress();
}
function markReady() {
if (bootReady) {
return;
}
document.documentElement.classList.add('app-ready');
clearBootLocalRetryFlag();
setProgress(100, {
tip: '启动完成,正在进入工作台...',
});
bootReady = true;
clearBootTimers();
var bootRoot = getBootRoot();
if (!bootRoot) {
return;
}
bootRoot.classList.add('is-leaving');
var removeBootRoot = function () {
if (bootRoot.parentNode) {
bootRoot.parentNode.removeChild(bootRoot);
}
};
bootRoot.addEventListener('transitionend', removeBootRoot, {
once: true,
});
removeTimer = window.setTimeout(removeBootRoot, 360);
}
function markError(message) {
if (bootReady) {
return;
}
setProgress(100);
clearBootTimers();
document.documentElement.classList.add('app-boot-error');
var title = document.querySelector('[data-app-boot-title]');
var tip = document.querySelector('[data-app-boot-tip]');
if (title) {
title.textContent = '启动中遇到问题';
}
if (tip) {
tip.textContent = message || '资源加载失败,请刷新页面后重试。';
}
}
window.__OPENTU_BOOT__ = {
markReady: markReady,
markError: markError,
setProgress: setProgress,
};
function getRuntimeCDNPreference() {
var preference = window.__OPENTU_CDN__ || window.__AITU_CDN__;
if (!preference || typeof preference !== 'object') {
return null;
}
var cdn = preference.cdn;
if (cdn !== 'jsdelivr' && cdn !== 'unpkg' && cdn !== 'local') {
return null;
}
return {
cdn: cdn,
latency:
typeof preference.latency === 'number' &&
isFinite(preference.latency)
? Math.max(0, preference.latency)
: 0,
timestamp:
typeof preference.timestamp === 'number' &&
isFinite(preference.timestamp) &&
preference.timestamp > 0
? preference.timestamp
: Date.now(),
};
}
function postCDNPreferenceToRegistration(registration, preference) {
if (!registration || !preference) {
return;
}
var payload = {
type: 'SW_CDN_SET_PREFERENCE',
cdn: preference.cdn,
latency: preference.latency,
timestamp: preference.timestamp,
version: (function () {
var versionMeta = document.querySelector(
'meta[name="app-version"]'
);
return versionMeta
? versionMeta.getAttribute('content') || '0.0.0'
: '0.0.0';
})(),
};
var targets = [];
var maybeWorkers = [
navigator.serviceWorker.controller,
registration.active,
registration.waiting,
registration.installing,
];
for (var i = 0; i < maybeWorkers.length; i++) {
var worker = maybeWorkers[i];
if (worker && targets.indexOf(worker) === -1) {
targets.push(worker);
}
}
for (var j = 0; j < targets.length; j++) {
targets[j].postMessage(payload);
}
}
function syncEarlyCDNPreference(registration) {
var cachedPreference = getRuntimeCDNPreference();
if (cachedPreference) {
postCDNPreferenceToRegistration(registration, cachedPreference);
}
var api = window.__OPENTU_CDN_API__ || window.__AITU_CDN_API__;
if (!api || typeof api.selectBestCDN !== 'function') {
return;
}
api
.selectBestCDN()
.then(function (preference) {
if (!preference || typeof preference !== 'object') {
return;
}
window.__OPENTU_CDN__ = preference;
window.__AITU_CDN__ = preference;
postCDNPreferenceToRegistration(registration, {
cdn: preference.cdn,
latency:
typeof preference.latency === 'number' &&
isFinite(preference.latency)
? Math.max(0, preference.latency)
: 0,
timestamp:
typeof preference.timestamp === 'number' &&
isFinite(preference.timestamp) &&
preference.timestamp > 0
? preference.timestamp
: Date.now(),
});
})
.catch(function (error) {
console.warn('[Boot] Early CDN preference sync failed:', error);
});
}
function shouldEnableEarlyServiceWorkerBootstrap() {
try {
var swParam = new URLSearchParams(window.location.search).get('sw');
if (swParam === '0') {
return false;
}
return true;
} catch {
if (window.location.search.indexOf('sw=0') !== -1) {
return false;
}
return true;
}
}
function cleanupExplicitlyDisabledServiceWorker() {
if (!('serviceWorker' in navigator)) {
return;
}
navigator.serviceWorker
.getRegistration()
.then(function (registration) {
if (registration) {
return registration.unregister();
}
return false;
})
.catch(function (error) {
console.warn(
'[Boot] Disabled service worker cleanup failed:',
error
);
});
}
function setupEarlyServiceWorkerBootstrap() {
if (!('serviceWorker' in navigator)) {
return;
}
if (!shouldEnableEarlyServiceWorkerBootstrap()) {
cleanupExplicitlyDisabledServiceWorker();
setProgress(52, {
tip: '已按 URL 参数跳过离线缓存服务,正在直接启动工作台...',
source: 'phase',
});
return;
}
if (!window.__OPENTU_SW_REGISTRATION_PROMISE__) {
setProgress(undefined, {
tip: '正在连接启动缓存服务...',
source: 'phase',
});
window.__OPENTU_SW_REGISTRATION_PROMISE__ = navigator.serviceWorker
.register('./sw.js')
.then(function (registration) {
syncEarlyCDNPreference(registration);
setProgress(54, {
tip: '启动缓存服务已连接,正在准备资源清单...',
source: 'phase',
});
if (
registration.active &&
!registration.installing &&
!registration.waiting
) {
setProgress(58, {
tip: '启动缓存服务已就绪,正在恢复工作台状态...',
source: 'phase',
});
}
return registration;
})
.catch(function (error) {
console.warn(
'[Boot] Early service worker registration failed:',
error
);
setProgress(52, {
tip: '离线加速未启用,正在直接启动工作台...',
source: 'phase',
});
return null;
});
} else {
window.__OPENTU_SW_REGISTRATION_PROMISE__.then(function (
registration
) {
syncEarlyCDNPreference(registration);
});
}
}
function loadCDNConfigAndBootstrap() {
if (cdnConfigLoadStarted) {
return;
}
cdnConfigLoadStarted = true;
appendManagedBootScript(
'./cdn-config.js',
function () {
setupEarlyServiceWorkerBootstrap();
if (resolveMainEntryReady) {
resolveMainEntryReady();
resolveMainEntryReady = null;
}
},
function () {
console.warn(
'[Boot] CDN config load failed, fallback to local bootstrap'
);
setupEarlyServiceWorkerBootstrap();
if (resolveMainEntryReady) {
resolveMainEntryReady();
resolveMainEntryReady = null;
}
}
);
}
renderProgress();
startSimulatedProgress();
loadCDNConfigAndBootstrap();
window.addEventListener(
'error',
function (event) {
var target = event && event.target;
if (target && target !== window && (target.src || target.href)) {
if (isManagedBootFallbackTarget(target)) {
return;
}
var resourceUrl = target.src || target.href || '';
var resourceName = resourceUrl.split('/').pop() || '资源文件';
markError(resourceName + ' 加载失败,请刷新页面后重试。');
return;
}
var message =
event && typeof event.message === 'string' && event.message.trim()
? event.message.trim()
: '启动脚本执行失败,请刷新页面后重试。';
markError(message);
},
{ once: true }
);
window.addEventListener(
'unhandledrejection',
function (event) {
var reason = event && event.reason;
var message =
reason && typeof reason.message === 'string'
? reason.message
: typeof reason === 'string'
? reason
: '启动过程中发生异常,请刷新页面后重试。';
markError(message);
},
{ once: true }
);
})();
</script>
<div id="root"></div>
<script type="module">
(async function () {
try {
await (window.__OPENTU_START_MAIN_ENTRY__ || Promise.resolve());
await import('./src/main.tsx');
} catch (error) {
if (
window.__OPENTU_BOOT_DYNAMIC_IMPORT_RECOVERY__ &&
window.__OPENTU_BOOT_DYNAMIC_IMPORT_RECOVERY__(error)
) {
return;
}
throw error;
}
})();
</script>
</body>
<!-- PostHog Analytics -->
<!-- 本地开发环境localhost/127.0.0.1)默认不加载,除非 URL 带 report=1 参数 -->
<script>
(function () {
var isLocalDev =
window.location.hostname === 'localhost' ||
window.location.hostname === '127.0.0.1';
var forceReport =
new URLSearchParams(window.location.search).get('report') === '1';
// 本地开发环境且没有 report=1 参数时,不加载 PostHog
if (isLocalDev && !forceReport) {
return;
}
!(function (t, e) {
var o, n, p, r;
e.__SV ||
(window.posthog && window.posthog.__loaded) ||
((window.posthog = e),
(e._i = []),
(e.init = function (i, s, a) {
function g(t, e) {
var o = e.split('.');
2 == o.length && ((t = t[o[0]]), (e = o[1])),
(t[e] = function () {
t.push([e].concat(Array.prototype.slice.call(arguments, 0)));
});
}
((p = t.createElement('script')).type = 'text/javascript'),
(p.crossOrigin = 'anonymous'),
(p.async = !0),
(p.src =
s.api_host.replace('.i.posthog.com', '-assets.i.posthog.com') +
'/static/array.js'),
(r = t.getElementsByTagName('script')[0]).parentNode.insertBefore(
p,
r
);
var u = e;
for (
void 0 !== a ? (u = e[a] = []) : (a = 'posthog'),
u.people = u.people || [],
u.toString = function (t) {
var e = 'posthog';
return (
'posthog' !== a && (e += '.' + a), t || (e += ' (stub)'), e
);
},
u.people.toString = function () {
return u.toString(1) + '.people (stub)';
},
o =
'init Dr Ur fi Lr zr ci Or jr capture Ai calculateEventProperties qr register register_once register_for_session unregister unregister_for_session Jr getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSurveysLoaded onSessionId getSurveys getActiveMatchingSurveys renderSurvey displaySurvey cancelPendingSurvey canRenderSurvey canRenderSurveyAsync identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty Gr Br createPersonProfile Vr Cr Kr opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing get_explicit_consent_status is_capturing clear_opt_in_out_capturing Hr debug O Wr getPageViewId captureTraceFeedback captureTraceMetric Rr'.split(
' '
),
n = 0;
n < o.length;
n++
)
g(u, o[n]);
e._i.push([i, s, a]);
}),
(e.__SV = 1));
})(document, window.posthog || []);
var isIgnorableExceptionEvent = function (event) {
if (!event || event.event !== '$exception') return false;
var properties = event.properties || {};
var messages = [];
var appendMessages = function (value) {
if (!value) return;
if (typeof value === 'string') {
messages.push(value);
if (
value.length < 2000 &&
(value.charAt(0) === '[' || value.charAt(0) === '{')
) {
try {
appendMessages(JSON.parse(value));
} catch (_) {}
}
return;
}
if (Array.isArray(value)) {
for (var i = 0; i < value.length; i++) {
appendMessages(value[i]);
}
return;
}
if (typeof value === 'object') {
if (typeof value.value === 'string') messages.push(value.value);
if (typeof value.message === 'string') messages.push(value.message);
if (typeof value.name === 'string') messages.push(value.name);
}
};
appendMessages(properties.$exception_values);
appendMessages(properties.$exception_list);
appendMessages(properties.$exception_message);
appendMessages(properties.$exception_type);
appendMessages(properties.$exception_types);
appendMessages(properties.message);
appendMessages(properties.name);
appendMessages(event.exception);
appendMessages(event.error);
var text = messages.join('\n');
return (
text.indexOf(
'ResizeObserver loop completed with undelivered notifications'
) !== -1 ||
text.indexOf('ResizeObserver loop limit exceeded') !== -1 ||
(text.indexOf('WebCodecs API') !== -1 &&
(text.indexOf('Chrome 94+') !== -1 ||
text.indexOf('Edge 94+') !== -1)) ||
(text.indexOf("Failed to execute 'write' on 'Clipboard'") !== -1 &&
text.indexOf('permissions policy') !== -1) ||
((text.indexOf('AbortError') !== -1 ||
text.indexOf('The user aborted a request') !== -1) &&
(text.indexOf("Failed to execute 'showOpenFilePicker'") !== -1 ||
text.indexOf("Failed to execute 'showSaveFilePicker'") !== -1 ||
text.indexOf('The user aborted a request') !== -1)) ||
text.indexOf('No key or key range specified') !== -1
);
};
posthog.init('phc_13URtidKwTR9POlwnB153NsN99shRykvPguKWf3vZVn', {
api_host: 'https://us.i.posthog.com',
defaults: '2025-11-30',
person_profiles: 'identified_only',
// 关闭 Session Recording避免 rrweb 主线程开销wheel/setInterval与 413
disable_session_recording: true,
// 限制单次 flush 体积,避免 413 Content Too Large
rate_limiting: { events_per_second: 10, events_burst_limit: 30 },
request_queue: { flush_interval_ms: 2000 },
// 白板 SPA 点击多,关闭 autocapture 减少事件量与请求体
autocapture: false,
// 静默网络错误;避免 413 重试风暴干扰
on_xhr_error: function (err) {
var code =
err &&
(typeof err.statusCode !== 'undefined'
? err.statusCode
: err.status);
void code;
},
before_send: function (event) {
if (isIgnorableExceptionEvent(event)) return false;
return event;
},
});
})();
</script>
</html>