stacie vor 1 Monat
Commit
817bc68715

+ 69 - 0
create-less-and-cosmos-business-card/SKILL.md

@@ -0,0 +1,69 @@
+---
+name: create-less-and-cosmos-business-card
+description: Create matching minimalist, high-end, double-sided business cards for 杭州纯粹星辰人工智能科技有限公司 (Less and Cosmos) from a person's name, title, email, and phone number. Use when Codex needs to make, add, revise, preview, or export a 90×54 mm 纯粹星辰 employee business card in SVG or PNG while preserving the supplied brand logo, warm-white palette, generous whitespace, slogan, company address, and established layout.
+---
+
+# Create Less and Cosmos Business Cards
+
+Generate the card from the bundled templates; do not redraw or reinterpret the visual system unless the user explicitly requests a redesign.
+
+## Required input
+
+Collect or infer only these employee-specific fields:
+
+- Chinese name
+- Chinese title, optionally followed by an English abbreviation such as `联合创始人 / CMO`
+- Email
+- Mobile number
+
+Keep these brand fields fixed unless the user supplies corrections:
+
+- Company: `杭州纯粹星辰人工智能科技有限公司`
+- Address: `浙江省杭州市西湖区转塘街道云腾丝路中心5号楼商业208室`
+- Website: `lessncosmos.com`
+- Slogan: `构建能够持续学习与进化的企业级人工智能系统。`
+
+## Generate the card
+
+Run the bundled generator from the skill directory:
+
+```bash
+python3 scripts/generate_card.py \
+  --name "石志瑞" \
+  --title "联合创始人 / CMO" \
+  --email "shizr@lessncosmos.com" \
+  --phone "139 1051 5989" \
+  --output-dir ./output/shi-zhirui
+```
+
+The script creates:
+
+- `front.svg`: common brand front
+- `back.svg`: personalized contact side
+- `preview.html`: side-by-side browser preview
+- `card-data.json`: normalized source data for later edits
+
+Use a short lowercase Latin slug for the output directory. Preserve spaces in phone groups; the generator adds `+86` when no country code is present.
+
+## Render and verify
+
+1. Render both SVG files or open `preview.html` in a browser.
+2. Produce 1800×1080 PNG files when the user requests images or a downloadable bundle. Prefer an installed SVG renderer such as Sharp, a browser screenshot, Inkscape, or `rsvg-convert`.
+3. Visually check the preview at full size. Confirm that the email does not overflow and all Chinese glyphs render correctly.
+4. Compare every output field with `card-data.json`; never silently correct a person's name or email.
+5. Package the two SVG files, PNG files when rendered, preview, and JSON into a ZIP for sharing.
+
+## Preserve the visual system
+
+- Keep the canvas at 90×54 mm with `viewBox="0 0 1800 1080"`.
+- Keep the warm-white background `#F7F7F5`, near-black text, cool gray secondary text, and restrained gold accent `#B89652`.
+- Keep the front common across all employees.
+- Keep the employee name and title on the left of the back, contact information on the right, and company/address below the divider.
+- Maintain the generous margins and avoid adding icons, QR codes, borders, gradients, shadows, or decorative imagery unless requested.
+- Use the font fallbacks already embedded in the SVG. Do not outline text unless a print vendor requires it.
+
+For production details and delivery checks, read [references/print-specifications.md](references/print-specifications.md).
+
+## Revise an existing card
+
+Regenerate from the corrected fields instead of editing positioned text manually. Re-render and re-check the result after every data change.

+ 4 - 0
create-less-and-cosmos-business-card/agents/openai.yaml

@@ -0,0 +1,4 @@
+interface:
+  display_name: "纯粹星辰名片制作"
+  short_description: "根据人员信息生成纯粹星辰品牌的极简双面商务名片及预览文件"
+  default_prompt: "使用 $create-less-and-cosmos-business-card 根据姓名、职位、邮箱和电话生成一套双面名片。"

+ 16 - 0
create-less-and-cosmos-business-card/assets/back-template.svg

@@ -0,0 +1,16 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="90mm" height="54mm" viewBox="0 0 1800 1080" role="img" aria-labelledby="title desc">
+  <title id="title">{{NAME}}名片背面</title><desc id="desc">{{NAME}},{{TITLE}}的联系方式与公司地址。</desc>
+  <rect width="1800" height="1080" fill="#F7F7F5"/>
+  <g opacity="0.11" transform="translate(1170 52) scale(2.1)"><circle cx="12" cy="36" r="4" fill="#B89652"/><path d="M38 43C76 11 142 1 204 15C228 21 249 31 266 44" fill="none" stroke="#4E5862" stroke-width="1.15" stroke-linecap="round"/><path d="M66 49C117 31 187 28 246 45" fill="none" stroke="#0B0C10" stroke-width="0.62" stroke-linecap="round"/><circle cx="268" cy="45" r="1.35" fill="#0B0C10"/></g>
+  <circle cx="150" cy="152" r="6" fill="#B89652"/>
+  <text x="150" y="350" fill="#111318" font-family="'PingFang SC','Noto Sans SC','Source Han Sans SC','Microsoft YaHei',sans-serif" font-size="130" font-weight="300" letter-spacing="13">{{NAME}}</text>
+  <text x="156" y="435" fill="#656B72" font-family="'PingFang SC','Noto Sans SC','Source Han Sans SC','Microsoft YaHei',sans-serif" font-size="42" font-weight="400" letter-spacing="5">{{TITLE}}</text>
+  <g transform="translate(912 337)" font-family="Inter,'Helvetica Neue',Arial,sans-serif">
+    <text x="0" y="0" fill="#999DA2" font-size="22" font-weight="600" letter-spacing="4">EMAIL</text><text x="0" y="53" fill="#20242A" font-size="38" font-weight="400" letter-spacing="0.2">{{EMAIL}}</text>
+    <text x="0" y="145" fill="#999DA2" font-size="22" font-weight="600" letter-spacing="4">MOBILE</text><text x="0" y="198" fill="#20242A" font-size="38" font-weight="400" letter-spacing="1.2">{{PHONE}}</text>
+    <text x="0" y="290" fill="#999DA2" font-size="22" font-weight="600" letter-spacing="4">WEB</text><text x="0" y="343" fill="#20242A" font-size="38" font-weight="400" letter-spacing="0.5">{{WEBSITE}}</text>
+  </g>
+  <path d="M150 740H1650" stroke="#D5D6D5" stroke-width="1"/>
+  <g font-family="'PingFang SC','Noto Sans SC','Source Han Sans SC','Microsoft YaHei',sans-serif"><text x="150" y="817" fill="#2A2E34" font-size="36" font-weight="400" letter-spacing="1.3">{{COMPANY}}</text><text x="150" y="887" fill="#747A80" font-size="32" font-weight="300" letter-spacing="0.4">{{ADDRESS}}</text></g>
+  <text x="1650" y="954" text-anchor="end" fill="#A0A4A8" font-family="Inter,'Helvetica Neue',Arial,sans-serif" font-size="20" letter-spacing="4.3">LESS AND COSMOS · HANGZHOU</text>
+</svg>

+ 17 - 0
create-less-and-cosmos-business-card/assets/common-front.svg

@@ -0,0 +1,17 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="90mm" height="54mm" viewBox="0 0 1800 1080" role="img" aria-labelledby="title desc">
+  <title id="title">纯粹星辰名片正面</title><desc id="desc">品牌、企业理念和网站。</desc>
+  <rect width="1800" height="1080" fill="#F7F7F5"/>
+  <g transform="translate(146 130)"><g transform="translate(0 12) scale(0.78)">
+    <circle cx="12" cy="36" r="6" fill="#B89652"/>
+    <path d="M38 43C76 11 142 1 204 15C228 21 249 31 266 44" fill="none" stroke="#4E5862" stroke-width="3.5" stroke-linecap="round" opacity="0.78"/>
+    <path d="M66 49C117 31 187 28 246 45" fill="none" stroke="#0B0C10" stroke-width="2" stroke-linecap="round" opacity="0.26"/>
+    <circle cx="268" cy="45" r="3" fill="#0B0C10" opacity="0.76"/>
+  </g><text x="264" y="78" fill="#0B0C10" font-family="'PingFang SC','Noto Sans SC','Source Han Sans SC','Microsoft YaHei',sans-serif" font-size="72" font-weight="300" letter-spacing="20">纯粹星辰</text>
+  <text x="269" y="132" fill="#59616A" font-family="Inter,'Helvetica Neue',Arial,sans-serif" font-size="25" font-weight="300" letter-spacing="7">less and cosmos.</text></g>
+  <g transform="translate(900 386)"><circle cx="0" cy="11" r="6" fill="#B89652"/>
+    <text x="38" y="0" fill="#17191D" font-family="'PingFang SC','Noto Sans SC','Source Han Sans SC','Microsoft YaHei',sans-serif" font-size="58" font-weight="300" letter-spacing="2"><tspan x="38" dy="0">构建能够持续学习与进化的</tspan><tspan x="38" dy="92">企业级人工智能系统。</tspan></text>
+    <path d="M38 191H580" stroke="#B9BDC1" stroke-width="1"/><text x="38" y="235" fill="#7B8188" font-family="Inter,'Helvetica Neue',Arial,sans-serif" font-size="22" font-weight="400" letter-spacing="4.6">CONTINUOUSLY LEARNING AI</text>
+  </g>
+  <text x="146" y="935" fill="#4E545B" font-family="Inter,'Helvetica Neue',Arial,sans-serif" font-size="42" font-weight="400" letter-spacing="1.2">lessncosmos.com</text>
+  <path d="M146 986H1654" stroke="#D5D6D5" stroke-width="1"/><circle cx="1654" cy="986" r="4" fill="#B89652"/>
+</svg>

+ 34 - 0
create-less-and-cosmos-business-card/references/print-specifications.md

@@ -0,0 +1,34 @@
+# Print specifications
+
+## Digital master
+
+- Trim size: 90×54 mm, landscape
+- SVG viewBox: 1800×1080
+- Recommended PNG preview: 1800×1080 pixels
+- Working color space: RGB
+- Safe area: keep essential content at least 7.5 mm from the trimmed edge
+
+## Commercial printing
+
+Ask the printer to:
+
+- add 3 mm bleed on all sides, yielding a 96×60 mm production page;
+- convert the artwork to the printer's requested CMYK profile;
+- embed or outline fonts if their workflow requires it;
+- preserve the warm-white background or omit the background when printing on a matching warm-white stock;
+- optionally print the small gold accents as a restrained spot gold.
+
+Recommended finish: 350 g/m² warm-white uncoated stock with a matte, low-gloss surface.
+
+## Final content check
+
+Verify these items character by character:
+
+1. Chinese name
+2. Chinese title and English abbreviation
+3. Email
+4. Mobile number and country code
+5. Company legal name
+6. Address, including building and room number
+7. Website
+8. Slogan

+ 102 - 0
create-less-and-cosmos-business-card/scripts/generate_card.py

@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+"""Generate a Less and Cosmos double-sided employee business card."""
+
+from __future__ import annotations
+
+import argparse
+import html
+import json
+import re
+from pathlib import Path
+
+
+SKILL_DIR = Path(__file__).resolve().parent.parent
+ASSETS_DIR = SKILL_DIR / "assets"
+
+
+def clean(value: str, field: str) -> str:
+    value = " ".join(value.strip().split())
+    if not value:
+        raise ValueError(f"{field} must not be empty")
+    return value
+
+
+def normalize_phone(value: str) -> str:
+    value = clean(value, "phone")
+    value = re.sub(r"\s+", " ", value)
+    if value.startswith("+86"):
+        return value
+    if value.startswith("86 "):
+        return "+" + value
+    return "+86 " + value
+
+
+def render_template(template: str, values: dict[str, str]) -> str:
+    for key, value in values.items():
+        template = template.replace("{{" + key + "}}", html.escape(value))
+    unresolved = sorted(set(re.findall(r"\{\{([A-Z_]+)\}\}", template)))
+    if unresolved:
+        raise ValueError("Unresolved template fields: " + ", ".join(unresolved))
+    return template
+
+
+def build_preview(name: str) -> str:
+    safe_name = html.escape(name)
+    return f"""<!doctype html>
+<html lang=\"zh-CN\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">
+<title>{safe_name} · 纯粹星辰名片</title><style>
+*{{box-sizing:border-box}}body{{margin:0;background:#e9e9e7;font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif}}
+main{{width:min(1480px,94vw);margin:0 auto;padding:5vw 0}}h1{{margin:0 0 28px;color:#363a3f;font-size:18px;font-weight:500;letter-spacing:2px}}
+.pair{{display:grid;grid-template-columns:1fr 1fr;gap:30px}}figure{{margin:0}}img{{display:block;width:100%;box-shadow:0 16px 46px rgba(25,28,31,.12)}}
+figcaption{{margin-top:12px;color:#8d9297;font-size:11px;letter-spacing:2px;text-transform:uppercase}}@media(max-width:800px){{.pair{{grid-template-columns:1fr}}}}
+</style></head><body><main><h1>{safe_name} · 纯粹星辰</h1><div class=\"pair\">
+<figure><img src=\"front.svg\" alt=\"名片正面\"><figcaption>Front</figcaption></figure>
+<figure><img src=\"back.svg\" alt=\"名片背面\"><figcaption>Back</figcaption></figure>
+</div></main></body></html>"""
+
+
+def main() -> None:
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument("--name", required=True, help="Chinese name")
+    parser.add_argument("--title", required=True, help="Role, e.g. 联合创始人 / CMO")
+    parser.add_argument("--email", required=True)
+    parser.add_argument("--phone", required=True)
+    parser.add_argument("--output-dir", required=True, type=Path)
+    args = parser.parse_args()
+
+    name = clean(args.name, "name")
+    title = clean(args.title, "title")
+    email = clean(args.email, "email")
+    if "@" not in email or email.startswith("@") or email.endswith("@"):
+        raise ValueError("email does not look valid")
+    phone = normalize_phone(args.phone)
+
+    data = {
+        "name": name,
+        "title": title,
+        "email": email,
+        "phone": phone,
+        "company": "杭州纯粹星辰人工智能科技有限公司",
+        "address": "浙江省杭州市西湖区转塘街道云腾丝路中心5号楼商业208室",
+        "website": "lessncosmos.com",
+        "slogan": "构建能够持续学习与进化的企业级人工智能系统。",
+    }
+
+    args.output_dir.mkdir(parents=True, exist_ok=True)
+    (args.output_dir / "front.svg").write_text(
+        (ASSETS_DIR / "common-front.svg").read_text(encoding="utf-8"), encoding="utf-8"
+    )
+    template = (ASSETS_DIR / "back-template.svg").read_text(encoding="utf-8")
+    replacements = {key.upper(): value for key, value in data.items()}
+    (args.output_dir / "back.svg").write_text(
+        render_template(template, replacements), encoding="utf-8"
+    )
+    (args.output_dir / "preview.html").write_text(build_preview(name), encoding="utf-8")
+    (args.output_dir / "card-data.json").write_text(
+        json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
+    )
+    print(f"Created business card in {args.output_dir.resolve()}")
+
+
+if __name__ == "__main__":
+    main()