diff --git a/crates/op-editor-core/assets/scene_templates.toml b/crates/op-editor-core/assets/scene_templates.toml index a83e0c438..088f976ff 100644 --- a/crates/op-editor-core/assets/scene_templates.toml +++ b/crates/op-editor-core/assets/scene_templates.toml @@ -45,6 +45,30 @@ frames = 6 frame_width = 1920 frame_height = 1080 +[[template]] +id = "knowledge-card-vertical" +scene = "card" +title_key = "sceneTemplate.item.knowledgeCardVertical.title" +title_fallback = "知识卡片 · 竖版" +summary_key = "sceneTemplate.item.knowledgeCardVertical.summary" +summary_fallback = "3:4 单张图文卡,标题、四条要点和署名条,换掉文案就能发小红书。" +tags = ["卡片", "知识", "小红书", "图文", "card", "note"] +frames = 1 +frame_width = 1080 +frame_height = 1440 + +[[template]] +id = "knowledge-card-square" +scene = "card" +title_key = "sceneTemplate.item.knowledgeCardSquare.title" +title_fallback = "知识卡片 · 方版" +summary_key = "sceneTemplate.item.knowledgeCardSquare.summary" +summary_fallback = "1:1 方形卡,同一套版式的紧凑版,适合公众号头图与朋友圈。" +tags = ["卡片", "知识", "方形", "公众号", "card", "square"] +frames = 1 +frame_width = 1080 +frame_height = 1080 + [[template]] id = "before-after" scene = "comparison" @@ -56,3 +80,51 @@ tags = ["对比", "前后", "复盘", "comparison", "before after"] frames = 1 frame_width = 1600 frame_height = 900 + +[[template]] +id = "pitch-deck-dark" +scene = "slides" +title_key = "sceneTemplate.item.pitchDeckDark.title" +title_fallback = "路演 deck · 深色" +summary_key = "sceneTemplate.item.pitchDeckDark.summary" +summary_fallback = "封面、问题、方案、数据、里程碑和联系页,深底大字,适合融资路演与产品发布。" +tags = ["路演", "融资", "创业", "深色", "PPT", "pitch", "deck", "startup", "dark"] +frames = 6 +frame_width = 1920 +frame_height = 1080 + +[[template]] +id = "lecture-deck-light" +scene = "slides" +title_key = "sceneTemplate.item.lectureDeckLight.title" +title_fallback = "课件 deck · 浅色" +summary_key = "sceneTemplate.item.lectureDeckLight.summary" +summary_fallback = "课程封面、学习目标、概念讲解、例题、对比表和小结作业,纸白底耐看,适合上课投影。" +tags = ["课件", "教学", "讲课", "教育", "PPT", "lecture", "teaching", "course", "light"] +frames = 6 +frame_width = 1920 +frame_height = 1080 + +[[template]] +id = "minimal-keynote" +scene = "slides" +title_key = "sceneTemplate.item.minimalKeynote.title" +title_fallback = "极简 Keynote" +summary_key = "sceneTemplate.item.minimalKeynote.summary" +summary_fallback = "纯白留白、超大字号、一页一个意思,八页里没有一张卡片,适合发布会与主题演讲。" +tags = ["极简", "留白", "发布会", "演讲", "keynote", "minimal", "PPT", "slides"] +frames = 8 +frame_width = 1920 +frame_height = 1080 + +[[template]] +id = "gradient-tech" +scene = "slides" +title_key = "sceneTemplate.item.gradientTech.title" +title_fallback = "渐变科技风" +summary_key = "sceneTemplate.item.gradientTech.summary" +summary_fallback = "深色渐变底加玻璃拟态卡,含架构、性能对比与客户墙,适合开发者产品发布。" +tags = ["渐变", "科技", "玻璃", "深色", "开发者", "gradient", "tech", "glass", "PPT"] +frames = 6 +frame_width = 1920 +frame_height = 1080 diff --git a/crates/op-editor-core/assets/scene_templates/gradient-tech.op b/crates/op-editor-core/assets/scene_templates/gradient-tech.op new file mode 100644 index 000000000..7b77cb754 --- /dev/null +++ b/crates/op-editor-core/assets/scene_templates/gradient-tech.op @@ -0,0 +1,2838 @@ +{ + "version": "1.0.0", + "name": "渐变科技风 · 16:9", + "variables": { + "c-grad-a": { + "type": "color", + "value": "#1B0B3B" + }, + "c-grad-b": { + "type": "color", + "value": "#2A1E6E" + }, + "c-grad-c": { + "type": "color", + "value": "#0A2C6E" + }, + "c-ink": { + "type": "color", + "value": "#FFFFFF" + }, + "c-muted": { + "type": "color", + "value": "#C9D4F5" + }, + "c-accent": { + "type": "color", + "value": "#3AC8FF" + }, + "c-bar-base": { + "type": "color", + "value": "#8A83AF" + }, + "c-glass-a": { + "type": "color", + "value": "#362853" + }, + "c-glass-b": { + "type": "color", + "value": "#44397F" + }, + "c-glass-c": { + "type": "color", + "value": "#27457F" + }, + "c-glass-edge": { + "type": "color", + "value": "#FFFFFF4D" + } + }, + "children": [ + { + "type": "frame", + "id": "f6", + "name": "01 封面", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 48, + "justifyContent": "space_between", + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-grad-a" + }, + { + "offset": 0.55, + "color": "$c-grad-b" + }, + { + "offset": 1.0, + "color": "$c-grad-c" + } + ] + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f7", + "name": "标签", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "padding": [ + 10, + 22 + ], + "gap": 0, + "cornerRadius": 999, + "alignItems": "center", + "justifyContent": "center", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t8", + "name": "标签文字", + "content": "v3.0 · 公测", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.4, + "letterSpacing": 1.0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f3", + "name": "主张", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 32, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t1", + "name": "主标题", + "content": "让每一次调用\n都在 20 毫秒内返回", + "fontFamily": "Noto Sans SC", + "fontSize": 96, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.12, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t2", + "name": "副标题", + "content": "边缘推理网关 v3.0,现已开放公测。", + "fontFamily": "Noto Sans SC", + "fontSize": 32, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f5", + "name": "安装行", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 26, + 32 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t4", + "name": "安装命令", + "content": "$ npm i -g edgegate && edgegate up", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ], + "x": 0, + "y": 0 + }, + { + "type": "frame", + "id": "f21", + "name": "02 痛点", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-grad-a" + }, + { + "offset": 0.55, + "color": "$c-grad-b" + }, + { + "offset": 1.0, + "color": "$c-grad-c" + } + ] + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f24", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t22", + "name": "页标题", + "content": "在边缘跑推理,卡在三件事上", + "fontFamily": "Noto Sans SC", + "fontSize": 60, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t23", + "name": "页副标题", + "content": "都不是模型的问题,是它前面那一层的问题。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f26", + "name": "痛点区", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "f25", + "name": "痛点网格", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 32, + "alignItems": "stretch", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f12", + "name": "痛点卡", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 44, + 36 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t9", + "name": "痛点序号", + "content": "01", + "fontFamily": "Inter", + "fontSize": 30, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.1, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "text", + "id": "t10", + "name": "痛点标题", + "content": "冷启动吃掉了首包", + "fontFamily": "Noto Sans SC", + "fontSize": 36, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t11", + "name": "痛点说明", + "content": "函数实例每次唤醒要 800ms,用户看到的却是整整一秒的白屏。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.55, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f16", + "name": "痛点卡", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 44, + 36 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t13", + "name": "痛点序号", + "content": "02", + "fontFamily": "Inter", + "fontSize": 30, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.1, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "text", + "id": "t14", + "name": "痛点标题", + "content": "账单没法归因", + "fontFamily": "Noto Sans SC", + "fontSize": 36, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t15", + "name": "痛点说明", + "content": "月底一张总额,分不清哪个模型、哪条链路花掉的。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.55, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f20", + "name": "痛点卡", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 44, + 36 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t17", + "name": "痛点序号", + "content": "03", + "fontFamily": "Inter", + "fontSize": 30, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.1, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "text", + "id": "t18", + "name": "痛点标题", + "content": "换云就得重写", + "fontFamily": "Noto Sans SC", + "fontSize": 36, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t19", + "name": "痛点说明", + "content": "每家的运行时都不一样,迁移一次等于把接入层重做一遍。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.55, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + } + ], + "x": 2040, + "y": 0 + }, + { + "type": "frame", + "id": "f42", + "name": "03 架构", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-grad-a" + }, + { + "offset": 0.55, + "color": "$c-grad-b" + }, + { + "offset": 1.0, + "color": "$c-grad-c" + } + ] + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f45", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t43", + "name": "页标题", + "content": "三层,一层只做一件事", + "fontFamily": "Noto Sans SC", + "fontSize": 60, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t44", + "name": "页副标题", + "content": "自上而下,每一层都能单独替换。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f47", + "name": "架构区", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "f46", + "name": "架构堆叠", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 20, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f31", + "name": "架构层", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 12, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 32, + 36 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "frame", + "id": "f29", + "name": "层头", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "gap": 16, + "alignItems": "center", + "fill": [], + "children": [ + { + "type": "text", + "id": "t27", + "name": "层名", + "content": "接入层", + "fontFamily": "Noto Sans SC", + "fontSize": 36, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "text", + "id": "t28", + "name": "层英文名", + "content": "Gateway", + "fontFamily": "Inter", + "fontSize": 26, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "text", + "id": "t30", + "name": "层说明", + "content": "一个 Anycast 入口,就近落到最快的可用区。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.55, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f36", + "name": "架构层", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 12, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 32, + 36 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "frame", + "id": "f34", + "name": "层头", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "gap": 16, + "alignItems": "center", + "fill": [], + "children": [ + { + "type": "text", + "id": "t32", + "name": "层名", + "content": "调度层", + "fontFamily": "Noto Sans SC", + "fontSize": 36, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "text", + "id": "t33", + "name": "层英文名", + "content": "Scheduler", + "fontFamily": "Inter", + "fontSize": 26, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "text", + "id": "t35", + "name": "层说明", + "content": "按延迟预算和单价实时选模型,超时自动降级。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.55, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f41", + "name": "架构层", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 12, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 32, + 36 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "frame", + "id": "f39", + "name": "层头", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "gap": 16, + "alignItems": "center", + "fill": [], + "children": [ + { + "type": "text", + "id": "t37", + "name": "层名", + "content": "运行层", + "fontFamily": "Noto Sans SC", + "fontSize": 36, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "text", + "id": "t38", + "name": "层英文名", + "content": "Runtime", + "fontFamily": "Inter", + "fontSize": 26, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "text", + "id": "t40", + "name": "层说明", + "content": "常驻实例池,冷启动摊薄到 3 毫秒以内。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.55, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + } + ], + "x": 4080, + "y": 0 + }, + { + "type": "frame", + "id": "f79", + "name": "04 性能", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 44, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-grad-a" + }, + { + "offset": 0.55, + "color": "$c-grad-b" + }, + { + "offset": 1.0, + "color": "$c-grad-c" + } + ] + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f81", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t80", + "name": "页标题", + "content": "数字是压测出来的,不是估的", + "fontFamily": "Noto Sans SC", + "fontSize": 60, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f82", + "name": "性能居中", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "f78", + "name": "性能区", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 32, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f77", + "name": "性能网格", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 32, + "alignItems": "stretch", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f62", + "name": "性能卡", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 16, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 40, + 32 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "frame", + "id": "f59", + "name": "数值", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "gap": 8, + "alignItems": "end", + "fill": [], + "children": [ + { + "type": "text", + "id": "t56", + "name": "数值文字", + "content": "20", + "fontFamily": "Inter", + "fontSize": 132, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "frame", + "id": "f58", + "name": "单位", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "padding": [ + 0, + 0, + 18, + 0 + ], + "children": [ + { + "type": "text", + "id": "t57", + "name": "单位文字", + "content": "ms", + "fontFamily": "Inter", + "fontSize": 40, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ] + }, + { + "type": "text", + "id": "t60", + "name": "指标名", + "content": "P50 端到端", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t61", + "name": "指标说明", + "content": "含调度与网络", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f69", + "name": "性能卡", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 16, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 40, + 32 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "frame", + "id": "f66", + "name": "数值", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "gap": 8, + "alignItems": "end", + "fill": [], + "children": [ + { + "type": "text", + "id": "t63", + "name": "数值文字", + "content": "3", + "fontFamily": "Inter", + "fontSize": 132, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "frame", + "id": "f65", + "name": "单位", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "padding": [ + 0, + 0, + 18, + 0 + ], + "children": [ + { + "type": "text", + "id": "t64", + "name": "单位文字", + "content": "ms", + "fontFamily": "Inter", + "fontSize": 40, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ] + }, + { + "type": "text", + "id": "t67", + "name": "指标名", + "content": "冷启动", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t68", + "name": "指标说明", + "content": "常驻池摊薄后", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f76", + "name": "性能卡", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 16, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 40, + 32 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "frame", + "id": "f73", + "name": "数值", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "gap": 8, + "alignItems": "end", + "fill": [], + "children": [ + { + "type": "text", + "id": "t70", + "name": "数值文字", + "content": "62", + "fontFamily": "Inter", + "fontSize": 132, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "frame", + "id": "f72", + "name": "单位", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "padding": [ + 0, + 0, + 18, + 0 + ], + "children": [ + { + "type": "text", + "id": "t71", + "name": "单位文字", + "content": "%", + "fontFamily": "Inter", + "fontSize": 40, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ] + }, + { + "type": "text", + "id": "t74", + "name": "指标名", + "content": "成本下降", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t75", + "name": "指标说明", + "content": "同等 QPS 对比自建", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f55", + "name": "延迟对比", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 20, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 32, + 40 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t48", + "name": "对比标题", + "content": "端到端延迟对比", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "frame", + "id": "f51", + "name": "对比条组", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t49", + "name": "条目标签", + "content": "本产品 · 20ms", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "rectangle", + "id": "r50", + "name": "对比条", + "width": 152, + "height": 16, + "cornerRadius": 999, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f54", + "name": "对比条组", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t52", + "name": "条目标签", + "content": "自建方案 · 210ms", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "rectangle", + "id": "r53", + "name": "对比条", + "width": 1600, + "height": 16, + "cornerRadius": 999, + "fill": [ + { + "type": "solid", + "color": "$c-bar-base" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ], + "x": 0, + "y": 1440 + }, + { + "type": "frame", + "id": "f102", + "name": "05 客户", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-grad-a" + }, + { + "offset": 0.55, + "color": "$c-grad-b" + }, + { + "offset": 1.0, + "color": "$c-grad-c" + } + ] + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f105", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t103", + "name": "页标题", + "content": "已经在生产环境上跑", + "fontFamily": "Noto Sans SC", + "fontSize": 60, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t104", + "name": "页副标题", + "content": "八家团队,日均 27 亿次调用。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f106", + "name": "Logo 区", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "f101", + "name": "Logo 网格", + "width": "fill_container", + "height": 420, + "layout": "vertical", + "gap": 28, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f99", + "name": "Logo 行", + "width": "fill_container", + "height": "fill_container", + "layout": "horizontal", + "gap": 28, + "alignItems": "stretch", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f83", + "name": "Logo 位 1", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 16, + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t84", + "name": "占位提示", + "content": "拖入 Logo", + "fontFamily": "Noto Sans SC", + "fontSize": 24, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f85", + "name": "Logo 位 2", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 16, + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t86", + "name": "占位提示", + "content": "拖入 Logo", + "fontFamily": "Noto Sans SC", + "fontSize": 24, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f87", + "name": "Logo 位 3", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 16, + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t88", + "name": "占位提示", + "content": "拖入 Logo", + "fontFamily": "Noto Sans SC", + "fontSize": 24, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f89", + "name": "Logo 位 4", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 16, + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t90", + "name": "占位提示", + "content": "拖入 Logo", + "fontFamily": "Noto Sans SC", + "fontSize": 24, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f100", + "name": "Logo 行", + "width": "fill_container", + "height": "fill_container", + "layout": "horizontal", + "gap": 28, + "alignItems": "stretch", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f91", + "name": "Logo 位 5", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 16, + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t92", + "name": "占位提示", + "content": "拖入 Logo", + "fontFamily": "Noto Sans SC", + "fontSize": 24, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f93", + "name": "Logo 位 6", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 16, + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t94", + "name": "占位提示", + "content": "拖入 Logo", + "fontFamily": "Noto Sans SC", + "fontSize": 24, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f95", + "name": "Logo 位 7", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 16, + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t96", + "name": "占位提示", + "content": "拖入 Logo", + "fontFamily": "Noto Sans SC", + "fontSize": 24, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f97", + "name": "Logo 位 8", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 16, + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t98", + "name": "占位提示", + "content": "拖入 Logo", + "fontFamily": "Noto Sans SC", + "fontSize": 24, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ] + } + ] + } + ] + } + ], + "x": 2040, + "y": 1440 + }, + { + "type": "frame", + "id": "f115", + "name": "06 CTA", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 48, + "justifyContent": "space_between", + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-grad-a" + }, + { + "offset": 0.55, + "color": "$c-grad-b" + }, + { + "offset": 1.0, + "color": "$c-grad-c" + } + ] + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f116", + "name": "标签", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "padding": [ + 10, + 22 + ], + "gap": 0, + "cornerRadius": 999, + "alignItems": "center", + "justifyContent": "center", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t117", + "name": "标签文字", + "content": "公测开放中", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.4, + "letterSpacing": 1.0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f109", + "name": "结语", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 30, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t107", + "name": "结语标题", + "content": "十分钟接完\n剩下的交给我们", + "fontFamily": "Noto Sans SC", + "fontSize": 84, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t108", + "name": "结语副标题", + "content": "公测期不限调用量,接入文档一页写完。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f114", + "name": "行动区", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "gap": 24, + "alignItems": "center", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f111", + "name": "安装卡", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 26, + 32 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t110", + "name": "安装命令", + "content": "$ npm i -g edgegate", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f113", + "name": "文档卡", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [ + { + "type": "linear_gradient", + "angle": 135, + "stops": [ + { + "offset": 0.0, + "color": "$c-glass-a" + }, + { + "offset": 0.55, + "color": "$c-glass-b" + }, + { + "offset": 1.0, + "color": "$c-glass-c" + } + ] + } + ], + "padding": [ + 26, + 32 + ], + "cornerRadius": 20, + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-glass-edge" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t112", + "name": "文档地址", + "content": "docs.edgegate.dev", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ] + } + ], + "x": 4080, + "y": 1440 + } + ] +} diff --git a/crates/op-editor-core/assets/scene_templates/knowledge-card-square.op b/crates/op-editor-core/assets/scene_templates/knowledge-card-square.op new file mode 100644 index 000000000..4ce5b4f77 --- /dev/null +++ b/crates/op-editor-core/assets/scene_templates/knowledge-card-square.op @@ -0,0 +1,617 @@ +{ + "version": "1.0.0", + "name": "知识卡片 · 方版 1:1", + "variables": { + "c-bg": { + "type": "color", + "value": "#FFF7F0" + }, + "c-surface": { + "type": "color", + "value": "#FFFFFF" + }, + "c-ink": { + "type": "color", + "value": "#241A12" + }, + "c-muted": { + "type": "color", + "value": "#7A6455" + }, + "c-accent": { + "type": "color", + "value": "#C8502B" + }, + "c-accent-soft": { + "type": "color", + "value": "#FAE3D8" + }, + "c-border": { + "type": "color", + "value": "#EDDCD0" + } + }, + "children": [ + { + "type": "frame", + "id": "f74", + "name": "知识卡片 · 方版", + "width": 1080, + "height": 1080, + "layout": "vertical", + "padding": [ + 88, + 84 + ], + "gap": 0, + "justifyContent": "space_between", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f46", + "name": "卡头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 26, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f41", + "name": "标签", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "padding": [ + 12, + 24 + ], + "gap": 0, + "cornerRadius": 999, + "alignItems": "center", + "justifyContent": "center", + "fill": [ + { + "type": "solid", + "color": "$c-accent-soft" + } + ], + "children": [ + { + "type": "text", + "id": "t42", + "name": "标签文字", + "content": "学习方法", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "text", + "id": "t43", + "name": "主标题", + "content": "读完就忘?\n先补上这一步", + "fontFamily": "Noto Sans SC", + "fontSize": 76, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "rectangle", + "id": "r44", + "name": "强调短线", + "width": 112, + "height": 10, + "cornerRadius": 5, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "text", + "id": "t45", + "name": "副标题", + "content": "三个动作,把书里的东西真正带走。", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f65", + "name": "要点列表", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f47", + "name": "要点 1", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 22, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f48", + "name": "序号 1", + "width": 52, + "height": 52, + "layout": "horizontal", + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 26, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t49", + "name": "序号数字", + "content": "1", + "fontFamily": "Inter", + "fontSize": 26, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f52", + "name": "要点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t50", + "name": "要点标题", + "content": "先提问,再翻开", + "fontFamily": "Noto Sans SC", + "fontSize": 34, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t51", + "name": "要点说明", + "content": "带着问题进去,信息才有地方落。", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f53", + "name": "要点 2", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 22, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f54", + "name": "序号 2", + "width": 52, + "height": 52, + "layout": "horizontal", + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 26, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t55", + "name": "序号数字", + "content": "2", + "fontFamily": "Inter", + "fontSize": 26, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f58", + "name": "要点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t56", + "name": "要点标题", + "content": "合上书,先复述", + "fontFamily": "Noto Sans SC", + "fontSize": 34, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t57", + "name": "要点说明", + "content": "讲不出来的地方,就是还没懂的地方。", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f59", + "name": "要点 3", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 22, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f60", + "name": "序号 3", + "width": 52, + "height": 52, + "layout": "horizontal", + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 26, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t61", + "name": "序号数字", + "content": "3", + "fontFamily": "Inter", + "fontSize": 26, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f64", + "name": "要点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t62", + "name": "要点标题", + "content": "两天之内用一次", + "fontFamily": "Noto Sans SC", + "fontSize": 34, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t63", + "name": "要点说明", + "content": "用过一次,才算真的学过。", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "f73", + "name": "署名", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 22, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "rectangle", + "id": "r72", + "name": "分隔线", + "width": "fill_container", + "height": 2, + "fill": [ + { + "type": "solid", + "color": "$c-border" + } + ] + }, + { + "type": "frame", + "id": "f68", + "name": "署名行", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 22, + "alignItems": "center", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f66", + "name": "头像占位", + "width": 76, + "height": 76, + "layout": "horizontal", + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 38, + "fill": [ + { + "type": "solid", + "color": "$c-accent-soft" + } + ], + "children": [ + { + "type": "text", + "id": "t67", + "name": "头像文字", + "content": "笔", + "fontFamily": "Noto Sans SC", + "fontSize": 32, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f71", + "name": "署名文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 6, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t69", + "name": "账号名", + "content": "@ 你的账号名", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t70", + "name": "一句话简介", + "content": "每周更新一条可落地的学习方法", + "fontFamily": "Noto Sans SC", + "fontSize": 23, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + } + ], + "x": 0, + "y": 0 + } + ] +} diff --git a/crates/op-editor-core/assets/scene_templates/knowledge-card-vertical.op b/crates/op-editor-core/assets/scene_templates/knowledge-card-vertical.op new file mode 100644 index 000000000..a3dda3b9b --- /dev/null +++ b/crates/op-editor-core/assets/scene_templates/knowledge-card-vertical.op @@ -0,0 +1,719 @@ +{ + "version": "1.0.0", + "name": "知识卡片 · 竖版 3:4", + "variables": { + "c-bg": { + "type": "color", + "value": "#FFF7F0" + }, + "c-surface": { + "type": "color", + "value": "#FFFFFF" + }, + "c-ink": { + "type": "color", + "value": "#241A12" + }, + "c-muted": { + "type": "color", + "value": "#7A6455" + }, + "c-accent": { + "type": "color", + "value": "#C8502B" + }, + "c-accent-soft": { + "type": "color", + "value": "#FAE3D8" + }, + "c-border": { + "type": "color", + "value": "#EDDCD0" + } + }, + "children": [ + { + "type": "frame", + "id": "f40", + "name": "知识卡片 · 竖版", + "width": 1080, + "height": 1440, + "layout": "vertical", + "padding": [ + 96, + 88 + ], + "gap": 0, + "justifyContent": "space_between", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f6", + "name": "卡头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 32, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f1", + "name": "标签", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "padding": [ + 12, + 24 + ], + "gap": 0, + "cornerRadius": 999, + "alignItems": "center", + "justifyContent": "center", + "fill": [ + { + "type": "solid", + "color": "$c-accent-soft" + } + ], + "children": [ + { + "type": "text", + "id": "t2", + "name": "标签文字", + "content": "学习方法 · 01", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "text", + "id": "t3", + "name": "主标题", + "content": "为什么你读了很多书\n却什么都记不住", + "fontFamily": "Noto Sans SC", + "fontSize": 88, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "rectangle", + "id": "r4", + "name": "强调短线", + "width": 132, + "height": 12, + "cornerRadius": 6, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "text", + "id": "t5", + "name": "副标题", + "content": "不是记性差,是你少做了这一步。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f31", + "name": "要点列表", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 28, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f7", + "name": "要点 1", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f8", + "name": "序号 1", + "width": 56, + "height": 56, + "layout": "horizontal", + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 28, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t9", + "name": "序号数字", + "content": "1", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f12", + "name": "要点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t10", + "name": "要点标题", + "content": "先提问,再翻开", + "fontFamily": "Noto Sans SC", + "fontSize": 36, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t11", + "name": "要点说明", + "content": "带着「我想解决什么」进去,信息才有地方落。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f13", + "name": "要点 2", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f14", + "name": "序号 2", + "width": 56, + "height": 56, + "layout": "horizontal", + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 28, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t15", + "name": "序号数字", + "content": "2", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f18", + "name": "要点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t16", + "name": "要点标题", + "content": "合上书,先复述", + "fontFamily": "Noto Sans SC", + "fontSize": 36, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t17", + "name": "要点说明", + "content": "读完立刻用自己的话讲一遍,卡壳的地方就是没懂的地方。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f19", + "name": "要点 3", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f20", + "name": "序号 3", + "width": 56, + "height": 56, + "layout": "horizontal", + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 28, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t21", + "name": "序号数字", + "content": "3", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f24", + "name": "要点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t22", + "name": "要点标题", + "content": "一次只带走三条", + "fontFamily": "Noto Sans SC", + "fontSize": 36, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t23", + "name": "要点说明", + "content": "贪多必忘。记住三个能用的点,比划满一整本有用。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f25", + "name": "要点 4", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f26", + "name": "序号 4", + "width": 56, + "height": 56, + "layout": "horizontal", + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 28, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t27", + "name": "序号数字", + "content": "4", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f30", + "name": "要点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t28", + "name": "要点标题", + "content": "两天之内用一次", + "fontFamily": "Noto Sans SC", + "fontSize": 36, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t29", + "name": "要点说明", + "content": "写进笔记、讲给朋友、或者直接做一遍,用过才算学过。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "f39", + "name": "署名", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "rectangle", + "id": "r38", + "name": "分隔线", + "width": "fill_container", + "height": 2, + "fill": [ + { + "type": "solid", + "color": "$c-border" + } + ] + }, + { + "type": "frame", + "id": "f34", + "name": "署名行", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 24, + "alignItems": "center", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f32", + "name": "头像占位", + "width": 88, + "height": 88, + "layout": "horizontal", + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 44, + "fill": [ + { + "type": "solid", + "color": "$c-accent-soft" + } + ], + "children": [ + { + "type": "text", + "id": "t33", + "name": "头像文字", + "content": "笔", + "fontFamily": "Noto Sans SC", + "fontSize": 37, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f37", + "name": "署名文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 6, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t35", + "name": "账号名", + "content": "@ 你的账号名", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t36", + "name": "一句话简介", + "content": "每周更新一条可落地的学习方法", + "fontFamily": "Noto Sans SC", + "fontSize": 24, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + } + ], + "x": 0, + "y": 0 + } + ] +} diff --git a/crates/op-editor-core/assets/scene_templates/lecture-deck-light.op b/crates/op-editor-core/assets/scene_templates/lecture-deck-light.op new file mode 100644 index 000000000..417466ddf --- /dev/null +++ b/crates/op-editor-core/assets/scene_templates/lecture-deck-light.op @@ -0,0 +1,2671 @@ +{ + "version": "1.0.0", + "name": "课件 deck · 浅色 16:9", + "variables": { + "c-bg": { + "type": "color", + "value": "#F2EEE2" + }, + "c-surface": { + "type": "color", + "value": "#FFFFFF" + }, + "c-ink": { + "type": "color", + "value": "#17211C" + }, + "c-muted": { + "type": "color", + "value": "#55635A" + }, + "c-accent": { + "type": "color", + "value": "#1B6B4C" + }, + "c-accent-soft": { + "type": "color", + "value": "#D8E9DE" + }, + "c-border": { + "type": "color", + "value": "#D9D2C2" + } + }, + "children": [ + { + "type": "frame", + "id": "f8", + "name": "01 课程封面", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 48, + "justifyContent": "space_between", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f9", + "name": "标签", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "padding": [ + 10, + 22 + ], + "gap": 0, + "cornerRadius": 999, + "alignItems": "center", + "justifyContent": "center", + "fill": [ + { + "type": "solid", + "color": "$c-accent-soft" + } + ], + "children": [ + { + "type": "text", + "id": "t10", + "name": "标签文字", + "content": "第 07 讲", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.4, + "letterSpacing": 1.0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f4", + "name": "课程标题", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 36, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t1", + "name": "课名", + "content": "函数的单调性\n与极值判定", + "fontFamily": "Noto Sans SC", + "fontSize": 100, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.12, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "rectangle", + "id": "r2", + "name": "强调条", + "width": 150, + "height": 10, + "cornerRadius": 999, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "text", + "id": "t3", + "name": "课程说明", + "content": "这一讲我们只解决一个问题:拿到一个函数,怎么判断它在哪段往上走。", + "fontFamily": "Noto Sans SC", + "fontSize": 32, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f7", + "name": "讲师信息", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 32, + "alignItems": "center", + "fill": [], + "justifyContent": "space_between", + "children": [ + { + "type": "text", + "id": "t5", + "name": "讲师", + "content": "主讲 · 林望舒", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "text", + "id": "t6", + "name": "学期", + "content": "高等数学(上)· 2026 秋", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ], + "x": 0, + "y": 0 + }, + { + "type": "frame", + "id": "f29", + "name": "02 学习目标", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f32", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t30", + "name": "页标题", + "content": "这节课下课时,你应该能——", + "fontFamily": "Noto Sans SC", + "fontSize": 64, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t31", + "name": "页副标题", + "content": "三条,都要能自己动手做出来,不是听懂就算。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f34", + "name": "目标区", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "f33", + "name": "目标列表", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f16", + "name": "目标 1", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 28, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "padding": [ + 36, + 40 + ], + "cornerRadius": 20, + "children": [ + { + "type": "frame", + "id": "f11", + "name": "序号 1", + "width": 64, + "height": 64, + "layout": "horizontal", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 32, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t12", + "name": "序号数字", + "content": "1", + "fontFamily": "Inter", + "fontSize": 29, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f15", + "name": "目标文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 12, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t13", + "name": "目标标题", + "content": "说得出定义", + "fontFamily": "Noto Sans SC", + "fontSize": 38, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t14", + "name": "目标说明", + "content": "用导数的符号说明单调递增、递减到底在讲什么。", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f22", + "name": "目标 2", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 28, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "padding": [ + 36, + 40 + ], + "cornerRadius": 20, + "children": [ + { + "type": "frame", + "id": "f17", + "name": "序号 2", + "width": 64, + "height": 64, + "layout": "horizontal", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 32, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t18", + "name": "序号数字", + "content": "2", + "fontFamily": "Inter", + "fontSize": 29, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f21", + "name": "目标文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 12, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t19", + "name": "目标标题", + "content": "判得出区间", + "fontFamily": "Noto Sans SC", + "fontSize": 38, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t20", + "name": "目标说明", + "content": "给定一个可导函数,能划出它的单调区间。", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f28", + "name": "目标 3", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 28, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "padding": [ + 36, + 40 + ], + "cornerRadius": 20, + "children": [ + { + "type": "frame", + "id": "f23", + "name": "序号 3", + "width": 64, + "height": 64, + "layout": "horizontal", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 32, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t24", + "name": "序号数字", + "content": "3", + "fontFamily": "Inter", + "fontSize": 29, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f27", + "name": "目标文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 12, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t25", + "name": "目标标题", + "content": "找得到极值", + "fontFamily": "Noto Sans SC", + "fontSize": 38, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t26", + "name": "目标说明", + "content": "会用一阶导数的符号变化确定极大值与极小值。", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + } + ] + } + ], + "x": 2040, + "y": 0 + }, + { + "type": "frame", + "id": "f46", + "name": "03 概念讲解", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f48", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t47", + "name": "页标题", + "content": "导数的符号,决定曲线的走向", + "fontFamily": "Noto Sans SC", + "fontSize": 64, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f50", + "name": "图文区", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "f49", + "name": "图文两栏", + "width": "fill_container", + "height": 560, + "layout": "horizontal", + "gap": 48, + "alignItems": "stretch", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f42", + "name": "概念正文", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 40, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "justifyContent": "space_between", + "padding": [ + 44, + 44 + ], + "cornerRadius": 20, + "children": [ + { + "type": "frame", + "id": "f37", + "name": "定义组", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 20, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t35", + "name": "定义标题", + "content": "单调性的判定定理", + "fontFamily": "Noto Sans SC", + "fontSize": 40, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t36", + "name": "定义正文", + "content": "设函数 f(x) 在区间 (a, b) 内可导。若在该区间内恒有 f'(x) > 0,则 f(x) 在 (a, b) 上单调递增;若恒有 f'(x) < 0,则单调递减。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f41", + "name": "追问组", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 20, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "rectangle", + "id": "r38", + "name": "正文分隔线", + "width": "fill_container", + "height": 2, + "fill": [ + { + "type": "solid", + "color": "$c-border" + } + ] + }, + { + "type": "text", + "id": "t39", + "name": "提示标题", + "content": "为什么成立", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t40", + "name": "提示正文", + "content": "导数是切线的斜率。斜率一直为正,意味着曲线上任意两点连线都在往右上方走——这正是「递增」的几何说法。", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f45", + "name": "配图占位", + "width": 700, + "height": "fill_container", + "layout": "vertical", + "gap": 12, + "alignItems": "center", + "fill": [ + { + "type": "solid", + "color": "$c-accent-soft" + } + ], + "padding": [ + 0, + 48 + ], + "justifyContent": "center", + "cornerRadius": 20, + "children": [ + { + "type": "text", + "id": "t43", + "name": "配图提示", + "content": "把函数图像拖到这里", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "text", + "id": "t44", + "name": "配图说明", + "content": "建议画出 f(x) 与 f'(x) 的符号对照", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ] + } + ] + } + ], + "x": 4080, + "y": 0 + }, + { + "type": "frame", + "id": "f80", + "name": "04 例题", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f82", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t81", + "name": "页标题", + "content": "按这四步走,一步都不要跳", + "fontFamily": "Noto Sans SC", + "fontSize": 64, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f83", + "name": "例题区", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "f79", + "name": "例题卡", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 32, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "padding": [ + 40, + 44 + ], + "cornerRadius": 20, + "children": [ + { + "type": "frame", + "id": "f53", + "name": "题干", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 12, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-accent-soft" + } + ], + "padding": [ + 32, + 36 + ], + "cornerRadius": 16, + "children": [ + { + "type": "text", + "id": "t51", + "name": "题干标签", + "content": "例题", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.3, + "letterSpacing": 1.0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "text", + "id": "t52", + "name": "题干正文", + "content": "求函数 f(x) = x³ − 3x² + 1 的单调区间与极值。", + "fontFamily": "Noto Sans SC", + "fontSize": 34, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.35, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f78", + "name": "解答步骤", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f59", + "name": "步骤 1", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f54", + "name": "序号 1", + "width": 52, + "height": 52, + "layout": "horizontal", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 26, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t55", + "name": "序号数字", + "content": "1", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f58", + "name": "步骤文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 8, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t56", + "name": "步骤标题", + "content": "求导", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t57", + "name": "步骤算式", + "content": "f'(x) = 3x² − 6x = 3x(x − 2)", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f65", + "name": "步骤 2", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f60", + "name": "序号 2", + "width": 52, + "height": 52, + "layout": "horizontal", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 26, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t61", + "name": "序号数字", + "content": "2", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f64", + "name": "步骤文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 8, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t62", + "name": "步骤标题", + "content": "找驻点", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t63", + "name": "步骤算式", + "content": "令 f'(x) = 0,得 x = 0 与 x = 2", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f71", + "name": "步骤 3", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f66", + "name": "序号 3", + "width": 52, + "height": 52, + "layout": "horizontal", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 26, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t67", + "name": "序号数字", + "content": "3", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f70", + "name": "步骤文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 8, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t68", + "name": "步骤标题", + "content": "判符号", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t69", + "name": "步骤算式", + "content": "x < 0 与 x > 2 时 f'(x) > 0;0 < x < 2 时 f'(x) < 0", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f77", + "name": "步骤 4", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f72", + "name": "序号 4", + "width": 52, + "height": 52, + "layout": "horizontal", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 26, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "children": [ + { + "type": "text", + "id": "t73", + "name": "序号数字", + "content": "4", + "fontFamily": "Inter", + "fontSize": 24, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "#FFFFFF" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f76", + "name": "步骤文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 8, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t74", + "name": "步骤标题", + "content": "下结论", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t75", + "name": "步骤算式", + "content": "x = 0 处取极大值 f(0) = 1,x = 2 处取极小值 f(2) = −3", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ], + "x": 0, + "y": 1440 + }, + { + "type": "frame", + "id": "f113", + "name": "05 对比", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f116", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t114", + "name": "页标题", + "content": "两个概念,别再混着用", + "fontFamily": "Noto Sans SC", + "fontSize": 64, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t115", + "name": "页副标题", + "content": "单调性说的是一段,极值说的是一点。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f117", + "name": "对比区", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "f112", + "name": "对比表", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "cornerRadius": 20, + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f90", + "name": "表头", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 40, + "alignItems": "start", + "fill": [], + "padding": [ + 26, + 32 + ], + "stroke": { + "thickness": { + "bottom": 3 + }, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + "children": [ + { + "type": "frame", + "id": "f85", + "name": "表头行标题", + "width": 260, + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t84", + "name": "表头留白", + "content": " ", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f87", + "name": "表头左列", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t86", + "name": "表头左列文字", + "content": "单调性", + "fontFamily": "Noto Sans SC", + "fontSize": 34, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f89", + "name": "表头右列", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t88", + "name": "表头右列文字", + "content": "极值", + "fontFamily": "Noto Sans SC", + "fontSize": 34, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f97", + "name": "对比行", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 40, + "alignItems": "start", + "fill": [], + "padding": [ + 26, + 32 + ], + "stroke": { + "thickness": { + "bottom": 2 + }, + "fill": [ + { + "type": "solid", + "color": "$c-border" + } + ] + }, + "children": [ + { + "type": "frame", + "id": "f92", + "name": "行标题", + "width": 260, + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t91", + "name": "行标题文字", + "content": "看的是什么", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f94", + "name": "左列内容", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t93", + "name": "左列文字", + "content": "f'(x) 在整个区间上的符号", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f96", + "name": "右列内容", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t95", + "name": "右列文字", + "content": "f'(x) 在某一点两侧的符号变化", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f104", + "name": "对比行", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 40, + "alignItems": "start", + "fill": [], + "padding": [ + 26, + 32 + ], + "stroke": { + "thickness": { + "bottom": 2 + }, + "fill": [ + { + "type": "solid", + "color": "$c-border" + } + ] + }, + "children": [ + { + "type": "frame", + "id": "f99", + "name": "行标题", + "width": 260, + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t98", + "name": "行标题文字", + "content": "回答的问题", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f101", + "name": "左列内容", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t100", + "name": "左列文字", + "content": "这段曲线往上还是往下", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f103", + "name": "右列内容", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t102", + "name": "右列文字", + "content": "这一点是不是拐上去/拐下来的地方", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f111", + "name": "对比行", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 40, + "alignItems": "start", + "fill": [], + "padding": [ + 26, + 32 + ], + "children": [ + { + "type": "frame", + "id": "f106", + "name": "行标题", + "width": 260, + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t105", + "name": "行标题文字", + "content": "容易错在哪", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f108", + "name": "左列内容", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t107", + "name": "左列文字", + "content": "漏掉不可导的点也要单独讨论", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f110", + "name": "右列内容", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t109", + "name": "右列文字", + "content": "驻点不一定是极值点,要看符号是否真的变了", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + } + ] + } + ], + "x": 2040, + "y": 1440 + }, + { + "type": "frame", + "id": "f145", + "name": "06 小结与作业", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f147", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t146", + "name": "页标题", + "content": "带走这三句话就够了", + "fontFamily": "Noto Sans SC", + "fontSize": 64, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f149", + "name": "小结区", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "f148", + "name": "小结两栏", + "width": "fill_container", + "height": 490, + "layout": "horizontal", + "gap": 48, + "alignItems": "stretch", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f132", + "name": "本讲小结", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 28, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "padding": [ + 44, + 44 + ], + "cornerRadius": 20, + "children": [ + { + "type": "text", + "id": "t118", + "name": "小结标题", + "content": "本讲小结", + "fontFamily": "Noto Sans SC", + "fontSize": 40, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.2, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "frame", + "id": "f131", + "name": "小结条目", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 20, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f122", + "name": "小结条", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 20, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f120", + "name": "条目圆点位", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "padding": [ + 15, + 0, + 0, + 0 + ], + "children": [ + { + "type": "rectangle", + "id": "r119", + "name": "条目圆点", + "width": 14, + "height": 14, + "cornerRadius": 7, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + } + ] + }, + { + "type": "text", + "id": "t121", + "name": "条目文字", + "content": "先求导,再找驻点,最后判符号——顺序不能换。", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.55, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f126", + "name": "小结条", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 20, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f124", + "name": "条目圆点位", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "padding": [ + 15, + 0, + 0, + 0 + ], + "children": [ + { + "type": "rectangle", + "id": "r123", + "name": "条目圆点", + "width": 14, + "height": 14, + "cornerRadius": 7, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + } + ] + }, + { + "type": "text", + "id": "t125", + "name": "条目文字", + "content": "驻点只是候选,符号真的变了才是极值点。", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.55, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f130", + "name": "小结条", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 20, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f128", + "name": "条目圆点位", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "padding": [ + 15, + 0, + 0, + 0 + ], + "children": [ + { + "type": "rectangle", + "id": "r127", + "name": "条目圆点", + "width": 14, + "height": 14, + "cornerRadius": 7, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + } + ] + }, + { + "type": "text", + "id": "t129", + "name": "条目文字", + "content": "不可导的点也要单独拿出来讨论。", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.55, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "f144", + "name": "课后作业", + "width": 680, + "height": "fill_container", + "layout": "vertical", + "gap": 28, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-accent-soft" + } + ], + "padding": [ + 44, + 44 + ], + "cornerRadius": 20, + "children": [ + { + "type": "text", + "id": "t133", + "name": "作业标题", + "content": "课后作业", + "fontFamily": "Noto Sans SC", + "fontSize": 40, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.2, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "frame", + "id": "f143", + "name": "作业条目", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 24, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f136", + "name": "作业条", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 8, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t134", + "name": "作业出处", + "content": "课本 P128", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t135", + "name": "作业内容", + "content": "习题 3.4 第 1、3、5 题", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f139", + "name": "作业条", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 8, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t137", + "name": "作业出处", + "content": "补充题", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t138", + "name": "作业内容", + "content": "讨论 f(x) = x·e^(−x) 的单调区间与极值", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f142", + "name": "作业条", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 8, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t140", + "name": "作业出处", + "content": "下次课前", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t141", + "name": "作业内容", + "content": "预习凹凸性与拐点(P131–P136)", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ], + "x": 4080, + "y": 1440 + } + ] +} diff --git a/crates/op-editor-core/assets/scene_templates/minimal-keynote.op b/crates/op-editor-core/assets/scene_templates/minimal-keynote.op new file mode 100644 index 000000000..c340b5c48 --- /dev/null +++ b/crates/op-editor-core/assets/scene_templates/minimal-keynote.op @@ -0,0 +1,641 @@ +{ + "version": "1.0.0", + "name": "极简 Keynote · 16:9", + "variables": { + "c-bg": { + "type": "color", + "value": "#FFFFFF" + }, + "c-ink": { + "type": "color", + "value": "#0A0A0A" + }, + "c-muted": { + "type": "color", + "value": "#6B6B6B" + }, + "c-accent": { + "type": "color", + "value": "#C7340F" + } + }, + "children": [ + { + "type": "frame", + "id": "f8", + "name": "01 封面", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 160, + 160 + ], + "gap": 48, + "justifyContent": "space_between", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f4", + "name": "主张", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 40, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t1", + "name": "主标题", + "content": "把复杂\n留在里面", + "fontFamily": "Noto Sans SC", + "fontSize": 130, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.08, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "rectangle", + "id": "r2", + "name": "强调短线", + "width": 120, + "height": 8, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "text", + "id": "t3", + "name": "副标题", + "content": "第七代产品,今天发布。", + "fontFamily": "Noto Sans SC", + "fontSize": 32, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f7", + "name": "落款", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 28, + "alignItems": "center", + "fill": [], + "justifyContent": "space_between", + "children": [ + { + "type": "text", + "id": "t5", + "name": "场合", + "content": "2026 秋季发布会", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "text", + "id": "t6", + "name": "日期", + "content": "2026.10.08", + "fontFamily": "Inter", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ], + "x": 0, + "y": 0 + }, + { + "type": "frame", + "id": "f9", + "name": "02 论点", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 160, + 160 + ], + "gap": 44, + "justifyContent": "center", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "rectangle", + "id": "r10", + "name": "强调点", + "width": 18, + "height": 18, + "cornerRadius": 9, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "text", + "id": "t11", + "name": "论点", + "content": "我们删掉了三十七个按钮。", + "fontFamily": "Noto Sans SC", + "fontSize": 76, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ], + "x": 2040, + "y": 0 + }, + { + "type": "frame", + "id": "f12", + "name": "03 词 · 少", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 160, + 160 + ], + "gap": 36, + "justifyContent": "center", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "text", + "id": "t13", + "name": "大词", + "content": "少", + "fontFamily": "Noto Sans SC", + "fontSize": 200, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.05, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t14", + "name": "注解", + "content": "从三十七个按钮,到三个。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ], + "x": 4080, + "y": 0 + }, + { + "type": "frame", + "id": "f15", + "name": "04 词 · 轻", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 160, + 160 + ], + "gap": 36, + "justifyContent": "center", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "text", + "id": "t16", + "name": "大词", + "content": "轻", + "fontFamily": "Noto Sans SC", + "fontSize": 200, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.05, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t17", + "name": "注解", + "content": "整机一点零九公斤,比上一代少了两百四十克。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ], + "x": 0, + "y": 1440 + }, + { + "type": "frame", + "id": "f18", + "name": "05 词 · 久", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 160, + 160 + ], + "gap": 36, + "justifyContent": "center", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "text", + "id": "t19", + "name": "大词", + "content": "久", + "fontFamily": "Noto Sans SC", + "fontSize": 200, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.05, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t20", + "name": "注解", + "content": "一次充电,用满两天。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ], + "x": 2040, + "y": 1440 + }, + { + "type": "frame", + "id": "f21", + "name": "06 引用", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 160, + 160 + ], + "gap": 32, + "justifyContent": "center", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "text", + "id": "t22", + "name": "引号", + "content": "“", + "fontFamily": "Inter", + "fontSize": 160, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 0.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t23", + "name": "引文", + "content": "最好的设计,是让人忘了它存在。", + "fontFamily": "Noto Sans SC", + "fontSize": 54, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t24", + "name": "出处", + "content": "— 产品负责人 沈亦文", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ], + "x": 4080, + "y": 1440 + }, + { + "type": "frame", + "id": "f25", + "name": "07 数据", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 160, + 160 + ], + "gap": 32, + "justifyContent": "center", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "text", + "id": "t26", + "name": "大数字", + "content": "0.4 秒", + "fontFamily": "Inter", + "fontSize": 200, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.05, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t27", + "name": "注解", + "content": "从按下到出图的全部时间,上一代是 2.6 秒。", + "fontFamily": "Noto Sans SC", + "fontSize": 32, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ], + "x": 0, + "y": 2880 + }, + { + "type": "frame", + "id": "f28", + "name": "08 结尾", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 160, + 160 + ], + "gap": 40, + "justifyContent": "center", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "rectangle", + "id": "r29", + "name": "强调短线", + "width": 120, + "height": 8, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "text", + "id": "t30", + "name": "结语", + "content": "今天开始发货。", + "fontFamily": "Noto Sans SC", + "fontSize": 96, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.12, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t31", + "name": "补充", + "content": "全国门店同步开售,官网可预约体验。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ], + "x": 2040, + "y": 2880 + } + ] +} diff --git a/crates/op-editor-core/assets/scene_templates/pitch-deck-dark.op b/crates/op-editor-core/assets/scene_templates/pitch-deck-dark.op new file mode 100644 index 000000000..e36af4730 --- /dev/null +++ b/crates/op-editor-core/assets/scene_templates/pitch-deck-dark.op @@ -0,0 +1,2374 @@ +{ + "version": "1.0.0", + "name": "路演 deck · 深色 16:9", + "variables": { + "c-bg": { + "type": "color", + "value": "#0B1220" + }, + "c-surface": { + "type": "color", + "value": "#18263F" + }, + "c-ink": { + "type": "color", + "value": "#F2F6FF" + }, + "c-muted": { + "type": "color", + "value": "#93A4C4" + }, + "c-accent": { + "type": "color", + "value": "#4D8DFF" + }, + "c-accent-soft": { + "type": "color", + "value": "#16233D" + }, + "c-border": { + "type": "color", + "value": "#24314D" + } + }, + "children": [ + { + "type": "frame", + "id": "f8", + "name": "01 封面", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 48, + "justifyContent": "space_between", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f9", + "name": "标签", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "padding": [ + 10, + 22 + ], + "gap": 0, + "cornerRadius": 999, + "alignItems": "center", + "justifyContent": "center", + "fill": [ + { + "type": "solid", + "color": "$c-accent-soft" + } + ], + "children": [ + { + "type": "text", + "id": "t10", + "name": "标签文字", + "content": "种子轮 · 融资路演", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.4, + "letterSpacing": 1.0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + }, + { + "type": "frame", + "id": "f4", + "name": "主张", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 36, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t1", + "name": "主标题", + "content": "把三天的报价\n压进三分钟", + "fontFamily": "Noto Sans SC", + "fontSize": 112, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.12, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "rectangle", + "id": "r2", + "name": "强调条", + "width": 160, + "height": 10, + "cornerRadius": 999, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "text", + "id": "t3", + "name": "副标题", + "content": "我们在做的,是让每一家工厂当场就能报出价来。", + "fontFamily": "Noto Sans SC", + "fontSize": 34, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f7", + "name": "落款", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 32, + "alignItems": "center", + "fill": [], + "justifyContent": "space_between", + "children": [ + { + "type": "text", + "id": "t5", + "name": "演讲者", + "content": "启明智造 · 创始人 陈知远", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "text", + "id": "t6", + "name": "场合", + "content": "2026.08 · 种子轮路演", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.6, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ], + "x": 0, + "y": 0 + }, + { + "type": "frame", + "id": "f28", + "name": "02 问题", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f31", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t29", + "name": "页标题", + "content": "报价这一步,卡住了整条链路", + "fontFamily": "Noto Sans SC", + "fontSize": 64, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t30", + "name": "页副标题", + "content": "三个问题,每一个都在直接吃掉订单。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f32", + "name": "痛点列表", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "space_between", + "children": [ + { + "type": "frame", + "id": "f15", + "name": "痛点 1", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 40, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t11", + "name": "痛点序号", + "content": "01", + "fontFamily": "Inter", + "fontSize": 64, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "frame", + "id": "f14", + "name": "痛点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 12, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t12", + "name": "痛点标题", + "content": "算不清", + "fontFamily": "Noto Sans SC", + "fontSize": 40, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.2, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t13", + "name": "痛点说明", + "content": "一份报价要问遍四个部门,等两天才知道能不能接。", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "rectangle", + "id": "r16", + "name": "分隔线", + "width": "fill_container", + "height": 2, + "fill": [ + { + "type": "solid", + "color": "$c-border" + } + ] + }, + { + "type": "frame", + "id": "f21", + "name": "痛点 2", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 40, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t17", + "name": "痛点序号", + "content": "02", + "fontFamily": "Inter", + "fontSize": 64, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "frame", + "id": "f20", + "name": "痛点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 12, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t18", + "name": "痛点标题", + "content": "报不准", + "fontFamily": "Noto Sans SC", + "fontSize": 40, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.2, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t19", + "name": "痛点说明", + "content": "凭经验拍的价,做完才发现毛利被工时和损耗吃光了。", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "rectangle", + "id": "r22", + "name": "分隔线", + "width": "fill_container", + "height": 2, + "fill": [ + { + "type": "solid", + "color": "$c-border" + } + ] + }, + { + "type": "frame", + "id": "f27", + "name": "痛点 3", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 40, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t23", + "name": "痛点序号", + "content": "03", + "fontFamily": "Inter", + "fontSize": 64, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "frame", + "id": "f26", + "name": "痛点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 12, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t24", + "name": "痛点标题", + "content": "跟不上", + "fontFamily": "Noto Sans SC", + "fontSize": 40, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.2, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t25", + "name": "痛点说明", + "content": "客户当场要数,我们只能说「回去核一下」——单子就这么走了。", + "fontFamily": "Noto Sans SC", + "fontSize": 28, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + } + ], + "x": 2040, + "y": 0 + }, + { + "type": "frame", + "id": "f45", + "name": "03 方案", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f48", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t46", + "name": "页标题", + "content": "把报价变成一次点击", + "fontFamily": "Noto Sans SC", + "fontSize": 64, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t47", + "name": "页副标题", + "content": "工艺库 + 实时成本模型,客户还在电话里,价就出来了。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f50", + "name": "卖点区", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "f49", + "name": "卖点网格", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 36, + "alignItems": "stretch", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f36", + "name": "卖点卡", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 22, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "padding": [ + 48, + 40 + ], + "cornerRadius": 20, + "children": [ + { + "type": "rectangle", + "id": "r33", + "name": "卡首强调条", + "width": 56, + "height": 6, + "cornerRadius": 999, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "text", + "id": "t34", + "name": "卖点标题", + "content": "三分钟出价", + "fontFamily": "Noto Sans SC", + "fontSize": 38, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.2, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t35", + "name": "卖点说明", + "content": "上传图纸,系统直接算出工时、材料与损耗。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.55, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f40", + "name": "卖点卡", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 22, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "padding": [ + 48, + 40 + ], + "cornerRadius": 20, + "children": [ + { + "type": "rectangle", + "id": "r37", + "name": "卡首强调条", + "width": 56, + "height": 6, + "cornerRadius": 999, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "text", + "id": "t38", + "name": "卖点标题", + "content": "毛利先看见", + "fontFamily": "Noto Sans SC", + "fontSize": 38, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.2, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t39", + "name": "卖点说明", + "content": "每一档价格旁边就是毛利率,接不接一眼决定。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.55, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f44", + "name": "卖点卡", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 22, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "padding": [ + 48, + 40 + ], + "cornerRadius": 20, + "children": [ + { + "type": "rectangle", + "id": "r41", + "name": "卡首强调条", + "width": 56, + "height": 6, + "cornerRadius": 999, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "text", + "id": "t42", + "name": "卖点标题", + "content": "越报越准", + "fontFamily": "Noto Sans SC", + "fontSize": 38, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.2, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t43", + "name": "卖点说明", + "content": "每完成一单回流真实成本,模型自己往回修。", + "fontFamily": "Noto Sans SC", + "fontSize": 27, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.55, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + } + ], + "x": 4080, + "y": 0 + }, + { + "type": "frame", + "id": "f51", + "name": "04 数据", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f54", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t52", + "name": "页标题", + "content": "半年里,它已经在跑", + "fontFamily": "Noto Sans SC", + "fontSize": 64, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t53", + "name": "页副标题", + "content": "不是路演里的假设,是 46 家工厂每天在用的数。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f77", + "name": "数据区", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "f76", + "name": "数据网格", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 36, + "alignItems": "stretch", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f61", + "name": "数据卡", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 20, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "justifyContent": "center", + "padding": [ + 56, + 44 + ], + "cornerRadius": 24, + "children": [ + { + "type": "frame", + "id": "f58", + "name": "数值", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "gap": 10, + "alignItems": "end", + "fill": [], + "children": [ + { + "type": "text", + "id": "t57", + "name": "数值文字", + "content": "42", + "fontFamily": "Inter", + "fontSize": 140, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "frame", + "id": "f55", + "name": "单位", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "padding": [ + 0, + 0, + 19, + 0 + ], + "fill": [], + "children": [ + { + "type": "text", + "id": "t56", + "name": "单位文字", + "content": "倍", + "fontFamily": "Noto Sans SC", + "fontSize": 44, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ] + }, + { + "type": "text", + "id": "t59", + "name": "指标名", + "content": "报价提速", + "fontFamily": "Noto Sans SC", + "fontSize": 32, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t60", + "name": "指标说明", + "content": "两天的活儿,三分钟出结果", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f68", + "name": "数据卡", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 20, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "justifyContent": "center", + "padding": [ + 56, + 44 + ], + "cornerRadius": 24, + "children": [ + { + "type": "frame", + "id": "f65", + "name": "数值", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "gap": 10, + "alignItems": "end", + "fill": [], + "children": [ + { + "type": "text", + "id": "t64", + "name": "数值文字", + "content": "97", + "fontFamily": "Inter", + "fontSize": 140, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "frame", + "id": "f62", + "name": "单位", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "padding": [ + 0, + 0, + 19, + 0 + ], + "fill": [], + "children": [ + { + "type": "text", + "id": "t63", + "name": "单位文字", + "content": "%", + "fontFamily": "Inter", + "fontSize": 44, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ] + }, + { + "type": "text", + "id": "t66", + "name": "指标名", + "content": "报价准确率", + "fontFamily": "Noto Sans SC", + "fontSize": 32, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t67", + "name": "指标说明", + "content": "与实际成本偏差不超过 3%", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f75", + "name": "数据卡", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 20, + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "justifyContent": "center", + "padding": [ + 56, + 44 + ], + "cornerRadius": 24, + "children": [ + { + "type": "frame", + "id": "f72", + "name": "数值", + "width": "fit_content", + "height": "fit_content", + "layout": "horizontal", + "gap": 10, + "alignItems": "end", + "fill": [], + "children": [ + { + "type": "text", + "id": "t71", + "name": "数值文字", + "content": "2.3", + "fontFamily": "Inter", + "fontSize": 140, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + }, + { + "type": "frame", + "id": "f69", + "name": "单位", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "padding": [ + 0, + 0, + 19, + 0 + ], + "fill": [], + "children": [ + { + "type": "text", + "id": "t70", + "name": "单位文字", + "content": "亿元", + "fontFamily": "Noto Sans SC", + "fontSize": 44, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.0, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ] + }, + { + "type": "text", + "id": "t73", + "name": "指标名", + "content": "在跑的订单金额", + "fontFamily": "Noto Sans SC", + "fontSize": 32, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t74", + "name": "指标说明", + "content": "来自 46 家制造企业", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + } + ], + "x": 0, + "y": 1440 + }, + { + "type": "frame", + "id": "f78", + "name": "05 里程碑", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "start", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f81", + "name": "页头", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t79", + "name": "页标题", + "content": "接下来十二个月", + "fontFamily": "Noto Sans SC", + "fontSize": 64, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t80", + "name": "页副标题", + "content": "前两步已经走完,这轮钱花在后两步上。", + "fontFamily": "Noto Sans SC", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f119", + "name": "时间轴区", + "width": "fill_container", + "height": "fill_container", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "f118", + "name": "时间轴", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 0, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f90", + "name": "里程碑", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 28, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f86", + "name": "节点日期", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "padding": [ + 0, + 56, + 0, + 0 + ], + "children": [ + { + "type": "text", + "id": "t85", + "name": "日期", + "content": "2026 Q3", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.2, + "letterSpacing": 0.5, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f84", + "name": "轴段", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 0, + "alignItems": "center", + "fill": [], + "children": [ + { + "type": "rectangle", + "id": "r82", + "name": "节点圆", + "width": 28, + "height": 28, + "cornerRadius": 14, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "rectangle", + "id": "r83", + "name": "轴线", + "width": "fill_container", + "height": 4, + "fill": [ + { + "type": "solid", + "color": "$c-border" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f89", + "name": "节点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "padding": [ + 0, + 56, + 0, + 0 + ], + "children": [ + { + "type": "text", + "id": "t87", + "name": "节点标题", + "content": "工艺库上线", + "fontFamily": "Noto Sans SC", + "fontSize": 34, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t88", + "name": "节点说明", + "content": "覆盖钣金、机加两条主线", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f99", + "name": "里程碑", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 28, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f95", + "name": "节点日期", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "padding": [ + 0, + 56, + 0, + 0 + ], + "children": [ + { + "type": "text", + "id": "t94", + "name": "日期", + "content": "2026 Q4", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.2, + "letterSpacing": 0.5, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f93", + "name": "轴段", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 0, + "alignItems": "center", + "fill": [], + "children": [ + { + "type": "rectangle", + "id": "r91", + "name": "节点圆", + "width": 28, + "height": 28, + "cornerRadius": 14, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "rectangle", + "id": "r92", + "name": "轴线", + "width": "fill_container", + "height": 4, + "fill": [ + { + "type": "solid", + "color": "$c-border" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f98", + "name": "节点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "padding": [ + 0, + 56, + 0, + 0 + ], + "children": [ + { + "type": "text", + "id": "t96", + "name": "节点标题", + "content": "接入 ERP", + "fontFamily": "Noto Sans SC", + "fontSize": 34, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t97", + "name": "节点说明", + "content": "报价直接落成订单", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f108", + "name": "里程碑", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 28, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f104", + "name": "节点日期", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "padding": [ + 0, + 56, + 0, + 0 + ], + "children": [ + { + "type": "text", + "id": "t103", + "name": "日期", + "content": "2027 Q1", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.2, + "letterSpacing": 0.5, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f102", + "name": "轴段", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 0, + "alignItems": "center", + "fill": [], + "children": [ + { + "type": "rectangle", + "id": "r100", + "name": "节点圆", + "width": 28, + "height": 28, + "cornerRadius": 14, + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "stroke": { + "thickness": 4, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + } + }, + { + "type": "rectangle", + "id": "r101", + "name": "轴线", + "width": "fill_container", + "height": 4, + "fill": [ + { + "type": "solid", + "color": "$c-border" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f107", + "name": "节点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "padding": [ + 0, + 56, + 0, + 0 + ], + "children": [ + { + "type": "text", + "id": "t105", + "name": "节点标题", + "content": "开放 API", + "fontFamily": "Noto Sans SC", + "fontSize": 34, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t106", + "name": "节点说明", + "content": "让客户在自己系统里报价", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f117", + "name": "里程碑", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 28, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "frame", + "id": "f113", + "name": "节点日期", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 0, + "alignItems": "start", + "fill": [], + "padding": [ + 0, + 56, + 0, + 0 + ], + "children": [ + { + "type": "text", + "id": "t112", + "name": "日期", + "content": "2027 Q2", + "fontFamily": "Inter", + "fontSize": 28, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.2, + "letterSpacing": 0.5, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f111", + "name": "轴段", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 0, + "alignItems": "center", + "fill": [], + "children": [ + { + "type": "rectangle", + "id": "r109", + "name": "节点圆", + "width": 28, + "height": 28, + "cornerRadius": 14, + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "stroke": { + "thickness": 4, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + } + }, + { + "type": "rectangle", + "id": "r110", + "name": "轴线", + "width": "fill_container", + "height": 4, + "fill": [ + { + "type": "solid", + "color": "$c-border" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f116", + "name": "节点文案", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "padding": [ + 0, + 56, + 0, + 0 + ], + "children": [ + { + "type": "text", + "id": "t114", + "name": "节点标题", + "content": "行业模板", + "fontFamily": "Noto Sans SC", + "fontSize": 34, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.25, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t115", + "name": "节点说明", + "content": "从制造扩到工程与装修", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.5, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + } + ] + } + ] + } + ], + "x": 2040, + "y": 1440 + }, + { + "type": "frame", + "id": "f132", + "name": "06 结尾", + "width": 1920, + "height": 1080, + "layout": "vertical", + "padding": [ + 120, + 120 + ], + "gap": 56, + "justifyContent": "space_between", + "alignItems": "start", + "fill": [ + { + "type": "solid", + "color": "$c-bg" + } + ], + "clipContent": true, + "children": [ + { + "type": "frame", + "id": "f123", + "name": "结语", + "width": "fill_container", + "height": "fit_content", + "layout": "vertical", + "gap": 36, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "rectangle", + "id": "r120", + "name": "强调条", + "width": 160, + "height": 10, + "cornerRadius": 999, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + { + "type": "text", + "id": "t121", + "name": "结语标题", + "content": "如果你也觉得\n这事早该被解决", + "fontFamily": "Noto Sans SC", + "fontSize": 88, + "fontWeight": 700, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.15, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t122", + "name": "结语副标题", + "content": "我们缺的不是订单,是把它做快的那笔钱。", + "fontFamily": "Noto Sans SC", + "fontSize": 32, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.45, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + }, + { + "type": "frame", + "id": "f131", + "name": "联系卡", + "width": "fill_container", + "height": "fit_content", + "layout": "horizontal", + "gap": 48, + "alignItems": "center", + "fill": [ + { + "type": "solid", + "color": "$c-surface" + } + ], + "justifyContent": "space_between", + "padding": [ + 48, + 56 + ], + "cornerRadius": 24, + "children": [ + { + "type": "frame", + "id": "f128", + "name": "联系方式", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 18, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t124", + "name": "联系人", + "content": "陈知远 · 创始人", + "fontFamily": "Noto Sans SC", + "fontSize": 32, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-ink" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "frame", + "id": "f127", + "name": "联络方式", + "width": "fit_content", + "height": "fit_content", + "layout": "vertical", + "gap": 10, + "alignItems": "start", + "fill": [], + "children": [ + { + "type": "text", + "id": "t125", + "name": "邮箱", + "content": "zhiyuan@qimingzz.com", + "fontFamily": "Inter", + "fontSize": 30, + "fontWeight": 500, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + }, + { + "type": "text", + "id": "t126", + "name": "电话", + "content": "+86 138 0000 0000", + "fontFamily": "Inter", + "fontSize": 30, + "fontWeight": 400, + "fill": [ + { + "type": "solid", + "color": "$c-muted" + } + ], + "lineHeight": 1.4, + "letterSpacing": 0, + "textGrowth": "fixed-width", + "width": "fill_container" + } + ] + } + ] + }, + { + "type": "frame", + "id": "f129", + "name": "二维码占位", + "width": 200, + "height": 200, + "layout": "vertical", + "gap": 0, + "alignItems": "center", + "justifyContent": "center", + "cornerRadius": 16, + "fill": [ + { + "type": "solid", + "color": "$c-accent-soft" + } + ], + "stroke": { + "thickness": 2, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ] + }, + "children": [ + { + "type": "text", + "id": "t130", + "name": "二维码提示", + "content": "扫码看 Demo", + "fontFamily": "Noto Sans SC", + "fontSize": 26, + "fontWeight": 600, + "fill": [ + { + "type": "solid", + "color": "$c-accent" + } + ], + "lineHeight": 1.3, + "letterSpacing": 0, + "textGrowth": "auto", + "width": "fit_content" + } + ] + } + ] + } + ], + "x": 4080, + "y": 1440 + } + ] +} diff --git a/crates/op-editor-core/src/host_ui_transitions.rs b/crates/op-editor-core/src/host_ui_transitions.rs index d3bbf4c11..732590dc0 100644 --- a/crates/op-editor-core/src/host_ui_transitions.rs +++ b/crates/op-editor-core/src/host_ui_transitions.rs @@ -89,9 +89,15 @@ pub fn scenario_default_export_format(scenario: Option) -> Option // A deck is delivered as a slide-per-page PDF — see // `op_host_services::export_pdf::export_deck_pdf`. Some(TemplateScene::Slides) => Some(ExportFormat::Pdf), + // A card is delivered as a PNG, but so is a tutorial and a carousel, + // and the user's own last choice (WebP for a lighter upload, say) is + // as valid. Presetting here would silently overwrite that on every + // export; the deck is the only scenario with a format its delivery + // actually depends on. Some(TemplateScene::Tutorial) | Some(TemplateScene::Comparison) | Some(TemplateScene::Carousel) + | Some(TemplateScene::Card) | None => None, } } diff --git a/crates/op-editor-core/src/scene_template_catalog.rs b/crates/op-editor-core/src/scene_template_catalog.rs index 216a606b9..6344d19f6 100644 --- a/crates/op-editor-core/src/scene_template_catalog.rs +++ b/crates/op-editor-core/src/scene_template_catalog.rs @@ -27,6 +27,14 @@ const SCREENSHOT_TUTORIAL_OP: &str = const KNOWLEDGE_CAROUSEL_OP: &str = include_str!("../assets/scene_templates/knowledge-carousel.op"); const BEFORE_AFTER_OP: &str = include_str!("../assets/scene_templates/before-after.op"); const SLIDE_DECK_OP: &str = include_str!("../assets/scene_templates/slide-deck.op"); +const KNOWLEDGE_CARD_VERTICAL_OP: &str = + include_str!("../assets/scene_templates/knowledge-card-vertical.op"); +const KNOWLEDGE_CARD_SQUARE_OP: &str = + include_str!("../assets/scene_templates/knowledge-card-square.op"); +const PITCH_DECK_DARK_OP: &str = include_str!("../assets/scene_templates/pitch-deck-dark.op"); +const LECTURE_DECK_LIGHT_OP: &str = include_str!("../assets/scene_templates/lecture-deck-light.op"); +const MINIMAL_KEYNOTE_OP: &str = include_str!("../assets/scene_templates/minimal-keynote.op"); +const GRADIENT_TECH_OP: &str = include_str!("../assets/scene_templates/gradient-tech.op"); /// Return the embedded document JSON for a template id. /// @@ -40,6 +48,12 @@ pub fn scene_template_document(template_id: &str) -> Option<&'static str> { "knowledge-carousel" => Some(KNOWLEDGE_CAROUSEL_OP), "before-after" => Some(BEFORE_AFTER_OP), "slide-deck" => Some(SLIDE_DECK_OP), + "knowledge-card-vertical" => Some(KNOWLEDGE_CARD_VERTICAL_OP), + "knowledge-card-square" => Some(KNOWLEDGE_CARD_SQUARE_OP), + "pitch-deck-dark" => Some(PITCH_DECK_DARK_OP), + "lecture-deck-light" => Some(LECTURE_DECK_LIGHT_OP), + "minimal-keynote" => Some(MINIMAL_KEYNOTE_OP), + "gradient-tech" => Some(GRADIENT_TECH_OP), _ => None, } } @@ -55,14 +69,22 @@ pub enum TemplateScene { Carousel, /// Presentation decks. Slides, + /// Single-board social cards — one finished image, not a sequence. + /// + /// Distinct from [`Self::Carousel`]: a carousel's unit of meaning is the + /// swipe across several boards, so its templates ship a whole sequence. A + /// card is delivered on its own, which is what makes "title + points + + /// byline" a complete layout rather than a page of one. + Card, } impl TemplateScene { - pub const ALL: [Self; 4] = [ + pub const ALL: [Self; 5] = [ Self::Tutorial, Self::Comparison, Self::Carousel, Self::Slides, + Self::Card, ]; pub const fn as_str(self) -> &'static str { @@ -71,6 +93,7 @@ impl TemplateScene { Self::Comparison => "comparison", Self::Carousel => "carousel", Self::Slides => "slides", + Self::Card => "card", } } @@ -81,16 +104,23 @@ impl TemplateScene { Self::Comparison => "sceneTemplate.scene.comparison", Self::Carousel => "sceneTemplate.scene.carousel", Self::Slides => "sceneTemplate.scene.slides", + Self::Card => "sceneTemplate.scene.card", } } /// Label shown when the catalogue key is not yet translated. + /// + /// Chip-sized nouns, not descriptions: the filter row is a single + /// non-wrapping line. `Carousel` reads "轮播" rather than "知识卡片" + /// because the latter is what a [`Self::Card`] chip means — two chips + /// labelled the same thing is worse than a slightly drier word. pub const fn title_fallback(self) -> &'static str { match self { Self::Tutorial => "教程图", Self::Comparison => "对比图", - Self::Carousel => "知识卡片", + Self::Carousel => "轮播", Self::Slides => "PPT", + Self::Card => "卡片", } } } @@ -104,6 +134,7 @@ impl FromStr for TemplateScene { "comparison" => Ok(Self::Comparison), "carousel" => Ok(Self::Carousel), "slides" => Ok(Self::Slides), + "card" => Ok(Self::Card), _ => Err(()), } } diff --git a/crates/op-editor-core/src/scene_template_catalog_tests.rs b/crates/op-editor-core/src/scene_template_catalog_tests.rs index a63ca56f9..4a637a2c5 100644 --- a/crates/op-editor-core/src/scene_template_catalog_tests.rs +++ b/crates/op-editor-core/src/scene_template_catalog_tests.rs @@ -140,6 +140,22 @@ colour = "red" ); } +/// A scene with no templates paints a chip that filters the grid to empty. +/// +/// The scene enum and the catalogue are edited separately — adding a variant +/// is a compiler-guided change, adding its templates is not — so nothing else +/// stops a chip from shipping ahead of the documents it filters for. +#[test] +fn every_scene_has_at_least_one_template_so_no_filter_chip_is_dead() { + for scene in TemplateScene::ALL { + assert!( + scene_templates_for(scene).next().is_some(), + "scene `{}` has no templates — its filter chip would show an empty grid", + scene.as_str() + ); + } +} + #[test] fn every_scene_has_a_distinct_label_so_the_filter_row_is_unambiguous() { let labels: Vec<&str> = TemplateScene::ALL diff --git a/crates/op-editor-ui/assets/scene_template_previews/gradient-tech.jpg b/crates/op-editor-ui/assets/scene_template_previews/gradient-tech.jpg new file mode 100644 index 000000000..64b6a7076 Binary files /dev/null and b/crates/op-editor-ui/assets/scene_template_previews/gradient-tech.jpg differ diff --git a/crates/op-editor-ui/assets/scene_template_previews/knowledge-card-square.jpg b/crates/op-editor-ui/assets/scene_template_previews/knowledge-card-square.jpg new file mode 100644 index 000000000..7c2e46160 Binary files /dev/null and b/crates/op-editor-ui/assets/scene_template_previews/knowledge-card-square.jpg differ diff --git a/crates/op-editor-ui/assets/scene_template_previews/knowledge-card-vertical.jpg b/crates/op-editor-ui/assets/scene_template_previews/knowledge-card-vertical.jpg new file mode 100644 index 000000000..4d263bbcf Binary files /dev/null and b/crates/op-editor-ui/assets/scene_template_previews/knowledge-card-vertical.jpg differ diff --git a/crates/op-editor-ui/assets/scene_template_previews/lecture-deck-light.jpg b/crates/op-editor-ui/assets/scene_template_previews/lecture-deck-light.jpg new file mode 100644 index 000000000..13f087100 Binary files /dev/null and b/crates/op-editor-ui/assets/scene_template_previews/lecture-deck-light.jpg differ diff --git a/crates/op-editor-ui/assets/scene_template_previews/minimal-keynote.jpg b/crates/op-editor-ui/assets/scene_template_previews/minimal-keynote.jpg new file mode 100644 index 000000000..342f93afc Binary files /dev/null and b/crates/op-editor-ui/assets/scene_template_previews/minimal-keynote.jpg differ diff --git a/crates/op-editor-ui/assets/scene_template_previews/pitch-deck-dark.jpg b/crates/op-editor-ui/assets/scene_template_previews/pitch-deck-dark.jpg new file mode 100644 index 000000000..d4d381899 Binary files /dev/null and b/crates/op-editor-ui/assets/scene_template_previews/pitch-deck-dark.jpg differ diff --git a/crates/op-editor-ui/assets/scene_template_previews/slide-deck.jpg b/crates/op-editor-ui/assets/scene_template_previews/slide-deck.jpg index 9168447b6..b7152da1f 100644 Binary files a/crates/op-editor-ui/assets/scene_template_previews/slide-deck.jpg and b/crates/op-editor-ui/assets/scene_template_previews/slide-deck.jpg differ diff --git a/crates/op-editor-ui/src/widgets/scene_template_previews.rs b/crates/op-editor-ui/src/widgets/scene_template_previews.rs index 62b34bf80..8d8c5f21b 100644 --- a/crates/op-editor-ui/src/widgets/scene_template_previews.rs +++ b/crates/op-editor-ui/src/widgets/scene_template_previews.rs @@ -36,6 +36,12 @@ pub(crate) fn scene_template_preview(template_id: &str) -> Option<(u64, &'static "knowledge-carousel" => preview!(2, "knowledge-carousel"), "before-after" => preview!(3, "before-after"), "slide-deck" => preview!(4, "slide-deck"), + "knowledge-card-vertical" => preview!(5, "knowledge-card-vertical"), + "knowledge-card-square" => preview!(6, "knowledge-card-square"), + "pitch-deck-dark" => preview!(7, "pitch-deck-dark"), + "lecture-deck-light" => preview!(8, "lecture-deck-light"), + "minimal-keynote" => preview!(9, "minimal-keynote"), + "gradient-tech" => preview!(10, "gradient-tech"), _ => None, } } diff --git a/templates/step0/_generators/previews.sh b/templates/step0/_generators/previews.sh index 67385a023..fe654f719 100644 --- a/templates/step0/_generators/previews.sh +++ b/templates/step0/_generators/previews.sh @@ -8,7 +8,10 @@ OUT=$R/templates/step0/previews TMP=$(mktemp -d) mkdir -p "$OUT" -for t in screenshot-tutorial knowledge-carousel before-after slide-deck; do +for t in screenshot-tutorial knowledge-carousel before-after slide-deck \ + knowledge-card-vertical knowledge-card-square \ + pitch-deck-dark lecture-deck-light \ + minimal-keynote gradient-tech; do # The documents themselves are shipped assets (embedded by the scene # template catalogue); this directory keeps only the generators and the # full-resolution renders they produce. diff --git a/templates/step0/_generators/scene_preview_cards.py b/templates/step0/_generators/scene_preview_cards.py index f1620ddff..29fa5b3f7 100644 --- a/templates/step0/_generators/scene_preview_cards.py +++ b/templates/step0/_generators/scene_preview_cards.py @@ -46,6 +46,13 @@ CARDS = [ ("knowledge-carousel", "knowledge-carousel-overview.png"), ("before-after", "before-after.png"), ("slide-deck", [f"slide-deck-{i:02d}.png" for i in range(1, 7)]), + ("knowledge-card-vertical", "knowledge-card-vertical.png"), + ("knowledge-card-square", "knowledge-card-square.png"), + ("pitch-deck-dark", [f"pitch-deck-dark-{i:02d}.png" for i in range(1, 7)]), + ("lecture-deck-light", + [f"lecture-deck-light-{i:02d}.png" for i in range(1, 7)]), + ("minimal-keynote", [f"minimal-keynote-{i:02d}.png" for i in range(1, 9)]), + ("gradient-tech", [f"gradient-tech-{i:02d}.png" for i in range(1, 7)]), ] # Gap between tiles, in source pixels — scaled down with everything else. diff --git a/templates/step0/_generators/tpl_cards.py b/templates/step0/_generators/tpl_cards.py new file mode 100644 index 000000000..ae2a7e50a --- /dev/null +++ b/templates/step0/_generators/tpl_cards.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 +"""knowledge-card-vertical.op + knowledge-card-square.op — 中文知识卡片 + +两套模板共用一份生成器,因为它们是同一套设计语言的两个画幅:竖版 +1080×1440 发小红书图文,方版 1080×1080 发公众号头图和朋友圈。分成两个 +文件写,改一处配色就得记得改另一处;合成一个,两张卡永远同源。 + +版式只做「标题 + 要点 + 署名」三段,是刻意的:卡片场景的用户要改的是 +文案,不是结构。多一个装饰区就多一处他们得先看懂再删掉的东西。 + +硬契约(与 skills 的中文排版约定一致): + - 内容距边缘 ≥80px(竖版 88/96,方版 84/88) + - 配色全部走 color_vars,改主色只改 $c-accent 一处 + - 正文与背景对比度 ≥2.0(本配色最低一对是 3.67,见文件末尾注释) + - CJK 行高:大标题 1.15,小标题 1.3,正文 1.6 + - 顶层 frame 必须显式写 x/y,否则多帧会全部堆在原点 +""" + +import os +import sys + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +from oplib import Ids, color_vars, frame, rect, solid, text, write_doc + +ids = Ids() + +# 暖纸底 + 单一强调色。知识卡片是「读」的东西,底色带一点暖比纯白更耐看, +# 也和已有的 knowledge-carousel(冷调靛蓝)拉开距离。 +VARS = color_vars({ + "c-bg": "#FFF7F0", + "c-surface": "#FFFFFF", + "c-ink": "#241A12", + "c-muted": "#7A6455", + "c-accent": "#C8502B", + "c-accent-soft": "#FAE3D8", + "c-border": "#EDDCD0", +}) + +# 正文用的中文字族。oplib 的默认族按字号/字重挑(<34 且 <600 走 Inter), +# 那条规则是为中英混排写的;这两张卡是纯中文,所以每个文本节点都显式写死 +# 中文族,免得小字号正文落到一个没有汉字的字族上再靠 fallback 兜。 +CJK = "Noto Sans SC" +# 序号和数字用 Inter:等宽感更强,"01" 这类标号排出来才齐。 +NUM = "Inter" + + +def card(name, *, width, height, pad_y, pad_x, children): + """一张卡。固定画幅,绝不 fit_content —— 发布尺寸是硬约束。 + + `space_between` 把「头部 / 要点 / 署名」三段推到各自该在的位置: + 卡片的留白不该是均匀的 gap,而是三段之间自然撑开的呼吸。 + """ + node = frame(ids, name, width=width, height=height, layout="vertical", + padding=[pad_y, pad_x], gap=0, + justifyContent="space_between", alignItems="start", + fill=solid("$c-bg"), clipContent=True) + node["children"] = children + node["x"] = 0 + node["y"] = 0 + return node + + +def block(name, children, gap=32): + """透明结构容器。没有 fill 才是结构层;一旦有 fill 它就是一张卡面了。""" + node = frame(ids, name, width="fill_container", height="fit_content", + layout="vertical", gap=gap, alignItems="start", fill=[]) + node["children"] = children + return node + + +def eyebrow(label, size=26): + """小标签。整张卡唯一的胶囊,用来交代这是哪一类内容。""" + node = frame(ids, "标签", width="fit_content", height="fit_content", + layout="horizontal", padding=[12, 24], gap=0, + cornerRadius=999, alignItems="center", + justifyContent="center", fill=solid("$c-accent-soft")) + node["children"] = [ + text(ids, "标签文字", label, size, 600, "$c-accent", family=CJK, + width="fit_content", growth="auto", line_height=1.4), + ] + return node + + +def rule(width=132, height=12): + return rect(ids, "强调短线", width=width, height=height, + cornerRadius=height // 2, fill=solid("$c-accent")) + + +def numbered(no, size): + """实心序号圆。白字压在主色上,是卡里对比度最高的一处,读者的视线锚点。""" + node = frame(ids, f"序号 {no}", width=size, height=size, + layout="horizontal", alignItems="center", + justifyContent="center", cornerRadius=size // 2, + fill=solid("$c-accent")) + node["children"] = [ + text(ids, "序号数字", str(no), round(size * 0.5), 700, "#FFFFFF", + family=NUM, width="fit_content", growth="auto", line_height=1.0), + ] + return node + + +def point(no, title, desc, *, badge, title_size, desc_size, gap): + node = frame(ids, f"要点 {no}", width="fill_container", + height="fit_content", layout="horizontal", gap=gap, + alignItems="start", fill=[]) + node["children"] = [ + numbered(no, badge), + block("要点文案", [ + text(ids, "要点标题", title, title_size, 600, "$c-ink", + family=CJK, line_height=1.3), + text(ids, "要点说明", desc, desc_size, 400, "$c-muted", + family=CJK, line_height=1.6), + ], gap=10), + ] + return node + + +def signature(*, avatar, name_size, slogan_size, gap): + """署名条。一条细分隔线 + 头像占位 + 名字 + 一句 slogan。 + + 头像用 frame 而不是 rectangle:frame 会递归渲染子节点,圆里那个字才 + 显示得出来;同时 frame 也是合法的图片拖放目标,用户把自己的头像拖上去 + 就直接替换掉这个占位。 + """ + disc = frame(ids, "头像占位", width=avatar, height=avatar, + layout="horizontal", alignItems="center", + justifyContent="center", cornerRadius=avatar // 2, + fill=solid("$c-accent-soft")) + disc["children"] = [ + text(ids, "头像文字", "笔", round(avatar * 0.42), 700, "$c-accent", + family=CJK, width="fit_content", growth="auto", line_height=1.0), + ] + + row = frame(ids, "署名行", width="fill_container", height="fit_content", + layout="horizontal", gap=gap, alignItems="center", fill=[]) + row["children"] = [ + disc, + block("署名文案", [ + text(ids, "账号名", "@ 你的账号名", name_size, 600, "$c-ink", + family=CJK, line_height=1.3), + text(ids, "一句话简介", "每周更新一条可落地的学习方法", + slogan_size, 400, "$c-muted", family=CJK, line_height=1.5), + ], gap=6), + ] + + divider = rect(ids, "分隔线", width="fill_container", height=2, + fill=solid("$c-border")) + return block("署名", [divider, row], gap=gap) + + +# ----------------------------------------------------------- 竖版 1080×1440 +VERTICAL_POINTS = [ + ("先提问,再翻开", + "带着「我想解决什么」进去,信息才有地方落。"), + ("合上书,先复述", + "读完立刻用自己的话讲一遍,卡壳的地方就是没懂的地方。"), + ("一次只带走三条", + "贪多必忘。记住三个能用的点,比划满一整本有用。"), + ("两天之内用一次", + "写进笔记、讲给朋友、或者直接做一遍,用过才算学过。"), +] + + +def vertical(): + head = block("卡头", [ + eyebrow("学习方法 · 01"), + text(ids, "主标题", "为什么你读了很多书\n却什么都记不住", 88, 700, + "$c-ink", family=CJK, line_height=1.15), + rule(), + text(ids, "副标题", "不是记性差,是你少做了这一步。", 30, 400, + "$c-muted", family=CJK, line_height=1.5), + ], gap=32) + + points = block("要点列表", [ + point(no, title, desc, badge=56, title_size=36, desc_size=27, gap=24) + for no, (title, desc) in enumerate(VERTICAL_POINTS, 1) + ], gap=28) + + return card("知识卡片 · 竖版", width=1080, height=1440, pad_y=96, pad_x=88, + children=[head, points, + signature(avatar=88, name_size=30, slogan_size=24, + gap=24)]) + + +# ----------------------------------------------------------- 方版 1080×1080 +SQUARE_POINTS = [ + ("先提问,再翻开", + "带着问题进去,信息才有地方落。"), + ("合上书,先复述", + "讲不出来的地方,就是还没懂的地方。"), + ("两天之内用一次", + "用过一次,才算真的学过。"), +] + + +def square(): + head = block("卡头", [ + eyebrow("学习方法"), + text(ids, "主标题", "读完就忘?\n先补上这一步", 76, 700, "$c-ink", + family=CJK, line_height=1.15), + rule(112, 10), + text(ids, "副标题", "三个动作,把书里的东西真正带走。", 28, 400, + "$c-muted", family=CJK, line_height=1.5), + ], gap=26) + + points = block("要点列表", [ + point(no, title, desc, badge=52, title_size=34, desc_size=26, gap=22) + for no, (title, desc) in enumerate(SQUARE_POINTS, 1) + ], gap=24) + + return card("知识卡片 · 方版", width=1080, height=1080, pad_y=88, pad_x=84, + children=[head, points, + signature(avatar=76, name_size=28, slogan_size=23, + gap=22)]) + + +# 对比度(WCAG 相对亮度比,op-design-lint 的门槛是 2.0): +# c-ink on c-bg 16.09 c-muted on c-bg 5.24 +# c-accent on c-bg 4.27 c-accent on c-accent-soft 3.67 +# #FFFFFF on c-accent 4.53 +# 最低一对 3.67 仍高出门槛近一倍,换主色时保留这个余量即可。 + +if __name__ == "__main__": + write_doc(sys.argv[1], VARS, [vertical()], "知识卡片 · 竖版 3:4") + write_doc(sys.argv[2], VARS, [square()], "知识卡片 · 方版 1:1") diff --git a/templates/step0/_generators/tpl_gradient_tech.py b/templates/step0/_generators/tpl_gradient_tech.py new file mode 100644 index 000000000..fd1f76bfe --- /dev/null +++ b/templates/step0/_generators/tpl_gradient_tech.py @@ -0,0 +1,416 @@ +#!/usr/bin/env python3 +"""gradient-tech.op — 渐变科技风 deck(6 页 1920×1080) + +深底 + 大面积渐变 + 玻璃拟态卡,开发者产品口吻。这套同时是引擎能力的展台: +线性渐变、径向光晕、玻璃卡三样都是 schema 原生支持、渲染栈真画得出来的 +(渲染探针见交付说明)。 + +## 玻璃卡为什么不用真 alpha + +玻璃拟态的自然写法是半透明白 `#FFFFFF1F`。渲染没问题,但 op-design-lint +的对比度检测器 `parse_hex_color` 会丢掉 alpha 通道,把这张卡当成**纯白不 +透明**:卡里的白字于是被判成 1.00:1,而真实合成结果是深紫上的白字。后果 +不只是误报——它会让这张卡内的所有文字都失去有效检测,真出现低对比配色也 +照样不报。 + +所以这里的玻璃卡用「不透明渐变」:stops 是「白 @ GLASS_ALPHA 合成到页面 +渐变对应 stop」的结果,光学上与真 alpha 一致(对照渲染验证过),但不含 +alpha 通道。代价是 stops 是烤死的——改了下面的 GRADIENT 就必须重跑本生成 +器,不能只改 .op 里的变量。 + +排版遵循 skills/domains/slides.md 的硬契约: + - 每帧固定 1920×1080,绝不 fit_content;内容距边 ≥100(这里 120) + - 正文 ≥24(取 26-30),标题 ≥40,关键数字 80-200(数据页取 132) + - 行高:标题 1.1-1.2,正文 1.45+ + - 最多 2 个字体族(Noto Sans SC 排中文,Inter 排数字与代码) + - 强调色只用于强调 + +渐变底上的对比度按**渐变两端分别实测**(比单点检测更严),最低一对 +4.85:1,全部高于 4.5。数值见文件末尾。 +""" + +import os +import sys + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +from oplib import Ids, color_vars, frame, rect, solid, text, write_doc + +ids = Ids() + +# 页面渐变的三个 stop:深紫 → 靛 → 蓝。玻璃卡的合成色由它们算出来,所以 +# 这里是整套配色的唯一真源。 +GRADIENT = [(0.0, "#1B0B3B"), (0.55, "#2A1E6E"), (1.0, "#0A2C6E")] +# 玻璃的白覆盖率。这个数是承重的:0.12 时强调色压在最亮那段玻璃上是 +# 4.85:1,提到 0.18 就掉到 4.00 —— 想让玻璃更亮,得先把强调色一起调。 +GLASS_ALPHA = 0.12 +GLASS_EDGE_ALPHA = 0.30 + + +def over(alpha, background): + """白色以 alpha 覆盖 background 后的不透明结果(直接的 source-over)。""" + channels = [int(background[i:i + 2], 16) for i in (1, 3, 5)] + return "#" + "".join( + f"{round(alpha * 255 + (1 - alpha) * c):02X}" for c in channels + ) + + +VARS = color_vars({ + "c-grad-a": GRADIENT[0][1], + "c-grad-b": GRADIENT[1][1], + "c-grad-c": GRADIENT[2][1], + "c-ink": "#FFFFFF", + "c-muted": "#C9D4F5", + "c-accent": "#3AC8FF", + # 对比条里「被比下去」的那根。用正文的 c-muted 会让基线条比强调条还 + # 抢眼(它更长),所以单独给一档更收的合成色;条不是文字,不参与对比 + # 度门槛。 + "c-bar-base": over(0.45, GRADIENT[1][1]), + # 玻璃卡的三段合成色(由 GRADIENT + GLASS_ALPHA 算出,改了要重跑)。 + "c-glass-a": over(GLASS_ALPHA, GRADIENT[0][1]), + "c-glass-b": over(GLASS_ALPHA, GRADIENT[1][1]), + "c-glass-c": over(GLASS_ALPHA, GRADIENT[2][1]), + # 描边不参与对比度检测,这里可以放心用真 alpha 取那道细白边。 + "c-glass-edge": "#FFFFFF4D", +}) + +W, H = 1920, 1080 +EDGE = 120 + +CJK = "Noto Sans SC" +NUM = "Inter" + +# 角度 135 = 左上 → 右下(渲染实测)。 +PAGE_ANGLE = 135 + + +def page_fill(): + return [{ + "type": "linear_gradient", + "angle": PAGE_ANGLE, + "stops": [{"offset": offset, "color": f"$c-grad-{key}"} + for (offset, _), key in zip(GRADIENT, "abc")], + }] + + +def glass_fill(): + """玻璃卡体。见文件头:不透明渐变,不是 alpha。""" + return [{ + "type": "linear_gradient", + "angle": PAGE_ANGLE, + "stops": [{"offset": offset, "color": f"$c-glass-{key}"} + for (offset, _), key in zip(GRADIENT, "abc")], + }] + + +def glass_edge(): + return {"thickness": 2, "fill": solid("$c-glass-edge")} + + +def slide(name, *, gap=56, justify="start"): + """一帧。固定 1920×1080,底是整页渐变。""" + node = frame(ids, name, width=W, height=H, layout="vertical", + padding=[EDGE, EDGE], gap=gap, justifyContent=justify, + alignItems="start", fill=page_fill(), clipContent=True) + node["children"] = [] + return node + + +def col(name, children, *, gap=16, width="fill_container", + height="fit_content", align="start", fill=None, **props): + node = frame(ids, name, width=width, height=height, layout="vertical", + gap=gap, alignItems=align, fill=fill or [], **props) + node["children"] = children + return node + + +def row(name, children, *, gap=32, align="start", width="fill_container", + height="fit_content", fill=None, **props): + node = frame(ids, name, width=width, height=height, layout="horizontal", + gap=gap, alignItems=align, fill=fill or [], **props) + node["children"] = children + return node + + +def glass_card(name, children, *, gap=18, height="fit_content", + padding=(40, 32), **props): + return col(name, children, gap=gap, height=height, + padding=[padding[0], padding[1]], cornerRadius=20, + fill=glass_fill(), stroke=glass_edge(), **props) + + +def centered_body(name, child): + """内容块在页标题以下的整块空间里垂直居中,页标题每页同高。""" + return col(name, [child], gap=0, height="fill_container", + justifyContent="center") + + +def eyebrow(label): + node = frame(ids, "标签", width="fit_content", height="fit_content", + layout="horizontal", padding=[10, 22], gap=0, + cornerRadius=999, alignItems="center", + justifyContent="center", fill=glass_fill(), + stroke=glass_edge()) + node["children"] = [ + text(ids, "标签文字", label, 26, 600, "$c-accent", family=CJK, + width="fit_content", growth="auto", line_height=1.4, + spacing=1.0), + ] + return node + + +def page_head(title, subtitle=None, *, size=60): + kids = [text(ids, "页标题", title, size, 700, "$c-ink", family=CJK, + line_height=1.15)] + if subtitle: + kids.append(text(ids, "页副标题", subtitle, 30, 400, "$c-muted", + family=CJK, line_height=1.45)) + return col("页头", kids, gap=18) + + +def mono(name, content, size=26, color="$c-accent"): + """代码腔的一行。Inter 不是等宽,但整套只允许两个字族,用字重区分。""" + return text(ids, name, content, size, 500, color, family=NUM, + width="fit_content", growth="auto", line_height=1.5) + + +# ------------------------------------------------------------------ 01 封面 +def cover(): + lede = col("主张", [ + text(ids, "主标题", "让每一次调用\n都在 20 毫秒内返回", 96, 700, + "$c-ink", family=CJK, line_height=1.12), + text(ids, "副标题", "边缘推理网关 v3.0,现已开放公测。", 32, 400, + "$c-muted", family=CJK, line_height=1.45), + ], gap=32) + + install = glass_card("安装行", [ + mono("安装命令", "$ npm i -g edgegate && edgegate up", 28), + ], gap=0, padding=(26, 32), width="fit_content") + + s = slide("01 封面", gap=48, justify="space_between") + s["children"] = [eyebrow("v3.0 · 公测"), lede, install] + return s + + +# ------------------------------------------------------------------ 02 痛点 +PAINS = [ + ("冷启动吃掉了首包", + "函数实例每次唤醒要 800ms,用户看到的却是整整一秒的白屏。"), + ("账单没法归因", + "月底一张总额,分不清哪个模型、哪条链路花掉的。"), + ("换云就得重写", + "每家的运行时都不一样,迁移一次等于把接入层重做一遍。"), +] + + +def problems(): + cards = [ + glass_card("痛点卡", [ + text(ids, "痛点序号", f"0{index}", 30, 700, "$c-accent", + family=NUM, width="fit_content", growth="auto", + line_height=1.1), + text(ids, "痛点标题", title, 36, 600, "$c-ink", family=CJK, + line_height=1.25), + text(ids, "痛点说明", desc, 27, 400, "$c-muted", family=CJK, + line_height=1.55), + ], gap=18, height="fill_container", padding=(44, 36)) + for index, (title, desc) in enumerate(PAINS, 1) + ] + + s = slide("02 痛点") + s["children"] = [ + page_head("在边缘跑推理,卡在三件事上", + "都不是模型的问题,是它前面那一层的问题。"), + centered_body("痛点区", row("痛点网格", cards, gap=32, + align="stretch")), + ] + return s + + +# ------------------------------------------------------------------ 03 架构 +LAYERS = [ + ("接入层", "Gateway", "一个 Anycast 入口,就近落到最快的可用区。"), + ("调度层", "Scheduler", "按延迟预算和单价实时选模型,超时自动降级。"), + ("运行层", "Runtime", "常驻实例池,冷启动摊薄到 3 毫秒以内。"), +] + + +def architecture(): + cards = [] + for index, (name, en, desc) in enumerate(LAYERS, 1): + head = row("层头", [ + text(ids, "层名", name, 36, 600, "$c-ink", family=CJK, + width="fit_content", growth="auto", line_height=1.25), + mono("层英文名", en, 26, "$c-accent"), + ], gap=16, align="center", width="fit_content") + cards.append(glass_card("架构层", [ + head, + text(ids, "层说明", desc, 27, 400, "$c-muted", family=CJK, + line_height=1.55), + ], gap=12, padding=(32, 36))) + + s = slide("03 架构") + s["children"] = [ + page_head("三层,一层只做一件事", + "自上而下,每一层都能单独替换。"), + centered_body("架构区", col("架构堆叠", cards, gap=20)), + ] + return s + + +# ------------------------------------------------------------------ 04 性能 +METRICS = [ + ("20", "ms", "P50 端到端", "含调度与网络"), + ("3", "ms", "冷启动", "常驻池摊薄后"), + ("62", "%", "成本下降", "同等 QPS 对比自建"), +] + +# 对比条:条长按真实数值成比例(越短越快),数字写在标签里。 +BAR_TRACK = 1600 +BAR_OURS_MS = 20 +BAR_BASE_MS = 210 + + +def metric_card(value, unit, label, note): + head = row("数值", [ + text(ids, "数值文字", value, 132, 700, "$c-accent", family=NUM, + width="fit_content", growth="auto", line_height=1.0), + # 单位跟着数字基线走:lineHeight 1.0 下 `end` 会把小字压到基线以 + # 下,这层只有下内距的盒子把它抬回来(jian 没有真 baseline 对齐)。 + col("单位", [ + text(ids, "单位文字", unit, 40, 600, "$c-accent", family=NUM, + width="fit_content", growth="auto", line_height=1.0), + ], gap=0, width="fit_content", padding=[0, 0, round((132 - 40) * 0.2), 0]), + ], gap=8, align="end", width="fit_content") + + return glass_card("性能卡", [ + head, + text(ids, "指标名", label, 30, 600, "$c-ink", family=CJK, + line_height=1.25), + text(ids, "指标说明", note, 26, 400, "$c-muted", family=CJK, + line_height=1.45), + ], gap=16, height="fill_container", padding=(40, 32)) + + +def bar(label, milliseconds, color): + width = round(BAR_TRACK * milliseconds / BAR_BASE_MS) + return col("对比条组", [ + text(ids, "条目标签", label, 26, 500, "$c-muted", family=CJK, + line_height=1.4), + rect(ids, "对比条", width=width, height=16, cornerRadius=999, + fill=solid(color)), + ], gap=10) + + +def performance(): + bars = glass_card("延迟对比", [ + text(ids, "对比标题", "端到端延迟对比", 30, 600, "$c-ink", + family=CJK, line_height=1.25), + bar("本产品 · 20ms", BAR_OURS_MS, "$c-accent"), + bar("自建方案 · 210ms", BAR_BASE_MS, "$c-bar-base"), + ], gap=20, padding=(32, 40)) + + # 三张卡与对比条合成一块「性能区」:直接摊在帧下会让页头、网格、对比 + # 卡成为三个平级兄弟,其中只有对比卡有圆角,mixed-sibling-corner-radius + # 会照实报出来(也确实读着像手滑)。 + body = col("性能区", [ + row("性能网格", [metric_card(*entry) for entry in METRICS], + gap=32, align="stretch"), + bars, + ], gap=32) + + s = slide("04 性能", gap=44) + s["children"] = [ + page_head("数字是压测出来的,不是估的"), + centered_body("性能居中", body), + ] + return s + + +# ------------------------------------------------------------------ 05 客户 +LOGO_SLOTS = 8 + + +def customers(): + # 每个格子是 frame 而不是 rectangle:frame 会递归渲染子节点(里面那行 + # 提示才显示得出来),同时它是合法的图片拖放目标,把客户 logo 拖上去 + # 就直接替换掉占位。 + slots = [] + for index in range(LOGO_SLOTS): + slot = frame(ids, f"Logo 位 {index + 1}", width="fill_container", + height="fill_container", layout="vertical", gap=0, + alignItems="center", justifyContent="center", + cornerRadius=16, fill=glass_fill(), stroke=glass_edge()) + slot["children"] = [ + text(ids, "占位提示", "拖入 Logo", 24, 500, "$c-muted", + family=CJK, width="fit_content", growth="auto", + line_height=1.4), + ] + slots.append(slot) + + grid = col("Logo 网格", [ + row("Logo 行", slots[0:4], gap=28, align="stretch", + height="fill_container"), + row("Logo 行", slots[4:8], gap=28, align="stretch", + height="fill_container"), + ], gap=28, height=420) + + s = slide("05 客户") + s["children"] = [ + page_head("已经在生产环境上跑", + "八家团队,日均 27 亿次调用。"), + centered_body("Logo 区", grid), + ] + return s + + +# ------------------------------------------------------------------ 06 CTA +def call_to_action(): + lede = col("结语", [ + text(ids, "结语标题", "十分钟接完\n剩下的交给我们", 84, 700, + "$c-ink", family=CJK, line_height=1.15), + text(ids, "结语副标题", "公测期不限调用量,接入文档一页写完。", + 30, 400, "$c-muted", family=CJK, line_height=1.45), + ], gap=30) + + actions = row("行动区", [ + glass_card("安装卡", [ + mono("安装命令", "$ npm i -g edgegate", 28), + ], gap=0, padding=(26, 32), width="fit_content"), + glass_card("文档卡", [ + mono("文档地址", "docs.edgegate.dev", 28, "$c-ink"), + ], gap=0, padding=(26, 32), width="fit_content"), + ], gap=24, align="center", width="fit_content") + + s = slide("06 CTA", gap=48, justify="space_between") + s["children"] = [eyebrow("公测开放中"), lede, actions] + return s + + +# 顶层 frame 必须显式写 x/y:缺省时每帧都落在原点,六页会叠成一页。纵向 +# gap 比横向多留 240,是给画布上固定在帧顶部的帧名标签让位。 +BOARD_GAP_X = 120 +BOARD_GAP_Y = BOARD_GAP_X + 240 +BOARDS_PER_ROW = 3 + + +def build(): + boards = [cover(), problems(), architecture(), performance(), + customers(), call_to_action()] + for index, board in enumerate(boards): + board["x"] = (index % BOARDS_PER_ROW) * (W + BOARD_GAP_X) + board["y"] = (index // BOARDS_PER_ROW) * (H + BOARD_GAP_Y) + return boards + + +# 对比度(WCAG,按渐变两端分别量,取最差值;门槛 4.5): +# 压在页面渐变上(三个 stop): +# c-ink 18.14 / 13.91 / 13.14 c-muted 12.28 / 9.42 / 8.90 +# c-accent 9.40 / 7.21 / 6.81 +# 压在玻璃卡上(白 @0.12 合成后的三段): +# c-ink 13.25 / 9.82 / 9.36 c-muted 8.97 / 6.65 / 6.34 +# c-accent 6.87 / 5.09 / 4.85 ← 最低一对 +# 注意 GLASS_ALPHA 是承重参数:提到 0.18,c-accent 会掉到 4.00。 + +if __name__ == "__main__": + write_doc(sys.argv[1], VARS, build(), "渐变科技风 · 16:9") diff --git a/templates/step0/_generators/tpl_lecture_light.py b/templates/step0/_generators/tpl_lecture_light.py new file mode 100644 index 000000000..19bf23cd7 --- /dev/null +++ b/templates/step0/_generators/tpl_lecture_light.py @@ -0,0 +1,431 @@ +#!/usr/bin/env python3 +"""lecture-deck-light.op — 浅色课件 deck(封面 / 目标 / 讲解 / 例题 / 对比 / 小结) + +课件跟汇报 deck 不是同一件事:听众要跟着做笔记,所以正文比路演更密、更 +完整,序号和步骤必须一眼数得清;同时它会被投在教室最后一排也看得见的地 +方,所以字号一点不能省。米白纸底 + 墨绿,是为了长时间盯着看不刺眼。 + +排版遵循 skills/domains/slides.md 的硬契约: + - 每帧固定 1920×1080,绝不 fit_content;内容距边缘 ≥100(这里 120) + - 正文 ≥24(取 26-30),标题 ≥40,行高标题 1.1-1.2、正文 1.4+ + - 最多 2 个字体族(Noto Sans SC 排中文,Inter 排数字与公式) + - 2-3 个主色 + 中性色,强调色只用于强调 + +纸白底上的对比度(WCAG,实测见文件末尾)最低一对是 5.01:1,全部高于 4.5。 +""" + +import os +import sys + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +from oplib import Ids, color_vars, frame, rect, solid, stroke, text, write_doc + +ids = Ids() + +# 米白纸 + 墨绿。底色刻意不是纯白:投影时纯白底会把整间教室照亮,米白既 +# 压得住反光,也让白色卡面浮得起来(白卡 / 纸底亮度比 1.16,看得出层次)。 +VARS = color_vars({ + "c-bg": "#F2EEE2", + "c-surface": "#FFFFFF", + "c-ink": "#17211C", + "c-muted": "#55635A", + "c-accent": "#1B6B4C", + "c-accent-soft": "#D8E9DE", + "c-border": "#D9D2C2", +}) + +W, H = 1920, 1080 +EDGE = 120 + +CJK = "Noto Sans SC" +NUM = "Inter" + + +def slide(name, *, gap=56, justify="start", fill="$c-bg"): + """一帧课件。固定 1920×1080 —— 投影比例是硬约束,不是建议。""" + node = frame(ids, name, width=W, height=H, layout="vertical", + padding=[EDGE, EDGE], gap=gap, justifyContent=justify, + alignItems="start", fill=solid(fill), clipContent=True) + node["children"] = [] + return node + + +def col(name, children, *, gap=16, width="fill_container", + height="fit_content", align="start", fill=None, **props): + """纵向容器。`fill=None` 才是结构层;一旦有 fill 它就是一张卡面了。""" + node = frame(ids, name, width=width, height=height, layout="vertical", + gap=gap, alignItems=align, fill=fill or [], **props) + node["children"] = children + return node + + +def row(name, children, *, gap=40, align="start", width="fill_container", + height="fit_content", fill=None, **props): + node = frame(ids, name, width=width, height=height, layout="horizontal", + gap=gap, alignItems=align, fill=fill or [], **props) + node["children"] = children + return node + + +def eyebrow(label): + """讲次标签。整套课件唯一的胶囊,交代「这是第几讲」。""" + node = frame(ids, "标签", width="fit_content", height="fit_content", + layout="horizontal", padding=[10, 22], gap=0, + cornerRadius=999, alignItems="center", + justifyContent="center", fill=solid("$c-accent-soft")) + node["children"] = [ + text(ids, "标签文字", label, 26, 600, "$c-accent", family=CJK, + width="fit_content", growth="auto", line_height=1.4, + spacing=1.0), + ] + return node + + +def accent_bar(width=150, height=10): + return rect(ids, "强调条", width=width, height=height, cornerRadius=999, + fill=solid("$c-accent")) + + +def numbered(no, size, *, filled=True): + """序号圆。白字压在墨绿上是全页对比度最高的一处,是眼睛的落点。""" + if filled: + fill, ink, edge = solid("$c-accent"), "#FFFFFF", None + else: + fill, ink, edge = solid("$c-surface"), "$c-accent", stroke("$c-accent", 3) + node = frame(ids, f"序号 {no}", width=size, height=size, + layout="horizontal", gap=0, alignItems="center", + justifyContent="center", cornerRadius=size // 2, fill=fill, + **({"stroke": edge} if edge else {})) + node["children"] = [ + text(ids, "序号数字", str(no), round(size * 0.46), 700, ink, + family=NUM, width="fit_content", growth="auto", line_height=1.0), + ] + return node + + +def centered_body(name, child): + """把内容块撑到页标题以下的整块空间里再垂直居中。 + + 页标题每页固定在同一高度(重复)是课件读起来整齐的前提;正文块又不该 + 被拉长到失真。两个诉求靠这一层透明容器同时满足。 + """ + return col(name, [child], gap=0, height="fill_container", + justifyContent="center") + + +def bullet_dot(size=14, line_size=28, line_height=1.55): + """项目符号。包一层只有上内距的容器,把圆心压到首行的光学中线上。 + + `align="start"` 会把圆点顶边对齐到文本盒顶边,而文本首行的中线在 + `fontSize * lineHeight / 2` 处 —— 直接并排会让每个圆点浮在字的上方。 + """ + lift = round(line_size * line_height / 2 - size / 2) + return col("条目圆点位", [ + rect(ids, "条目圆点", width=size, height=size, + cornerRadius=size // 2, fill=solid("$c-accent")), + ], gap=0, width="fit_content", padding=[lift, 0, 0, 0]) + + +def page_head(title, subtitle=None, *, size=64): + kids = [text(ids, "页标题", title, size, 700, "$c-ink", family=CJK, + line_height=1.15)] + if subtitle: + kids.append(text(ids, "页副标题", subtitle, 30, 400, "$c-muted", + family=CJK, line_height=1.45)) + return col("页头", kids, gap=18) + + +# ------------------------------------------------------------------ 01 封面 +def cover(): + lede = col("课程标题", [ + text(ids, "课名", "函数的单调性\n与极值判定", 100, 700, "$c-ink", + family=CJK, line_height=1.12), + accent_bar(), + text(ids, "课程说明", "这一讲我们只解决一个问题:拿到一个函数,怎么" + "判断它在哪段往上走。", 32, 400, "$c-muted", + family=CJK, line_height=1.45), + ], gap=36) + + meta = row("讲师信息", [ + text(ids, "讲师", "主讲 · 林望舒", 28, 500, "$c-ink", family=CJK, + width="fit_content", growth="auto"), + text(ids, "学期", "高等数学(上)· 2026 秋", 28, 400, "$c-muted", + family=CJK, width="fit_content", growth="auto"), + ], gap=32, align="center", justifyContent="space_between") + + s = slide("01 课程封面", gap=48, justify="space_between") + s["children"] = [eyebrow("第 07 讲"), lede, meta] + return s + + +# ------------------------------------------------------------------ 02 目标 +OBJECTIVES = [ + ("说得出定义", "用导数的符号说明单调递增、递减到底在讲什么。"), + ("判得出区间", "给定一个可导函数,能划出它的单调区间。"), + ("找得到极值", "会用一阶导数的符号变化确定极大值与极小值。"), +] + + +def objectives(): + items = [] + for index, (title, desc) in enumerate(OBJECTIVES, 1): + items.append(row(f"目标 {index}", [ + numbered(index, 64), + col("目标文案", [ + text(ids, "目标标题", title, 38, 600, "$c-ink", family=CJK, + line_height=1.25), + text(ids, "目标说明", desc, 28, 400, "$c-muted", family=CJK, + line_height=1.5), + ], gap=12), + ], gap=28, align="start", padding=[36, 40], cornerRadius=20, + fill=solid("$c-surface"))) + + s = slide("02 学习目标", gap=56) + s["children"] = [ + page_head("这节课下课时,你应该能——", + "三条,都要能自己动手做出来,不是听懂就算。"), + centered_body("目标区", col("目标列表", items, gap=24)), + ] + return s + + +# ------------------------------------------------------------------ 03 讲解 +def concept(): + body = col("概念正文", [ + col("定义组", [ + text(ids, "定义标题", "单调性的判定定理", 40, 600, "$c-ink", + family=CJK, line_height=1.25), + text(ids, "定义正文", + "设函数 f(x) 在区间 (a, b) 内可导。若在该区间内恒有 " + "f'(x) > 0,则 f(x) 在 (a, b) 上单调递增;若恒有 " + "f'(x) < 0,则单调递减。", + 30, 400, "$c-ink", family=CJK, line_height=1.6), + ], gap=20), + col("追问组", [ + rect(ids, "正文分隔线", width="fill_container", height=2, + fill=solid("$c-border")), + text(ids, "提示标题", "为什么成立", 30, 600, "$c-accent", + family=CJK, line_height=1.3), + text(ids, "提示正文", + "导数是切线的斜率。斜率一直为正,意味着曲线上任意两点连线" + "都在往右上方走——这正是「递增」的几何说法。", + 28, 400, "$c-muted", family=CJK, line_height=1.6), + ], gap=20), + ], gap=40, height="fill_container", justifyContent="space_between", + padding=[44, 44], cornerRadius=20, fill=solid("$c-surface")) + + # 配图位用 frame 而不是 rectangle:frame 会递归渲染子节点,里面那两行 + # 提示才显示得出来;frame 同时是合法的图片拖放目标,把函数图像拖上去 + # 就直接替换掉这个占位。 + figure = col("配图占位", [ + text(ids, "配图提示", "把函数图像拖到这里", 30, 600, "$c-accent", + family=CJK, width="fit_content", growth="auto", + line_height=1.3), + text(ids, "配图说明", "建议画出 f(x) 与 f'(x) 的符号对照", + 26, 400, "$c-muted", family=CJK, width="fit_content", + growth="auto", line_height=1.45), + ], gap=12, width=700, height="fill_container", padding=[0, 48], + align="center", justifyContent="center", cornerRadius=20, + fill=solid("$c-accent-soft")) + + s = slide("03 概念讲解", gap=56) + s["children"] = [ + page_head("导数的符号,决定曲线的走向"), + centered_body("图文区", row("图文两栏", [body, figure], gap=48, + align="stretch", height=560)), + ] + return s + + +# ------------------------------------------------------------------ 04 例题 +STEPS = [ + ("求导", "f'(x) = 3x² − 6x = 3x(x − 2)"), + ("找驻点", "令 f'(x) = 0,得 x = 0 与 x = 2"), + ("判符号", "x < 0 与 x > 2 时 f'(x) > 0;0 < x < 2 时 f'(x) < 0"), + ("下结论", "x = 0 处取极大值 f(0) = 1,x = 2 处取极小值 f(2) = −3"), +] + + +def worked_example(): + prompt = col("题干", [ + text(ids, "题干标签", "例题", 26, 600, "$c-accent", family=CJK, + width="fit_content", growth="auto", line_height=1.3, + spacing=1.0), + text(ids, "题干正文", + "求函数 f(x) = x³ − 3x² + 1 的单调区间与极值。", + 34, 600, "$c-ink", family=CJK, line_height=1.35), + ], gap=12, padding=[32, 36], cornerRadius=16, fill=solid("$c-accent-soft")) + + steps = [] + for index, (title, formula) in enumerate(STEPS, 1): + steps.append(row(f"步骤 {index}", [ + numbered(index, 52), + col("步骤文案", [ + text(ids, "步骤标题", title, 30, 600, "$c-ink", family=CJK, + line_height=1.3), + text(ids, "步骤算式", formula, 28, 400, "$c-muted", + family=NUM, line_height=1.5), + ], gap=8), + ], gap=24, align="start")) + + # 题干与解答装进同一张卡:例题在课件里是一个整体,拆成两块平级容器既 + # 削弱了「这是一道题」的读法,也让页面上出现三个圆角不一致的兄弟 + # (mixed-sibling-corner-radius 会照实报出来)。 + exam = col("例题卡", [ + prompt, + col("解答步骤", steps, gap=24), + ], gap=32, padding=[40, 44], cornerRadius=20, fill=solid("$c-surface")) + + s = slide("04 例题", gap=56) + s["children"] = [ + page_head("按这四步走,一步都不要跳"), + centered_body("例题区", exam), + ] + return s + + +# ------------------------------------------------------------------ 05 对比 +COMPARISON = [ + ("看的是什么", "f'(x) 在整个区间上的符号", "f'(x) 在某一点两侧的符号变化"), + ("回答的问题", "这段曲线往上还是往下", "这一点是不是拐上去/拐下来的地方"), + ("容易错在哪", "漏掉不可导的点也要单独讨论", + "驻点不一定是极值点,要看符号是否真的变了"), +] + +# 表格分隔线用 PenStroke 的 per-side 厚度:只画底边,四条边全画会把表格 +# 变成田字格,行与行的关系反而看不出来。最后一行不画,免得表格底部多出 +# 一条没有下文的线。 +def table_row(label, left, right, *, last=False): + cells = [ + col("行标题", [ + text(ids, "行标题文字", label, 27, 600, "$c-muted", family=CJK, + line_height=1.4), + ], gap=0, width=260), + col("左列内容", [ + text(ids, "左列文字", left, 28, 400, "$c-ink", family=CJK, + line_height=1.5), + ], gap=0), + col("右列内容", [ + text(ids, "右列文字", right, 28, 400, "$c-ink", family=CJK, + line_height=1.5), + ], gap=0), + ] + props = {"padding": [26, 32]} + if not last: + props["stroke"] = {"thickness": {"bottom": 2}, + "fill": solid("$c-border")} + return row("对比行", cells, gap=40, align="start", **props) + + +def comparison(): + header = row("表头", [ + col("表头行标题", [ + text(ids, "表头留白", " ", 27, 600, "$c-muted", family=CJK, + line_height=1.4), + ], gap=0, width=260), + col("表头左列", [ + text(ids, "表头左列文字", "单调性", 34, 700, "$c-accent", + family=CJK, line_height=1.3), + ], gap=0), + col("表头右列", [ + text(ids, "表头右列文字", "极值", 34, 700, "$c-accent", + family=CJK, line_height=1.3), + ], gap=0), + ], gap=40, align="start", padding=[26, 32], + stroke={"thickness": {"bottom": 3}, "fill": solid("$c-accent")}) + + table = col("对比表", [header] + [ + table_row(*entry, last=index == len(COMPARISON) - 1) + for index, entry in enumerate(COMPARISON) + ], gap=0, cornerRadius=20, fill=solid("$c-surface"), clipContent=True) + + s = slide("05 对比", gap=56) + s["children"] = [ + page_head("两个概念,别再混着用", + "单调性说的是一段,极值说的是一点。"), + centered_body("对比区", table), + ] + return s + + +# ------------------------------------------------------------------ 06 小结 +TAKEAWAYS = [ + "先求导,再找驻点,最后判符号——顺序不能换。", + "驻点只是候选,符号真的变了才是极值点。", + "不可导的点也要单独拿出来讨论。", +] + +HOMEWORK = [ + ("课本 P128", "习题 3.4 第 1、3、5 题"), + ("补充题", "讨论 f(x) = x·e^(−x) 的单调区间与极值"), + ("下次课前", "预习凹凸性与拐点(P131–P136)"), +] + + +def summary(): + left = col("本讲小结", [ + text(ids, "小结标题", "本讲小结", 40, 700, "$c-ink", family=CJK, + line_height=1.2), + col("小结条目", [ + row("小结条", [bullet_dot(), + text(ids, "条目文字", line, 28, 400, "$c-ink", family=CJK, + line_height=1.55)], + gap=20, align="start") + for line in TAKEAWAYS + ], gap=20), + ], gap=28, height="fill_container", padding=[44, 44], cornerRadius=20, + fill=solid("$c-surface")) + + right = col("课后作业", [ + text(ids, "作业标题", "课后作业", 40, 700, "$c-ink", family=CJK, + line_height=1.2), + col("作业条目", [ + col("作业条", [ + text(ids, "作业出处", source, 26, 600, "$c-accent", + family=CJK, line_height=1.3), + text(ids, "作业内容", detail, 28, 400, "$c-muted", + family=CJK, line_height=1.5), + ], gap=8) + for source, detail in HOMEWORK + ], gap=24), + ], gap=28, width=680, height="fill_container", padding=[44, 44], + cornerRadius=20, fill=solid("$c-accent-soft")) + + s = slide("06 小结与作业", gap=56) + s["children"] = [ + page_head("带走这三句话就够了"), + centered_body("小结区", row("小结两栏", [left, right], gap=48, + align="stretch", height=490)), + ] + return s + + +# 顶层 frame 必须显式写 x/y:缺省时每帧都落在原点,六页会叠成一页,另外 +# 五页藏在下面(2026-08-02 实录)。纵向 gap 比横向多留 240,是给画布上固定 +# 在帧顶部的帧名标签让位——标签是屏幕空间的,不随缩放变小。 +BOARD_GAP_X = 120 +BOARD_GAP_Y = BOARD_GAP_X + 240 +BOARDS_PER_ROW = 3 + + +def build(): + boards = [cover(), objectives(), concept(), worked_example(), + comparison(), summary()] + for index, board in enumerate(boards): + board["x"] = (index % BOARDS_PER_ROW) * (W + BOARD_GAP_X) + board["y"] = (index // BOARDS_PER_ROW) * (H + BOARD_GAP_Y) + return boards + + +# 对比度(WCAG 相对亮度比,投影场景自设门槛 4.5,远高于 op-design-lint 的 2.5): +# c-ink on c-bg 14.25 c-ink on c-surface 16.53 +# c-muted on c-bg 5.46 c-muted on c-surface 6.33 +# c-accent on c-bg 5.56 c-accent on c-surface 6.45 +# c-accent on c-accent-soft 5.11 c-muted on c-accent-soft 5.01 ← 最低 +# #FFFFFF on c-accent 6.45(序号圆里的白字) +# 换主色时先量 c-muted on c-accent-soft:浅色 deck 的下限总是出在 +# 「弱化文字压在弱化底色上」这一对,不是出在标题上。 + +if __name__ == "__main__": + write_doc(sys.argv[1], VARS, build(), "课件 deck · 浅色 16:9") diff --git a/templates/step0/_generators/tpl_minimal_keynote.py b/templates/step0/_generators/tpl_minimal_keynote.py new file mode 100644 index 000000000..555089476 --- /dev/null +++ b/templates/step0/_generators/tpl_minimal_keynote.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python3 +"""minimal-keynote.op — 极简 Keynote deck(8 页 1920×1080) + +这套的难点是「少」。没有卡片、没有描边、没有底色块,一页只留 2-4 个元素, +版面全靠字阶落差和留白撑。元素越少,任何一处对不齐都无处遁形——所以整套 +只有一条左基线(EDGE=160),每页的内容块都从这条线起排,纵向居中。 + +跟已有三套的区别:slide-deck 是暖白商务、pitch-deck-dark 是深底路演、 +lecture-deck-light 是纸白课件,它们都靠「卡片」组织信息;这一套刻意不给 +任何容器上色,是发布会舞台上那种一句话一屏的节奏。 + +排版遵循 skills/domains/slides.md 的硬契约: + - 每帧固定 1920×1080,绝不 fit_content;内容距边 ≥100(这里 160) + - 正文 ≥24(取 28-32),标题 ≥40,关键数字 80-200(数据页取 200) + - 行高:展示字 1.05-1.15,正文 1.45+ + - 最多 2 个字体族(Noto Sans SC 排中文,Inter 排数字),靠字重分层 + - 强调色只用于强调 + +白底上的对比度(WCAG,实测见文件末尾)最低一对是 5.33:1,全部高于 4.5。 +""" + +import os +import sys + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +from oplib import Ids, color_vars, frame, rect, solid, text, write_doc + +ids = Ids() + +# 纯白 + 近黑 + 一个克制的朱红。 +# +# 强调色没有用常见的 #FF5A36:那个橙在纯白上只有 3.10:1,当文字用不到 +# 4.5 的可读线(实测,见文件末尾)。降明度到 #C7340F 后是 5.35:1,色相 +# 仍在同一族,投影时反而更沉得住。整套只有这一个彩色,出现三次以内。 +VARS = color_vars({ + "c-bg": "#FFFFFF", + "c-ink": "#0A0A0A", + "c-muted": "#6B6B6B", + "c-accent": "#C7340F", +}) + +W, H = 1920, 1080 +# 留白是这套模板唯一的「装饰」,所以边距给到 160 —— 契约下限 100 的 1.6 倍。 +EDGE = 160 + +CJK = "Noto Sans SC" +NUM = "Inter" + + +def slide(name, *, gap=40, justify="center"): + """一帧。固定 1920×1080,无底色块、无描边 —— 白就是版面本身。""" + node = frame(ids, name, width=W, height=H, layout="vertical", + padding=[EDGE, EDGE], gap=gap, justifyContent=justify, + alignItems="start", fill=solid("$c-bg"), clipContent=True) + node["children"] = [] + return node + + +def col(name, children, *, gap=16, width="fill_container", + height="fit_content", **props): + """透明结构容器。这套模板里没有任何一个容器该有 fill。""" + node = frame(ids, name, width=width, height=height, layout="vertical", + gap=gap, alignItems="start", fill=[], **props) + node["children"] = children + return node + + +def row(name, children, *, gap=32, align="center", **props): + node = frame(ids, name, width="fill_container", height="fit_content", + layout="horizontal", gap=gap, alignItems=align, fill=[], + **props) + node["children"] = children + return node + + +def accent_rule(width=120, height=8): + """整套唯一的图形元素。一条短线,替代所有本该是卡片边框的东西。""" + return rect(ids, "强调短线", width=width, height=height, + fill=solid("$c-accent")) + + +# ------------------------------------------------------------------ 01 封面 +def cover(): + lede = col("主张", [ + text(ids, "主标题", "把复杂\n留在里面", 130, 700, "$c-ink", + family=CJK, line_height=1.08), + accent_rule(), + text(ids, "副标题", "第七代产品,今天发布。", 32, 400, "$c-muted", + family=CJK, line_height=1.45), + ], gap=40) + + meta = row("落款", [ + text(ids, "场合", "2026 秋季发布会", 26, 500, "$c-ink", family=CJK, + width="fit_content", growth="auto"), + text(ids, "日期", "2026.10.08", 26, 400, "$c-muted", family=NUM, + width="fit_content", growth="auto"), + ], gap=28, justifyContent="space_between") + + s = slide("01 封面", gap=48, justify="space_between") + s["children"] = [lede, meta] + return s + + +# ------------------------------------------------------------ 02 一句话论点 +def statement(): + s = slide("02 论点", gap=44) + s["children"] = [ + rect(ids, "强调点", width=18, height=18, cornerRadius=9, + fill=solid("$c-accent")), + text(ids, "论点", "我们删掉了三十七个按钮。", 76, 700, "$c-ink", + family=CJK, line_height=1.15), + ] + return s + + +# ------------------------------------------------------------- 03-05 词页 +# 一页一个字。注解只有一行,写不下就说明这个词选错了。 +WORDS = [ + ("少", "从三十七个按钮,到三个。"), + ("轻", "整机一点零九公斤,比上一代少了两百四十克。"), + ("久", "一次充电,用满两天。"), +] + + +def word_page(index, word, note): + s = slide(f"0{index + 3} 词 · {word}", gap=36) + s["children"] = [ + text(ids, "大词", word, 200, 700, "$c-ink", family=CJK, + line_height=1.05), + text(ids, "注解", note, 30, 400, "$c-muted", family=CJK, + line_height=1.5), + ] + return s + + +# ------------------------------------------------------------------ 06 引用 +def quote(): + s = slide("06 引用", gap=32) + s["children"] = [ + # 引号本身当图形用,替掉一切边框和背景块。lineHeight 压到 0.5 是 + # 量出来的:引号的墨迹只占 em 盒顶部约三分之一,默认行高会在它下面 + # 留出一大片空行盒,看起来就像 gap 没设对(同 oplib 里 `●` 用 + # DOT_LINE_HEIGHT 收行盒的做法)。 + text(ids, "引号", "“", 160, 700, "$c-accent", family=NUM, + line_height=0.5), + text(ids, "引文", "最好的设计,是让人忘了它存在。", 54, 600, + "$c-ink", family=CJK, line_height=1.3), + text(ids, "出处", "— 产品负责人 沈亦文", 28, 400, "$c-muted", + family=CJK, line_height=1.5), + ] + return s + + +# ------------------------------------------------------------- 07 数据一句话 +def one_number(): + s = slide("07 数据", gap=32) + s["children"] = [ + # 契约允许关键数字 80-200,这里取上限:整页只有它和一行注。 + text(ids, "大数字", "0.4 秒", 200, 700, "$c-ink", family=NUM, + line_height=1.05), + text(ids, "注解", "从按下到出图的全部时间,上一代是 2.6 秒。", + 32, 400, "$c-muted", family=CJK, line_height=1.5), + ] + return s + + +# ------------------------------------------------------------------ 08 结尾 +def closing(): + s = slide("08 结尾", gap=40) + s["children"] = [ + accent_rule(), + text(ids, "结语", "今天开始发货。", 96, 700, "$c-ink", family=CJK, + line_height=1.12), + text(ids, "补充", "全国门店同步开售,官网可预约体验。", 30, 400, + "$c-muted", family=CJK, line_height=1.5), + ] + return s + + +# 顶层 frame 必须显式写 x/y:缺省时每帧都落在原点,八页会叠成一页(前一批 +# 模板 2026-08-02 的实录)。纵向 gap 比横向多留 240,是给画布上固定在帧顶部 +# 的帧名标签让位——标签是屏幕空间的,不随缩放变小。 +BOARD_GAP_X = 120 +BOARD_GAP_Y = BOARD_GAP_X + 240 +BOARDS_PER_ROW = 3 + + +def build(): + boards = [cover(), statement()] + boards += [word_page(i, w, n) for i, (w, n) in enumerate(WORDS)] + boards += [quote(), one_number(), closing()] + for index, board in enumerate(boards): + board["x"] = (index % BOARDS_PER_ROW) * (W + BOARD_GAP_X) + board["y"] = (index // BOARDS_PER_ROW) * (H + BOARD_GAP_Y) + return boards + + +# 对比度(WCAG 相对亮度比,投影场景自设门槛 4.5,远高于 op-design-lint 的 2.5): +# c-ink on c-bg 19.80 +# c-muted on c-bg 5.33 ← 最低一对 +# c-accent on c-bg 5.35 +# 换强调色时先量它在纯白上的比值:橙红一族很容易掉到 4.5 以下 +# (#FF5A36 = 3.10、#E5471F = 4.00 都不够,#C7340F = 5.35 才过)。 + +if __name__ == "__main__": + write_doc(sys.argv[1], VARS, build(), "极简 Keynote · 16:9") diff --git a/templates/step0/_generators/tpl_pitch_dark.py b/templates/step0/_generators/tpl_pitch_dark.py new file mode 100644 index 000000000..00cbaccac --- /dev/null +++ b/templates/step0/_generators/tpl_pitch_dark.py @@ -0,0 +1,396 @@ +#!/usr/bin/env python3 +"""pitch-deck-dark.op — 深色路演 deck(封面 / 问题 / 方案 / 数据 / 里程碑 / CTA) + +已有的 slide-deck 是暖白商务风,适合汇报;这一套是它的反面:黑底、单强调 +色、大字号、少而重的信息。路演是「在别人只肯给你八分钟的房间里,把一件 +事讲到对方想追问」——所以每页只有一个视觉锚点,其余全部让位。 + +排版遵循 skills/domains/slides.md 的硬契约: + - 每帧固定 1920×1080,绝不 fit_content;内容距边缘 ≥100(这里 120) + - 正文 ≥24(取 26-30),标题 ≥40,关键数字 80-200(数据页取 140) + - 行高:标题 1.1-1.2,正文 1.4+ + - 最多 2 个字体族(Noto Sans SC 排中文,Inter 排数字),靠字重分层 + - 强调色只用于强调;正文一律中性色 + +深底上的对比度(WCAG,实测见文件末尾)最低一对是 4.73:1,全部高于 4.5。 +""" + +import os +import sys + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +from oplib import Ids, color_vars, frame, rect, solid, stroke, text, write_doc + +ids = Ids() + +# 近黑的石墨蓝 + 一个电光蓝。深色 deck 最容易翻车的地方是「深色 = 一堆 +# 灰」:所以底色只有两级(bg / surface),层级靠字重和强调色拉,不靠再多 +# 铺几层灰面。 +VARS = color_vars({ + "c-bg": "#0B1220", + "c-surface": "#18263F", + "c-ink": "#F2F6FF", + "c-muted": "#93A4C4", + "c-accent": "#4D8DFF", + "c-accent-soft": "#16233D", + "c-border": "#24314D", +}) + +W, H = 1920, 1080 +EDGE = 120 + +# 中文字族写死:oplib 的默认族按字号/字重挑(<34 且 <600 走 Inter),那条 +# 规则是给中英混排写的;这套 deck 是纯中文正文,小字号也必须落在有汉字的 +# 字族上,否则要靠 fallback 兜。 +CJK = "Noto Sans SC" +# 数字、单位符号走 Inter:等宽感更强,KPI 排出来才齐。 +NUM = "Inter" + + +def slide(name, *, gap=56, justify="start", fill="$c-bg"): + """一帧幻灯片。固定 1920×1080 —— 投影比例是硬约束,不是建议。""" + node = frame(ids, name, width=W, height=H, layout="vertical", + padding=[EDGE, EDGE], gap=gap, justifyContent=justify, + alignItems="start", fill=solid(fill), clipContent=True) + node["children"] = [] + return node + + +def col(name, children, *, gap=16, width="fill_container", + height="fit_content", align="start", fill=None, **props): + """纵向容器。`fill=None` 才是结构层;一旦有 fill 它就是一张卡面了。""" + node = frame(ids, name, width=width, height=height, layout="vertical", + gap=gap, alignItems=align, fill=fill or [], **props) + node["children"] = children + return node + + +def row(name, children, *, gap=40, align="start", width="fill_container", + height="fit_content", fill=None, **props): + node = frame(ids, name, width=width, height=height, layout="horizontal", + gap=gap, alignItems=align, fill=fill or [], **props) + node["children"] = children + return node + + +def eyebrow(label): + """小标签。整套 deck 唯一的胶囊,用来交代「这是什么场合」。""" + node = frame(ids, "标签", width="fit_content", height="fit_content", + layout="horizontal", padding=[10, 22], gap=0, + cornerRadius=999, alignItems="center", + justifyContent="center", fill=solid("$c-accent-soft")) + node["children"] = [ + text(ids, "标签文字", label, 26, 600, "$c-accent", family=CJK, + width="fit_content", growth="auto", line_height=1.4, + spacing=1.0), + ] + return node + + +def accent_bar(width=160, height=10): + return rect(ids, "强调条", width=width, height=height, cornerRadius=999, + fill=solid("$c-accent")) + + +def divider(): + return rect(ids, "分隔线", width="fill_container", height=2, + fill=solid("$c-border")) + + +def centered_body(name, child): + """把内容块撑到页标题以下的整块空间里再垂直居中。 + + 页标题每页固定在同一高度(重复)是 deck 读起来整齐的前提;正文块又不 + 该被拉长到失真。两个诉求靠这一层透明容器同时满足。 + """ + return col(name, [child], gap=0, height="fill_container", + justifyContent="center") + + +def page_head(title, subtitle=None, *, size=64): + kids = [text(ids, "页标题", title, size, 700, "$c-ink", family=CJK, + line_height=1.15)] + if subtitle: + kids.append(text(ids, "页副标题", subtitle, 30, 400, "$c-muted", + family=CJK, line_height=1.45)) + return col("页头", kids, gap=18) + + +# ------------------------------------------------------------------ 01 封面 +def cover(): + lede = col("主张", [ + text(ids, "主标题", "把三天的报价\n压进三分钟", 112, 700, "$c-ink", + family=CJK, line_height=1.12), + accent_bar(), + text(ids, "副标题", "我们在做的,是让每一家工厂当场就能报出价来。", + 34, 400, "$c-muted", family=CJK, line_height=1.45), + ], gap=36) + + meta = row("落款", [ + text(ids, "演讲者", "启明智造 · 创始人 陈知远", 28, 500, "$c-ink", + family=CJK, width="fit_content", growth="auto"), + text(ids, "场合", "2026.08 · 种子轮路演", 28, 400, "$c-muted", + family=CJK, width="fit_content", growth="auto"), + ], gap=32, align="center", justifyContent="space_between") + + s = slide("01 封面", gap=48, justify="space_between") + s["children"] = [eyebrow("种子轮 · 融资路演"), lede, meta] + return s + + +# ------------------------------------------------------------------ 02 问题 +PAINS = [ + ("算不清", "一份报价要问遍四个部门,等两天才知道能不能接。"), + ("报不准", "凭经验拍的价,做完才发现毛利被工时和损耗吃光了。"), + ("跟不上", "客户当场要数,我们只能说「回去核一下」——单子就这么走了。"), +] + + +def problem(): + rows = [] + for index, (title, desc) in enumerate(PAINS, 1): + if rows: + rows.append(divider()) + rows.append(row(f"痛点 {index}", [ + text(ids, "痛点序号", f"0{index}", 64, 700, "$c-accent", + family=NUM, width="fit_content", growth="auto", + line_height=1.0), + col("痛点文案", [ + text(ids, "痛点标题", title, 40, 600, "$c-ink", family=CJK, + line_height=1.2), + text(ids, "痛点说明", desc, 28, 400, "$c-muted", family=CJK, + line_height=1.5), + ], gap=12), + ], gap=40, align="start")) + + s = slide("02 问题", gap=56) + s["children"] = [ + page_head("报价这一步,卡住了整条链路", + "三个问题,每一个都在直接吃掉订单。"), + col("痛点列表", rows, gap=0, height="fill_container", + justifyContent="space_between"), + ] + return s + + +# ------------------------------------------------------------------ 03 方案 +SELLING_POINTS = [ + ("三分钟出价", "上传图纸,系统直接算出工时、材料与损耗。"), + ("毛利先看见", "每一档价格旁边就是毛利率,接不接一眼决定。"), + ("越报越准", "每完成一单回流真实成本,模型自己往回修。"), +] + + +def solution(): + cards = [] + for title, desc in SELLING_POINTS: + cards.append(col("卖点卡", [ + rect(ids, "卡首强调条", width=56, height=6, cornerRadius=999, + fill=solid("$c-accent")), + text(ids, "卖点标题", title, 38, 600, "$c-ink", family=CJK, + line_height=1.2), + text(ids, "卖点说明", desc, 27, 400, "$c-muted", family=CJK, + line_height=1.55), + ], gap=22, height="fill_container", padding=[48, 40], + cornerRadius=20, fill=solid("$c-surface"))) + + s = slide("03 方案", gap=56) + s["children"] = [ + page_head("把报价变成一次点击", + "工艺库 + 实时成本模型,客户还在电话里,价就出来了。"), + centered_body("卖点区", row("卖点网格", cards, gap=36, + align="stretch")), + ] + return s + + +# ------------------------------------------------------------------ 04 数据 +METRICS = [ + ("42", "倍", "报价提速", "两天的活儿,三分钟出结果"), + ("97", "%", "报价准确率", "与实际成本偏差不超过 3%"), + ("2.3", "亿元", "在跑的订单金额", "来自 46 家制造企业"), +] + +# 大数字 lineHeight 1.0 时基线离行盒底部约 0.2em;单位字号小得多,`end` +# 对齐会把它压到基线以下。这个补偿把单位的行盒底抬回大数字的基线附近, +# 让「42」和「×」看起来站在同一条线上。jian 没有真正的 baseline 对齐 +# (AlignItems::from_css 把 "baseline" 折成 End),所以只能这样补。 +VALUE_SIZE = 140 +UNIT_SIZE = 44 +UNIT_BASELINE_LIFT = round((VALUE_SIZE - UNIT_SIZE) * 0.2) + + +def unit_family(unit): + """汉字单位(亿元)排中文族,符号单位(× %)排 Inter 跟数字同源。""" + return CJK if any(ord(ch) > 0x2FFF for ch in unit) else NUM + + +def metric_card(value, unit, label, note): + unit_box = frame(ids, "单位", width="fit_content", height="fit_content", + layout="vertical", gap=0, + padding=[0, 0, UNIT_BASELINE_LIFT, 0], fill=[]) + unit_box["children"] = [ + text(ids, "单位文字", unit, UNIT_SIZE, 600, "$c-accent", + family=unit_family(unit), width="fit_content", growth="auto", + line_height=1.0), + ] + return col("数据卡", [ + row("数值", [ + text(ids, "数值文字", value, VALUE_SIZE, 700, "$c-accent", + family=NUM, width="fit_content", growth="auto", + line_height=1.0), + unit_box, + ], gap=10, align="end", width="fit_content"), + text(ids, "指标名", label, 32, 600, "$c-ink", family=CJK, + line_height=1.25), + text(ids, "指标说明", note, 26, 400, "$c-muted", family=CJK, + line_height=1.45), + ], gap=20, height="fill_container", justifyContent="center", + padding=[56, 44], cornerRadius=24, fill=solid("$c-surface")) + + +def metrics(): + s = slide("04 数据", gap=56) + s["children"] = [ + page_head("半年里,它已经在跑", + "不是路演里的假设,是 46 家工厂每天在用的数。"), + centered_body("数据区", row("数据网格", + [metric_card(*entry) for entry in METRICS], + gap=36, align="stretch")), + ] + return s + + +# --------------------------------------------------------------- 05 里程碑 +MILESTONES = [ + ("2026 Q3", "工艺库上线", "覆盖钣金、机加两条主线", True), + ("2026 Q4", "接入 ERP", "报价直接落成订单", True), + ("2027 Q1", "开放 API", "让客户在自己系统里报价", False), + ("2027 Q2", "行业模板", "从制造扩到工程与装修", False), +] + +# 时间轴列之间不留 gap:轴线是每列自己那一段拼起来的,列间一旦有间隙, +# 轴就断成四截。列内文案靠右 padding 让出呼吸,轴线段照样贯穿。 +TIMELINE_TEXT_INSET = 56 +DOT = 28 + + +def milestone_column(date, title, desc, reached): + """一段时间轴。圆点与文案都左对齐,轴线从圆点向右延伸到下一个圆点。""" + if reached: + dot = rect(ids, "节点圆", width=DOT, height=DOT, cornerRadius=DOT // 2, + fill=solid("$c-accent")) + else: + dot = rect(ids, "节点圆", width=DOT, height=DOT, cornerRadius=DOT // 2, + fill=solid("$c-bg"), stroke=stroke("$c-accent", 4)) + + axis = row("轴段", [ + dot, + rect(ids, "轴线", width="fill_container", height=4, + fill=solid("$c-border")), + ], gap=0, align="center", height="fit_content") + + # 上下两块文案带右内缩,轴段一律不写 padding —— 三个同类兄弟里只有两个 + # 可归一化的 padding 值,mixed-sibling-padding 因此不会误判(同一个值 + # 出现两次,另一个不参与统计)。 + head = col("节点日期", [ + text(ids, "日期", date, 28, 600, "$c-accent", family=NUM, + line_height=1.2, spacing=0.5), + ], gap=0, padding=[0, TIMELINE_TEXT_INSET, 0, 0]) + body = col("节点文案", [ + text(ids, "节点标题", title, 34, 600, "$c-ink", family=CJK, + line_height=1.25), + text(ids, "节点说明", desc, 26, 400, "$c-muted", family=CJK, + line_height=1.5), + ], gap=10, padding=[0, TIMELINE_TEXT_INSET, 0, 0]) + + return col("里程碑", [head, axis, body], gap=28) + + +def roadmap(): + s = slide("05 里程碑", gap=56) + s["children"] = [ + page_head("接下来十二个月", + "前两步已经走完,这轮钱花在后两步上。"), + centered_body("时间轴区", + row("时间轴", + [milestone_column(*entry) for entry in MILESTONES], + gap=0, align="start")), + ] + return s + + +# ---------------------------------------------------------------- 06 结尾 +def closing(): + lede = col("结语", [ + accent_bar(), + text(ids, "结语标题", "如果你也觉得\n这事早该被解决", 88, 700, + "$c-ink", family=CJK, line_height=1.15), + text(ids, "结语副标题", "我们缺的不是订单,是把它做快的那笔钱。", + 32, 400, "$c-muted", family=CJK, line_height=1.45), + ], gap=36) + + # 名字与两行联络方式分成两层,不是排版洁癖:三个平级文本一旦字号 32 / + # 30 / 30,sibling-inconsistency 会把那个 32 当成手滑。分层之后 32 是 + # 标题、30 是并列的两行,各自内部一致。 + contact = col("联系方式", [ + text(ids, "联系人", "陈知远 · 创始人", 32, 600, "$c-ink", family=CJK, + line_height=1.3), + col("联络方式", [ + text(ids, "邮箱", "zhiyuan@qimingzz.com", 30, 500, "$c-accent", + family=NUM, line_height=1.4), + text(ids, "电话", "+86 138 0000 0000", 30, 400, "$c-muted", + family=NUM, line_height=1.4), + ], gap=10, width="fit_content"), + ], gap=18, width="fit_content") + + # 二维码占位用 frame 而不是 rectangle:frame 会递归渲染子节点,里面那行 + # 提示才显示得出来;frame 同时是合法的图片拖放目标,把二维码图片拖上去 + # 就直接替换掉这个占位。 + qr = frame(ids, "二维码占位", width=200, height=200, layout="vertical", + gap=0, alignItems="center", justifyContent="center", + cornerRadius=16, fill=solid("$c-accent-soft"), + stroke=stroke("$c-accent", 2)) + qr["children"] = [ + text(ids, "二维码提示", "扫码看 Demo", 26, 600, "$c-accent", + family=CJK, width="fit_content", growth="auto", + line_height=1.3), + ] + + card = row("联系卡", [contact, qr], gap=48, align="center", + justifyContent="space_between", padding=[48, 56], + cornerRadius=24, fill=solid("$c-surface")) + + s = slide("06 结尾", gap=56, justify="space_between") + s["children"] = [lede, card] + return s + + +# 顶层 frame 必须显式写 x/y:缺省时每帧都落在原点,六页会叠成一页,另外 +# 五页藏在下面(2026-08-02 实录)。横向 gap 与纵向 gap 的取值同 tpl_slides: +# 纵向多留 240,是给画布上固定在帧顶部的帧名标签让位——标签是屏幕空间的, +# 不随缩放变小,deck 缩到能整屏看时 120 文档像素只剩十几个屏幕像素。 +BOARD_GAP_X = 120 +BOARD_GAP_Y = BOARD_GAP_X + 240 +BOARDS_PER_ROW = 3 + + +def build(): + boards = [cover(), problem(), solution(), metrics(), roadmap(), closing()] + for index, board in enumerate(boards): + board["x"] = (index % BOARDS_PER_ROW) * (W + BOARD_GAP_X) + board["y"] = (index // BOARDS_PER_ROW) * (H + BOARD_GAP_Y) + return boards + + +# 对比度(WCAG 相对亮度比,投影场景自设门槛 4.5,远高于 op-design-lint 的 2.5): +# c-ink on c-bg 17.30 c-ink on c-surface 13.98 +# c-muted on c-bg 7.44 c-muted on c-surface 6.01 +# c-accent on c-bg 5.86 c-accent on c-surface 4.73 ← 最低一对 +# c-accent on c-accent-soft 4.90 +# 数据页的 140px 大数字用的是 c-accent on c-surface = 4.73:1。换强调色时 +# 先拿这一对量一遍:深底上亮色越纯,比值掉得越快。 + +if __name__ == "__main__": + write_doc(sys.argv[1], VARS, build(), "路演 deck · 深色 16:9") diff --git a/templates/step0/previews/gradient-tech-01.png b/templates/step0/previews/gradient-tech-01.png new file mode 100644 index 000000000..bb9ea892a Binary files /dev/null and b/templates/step0/previews/gradient-tech-01.png differ diff --git a/templates/step0/previews/gradient-tech-02.png b/templates/step0/previews/gradient-tech-02.png new file mode 100644 index 000000000..005a0ea01 Binary files /dev/null and b/templates/step0/previews/gradient-tech-02.png differ diff --git a/templates/step0/previews/gradient-tech-03.png b/templates/step0/previews/gradient-tech-03.png new file mode 100644 index 000000000..0cf8d7691 Binary files /dev/null and b/templates/step0/previews/gradient-tech-03.png differ diff --git a/templates/step0/previews/gradient-tech-04.png b/templates/step0/previews/gradient-tech-04.png new file mode 100644 index 000000000..4c9a2e3b3 Binary files /dev/null and b/templates/step0/previews/gradient-tech-04.png differ diff --git a/templates/step0/previews/gradient-tech-05.png b/templates/step0/previews/gradient-tech-05.png new file mode 100644 index 000000000..2bcb1f87b Binary files /dev/null and b/templates/step0/previews/gradient-tech-05.png differ diff --git a/templates/step0/previews/gradient-tech-06.png b/templates/step0/previews/gradient-tech-06.png new file mode 100644 index 000000000..575cf94c4 Binary files /dev/null and b/templates/step0/previews/gradient-tech-06.png differ diff --git a/templates/step0/previews/gradient-tech-overview.png b/templates/step0/previews/gradient-tech-overview.png new file mode 100644 index 000000000..91808dd8a Binary files /dev/null and b/templates/step0/previews/gradient-tech-overview.png differ diff --git a/templates/step0/previews/knowledge-card-square.png b/templates/step0/previews/knowledge-card-square.png new file mode 100644 index 000000000..fdb27222d Binary files /dev/null and b/templates/step0/previews/knowledge-card-square.png differ diff --git a/templates/step0/previews/knowledge-card-vertical.png b/templates/step0/previews/knowledge-card-vertical.png new file mode 100644 index 000000000..f29203cc0 Binary files /dev/null and b/templates/step0/previews/knowledge-card-vertical.png differ diff --git a/templates/step0/previews/lecture-deck-light-01.png b/templates/step0/previews/lecture-deck-light-01.png new file mode 100644 index 000000000..133847534 Binary files /dev/null and b/templates/step0/previews/lecture-deck-light-01.png differ diff --git a/templates/step0/previews/lecture-deck-light-02.png b/templates/step0/previews/lecture-deck-light-02.png new file mode 100644 index 000000000..2516db1e3 Binary files /dev/null and b/templates/step0/previews/lecture-deck-light-02.png differ diff --git a/templates/step0/previews/lecture-deck-light-03.png b/templates/step0/previews/lecture-deck-light-03.png new file mode 100644 index 000000000..0bb7fae91 Binary files /dev/null and b/templates/step0/previews/lecture-deck-light-03.png differ diff --git a/templates/step0/previews/lecture-deck-light-04.png b/templates/step0/previews/lecture-deck-light-04.png new file mode 100644 index 000000000..7f6119948 Binary files /dev/null and b/templates/step0/previews/lecture-deck-light-04.png differ diff --git a/templates/step0/previews/lecture-deck-light-05.png b/templates/step0/previews/lecture-deck-light-05.png new file mode 100644 index 000000000..8d5c0049c Binary files /dev/null and b/templates/step0/previews/lecture-deck-light-05.png differ diff --git a/templates/step0/previews/lecture-deck-light-06.png b/templates/step0/previews/lecture-deck-light-06.png new file mode 100644 index 000000000..fd38f9a39 Binary files /dev/null and b/templates/step0/previews/lecture-deck-light-06.png differ diff --git a/templates/step0/previews/lecture-deck-light-overview.png b/templates/step0/previews/lecture-deck-light-overview.png new file mode 100644 index 000000000..6dbb6d256 Binary files /dev/null and b/templates/step0/previews/lecture-deck-light-overview.png differ diff --git a/templates/step0/previews/minimal-keynote-01.png b/templates/step0/previews/minimal-keynote-01.png new file mode 100644 index 000000000..8be581314 Binary files /dev/null and b/templates/step0/previews/minimal-keynote-01.png differ diff --git a/templates/step0/previews/minimal-keynote-02.png b/templates/step0/previews/minimal-keynote-02.png new file mode 100644 index 000000000..ed57b5adb Binary files /dev/null and b/templates/step0/previews/minimal-keynote-02.png differ diff --git a/templates/step0/previews/minimal-keynote-03.png b/templates/step0/previews/minimal-keynote-03.png new file mode 100644 index 000000000..961a0c472 Binary files /dev/null and b/templates/step0/previews/minimal-keynote-03.png differ diff --git a/templates/step0/previews/minimal-keynote-04.png b/templates/step0/previews/minimal-keynote-04.png new file mode 100644 index 000000000..1e811e2b0 Binary files /dev/null and b/templates/step0/previews/minimal-keynote-04.png differ diff --git a/templates/step0/previews/minimal-keynote-05.png b/templates/step0/previews/minimal-keynote-05.png new file mode 100644 index 000000000..2dc00d070 Binary files /dev/null and b/templates/step0/previews/minimal-keynote-05.png differ diff --git a/templates/step0/previews/minimal-keynote-06.png b/templates/step0/previews/minimal-keynote-06.png new file mode 100644 index 000000000..1f0ad1691 Binary files /dev/null and b/templates/step0/previews/minimal-keynote-06.png differ diff --git a/templates/step0/previews/minimal-keynote-07.png b/templates/step0/previews/minimal-keynote-07.png new file mode 100644 index 000000000..debf36222 Binary files /dev/null and b/templates/step0/previews/minimal-keynote-07.png differ diff --git a/templates/step0/previews/minimal-keynote-08.png b/templates/step0/previews/minimal-keynote-08.png new file mode 100644 index 000000000..2001e951a Binary files /dev/null and b/templates/step0/previews/minimal-keynote-08.png differ diff --git a/templates/step0/previews/minimal-keynote-overview.png b/templates/step0/previews/minimal-keynote-overview.png new file mode 100644 index 000000000..2b726cb2d Binary files /dev/null and b/templates/step0/previews/minimal-keynote-overview.png differ diff --git a/templates/step0/previews/pitch-deck-dark-01.png b/templates/step0/previews/pitch-deck-dark-01.png new file mode 100644 index 000000000..93501be8a Binary files /dev/null and b/templates/step0/previews/pitch-deck-dark-01.png differ diff --git a/templates/step0/previews/pitch-deck-dark-02.png b/templates/step0/previews/pitch-deck-dark-02.png new file mode 100644 index 000000000..6c9ebf9d8 Binary files /dev/null and b/templates/step0/previews/pitch-deck-dark-02.png differ diff --git a/templates/step0/previews/pitch-deck-dark-03.png b/templates/step0/previews/pitch-deck-dark-03.png new file mode 100644 index 000000000..94756ef32 Binary files /dev/null and b/templates/step0/previews/pitch-deck-dark-03.png differ diff --git a/templates/step0/previews/pitch-deck-dark-04.png b/templates/step0/previews/pitch-deck-dark-04.png new file mode 100644 index 000000000..702377e81 Binary files /dev/null and b/templates/step0/previews/pitch-deck-dark-04.png differ diff --git a/templates/step0/previews/pitch-deck-dark-05.png b/templates/step0/previews/pitch-deck-dark-05.png new file mode 100644 index 000000000..6d9a305cf Binary files /dev/null and b/templates/step0/previews/pitch-deck-dark-05.png differ diff --git a/templates/step0/previews/pitch-deck-dark-06.png b/templates/step0/previews/pitch-deck-dark-06.png new file mode 100644 index 000000000..de82ef831 Binary files /dev/null and b/templates/step0/previews/pitch-deck-dark-06.png differ diff --git a/templates/step0/previews/pitch-deck-dark-overview.png b/templates/step0/previews/pitch-deck-dark-overview.png new file mode 100644 index 000000000..05187921c Binary files /dev/null and b/templates/step0/previews/pitch-deck-dark-overview.png differ diff --git a/templates/step0/previews/slide-deck-01.png b/templates/step0/previews/slide-deck-01.png index 84bdb7da8..5db0da054 100644 Binary files a/templates/step0/previews/slide-deck-01.png and b/templates/step0/previews/slide-deck-01.png differ diff --git a/templates/step0/previews/slide-deck-02.png b/templates/step0/previews/slide-deck-02.png index 27eda1761..51a0d87ff 100644 Binary files a/templates/step0/previews/slide-deck-02.png and b/templates/step0/previews/slide-deck-02.png differ diff --git a/templates/step0/previews/slide-deck-03.png b/templates/step0/previews/slide-deck-03.png index 47c12b6bb..2d0b22ca5 100644 Binary files a/templates/step0/previews/slide-deck-03.png and b/templates/step0/previews/slide-deck-03.png differ diff --git a/templates/step0/previews/slide-deck-04.png b/templates/step0/previews/slide-deck-04.png index bd6b82260..8a641c244 100644 Binary files a/templates/step0/previews/slide-deck-04.png and b/templates/step0/previews/slide-deck-04.png differ diff --git a/templates/step0/previews/slide-deck-05.png b/templates/step0/previews/slide-deck-05.png index 52a59fae3..a50c22940 100644 Binary files a/templates/step0/previews/slide-deck-05.png and b/templates/step0/previews/slide-deck-05.png differ diff --git a/templates/step0/previews/slide-deck-06.png b/templates/step0/previews/slide-deck-06.png index 0c3fc1ee6..991961be9 100644 Binary files a/templates/step0/previews/slide-deck-06.png and b/templates/step0/previews/slide-deck-06.png differ diff --git a/templates/step0/previews/slide-deck-overview.png b/templates/step0/previews/slide-deck-overview.png new file mode 100644 index 000000000..92ef54f92 Binary files /dev/null and b/templates/step0/previews/slide-deck-overview.png differ