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.

Informações da origem

Repositório
dreamiurg/porthole
Última atividade na origem
25 de setembro de 2026 às 10:07
Idioma detectado do SKILL.md
inglês
Estrelas
0
Forks
0

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
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).
Ver no GitHub