北师珠校园猫咪分布地图 (BNUZ Cat Map)
Overview
This skill turns the campus cat registry into an answerable knowledge base and a
visual distribution map for Beijing Normal University at Zhuhai (北师珠). It is the
delivery end of a creative tool chain:
腾讯文档 (collection) → ima 知识库 (optional curation) → WorkBuddy Skill (this skill, answers + map)
The cat data is embedded in this skill as references/cats.csv (sourced from the
Tencent Docs registry), so the skill works reliably without a live connection.
When to use
- A user asks "北师珠哪里有猫" / "校园猫咪地图" / "文华苑有哪些猫".
- A user asks about a specific cat by name: "布丁在哪" / "橘猫性格怎么样" / "月亮有几只".
- A user wants a distribution map or statistics (how many cats per zone, total count).
- A user wants to add/update cat records (route to the Tencent Docs source).
Data layout
| File | Contents |
|---|---|
references/cats.csv |
Cat records: id,name,zone,location,description,preference,status,photo. 45 records (1 marked 已故). |
references/campus-zones.md |
Zone definitions, member buildings, rough orientation, and schematic map coordinates. |
references/photos/ |
(optional) Cat photos, named by id or nickname, e.g. 1.jpg, 布丁.jpg. |
assets/campus-map.jpg |
Original BNU Zhuhai campus map image (source for cleaning). |
assets/campus-map-clean.jpg |
Cleaned campus map: the top-left legend blocks (校园建筑/设施/师生公寓/食堂/校园服务) and bottom title (校园平面图 / BEIJING NORMAL... / 理工综合体(施工中)) and watermark have been erased. This is the default map background used by generate_map.py. Regenerate with scripts/clean_campus_map.py. |
scripts/generate_map.py |
Reads the CSV (and optional map image) and emits a self-contained interactive HTML map. |
scripts/clean_campus_map.py |
Preprocesses campus-map.jpg → campus-map-clean.jpg (whitewash top legend + bottom title with feathering). Run once; idempotent. |
scripts/import_photos.py |
Matches photos in references/photos/ into cats.csv by id/nickname. |
CSV columns:
- id — registry number from the Tencent Docs sheet.
- name — cat nickname; "(未命名)" means unnamed.
- zone — one of 9 campus zones (see campus-zones.md).
- location — verbatim location text from the source sheet (may list several buildings).
- description — temperament/personality notes.
- preference — where the cat likes to hang out (often empty).
- status — 常驻 / 已驻 / 已故. Exclude 已故 when counting living cats.
- photo — optional: a URL, a data:image/... URI, or a relative path (e.g. photos/1.jpg).
Left empty when no photo is available; the UI shows a 🐱 placeholder.
How to answer questions
- Read
references/cats.csv(useutf-8-sigto strip the BOM). - Filter by the requested dimension:
- By name: case-insensitive substring match onname. Warn the user when a name
appears in multiple zones (e.g. 布袋 in 燕华会同乐育区 and 海华苑区; 月亮 in 海华苑区
and 文华苑区) — disambiguate by zone.
- By zone/location: match onzoneorlocationkeywords (e.g. "文华苑", "燕华",
"学三食堂"). Note 学三食堂 == 学三饭堂.
- Statistics: count records; for "现存" counts excludestatus == 已故. - Present a concise answer with the cat's name, location, and personality note.
- Offer to render the map when the user is exploring distribution.
How to generate the distribution map
Run the bundled generator and present the resulting HTML to the user:
python3 <skill_dir>/scripts/generate_map.py \
--out <workspace>/cat_map.html \
[--map-image <skill_dir>/assets/campus-map.jpg] \
[--only-living]
The script outputs a standalone HTML file (no external dependencies; the campus map
image, if provided, is base64-embedded). Open it in the built-in preview. Features:
- Real BNU Zhuhai campus map as background (when
--map-imagepoints to the asset);
otherwise a neutral green gradient placeholder is used. - One marker per cat, positioned on the map by its exact building(s). Orange = living,
grey = 已故, green ring = visitor-added. Mobile cats (recorded in several buildings) get
one marker per building linked by an orange dashed line. Hover for tooltip; click a
marker or a side-panel card to open the cat's archive (with photo, personality, spots). - 📸 Cat photo album (top carousel): auto-playing row of cat cards (only cats
with a photo are shown; cats without a photo are excluded). Click any photo to
open that cat's archive. - 🐱 Two-cat compare: the archive modal is two columns. Opening a cat fills the
left slot; clicking another cat (map marker / list card / carousel photo) while the
archive is open fills the right slot for side-by-side comparison. A "🔍 对比中" tag
and "✕ 退出对比" button appear; each column keeps its own 收藏/投票/海报/编辑 actions.
The side-panel list header reads "猫咪🐱档案", and cats without a photo are sorted to
the end of that list. - 🎲 "今天偶遇哪只猫?" button + daily auto-popup: opens a large themed
encounter modal (header shows a hand-drawn, locally-embedded animated SVG cat
— ears wiggle, eyes blink, tail wags, gentle bob). After drawing, the map
auto-pans and zooms to that cat (the chosen marker enlarges ~1.7×) for
~3s, then eases back. Showing a big cat photo, name, meta, and
reroll/view-archive buttons. The first time the page is loaded each day it
auto-pops after ~0.9s; a "今天不再自动弹出" link snoozes it for the rest of
the day. State persists inlocalStorage(keysbnuz-cat-encounter-dateand
bnuz-cat-encounter-snooze). - Cute map doodles: hand-drawn paw/fish/sitting-cat/curled-cat/yarn/heart
doodles are scattered in the map's empty areas (semi-transparent, gently
floating,pointer-events:noneso they never block marker clicks). - A name/zone search and zone filter on the right; matched cats highlight, others dim.
Exploration modules (always-visible, directly below the 猫咪🐱档案 list)
- 🗺️ 偶遇路线 module: "开启路线" toggle, then click cats in order (or "🎲 随机路线")
to draw a numbered walking route shown inline; "完成" / "清空" controls.
- ✅ 今日打卡 module: shows your current consecutive-day streak + today's seen cats as
chips; a "去打卡" button opens the check-in picker (localStorage key bnuz-cat-checkins).
- 🏆 投票排行 module: live popularity ranking as an inline bar list, each row has a
"👍" vote button; votes persist (localStorage key bnuz-cat-votes).
- 🎯 猜猫 module: inline guess-the-cat game (photo + 4 name options), "开始 / 下一题"
button and a live score readout.
- The remaining toolbar buttons (⭐ 收藏夹 / 🏢 楼栋关联 / 🎚️ 图层) stay in the top toolbar.
Beautify pack
- Markers show a circular photo avatar when a photo exists, else a cat emoji.
- Animated flowing dashed mobility lines (CSS @keyframes).
- Glassmorphism panels + gradient header; 🌗 夜间模式 toggle (dark theme).
- Hover mini-card: hovering a marker floats a small card with photo + name + spots.
- Legend strip under the map explains marker colors.
- 💖 云撸猫解压墙: sits directly below the map (left column, above 校区猫口一览). It features a random real campus cat (photo avatar in a hand-drawn pink ring, picked on load / via "🐾 换一只"); clicking pets that specific cat → happy bounce + floating hearts + a "猫名:喵~" speech bubble + a synthesized meow (toggleable). Per-cat daily counts persist in localStorage (bnuz-cat-pet-<date> as a {catId:count} JSON object, current cat in bnuz-cat-pet-current, grand total in bnuz-cat-pet-total). A 🏆 今日撸猫榜 mini leaderboard shows the top 5 most-petted cats today (with medal 🥇🥈🥉). A tappable card flips through random cat facts.
Stats pack (bottom section)
- Per-zone bar chart (living cats per zone) + status donut (现存/流动/已故), drawn as SVG.
Social pack
- From any archive: ⭐ 收藏 (favorites, localStorage key bnuz-cat-favorites),
🖼️ 海报 downloads a shareable PNG poster (canvas), 🎯 猜猫 mini-game
(photo → pick the name, score kept for the session).
- ⭐ 收藏夹 filter button shows only favorited cats.
Layout & navigation
- A fixed left vertical navigation bar (<nav class="sidenav">) lists every primary + secondary feature as scroll links: 校园地图 / 猫咪相册 (+ 收藏夹 / 楼栋关联 / 图层 sub-links) / 猫咪档案 (+ 投稿管理) / 互动乐园 group (偶遇路线 · 云撸猫 · 今日打卡 · 投票排行 · 猜猫) / 今日猫咪美照 / 校区猫口一览. Clicking smooth-scrolls to the section; an IntersectionObserver scrollspy highlights the active item. Collapses (hidden) below 820px width. All page content is wrapped in <div class="page"> with margin-left:212px.
💬 今日猫咪美照 (visitor message board)
- A bottom section (#secBoard) that is a public photo-message wall. Entries store {id, photo, auth, cap, time, like} in localStorage (bnuz-cat-board; liked ids in bnuz-cat-board-liked). First load seeds one demo post from a real campus cat (so the wall is never empty). ✍️ 我要投稿 opens a modal (nickname + photo file picker + caption) to publish; clicking a post's photo focuses that cat on the map + opens its archive. Each post has a ❤ like button (toggles + increments).
Visitor contribute mode (default ON): a header toggle enables visitors to
click any existing marker to edit name/photo/description/location/zone/status,
or click empty map space to add a new cat at that location. Edits are saved to
the visitor's browser localStorage (key bnuz-cat-contributions) and can be
exported as JSON via "⬇ 导出". Import ("⬆ 导入") to merge another visitor's
contributions. "清空" wipes local contributions.
- Curate submitted contributions: export the JSON, review, and merge accepted
changes back into references/cats.csv and the Tencent Docs registry, then
regenerate the map.
Replace <skill_dir> with the absolute path of this skill folder and <workspace>
with the user's working directory.
演示效果 / Demo
生成后的 cat_map.html 是一个单文件、离线可用的交互式校猫地图。整体少女粉嫩手绘风,从上到下的板块布局如下(可直接用内置预览打开查看):
- 顶部标题栏:粉色渐变 + 手绘猫爪,含搜索框、区域筛选与「🌗 夜间模式 / ✏️ 游客投稿 / ⭐ 收藏夹 / 🏢 楼栋关联 / 🎚️ 图层」等按钮。
- 📸 猫咪相册(顶部轮播):自动播放的校猫照片卡(仅展示有照片的猫,点击照片直达档案)。
- 🗺️ 校园地图(主视觉):真实北师珠手绘校区底图,每只猫一个标记(橙色=现存,灰色=已故,绿圈=游客新增);流动猫按楼栋分布并在标记间画橙色虚线。悬停浮出小卡,点击标记或侧栏卡片打开档案。空旷处散布半透明爪印 / 小鱼 / 蜷猫涂鸦。左侧固定竖向导航条列出全部一二级功能并高亮当前板块。
- 🐱 猫咪档案(双猫对比):侧栏列表(无照片的猫排最后);档案弹窗双栏,可同时对比两只猫,含收藏 / 投票 / 海报 / 编辑。
- 🎲 今日偶遇:手绘风动画猫(耳朵动、眨眼、摇尾)弹窗,抽完后地图自动平移放大到该猫约 3 秒;每日首次加载自动弹出,可「今天不再自动弹出」。
- 💖 云撸猫解压墙:随机一只真实校猫头像(粉色手绘圈),点击撸猫触发爱心 + 合成喵声,含「🏆 今日撸猫榜」Top5 与随机猫知识卡。
- 🗺️ 偶遇路线 / ✅ 今日打卡 / 🏆 投票排行 / 🎯 猜猫:档案下方的四大常驻互动模块。
- 📊 校区猫口一览:各区域校猫数量柱状图 + 状态环图(现存 / 流动 / 已故)。
- 💬 今日猫咪美照(留言板):底部游客投稿墙,可上传猫照 + 昵称 + 文案,点赞互动;首次加载预置一条真实校猫投稿。
> 预览方式:运行上面的 generate_map.py 生成 cat_map.html,用内置预览面板打开即可。所有互动状态(收藏、打卡、投票、撸猫、投稿、偶遇弹窗)均保存在浏览器 localStorage,无需联网。
Keeping the data fresh (tool-chain sync)
The dataset originates in a Tencent Docs sheet and is mirrored into this skill. To
update:
- Tencent Docs — edit the source registry (the live sheet). The connector is
already connected, so records can be read/edited via thetencent-docsskill
(sheet-mcp→get_cell_data/set_cell_value). - Sync into this skill — re-derive
references/cats.csvfrom the sheet. The sheet
stores one cat per column (fields per row): row0 = 编号, row1 = 位置, row4 =
昵称, row5 = 描述, row6 = 偏好. Transpose, map eachlocationto azoneusing
references/campus-zones.md, and write the CSV. - ima 知识库 (optional) — for natural-language Q&A over the raw sheet without a
structured CSV, import the sheet into ima and answer via its retrieval. The embedded
CSV path is preferred for deterministic, offline answers. - Photos: Tencent Docs stores cat photos as cell overlay images, which the
tencent-docsMCP cannot read back (verified: the 照片 row's cells are empty STRING
andget_sheet_object_listreturns no image objects). So photos are collected
out-of-band: ask the user to export the photos toreferences/photos/, named by cat
id or nickname (e.g.1.jpg,布丁.jpg), then runscripts/import_photos.pyto
write thephotocolumn.generate_map.pyinlines local photos as base64 — and
downscales them to ≤560px / JPEG q82 via Pillow — so the exported HTML stays a
single shareable file (≈3.9MB for 40 photos + map, not hundreds of MB of raw PNG).
Cats without a photo (currently: 加菲, 小司, 蝙蝠侠, 橘猫, (未命名)) show a 🐱
placeholder; drop a matching photo inreferences/photos/and re-run import to fill them. - Re-run
generate_map.pyto refresh the map after any data change.
Notes & caveats
- Map coordinates are schematic, not GPS — they reflect relative zone positions only.
- Some cats are unnamed and one (鸭头) is deceased; surface these clearly.
- When a name is ambiguous across zones, always state the zone to avoid confusion.