Skip to content

Commit 383ef9a

Browse files
committed
feat(skills): upgrade codingcat-media-studio for Gemini App Avatar + Style + 6-part Excalidraw diagram mechanics
1 parent deacd6d commit 383ef9a

5 files changed

Lines changed: 281 additions & 147 deletions

File tree

‎scripts/bundle-gemini-skills.ts‎

Lines changed: 89 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
/**
22
* Bundles CodingCat.dev skills (SKILL.md + all references/*.md + tokens/tokens.json)
3-
* into standalone Markdown bundle files in dist/gemini-web-skills/ so they can be
4-
* pasted or uploaded directly into Gemini Web Saved Skills / Gems.
3+
* into standalone Markdown bundle files (.bundle.md) AND uploadable Gemini App
4+
* Skill archives (.skill.zip) in dist/gemini-web-skills/.
55
*
66
* Usage:
77
* node --experimental-strip-types scripts/bundle-gemini-skills.ts
88
*/
99

10-
import { mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
10+
import { execFileSync } from "node:child_process";
11+
import { mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
1112
import { dirname, join, resolve } from "node:path";
1213
import { fileURLToPath } from "node:url";
1314

@@ -18,66 +19,95 @@ const SKILLS_DIR = join(REPO_ROOT, "skills");
1819
const TOKENS_DIR = join(REPO_ROOT, "tokens");
1920
const OUT_DIR = join(REPO_ROOT, "dist", "gemini-web-skills");
2021

22+
const GEMINI_STYLE_PRESET = `Always render visuals and copy in the CodingCat.dev Dark Whiteboard & Studio aesthetic:
23+
1. Dark Whiteboard Diagram Canvas: Flat 2D pure black (#000000) background with a faint dark gray (#212121) 20px technical gridline pattern. Zero 3D perspective, zero isometric angles, zero glossy bevels or drop shadows on diagram boxes.
24+
2. Hand-Drawn Diagram Mechanics (Rough.js / Excalidraw look): Every diagram box, document card (with folded top-right corner), and boundary container is drawn with TWO slightly offset, overlapping, hand-drawn sketchy white or soft lavender marker strokes (double-stroked wobble). Box interiors use visible 45-degree diagonal parallel marker hatch lines (hachure cross-hatching) in deep purple, dark slate, or brand orange, never solid gradients.
25+
3. Diagram Layout & Labels: Maximum 3 to 5 boxes flowing left-to-right connected by thick, sketchy, double-stroked white hand-drawn arrows. Left cluster shows the old painful anti-pattern slashed with a large sketchy Coral Red X mark and an ALL-CAPS marker caption (e.g., "DUPLICATES"). Right cluster shows the modern pattern topped with a bright sketchy Electric Lime / Mint Green checkmark and an ALL-CAPS marker caption (e.g., "DYNAMIC"). All text uses clean, legible white hand-drawn marker handwriting (Virgil font style), strictly 1 to 3 words per box. Never print hex codes as text on the image.
26+
4. Presenter Likeness (@alex.patterson): When a presenter cutout or video is requested, depict Alex Patterson (Caucasian man in his mid-40s, short styled light-brown hair, warm blue-green eyes, neatly trimmed salt-and-pepper beard, NO glasses, black crew-neck t-shirt, sleek round black Pixel Watch on left wrist, bare right wrist, no rings). In 16:9 thumbnails, lock Alex strictly to the Left Third or Right Third with a colored sketch rim-light, ensuring zero overlap with any diagram boxes or text.
27+
5. Editorial Voice: Direct, pragmatic Senior Solutions Engineer tone. Never use em-dashes anywhere. Always use Markdown tables when comparing two or more tools, frameworks, or architectural patterns.
28+
`;
29+
2130
function bundleSkill(skillName: string): string {
22-
const skillPath = join(SKILLS_DIR, skillName);
23-
const skillMdPath = join(skillPath, "SKILL.md");
24-
const refsDir = join(skillPath, "references");
25-
26-
const parts: string[] = [];
27-
parts.push(`<!-- Bundled Gemini Web Skill: ${skillName} -->`);
28-
parts.push(readFileSync(skillMdPath, "utf8").trim());
29-
30-
if (statSync(refsDir, { throwIfNoEntry: false })?.isDirectory()) {
31-
const refFiles = readdirSync(refsDir)
32-
.filter((f) => f.endsWith(".md"))
33-
.sort();
34-
35-
for (const refFile of refFiles) {
36-
const refContent = readFileSync(join(refsDir, refFile), "utf8").trim();
37-
parts.push(`\n---\n\n<!-- Reference: references/${refFile} -->\n\n${refContent}`);
38-
}
39-
}
40-
41-
if (skillName === "codingcat-design-system") {
42-
const tokensJsonPath = join(TOKENS_DIR, "tokens.json");
43-
const themeCssPath = join(TOKENS_DIR, "theme.css");
44-
if (statSync(tokensJsonPath, { throwIfNoEntry: false })?.isFile()) {
45-
parts.push(
46-
`\n---\n\n## Bundled W3C Design Tokens (tokens/tokens.json)\n\n\`\`\`json\n${readFileSync(tokensJsonPath, "utf8").trim()}\n\`\`\``
47-
);
48-
}
49-
if (statSync(themeCssPath, { throwIfNoEntry: false })?.isFile()) {
50-
parts.push(
51-
`\n---\n\n## Bundled Tailwind CSS v4 Theme (tokens/theme.css)\n\n\`\`\`css\n${readFileSync(themeCssPath, "utf8").trim()}\n\`\`\``
52-
);
53-
}
54-
}
55-
56-
return `${parts.join("\n")}\n`;
31+
const skillPath = join(SKILLS_DIR, skillName);
32+
const skillMdPath = join(skillPath, "SKILL.md");
33+
const refsDir = join(skillPath, "references");
34+
35+
const parts: string[] = [];
36+
parts.push(`<!-- Bundled Gemini Web Skill: ${skillName} -->`);
37+
parts.push(readFileSync(skillMdPath, "utf8").trim());
38+
39+
if (statSync(refsDir, { throwIfNoEntry: false })?.isDirectory()) {
40+
const refFiles = readdirSync(refsDir)
41+
.filter((f) => f.endsWith(".md"))
42+
.sort();
43+
44+
for (const refFile of refFiles) {
45+
const refContent = readFileSync(join(refsDir, refFile), "utf8").trim();
46+
parts.push(
47+
`\n---\n\n<!-- Reference: references/${refFile} -->\n\n${refContent}`,
48+
);
49+
}
50+
}
51+
52+
if (skillName === "codingcat-design-system") {
53+
const tokensJsonPath = join(TOKENS_DIR, "tokens.json");
54+
const themeCssPath = join(TOKENS_DIR, "theme.css");
55+
if (statSync(tokensJsonPath, { throwIfNoEntry: false })?.isFile()) {
56+
parts.push(
57+
`\n---\n\n## Bundled W3C Design Tokens (tokens/tokens.json)\n\n\`\`\`json\n${readFileSync(tokensJsonPath, "utf8").trim()}\n\`\`\``,
58+
);
59+
}
60+
if (statSync(themeCssPath, { throwIfNoEntry: false })?.isFile()) {
61+
parts.push(
62+
`\n---\n\n## Bundled Tailwind CSS v4 Theme (tokens/theme.css)\n\n\`\`\`css\n${readFileSync(themeCssPath, "utf8").trim()}\n\`\`\``,
63+
);
64+
}
65+
}
66+
67+
return `${parts.join("\n")}\n`;
68+
}
69+
70+
function zipSkill(skillName: string): void {
71+
const skillPath = join(SKILLS_DIR, skillName);
72+
const zipOutFile = join(OUT_DIR, `${skillName}.skill.zip`);
73+
rmSync(zipOutFile, { force: true });
74+
try {
75+
execFileSync("zip", ["-rq", zipOutFile, "SKILL.md", "references"], {
76+
cwd: skillPath,
77+
});
78+
console.log(`[bundle-gemini-skills] Wrote ${zipOutFile}`);
79+
} catch (err) {
80+
console.warn(`[bundle-gemini-skills] Could not zip ${skillName}:`, err);
81+
}
5782
}
5883

5984
function main(): void {
60-
mkdirSync(OUT_DIR, { recursive: true });
61-
62-
const skills = readdirSync(SKILLS_DIR).filter((name) =>
63-
statSync(join(SKILLS_DIR, name)).isDirectory()
64-
);
65-
66-
const masterParts: string[] = [
67-
"# CodingCat.dev Complete Agent Toolkit Bundle (Gemini Web Master Skill)\n",
68-
];
69-
70-
for (const skill of skills) {
71-
const bundled = bundleSkill(skill);
72-
const outFile = join(OUT_DIR, `${skill}.bundle.md`);
73-
writeFileSync(outFile, bundled, "utf8");
74-
masterParts.push(bundled);
75-
console.log(`[bundle-gemini-skills] Wrote ${outFile}`);
76-
}
77-
78-
const masterOutFile = join(OUT_DIR, "codingcatdev-complete-toolkit.bundle.md");
79-
writeFileSync(masterOutFile, masterParts.join("\n\n===\n\n"), "utf8");
80-
console.log(`[bundle-gemini-skills] Wrote master bundle ${masterOutFile}`);
85+
mkdirSync(OUT_DIR, { recursive: true });
86+
87+
const skills = readdirSync(SKILLS_DIR).filter((name) =>
88+
statSync(join(SKILLS_DIR, name)).isDirectory(),
89+
);
90+
91+
const masterParts: string[] = [
92+
"# CodingCat.dev Complete Agent Toolkit Bundle (Gemini Web Master Skill)\n",
93+
];
94+
95+
for (const skill of skills) {
96+
const bundled = bundleSkill(skill);
97+
const outFile = join(OUT_DIR, `${skill}.bundle.md`);
98+
writeFileSync(outFile, bundled, "utf8");
99+
zipSkill(skill);
100+
masterParts.push(bundled);
101+
console.log(`[bundle-gemini-skills] Wrote ${outFile}`);
102+
}
103+
104+
const masterOutFile = join(OUT_DIR, "codingcatdev-complete-toolkit.bundle.md");
105+
writeFileSync(masterOutFile, masterParts.join("\n\n===\n\n"), "utf8");
106+
console.log(`[bundle-gemini-skills] Wrote master bundle ${masterOutFile}`);
107+
108+
const styleOutFile = join(OUT_DIR, "codingcat-gemini-style.txt");
109+
writeFileSync(styleOutFile, GEMINI_STYLE_PRESET, "utf8");
110+
console.log(`[bundle-gemini-skills] Wrote Gemini Style preset ${styleOutFile}`);
81111
}
82112

83113
main();
Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,35 @@
11
---
22
name: codingcat-media-studio
3-
description: Visual and video generation rules for CodingCat.dev, including 2D upright bipedal and 3D vinyl-toy AJ the Cat mascot prompts, hand-drawn architecture diagrams, 16:9 YouTube thumbnails, and high-retention video intros. Activate whenever generating images, diagrams, thumbnails, or video scripts/storyboards.
3+
description: Visual and video generation rules for CodingCat.dev, including Gemini App Avatar (@alex.patterson) & Style workflows, 2D/3D AJ the Cat mascot prompts, hand-drawn dark-mode Excalidraw architecture diagrams, 16:9 YouTube thumbnails, and Veo 3.1 / Gemini App video prompts. Activate whenever generating images, diagrams, thumbnails, or video scripts/storyboards.
44
---
55

66
# CodingCat.dev Media Studio Skill
77

8-
This skill governs all visual media, mascot illustration prompts, hand-drawn architecture diagrams, YouTube thumbnails, and video production workflows for **CodingCat.dev**.
8+
This skill governs all visual media, mascot illustration prompts, hand-drawn dark-mode architecture diagrams, YouTube thumbnails, and video production workflows for **CodingCat.dev** across **Gemini App (`gemini.google.com`)**, **Google Flow (`Veo 3.1`)**, and **Google Antigravity (`agy`)**.
99

10-
## Canonical Terminology Guardrail
10+
## 1. Environment-Aware Asset & Likeness Resolution (Gemini App vs. Antigravity)
1111

12-
- In user-facing UI text, captions, and badges, always call diagrams **Diagrams**, **Visual Diagrams**, or **Architecture Diagrams** (never write the brand name `"Excalidraw"` in user-facing UI copy, and never call content `"Teardowns"` or `"Blueprints"`).
13-
- Content pillars are strictly **Courses** (made of **Lessons**), **Podcasts** (made of **Episodes**), and **Blog** (made of **Blog Posts**).
12+
Because **Gemini App (`gemini.google.com`)** uses **Avatar (`@alex.patterson`) + Styles + Skills** (rather than legacy Gems with attached photo folders), always resolve likenesses, brand marks, and styles based on the active runtime:
13+
14+
| Asset / Element | In Gemini App (`gemini.google.com`) | In Google Antigravity (`agy` Local Repo) |
15+
| :--- | :--- | :--- |
16+
| **Alex Patterson Likeness** | Invoke `@alex.patterson` (or `@codingcatthumbnails`) + always include the **Explicit Physical Likeness Lock** in the image/video prompt (mid-40s Caucasian man, short light-brown hair, blue-green eyes, trimmed salt-and-pepper beard, **NO glasses**, black crew-neck t-shirt, round black Pixel Watch on left wrist, no rings). | Read directly from `assets/alex-likeness/alex-likeness-01.jpg` .. `13.jpg` (`10.jpg`/`02.jpg` pointing left; `11.jpg` pointing right; `03.jpg`/`04.jpg` mind-blown). |
17+
| **Vendor Brand Logos (Sanity, Firebase, Amplify)** | Invoke `@sanitybrand` (or attach official white-on-black PNG) and explicitly specify: `"stepped diagonal 3-line geometric zig-zag symbol + bold serif Sanity wordmark, NEVER a red square or lightning bolt"`. | Read directly from `assets/logos/sanity-logos/Sanity-Full_logo/Sanity-Full_logo--white_on_black.png`, `assets/logos/firebase-brand-assets/`, and `assets/logos/Amplify.png`. |
18+
| **Hand-Drawn Architecture Diagrams** | Expand every diagram request into the **6-Part Zero-Shot Excalidraw Geometry Prompt** in `references/excalidraw-diagrams.md` (double-stroked wobbly white outlines, 45-degree diagonal hachure line fills, max 4-5 nodes, 2-3 word Virgil labels, zero hex code text rendered on canvas). | Use `references/excalidraw-diagrams.md` or render interactive SVG diagrams via `ExcalidrawDiagram.astro`. |
19+
| **AJ the Cat Mascot** | Use the self-contained 2D/3D anatomical prompt lock in `references/aj-mascot-prompts.md`. | Ground in `assets/AJHeadphones.png`, `assets/AJ-2D-Bipedal.jpg`, and `assets/AJ-3D-Headphones-*.jpg`. |
1420

15-
## Canonical Reference Assets
21+
## 2. Canonical Terminology Guardrail
1622

17-
Always ground multimodal image and video generation in the canonical reference files stored in `assets/`:
18-
- `assets/AJHeadphones.png`: Canonical 2D vector head-and-collar emblem of AJ wearing `"CodingCat.dev Podcast"` over-ear headphones and the pastel rainbow hexagonal `"AJ"` tag.
19-
- `assets/AJ-2D-Bipedal.jpg`: Canonical 2D flat vector full-body upright bipedal AJ standing on two legs.
20-
- `assets/AJ-3D-Headphones-Front.jpg`: Canonical 3D stylized vinyl-toy front 3/4 turnaround render on a matte black pedestal.
21-
- `assets/AJ-3D-Headphones-Left.jpg`: Canonical 3D stylized vinyl-toy left profile turnaround render.
22-
- `assets/AJ-3D-Headphones-Right.jpg`: Canonical 3D stylized vinyl-toy right profile turnaround render.
23-
- `assets/alex-likeness/alex-likeness-01.jpg` .. `assets/alex-likeness/alex-likeness-13.jpg`: Canonical `2048x2048` studio reaction & pointing portraits of **Alex Patterson** against `#000000` black (sourced from `https://photos.app.goo.gl/bmrt6shq5YKfG16SA`). Use `alex-likeness-10.jpg` or `alex-likeness-02.jpg` when Alex is placed on the right pointing left at a diagram, and `alex-likeness-11.jpg` when Alex is placed on the left pointing right at a diagram.
24-
- `assets/logos/sanity-logos/`: Canonical **Sanity** brand logos (`Sanity-Full_logo/Sanity-Full_logo--white_on_black.png`, `Sanity-Symbol/Sanity-Symbol--white_on_black.png`, `Sanity-Logotype/Sanity-Logotype--white_on_black.png`, plus SVG & light-mode variants). **CRITICAL RULE**: Always read and use these official Sanity logos (angular zig-zag symbol + serif `Sanity` wordmark). **NEVER** generate or use the legacy red/coral square `"S"` icon.
25-
- `assets/logos/firebase-brand-assets/` & `assets/logos/Amplify.png`: Official **Firebase** (Primary Lockup, Logomark, and Product Icons for Genkit, App Hosting, Data Connect, Firestore, etc.) and **AWS Amplify** brand logos.
23+
- In user-facing UI text, captions, and badges, always call diagrams **Diagrams**, **Visual Diagrams**, or **Architecture Diagrams** (never write the brand name `"Excalidraw"` in user-facing UI copy, and never call content `"Teardowns"` or `"Blueprints"`).
24+
- Content pillars are strictly **Courses** (made of **Lessons**), **Podcasts** (made of **Episodes**), and **Blog** (made of **Blog Posts**).
25+
- **Never Print Hex Codes as Visible Text**: When expanding color tokens (`#000000`, `#C5E86C`, `#FCA5A5`, `#B4A7D6`) into an image generation prompt, always instruct the image generator: `"Use these colors strictly for rendering; never write hex codes or metadata text onto the image canvas."`
2626

27-
## Reference Modules (`references/`)
27+
## 3. Reference Modules (`references/`)
2828

2929
| Reference File | Purpose |
3030
| :--- | :--- |
31-
| [`references/aj-mascot-prompts.md`](./references/aj-mascot-prompts.md) | Exact 2D upright bipedal vector prompt, 3D vinyl-toy turnaround prompt modifiers, and anatomical guardrails for AJ |
32-
| [`references/excalidraw-diagrams.md`](./references/excalidraw-diagrams.md) | Hand-drawn architecture diagram style rules, `Virgil` labels, Coral `#FCA5A5` `✗` vs. Mint `#86EFAC` `✓` checkmarks |
33-
| [`references/youtube-thumbnails.md`](./references/youtube-thumbnails.md) | 16:9 YouTube thumbnail composition, safe zones (`96px` edge, `320x120px` bottom-right clear), and 3-4 word `Nunito` display text rules |
31+
| [`references/excalidraw-diagrams.md`](./references/excalidraw-diagrams.md) | **6-Part Zero-Shot Excalidraw Prompt Expander**, Gemini App `Style` preset, Rough.js double-stroke + hachure geometry rules, and Gemini Canvas interactive SVG mode |
32+
| [`references/youtube-thumbnails.md`](./references/youtube-thumbnails.md) | 16:9 YouTube thumbnail 3-zone grid, `@alex.patterson` non-overlapping likeness lock, and brand logo rules |
33+
| [`references/google-flow-veo.md`](./references/google-flow-veo.md) | Gemini App 9:16 & 16:9 talking-head video prompts (`@alex.patterson` with synced audio) + Google Flow (Veo 3.1) 3-slot recipes |
34+
| [`references/aj-mascot-prompts.md`](./references/aj-mascot-prompts.md) | Self-contained 2D upright bipedal vector prompt and 3D vinyl-toy turnaround prompt modifiers for AJ |
3435
| [`references/youtube-intros-and-video.md`](./references/youtube-intros-and-video.md) | First-15-second retention hooks, presenter cutaway rules, lower-third plates, and 9:16 vertical Shorts safe zones |
35-
| [`references/google-flow-veo.md`](./references/google-flow-veo.md) | Google Flow (Veo 3.1) Ingredients-to-Video 3-slot casting, Frames-to-Video transitions, and Gemini App video prompts |

0 commit comments

Comments
 (0)