opencrush 0.3.15 → 0.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +121 -46
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -41872,6 +41872,7 @@ var init_llm_direct = __esm({
|
|
|
41872
41872
|
"src/llm-direct.ts"() {
|
|
41873
41873
|
PROVIDER_META = {
|
|
41874
41874
|
openai: { baseURL: "", defaultModel: "gpt-4o-mini" },
|
|
41875
|
+
xai: { baseURL: "https://api.x.ai/v1", defaultModel: "grok-4-1-fast-non-reasoning" },
|
|
41875
41876
|
deepseek: { baseURL: "https://api.deepseek.com", defaultModel: "deepseek-chat" },
|
|
41876
41877
|
qwen: { baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1", defaultModel: "qwen-max" },
|
|
41877
41878
|
kimi: { baseURL: "https://api.moonshot.cn/v1", defaultModel: "moonshot-v1-8k" },
|
|
@@ -41992,6 +41993,18 @@ var init_llm_direct = __esm({
|
|
|
41992
41993
|
requiresVPN: true,
|
|
41993
41994
|
isLocal: false
|
|
41994
41995
|
},
|
|
41996
|
+
{
|
|
41997
|
+
id: "xai",
|
|
41998
|
+
name: "xAI (Grok)",
|
|
41999
|
+
emoji: "\u26A1",
|
|
42000
|
+
tagline: "$25 free credit on signup, fast reasoning",
|
|
42001
|
+
taglineCN: "$25\u514D\u8D39\u989D\u5EA6\uFF0C\u63A8\u7406\u5FEB",
|
|
42002
|
+
keyUrl: "https://console.x.ai",
|
|
42003
|
+
keyUrlCN: "https://console.x.ai",
|
|
42004
|
+
envKey: "XAI_API_KEY",
|
|
42005
|
+
requiresVPN: true,
|
|
42006
|
+
isLocal: false
|
|
42007
|
+
},
|
|
41995
42008
|
// ── Local ──
|
|
41996
42009
|
{
|
|
41997
42010
|
id: "ollama",
|
|
@@ -127539,6 +127552,7 @@ RULES:
|
|
|
127539
127552
|
];
|
|
127540
127553
|
OPENAI_COMPAT_PROVIDERS = {
|
|
127541
127554
|
openai: { baseURL: "", defaultModel: "gpt-4o-mini" },
|
|
127555
|
+
xai: { baseURL: "https://api.x.ai/v1", defaultModel: "grok-4-1-fast-non-reasoning" },
|
|
127542
127556
|
deepseek: { baseURL: "https://api.deepseek.com", defaultModel: "deepseek-chat" },
|
|
127543
127557
|
qwen: { baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1", defaultModel: "qwen-max" },
|
|
127544
127558
|
kimi: { baseURL: "https://api.moonshot.cn/v1", defaultModel: "moonshot-v1-8k" },
|
|
@@ -127710,6 +127724,7 @@ RULES:
|
|
|
127710
127724
|
resolveApiKey(config) {
|
|
127711
127725
|
const map4 = {
|
|
127712
127726
|
openai: config.openaiApiKey,
|
|
127727
|
+
xai: config.xaiApiKey,
|
|
127713
127728
|
deepseek: config.deepseekApiKey,
|
|
127714
127729
|
qwen: config.qwenApiKey,
|
|
127715
127730
|
kimi: config.kimiApiKey,
|
|
@@ -244763,6 +244778,7 @@ async function startOpencrush() {
|
|
|
244763
244778
|
// International
|
|
244764
244779
|
anthropicApiKey: config.ANTHROPIC_API_KEY,
|
|
244765
244780
|
openaiApiKey: config.OPENAI_API_KEY,
|
|
244781
|
+
xaiApiKey: config.XAI_API_KEY,
|
|
244766
244782
|
// Chinese providers
|
|
244767
244783
|
deepseekApiKey: config.DEEPSEEK_API_KEY,
|
|
244768
244784
|
qwenApiKey: config.DASHSCOPE_API_KEY,
|
|
@@ -244948,6 +244964,7 @@ function loadConfig() {
|
|
|
244948
244964
|
// International
|
|
244949
244965
|
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
|
|
244950
244966
|
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
|
|
244967
|
+
XAI_API_KEY: process.env.XAI_API_KEY,
|
|
244951
244968
|
// Chinese providers
|
|
244952
244969
|
DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY,
|
|
244953
244970
|
DASHSCOPE_API_KEY: process.env.DASHSCOPE_API_KEY,
|
|
@@ -245012,11 +245029,11 @@ function validateConfig(config) {
|
|
|
245012
245029
|
console.log(source_default.gray(' Run "npx opencrush@latest setup" to configure, or edit .env directly'));
|
|
245013
245030
|
process.exit(1);
|
|
245014
245031
|
}
|
|
245015
|
-
const hasLLM = config.ANTHROPIC_API_KEY || config.OPENAI_API_KEY || config.DEEPSEEK_API_KEY || config.DASHSCOPE_API_KEY || config.MOONSHOT_API_KEY || config.ZHIPU_API_KEY || config.MINIMAX_API_KEY || config.LLM_PROVIDER === "ollama";
|
|
245032
|
+
const hasLLM = config.ANTHROPIC_API_KEY || config.OPENAI_API_KEY || config.XAI_API_KEY || config.DEEPSEEK_API_KEY || config.DASHSCOPE_API_KEY || config.MOONSHOT_API_KEY || config.ZHIPU_API_KEY || config.MINIMAX_API_KEY || config.LLM_PROVIDER === "ollama";
|
|
245016
245033
|
if (!hasLLM) {
|
|
245017
245034
|
console.log(source_default.red("\n \u274C No LLM API key configured"));
|
|
245018
245035
|
console.log(source_default.gray(" Add one of these to .env:"));
|
|
245019
|
-
console.log(source_default.gray(" ANTHROPIC_API_KEY / OPENAI_API_KEY / DEEPSEEK_API_KEY"));
|
|
245036
|
+
console.log(source_default.gray(" ANTHROPIC_API_KEY / OPENAI_API_KEY / XAI_API_KEY / DEEPSEEK_API_KEY"));
|
|
245020
245037
|
console.log(source_default.gray(" DASHSCOPE_API_KEY / MOONSHOT_API_KEY / ZHIPU_API_KEY / MINIMAX_API_KEY"));
|
|
245021
245038
|
console.log(source_default.gray(" Or set LLM_PROVIDER=ollama for local inference"));
|
|
245022
245039
|
process.exit(1);
|
|
@@ -245115,7 +245132,7 @@ function maybeOpenCard(name) {
|
|
|
245115
245132
|
}
|
|
245116
245133
|
function generateEnvFile(values) {
|
|
245117
245134
|
const sections = {
|
|
245118
|
-
"# \u2500\u2500 AI Provider \u2500\u2500": ["LLM_PROVIDER", "LLM_MODEL", "ANTHROPIC_API_KEY", "OPENAI_API_KEY", "DEEPSEEK_API_KEY", "DASHSCOPE_API_KEY", "MOONSHOT_API_KEY", "ZHIPU_API_KEY", "MINIMAX_API_KEY", "OLLAMA_BASE_URL", "OLLAMA_MODEL", "JINA_API_KEY"],
|
|
245135
|
+
"# \u2500\u2500 AI Provider \u2500\u2500": ["LLM_PROVIDER", "LLM_MODEL", "ANTHROPIC_API_KEY", "OPENAI_API_KEY", "XAI_API_KEY", "DEEPSEEK_API_KEY", "DASHSCOPE_API_KEY", "MOONSHOT_API_KEY", "ZHIPU_API_KEY", "MINIMAX_API_KEY", "OLLAMA_BASE_URL", "OLLAMA_MODEL", "JINA_API_KEY"],
|
|
245119
245136
|
"# \u2500\u2500 Character \u2500\u2500": ["CHARACTER_NAME"],
|
|
245120
245137
|
"# \u2500\u2500 Messaging Platforms \u2500\u2500": ["DISCORD_BOT_TOKEN", "DISCORD_OWNER_ID", "DISCORD_CLIENT_ID", "TELEGRAM_BOT_TOKEN", "TELEGRAM_OWNER_ID", "WHATSAPP_ENABLED"],
|
|
245121
245138
|
"# \u2500\u2500 Media (Selfies, Voice, Video) \u2500\u2500": ["FAL_KEY", "IMAGE_MODEL", "IMAGE_REFERENCE_MODEL", "TTS_PROVIDER", "ELEVENLABS_API_KEY", "ELEVENLABS_VOICE_ID", "FISH_AUDIO_API_KEY", "FISH_AUDIO_VOICE_ID"],
|
|
@@ -245185,6 +245202,7 @@ async function runSetupWizard() {
|
|
|
245185
245202
|
const providerChoices = [
|
|
245186
245203
|
PROVIDER_INFO.find((p2) => p2.id === "anthropic"),
|
|
245187
245204
|
PROVIDER_INFO.find((p2) => p2.id === "openai"),
|
|
245205
|
+
PROVIDER_INFO.find((p2) => p2.id === "xai"),
|
|
245188
245206
|
PROVIDER_INFO.find((p2) => p2.id === "deepseek"),
|
|
245189
245207
|
PROVIDER_INFO.find((p2) => p2.id === "qwen"),
|
|
245190
245208
|
PROVIDER_INFO.find((p2) => p2.id === "kimi"),
|
|
@@ -245217,6 +245235,8 @@ async function runSetupWizard() {
|
|
|
245217
245235
|
console.log(source_default.gray(' Sign up \u2192 API Keys \u2192 Create Key \u2192 copy the key (starts with "sk-ant-")\n'));
|
|
245218
245236
|
} else if (llmProvider === "openai") {
|
|
245219
245237
|
console.log(source_default.gray(" Sign up \u2192 API Keys \u2192 Create new secret key\n"));
|
|
245238
|
+
} else if (llmProvider === "xai") {
|
|
245239
|
+
console.log(source_default.gray(" Sign up \u2192 get $25 free credit \u2192 copy API key\n"));
|
|
245220
245240
|
} else if (llmProvider === "deepseek") {
|
|
245221
245241
|
console.log(source_default.gray(" Sign up \u2192 API Keys \u2192 Create key (new users get free credits)\n"));
|
|
245222
245242
|
}
|
|
@@ -245591,74 +245611,122 @@ __export(card_exports, {
|
|
|
245591
245611
|
generateCard: () => generateCard
|
|
245592
245612
|
});
|
|
245593
245613
|
function parseIdentity(identityPath) {
|
|
245594
|
-
var _a3, _b2, _c, _d;
|
|
245614
|
+
var _a3, _b2, _c, _d, _e2;
|
|
245595
245615
|
const raw = (0, import_fs18.readFileSync)(identityPath, "utf-8");
|
|
245596
245616
|
const { content } = (0, import_gray_matter3.default)(raw);
|
|
245597
245617
|
const nameMatch = content.match(/^#\s+(.+)$/m);
|
|
245598
245618
|
const name = ((_a3 = nameMatch == null ? void 0 : nameMatch[1]) == null ? void 0 : _a3.trim()) ?? "Unknown";
|
|
245599
245619
|
const ageMatch = content.match(/\*\*Age:\*\*\s*(\d+)/i);
|
|
245600
|
-
const age = (ageMatch == null ? void 0 : ageMatch[1]) ?? "
|
|
245620
|
+
const age = (ageMatch == null ? void 0 : ageMatch[1]) ?? "";
|
|
245601
245621
|
const fromMatch = content.match(/\*\*From:\*\*\s*(.+)/i);
|
|
245602
|
-
const locationRaw = ((_b2 = fromMatch == null ? void 0 : fromMatch[1]) == null ? void 0 : _b2.trim()) ?? "
|
|
245603
|
-
const location = locationRaw.replace(/\s*\(.*\)/, "").split(" \u2014 ")[0].trim();
|
|
245622
|
+
const locationRaw = ((_b2 = fromMatch == null ? void 0 : fromMatch[1]) == null ? void 0 : _b2.trim()) ?? "";
|
|
245623
|
+
const location = locationRaw.replace(/\s*\(.*\)/, "").split(" \u2014 ")[0].split(" - ")[0].trim();
|
|
245624
|
+
const cleanLocation = location.length > 40 || location.toLowerCase().startsWith("says ") ? "" : location;
|
|
245604
245625
|
const hobbiesMatch = content.match(/\*\*Hobbies:\*\*\s*(.+)/i);
|
|
245605
245626
|
const hobbiesRaw = (hobbiesMatch == null ? void 0 : hobbiesMatch[1]) ?? "";
|
|
245606
|
-
const tags = hobbiesRaw.
|
|
245607
|
-
const
|
|
245608
|
-
|
|
245627
|
+
const tags = splitRespectingParens(hobbiesRaw).map((t2) => t2.trim()).filter(Boolean).map((t2) => t2.length > 25 ? t2.split(/[,(]/)[0].trim() : t2).filter((t2) => t2.length > 1 && t2.length <= 25).slice(0, 6);
|
|
245628
|
+
const soulPath = identityPath.replace("IDENTITY.md", "SOUL.md");
|
|
245629
|
+
let description = "";
|
|
245630
|
+
if ((0, import_fs18.existsSync)(soulPath)) {
|
|
245631
|
+
const soul = (0, import_fs18.readFileSync)(soulPath, "utf-8");
|
|
245632
|
+
const vibeLine = soul.split("\n").find((l2) => l2.trim() && !l2.startsWith("#") && !l2.startsWith("-"));
|
|
245633
|
+
if (vibeLine) {
|
|
245634
|
+
description = ((_c = vibeLine.trim().split(".")[0]) == null ? void 0 : _c.trim()) ?? "";
|
|
245635
|
+
}
|
|
245636
|
+
}
|
|
245637
|
+
if (!description) {
|
|
245638
|
+
const bgMatch = content.match(/## (?:Background|Appearance)\s*\n+(.+)/i);
|
|
245639
|
+
description = ((_e2 = (_d = bgMatch == null ? void 0 : bgMatch[1]) == null ? void 0 : _d.trim().split(".")[0]) == null ? void 0 : _e2.trim()) ?? "";
|
|
245640
|
+
}
|
|
245609
245641
|
const { data: meta } = (0, import_gray_matter3.default)(raw);
|
|
245610
245642
|
const gender = meta.gender ?? "female";
|
|
245611
|
-
return { name, age, location, tags, description, gender };
|
|
245643
|
+
return { name, age, location: cleanLocation, tags, description, gender };
|
|
245644
|
+
}
|
|
245645
|
+
function splitRespectingParens(str2) {
|
|
245646
|
+
const result = [];
|
|
245647
|
+
let depth = 0;
|
|
245648
|
+
let current = "";
|
|
245649
|
+
for (const ch of str2) {
|
|
245650
|
+
if (ch === "(") depth++;
|
|
245651
|
+
else if (ch === ")") depth--;
|
|
245652
|
+
if (ch === "," && depth === 0) {
|
|
245653
|
+
result.push(current);
|
|
245654
|
+
current = "";
|
|
245655
|
+
} else {
|
|
245656
|
+
current += ch;
|
|
245657
|
+
}
|
|
245658
|
+
}
|
|
245659
|
+
if (current) result.push(current);
|
|
245660
|
+
return result;
|
|
245661
|
+
}
|
|
245662
|
+
async function sampleGradientFromImage(imagePath) {
|
|
245663
|
+
try {
|
|
245664
|
+
const sharp = (await import("sharp")).default;
|
|
245665
|
+
const { data, info } = await sharp(imagePath).resize(1, 1, { fit: "cover" }).raw().toBuffer({ resolveWithObject: true });
|
|
245666
|
+
const r2 = data[0], g2 = data[1], b2 = data[2];
|
|
245667
|
+
const darken = (v2, f2) => Math.round(v2 * f2);
|
|
245668
|
+
const from2 = `rgb(${darken(r2, 0.25)}, ${darken(g2, 0.25)}, ${darken(b2, 0.25)})`;
|
|
245669
|
+
const to = `rgb(${darken(r2, 0.12)}, ${darken(g2, 0.12)}, ${darken(b2, 0.12)})`;
|
|
245670
|
+
return { from: from2, to };
|
|
245671
|
+
} catch {
|
|
245672
|
+
return { from: "#1a1a2e", to: "#0f0f1a" };
|
|
245673
|
+
}
|
|
245612
245674
|
}
|
|
245613
245675
|
function pickGradient(name) {
|
|
245614
245676
|
const gradients = [
|
|
245615
|
-
{ from: "#1a1a2e", to: "#
|
|
245677
|
+
{ from: "#1a1a2e", to: "#0f0f1a" },
|
|
245616
245678
|
// deep navy
|
|
245617
|
-
{ from: "#2d1b3d", to: "#
|
|
245679
|
+
{ from: "#2d1b3d", to: "#150d1e" },
|
|
245618
245680
|
// purple-dark
|
|
245619
|
-
{ from: "#1b2d2d", to: "#
|
|
245681
|
+
{ from: "#1b2d2d", to: "#0a1414" },
|
|
245620
245682
|
// teal-dark
|
|
245621
|
-
{ from: "#2d1b1b", to: "#
|
|
245683
|
+
{ from: "#2d1b1b", to: "#140d0d" },
|
|
245622
245684
|
// warm dark
|
|
245623
|
-
{ from: "#
|
|
245624
|
-
//
|
|
245625
|
-
{ from: "#
|
|
245685
|
+
{ from: "#1a1a30", to: "#0d0d18" },
|
|
245686
|
+
// midnight
|
|
245687
|
+
{ from: "#2d241b", to: "#14120d" }
|
|
245626
245688
|
// amber dark
|
|
245627
245689
|
];
|
|
245628
245690
|
const hash = name.split("").reduce((acc, ch) => acc + ch.charCodeAt(0), 0);
|
|
245629
245691
|
return gradients[hash % gradients.length];
|
|
245630
245692
|
}
|
|
245631
245693
|
function createSvgOverlay(data, gradient) {
|
|
245632
|
-
const
|
|
245633
|
-
const
|
|
245634
|
-
const
|
|
245635
|
-
const
|
|
245636
|
-
const
|
|
245694
|
+
const S2 = SCALE;
|
|
245695
|
+
const textX = PORTRAIT_X + PORTRAIT_SIZE + 50 * S2;
|
|
245696
|
+
const maxTagX = WIDTH - 40 * S2;
|
|
245697
|
+
const nameY = 200 * S2;
|
|
245698
|
+
const metaY = nameY + 44 * S2;
|
|
245699
|
+
const tagStartY = metaY + 48 * S2;
|
|
245700
|
+
const metaParts = [data.age, data.location].filter(Boolean);
|
|
245701
|
+
const metaText = metaParts.length > 0 ? metaParts.join(" \xB7 ") : "";
|
|
245637
245702
|
let inlineTags = "";
|
|
245638
245703
|
let offsetX = textX;
|
|
245639
245704
|
let rowY = tagStartY;
|
|
245640
|
-
const rowHeight =
|
|
245705
|
+
const rowHeight = 28 * S2;
|
|
245641
245706
|
const maxRows = 2;
|
|
245642
245707
|
let currentRow = 1;
|
|
245643
245708
|
for (const tag of data.tags) {
|
|
245644
|
-
const label = tag.length >
|
|
245645
|
-
const w2 = label.length * 7.
|
|
245709
|
+
const label = tag.length > 20 ? tag.slice(0, 19) + "\u2026" : tag;
|
|
245710
|
+
const w2 = label.length * 7.2 * S2 + 14 * S2;
|
|
245646
245711
|
if (offsetX + w2 > maxTagX) {
|
|
245647
245712
|
if (currentRow >= maxRows) break;
|
|
245648
245713
|
currentRow++;
|
|
245649
245714
|
offsetX = textX;
|
|
245650
245715
|
rowY += rowHeight;
|
|
245651
245716
|
}
|
|
245717
|
+
const bubbleH = 22 * S2;
|
|
245718
|
+
const bubbleR = 11 * S2;
|
|
245652
245719
|
inlineTags += `
|
|
245653
|
-
<rect x="${offsetX}" y="${rowY -
|
|
245654
|
-
<text x="${offsetX +
|
|
245720
|
+
<rect x="${offsetX}" y="${rowY - 13 * S2}" width="${w2}" height="${bubbleH}" rx="${bubbleR}" fill="rgba(255,255,255,0.08)" />
|
|
245721
|
+
<text x="${offsetX + 7 * S2}" y="${rowY + 2 * S2}" font-family="system-ui, -apple-system, sans-serif" font-size="${11 * S2}" fill="#b0b0b0">${escapeXml(label)}</text>
|
|
245655
245722
|
`;
|
|
245656
|
-
offsetX += w2 + 6;
|
|
245723
|
+
offsetX += w2 + 6 * S2;
|
|
245657
245724
|
}
|
|
245658
|
-
const descriptionY = tagStartY + currentRow * rowHeight +
|
|
245725
|
+
const descriptionY = tagStartY + currentRow * rowHeight + 16 * S2;
|
|
245726
|
+
const barH = 40 * S2;
|
|
245659
245727
|
return `<svg width="${WIDTH}" height="${HEIGHT}" xmlns="http://www.w3.org/2000/svg">
|
|
245660
245728
|
<defs>
|
|
245661
|
-
<linearGradient id="bg" x1="0" y1="0" x2="
|
|
245729
|
+
<linearGradient id="bg" x1="0" y1="0" x2="0.5" y2="1">
|
|
245662
245730
|
<stop offset="0%" stop-color="${gradient.from}" />
|
|
245663
245731
|
<stop offset="100%" stop-color="${gradient.to}" />
|
|
245664
245732
|
</linearGradient>
|
|
@@ -245669,19 +245737,25 @@ function createSvgOverlay(data, gradient) {
|
|
|
245669
245737
|
|
|
245670
245738
|
<rect width="${WIDTH}" height="${HEIGHT}" fill="url(#bg)" />
|
|
245671
245739
|
|
|
245672
|
-
|
|
245740
|
+
<!-- Portrait ring -->
|
|
245741
|
+
<circle cx="${PORTRAIT_X + PORTRAIT_SIZE / 2}" cy="${PORTRAIT_Y + PORTRAIT_SIZE / 2}" r="${PORTRAIT_SIZE / 2 + 2 * S2}" fill="none" stroke="rgba(255,255,255,0.10)" stroke-width="${2 * S2}" />
|
|
245673
245742
|
|
|
245674
|
-
|
|
245743
|
+
<!-- Name -->
|
|
245744
|
+
<text x="${textX}" y="${nameY}" font-family="system-ui, -apple-system, sans-serif" font-size="${42 * S2}" font-weight="bold" fill="white">${escapeXml(data.name)}</text>
|
|
245675
245745
|
|
|
245676
|
-
|
|
245746
|
+
<!-- Age \xB7 Location -->
|
|
245747
|
+
${metaText ? `<text x="${textX}" y="${metaY}" font-family="system-ui, -apple-system, sans-serif" font-size="${15 * S2}" fill="#999">${escapeXml(truncate(metaText, 40))}</text>` : ""}
|
|
245677
245748
|
|
|
245749
|
+
<!-- Tags -->
|
|
245678
245750
|
${inlineTags}
|
|
245679
245751
|
|
|
245680
|
-
|
|
245752
|
+
<!-- Description -->
|
|
245753
|
+
${data.description ? `<text x="${textX}" y="${descriptionY}" font-family="system-ui, -apple-system, sans-serif" font-size="${13 * S2}" fill="#888" font-style="italic">${escapeXml(truncate(data.description, 55))}</text>` : ""}
|
|
245681
245754
|
|
|
245682
|
-
|
|
245683
|
-
<
|
|
245684
|
-
<text x="${
|
|
245755
|
+
<!-- Bottom bar -->
|
|
245756
|
+
<rect x="0" y="${HEIGHT - barH}" width="${WIDTH}" height="${barH}" fill="rgba(0,0,0,0.25)" />
|
|
245757
|
+
<text x="${36 * S2}" y="${HEIGHT - 14 * S2}" font-family="system-ui, -apple-system, sans-serif" font-size="${13 * S2}" font-weight="bold" fill="#ff69b4">Opencrush</text>
|
|
245758
|
+
<text x="${WIDTH - 36 * S2}" y="${HEIGHT - 14 * S2}" font-family="system-ui, -apple-system, sans-serif" font-size="${11 * S2}" fill="#666" text-anchor="end">github.com/Hollandchirs/Opencrush</text>
|
|
245685
245759
|
</svg>`;
|
|
245686
245760
|
}
|
|
245687
245761
|
function escapeXml(str2) {
|
|
@@ -245702,7 +245776,6 @@ async function generateCard(characterName) {
|
|
|
245702
245776
|
throw new Error(`Missing IDENTITY.md for character "${characterName}"`);
|
|
245703
245777
|
}
|
|
245704
245778
|
const data = parseIdentity(identityPath);
|
|
245705
|
-
const gradient = pickGradient(data.name);
|
|
245706
245779
|
const imageExts = [".jpeg", ".jpg", ".png", ".webp"];
|
|
245707
245780
|
let refImagePath;
|
|
245708
245781
|
for (const ext of imageExts) {
|
|
@@ -245712,6 +245785,7 @@ async function generateCard(characterName) {
|
|
|
245712
245785
|
break;
|
|
245713
245786
|
}
|
|
245714
245787
|
}
|
|
245788
|
+
const gradient = refImagePath ? await sampleGradientFromImage(refImagePath) : pickGradient(data.name);
|
|
245715
245789
|
const svgOverlay = createSvgOverlay(data, gradient);
|
|
245716
245790
|
const svgBuffer = Buffer.from(svgOverlay);
|
|
245717
245791
|
let card = sharp(svgBuffer, { density: 300 }).resize(WIDTH, HEIGHT);
|
|
@@ -245734,22 +245808,23 @@ async function generateCard(characterName) {
|
|
|
245734
245808
|
await card.png().toFile(outputPath);
|
|
245735
245809
|
console.log(source_default.green(`
|
|
245736
245810
|
Card generated: characters/${characterName}/card.png`));
|
|
245737
|
-
console.log(source_default.gray(` ${WIDTH}x${HEIGHT} PNG
|
|
245811
|
+
console.log(source_default.gray(` ${WIDTH}x${HEIGHT} PNG (2x retina)
|
|
245738
245812
|
`));
|
|
245739
245813
|
return outputPath;
|
|
245740
245814
|
}
|
|
245741
|
-
var import_fs18, import_path12, import_gray_matter3, WIDTH, HEIGHT, PORTRAIT_SIZE, PORTRAIT_X, PORTRAIT_Y;
|
|
245815
|
+
var import_fs18, import_path12, import_gray_matter3, SCALE, WIDTH, HEIGHT, PORTRAIT_SIZE, PORTRAIT_X, PORTRAIT_Y;
|
|
245742
245816
|
var init_card = __esm({
|
|
245743
245817
|
"src/card.ts"() {
|
|
245744
245818
|
import_fs18 = require("fs");
|
|
245745
245819
|
import_path12 = require("path");
|
|
245746
245820
|
import_gray_matter3 = __toESM(require_gray_matter());
|
|
245747
245821
|
init_source();
|
|
245748
|
-
|
|
245749
|
-
|
|
245750
|
-
|
|
245751
|
-
|
|
245752
|
-
|
|
245822
|
+
SCALE = 2;
|
|
245823
|
+
WIDTH = 1200 * SCALE;
|
|
245824
|
+
HEIGHT = 630 * SCALE;
|
|
245825
|
+
PORTRAIT_SIZE = 260 * SCALE;
|
|
245826
|
+
PORTRAIT_X = 80 * SCALE;
|
|
245827
|
+
PORTRAIT_Y = Math.round((HEIGHT - PORTRAIT_SIZE) / 2) - 10 * SCALE;
|
|
245753
245828
|
}
|
|
245754
245829
|
});
|
|
245755
245830
|
|