Skip to main content

content

Any game (apps/porthole/games/<game>/). Use when writing or revising content -- Pets Club stories and spelling words, or Biscuit stories, discoveries, daily adventures and words. Covers each game's content gate (both pixel-fit), the claim ledger for factual entries, and voice/style rules.

معلومات المصدر

المستودع
dreamiurg/porthole
آخر نشاط في المصدر
٢٥ سبتمبر ٢٠٢٦ في ١٠:٠٧
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
١
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
content
description
Any game (apps/porthole/games/<game>/). Use when writing or revising content -- Pets Club stories and spelling words, or Biscuit stories, discoveries, daily adventures and words. Covers each game's content gate (both pixel-fit), the claim ledger for factual entries, and voice/style rules.
Pets Club's content gate is pixel-accurate, not a character count -- it renders every string through the actual bundled font and word-wraps it into the exact box the game draws it in; Biscuit's does the same with its own renderer (`os/font.cpp`) and boxes (`games/biscuit/layout.h`). Run the relevant gate before calling any content change done; 0 problems is the bar, not "fewer than before." Append new entries; never edit or remove an existing one unless explicitly asked to fix that entry -- ids and array order are persisted. Regenerate any generated asset from its source tool; never hand-edit a generated header. ## Pets Club (`apps/porthole/games/pets-club/`) 1. Reading level by age (`pet.cpp`'s `levelRange`, also in `games/pets-club/CLAUDE.md`): age <= 6 -> level 1 only; age 7 -> levels 1-2; age 8 -> levels 2-3; age >= 9 -> level 3 only. Write to the level you were asked for. 2. The gate: `tools/check_content.py` renders every string through the real 8x8 proportional font and word-wraps it into the exact box the game draws it in -- `page` 122px wide x 7-8 lines, `title` 108px x 2 lines, `question` 116px x 2-3 lines, `answer` 102px x 2 lines, `clue` 118px x 3 lines (line budgets shift slightly with how many lines the title itself wraps to). Rough drafting budget before running it: a page usually fits in ~130 characters, a title in ~16, a question in ~55, an answer in ~18 -- heuristics, not the rule. 3. Other limits it enforces: 3-11 pages per story, 2-3 answers, `correct` index in range, title and word uniqueness across the whole content set, spelling words uppercase and 3-9 characters, 7-bit ASCII only everywhere (no curly quotes, no em/en dashes, no accented letters -- plain `'`, a straight `"` escaped as `\"` inside the C string literal, plain hyphens). 4. Beyond what the checker measures: the comprehension question must require connecting at least two pages, not restate one page verbatim, and the `correct` answer index should vary across a batch -- check the existing distribution before defaulting to index 0. 5. Append a `Book{...}` entry to `BOOKS[]` in `content.h` (or `content_level3_books.h` for level 3); append a `WordClue{...}` entry to `WORDS[]` in `content.h` (or `content_level3_words.h` for level 3). The `#if __has_include(...)` guard string in `content.h` must match the filename exactly. 6. Run `python3 apps/porthole/games/pets-club/tools/check_content.py` -- it prints `content: N stories, M words, K problems` then one line per problem with a file:line and the reason. Then run `make -C apps/porthole test` (a build failure here usually means a stray non-ASCII character or unescaped `"` the checker's source-text scan didn't catch). ## Biscuit (`apps/porthole/games/biscuit/`) Content and its gate: `content_stories.h`, `content_discoveries.h`, `content_daily.h`, `tools/check_content.py` and the pixel gate below; the screens that draw each string are in `games/biscuit/CLAUDE.md`. 1. Content types, see `games/biscuit/CLAUDE.md` for the exact module map: `content_stories.h` (7 branching stories, `Story{id, title, subtitle, unlockDay, pages[10], prompt, choices[2]{label, ending[4]}}`), `content_discoveries.h` (96 `Discovery{id, topic, title, pages[2], wonder, sourceName, sourceUrl}` across 12 topics), `content_daily.h` (7 daily adventures with a word and meaning, 6 tricks with 3 cue-pattern lessons each, 12 sticker names). 2. The gate: `games/biscuit/tools/check_content.py` checks every string's glyphs against the bundled font's actual set (ASCII 32-126 plus the extras `generated/fonts.h` lists: e-acute, o-umlaut, the middle dot), that a `{...}` token is only `{name}` or `{pet}` and only inside a field the game personalizes (page/prompt/fact_page/wonder/description/meaning), the fixed counts (7 stories, 96 discoveries across 12 topics x 8, 7 adventures, 6 tricks, 12 stickers), unique ids, and that `content_discoveries.h`'s id order matches the `DiscoveryId` enum in `generated/discovery_art.h`. Fit is measured in pixels by `host/test_biscuit_content.cpp` (in `make test`) measures and draws every string with `os/font.cpp` itself, tokens filled with the widest names (11 and 12 W's), in the box `games/biscuit/layout.h` gives its screen, and fails on text taller than its box or ink off the round glass; a story up to its choice, an ending or a discovery is its pages filled and joined with a space into one text (`Game::openPages`) and flowed onto screens of the 352x176 font24 page box, at most `READ_BYTES` filled and `READ_SCREENS` screens (`layout.h`), the last screen holding at least `MIN_LAST_WORDS` words at the widest names and at short ones (Sam/Pip; `pageBreaks` moves words onto it from the screen before, and the gate fails only when that screen can't spare them or the last one would overflow). A failure prints the string, its measured height and its box, or the pixel the bezel cuts. 3. Before writing a discovery, inspect the existing catalog for a duplicate fact, question, visual metaphor, culture, or source institution. For each candidate, write one line each: **surprise** (what changes the reader's first guess), **evidence** (what the source actually establishes), **picture** (what the image explains that prose can't), **question** (what the child can reason about, unscored), **warmth** (does a doglike reaction or the surrounding interaction add any). Reject an item that only renames an existing discovery, needs a paragraph of setup before becoming interesting, or has no real visual treatment. 4. Claim ledger: while drafting a factual entry, keep a compact table (claim | exact URL plus page/section | supporting passage | confidence | visual implication) under ignored `build/content-review/` until review is done. The source must support the specific claim, not just the general topic. Separate established fact from interpretation, reconstruction, legend, and open scholarly question; avoid unsupported superlatives ("first," "oldest," "proved"). Automated checks validate structure and URLs, not truth -- reopen every source and compare it against the final text by hand before shipping. 5. Voice: short, natural, doglike sentences -- noticing smells, sounds, naps, paws, snacks, closeness, the child's mood. He may ask a sharp question but never sounds like an investigator, teacher, or assistant. Good: "You read the tiny marks. I'll keep your toes warm." Bad: "Supplies secured. What are we investigating?" Not every discovery needs a line -- don't force dialogue where it doesn't belong. Stories reward inference and meaningful choices; both endings must follow from the choice made and add distinct information, neither is "wrong." 6. Every discovery needs an original 96x48 illustration (Biscuit's art tool, see the `art` skill) that shows the relationship being explained -- comparison, process, pattern, scale, cause and effect -- not a decorative symbol. For historical or cultural subjects, verify depicted forms, orientation, materials and meaning; never present an invented mark as readable writing or a stylized reconstruction as exact scale. 7. Copy uses two tokens that `personalize()` (`games/biscuit/personalize.{h,cpp}`) fills from the profile at render time: `{name}` for the child (falls back to "Friend") and `{pet}` for the dog (falls back to "Biscuit"). Never hardcode a specific child's name into content, a test fixture, or a migration default -- and only use a token inside a field the gate treats as personalized (item 2); anywhere else it would be drawn literally. 8. Run `python3 games/biscuit/tools/check_content.py`, then `make -C apps/porthole test` (builds `host/test_biscuit_content.cpp`: `personalize()`, the generated art tables and the pixel-fit gate from item 2).
عرض على GitHub