Skip to content

Restyle the generated infobooks and make them work on mobile - #55

Merged
rubensworks merged 1 commit into
masterfrom
claude/festive-cori-aeagmp
Sep 13, 2026
Merged

rubensworks merged 1 commit into
masterfrom
claude/festive-cori-aeagmp

Conversation

@rubensworks

@rubensworks rubensworks commented Sep 12, 2026 •

Copy link
Copy Markdown
Member

The generated books were a fixed 800px wide and had no viewport meta tag, so phones rendered them zoomed out with the text running off screen. This reworks the shared stylesheet and the templates into a responsive layout, and takes the opportunity to move the look closer to the infobook inside the game.

Design

The in-game book is a parchment page on a leather cover, with a stitched edge, a small ornamental divider and rounded pill buttons. The web version now follows that:

  • One centred parchment sheet on the dark outer background, with a frame in border_light, a faint paper grain, an inner vignette and a dashed stitch line along the right edge.
  • An ornamental rule under every section title, drawn with an SVG mask so it picks up the mod's border color.
  • Lora for the book name, section titles and appendix labels; Open Sans for body text. Droid Sans is dropped, and both remaining faces load in one request.
  • Recipes, aspects and operators sit in slightly darker parchment panels. Slots use the vanilla inventory slot look, and the machine icon sits above a pixel arrow in the mod color.
  • Previous and next pages become pill buttons filled with border_muted and outlined in border, matching the button sprite in the book textures.
  • Index pages become a table of contents, single column when short and multi column when long.

Every color is still derived from the six values that config.json already defines, using color-mix(), so no mod configuration has to change. Mods that want to deviate can override the derived tokens (--page, --ink, --link, --frame, ...) in their own stylesheet.

Templates

  • Add a charset and a viewport meta tag. There was no charset before, which left the encoding to browser guessing on non-ASCII languages.
  • Replace the wall of 50+ language links with a details dropdown that needs no JavaScript, and mark the current language with aria-current.
  • Move the breadcrumbs into the page as a nav element.
  • Make the section title the h1 of the page instead of the site name, so every page has exactly one h1 that describes it. The schema:name triple is unchanged: it moved to a meta element in the header with the same "Mod - Book" value.
  • Group appendices in a container so they can flow into columns.

Fixes found along the way

  • The footer loaded main.js from an absolute /assets/main.js. Both deployed books live under /book/, so that has always 404'd and the ingredient variant spinner never ran. It now resolves against baseUrl.
  • index.pug nested its each next to the ul instead of inside it, which emitted an empty <ul></ul> followed by stray <li> siblings.
  • assets/main.js is matched by the *.js line in .gitignore and was never committed, so it exists only inside the published tarball. A publish from a fresh clone would have dropped it. It is now tracked through a negation.
  • Image appendices had a hardcoded pixel width and height that overflowed narrow screens. They now carry an aspect ratio and a proportional background size, so the stylesheet can shrink them without cropping.

Formatting colors

formatString emitted inline hex colors, which meant the in-game yellow, gray and white were unreadable on parchment and impossible to tune from CSS. Each colored span now carries a class and the in-game color as an inline custom property fallback:

<span class="mc mc-6" style="color: var(--mc-6, #FFAA00)">Integer</span>

A stylesheet that knows nothing about --mc-* still gets exactly the old color, and the shared stylesheet redefines the 16 codes so they stay recognisable while remaining readable on the page background. The 16 repeated replacement lines are now table-driven, and HtmlInfoBookSerializer.colorCodes is public so plugins can reuse the mapping.

New config option

bookIconItem is optional and takes an item id, such as "integrateddynamics:on_the_dynamics_of_integration". Its exported icon is shown next to the book name in the header. It falls back to icon when unset or when that item has no exported icon, and icon falls back to it, so existing configs keep working untouched.

Compatibility

Release order

Merging and releasing this first, then merging the two companion PRs, keeps the deployed books consistent: their ^5.2.x ranges resolve to the new release at build time, so the deploy that follows each merge picks up the new templates and the matching stylesheet together.

Going the other way around, or deploying a mod repo in between, pairs new templates with an old mod stylesheet for one deploy. That only misplaces recipe machine icons, and the next deploy fixes it, but doing it in this order avoids it entirely.

Verification

  • npm run build, npm run lint and npm test pass. Added 8 tests for formatString, which had none; this needed esModuleInterop in the test tsconfig, since no test had imported the serializer before.
  • CI generates the CyclopsCore test book end to end on this branch, so the templates are exercised by a real generation run.
  • Rendered the real templates with content taken from the two deployed books (crafting, smelting, squeezer, drying basin, blood infuser with and without a tier icon, environmental accumulator, aspects, operators, advancement rewards, broom modifiers, image and textfield appendices, tag index, and both index page shapes), then checked every page at 1280px and at 390px. No page scrolls horizontally at 390px.
  • Not covered by that render: keybinding appendices, and right-to-left or CJK pages. Those are worth a look on the first real deployment.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FuDB4UAnaLnNEEv8kVuotH

The pages were a fixed 800px wide without a viewport meta tag, so phones
rendered them zoomed out with the text running off screen. This reworks the
shared stylesheet and the templates into a responsive layout that stays close
to the look of the infobook inside the game: one parchment page on a dark
cover, with a stitched edge, an ornamental rule under the title, and pill
buttons for page navigation.

All colors are still derived from the six values that config.json already
defines, so no mod configuration has to change.

Templates:
* Add a charset and a viewport meta tag.
* Replace the wall of language links with a details dropdown that needs no
  JavaScript, and mark the current language with aria-current.
* Move the breadcrumbs into the page as a nav element.
* Make the section title the h1 of the page instead of the site name, and keep
  the schema:name triple intact with a meta element.
* Group appendices in a container so they can flow into columns.
* Swap Droid Sans for Lora, and load both fonts in a single request.

Fixes:
* The footer loaded main.js from an absolute /assets/main.js, which 404s for
  every book that is not hosted at the domain root, so the ingredient variant
  spinner never ran. It now resolves against baseUrl.
* The index template nested its each next to the ul instead of inside it,
  which emitted an empty ul followed by stray li siblings.
* assets/main.js was matched by the *.js gitignore rule and was never
  committed, so it only existed in the published package. It is now tracked.
* Image appendices had a hardcoded pixel size that overflowed narrow screens.
  They now keep their aspect ratio and scale their background with the element,
  so the stylesheet can shrink them to fit.

Colors from formatting codes are emitted as an mc-* class with the in-game
color as an inline custom property fallback, so that stylesheets can tune them
for readability on parchment without losing the in-game color when they don't.

Adds an optional bookIconItem config option, which shows the icon of that item
next to the book name in the header.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FuDB4UAnaLnNEEv8kVuotH
@rubensworks
rubensworks force-pushed the claude/festive-cori-aeagmp branch from ae9c58a to 4db2991 Compare September 12, 2026 20:43

Copy link
Copy Markdown
Member Author

Heads up on the one red check here: coverage/coveralls reports "Coverage decreased (-30.1%) to 55.032%". No tests were removed, and nothing is actually less tested than before. The number moved because the denominator did.

collectCoverage is on without collectCoverageFrom, so Jest only instruments files that a test imports. Before this PR, no test imported HtmlInfoBookSerializer.ts, which is the largest file in lib/, so its 380 lines were absent from the report and the total sat at 84%. This PR adds the first tests for it, which pulls the whole file into the report at partial coverage and drags the total down.

I have since extended those tests to cover the pure helpers as well, so the file now reports 33% instead of 16%, and the total is 58% rather than 55%. Coveralls will still read that as a decrease against master, because master was never measuring the file at all.

Two options, both yours to pick:

  • Leave it. The check is not required, so the PR is still mergeable, and the number will settle on the new baseline after the merge.
  • Add collectCoverageFrom: ["lib/**/*.ts"] to the Jest config, so every source file counts whether or not a test imports it. That makes the metric stable and comparable from then on, at the cost of one more drop in the reported number on the commit that introduces it. Happy to do that here or in a separate PR, just say which.

Generated by Claude Code

@rubensworks
rubensworks merged commit 28b8ce7 into master Sep 13, 2026
2 of 4 checks passed
@rubensworks
rubensworks deleted the claude/festive-cori-aeagmp branch September 13, 2026 04:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants