MODULE-COVER-001: full package for external AI consumption - server.js + renderer.js + generate.js + config.js - templates/ (5 templates: xiaohongshu + dynamic + jike + poster + registry) - package.json + README.md + MODULE.hdlp - INDEX.hdlp + SYSTEM.hdlp (HLDP declarations) - Fonts: Noto Sans CJK SC priority (no tofu blocks) - No domain watermark - Updated module-registry.json - Copyright 2026-A-00037559
243 lines
7.4 KiB
JavaScript
243 lines
7.4 KiB
JavaScript
/**
|
||
* ═══════════════════════════════════════════════════
|
||
* 铸渊图片工作室 · 风格配置系统
|
||
* ═══════════════════════════════════════════════════
|
||
*
|
||
* 冰朔,这里所有的颜色、字体、间距你都可以改。
|
||
* 告诉我想要的「感觉」,我来调。
|
||
*/
|
||
|
||
export const STYLES = {
|
||
|
||
/* ── 当前风格:光湖极简 ── */
|
||
name: '光湖极简',
|
||
|
||
colors: {
|
||
primary: '#1a1a2e', // 主色 · 深蓝黑
|
||
secondary: '#16213e', // 辅色 · 深蓝
|
||
accent: '#0f3460', // 强调色 · 普鲁士蓝
|
||
highlight: '#e94560', // 高亮 · 珊瑚红
|
||
gold: '#c9a96e', // 金色 · 点缀
|
||
warm: '#f5e6c8', // 暖白 · 背景
|
||
|
||
bg: '#faf8f5', // 页面背景
|
||
bgCard: '#ffffff', // 卡片背景
|
||
text: '#1a1a2e', // 正文
|
||
textMuted: '#6b7280', // 辅助文字
|
||
textLight: '#ffffff', // 浅色背景上的文字
|
||
border: '#e5e7eb', // 边框
|
||
divider: '#f0e6d3', // 分割线 · 暖色
|
||
},
|
||
|
||
fonts: {
|
||
title: '"Noto Serif SC", "Source Han Serif SC", serif',
|
||
body: '"Noto Sans SC", "Source Han Sans SC", "PingFang SC", sans-serif',
|
||
quote: '"ZCOOL QingKe HuangYou", cursive',
|
||
mono: '"JetBrains Mono", "Fira Code", monospace',
|
||
},
|
||
|
||
/* 卡片尺寸 —— 这些只是参考,可以随时改 */
|
||
sizes: {
|
||
xiaohongshu: { width: 1080, height: 1440 }, // 3:4
|
||
jike: { width: 1080, height: 1080 }, // 1:1
|
||
poster: { width: 1080, height: 1920 }, // 9:16 海报
|
||
wechat: { width: 1080, height: 1350 }, // 4:5 朋友圈
|
||
square: { width: 1080, height: 1080 }, // 1:1 通用方图
|
||
wide: { width: 1920, height: 1080 }, // 16:9 宽图
|
||
},
|
||
|
||
/* 排版 */
|
||
typography: {
|
||
titleSize: 56,
|
||
subtitleSize: 32,
|
||
bodySize: 28,
|
||
smallSize: 22,
|
||
captionSize: 18,
|
||
lineHeight: 1.6,
|
||
},
|
||
|
||
/* 间距 */
|
||
spacing: {
|
||
paddingX: 64,
|
||
paddingY: 60,
|
||
gap: 32,
|
||
},
|
||
|
||
/* 水印/品牌标识 */
|
||
brand: {
|
||
show: true,
|
||
text: '光湖 · 铸渊',
|
||
size: 16,
|
||
opacity: 0.4,
|
||
},
|
||
}
|
||
|
||
|
||
/* ── 配色方案 ── */
|
||
export const COLOR_SCHEMES = {
|
||
guanghu: {
|
||
name: '光湖极简',
|
||
primary: '#1a1a2e', bg: '#faf8f5', accent: '#0f3460',
|
||
highlight: '#e94560', gold: '#c9a96e', warm: '#f5e6c8',
|
||
},
|
||
cream: {
|
||
name: '奶油暖调',
|
||
primary: '#5d4037', bg: '#fef7f0', accent: '#8d6e63',
|
||
highlight: '#e07a5f', gold: '#d4a373', warm: '#fae1dd',
|
||
},
|
||
night: {
|
||
name: '暗夜深蓝',
|
||
primary: '#e0e0e0', bg: '#0d1117', accent: '#58a6ff',
|
||
highlight: '#f78166', gold: '#d4a373', warm: '#21262d',
|
||
},
|
||
green: {
|
||
name: '文艺绿植',
|
||
primary: '#2d3e2f', bg: '#f5f9f2', accent: '#5a8f5a',
|
||
highlight: '#c78b5c', gold: '#b8a06e', warm: '#e8f0e0',
|
||
},
|
||
rose: {
|
||
name: '玫瑰粉调',
|
||
primary: '#4a1942', bg: '#fdf2f8', accent: '#9d4e8d',
|
||
highlight: '#e8435e', gold: '#c9a96e', warm: '#fce4ec',
|
||
},
|
||
}
|
||
|
||
|
||
export function useScheme(name) {
|
||
const scheme = COLOR_SCHEMES[name]
|
||
if (!scheme) return false
|
||
const c = STYLES.colors
|
||
c.primary = scheme.primary; c.bg = scheme.bg
|
||
c.accent = scheme.accent; c.highlight = scheme.highlight
|
||
c.gold = scheme.gold; c.warm = scheme.warm
|
||
STYLES.name = scheme.name
|
||
return true
|
||
}
|
||
|
||
|
||
/* ═══════════════════════════════════════════════════
|
||
* 内容感知 · 自动检测函数
|
||
* ═══════════════════════════════════════════════════
|
||
*
|
||
* 冰朔给我一段文字,我分析它是什么类型的、什么情绪、
|
||
* 适合什么布局。不需要她告诉我。
|
||
*/
|
||
|
||
/**
|
||
* 分析文本特征,返回检测结果
|
||
*/
|
||
export function analyzeText(text) {
|
||
if (!text) return { type: 'empty' }
|
||
|
||
const t = text.trim()
|
||
|
||
/* ── 特征检测 ── */
|
||
const hasList = /^[-•·*]\s|^\d+[\.\)]\s/m.test(t) // 列表项
|
||
const isShort = t.length < 30 // 短句(金句)
|
||
const isMedium = t.length < 100 // 中等长度
|
||
const hasTitle = t.includes('标题') || t.includes(':') // 可能有标题
|
||
const lines = t.split('\n').filter(Boolean)
|
||
const lineCount = lines.length
|
||
|
||
const keywords = {
|
||
notice: /通知|公告|放假|放假安排|节假日|放假通知/i,
|
||
recruit: /征稿|收稿|投稿|征集|诚征|招聘|招募|稿酬/i,
|
||
share: /干货|教程|指南|技巧|方法|如何|步骤|经验|分享/i,
|
||
quote: /说|说过|句话|名言|语录|金句|记得|曾经/i,
|
||
product: /新品|上线|发布|推出|产品|功能|更新/i,
|
||
event: /活动|沙龙|讲座|直播|分享会|聚会/i,
|
||
}
|
||
|
||
const detected = {}
|
||
let type = 'general'
|
||
|
||
for (const [key, re] of Object.entries(keywords)) {
|
||
if (re.test(t)) detected[key] = true
|
||
}
|
||
|
||
/* ── 类型推断 ── */
|
||
if (detected.notice) type = 'notice'
|
||
else if (detected.recruit) type = 'recruit'
|
||
else if (detected.quote || isShort) type = 'quote'
|
||
else if (detected.share || hasList) type = 'list'
|
||
else if (detected.product) type = 'product'
|
||
else if (detected.event) type = 'event'
|
||
else if (lineCount >= 4) type = 'article'
|
||
else if (isMedium) type = 'paragraph'
|
||
|
||
/* ── 情绪推断(基于关键词) ── */
|
||
let mood = 'neutral'
|
||
const warmWords = /感谢|温暖|爱|喜欢|开心|快乐|幸福|美好|谢谢/i
|
||
const urgentWords = /紧急|重要|注意|必读|截止|最后/i
|
||
const elegantWords = /岁月|时光|静好|诗意|远方|温柔/i
|
||
|
||
if (elegantWords.test(t)) mood = 'elegant'
|
||
else if (warmWords.test(t)) mood = 'warm'
|
||
else if (urgentWords.test(t)) mood = 'urgent'
|
||
|
||
return {
|
||
type,
|
||
mood,
|
||
lineCount,
|
||
isShort,
|
||
hasList,
|
||
lines,
|
||
detected,
|
||
text: t,
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 根据内容分析结果推荐配色方案
|
||
*/
|
||
export function recommendScheme(analysis) {
|
||
const { mood, type } = analysis
|
||
|
||
if (mood === 'warm') return 'cream'
|
||
if (mood === 'elegant') return 'green'
|
||
if (mood === 'urgent') return 'guanghu'
|
||
|
||
if (type === 'recruit') return 'cream'
|
||
if (type === 'notice') return 'guanghu'
|
||
if (type === 'quote') return 'rose'
|
||
|
||
return 'guanghu'
|
||
}
|
||
|
||
|
||
/**
|
||
* 根据内容分析推荐布局
|
||
*/
|
||
export function recommendLayout(analysis) {
|
||
const { type, hasList, isShort, lineCount } = analysis
|
||
|
||
if (isShort) return 'quote'
|
||
if (type === 'notice') return 'notice'
|
||
if (type === 'recruit') return 'recruit'
|
||
if (hasList) return 'list'
|
||
if (lineCount <= 3) return 'minimal'
|
||
|
||
return 'default'
|
||
}
|
||
|
||
|
||
/**
|
||
* 根据内容分析推荐尺寸
|
||
* @param {'xiaohongshu'|'jike'|'poster'|'wechat'|'wide'|string} platform
|
||
*/
|
||
export function recommendSize(platform) {
|
||
const sizes = STYLES.sizes
|
||
if (sizes[platform]) return sizes[platform]
|
||
|
||
// 关键词匹配
|
||
if (/小红书/i.test(platform)) return sizes.xiaohongshu
|
||
if (/即刻/i.test(platform)) return sizes.jike
|
||
if (/海报/i.test(platform) || /通知/i.test(platform) || /收稿/i.test(platform)) return sizes.poster
|
||
if (/朋友圈/i.test(platform)) return sizes.wechat
|
||
if (/宽/i.test(platform) || /横/i.test(platform)) return sizes.wide
|
||
|
||
// 默认识别
|
||
return sizes.square
|
||
}
|