import type { StyleProfileSnapshot } from "@/lib/canvas/style-profile"; export type ProjectStyleWorldId = "xianxia" | "urban" | "historical" | "suspense" | "science-fiction" | "pastoral"; export type ProjectStyleToneId = "epic" | "dark" | "light-comedy" | "romantic" | "healing"; export type ProjectStyleMediumId = "live-action" | "3d-anime" | "3d-cartoon" | "2d-guoman" | "ink"; export type ProjectStyleCharacterId = "realistic" | "semi-real" | "anime" | "stylized"; export type ProjectStyleSelection = { world: ProjectStyleWorldId; tone: ProjectStyleToneId; medium: ProjectStyleMediumId; character: ProjectStyleCharacterId; }; export type CanvasStylePreset = { id: string; title: string; category: string; description: string; tags: string[]; prompt: string; imageUrl: string; selection?: ProjectStyleSelection; profile?: StyleProfileSnapshot; }; type StyleOption = { id: T; label: string; description: string; prompt: string; palette?: string; wardrobe?: string; environment?: string; motion?: string; forbidden: string; }; export const projectStyleWorlds: Array> = [ { id: "xianxia", label: "仙侠", description: "宗门、仙城、洞府、云海与法术规则共同构成东方修行世界。", prompt: "东方仙侠世界以宗门、境界、法器、灵兽和因果秩序为基础;奇观从中式山水、木构建筑、道家意象和修行体系演化,所有地点共享明确的时代、地理与力量规则。", palette: "云雾白、黛青、青玉、朱砂、古铜与阵营能量色", wardrobe: "袍服、劲装、甲胄、宗门纹样、发冠、腰封和法器按身份与阵营建立稳定资产层级", environment: "山门、殿宇、楼阁、洞府、仙城、云海、古战场和凡间城镇采用中式结构与东方山水空间", motion: "御剑、身法、法术和衣袍运动必须有起势、蓄力、受力与落点,力量等级通过规模和环境反馈表达", forbidden: "欧洲城堡、哥特教堂、日式鸟居、西式魔法阵、随机游戏 UI、宗门与法术规则漂移", }, { id: "urban", label: "当代都市", description: "以可信中国城市、职业身份与生活关系组织现代短剧。", prompt: "当代中国都市世界以职业、家庭、收入、社区和城市公共生活为基础;人物行动、空间功能、中文标识与生活设施必须符合明确城市和社会语境。", palette: "中性白、雾灰、浅木、水泥色与克制的角色识别色", wardrobe: "服装按职业、收入、季节和性格建立衣橱,固定配饰承担角色识别", environment: "办公室、公寓、学校、医院、商场、街区、社区和公共交通保持本地尺度与使用痕迹", motion: "表演贴近日常重心、停顿和微表情,镜头运动服务人物关系与信息揭示", forbidden: "欧美城市替代、空洞样板间、错误中文、无职业逻辑服装、网红滤镜和广告摆拍", }, { id: "historical", label: "古装历史", description: "先锁定单一时代,再统一礼制、服化道、器物与建筑。", prompt: "历史世界必须先依据故事锁定唯一朝代或年代子类型,人物制度、礼仪、服饰、兵器、器物、交通与建筑全部服从同一考据基线。", palette: "米白、黛灰、木褐、土黄、靛青、竹青与有限朱砂金色", wardrobe: "襟形、袖型、腰带、冠帽、鞋履和纹样按时代、阶层与身份建立制度", environment: "木构、院落、回廊、城镇、宫署、乡野和道路遵循所选时代的结构与材料", motion: "人物动作考虑礼制、服装重量、兵器惯性和具体生活劳动", forbidden: "朝代混搭、现代拉链家具、日式或欧式建筑、塑料饰品和现代偶像妆", }, { id: "suspense", label: "悬疑犯罪", description: "真实城市纹理、线索系统和心理压力构成可读的悬疑世界。", prompt: "现代悬疑世界以案件、秘密、身份关系和可追踪线索构成,地点布局、关键道具、伤痕与时间线必须稳定,信息隐藏不能牺牲画面可读性。", palette: "炭灰、冷水泥、旧木、脏黄实景灯与少量危险强调色", wardrobe: "职业服饰、制服、便装和关键随身物按身份与时间线建立版本", environment: "旧居民楼、办公空间、街巷、仓储、地下空间和城郊设施保持同一城市地域", motion: "观察、跟随、遮挡和反应镜头服务线索揭示,避免把晃动当作悬疑", forbidden: "黑成不可读、霓虹灯海、过量烟雾、血浆猎奇、反派脸谱化和线索资产变形", }, { id: "science-fiction", label: "未来科幻", description: "技术规则、社会结构与功能性空间共同支撑未来叙事。", prompt: "未来世界必须先确定技术水平、能源、交通、通讯和社会组织规则;科技资产具有可理解的功能、接口与使用限制,奇观必须反映文明尺度而非随机堆砌发光物。", palette: "深空黑、冷灰、银白、舱体白与单一阵营或能源强调色", wardrobe: "工作服、制服、航天或防护装备按功能与阵营模块化设计", environment: "舰船、空间站、未来城市、实验设施和居住空间遵循结构、维护与照明逻辑", motion: "运动体现设备重量、惯性、空间限制和技术反馈", forbidden: "无功能 HUD、随机霓虹、现实品牌、技术规则漂移、装备接口变化和无尺度参照", }, { id: "pastoral", label: "自然乡野", description: "地域、季节、生活劳动和自然环境共同参与叙事。", prompt: "自然乡野世界以明确地域、季节、家庭关系和生活劳动为基础;植物、天气、住宅、工具与集市不是装饰,而是持续参与人物行动和关系变化的真实环境。", palette: "叶绿、苔藓绿、土色、旧木、天空色、米白与季节性角色点色", wardrobe: "棉麻、针织、旧牛仔、工作服、雨具和手作物保留褶皱与使用痕迹", environment: "村镇住宅、林间小屋、农场、河岸、菜园、集市和小城边缘具有地域证据", motion: "风、雨、植物、动物和细小生活动作形成自然节奏", forbidden: "商业民宿广告感、欧美乡村替代、随机换季、无生活痕迹和过度航拍空镜", }, ]; export const projectStyleTones: Array> = [ { id: "epic", label: "宏大叙事", description: "用尺度、秩序与人物命运建立史诗感,不靠全程阴暗和特效堆积。", prompt: "叙事气质庄重、开阔、有历史与命运重量;宏大场面负责建立空间和力量关系,人物镜头负责承接选择与代价,奇观和表演之间保持清晰主次。", palette: "高明度空间层次、稳定阵营色与少量高亮奇观色,暗部保留细节", motion: "建立镜头克制而有尺度,高潮运动有明确起止,人物反应获得停顿", forbidden: "全片低照度、无休止慢动作、每镜航拍、特效盖住人物、只有规模没有情绪落点", }, { id: "dark", label: "暗黑诡谲", description: "以未知、禁忌和心理压力形成黑暗气质,同时保持信息可读。", prompt: "叙事气质危险、克制、带未知感;恐惧来自空间、规则和人物反应,不依赖血浆、全黑画面或持续尖叫。", palette: "低调但可读的冷暖分区,危险色只用于禁忌、敌意或线索", motion: "更多观察、遮挡、缓慢揭示和反应停顿,爆发运动只用于关键破局", forbidden: "黑成不可读、血腥猎奇、廉价红黑滤镜、全屏烟雾、无来源闪光和持续镜头抖动", }, { id: "light-comedy", label: "轻喜剧", description: "宏观处境与人物一本正经的反应形成反差,画面明快但不幼稚。", prompt: "叙事气质轻松、机敏、有人情味;笑点依靠人物关系、反应、停顿和处境反差,允许宏大世界承载小人物式幽默,不把喜剧等同于夸张鬼脸。", palette: "清晰明快的中高明度色彩,角色与背景保持稳定分离,危险场面也避免恐怖化压黑", motion: "动作有清楚预备、落点和喜剧停顿,反应镜头与正经表演优先于炫技运镜", forbidden: "阴森恐怖基调、儿童节目式糖果色、所有角色做鬼脸、连续快切和笑点被特效淹没", }, { id: "romantic", label: "唯美浪漫", description: "以人物距离、光线和环境细节表达关系变化,避免滤镜化糖水感。", prompt: "叙事气质细腻、含蓄、具有关系张力;浪漫来自视线、距离、触碰、环境变化和未说出口的情绪,不依赖随机花瓣与持续柔焦。", palette: "自然肤色、柔和冷暖关系与克制的情绪点色", motion: "镜头靠近人物和细节,运动缓慢而有情绪动机,保留呼吸与停顿", forbidden: "全程柔焦、过曝肤色、随机花瓣、MV 式空镜、无表演的慢动作和滤镜漂移", }, { id: "healing", label: "温暖治愈", description: "通过生活行动、环境触感和关系修复形成温暖,而不是泛化柔光。", prompt: "叙事气质温暖、松弛、具体;治愈来自可见的照料、劳动、陪伴和关系变化,环境材质与自然声音参与情绪表达。", palette: "自然中高明度、温暖但不过黄,保留木、布、植物和肤色的真实层次", motion: "观察细小动作、呼吸、眼神和环境响应,节奏舒展但不空洞", forbidden: "全片奶油滤镜、过度暖黄、无剧情自然空镜、广告式精致和人物永远微笑", }, ]; export const projectStyleMedia: Array & { characters: ProjectStyleCharacterId[] }> = [ { id: "live-action", label: "真人实拍", description: "真实演员、可信光学、服化道和物理环境。", prompt: "采用真人影视拍摄媒介:真实人物比例、自然皮肤与发丝、可信镜头光学和现场光源,服装、建筑、道具与特效保持真实材质响应。", motion: "动作遵循真实重心、惯性、衣料重量和摄影机物理运动", forbidden: "动画角色、游戏 CG、塑料皮肤、过度磨皮、虚假棚拍和无物理依据的材质", characters: ["realistic", "semi-real"], }, { id: "3d-anime", label: "3D 动漫", description: "高品质三维动画、东方动漫造型与电影化场景。", prompt: "采用高品质 3D 动漫媒介:清晰三维体积、统一 PBR 或风格化 PBR 材质、受控次表面散射、稳定拓扑和电影级灯光;保持动画角色的设计感,不滑向真人恐怖谷或廉价游戏过场。", motion: "动画具备明确关键姿势、预备动作、跟随、受力和停顿,特效与角色动作共享同一空间和光照", forbidden: "廉价手游 CG、塑料手办反光、僵硬待机动作、真人毛孔皮肤、角色与背景渲染体系不一致", characters: ["semi-real", "anime"], }, { id: "3d-cartoon", label: "3D 卡通", description: "风格化比例、清晰剪影、柔和材质和可读表情。", prompt: "采用风格化 3D 卡通动画媒介:简练几何、清晰剪影、半哑光材质、柔和次表面散射和可读表情;场景与角色使用同一圆角、粗糙度和细节密度体系。", motion: "角色运动使用适度挤压拉伸、跟随、缓入缓出和清晰停顿,夸张建立在稳定骨架与关节结构上", forbidden: "塑料公仔、所有角色同脸、过大玻璃眼、僵硬 T Pose、关节穿模和写实资产混入", characters: ["stylized"], }, { id: "2d-guoman", label: "国漫 2D", description: "稳定线稿、赛璐璐角色与东方绘景体系。", prompt: "采用国漫 2D 动画媒介:有粗细变化的稳定线稿、两至三阶赛璐璐明暗、清晰角色剪影和东方绘景层次;全项目保持二维绘画语言。", motion: "使用明确关键姿势、有限但准确的二维运动,口型、发丝、衣摆与特效遵循统一帧间节奏", forbidden: "三维塑料质感、真人照片、线宽漂移、角色转面失真、背景与角色画法不一致", characters: ["semi-real", "anime", "stylized"], }, { id: "ink", label: "水墨动画", description: "宣纸、墨阶、笔势与留白构成可识别的东方叙事。", prompt: "采用中国水墨动画媒介:宣纸纤维、干湿笔触、飞白、积墨、破墨与有限工笔勾线;留白、墨阶和固定点色共同塑造空间与人物身份。", motion: "轮廓先行、笔势跟随、墨迹生长与消散遵循统一规则,人物结构在变化中保持可识别", forbidden: "随机泼墨、角色五官消失、西式水彩、全屏脏灰、廉价纸纹滤镜和随机文字印章", characters: ["semi-real", "stylized"], }, ]; export const projectStyleCharacters: Array> = [ { id: "realistic", label: "写实人物", description: "真实骨相、年龄、皮肤和身体比例。", prompt: "角色采用真实东亚骨相、自然年龄和真实身体比例,通过脸型、五官、发型、体型、姿态与生活痕迹建立差异;保留自然皮肤和微表情。", forbidden: "网红同脸、过度磨皮、幼态大眼、年龄漂移、欧美默认脸和夸张动漫比例", }, { id: "semi-real", label: "半写实仿真人", description: "东方骨相与理想化造型平衡,保留可信结构。", prompt: "角色采用半写实东方造型:可信骨骼、肌肉和关节结构,五官适度理想化但保留年龄与身份差异;发丝、皮肤和服装细节服从所选媒介,不进入恐怖谷。", forbidden: "真人扫描僵硬感、统一偶像脸、毛孔级过度写实、假睫毛模板和身体比例漂移", }, { id: "anime", label: "动漫角色", description: "修长比例、清晰五官设计和稳定角色剪影。", prompt: "角色采用东方动漫造型:约 7 至 8 头身,五官、发束、眼形和服装结构高度可识别;夸张集中在设计语言和表情,不破坏身体结构与身份稳定性。", forbidden: "低幼大头、过大玻璃眼、随机发色、所有角色同一脸型、五官在转面中漂移", }, { id: "stylized", label: "风格化卡通", description: "夸张比例与可读表情服务喜剧和轻松叙事。", prompt: "角色采用统一的风格化卡通比例:成人约 5 至 6 头身,儿童约 3.5 至 4.5 头身,头手可适度夸张;通过眼鼻嘴比例、发型、体型和剪影建立显著差异。", forbidden: "所有角色同脸、头身随机变化、过大玻璃眼、关节结构错误、塑料玩具感和僵硬表情", }, ]; export const defaultProjectStyleSelection: ProjectStyleSelection = { world: "xianxia", tone: "epic", medium: "3d-anime", character: "semi-real", }; const STYLE_SCOPE = "【使用边界】本规范锁定项目级题材世界、叙事气质、视觉媒介、角色造型、资产材质与影像基线。单镜头的剧情动作、构图、景别、机位、运镜、光源位置和天气由分镜按本规范创作,不得机械复制项目级描述。"; export function compatibleProjectStyleCharacters(mediumId: ProjectStyleMediumId) { const allowed = projectStyleMedia.find((item) => item.id === mediumId)?.characters || []; return projectStyleCharacters.filter((item) => allowed.includes(item.id)); } export function compileCanvasStylePreset(selection: ProjectStyleSelection): CanvasStylePreset { const world = requiredOption(projectStyleWorlds, selection.world); const tone = requiredOption(projectStyleTones, selection.tone); const medium = requiredOption(projectStyleMedia, selection.medium); const compatibleCharacters = compatibleProjectStyleCharacters(selection.medium); const character = compatibleCharacters.find((item) => item.id === selection.character) || compatibleCharacters[0]; const resolvedSelection = { ...selection, character: character.id }; const title = `${world.label} · ${tone.label} · ${medium.label}`; const preset = { id: styleSelectionId(resolvedSelection), title, category: `${world.label} / ${medium.label}`, description: `${world.description}${tone.description}${medium.description}`, tags: [world.label, tone.label, medium.label, character.label], imageUrl: stylePreviewImage(resolvedSelection), selection: resolvedSelection, prompt: [ `【风格组合】题材世界:${world.label};叙事气质:${tone.label};视觉媒介:${medium.label};角色造型:${character.label}。以下四项必须同时成立,后续角色、场景、分镜和视频不得擅自替换其中任一维度。`, `【项目定位】面向“${world.label}”题材的${tone.label}${medium.label}项目,以统一世界规则、角色资产和视觉媒介支撑连续叙事;项目规范只定义长期稳定的美术基线,不代替单镜头导演设计。`, `【题材世界观】${world.prompt}`, `【叙事气质】${tone.prompt}`, `【视觉媒介】${medium.prompt} 成片保持高清可读的主体轮廓、稳定材质和受控高光;高清不等于过度锐化、磨皮或无来源泛光。`, `【角色设计系统】${character.prompt}`, `【项目色彩与光影】基础色彩来自${world.palette};本项目采用${tone.palette}。色彩按角色、阵营、地点和叙事功能分配,保证人物与环境具有稳定的明度和色相分离。`, `【服饰、材质与场景】${world.wardrobe};${world.environment}。所有材质和细节密度遵循“${medium.label}”媒介,不混入其他渲染体系。`, `【影像与动态基线】${tone.motion};${medium.motion};${world.motion}。分镜必须先确定镜头叙事意图,再选择景别与运镜。`, "【资产一致性】角色固定脸型、五官比例、发型、头身、服装、道具和阵营色;主要场景固定空间布局、建筑模块、材质与照明基线;换装、受损、升级和时间变化必须形成明确资产版本。", `【全局禁用】${world.forbidden};${tone.forbidden};${medium.forbidden};${character.forbidden}。`, STYLE_SCOPE, ].join("\n"), } satisfies CanvasStylePreset; return { ...preset, profile: createBuiltinStyleProfile(preset) }; } function createBuiltinStyleProfile(preset: Omit): StyleProfileSnapshot { return { schemaVersion: 1, presetId: preset.id, title: preset.title, description: preset.description, tags: [...preset.tags], prompt: preset.prompt, selection: preset.selection ? { ...preset.selection } : undefined, assets: [], executionPolicy: "compatible-fallback", source: "builtin", revision: 1, }; } export function parseCanvasStyleSelection(id?: string): ProjectStyleSelection | null { if (!id?.startsWith("v2-")) return null; const parts = id.slice(3).split("--"); if (parts.length !== 4) return null; const selection = { world: parts[0], tone: parts[1], medium: parts[2], character: parts[3] } as ProjectStyleSelection; if (!projectStyleWorlds.some((item) => item.id === selection.world) || !projectStyleTones.some((item) => item.id === selection.tone) || !projectStyleMedia.some((item) => item.id === selection.medium) || !projectStyleCharacters.some((item) => item.id === selection.character)) return null; return selection; } export function customCanvasStylePreset(id?: string) { const selection = parseCanvasStyleSelection(id); return selection ? compileCanvasStylePreset(selection) : undefined; } const recommendedSelections: ProjectStyleSelection[] = [ { world: "xianxia", tone: "epic", medium: "3d-anime", character: "semi-real" }, { world: "xianxia", tone: "dark", medium: "3d-anime", character: "semi-real" }, { world: "xianxia", tone: "light-comedy", medium: "3d-cartoon", character: "stylized" }, { world: "xianxia", tone: "epic", medium: "live-action", character: "realistic" }, { world: "urban", tone: "light-comedy", medium: "live-action", character: "realistic" }, { world: "suspense", tone: "dark", medium: "live-action", character: "realistic" }, { world: "pastoral", tone: "healing", medium: "3d-cartoon", character: "stylized" }, { world: "historical", tone: "romantic", medium: "2d-guoman", character: "semi-real" }, ]; export const recommendedCanvasStylePresets = recommendedSelections.map(compileCanvasStylePreset); function styleSelectionId(selection: ProjectStyleSelection) { return `v2-${selection.world}--${selection.tone}--${selection.medium}--${selection.character}`; } function stylePreviewImage(selection: ProjectStyleSelection) { if (selection.world === "xianxia") { if (selection.medium === "live-action") return "/short-drama-styles/period-live-action.jpg"; if (selection.medium === "3d-cartoon") return "/short-drama-styles/three-d-cartoon.jpg"; if (selection.medium === "2d-guoman") return "/short-drama-styles/chinese-2d.jpg"; if (selection.medium === "ink") return "/short-drama-styles/ink-narrative.jpg"; return "/short-drama-styles/fantasy-3d.jpg"; } if (selection.world === "suspense") return "/short-drama-styles/suspense-noir.jpg"; if (selection.world === "science-fiction") return "/short-drama-styles/future-tech.jpg"; if (selection.world === "pastoral") return "/short-drama-styles/nature-healing.jpg"; if (selection.world === "historical") return selection.medium === "2d-guoman" ? "/short-drama-styles/chinese-2d.jpg" : "/short-drama-styles/period-live-action.jpg"; return selection.medium === "3d-cartoon" ? "/short-drama-styles/three-d-cartoon.jpg" : "/short-drama-styles/urban-live-action.jpg"; } function requiredOption(options: Array>, id: T) { const option = options.find((item) => item.id === id); if (!option) throw new Error(`未知项目画风选项:${id}`); return option; }