/* ============================================================
* paper.jsx — PaperStrip component + presets
* ============================================================ */
// === Paper color/texture presets (curated, refined) ===
const PAPER_COLORS = [
{ id: "cream", name: "宣纸", bg: "#f3ead4", ink: "#1a1612" },
{ id: "snow", name: "雪白", bg: "#f8f4ea", ink: "#1a1612" },
{ id: "rice", name: "米黄", bg: "#eadaa6", ink: "#1a1612" },
{ id: "kraft", name: "牛皮", bg: "#c9a878", ink: "#2a1c10" },
{ id: "dan", name: "丹朱", bg: "#c4453a", ink: "#1a1612" },
{ id: "vermilion", name: "正红", bg: "#a8261b", ink: "#f2dd9a" },
{ id: "ochre", name: "赭石", bg: "#c97e3a", ink: "#1a1612" },
{ id: "saffron", name: "藤黄", bg: "#e8a93a", ink: "#1a1612" },
{ id: "celadon", name: "青瓷", bg: "#a8c2b3", ink: "#1a1612" },
{ id: "jade", name: "石绿", bg: "#7fa089", ink: "#1a1612" },
{ id: "indigo", name: "靛青", bg: "#9fb6c9", ink: "#1a1612" },
{ id: "twilight", name: "天青", bg: "#7f9bb2", ink: "#1a1612" },
{ id: "plum", name: "胭脂", bg: "#e9b6b1", ink: "#1a1612" },
{ id: "lilac", name: "紫藤", bg: "#b8a4c4", ink: "#1a1612" },
{ id: "sand", name: "枯叶", bg: "#a89172", ink: "#2a1c10" },
{ id: "moss", name: "苔色", bg: "#8a8a48", ink: "#1a1612" },
{ id: "ink", name: "墨色", bg: "#2a2520", ink: "#d4b56a" },
{ id: "gold", name: "金粉", bg: "#caa55a", ink: "#1a1612" },
];
// === Paper textures (overlay patterns) ===
const PAPER_TEXTURES = [
{ id: "plain", name: "素", svg: null },
{ id: "cloud", name: "祥云", svg: "cloud" },
{ id: "gold", name: "洒金", svg: "gold-fleck" },
{ id: "wave", name: "水波", svg: "wave" },
{ id: "kikko", name: "龟甲", svg: "kikko" },
{ id: "bamboo", name: "竹叶", svg: "bamboo" },
{ id: "blossom", name: "梅花", svg: "blossom" },
{ id: "fibers", name: "纸纹", svg: "fibers" },
];
// === Fonts (calligraphy styles) ===
const FONTS = [
{ id: "kai", name: "楷书", family: '"Noto Serif SC", serif', weight: 600 },
{ id: "song", name: "宋体", family: '"Noto Serif SC", serif', weight: 700 },
{ id: "xing", name: "行书", family: '"Ma Shan Zheng", cursive', weight: 400 },
{ id: "cao", name: "草书", family: '"Long Cang", cursive', weight: 400 },
{ id: "caoZhi", name: "狂草", family: '"Zhi Mang Xing", cursive', weight: 400 },
{ id: "li", name: "隶书", family: '"ZCOOL XiaoWei", serif', weight: 400 },
{ id: "zhuan", name: "篆书", family: '"ZCOOL QingKe HuangYou", serif', weight: 400 },
{ id: "shou", name: "瘦金", family: '"ZCOOL XiaoWei", serif', weight: 300, letterSpacing: "-0.02em" },
{ id: "maocao", name: "毛草", family: '"Liu Jian Mao Cao", cursive', weight: 400 },
];
// === Shapes ===
// Each shape returns {aspectRatio, clipPath, isRound, defaultVertical}
const SHAPES = {
"rect-v": { name: "竖长条", ar: 0.28, defaultVertical: true, clip: null },
"rect-h": { name: "横长条", ar: 3.6, defaultVertical: false, clip: null },
"square": { name: "方胜", ar: 1, defaultVertical: false, clip: null },
"diamond": { name: "菱形", ar: 1, defaultVertical: false, clip: "polygon(50% 0, 100% 50%, 50% 100%, 0 50%)" },
"circle": { name: "圆福", ar: 1, defaultVertical: false, clip: "circle(50% at 50% 50%)" },
"coin": { name: "铜钱", ar: 1, defaultVertical: false, clip: "circle(50% at 50% 50%)", innerHole: true },
"gourd": { name: "葫芦", ar: 0.66, defaultVertical: true, clip: "path('M50 5 C30 5, 28 20, 32 32 C36 42, 22 48, 22 65 C22 85, 78 85, 78 65 C78 48, 64 42, 68 32 C72 20, 70 5, 50 5 Z')", clipSvgViewBox: "0 0 100 100" },
"flower": { name: "花瓣", ar: 1, defaultVertical: false, clip: "flower" },
"pouch": { name: "福袋", ar: 0.85, defaultVertical: false, clip: "pouch" },
"tall": { name: "细长条", ar: 0.18, defaultVertical: true, clip: null },
};
// Patterns are inline SVG data URLs
function makePatternUrl(kind, color = "#000", opacity = 0.4) {
const c = encodeURIComponent(color);
const a = opacity;
let svg = "";
switch (kind) {
case "cloud":
svg = ``;
break;
case "wave":
svg = ``;
break;
case "kikko":
svg = ``;
break;
case "bamboo":
svg = ``;
break;
case "blossom":
svg = ``;
break;
case "fibers":
svg = ``;
break;
case "gold-fleck":
// gold flecks rendered separately, handled by gold-fleck layer
return null;
default:
return null;
}
return `url("data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}")`;
}
function makeGoldFleckSvg(seed = 0, density = 30) {
// Deterministic random based on seed
let s = seed * 9301 + 49297;
const rand = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };
const flecks = [];
for (let i = 0; i < density; i++) {
const x = rand() * 100;
const y = rand() * 100;
const r = 0.4 + rand() * 1.2;
const op = 0.4 + rand() * 0.5;
flecks.push(`