1127 lines
66 KiB
JavaScript
1127 lines
66 KiB
JavaScript
import { Buffer } from 'node:buffer';
|
||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
||
import http from 'node:http';
|
||
import https from 'node:https';
|
||
import path from 'node:path';
|
||
|
||
const repoRoot = process.cwd();
|
||
const outputDir = path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-concepts',
|
||
);
|
||
const defaultTimeoutMs = 1000000;
|
||
|
||
const dimensionalConcepts = [
|
||
{
|
||
id: 'taonier-clay-spark',
|
||
title: '灵感陶团',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字 Logo 图标。产品是精品 AI UGC 创作与轻休闲小游戏平台,核心理念是把脑洞、梗和小游戏像陶泥一样捏出来。图标主体是一团被轻轻捏塑的温润陶泥,内部自然形成一枚发光灵感火花和少量 AI 节点点线,整体高级、亲切、年轻、有传播感。使用暖陶土色、奶白、薄荷绿、深墨色少量点缀,居中构图,适合作为 App icon 和品牌主标。禁止文字、字母、汉字、水印、按钮、界面元素、复杂背景、儿童黏土课风格。',
|
||
},
|
||
{
|
||
id: 'taonier-play-mold',
|
||
title: '开玩模具',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字 Logo 图标。产品强调 AI 创作、UGC、自制小游戏、玩梗传播和轻度休闲。图标主体是一枚柔软陶泥捏成的圆角播放符号,播放三角像被手指压出的模具凹槽,周围有两三颗精品感小星点和像素级小方块,表达“捏个脑洞,马上开玩”。风格是现代品牌标志,柔软但不幼稚,干净、可缩小识别。禁止文字、字母、汉字、水印、真实陶艺工具、UI 按钮、教程感。',
|
||
},
|
||
{
|
||
id: 'taonier-meme-bubble',
|
||
title: '造梗气泡',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字 Logo 图标。产品是 AI UGC 创作社区,主打精品内容、梗传播、裂变分享、休闲小游戏。图标用一团软陶泥变形成聊天气泡和小表情的组合,气泡边缘像被揉捏过,中心有抽象笑脸和创意火花,但不要做儿童玩具感。品牌气质年轻、松弛、聪明、有社交传播力。配色使用陶土橙、奶白、清爽蓝绿和少量深色轮廓。禁止文字、字母、汉字、水印、复杂场景、表情包文字。',
|
||
},
|
||
{
|
||
id: 'taonier-creation-loop',
|
||
title: '共创回路',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字 Logo 图标。产品理念是 AI 与用户共同把灵感塑形成可玩的 UGC 作品。图标主体由两条柔软陶泥带构成循环造物轨迹,形成一个抽象无限符号和手工捏塑旋涡,中间嵌入一颗小型游戏棋子或星点,表达共创、迭代、传播和精品打磨。风格简洁高级、几何清楚、移动端小尺寸仍可识别。禁止文字、字母、汉字、水印、复杂阴影、科技冷硬金属感。',
|
||
},
|
||
{
|
||
id: 'taonier-premium-seal',
|
||
title: '精品泥印',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字 Logo 图标。产品主打精品 AI 创作、UGC 作品和轻小游戏发布。图标是一个被压印过的软陶徽章,外形像圆润印章但更现代,中间有抽象火花、小游戏方块和一处捏痕,表达“精品内容由脑洞塑形”。整体要有品牌信任感和高级手作质感,不要像儿童陶艺班。使用暖陶土、奶油白、莓红或湖蓝少量点缀,清晰居中。禁止文字、字母、汉字、水印、传统篆刻字、真实照片。',
|
||
},
|
||
];
|
||
|
||
const flatConcepts = [
|
||
{
|
||
id: 'taonier-flat-play-clay',
|
||
title: '扁平开捏',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品是 AI UGC 创作与轻休闲小游戏平台,主张“把脑洞捏成小游戏”。图标只使用一个柔软圆润的陶泥形主轮廓,内部用极简负形播放三角表达“马上开玩”,整体像现代 App icon 的核心符号。风格要求:flat vector logo, clean geometric, friendly, mainstream, memorable, high contrast, scalable, minimal shapes, solid colors, subtle 2D shadow only。配色使用暖陶土橙、奶油白、清爽薄荷绿或深墨色,最多 3 个主色。禁止:3D、立体、拟物、厚重阴影、渐变高光、照片质感、复杂纹理、中文字、英文字母、水印、UI 按钮、复杂背景、吉祥物。',
|
||
},
|
||
{
|
||
id: 'taonier-flat-spark-clay',
|
||
title: '灵感泥星',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品强调 AI 创作、UGC、造梗、精品轻小游戏。图形主体是一枚圆润陶泥团,中心用简洁四角星或火花负形表达灵感和 AI 生成,外轮廓要一眼像“可塑形的软泥”,但必须保持现代、主流、亲和、有记忆点。风格要求:flat vector brand mark, simple silhouette, app icon ready, no realism, no texture, no 3D, crisp edges, 2D friendly illustration。最多 3 色,暖陶土 + 奶油白 + 少量蓝绿。禁止文字、字母、水印、复杂小节点、儿童手工课风格。',
|
||
},
|
||
{
|
||
id: 'taonier-flat-meme-smile',
|
||
title: '造梗笑泥',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品主打 UGC、玩梗传播、裂变分享和轻休闲小游戏。图形是一团被捏成圆润聊天气泡的陶泥,内部只保留极简笑脸或一颗小星点,表达“造梗”和“分享快乐”。整体要像主流社交娱乐 App 的 Logo,亲和、轻松、容易记住,小尺寸清楚。风格要求:flat vector logo, simple, bold, friendly, clean, no gradients, no 3D, no mascot complexity。配色不超过 3 色。禁止中文字、英文字母、水印、表情包文字、复杂装饰、立体高光。',
|
||
},
|
||
{
|
||
id: 'taonier-flat-loop-mold',
|
||
title: '共创泥环',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品理念是用户与 AI 共同把灵感塑形成可玩的 UGC 作品。图形用一条柔软陶泥带形成简洁闭环或抽象无限符号,中间留出小星点负形,表达共创、迭代、传播和精品打磨。视觉要主流、简洁、亲和,不要科技冷硬。风格要求:flat vector symbol, clean loop mark, minimal, memorable, scalable, solid colors, crisp silhouette, suitable for app icon。禁止 3D、拟物、厚阴影、复杂渐变、文字、字母、水印。',
|
||
},
|
||
{
|
||
id: 'taonier-flat-seal-blocks',
|
||
title: '精品泥印',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品强调精品 AI 作品、UGC 创作和小游戏发布。图形是一枚现代软陶印记,外形为圆角徽章或圆润印章,内部用 2 到 3 个简洁小方块和一颗星点表达“作品”“小游戏”“精品内容”。整体应像可长期使用的品牌主标,主流、干净、亲和、有辨识度。风格要求:flat vector logo, bold simple shapes, app icon ready, minimal color palette, no realism, no texture。禁止文字、字母、水印、传统篆刻、3D、复杂阴影、拟物陶艺。',
|
||
},
|
||
];
|
||
|
||
const v3Concepts = [
|
||
{
|
||
id: 'taonier-v3-finger-spark',
|
||
title: '灵感捏痕',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。不要使用播放三角、聊天气泡、笑脸、循环无限符号、褐色陶土主色、碎片小元素。产品是 AI UGC 创作与轻休闲小游戏平台,核心是“把脑洞捏成可玩的作品”。图形主体是一个醒目的圆润软形,内部只有一枚极简指纹捏痕与小火花负形,表达“被手指一捏,灵感成型”。风格:主流 App icon、flat vector、bold simple silhouette、friendly、memorable、high contrast、可缩小识别。配色:珊瑚橙或莓红作为主色,奶油白负形,少量青绿色投影或边缘点缀,最多 3 色。画面居中,留白干净。禁止文字、字母、水印、3D、拟物、厚阴影、渐变高光、照片质感、复杂纹理、表情包感、UI 按钮。',
|
||
},
|
||
{
|
||
id: 'taonier-v3-seed-pop',
|
||
title: '脑洞种子',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。不要使用播放三角、聊天气泡、笑脸、无限循环、传统印章、褐色主色或多碎元素。产品主打 AI 创作、UGC、梗传播、精品轻小游戏。图标主体是一颗圆润明亮的“脑洞种子”:像软泥被捏成的一颗种子/小芽,顶部有一个简洁星点缺口,表达灵感生长、内容生成、人人创作。风格:flat vector logo, simple, mainstream, warm, lively, app icon ready, strong outline, minimal shapes。配色使用高饱和青绿、珊瑚粉、奶油白、深墨色中的 2-3 色,不要大面积褐色。禁止文字、字母、水印、3D、拟物、照片、复杂渐变、表情、儿童黏土课风格。',
|
||
},
|
||
{
|
||
id: 'taonier-v3-magic-dot',
|
||
title: '一捏成型',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。避开播放按钮、聊天气泡、笑脸、循环符号、褐色陶土和堆叠小图标。产品理念是用户轻轻一捏,AI 把脑洞生成小游戏和 UGC 作品。图形由两个圆润手捏触点和中间一个闪光成型点组成,像“捏合灵感”的瞬间,但不要画真实手指。整体应非常简洁,有强记忆点,像主流创作娱乐 App 的标志。风格:flat vector, iconic, minimal, friendly, bold shape, clear at 32px。配色:亮紫红或珊瑚红主色,奶油白负形,青绿色小面积辅助。禁止文字、字母、水印、3D、厚阴影、渐变高光、复杂纹理。',
|
||
},
|
||
{
|
||
id: 'taonier-v3-work-gem',
|
||
title: '作品胶囊',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。不要使用播放三角、聊天气泡、笑脸、循环无限符号、褐色主色、多枚小卡片或碎图标。产品强调精品 AI UGC 作品和轻小游戏创作。图形主体是一枚被捏成圆角宝石/胶囊的抽象作品符号,内部只有一条柔软弧线切面和一个小星点,表达“脑洞被打磨成精品”。风格:flat vector logo, premium but friendly, simple, memorable, app icon, solid colors, no texture。配色:湖蓝或青绿主色,珊瑚橙点缀,奶白负形,深墨小轮廓可选。禁止文字、字母、水印、3D、复杂渐变、照片质感、游戏手柄、图片卡片、用户头像。',
|
||
},
|
||
{
|
||
id: 'taonier-v3-soft-t',
|
||
title: '软体 T 形',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。尝试做一个抽象但亲和的品牌首字母符号,灵感来自 Taonier / 陶泥儿 的 T 和“被捏塑的软泥”。不要出现真实字母 T 的硬直排版,而是用一笔圆润软形构成可记忆的图腾。必须避开播放三角、聊天气泡、笑脸、循环符号、褐色陶土主色和碎元素。风格:flat vector brand mark, modern, friendly, bold, iconic, simple silhouette, app icon ready。配色:明亮珊瑚红、奶油白、薄荷青或深墨,最多 3 色。禁止文字、英文字母直出、汉字、水印、3D、拟物、厚阴影、复杂纹理。',
|
||
},
|
||
];
|
||
|
||
const magicDotConcepts = [
|
||
{
|
||
id: 'taonier-magic-dot-orbit',
|
||
title: '捏合星核',
|
||
prompt:
|
||
'围绕“陶泥儿”V3 方案“一捏成型”做 Logo 延展。设计一个无文字扁平矢量主标:两个圆润软泥触点从左右轻轻合拢,中心不是碰撞爆炸,而是一颗稳定的星核/作品核,外形要形成完整、可记忆的品牌符号。必须避免播放三角、聊天气泡、笑脸、循环无限符号、褐色陶土、真实手指、括号感、爆炸特效和碎元素。风格:flat vector logo, iconic, minimal, friendly, mainstream app icon, strong silhouette, clear at 32px。配色:珊瑚红或莓红主形,奶油白负形,青绿色只做中心小面积,最多 3 色。无文字、无字母、无水印、无 3D、无厚阴影、无拟物。',
|
||
},
|
||
{
|
||
id: 'taonier-magic-dot-seal',
|
||
title: '成型印记',
|
||
prompt:
|
||
'围绕“陶泥儿”V3 方案“一捏成型”做 Logo 延展。设计一个无文字扁平矢量主标:图形像一枚被两侧轻轻按压成型的软形印记,中心留出一个简洁星点或小圆孔,表达 AI 把脑洞塑形成作品。整体要比原本左右括号更完整,外轮廓形成一个独特图腾。禁止播放按钮、聊天气泡、笑脸、循环符号、褐色陶土主色、多小图标、真实手、爆炸火花。风格:flat vector, bold simple shape, friendly premium, memorable, app icon ready, solid colors。配色:亮珊瑚、奶油白、薄荷青或深墨,最多 3 色。',
|
||
},
|
||
{
|
||
id: 'taonier-magic-dot-squish',
|
||
title: '软泥合拍',
|
||
prompt:
|
||
'围绕“陶泥儿”V3 方案“一捏成型”做 Logo 延展。设计一个无文字扁平矢量 Logo:两个软泥形不是分散的括号,而是上下错位地挤压出中心灵感点,像“啪嗒一捏,作品成型”的瞬间。图形需要亲和、轻松、年轻,但不做表情包。必须保持元素极少,只有两块主形和一个中心成型点。禁止播放三角、聊天气泡、笑脸、无限循环、褐色主色、复杂渐变、拟物质感、真实手指、文字、字母。风格:flat vector brand mark, simple, memorable, high contrast, scalable。配色:莓红、奶白、青绿或明黄点缀。',
|
||
},
|
||
{
|
||
id: 'taonier-magic-dot-mold',
|
||
title: '灵感模口',
|
||
prompt:
|
||
'围绕“陶泥儿”V3 方案“一捏成型”做 Logo 延展。设计一个无文字扁平矢量主标:外形像一个被捏开的柔软模口,中心浮出一颗极简星点,表达从软泥模口里生成作品。它应该是一眼可记住的抽象符号,不像聊天框、不像播放键、不像括号。风格:flat vector logo, modern, friendly, clean, bold, minimal, app icon。配色使用高识别珊瑚红或玫粉主色,奶油白负形,少量青绿点缀。禁止褐色陶土、真实陶艺、3D、高光、厚阴影、复杂小碎片、文字、水印。',
|
||
},
|
||
{
|
||
id: 'taonier-magic-dot-bloom',
|
||
title: '捏开灵感',
|
||
prompt:
|
||
'围绕“陶泥儿”V3 方案“一捏成型”做 Logo 延展。设计一个无文字扁平矢量 Logo:用两片圆润软形夹出中央一颗灵感点,整体像一个正在打开的创意容器,但不要像花朵、聊天气泡或笑脸。图形要完整、主流、亲和、醒目,适合 App icon 和品牌主标。禁止播放三角、聊天气泡、笑脸、循环符号、褐色陶土、碎元素、真实手、复杂花瓣。风格:flat vector, minimal brand mark, strong silhouette, warm, youthful, memorable。配色:珊瑚红、奶油白、青绿,最多 3 色。',
|
||
},
|
||
];
|
||
|
||
const handsConcepts = [
|
||
{
|
||
id: 'taonier-hands-cradle-spark',
|
||
title: '托住灵感',
|
||
prompt:
|
||
'围绕“陶泥儿”Logo 方向 03 的“上下两只手托住灵感”的感觉继续打磨。设计一个无文字扁平矢量主标:上下两片圆润软掌状形体像手但不要画真实手指,轻轻托住中央一颗简洁灵感星核,表达用户与 AI 一起把脑洞捏成作品。整体要完整、主流、亲和、醒目,适合 App icon。避免播放三角、聊天气泡、笑脸、眼睛、花朵、循环符号、褐色陶土、多碎元素和真实手掌插画。风格:flat vector logo, bold simple silhouette, friendly, memorable, premium but warm, clear at 32px。配色:上方珊瑚红、下方青绿色、中央奶油白或金色小星,最多 3 色。无文字、无字母、无水印、无 3D、无厚阴影。',
|
||
},
|
||
{
|
||
id: 'taonier-hands-pinched-gem',
|
||
title: '合捏成珠',
|
||
prompt:
|
||
'围绕“陶泥儿”Logo 方向 03 的“上下两只手”感觉做延展。设计一个无文字扁平矢量主标:上下一对抽象软手 / 软泥掌从两侧微微合捏,中间形成一颗小圆珠或作品核。图形要像品牌符号,不像手势教学图;保留托举与成型的温柔感。禁止播放三角、聊天气泡、笑脸、眼睛、花朵、褐色主色、真实手指、复杂掌纹、碎小图标。风格:flat vector, minimal, mainstream app logo, high contrast, iconic, friendly。配色:莓红、奶白、薄荷青、少量深墨,最多 3 色。',
|
||
},
|
||
{
|
||
id: 'taonier-hands-cradle-v2',
|
||
title: '托星软掌',
|
||
prompt:
|
||
'为“陶泥儿”设计无文字扁平矢量 Logo。图形是上下两片圆润软托,托住中央一颗小星,像把灵感轻轻捏成作品。不要画具体手指,只保留抽象软掌感觉。适合 App icon,简单、亲和、醒目、小尺寸清楚。配色:珊瑚红、薄荷青、奶油白,最多三色。不要播放三角、聊天气泡、笑脸、眼睛、花朵、褐色、文字、字母、3D、碎元素。',
|
||
},
|
||
{
|
||
id: 'taonier-hands-soft-bowl',
|
||
title: '创意托碗',
|
||
prompt:
|
||
'围绕“陶泥儿”Logo 方向 03 的上下手感做主标延展。设计一个无文字扁平矢量 Logo:下方是一片像手掌也像软泥托碗的圆润形体,上方是一片较小软形轻轻压合,中间浮出星点,表达“轻托脑洞、AI 捏成作品”。整体要简洁、有包容感、年轻亲和。避免像眼睛、嘴巴、聊天气泡、播放器、花朵、真实手掌、儿童黏土课。风格:flat vector logo, bold simple shape, app icon ready, clean, memorable。配色:青绿主托、珊瑚红上形、奶白中心,最多 3 色。',
|
||
},
|
||
{
|
||
id: 'taonier-hands-formed-seal',
|
||
title: '双掌泥印',
|
||
prompt:
|
||
'围绕“陶泥儿”Logo 方向 03 的上下两只手感觉做更完整的图腾。设计一个无文字扁平矢量主标:两片抽象软掌上下扣合,外轮廓形成一个圆润印记,中心保留一个星形负空间,像“被双手捏出的创意印记”。要有主流品牌感,不要像宗教手势、医疗关怀、儿童手工。禁止播放三角、聊天气泡、笑脸、眼睛、花朵、循环符号、褐色陶土、真实手指、复杂纹理。风格:flat vector, iconic, simple, friendly premium, solid colors, scalable。配色:珊瑚红、奶油白、青绿或深墨,最多 3 色。',
|
||
},
|
||
{
|
||
id: 'taonier-hands-pop-capsule',
|
||
title: '掌心开捏',
|
||
prompt:
|
||
'围绕“陶泥儿”Logo 方向 03 的“上下两只手托住灵感”感觉做更活泼版本。设计一个无文字扁平矢量 Logo:上下两片软掌像打开的胶囊,中央小星点从掌心弹出,表达“脑洞被捏出来”。图形需要有传播感、亲和力、记忆点,但不要像表情包或聊天软件。禁止播放三角、聊天气泡、笑脸、眼睛、花朵、褐色陶土、真实手指、碎元素。风格:flat vector brand mark, simple, bold, youthful, app icon, high contrast。配色:亮珊瑚红、薄荷青、奶白,最多 3 色。',
|
||
},
|
||
];
|
||
|
||
const broadConcepts = [
|
||
{
|
||
id: 'taonier-broad-clay-dot-crown',
|
||
title: '泥点皇冠',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品是 AI UGC 创作与轻休闲互动内容平台,用户用“泥点”驱动 AI,把一句脑洞、一张图或一个梗捏成小游戏和可分享作品。本方向把“泥点”做成核心品牌符号:3 到 5 个圆润泥点自然聚合,形成一个像皇冠、火苗、作品星核之间的抽象主轮廓,表达很多灵感汇聚成精品作品。整体必须像成熟 App 主标,亲和、明亮、可注册感强,小尺寸清楚。避免播放三角、聊天气泡、笑脸、真实陶艺、褐色陶土主色、人物、手、复杂碎点。风格:flat vector logo, bold simple silhouette, modern consumer app, warm, memorable, scalable, solid colors。配色:珊瑚红、奶油白、青绿色、少量金色,最多 4 色。无文字、无字母、无水印、无 3D、无厚阴影、无玻璃高光。',
|
||
},
|
||
{
|
||
id: 'taonier-broad-soft-portal',
|
||
title: '软泥入口',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品把 AI 创作、UGC、小游戏、视觉小说、拼图和轻互动作品放在同一平台内,核心感觉是“打开一个软软的创作入口,进去就能造作品”。图形主体是一枚被捏开的柔软入口/门洞,外轮廓像软泥被拉开,中心留出干净负形作品核或小星点。图形要完整、抽象、主流,不像播放器、不像聊天框、不像眼睛。风格:flat vector brand mark, simple, iconic, friendly premium, strong silhouette, app icon ready。配色使用亮珊瑚、薄荷青、奶油白、深墨中的 3 色。禁止中文字、英文字母、真实门、真实陶土、3D、复杂纹理、碎小装饰、UI 按钮。',
|
||
},
|
||
{
|
||
id: 'taonier-broad-work-embryo',
|
||
title: '作品胚芽',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。品牌隐喻不是传统陶艺,而是“灵感胚胎被 AI 塑形成可玩的作品”。图形主体是一颗圆润的作品胚芽:外形像软泥种子、游戏棋子和小宇宙的结合,内部只有一条柔软切面和一个小星点负形。整体高级、温柔、年轻,适合平台主 Logo 和 App icon。避免植物叶子过强、教育儿童感、播放按钮、聊天气泡、笑脸、循环箭头、褐色主色。风格:flat vector, premium friendly app logo, minimal, bold, clear at 32px, solid colors。配色:湖蓝或青绿主色,珊瑚橙点缀,奶白负形,最多 3 色。无文字、无字母、无水印、无 3D、无照片质感。',
|
||
},
|
||
{
|
||
id: 'taonier-broad-game-mold',
|
||
title: '游戏模芯',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品不是工具后台,而是能把脑洞生成拼图、抓大鹅、视觉小说、文字游戏等互动作品的平台。本方向用“游戏模芯”做符号:一个圆润软泥主形中嵌入极简十字方向键或小方块负形,但不要画传统手柄,不要出现播放三角。图形要表达可玩、轻休闲、低门槛创作,同时保持品牌主标感。风格:flat vector logo, simple geometric, friendly, playful but mature, app icon, high contrast。配色:珊瑚红、青绿、奶油白、深墨,最多 4 色。禁止文字、字母、水印、3D、复杂按钮、真实手柄、聊天气泡、笑脸、儿童玩具感。',
|
||
},
|
||
{
|
||
id: 'taonier-broad-tao-negative',
|
||
title: '陶字负形',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。尝试从“陶”的结构提炼抽象负形,但不要直接写汉字,也不要让模型生成可读文字。图形主体是一枚圆润软泥徽标,内部用两到三块负形构成类似陶器开口、耳部、土块和作品核的抽象关系,让熟悉中文的人隐约感到“陶”,但第一眼仍是现代 App 标志。风格:flat vector brand symbol, abstract Chinese-inspired, clean, iconic, friendly premium, scalable。配色:深墨或莓红主形,奶油白负形,青绿小点缀。禁止真实汉字、书法、篆刻、传统印章、褐色陶艺、播放按钮、聊天气泡、人物、3D、水印。',
|
||
},
|
||
{
|
||
id: 'taonier-broad-soft-totem',
|
||
title: '软体图腾',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。基于 Taonier / 陶泥儿 的品牌声母感觉做一个抽象软体图腾,但不要直接画英文字母 T,也不要生成任何文字。图形由一笔连续的圆润软泥带形成稳定的竖向图腾,顶部像被轻捏出的小角,中心有一颗作品星核负形,表达“捏、造、发布”。整体要比普通字母标更独特,适合 App icon、favicon 和平台顶栏。风格:flat vector logo, bold, simple, modern, friendly, memorable, solid colors。配色:珊瑚红主形、奶油白负形、薄荷青小面积辅助。禁止文字、字母直出、播放三角、聊天气泡、笑脸、无限循环、褐色陶土、3D、复杂纹理。',
|
||
},
|
||
{
|
||
id: 'taonier-broad-creation-spark',
|
||
title: '开捏火花',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。核心动作为“开捏”:用户输入灵感,AI 立刻生成可玩的作品。图形不要画真实手,用两块极简软形挤压出中心火花,火花不是爆炸特效,而是一个稳定的四角作品星核。外轮廓要比上一轮左右括号更完整,像一个独立品牌图腾。风格:flat vector logo, iconic, minimal, high contrast, friendly, youthful, app icon ready。配色:莓红或珊瑚红主形,奶油白负形,青绿中心点缀,最多 3 色。禁止文字、字母、水印、播放三角、聊天气泡、笑脸、眼睛、真实手指、碎粒、3D、厚阴影。',
|
||
},
|
||
{
|
||
id: 'taonier-broad-content-orbit',
|
||
title: '作品星轨',
|
||
prompt:
|
||
'为中文产品“陶泥儿”设计一个无文字扁平矢量 Logo 图标。产品承载多种互动内容:RPG、拼图、抓大鹅、视觉小说、文字游戏、儿童寓教于乐。图形用一个软泥圆核和两条极简短弧形成“作品星轨”,表达一个灵感生成多个作品形态;但整体必须是一个凝聚的主标,不是天文图标。风格:flat vector brand mark, simple, premium friendly, clean geometry, app icon, scalable。配色:青绿主核、珊瑚红弧线、奶油白负形、深墨小轮廓可选。禁止文字、字母、水印、真实星球、复杂轨道、科技冷硬、播放键、聊天气泡、循环箭头、3D。',
|
||
},
|
||
];
|
||
|
||
const freshConcepts = [
|
||
{
|
||
id: 'taonier-fresh-wheel-imprint',
|
||
title: '陶轮印记',
|
||
prompt:
|
||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:俯视一个正在旋转的创作轮盘,圆环被轻轻压出一处缺口,像把灵感旋成作品。成熟消费级 App 主标,几何、干净、有速度感。配色:钴蓝、奶白、珊瑚红、少量深墨。不要软手、星核、聊天气泡、播放键、笑脸、真实陶艺、褐色、文字、字母、3D。',
|
||
},
|
||
{
|
||
id: 'taonier-fresh-mold-window',
|
||
title: '模具窗格',
|
||
prompt:
|
||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一个圆角模具窗口,内部是 2x2 的不规则负形窗格,像多种小游戏和互动作品从同一个模具里生成。主流、简洁、品牌感强、小尺寸清楚。配色:深墨主形、奶油白负形、亮青绿和珊瑚小点缀。不要软手、星星、播放键、聊天气泡、脸、真实陶土、文字、字母、3D。',
|
||
},
|
||
{
|
||
id: 'taonier-fresh-dot-dice',
|
||
title: '泥点骰面',
|
||
prompt:
|
||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一枚圆润方形骰面或游戏牌面,5 个泥点孔组成独特节奏,表达泥点、玩法和随机脑洞。不要画立体骰子,只要正面抽象符号。潮流、轻游戏、可注册。配色:象牙白底、黑色主形、荧光青、珊瑚红。不要播放键、聊天气泡、笑脸、星星、软手、褐色、文字、字母、3D。',
|
||
},
|
||
{
|
||
id: 'taonier-fresh-pinwheel',
|
||
title: '灵感风车',
|
||
prompt:
|
||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:抽象纸风车,由四片圆润色块围成旋转中心,表达简单、轻松、人人能造内容。它要像品牌主标,不像儿童玩具。配色:莓红、天蓝、薄荷、奶白、深墨。不要软泥团、手、星核、播放键、聊天气泡、笑脸、花朵、文字、字母、3D、复杂渐变。',
|
||
},
|
||
{
|
||
id: 'taonier-fresh-pocket-world',
|
||
title: '口袋世界',
|
||
prompt:
|
||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一个抽象口袋形徽标,口袋里露出一小块世界切片或舞台切片,表示把脑洞装进口袋随手开玩。现代、亲和、平台感强。配色:青绿色主形、奶白负形、珊瑚红小块、深墨轮廓。不要软手、星核、播放键、聊天气泡、笑脸、地图图钉、真实口袋、文字、字母、3D。',
|
||
},
|
||
{
|
||
id: 'taonier-fresh-builder-blocks',
|
||
title: '创作积木',
|
||
prompt:
|
||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:三块圆角积木以不对称方式咬合,形成一个稳定主轮廓,表达 UGC 搭建、模板生成和小游戏创作。不要儿童玩具感,要成熟、潮流、清晰。配色:黑色或深紫主轮廓,珊瑚、青绿、奶白填色。不要软手、星星、播放键、聊天气泡、笑脸、褐色、文字、字母、3D。',
|
||
},
|
||
{
|
||
id: 'taonier-fresh-stage-window',
|
||
title: '叙事舞台窗',
|
||
prompt:
|
||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一个极简舞台窗或小剧场窗口,左右两片抽象幕布形成负形中心,代表视觉小说、RPG 和互动叙事。它要是 App icon 主标,不是插画。配色:深墨、珊瑚红、奶油白、少量湖蓝。不要播放键、聊天气泡、笑脸、软手、星核、真实舞台、文字、字母、3D。',
|
||
},
|
||
{
|
||
id: 'taonier-fresh-ribbon-knot',
|
||
title: '灵感绳结',
|
||
prompt:
|
||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一条圆润彩色泥条打成简洁绳结,像把多个创意线索系成一个作品。形状必须凝聚成单个主标,不能散。配色:珊瑚、钴蓝、薄荷、奶白,边缘干净。不要无限符号、软手、星核、播放键、聊天气泡、笑脸、褐色陶土、文字、字母、3D。',
|
||
},
|
||
{
|
||
id: 'taonier-fresh-folded-sticker',
|
||
title: '贴纸折角',
|
||
prompt:
|
||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一张圆角贴纸或作品卡片,右上角轻轻折起,负形像一个小入口。表达 UGC、作品发布、随手开玩。成熟、潮流、极简。配色:奶白、黑、珊瑚、青绿。不要播放键、聊天气泡、笑脸、手、星星、褐色、文字、字母、3D。',
|
||
},
|
||
{
|
||
id: 'taonier-fresh-punch-hole',
|
||
title: '印模孔洞',
|
||
prompt:
|
||
'为“陶泥儿”设计无文字扁平矢量 Logo。完全换方向:一个圆润印模形状,中间被冲出一个不规则圆孔,像从泥板里取出作品。抽象、强轮廓、可注册、小尺寸清楚。配色:黑色主形、奶白负形、荧光青小块、珊瑚红。不要播放键、聊天气泡、笑脸、手、星星、陶罐、文字、字母、3D。',
|
||
},
|
||
];
|
||
|
||
const punchReferencePath = path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-fresh-concepts',
|
||
'taonier-fresh-punch-hole.png',
|
||
);
|
||
const punch04ReferencePath = path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-punch-hole-concepts',
|
||
'taonier-punch-color-inlay.png',
|
||
);
|
||
const paletteRefineReferencePath = path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-ref04-palette-transfer',
|
||
'taonier-ref04-palette-transfer-warm-yellow-sparkle.png',
|
||
);
|
||
const paletteShapeReferencePath = path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-ref04-locked-color-concepts',
|
||
'taonier-ref04-locked-warm-ink.png',
|
||
);
|
||
const sparkleRefineReferencePath = path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-ref04-warm-sparkle-v2-concepts',
|
||
'taonier-ref04-warm-sparkle-terracotta.png',
|
||
);
|
||
const sparkleCropReferencePath = path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-ref04-palette-refine-concepts',
|
||
'taonier-sparkle-reference-crop.png',
|
||
);
|
||
const paletteRefineV2ReferencePath = path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-ref04-palette-refine-v2-concepts',
|
||
'taonier-ref04-palette-refine-v2-pale-cream.png',
|
||
);
|
||
const paletteRefineV4PaleButterReferencePath = path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-ref04-palette-refine-v4-concepts',
|
||
'taonier-ref04-palette-refine-v4-pale-butter.png',
|
||
);
|
||
|
||
const punchConcepts = [
|
||
{
|
||
id: 'taonier-punch-locked-shape',
|
||
title: '原型锁定微调',
|
||
referenceImages: [punchReferencePath],
|
||
prompt:
|
||
'为“陶泥儿”继续打磨参考图 06 印模孔洞 logo。必须保持参考图基本造型不变:黑色圆润不规则环形主形、中央白色不规则孔洞、右上珊瑚红辅形、左下青蓝辅形。只优化比例、边缘、留白和小尺寸识别,让它更像成熟 App icon。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-punch-stable-icon',
|
||
title: '稳定主标',
|
||
referenceImages: [punchReferencePath],
|
||
prompt:
|
||
'基于参考图 06 印模孔洞,为“陶泥儿”做无文字扁平矢量 logo 延展。保留黑色冲孔主形和中央不规则白洞,但让外轮廓更稳定、更像长期品牌主标。右上珊瑚红和左下青蓝辅形更克制,白底,强轮廓,小尺寸清楚。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-punch-hole-balance',
|
||
title: '孔洞比例',
|
||
referenceImages: [punchReferencePath],
|
||
prompt:
|
||
'基于参考图 06 印模孔洞,为“陶泥儿”延展一个更干净的无文字 logo。核心仍是黑色圆润印模环和中央不规则白色孔洞,重点调整孔洞大小、厚薄关系和负形节奏,让黑形更有张力。珊瑚红、青蓝只作为小面积辅形。白底。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-punch-color-inlay',
|
||
title: '彩色嵌合',
|
||
referenceImages: [punchReferencePath],
|
||
prompt:
|
||
'基于参考图 06 印模孔洞,为“陶泥儿”做彩色嵌合版 logo。黑色主环保持冲孔感,右上珊瑚红和左下青蓝两块辅形与主形更自然嵌合,像从泥板里取出的两片作品碎片。造型简洁、可注册、App icon 友好。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-punch-mono-test',
|
||
title: '单色测试',
|
||
referenceImages: [punchReferencePath],
|
||
prompt:
|
||
'基于参考图 06 印模孔洞,为“陶泥儿”做单色极简版 logo。只保留黑色圆润冲孔主形和中央白色不规则孔洞,去掉彩色辅形。强调强轮廓、可注册、小尺寸识别和品牌符号感。白底。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-punch-app-token',
|
||
title: '应用图标',
|
||
referenceImages: [punchReferencePath],
|
||
prompt:
|
||
'基于参考图 06 印模孔洞,为“陶泥儿”延展一个更完整的 App icon 核心图形。黑色不规则冲孔主形更饱满,中央白洞更清晰,珊瑚红与青蓝辅形保持年轻感但不抢主体。整体像可长期使用的品牌符号,不像插画。白底。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||
},
|
||
];
|
||
|
||
const punch04Concepts = [
|
||
{
|
||
id: 'taonier-punch04-warm-ink-core',
|
||
title: '暖墨填芯',
|
||
referenceImages: [punch04ReferencePath],
|
||
prompt:
|
||
'基于参考图“04 彩色嵌合”为“陶泥儿”继续做 logo 延展。保持原有基本结构不变:一个圆润不规则环形主形,右上珊瑚红嵌合块,左下青蓝嵌合块,中央不规则孔洞。重点调整配色:中间黑色主形改为温暖深墨灰,不要纯黑;中央孔洞内部加入一枚很简洁的奶油色软泥种子/作品核填充,不要填满,保留留白呼吸。扁平矢量、品牌主标、小尺寸清楚。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-punch04-navy-game-core',
|
||
title: '靛蓝作品核',
|
||
referenceImages: [punch04ReferencePath],
|
||
prompt:
|
||
'基于参考图“04 彩色嵌合”为“陶泥儿”设计一版配色延展。保持黑环、右上红块、左下青块的基本结构和嵌合关系,但把主形从黑色改为深靛蓝或蓝黑色,整体更年轻、更像互联网 App。中央空心区域加入一个极简浅色作品核:小圆角方块或软形小岛,不能像播放键、不能像字母。白底,扁平矢量,干净可注册。无文字、无字母、无聊天气泡、无手、无星星、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-punch04-cream-window',
|
||
title: '奶油内窗',
|
||
referenceImages: [punch04ReferencePath],
|
||
prompt:
|
||
'基于参考图“04 彩色嵌合”为“陶泥儿”做一版更柔和的 logo。基本结构不变:主环、右上珊瑚红、左下青蓝、中央孔洞都保留。把原黑色主环调整为柔和深紫灰或墨绿色,降低硬度。中央孔洞不再是纯空白,设计成奶油色内窗,里面有两块极简小色面,表达多个作品从同一模具生成。整体仍然极简,不要复杂插画。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-punch04-clay-gradient-flat',
|
||
title: '陶盒彩芯',
|
||
referenceImages: [punch04ReferencePath],
|
||
prompt:
|
||
'基于参考图“04 彩色嵌合”为“陶泥儿”做配色与中孔设计。保持 04 的基本轮廓和红青嵌合块位置。主形不要纯黑,改成深陶紫、莓紫或炭灰紫,仍保持强轮廓。中央孔洞加入一个扁平的彩色泥芯,由珊瑚、青蓝、奶白三块圆润小面组成,像作品被捏出来的内核。不要渐变高光,不要立体,不要复杂细节。无文字、无字母、无播放键、无聊天气泡、无手、无星星。',
|
||
},
|
||
{
|
||
id: 'taonier-punch04-mint-shadow',
|
||
title: '薄荷深影',
|
||
referenceImages: [punch04ReferencePath],
|
||
prompt:
|
||
'基于参考图“04 彩色嵌合”为“陶泥儿”做一版更清爽的品牌 logo。保持 04 的三块嵌合结构不变。把中间黑色主形改成深青绿/墨绿,右上红块更偏珊瑚,左下青块更偏亮薄荷。中央空心处加入一枚小小的浅黄色或奶白圆角形,像可玩的作品胚,不要过大。整体强识别、轻休闲、App icon 友好。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-punch04-negative-tile',
|
||
title: '内嵌拼片',
|
||
referenceImages: [punch04ReferencePath],
|
||
prompt:
|
||
'基于参考图“04 彩色嵌合”为“陶泥儿”做一版中间内容更明确的 logo。保持外部基本结构和红青嵌合块位置不变。主形从纯黑改为深墨蓝灰。中央不规则孔洞内部放入一个极简拼片/圆角模块组合,表示拼图、小游戏、互动作品,但必须非常简洁,不能像 UI 图标堆叠。白底,扁平矢量,主标感强。无文字、无字母、无播放键、无聊天气泡、无手、无星星、无3D。',
|
||
},
|
||
];
|
||
|
||
const paletteRefineConcepts = [
|
||
{
|
||
id: 'taonier-ref04-palette-refine-butter',
|
||
title: '淡黄黄油',
|
||
referenceImages: [paletteRefineReferencePath, sparkleRefineReferencePath],
|
||
prompt:
|
||
'为“陶泥儿”继续调整 REF-04 配色迁移版。必须锁定参考图一的外轮廓和分区:主形、右上红块、左下青块和中间孔洞都保持不变;把中间主形改成温暖、低饱和、很淡的黄油黄或奶油黄,不要脏黄、土黄、芥末黄或偏橙黄。中间的星星必须保持参考图二的原样:四角闪光星,带短小光芒,不能拉伸成细长十字,不能变成五角星,不能加厚底托。整体要像成熟、干净、轻松的品牌 logo。无文字、无字母、无播放键、无聊天气泡、无手、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-cream',
|
||
title: '奶油淡黄',
|
||
referenceImages: [paletteRefineReferencePath, sparkleRefineReferencePath],
|
||
prompt:
|
||
'基于 REF-04 造型锁定版和四角闪光星参考图,生成一版更高级的暖黄配色。保持图一的造型完全不变,只把中间主形改成低饱和奶油淡黄,颜色要轻、透、干净,避免脏、沉、厚。中心星星完全沿用参考图二的四角闪光样式和短光芒,不要拉伸,不要变形,不要变成五角星。红块和青块保持现有位置与比例。白底、扁平、品牌标志感。无文字、无字母、无手、无播放键、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-biscuit',
|
||
title: '饼干淡黄',
|
||
referenceImages: [paletteRefineReferencePath, sparkleRefineReferencePath],
|
||
prompt:
|
||
'继续基于 REF-04 造型锁定版做色彩优化。外轮廓、红青辅形、中孔边界全部锁住不变;中间主形换成更淡的饼干黄、奶油黄或浅麦黄,必须低饱和、暖而不脏。中心填充严格使用参考图二的四角闪光星和短光芒,保持原样,不许被拉长,也不许改成几何五角星。整体要简洁、轻盈、专业。无文字、无字母、无聊天气泡、无3D、无复杂阴影。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-milk',
|
||
title: '牛奶暖黄',
|
||
referenceImages: [paletteRefineReferencePath, sparkleRefineReferencePath],
|
||
prompt:
|
||
'在 REF-04 锁形轮廓上做最后一轮暖黄微调。只改中间主形的颜色,把它变成接近牛奶、黄油、奶霜的浅暖黄,低饱和、柔和、干净,不要土气,不要发灰。中间星星必须保持参考图二的四角闪光星原型和短光芒,不能被拉伸,不能变瘦,不能加底托。红青两块辅形位置不动。白底,极简 logo。无文字、无字母、无手、无播放键、无3D。',
|
||
},
|
||
];
|
||
|
||
const paletteRefineV2Concepts = [
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v2-soft-butter',
|
||
title: '柔和奶黄',
|
||
referenceImages: [
|
||
paletteShapeReferencePath,
|
||
paletteRefineReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'为“陶泥儿”修正 REF-04 配色迁移版。严格锁定参考图一的造型和分区:不改变外轮廓、不改变右上辅形、不改变左下辅形、不改变中央孔洞边界。只做两处调整:1)把中间主形改成温暖、低饱和、淡淡的奶油黄/黄油黄,颜色要高级、轻、干净,绝对不要土黄、脏黄、芥末黄、焦糖黄、偏橙黄;2)中心空洞里的星星必须使用参考图三的原始四角闪光星和短光芒,保持饱满菱形闪光,不要拉伸成十字,不要变成五角星,不要加底托。保持白底和扁平 logo。无文字、无字母、无手、无播放键、无聊天气泡、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v2-pale-cream',
|
||
title: '浅奶油黄',
|
||
referenceImages: [
|
||
paletteShapeReferencePath,
|
||
paletteRefineReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'基于三张参考图生成一版修正版 logo:参考图一只用于锁定 REF-04 造型;参考图二只用于当前粉红与薄荷青位置;参考图三用于中心星星样式。中间主形颜色改为低饱和浅奶油黄,接近柔和奶霜,不要土气、不要脏、不要高饱和。中心星星必须照参考图三,四角闪光星带短光芒,比例自然饱满,不能被压扁或拉长。外轮廓和孔洞边界不变。白底、干净、成熟品牌 logo。无文字、无字母、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v2-light-vanilla',
|
||
title: '香草淡黄',
|
||
referenceImages: [
|
||
paletteShapeReferencePath,
|
||
paletteRefineReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'继续优化 REF-04 造型锁定 logo。必须保持参考图一的所有轮廓位置,只把中间原黑色区域换成温暖低饱和的香草淡黄,颜色像轻柔黄油、奶油纸、浅米黄,不能像陶土、咖啡、焦糖或芥末。中心空洞填入参考图三的星星:圆润四角闪光、短小光芒、自然比例,不要变瘦,不要拉伸,不要五角星。粉红和薄荷青辅形沿用参考图二的气质。无文字、无字母、无播放键、无聊天气泡、无手、无3D。',
|
||
},
|
||
];
|
||
|
||
const paletteRefineV3Concepts = [
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v3-butter-soft',
|
||
title: '淡奶油黄',
|
||
referenceImages: [
|
||
paletteShapeReferencePath,
|
||
paletteRefineV2ReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'为“陶泥儿”继续修正 REF-04 的配色迁移版。锁定参考图一的外轮廓、红块、青块和孔洞边界不动;把中间主形调成更高级的淡奶油黄、黄油白黄或柔软黄米色,颜色要更淡一点、更轻一点、更透一点,不要土黄、脏黄、焦糖黄、芥末黄,也不要偏橙偏褐。中心空洞使用参考图三的星星:必须是饱满的四角闪光星,带短小光芒,不能被拉长成细十字,不能变成五角星,也不能出现厚底托。整体保持白底、扁平、品牌 logo 感。无文字、无字母、无3D、无聊天气泡。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v3-milk-cream',
|
||
title: '奶霜淡黄',
|
||
referenceImages: [
|
||
paletteShapeReferencePath,
|
||
paletteRefineV2ReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'基于三张参考图输出一版更轻的 REF-04 logo。第一张参考只负责锁定原始造型;第二张参考只负责当前配色关系;第三张参考只负责中心闪光星的样子。中间主形改成低饱和的奶霜淡黄,颜色要轻柔、通透、像淡淡的黄油和牛奶混合,不要土、不要厚、不要脏。星星保持参考图三的四角闪光星和短光芒,不许拉伸,不许变形,不许五角星化。红块和青块位置固定。无文字、无字母、无手、无播放键、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v3-soft-vanilla',
|
||
title: '香草奶黄',
|
||
referenceImages: [
|
||
paletteShapeReferencePath,
|
||
paletteRefineV2ReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'继续保持 REF-04 的造型锁定,做一次更安静的暖黄修正。中间主形变成香草奶黄或浅奶油黄,必须是低饱和、柔和、高级的淡黄,不要像土黄、咖喱黄、焦糖黄或偏橙黄。中心填充沿用参考图三的四角闪光星,星体要圆润饱满,旁边的短光芒保留,但不能夸张,不能拉长。外轮廓完全不动。白底、logo 感、扁平。无文字、无字母、无聊天气泡、无3D。',
|
||
},
|
||
];
|
||
|
||
const paletteRefineV4Concepts = [
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v4-cream-paper',
|
||
title: '奶油纸淡黄',
|
||
referenceImages: [
|
||
paletteShapeReferencePath,
|
||
paletteRefineReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'继续用 image-2 修正“陶泥儿” REF-04 logo。参考图一只用于锁定 REF-04 原型:外轮廓、右上粉红块、左下薄荷青块、中央孔洞边界都不要重新设计;参考图二只说明当前需要修正的版本;参考图三只用于中心星星。把中间原本土黄/脏黄的主形改成温暖、低饱和、淡淡的奶油纸黄色,接近 #F3E5B4 或 #F6E9C5,颜色要轻、干净、高级,不要陶土黄、芥末黄、咖喱黄、焦糖黄、橙黄、棕黄。中心孔洞里的星星必须保持参考图三原本的四角闪光星比例:上下左右四个圆润尖角,宽高自然,不能被横向或纵向拉伸,不能变成细十字,不能变成五角星,旁边短光芒也保持短小。白底、扁平品牌 logo。无文字、无字母、无播放键、无聊天气泡、无手、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v4-warm-ivory',
|
||
title: '暖象牙淡黄',
|
||
referenceImages: [
|
||
paletteShapeReferencePath,
|
||
paletteRefineReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'基于三张参考图输出一版 REF-04 精修 logo。第一张参考图的形状和分区必须优先:主形轮廓不改、粉红块和薄荷青块位置不改、中间白色孔洞不改;只把中间主形从现在偏土的黄改成暖象牙淡黄,像很淡的黄油白、奶油米白、暖白纸,低饱和、柔和、通透,不要厚重和脏感。第三张参考图的四角闪光星需要原样放进中心:星体不能被压扁、不能拉长、不能瘦成十字,短光芒不要变多。整体保持成熟、干净、可做 App icon 的扁平 logo。无文字、无字母、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v4-soft-champagne',
|
||
title: '淡香槟暖黄',
|
||
referenceImages: [
|
||
paletteShapeReferencePath,
|
||
paletteRefineV2ReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'为“陶泥儿”做一版更高级的 REF-04 暖黄精修。参考图一锁定基本造型,不允许改成播放按钮、三角形、气泡或新图标;参考图二只参考淡黄的轻盈程度;参考图三锁定星星。中间主形使用低饱和淡香槟黄/奶霜黄,颜色要非常淡、温暖、干净,不能像泥土、咖喱、焦糖、芥末或橙棕。中心星星必须是参考图三那种饱满四角闪光,保留短光芒,按原始宽高比例绘制,不能拉伸、不能变形、不能五角星化。粉红和薄荷青辅形保持克制。白底、扁平、品牌主标感。无文字、无字母、无3D、无复杂阴影。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v4-pale-butter',
|
||
title: '淡黄油暖白',
|
||
referenceImages: [
|
||
paletteShapeReferencePath,
|
||
paletteRefineV2ReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'继续调整 REF-04 配色版本,只修正颜色和中心星星,不重画 logo。外轮廓、三块嵌合关系、中央孔洞边界以参考图一为准;中间主形换成淡黄油暖白,像轻薄奶油、温暖米白、浅黄纸,低饱和、不土、不脏、不橙、不褐。中心孔洞填入参考图三原样的四角闪光星:星星要圆润饱满,四个尖角长度均衡,短光芒短而自然,不能拉伸成细长十字。保留白底和扁平矢量 logo 气质。禁止文字、字母、五角星、播放键、聊天气泡、手、3D。',
|
||
},
|
||
];
|
||
|
||
const paletteRefineV5Concepts = [
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v5-filled-centered-spark',
|
||
title: '填心居中亮星',
|
||
referenceImages: [
|
||
paletteRefineV4PaleButterReferencePath,
|
||
paletteShapeReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'根据参考图修改“陶泥儿”04 图标,保留右上粉红块、左下薄荷青块和整体软泥圆润气质。重点做三处修改:1)补全左侧外轮廓曲线,让左侧从上到下形成连续、顺滑、饱满的弧线,不能有缺口、锯齿、截断或不自然凹陷;2)把中央白色空心孔洞完全用主体同色的温暖低饱和淡奶油黄填平,不能再出现白色中孔、白色环或内窗;3)把参考星星改成明亮的黄色四角闪光星,放在整个淡黄主体的视觉中央,星星清晰、圆润、比例自然,不要五角星,不要拉伸成十字。白底、扁平品牌 logo、干净高级。无文字、无字母、无播放键、无聊天气泡、无手、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v5-smooth-left-small-spark',
|
||
title: '顺滑左弧小亮星',
|
||
referenceImages: [
|
||
paletteRefineV4PaleButterReferencePath,
|
||
paletteShapeReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'继续精修“陶泥儿”04 图标。以参考图一的 04 配色和比例为基础,但不要保留中央白洞。左侧外边缘需要补成更完整、更协调的连续曲线,像一整块柔软陶泥的自然外轮廓;中间原空心区域必须填成和主形一致的淡奶油黄色,与主体融为一体。中心放一枚明亮黄色四角闪光星,星星略小、居中、干净,不带复杂底托,不是五角星,不是细长十字。粉红块和薄荷青块仍然分离在右上和左下,白色间隔保持干净。无文字、无字母、无3D。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v5-balanced-bright-spark',
|
||
title: '平衡亮星',
|
||
referenceImages: [
|
||
paletteRefineV4PaleButterReferencePath,
|
||
paletteShapeReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'为“陶泥儿”输出一版更协调的 04 图标修改稿。主形是温暖、低饱和、淡淡的奶油黄色;请补齐左侧曲线,让左边外轮廓更圆润完整,整体重心更稳。中央空心区域不再留白,必须填平为同样的淡黄色主形。把四角闪光星改成更明亮、更清楚的黄色,准确放在图标中央,星体饱满,四个尖角均衡,可以有很短的小光芒但不要抢主体。保持扁平 logo 感和白底。禁止文字、字母、五角星、播放键、聊天气泡、手、3D。',
|
||
},
|
||
{
|
||
id: 'taonier-ref04-palette-refine-v5-solid-core-no-hole',
|
||
title: '实体主形亮星',
|
||
referenceImages: [
|
||
paletteRefineV4PaleButterReferencePath,
|
||
paletteShapeReferencePath,
|
||
sparkleCropReferencePath,
|
||
],
|
||
prompt:
|
||
'按用户参考图修改 04 logo:把淡黄主形做成一个更完整的实体软泥形。左侧曲线补全并顺滑化,外轮廓不要破碎;原中央白色孔洞完全消失,改成与主形同色的淡奶油黄实体面;在实体面的正中央放一枚明亮黄色四角闪光星,星星比主体颜色更亮,有明确识别但不幼稚。保持右上粉红块和左下薄荷青块的年轻配色,整体干净、轻盈、品牌主标感。无文字、无字母、无内孔、无白色中窗、无五角星、无播放键、无3D。',
|
||
},
|
||
];
|
||
|
||
const args = new Map();
|
||
for (let index = 2; index < process.argv.length; index += 1) {
|
||
const raw = process.argv[index];
|
||
if (!raw.startsWith('--')) {
|
||
continue;
|
||
}
|
||
const next = process.argv[index + 1];
|
||
if (next && !next.startsWith('--')) {
|
||
args.set(raw, next);
|
||
index += 1;
|
||
} else {
|
||
args.set(raw, true);
|
||
}
|
||
}
|
||
|
||
const style = String(args.get('--style') || 'dimensional').trim();
|
||
const concepts =
|
||
style === 'flat'
|
||
? flatConcepts
|
||
: style === 'v3'
|
||
? v3Concepts
|
||
: style === 'magic'
|
||
? magicDotConcepts
|
||
: style === 'hands'
|
||
? handsConcepts
|
||
: style === 'broad'
|
||
? broadConcepts
|
||
: style === 'fresh'
|
||
? freshConcepts
|
||
: style === 'punch'
|
||
? punchConcepts
|
||
: style === 'punch04'
|
||
? punch04Concepts
|
||
: style === 'palette-refine'
|
||
? paletteRefineConcepts
|
||
: style === 'palette-refine-v2'
|
||
? paletteRefineV2Concepts
|
||
: style === 'palette-refine-v3'
|
||
? paletteRefineV3Concepts
|
||
: style === 'palette-refine-v4'
|
||
? paletteRefineV4Concepts
|
||
: style === 'palette-refine-v5'
|
||
? paletteRefineV5Concepts
|
||
: dimensionalConcepts;
|
||
const selectedOutputDir =
|
||
style === 'flat'
|
||
? path.join(repoRoot, 'public', 'branding', 'taonier-logo-flat-concepts')
|
||
: style === 'v3'
|
||
? path.join(repoRoot, 'public', 'branding', 'taonier-logo-v3-concepts')
|
||
: style === 'magic'
|
||
? path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-magic-dot-concepts',
|
||
)
|
||
: style === 'hands'
|
||
? path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-hands-concepts',
|
||
)
|
||
: style === 'broad'
|
||
? path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-broad-concepts',
|
||
)
|
||
: style === 'fresh'
|
||
? path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-fresh-concepts',
|
||
)
|
||
: style === 'punch'
|
||
? path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-punch-hole-concepts',
|
||
)
|
||
: style === 'punch04'
|
||
? path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-punch04-color-concepts',
|
||
)
|
||
: style === 'palette-refine'
|
||
? path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-ref04-palette-refine-concepts',
|
||
)
|
||
: style === 'palette-refine-v2'
|
||
? path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-ref04-palette-refine-v2-concepts',
|
||
)
|
||
: style === 'palette-refine-v3'
|
||
? path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-ref04-palette-refine-v3-concepts',
|
||
)
|
||
: style === 'palette-refine-v4'
|
||
? path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-ref04-palette-refine-v4-concepts',
|
||
)
|
||
: style === 'palette-refine-v5'
|
||
? path.join(
|
||
repoRoot,
|
||
'public',
|
||
'branding',
|
||
'taonier-logo-ref04-palette-refine-v5-concepts',
|
||
)
|
||
: outputDir;
|
||
|
||
function readDotenv(fileName) {
|
||
const filePath = path.join(repoRoot, fileName);
|
||
if (!existsSync(filePath)) {
|
||
return {};
|
||
}
|
||
|
||
const values = {};
|
||
for (const line of readFileSync(filePath, 'utf8').split(/\r?\n/u)) {
|
||
const trimmed = line.trim();
|
||
if (!trimmed || trimmed.startsWith('#')) {
|
||
continue;
|
||
}
|
||
const match = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/u.exec(trimmed);
|
||
if (!match) {
|
||
continue;
|
||
}
|
||
let value = match[2].trim();
|
||
if (
|
||
(value.startsWith('"') && value.endsWith('"')) ||
|
||
(value.startsWith("'") && value.endsWith("'"))
|
||
) {
|
||
value = value.slice(1, -1);
|
||
}
|
||
values[match[1]] = value;
|
||
}
|
||
return values;
|
||
}
|
||
|
||
function resolveEnv() {
|
||
const loaded = {
|
||
...readDotenv('.env.example'),
|
||
...readDotenv('.env.local'),
|
||
...readDotenv('.env.secrets.local'),
|
||
...process.env,
|
||
};
|
||
return {
|
||
baseUrl: String(loaded.VECTOR_ENGINE_BASE_URL || '')
|
||
.trim()
|
||
.replace(/\/+$/u, ''),
|
||
apiKey: String(loaded.VECTOR_ENGINE_API_KEY || '').trim(),
|
||
timeoutMs: Number.parseInt(
|
||
String(loaded.VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS || defaultTimeoutMs),
|
||
10,
|
||
),
|
||
};
|
||
}
|
||
|
||
function buildUrl(baseUrl) {
|
||
return baseUrl.endsWith('/v1')
|
||
? `${baseUrl}/images/generations`
|
||
: `${baseUrl}/v1/images/generations`;
|
||
}
|
||
|
||
function hasHeader(headers, targetName) {
|
||
return Object.keys(headers).some(
|
||
(name) => name.toLowerCase() === targetName.toLowerCase(),
|
||
);
|
||
}
|
||
|
||
async function requestBuffer(url, options, timeoutMs, redirectCount = 0) {
|
||
const body =
|
||
typeof options.body === 'string'
|
||
? Buffer.from(options.body)
|
||
: options.body || null;
|
||
const headers = { ...(options.headers || {}) };
|
||
if (body && !hasHeader(headers, 'content-length')) {
|
||
headers['Content-Length'] = String(body.length);
|
||
}
|
||
|
||
return new Promise((resolve, reject) => {
|
||
const parsedUrl = new URL(url);
|
||
const transport = parsedUrl.protocol === 'http:' ? http : https;
|
||
const request = transport.request(
|
||
parsedUrl,
|
||
{
|
||
method: options.method || 'GET',
|
||
headers,
|
||
},
|
||
(response) => {
|
||
const statusCode = response.statusCode || 0;
|
||
const location = response.headers.location;
|
||
if (
|
||
statusCode >= 300 &&
|
||
statusCode < 400 &&
|
||
location &&
|
||
redirectCount < 5
|
||
) {
|
||
response.resume();
|
||
const redirectedUrl = new URL(location, parsedUrl).toString();
|
||
const preserveBody = statusCode === 307 || statusCode === 308;
|
||
requestBuffer(
|
||
redirectedUrl,
|
||
preserveBody
|
||
? options
|
||
: {
|
||
method: 'GET',
|
||
headers: options.headers,
|
||
},
|
||
timeoutMs,
|
||
redirectCount + 1,
|
||
)
|
||
.then(resolve)
|
||
.catch(reject);
|
||
return;
|
||
}
|
||
|
||
const chunks = [];
|
||
response.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
|
||
response.on('end', () =>
|
||
resolve({
|
||
statusCode,
|
||
headers: response.headers,
|
||
bytes: Buffer.concat(chunks),
|
||
}),
|
||
);
|
||
},
|
||
);
|
||
|
||
request.setTimeout(timeoutMs, () => {
|
||
request.destroy(new Error(`request timed out after ${timeoutMs}ms`));
|
||
});
|
||
request.on('error', reject);
|
||
if (body) {
|
||
request.write(body);
|
||
}
|
||
request.end();
|
||
});
|
||
}
|
||
|
||
function collectStringsByKey(value, targetKey, output) {
|
||
if (Array.isArray(value)) {
|
||
value.forEach((entry) => collectStringsByKey(entry, targetKey, output));
|
||
return;
|
||
}
|
||
if (!value || typeof value !== 'object') {
|
||
return;
|
||
}
|
||
for (const [key, nested] of Object.entries(value)) {
|
||
if (key === targetKey) {
|
||
if (typeof nested === 'string' && nested.trim()) {
|
||
output.push(nested.trim());
|
||
}
|
||
if (Array.isArray(nested)) {
|
||
nested.forEach((entry) => {
|
||
if (typeof entry === 'string' && entry.trim()) {
|
||
output.push(entry.trim());
|
||
}
|
||
});
|
||
}
|
||
}
|
||
collectStringsByKey(nested, targetKey, output);
|
||
}
|
||
}
|
||
|
||
function extractImageUrls(payload) {
|
||
const urls = [];
|
||
collectStringsByKey(payload, 'url', urls);
|
||
collectStringsByKey(payload, 'image', urls);
|
||
collectStringsByKey(payload, 'image_url', urls);
|
||
return [...new Set(urls)].filter((url) => /^https?:\/\//u.test(url));
|
||
}
|
||
|
||
function extractBase64Images(payload) {
|
||
const values = [];
|
||
collectStringsByKey(payload, 'b64_json', values);
|
||
return values;
|
||
}
|
||
|
||
function inferExtensionFromBytes(bytes) {
|
||
if (bytes.subarray(0, 8).equals(Buffer.from('\x89PNG\r\n\x1A\n', 'binary'))) {
|
||
return 'png';
|
||
}
|
||
if (bytes.subarray(0, 3).equals(Buffer.from([0xff, 0xd8, 0xff]))) {
|
||
return 'jpg';
|
||
}
|
||
if (
|
||
bytes.subarray(0, 4).toString('ascii') === 'RIFF' &&
|
||
bytes.subarray(8, 12).toString('ascii') === 'WEBP'
|
||
) {
|
||
return 'webp';
|
||
}
|
||
return 'png';
|
||
}
|
||
|
||
function imagePathToDataUrl(imagePath) {
|
||
if (!existsSync(imagePath)) {
|
||
throw new Error(`Reference image not found: ${imagePath}`);
|
||
}
|
||
|
||
const bytes = readFileSync(imagePath);
|
||
const extension = path.extname(imagePath).toLowerCase();
|
||
const mimeType =
|
||
extension === '.jpg' || extension === '.jpeg'
|
||
? 'image/jpeg'
|
||
: extension === '.webp'
|
||
? 'image/webp'
|
||
: 'image/png';
|
||
return `data:${mimeType};base64,${bytes.toString('base64')}`;
|
||
}
|
||
|
||
async function fetchJson(url, options, timeoutMs) {
|
||
try {
|
||
const response = await requestBuffer(url, options, timeoutMs);
|
||
const text = response.bytes.toString('utf8');
|
||
if (response.statusCode < 200 || response.statusCode >= 300) {
|
||
throw new Error(
|
||
`VectorEngine ${response.statusCode}: ${text.slice(0, 600)}`,
|
||
);
|
||
}
|
||
return JSON.parse(text);
|
||
} catch (error) {
|
||
if (String(error?.message || '').includes('timed out')) {
|
||
throw new Error(
|
||
`VectorEngine request timed out after ${timeoutMs}ms`,
|
||
{ cause: error },
|
||
);
|
||
}
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
async function downloadUrl(url, timeoutMs) {
|
||
try {
|
||
const response = await requestBuffer(url, { method: 'GET' }, timeoutMs);
|
||
if (response.statusCode < 200 || response.statusCode >= 300) {
|
||
throw new Error(`download ${response.statusCode}`);
|
||
}
|
||
return response.bytes;
|
||
} catch (error) {
|
||
if (String(error?.message || '').includes('timed out')) {
|
||
throw new Error(
|
||
`Generated image download timed out after ${timeoutMs}ms`,
|
||
{ cause: error },
|
||
);
|
||
}
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
async function generateConcept(env, concept) {
|
||
const requestBody = {
|
||
model: 'gpt-image-2-all',
|
||
prompt: concept.prompt,
|
||
n: 1,
|
||
size: '1024x1024',
|
||
};
|
||
if (concept.referenceImages?.length) {
|
||
requestBody.image = concept.referenceImages.map(imagePathToDataUrl);
|
||
}
|
||
const payload = await fetchJson(
|
||
buildUrl(env.baseUrl),
|
||
{
|
||
method: 'POST',
|
||
headers: {
|
||
Authorization: `Bearer ${env.apiKey}`,
|
||
Accept: 'application/json',
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify(requestBody),
|
||
},
|
||
env.timeoutMs,
|
||
);
|
||
|
||
const urls = extractImageUrls(payload);
|
||
const b64Images = extractBase64Images(payload);
|
||
let bytes;
|
||
if (urls[0]) {
|
||
bytes = await downloadUrl(urls[0], env.timeoutMs);
|
||
} else if (b64Images[0]) {
|
||
bytes = Buffer.from(b64Images[0], 'base64');
|
||
} else {
|
||
throw new Error(`VectorEngine returned no image for ${concept.id}`);
|
||
}
|
||
|
||
mkdirSync(selectedOutputDir, { recursive: true });
|
||
const extension = inferExtensionFromBytes(bytes);
|
||
const outputPath = path.join(selectedOutputDir, `${concept.id}.${extension}`);
|
||
writeFileSync(outputPath, bytes);
|
||
return outputPath;
|
||
}
|
||
|
||
const dryRun = args.has('--dry-run') || !args.has('--live');
|
||
const onlyIds = String(args.get('--only') || '')
|
||
.split(',')
|
||
.map((value) => value.trim())
|
||
.filter(Boolean);
|
||
const limit = Number.parseInt(String(args.get('--limit') || '0'), 10);
|
||
const selected = concepts
|
||
.filter((concept) => !onlyIds.length || onlyIds.includes(concept.id))
|
||
.slice(0, limit > 0 ? limit : concepts.length);
|
||
|
||
if (dryRun) {
|
||
console.log(
|
||
JSON.stringify(
|
||
{
|
||
mode: 'dry-run',
|
||
style,
|
||
outputDir: selectedOutputDir,
|
||
count: selected.length,
|
||
requests: selected.map((concept) => ({
|
||
id: concept.id,
|
||
title: concept.title,
|
||
body: {
|
||
model: 'gpt-image-2-all',
|
||
prompt: concept.prompt,
|
||
n: 1,
|
||
size: '1024x1024',
|
||
...(concept.referenceImages?.length
|
||
? {
|
||
image: concept.referenceImages.map((imagePath) =>
|
||
path.relative(repoRoot, imagePath),
|
||
),
|
||
}
|
||
: {}),
|
||
},
|
||
})),
|
||
},
|
||
null,
|
||
2,
|
||
),
|
||
);
|
||
process.exit(0);
|
||
}
|
||
|
||
const env = resolveEnv();
|
||
if (!env.baseUrl || !env.apiKey) {
|
||
console.error(
|
||
JSON.stringify({
|
||
ok: false,
|
||
error: 'Missing VECTOR_ENGINE_BASE_URL or VECTOR_ENGINE_API_KEY',
|
||
hasBaseUrl: Boolean(env.baseUrl),
|
||
hasApiKey: Boolean(env.apiKey),
|
||
}),
|
||
);
|
||
process.exit(1);
|
||
}
|
||
|
||
const generated = [];
|
||
for (const concept of selected) {
|
||
console.log(`Generating ${concept.id}...`);
|
||
generated.push(await generateConcept(env, concept));
|
||
}
|
||
|
||
console.log(
|
||
JSON.stringify(
|
||
{
|
||
ok: true,
|
||
count: generated.length,
|
||
files: generated,
|
||
},
|
||
null,
|
||
2,
|
||
),
|
||
);
|