Skip to content

feat(openworlds): add attributed icon registry - #182

Merged
100yenadmin merged 3 commits into
mainfrom
openworlds/icon-registry
May 26, 2026
Merged

feat(openworlds): add attributed icon registry#182
100yenadmin merged 3 commits into
mainfrom
openworlds/icon-registry

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented May 26, 2026

Copy link
Copy Markdown
Member

Summary

Adds the first roadmap-squeeze PR lane from #174: an attributed local icon registry for OpenWorlds gameplay surfaces.

What changed:

  • Adds viewer/openworlds/icon-registry.jsx with stable semantic icon ids such as combat.attack, dice.d20, atlas.travel, quest.scroll, camp.rest, inventory.potion, economy.coins, and party.shield.
  • Vendors a curated 12-SVG subset from game-icons/icons, not the full icon repo.
  • Adds viewer/openworlds/assets/icons/ATTRIBUTION.md and top-level THIRD_PARTY_NOTICES.md coverage for Game Icons CC-BY-3.0 attribution.
  • Teaches scripts/license_check.py to fail when tracked Game Icons SVGs lack local attribution/notice coverage.
  • Serves .svg assets from /openworlds/ with image/svg+xml.
  • Wires icons into obvious OpenWorlds table, combat, atlas, stash, travel, and nav affordances while preserving display-only/read-only state behavior.

Source Research And Decision

Wave 1 research recommended a selective direct asset import only for game-icons/icons. The upstream license text says icons are Creative Commons BY 3.0 unless a contributor is explicitly CC0, and asks derivative works to mention the icon authors.

Rejected alternatives:

  • Bulk import of the full icon set: rejected as unnecessary bloat and harder attribution audit.
  • Network/CDN icon loading: rejected because the packaged app should remain local/offline.
  • Hand-rolled glyph-only UI: rejected because the OpenWorlds surface needs fast scanability for actions, travel, quests, and items.

Architecture Boundary

This PR is presentation-only.

  • It does not change engine, rules, voice, inventory, combat, quest, XP, world clock, or campaign persistence APIs.
  • It does not add a browser-local game-state authority.
  • OpenWorlds still consumes viewer read models and posts only existing /move intents where actions are backed.
  • Display-only/unbacked screens remain governed by [openworlds] Add capability badges and display-only states for unbacked screens #133 capability states.

Files To Review First

  • viewer/openworlds/icon-registry.jsx
  • viewer/openworlds/assets/icons/ATTRIBUTION.md
  • scripts/license_check.py
  • viewer/tests/test_openworlds_static.py
  • viewer/openworlds/screen-table.jsx
  • viewer/openworlds/screen-combat.jsx
  • viewer/openworlds/screen-map.jsx

Validation

Run from /Volumes/LEXAR/repos/ClawDnD-icon-registry:

python3 -m unittest viewer.tests.test_openworlds_static -q
python3 -m py_compile viewer/server.py scripts/license_check.py
python3 scripts/license_check.py
node - <<'NODE'
const fs = require('fs');
const vm = require('vm');
const babelCode = fs.readFileSync('viewer/openworlds/vendor/babel-standalone-7.29.0.min.js', 'utf8');
const ctx = { window: {}, self: {}, console };
ctx.window = ctx; ctx.self = ctx;
vm.createContext(ctx);
vm.runInContext(babelCode, ctx);
for (const file of ['viewer/openworlds/icon-registry.jsx','viewer/openworlds/chrome.jsx','viewer/openworlds/screen-table.jsx','viewer/openworlds/screen-combat.jsx','viewer/openworlds/screen-map.jsx']) {
  const src = fs.readFileSync(file, 'utf8');
  ctx.Babel.transform(src, { presets: ['react'] });
  console.log('babel ok', file);
}
NODE
git diff --check --cached

Observed:

  • viewer.tests.test_openworlds_static: 17 tests passed.
  • py_compile: passed.
  • license_check: passed after staging the icon assets.
  • Babel transform smoke for touched JSX: passed.
  • git diff --check --cached: passed.

Rollback Plan

Revert this commit. The icon registry is additive and does not alter engine state, persisted snapshots, or viewer API contracts. The fallback UI continues to render text/glyphs if the registry is absent.

Refs #174, #113, #115, #116, #117, #119, #121, #133.

Summary by CodeRabbit

  • New Features

    • Curated semantic icon registry and components integrated across combat, map, table, and UI action buttons with graceful fallbacks.
  • Documentation

    • Added bundled icon attribution and licensing records; updated third‑party notices.
  • Styles

    • New icon styling to enable CSS masking and accessible fallbacks.
  • Tests

    • Added tests validating local icon assets, attributions, and SVG serving.
  • Chores

    • CI/license check enhanced to verify icon attributions; server now serves SVGs with correct MIME type.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6f1d6d06-1e2c-4064-b285-e6c4254b2fa6

📥 Commits

Reviewing files that changed from the base of the PR and between 546f362 and 77ff6dd.

⛔ Files ignored due to path filters (12)
  • viewer/openworlds/assets/icons/game-icons/delapouite/coins.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/delapouite/dice-twenty-faces-twenty.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/delapouite/health-potion.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/delapouite/rolling-dices.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/delapouite/tavern-sign.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/lorc/campfire.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/lorc/compass.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/lorc/locked-chest.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/lorc/open-book.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/lorc/sword-clash.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/lorc/tied-scroll.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/willdabeast/round-shield.svg is excluded by !**/*.svg
📒 Files selected for processing (12)
  • THIRD_PARTY_NOTICES.md
  • scripts/license_check.py
  • viewer/openworlds/assets/icons/ATTRIBUTION.md
  • viewer/openworlds/chrome.jsx
  • viewer/openworlds/icon-registry.jsx
  • viewer/openworlds/index.html
  • viewer/openworlds/screen-combat.jsx
  • viewer/openworlds/screen-map.jsx
  • viewer/openworlds/screen-table.jsx
  • viewer/openworlds/styles.css
  • viewer/server.py
  • viewer/tests/test_openworlds_static.py

Cache: Disabled due to Reviews > Disable Cache setting


📝 Walkthrough

Walkthrough

Adds a local OpenWorlds semantic icon registry (manifest, aliases, resolver, React component), CSS mask rendering, server MIME mapping, attribution docs with CI checks, and integrates registry icons into Chrome/UI screens with tests verifying local assets and MIME correctness.

Changes

OpenWorlds Icon Registry System

Layer / File(s) Summary
Icon Registry Core Infrastructure
viewer/openworlds/icon-registry.jsx, viewer/openworlds/styles.css, viewer/openworlds/index.html, viewer/server.py
Manifest maps semantic IDs to SVG paths with metadata; alias map normalizes IDs; OpenWorldsIcon renders masked SVGs or fallbacks with accessible labels; exposes helpers on window; adds .ow-icon/.ow-icon-fallback styles; loads registry script; serves .svg with image/svg+xml.
Attribution & Licensing Compliance
THIRD_PARTY_NOTICES.md, viewer/openworlds/assets/icons/ATTRIBUTION.md, scripts/license_check.py
Documents vendored Game Icons (CC-BY-3.0 with CC0 exceptions); ATTRIBUTION.md lists local→upstream mappings and authors; scripts/license_check.py adds _check_game_icons_attribution() and runs it in main() to enforce attribution coverage.
Chrome Component Integration
viewer/openworlds/chrome.jsx
Glyph prefers window.OpenWorldsIcon for non-built-in kinds when available; IconPlate renders registered icons by size when children absent, otherwise falls back to existing text placeholder.
Screen-Level Icon Usage
viewer/openworlds/screen-combat.jsx, viewer/openworlds/screen-map.jsx, viewer/openworlds/screen-table.jsx
Replaces emoji/glyph literals with semantic icon IDs and conditionally renders window.OpenWorldsIcon nodes where supported; components fall back to raw glyph/text when registry icon unavailable.
Asset & Serving Tests
viewer/tests/test_openworlds_static.py
Adds tests that assert icon-registry references local assets, referenced SVG files exist and contain <svg>, are listed in ATTRIBUTION.md, and are served with image/svg+xml content type.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #174: Matches the described scope of adding a local icon registry, bundling Game Icons with attribution, CI license checks, and wiring icons into chrome/screens.

Possibly related PRs

  • 100yenadmin/ClawDnD#182: Overlaps directly with this PR’s icon-registry, attribution, and license-check changes.
  • 100yenadmin/ClawDnD#161: Related UI changes where icon registry is applied to GM-Advisory/chronicle button integration.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(openworlds): add attributed icon registry' accurately describes the main change: introducing a new icon registry with attribution support for OpenWorlds.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • LINEAR integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/license_check.py`:
- Around line 80-87: Guard the file reads for attr_path.read_text and
notice_path.read_text to avoid OSError crashes: wrap the
attr_path.read_text(encoding="utf-8") assignment (used to set attr_text) in a
try/except that catches OSError (or Exception), appends a descriptive error to
errors (e.g., "Failed reading ATTRIBUTION.md: {err}"), and sets attr_text = ""
on failure; do the same for notice_path.read_text(encoding="utf-8") that sets
notice_text so a failed read yields notice_text = "" and an errors entry instead
of raising.

In `@viewer/openworlds/icon-registry.jsx`:
- Around line 106-112: The resolveOpenWorldsIconId function only checks the raw
key against OPENWORLDS_ICON_MANIFEST, so case-variant semantic IDs like
"COMBAT.ATTACK" fail; after computing normalized (const normalized =
raw.toLowerCase().replace(/_/g, "-")), also check
OPENWORLDS_ICON_MANIFEST[normalized] and return normalized if present, before
falling back to OPENWORLDS_ICON_ALIASES[normalized] or "". Update
resolveOpenWorldsIconId to perform that extra manifest lookup using the
normalized key (referencing resolveOpenWorldsIconId, OPENWORLDS_ICON_MANIFEST,
and OPENWORLDS_ICON_ALIASES).

In `@viewer/openworlds/screen-map.jsx`:
- Around line 362-365: screen-map.jsx renders window.OpenWorldsIcon
unconditionally (in the BrassButton icons for "atlas.travel" and
"quest.scroll"); guard these renders the same way other screens do by checking
the registry before rendering the icon (use optional chaining and the .has
method on window.OpenWorldsIcon, e.g.
window.OpenWorldsIcon?.has?.('atlas.travel') and
window.OpenWorldsIcon?.has?.('quest.scroll')), and only render
<window.OpenWorldsIcon ... /> when the check passes, otherwise render the button
text only (preserve existing props like size, id references to "atlas.travel"
and "quest.scroll" and behavior tied to onTravel/onMark, busyTravel, selected,
travelDisabled).

In `@viewer/openworlds/screen-table.jsx`:
- Around line 246-249: The dice buttons (call sites using requestRoll and
actionById) currently reference window.OpenWorldsIcon directly; wrap the icon
usage with the same guard used elsewhere (e.g.,
window.OpenWorldsIcon?.has?.('dice.d20') or window.OpenWorldsIcon?) and only
render the <OpenWorldsIcon> when available (otherwise render just the label like
"d20" or no icon) so the buttons (and the chronicle CTA) won't crash when the
icon registry is missing; update the elements that render window.OpenWorldsIcon
for dice.d20, dice.roll, etc., to check availability before rendering the icon.

In `@viewer/openworlds/styles.css`:
- Around line 128-129: CSS uses the camel-cased keyword "currentColor" for the
color and background properties, which violates stylelint's value-keyword-case
rule; update the "color" and "background" declarations that currently use
"currentColor" to the lowercase "currentcolor" so both properties conform to the
lint rule (search for the "color" and "background" declarations in the shown
diff to locate and change them).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: afe79e98-a107-4f7a-8e59-8d6ca5a87b5e

📥 Commits

Reviewing files that changed from the base of the PR and between f8f1c7a and 546f362.

⛔ Files ignored due to path filters (12)
  • viewer/openworlds/assets/icons/game-icons/delapouite/coins.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/delapouite/dice-twenty-faces-twenty.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/delapouite/health-potion.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/delapouite/rolling-dices.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/delapouite/tavern-sign.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/lorc/campfire.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/lorc/compass.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/lorc/locked-chest.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/lorc/open-book.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/lorc/sword-clash.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/lorc/tied-scroll.svg is excluded by !**/*.svg
  • viewer/openworlds/assets/icons/game-icons/willdabeast/round-shield.svg is excluded by !**/*.svg
📒 Files selected for processing (12)
  • THIRD_PARTY_NOTICES.md
  • scripts/license_check.py
  • viewer/openworlds/assets/icons/ATTRIBUTION.md
  • viewer/openworlds/chrome.jsx
  • viewer/openworlds/icon-registry.jsx
  • viewer/openworlds/index.html
  • viewer/openworlds/screen-combat.jsx
  • viewer/openworlds/screen-map.jsx
  • viewer/openworlds/screen-table.jsx
  • viewer/openworlds/styles.css
  • viewer/server.py
  • viewer/tests/test_openworlds_static.py
📜 Review details
🧰 Additional context used
🧬 Code graph analysis (2)
viewer/openworlds/icon-registry.jsx (1)
viewer/openworlds/vendor/babel-standalone-7.29.0.min.js (1)
  • id (4-4)
viewer/openworlds/screen-map.jsx (1)
viewer/openworlds/chrome.jsx (1)
  • BrassButton (242-249)
🪛 Stylelint (17.12.0)
viewer/openworlds/styles.css

[error] 128-128: Expected "currentColor" to be "currentcolor" (value-keyword-case)

(value-keyword-case)


[error] 129-129: Expected "currentColor" to be "currentcolor" (value-keyword-case)

(value-keyword-case)

🔇 Additional comments (8)
viewer/openworlds/index.html (1)

21-21: LGTM!

viewer/server.py (1)

61-61: LGTM!

THIRD_PARTY_NOTICES.md (1)

42-56: LGTM!

viewer/openworlds/assets/icons/ATTRIBUTION.md (1)

1-31: LGTM!

viewer/openworlds/chrome.jsx (1)

60-63: LGTM!

Also applies to: 232-236

viewer/openworlds/screen-combat.jsx (1)

194-198: LGTM!

Also applies to: 479-481, 498-498

viewer/openworlds/screen-table.jsx (1)

319-319: LGTM!

Also applies to: 338-338, 417-419, 427-427, 498-500, 523-523

viewer/tests/test_openworlds_static.py (1)

5-5: LGTM!

Also applies to: 109-135

Comment thread scripts/license_check.py Outdated
Comment thread viewer/openworlds/icon-registry.jsx
Comment thread viewer/openworlds/screen-map.jsx Outdated
Comment thread viewer/openworlds/screen-table.jsx Outdated
Comment thread viewer/openworlds/styles.css Outdated
@100yenadmin

Copy link
Copy Markdown
Member Author

Pushed c82ef1a to address current-head CodeRabbit feedback:

  • guarded Game Icons attribution/notice reads against OSError
  • normalized semantic icon ids before manifest lookup
  • guarded direct OpenWorlds icon renders in Table/Atlas fallback paths
  • preserved built-in chrome glyphs for Map/Worlds nav scanability
  • normalized CSS keyword casing

Focused validation from /Volumes/LEXAR/repos/ClawDnD-icon-registry:

python3 -m unittest viewer.tests.test_openworlds_static -q
python3 -m py_compile viewer/server.py scripts/license_check.py
python3 scripts/license_check.py
node <vendored Babel transform smoke for touched JSX>
git diff --check

All passed locally. CI is re-running on the new head.

@100yenadmin
100yenadmin marked this pull request as ready for review May 26, 2026 15:25
@100yenadmin
100yenadmin marked this pull request as draft May 26, 2026 16:05
@100yenadmin
100yenadmin force-pushed the openworlds/icon-registry branch from c82ef1a to 77ff6dd Compare May 26, 2026 22:15
@100yenadmin
100yenadmin marked this pull request as ready for review May 26, 2026 22:15
@100yenadmin
100yenadmin merged commit e60faa1 into main May 26, 2026
4 of 5 checks passed
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.

1 participant