Skip to content

Commit b19141d

Browse files
afollestadclaude
andcommitted
Make watermark skill machine-agnostic and clarify ai-rules workflow
- Remove hardcoded absolute font path from watermark.py; resolve font from bundled .ttf/.ttc in skill directory or via --font flag - Improve error message to name Gingerink as the expected font - Update SKILL.md to document font setup and remove local path reference - Add rule: run `ai-rules generate` after editing any file in ai-rules/ - Add rule: do not manually edit files in ai-rules/.generated-ai-rules/ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7f6ea1f commit b19141d

10 files changed

+57
-3
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../ai-rules/skills/watermark-portfolio-images

.cursor/rules/ai-rules-generated-keep-agents-up-to-date.mdc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@ Examples of changes that should trigger a review:
1818
- `agents` — which AI agents (e.g. `claude`, `cursor`) receive the distributed rules
1919
- `nested_depth` — how many levels deep to nest rules when distributing them
2020
- `gitignore` — whether the generated/distributed rule files are added to `.gitignore`
21+
22+
**IMPORTANT**: After editing any `.md` file inside `ai-rules/` or any of its subfolders (including skills), you MUST run `ai-rules generate` from the project root to re-distribute the updated rules to all agent-specific locations.
23+
24+
**DO NOT** manually edit files inside `ai-rules/.generated-ai-rules/` — they are auto-generated by `ai-rules generate` and any manual changes will be overwritten.

.cursor/rules/ai-rules-generated-project-structure-and-stack.mdc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ scripts/
2525
image-modal.js — Photo gallery modal (swipe, pinch-to-zoom, keyboard nav)
2626
scroll-to-gallery.js — Smooth-scrolls to the "Recent shots" section on button click
2727
images/ — Portfolio photos, company logos, social icons
28+
ai-rules/skills/
29+
watermark-portfolio-images/ — Skill + script to apply signature watermark to portfolio images
2830
```
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../ai-rules/skills/watermark-portfolio-images

ai-rules/.generated-ai-rules/ai-rules-generated-AGENTS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ Examples of changes that should trigger a review:
3232
- `nested_depth` — how many levels deep to nest rules when distributing them
3333
- `gitignore` — whether the generated/distributed rule files are added to `.gitignore`
3434

35+
**IMPORTANT**: After editing any `.md` file inside `ai-rules/` or any of its subfolders (including skills), you MUST run `ai-rules generate` from the project root to re-distribute the updated rules to all agent-specific locations.
36+
37+
**DO NOT** manually edit files inside `ai-rules/.generated-ai-rules/` — they are auto-generated by `ai-rules generate` and any manual changes will be overwritten.
38+
3539
# Project structure and stack
3640

3741
## Tech Stack
@@ -56,6 +60,8 @@ scripts/
5660
image-modal.js — Photo gallery modal (swipe, pinch-to-zoom, keyboard nav)
5761
scroll-to-gallery.js — Smooth-scrolls to the "Recent shots" section on button click
5862
images/ — Portfolio photos, company logos, social icons
63+
ai-rules/skills/
64+
watermark-portfolio-images/ — Skill + script to apply signature watermark to portfolio images
5965
```
6066

6167
# Rules

ai-rules/.generated-ai-rules/ai-rules-generated-keep-agents-up-to-date.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ Examples of changes that should trigger a review:
1313
- `agents` — which AI agents (e.g. `claude`, `cursor`) receive the distributed rules
1414
- `nested_depth` — how many levels deep to nest rules when distributing them
1515
- `gitignore` — whether the generated/distributed rule files are added to `.gitignore`
16+
17+
**IMPORTANT**: After editing any `.md` file inside `ai-rules/` or any of its subfolders (including skills), you MUST run `ai-rules generate` from the project root to re-distribute the updated rules to all agent-specific locations.
18+
19+
**DO NOT** manually edit files inside `ai-rules/.generated-ai-rules/` — they are auto-generated by `ai-rules generate` and any manual changes will be overwritten.

ai-rules/.generated-ai-rules/ai-rules-generated-project-structure-and-stack.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ scripts/
2020
image-modal.js — Photo gallery modal (swipe, pinch-to-zoom, keyboard nav)
2121
scroll-to-gallery.js — Smooth-scrolls to the "Recent shots" section on button click
2222
images/ — Portfolio photos, company logos, social icons
23+
ai-rules/skills/
24+
watermark-portfolio-images/ — Skill + script to apply signature watermark to portfolio images
2325
```

ai-rules/keep-agents-up-to-date.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@ Examples of changes that should trigger a review:
1818
- `agents` — which AI agents (e.g. `claude`, `cursor`) receive the distributed rules
1919
- `nested_depth` — how many levels deep to nest rules when distributing them
2020
- `gitignore` — whether the generated/distributed rule files are added to `.gitignore`
21+
22+
**IMPORTANT**: After editing any `.md` file inside `ai-rules/` or any of its subfolders (including skills), you MUST run `ai-rules generate` from the project root to re-distribute the updated rules to all agent-specific locations.
23+
24+
**DO NOT** manually edit files inside `ai-rules/.generated-ai-rules/` — they are auto-generated by `ai-rules generate` and any manual changes will be overwritten.

ai-rules/skills/watermark-portfolio-images/SKILL.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,20 @@ python ai-rules/skills/watermark-portfolio-images/watermark.py
1818

1919
Requires Pillow (`pip install Pillow`).
2020

21+
### Font setup
22+
23+
The script resolves the font in this order:
24+
25+
1. **Bundled** — any `.ttf` or `.ttc` file placed directly in `ai-rules/skills/watermark-portfolio-images/` is picked up automatically.
26+
2. **CLI flag** — pass `--font /path/to/font.ttf` to specify it explicitly.
27+
28+
The intended font is **Gingerink** (`GingerinkPersonalUse-rvJd7.ttf`). Download it and drop it into the skill directory (or pass it via `--font`) before running.
29+
2130
## Parameters
2231

2332
| Setting | Value |
2433
|---|---|
25-
| Font | Gingerink `/Users/afollestad/Downloads/gingerink-font/GingerinkPersonalUse-rvJd7.ttf` |
34+
| Font | Gingerink (`GingerinkPersonalUse-rvJd7.ttf`) — place in skill directory or pass `--font` |
2635
| Font size | `max(8, int(width * 0.011))` — 1.1% of image width, min 8px |
2736
| Text color | White, **50% opacity** (`128/255`) |
2837
| Shadow color | Black, 39% opacity (`100/255`), blurred |
@@ -58,7 +67,7 @@ python ai-rules/skills/watermark-portfolio-images/watermark.py --file moon.jpg -
5867
- **Opacity**: change `DEFAULT_OPACITY` or `DARK_OPACITY` in `watermark.py`, or pass `--opacity`
5968
- **Font size**: adjust the `0.011` multiplier (e.g. `0.014` = slightly larger)
6069
- **Position**: adjust `0.02` (horizontal) and `0.018` (vertical) padding multipliers
61-
- **Font**: replace `FONT_PATH` with another `.ttf`/`.ttc` path
70+
- **Font**: drop a different `.ttf`/`.ttc` into the skill directory, or pass `--font /path/to/font.ttf`
6271

6372
## Re-running after changes
6473

ai-rules/skills/watermark-portfolio-images/watermark.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,19 @@
1010
import argparse
1111
import glob
1212
import os
13+
import sys
1314

1415
from PIL import Image, ImageDraw, ImageFont, ImageFilter
1516

1617
PORTFOLIO_DIR = os.path.join(os.path.dirname(__file__), "../../../images/portfolio")
1718
SIGNATURE_TEXT = "Aidan Follestad"
18-
FONT_PATH = "/Users/afollestad/Downloads/gingerink-font/GingerinkPersonalUse-rvJd7.ttf"
19+
20+
# Font search: look for any .ttf/.ttc in the skill directory first
21+
_SKILL_DIR = os.path.dirname(os.path.abspath(__file__))
22+
_BUNDLED_FONTS = sorted(
23+
f for f in os.listdir(_SKILL_DIR) if f.lower().endswith((".ttf", ".ttc"))
24+
)
25+
FONT_PATH = os.path.join(_SKILL_DIR, _BUNDLED_FONTS[0]) if _BUNDLED_FONTS else None
1926

2027
# Images that are mostly dark — use reduced opacity so the white text isn't jarring
2128
DARK_IMAGES = {"moon.jpg", "moon_thumbnail.jpg"}
@@ -68,8 +75,22 @@ def main() -> None:
6875
parser = argparse.ArgumentParser()
6976
parser.add_argument("--opacity", type=float, default=None, help="Override opacity (0.0–1.0) for all images")
7077
parser.add_argument("--file", type=str, default=None, help="Process a single filename only (e.g. moon.jpg)")
78+
parser.add_argument("--font", type=str, default=None, help="Path to a .ttf/.ttc font file")
7179
args = parser.parse_args()
7280

81+
global FONT_PATH
82+
if args.font:
83+
FONT_PATH = args.font
84+
if not FONT_PATH or not os.path.isfile(FONT_PATH):
85+
print(
86+
"Error: no font file found.\n"
87+
" Expected font: Gingerink (GingerinkPersonalUse-rvJd7.ttf)\n"
88+
f" Drop the .ttf file into {_SKILL_DIR}\n"
89+
" or pass --font /path/to/GingerinkPersonalUse-rvJd7.ttf",
90+
file=sys.stderr,
91+
)
92+
sys.exit(1)
93+
7394
jpg_files = sorted(glob.glob(os.path.join(PORTFOLIO_DIR, "*.jpg")))
7495
if args.file:
7596
jpg_files = [f for f in jpg_files if os.path.basename(f) == args.file]

0 commit comments

Comments
 (0)