fuzzyworld

explodorama / commit

Art provenance audit: docs/art-provenance.md and tools/audit-art.mjs

d64916dfc83b3b1a0421f7eeee7dc065fa3a82d0 · Pavel Safronov · 2026-11-01 10:27:21 -0800 · parents e9c64495b720

Claude Code usage: this commit 38.6K out / 3.9M cached (first commit of its session: everything since it began) · cost unknown (no per-model trailer) · session 9 tally 152 in / 38.6K out / 3.9M cached · usage by commit and session

Art provenance audit: docs/art-provenance.md and tools/audit-art.mjs

Every picture, sound and font is listed with who made it. 125 files are
hash-checked as Kenney's own; the splats, the pointing hand and the sounds
are explained; the composed icons are tied to compose-icons.sh; 14 items
Claude drew by hand are listed to keep, redo or replace (backlog). README
Attribution links to it and now names the two icon folders. Also adds
Valve's Nov 2026 AI policy text for reference.

FW-Tokens-In: 152
FW-Tokens-Out: 38611
FW-Tokens-Cached: 3934724
FW-Session: 20903b28-0dc8-40de-aad7-258052bc2947
FW-Rtk-Saved: 2828946
FW-Rtk-Cmds: 8228

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
 PLAN.md                        |   3 +-
 README.md                      |   7 +-
 docs/art-provenance.md         | 228 +++++++++++++++++++++++++++++++++++++++++
 steam-ai-policy-nov-01-2026.md |  17 +++
 tools/audit-art.mjs            |  53 ++++++++++
 5 files changed, 305 insertions(+), 3 deletions(-)

diff --git a/PLAN.md b/PLAN.md
index 9504cc6..fe25ca5 100644
--- a/PLAN.md
+++ b/PLAN.md
@@ -1046,7 +1046,8 @@ tools/                 compose-icons.sh (composed sprites and the app icons), sc
   art drawn in code, such as the oil highlight's ellipses in `tools/compose-icons.sh`) is either
   Kenney's own or produced by a script in the repo from Kenney's files; list everything made by
   hand or composed by Claude, with how, so the user can keep, redo or replace it. Also confirm the
-  menu and README credits cover every pack used. Queue item Q24.
+  menu and README credits cover every pack used. Done 2026-11-01: [docs/art-provenance.md](docs/art-provenance.md)
+  and `tools/audit-art.mjs`; the keep/redo/replace decisions are backlog (Q39).
 - **A worn dungeon (user request, 2026-10-25; built, then switched off the same day):** *the user:
   the splats looked too alike, and not the look wanted* — `render/decor.ts` stays, off
   (`ENABLED`), until a new approach is chosen. The first idea: use the Splat Pack (approved) to make
diff --git a/README.md b/README.md
index 29e3547..a288933 100644
--- a/README.md
+++ b/README.md
@@ -604,7 +604,9 @@ Art: [New Platformer Pack](https://kenney.nl/assets/new-platformer-pack) 1.1,
 looks the way it does because of it, so it is credited here (it was in the game's menu until 2026-10-31). Thank you, Kenney! Support his work at <https://www.kenney.nl/donate>.
 
 The files used are copied, unchanged and under their original file names, into
-[`assets/kenney/`](assets/kenney/), [`assets/kenney-ui/`](assets/kenney-ui/) (keeping the pack's
+[`assets/kenney/`](assets/kenney/), [`assets/kenney-icons/`](assets/kenney-icons/) and
+[`assets/kenney-board-icons/`](assets/kenney-board-icons/) (Game Icons and Board Game Icons),
+[`assets/kenney-ui/`](assets/kenney-ui/) (keeping the pack's
 colour folders), [`assets/kenney-ui-rpg/`](assets/kenney-ui-rpg/) and
 [`assets/kenney-splat/`](assets/kenney-splat/) (a few of the Splat Pack's splats, scaled down to
 128 px) and [`assets/kenney-foliage/`](assets/kenney-foliage/) (six of Foliage Sprites' white
@@ -613,7 +615,8 @@ shapes, which `tools/compose-icons.sh` tints green and outlines into `assets/com
 is the RPG Expansion's `cursorHand_beige` cut out of the pack's vector sheet
 (`Vector/uipack_rpg_vector.svg`: just its three shapes, unchanged), since the PNG is only 27 px
 across. They
-are not covered by this project's MIT licence.
+are not covered by this project's MIT licence. Who made every picture and sound, and what Claude drew
+by hand, is listed in [docs/art-provenance.md](docs/art-provenance.md).
 
 Sounds: the New Platformer Pack's 10 effects, in [`assets/kenney/sounds/`](assets/kenney/sounds/),
 and the UI Pack's `tap-a` and `switch-a`, in [`assets/kenney-ui/Sounds/`](assets/kenney-ui/Sounds/),
diff --git a/docs/art-provenance.md b/docs/art-provenance.md
new file mode 100644
index 0000000..ec7c8d9
--- /dev/null
+++ b/docs/art-provenance.md
@@ -0,0 +1,228 @@
+# Art provenance audit
+
+Written 2026-11-01. Answers one question for every picture, sound and font in the
+game: **who made it, and how?** Re-check the Kenney part any time with
+`node tools/audit-art.mjs` (needs the unpacked packs, default `~/code/kenney`).
+
+Makers used below:
+
+- **Kenney**: the file is Kenney's, byte for byte (checked by hash against the pack), or a
+  mechanical conversion of one (scaled, converted, cut out).
+- **Script**: made by a script in this repo from Kenney files, so it can be rebuilt. The
+  *design* (which symbol on which sprite, the colours) was chosen by Claude on Pavel's request.
+- **Claude by hand**: Claude wrote the drawing instructions itself (ellipses, polygons, colours,
+  sound parameters). No Kenney shape underneath, or Kenney's shape with Claude's additions.
+- **Generative AI**: no image or sound in the game was produced by an image or sound model.
+  The only AI involvement is that Claude (an AI) wrote the code and the scripts above.
+
+## Summary
+
+| Group | Files | Maker |
+|---|---|---|
+| Kenney, unchanged | 125 images and fonts | Kenney |
+| Splat Pack splats | 14 | Kenney, scaled 256 → 128 px (alpha identical after scaling; saved as grey + alpha) |
+| Pointing hand `cursorHand_beige.svg` | 1 | Kenney, three shapes cut out of the RPG Expansion vector sheet |
+| Sounds | 12 | Kenney, converted `.ogg` → `.mp3` |
+| `assets/composed/` | 34 | Script `tools/compose-icons.sh` from Kenney files (see below) |
+| `static/icons/` | 4 | Script `tools/compose-icons.sh`: Kenney bomb on a sky-blue square |
+| Drawn in code | many | Claude by hand (see below) |
+| Three sounds made in code | 3 | Claude by hand (ZzFX numbers) |
+| `docs/screenshots/` | 30 | Script `tools/screenshots.mjs` (screenshots of the game itself) |
+
+## Things Claude made by hand (decide: keep, redo or replace)
+
+These are the items with no Kenney shape behind them, or with Claude's own drawing on top.
+
+| # | What | Where | How it was made |
+|---|---|---|---|
+| 1 | **Oil spill** `composed/oil.png` | `compose-icons.sh` | Splat05 turned near black, plus **two white-ish ellipses** drawn as a gloss highlight (`ellipse 52,46 16,7` and `ellipse 76,70 7,3`). The ellipses are Claude's. |
+| 2 | **Rainbow gem** `composed/gem_rainbow.png` | `compose-icons.sh` | Kenney's green gem recoloured with a red-to-violet gradient (Overlay blend) that Claude defined. Plus, in code (`drawRainbowGem`, board.ts), five twinkling Kenney stars orbiting it. |
+| 3 | **Metal crate** `composed/block_metal.png` | `compose-icons.sh` | Kenney's strong crate, desaturated and tinted steel grey. |
+| 4 | **Bushes** `composed/grass_*`, `canopy_*` | `compose-icons.sh` | Foliage Sprites' white shapes, tinted green, given a dark outline built by dilating the alpha. Kenney's shape, Claude's colour and outline. |
+| 5 | **Ice block** | `drawIce`, board.ts | Frost-coloured square, four rim lines and one glint stroke, drawn in code, with three twinkling Kenney `star` sprites on top. |
+| 6 | **Cracks** on a pillar that Acid has reached | `drawCracks`, board.ts | Line segments drawn in code. |
+| 8 | **Arrows** (move hints, kick direction) | `drawArrow`, board.ts | One polygon, 7 points, drawn in code. |
+| 9 | **Floor checkerboard** | `drawBoard`, board.ts | Two flat colours, `drawRect`. |
+| 10 | **Stone wall outlines, dust, smoke puffs, flame and burning tiles** | board.ts | Rectangles and circles with alpha, drawn in code. Flame and burning tiles also carry Kenney's `fireball` sprite on top. Dust and smoke are circles only. |
+| 11 | **Danger, target, blast preview, path overlays** | board.ts | Coloured squares and lines. |
+| 12 | **Shield ring, flame-pass ring, star-power ring, armed pulse, hit flash, the white disc behind off-screen indicators** | board.ts | Circles drawn in code. |
+| 13 | **Boom, bomb set down, ICBM launch sounds** | `src/ui/feedback.ts` | ZzFX parameter lists written by Claude; the sound is synthesised in the browser. |
+| 14 | **Old-TV look of the demo** (scanlines, vignette, snow) | `src/style.css` `#demo-crt`, ~1394-1508 | CSS gradients and an inline SVG noise filter. |
+| 15 | **Button/panel layout, dialogs, toasts, caption panels** | `src/style.css` | CSS using Kenney's UI Pack frames; the arrangement is Claude's. |
+
+Also in code but **not** hand-drawn: the decoy is Kenney's `character_green_front` sprite tinted pale
+(`drawDecoy`), and sprites tinted when drawn (the splats on the floor, oil) keep Kenney's shape.
+
+## Composed icons (`assets/composed/`, all from `tools/compose-icons.sh`)
+
+Badge = green disc with dark rim, upper right, Kenney symbol on it. Base sprites are Kenney's.
+
+| File | Base | Symbol or treatment |
+|---|---|---|
+| icon_move, icon_wait, icon_fuse | board-icons character, hourglass, timer_CW_75 | Recoloured to the UI ink colour |
+| powerup_bomb_plus | bomb | game-icons plus |
+| powerup_fire_plus | bomb | game-icons larger |
+| powerup_fuse_plus | bomb | board-icons timer |
+| powerup_run | icon_move | game-icons fastForward |
+| powerup_kick | bomb | game-icons arrowRight |
+| powerup_throw | bomb | game-icons upRight |
+| powerup_teleport | icon_move | game-icons export |
+| powerup_diagonal | icon_move | board-icons arrow_diagonal_cross |
+| powerup_detonator | bomb | game-icons exclamation |
+| powerup_wall_pass | block_planks | game-icons cross |
+| powerup_bomb_pass | bomb | board-icons shield |
+| powerup_flame_pass | fireball | board-icons shield |
+| charge_nuke | bomb | board-icons skull |
+| charge_freeze | game-icons locked | Recoloured to the ink colour |
+| charge_decoy | board-icons pawns | Recoloured to the ink colour |
+| powerup_rpg | bomb | game-icons forward |
+| powerup_proximity | bomb | game-icons warning |
+| powerup_slide | icon_move | board-icons arrow_horizontal |
+| charge_icbm | bomb | game-icons target |
+| powerup_tnt | fireball | game-icons larger |
+| charge_acid | bomb | board-icons flask_full |
+| charge_shield | board-icons timer_0 | icon_move inside the ring |
+| block_metal, oil, gem_rainbow, grass_a-d, canopy_a-b | see the list above | |
+
+## Verbatim Kenney files (hash-checked)
+
+| File (under assets/) | Pack | Path in the pack |
+|---|---|---|
+| kenney-board-icons/arrow_diagonal_cross.png | board-game-icons | PNG/Double (128px)/arrow_diagonal_cross.png |
+| kenney-board-icons/arrow_horizontal.png | board-game-icons | PNG/Double (128px)/arrow_horizontal.png |
+| kenney-board-icons/character.png | board-game-icons | PNG/Double (128px)/character.png |
+| kenney-board-icons/dice_3D_detailed.png | board-game-icons | PNG/Double (128px)/dice_3D_detailed.png |
+| kenney-board-icons/flask_full.png | board-game-icons | PNG/Double (128px)/flask_full.png |
+| kenney-board-icons/hourglass.png | board-game-icons | PNG/Double (128px)/hourglass.png |
+| kenney-board-icons/pawns.png | board-game-icons | PNG/Double (128px)/pawns.png |
+| kenney-board-icons/shield.png | board-game-icons | PNG/Double (128px)/shield.png |
+| kenney-board-icons/skull.png | board-game-icons | PNG/Double (128px)/skull.png |
+| kenney-board-icons/timer_0.png | board-game-icons | PNG/Double (128px)/timer_0.png |
+| kenney-board-icons/timer_CW_75.png | board-game-icons | PNG/Double (128px)/timer_CW_75.png |
+| kenney-foliage/sprite_0052.png | foliage-sprites | PNG/Shaded/sprite_0052.png |
+| kenney-foliage/sprite_0053.png | foliage-sprites | PNG/Shaded/sprite_0053.png |
+| kenney-foliage/sprite_0062.png | foliage-sprites | PNG/Shaded/sprite_0062.png |
+| kenney-foliage/sprite_0063.png | foliage-sprites | PNG/Shaded/sprite_0063.png |
+| kenney-foliage/sprite_0090.png | foliage-sprites | PNG/Shaded/sprite_0090.png |
+| kenney-foliage/sprite_0091.png | foliage-sprites | PNG/Shaded/sprite_0091.png |
+| kenney-icons/White/arrowRight.png | game-icons | PNG/White/2x/arrowRight.png |
+| kenney-icons/White/cross.png | game-icons | PNG/White/2x/cross.png |
+| kenney-icons/White/exclamation.png | game-icons | PNG/White/2x/exclamation.png |
+| kenney-icons/White/export.png | game-icons | PNG/White/2x/export.png |
+| kenney-icons/White/fastForward.png | game-icons | PNG/White/2x/fastForward.png |
+| kenney-icons/White/forward.png | game-icons | PNG/White/1x/forward.png |
+| kenney-icons/White/larger.png | game-icons | PNG/White/2x/larger.png |
+| kenney-icons/White/locked.png | game-icons | PNG/White/2x/locked.png |
+| kenney-icons/White/plus.png | game-icons | PNG/White/2x/plus.png |
+| kenney-icons/White/target.png | game-icons | PNG/White/1x/target.png |
+| kenney-icons/White/upRight.png | game-icons | PNG/White/2x/upRight.png |
+| kenney-icons/White/warning.png | game-icons | PNG/White/1x/warning.png |
+| kenney-icons/question.png | game-icons | PNG/Black/2x/question.png |
+| kenney-ui-rpg/panel_beigeLight.png | ui-pack-rpg-expansion | PNG/panel_beigeLight.png |
+| kenney-ui/Extra/icon_play_light.png | ui-pack | PNG/Extra/Double/icon_play_light.png |
+| kenney-ui/Extra/icon_repeat_light.png | ui-pack | PNG/Extra/Double/icon_repeat_light.png |
+| kenney-ui/Green/button_rectangle_depth_flat.png | ui-pack | PNG/Green/Double/button_rectangle_depth_flat.png |
+| kenney-ui/Green/button_round_depth_flat.png | ui-pack | PNG/Green/Double/button_round_depth_flat.png |
+| kenney-ui/Grey/button_rectangle_depth_flat.png | ui-pack | PNG/Grey/Double/button_rectangle_depth_flat.png |
+| kenney-ui/Grey/button_round_depth_flat.png | ui-pack | PNG/Grey/Double/button_round_depth_flat.png |
+| kenney-ui/Grey/icon_cross.png | ui-pack | PNG/Grey/Double/icon_cross.png |
+| kenney-ui/Kenney Future.ttf | ui-pack | Font/Kenney Future.ttf |
+| kenney-ui/Red/button_rectangle_depth_flat.png | ui-pack | PNG/Red/Double/button_rectangle_depth_flat.png |
+| kenney/block_blue.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/block_blue.png |
+| kenney/block_green.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/block_green.png |
+| kenney/block_planks.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/block_planks.png |
+| kenney/block_red.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/block_red.png |
+| kenney/block_strong_danger.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/block_strong_danger.png |
+| kenney/block_strong_empty.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/block_strong_empty.png |
+| kenney/block_yellow.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/block_yellow.png |
+| kenney/bomb.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/bomb.png |
+| kenney/bomb_active.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/bomb_active.png |
+| kenney/bridge_logs.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/bridge_logs.png |
+| kenney/bush.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/bush.png |
+| kenney/chain.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/chain.png |
+| kenney/character_green_climb_a.png | new-platformer-pack-1.1 | Sprites/Characters/Default/character_green_climb_a.png |
+| kenney/character_green_climb_b.png | new-platformer-pack-1.1 | Sprites/Characters/Default/character_green_climb_b.png |
+| kenney/character_green_duck.png | new-platformer-pack-1.1 | Sprites/Characters/Default/character_green_duck.png |
+| kenney/character_green_front.png | new-platformer-pack-1.1 | Sprites/Characters/Default/character_green_front.png |
+| kenney/character_green_hit.png | new-platformer-pack-1.1 | Sprites/Characters/Default/character_green_hit.png |
+| kenney/character_green_idle.png | new-platformer-pack-1.1 | Sprites/Characters/Default/character_green_idle.png |
+| kenney/character_green_jump.png | new-platformer-pack-1.1 | Sprites/Characters/Default/character_green_jump.png |
+| kenney/character_green_walk_a.png | new-platformer-pack-1.1 | Sprites/Characters/Default/character_green_walk_a.png |
+| kenney/character_green_walk_b.png | new-platformer-pack-1.1 | Sprites/Characters/Default/character_green_walk_b.png |
+| kenney/coin_bronze.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/coin_bronze.png |
+| kenney/coin_gold.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/coin_gold.png |
+| kenney/coin_silver.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/coin_silver.png |
+| kenney/door_closed_top.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/door_closed_top.png |
+| kenney/door_open_top.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/door_open_top.png |
+| kenney/fireball.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/fireball.png |
+| kenney/flag_green_a.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/flag_green_a.png |
+| kenney/fly_a.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/fly_a.png |
+| kenney/fly_b.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/fly_b.png |
+| kenney/fly_rest.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/fly_rest.png |
+| kenney/frog_idle.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/frog_idle.png |
+| kenney/frog_jump.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/frog_jump.png |
+| kenney/frog_rest.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/frog_rest.png |
+| kenney/gem_blue.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/gem_blue.png |
+| kenney/gem_green.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/gem_green.png |
+| kenney/gem_red.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/gem_red.png |
+| kenney/gem_yellow.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/gem_yellow.png |
+| kenney/heart.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/heart.png |
+| kenney/hud_character_0.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_character_0.png |
+| kenney/hud_character_1.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_character_1.png |
+| kenney/hud_character_2.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_character_2.png |
+| kenney/hud_character_3.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_character_3.png |
+| kenney/hud_character_4.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_character_4.png |
+| kenney/hud_character_5.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_character_5.png |
+| kenney/hud_character_6.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_character_6.png |
+| kenney/hud_character_7.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_character_7.png |
+| kenney/hud_character_8.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_character_8.png |
+| kenney/hud_character_9.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_character_9.png |
+| kenney/hud_coin.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_coin.png |
+| kenney/hud_heart.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_heart.png |
+| kenney/hud_heart_empty.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_heart_empty.png |
+| kenney/hud_player_helmet_green.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/hud_player_helmet_green.png |
+| kenney/lever.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/lever.png |
+| kenney/lock_yellow.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/lock_yellow.png |
+| kenney/mouse_rest.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/mouse_rest.png |
+| kenney/mouse_walk_a.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/mouse_walk_a.png |
+| kenney/mouse_walk_b.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/mouse_walk_b.png |
+| kenney/ramp.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/ramp.png |
+| kenney/rock.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/rock.png |
+| kenney/saw_a.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/saw_a.png |
+| kenney/saw_b.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/saw_b.png |
+| kenney/saw_rest.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/saw_rest.png |
+| kenney/slime_block_jump.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/slime_block_jump.png |
+| kenney/slime_block_rest.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/slime_block_rest.png |
+| kenney/slime_block_walk_a.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/slime_block_walk_a.png |
+| kenney/slime_block_walk_b.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/slime_block_walk_b.png |
+| kenney/slime_fire_flat.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/slime_fire_flat.png |
+| kenney/slime_fire_rest.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/slime_fire_rest.png |
+| kenney/slime_fire_walk_a.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/slime_fire_walk_a.png |
+| kenney/slime_fire_walk_b.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/slime_fire_walk_b.png |
+| kenney/slime_normal_flat.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/slime_normal_flat.png |
+| kenney/slime_normal_rest.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/slime_normal_rest.png |
+| kenney/slime_normal_walk_a.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/slime_normal_walk_a.png |
+| kenney/slime_normal_walk_b.png | new-platformer-pack-1.1 | Sprites/Enemies/Double/slime_normal_walk_b.png |
+| kenney/spikes.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/spikes.png |
+| kenney/star.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/star.png |
+| kenney/switch_blue.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/switch_blue.png |
+| kenney/terrain_stone_block_bottom_left.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/terrain_stone_block_bottom_left.png |
+| kenney/terrain_stone_block_bottom_right.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/terrain_stone_block_bottom_right.png |
+| kenney/terrain_stone_block_top_left.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/terrain_stone_block_top_left.png |
+| kenney/terrain_stone_block_top_right.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/terrain_stone_block_top_right.png |
+| kenney/terrain_stone_horizontal_middle.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/terrain_stone_horizontal_middle.png |
+| kenney/terrain_stone_vertical_middle.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/terrain_stone_vertical_middle.png |
+| kenney/weight.png | new-platformer-pack-1.1 | Sprites/Tiles/Double/weight.png |
+
+## Findings
+
+- **README wording**: the Attribution section says the files are copied "unchanged". That is
+  true for all images except the 14 splats (scaled) and the pointing-hand SVG (cut out); it names
+  both. The sounds are described as converted. Its list of folders leaves out
+  `assets/kenney-icons/` and `assets/kenney-board-icons/` (to fix). It names all seven packs in
+  use, so the credits cover every pack.
+- **No script records the splat scaling or the .ogg → .mp3 conversion.** They were done once
+  by hand. They can't be rebuilt from the repo alone. Could add `tools/` scripts if wanted.
+- **`assets/kenney-ui/.DS_Store`** is a stray macOS file; harmless (ignored by `.gitignore`).
+- **Not checked**: that the mp3s match the packs' sounds in content (the bytes differ by
+  design; the names match 12 of 12 `.ogg` files in the packs).
diff --git a/steam-ai-policy-nov-01-2026.md b/steam-ai-policy-nov-01-2026.md
new file mode 100644
index 0000000..03e2492
--- /dev/null
+++ b/steam-ai-policy-nov-01-2026.md
@@ -0,0 +1,17 @@
+Back in June, we shared that while our goal continues to be shipping as many games as possible on Steam, we needed some time to learn about the fast-moving and legally murky space of AI technology, especially given Steam's worldwide reach.
+
+Today, after spending the last few months learning more about this space and talking with game developers, we are making changes to how we handle games that use AI technology. This will enable us to release the vast majority of games that use it.
+
+First, we are updating the Content Survey that developers fill out when submitting to Steam. The survey now includes a new AI disclosure section, where you'll need to describe how you are using AI in the development and execution of your game. It separates AI usage in games into two broad categories:
+
+    Pre-Generated: Any kind of content (art/code/sound/etc) created with the help of AI tools during development. Under the Steam Distribution Agreement, you promise Valve that your game will not include illegal or infringing content, and that your game will be consistent with your marketing materials. In our pre-release review, we will evaluate the output of AI generated content in your game the same way we evaluate all non-AI content - including a check that your game meets those promises.
+    Live-Generated: Any kind of content created with the help of AI tools while the game is running. In addition to following the same rules as Pre-Generated AI content, this comes with an additional requirement: in the Content Survey, you'll need to tell us what kind of guardrails you're putting on your AI to ensure it's not generating illegal content.
+
+
+Valve will use this disclosure in our review of your game prior to release. We will also include much of your disclosure on the Steam store page for your game, so customers can also understand how the game uses AI.
+
+Second, we're releasing a new system on Steam that allows players to report illegal content inside games that contain Live-Generated AI content. Using the in-game overlay, players can easily submit a report when they encounter content that they believe should have been caught by appropriate guardrails on AI generation.
+
+Today's changes are the result of us improving our understanding of the landscape and risks in this space, as well as talking to game developers using AI, and those building AI tools. This will allow us to be much more open to releasing games using AI technology on Steam. The only exception to this will be Adult Only Sexual Content that is created with Live-Generated AI - we are unable to release that type of content right now.
+
+It's taken us some time to figure this out, and we're sorry that has made it harder for some developers to make decisions around their games. But we don't feel like we serve our players or developer partners by rushing into decisions that have this much complexity. We'll continue to learn from the games being submitted to Steam, and the legal progress around AI, and will revisit this decision when necessary.
\ No newline at end of file
diff --git a/tools/audit-art.mjs b/tools/audit-art.mjs
new file mode 100644
index 0000000..dbe1916
--- /dev/null
+++ b/tools/audit-art.mjs
@@ -0,0 +1,53 @@
+// Art provenance check (2026-11-01): is every file under assets/kenney* really Kenney's?
+// Hashes each file and looks for the same bytes anywhere in a folder of unpacked Kenney packs.
+// Files that match are "verbatim"; the rest are listed, so each can be explained in
+// docs/art-provenance.md (a scaled copy, a converted sound). The packs are not in the repo.
+//
+//   node tools/audit-art.mjs [folder of unpacked packs, default ~/code/kenney] [--table]
+//
+// --table prints the verbatim files as markdown rows (file | pack | pack path).
+import { createHash } from 'node:crypto'
+import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'
+import { homedir } from 'node:os'
+import { join, relative } from 'node:path'
+import { fileURLToPath } from 'node:url'
+
+const args = process.argv.slice(2)
+const table = args.includes('--table')
+const packs = args.find((a) => !a.startsWith('--')) ?? join(homedir(), 'code/kenney')
+const repo = fileURLToPath(new URL('..', import.meta.url))
+if (!existsSync(packs)) {
+  console.error(`No folder of Kenney packs at ${packs}; pass its path as the first argument.`)
+  process.exit(1)
+}
+
+const walk = (dir) =>
+  readdirSync(dir).flatMap((n) => {
+    const p = join(dir, n)
+    return statSync(p).isDirectory() ? walk(p) : [p]
+  })
+const md5 = (p) => createHash('md5').update(readFileSync(p)).digest('hex')
+
+const byHash = new Map()
+for (const p of walk(packs).filter((f) => !f.endsWith('.zip'))) byHash.set(md5(p), relative(packs, p))
+
+const verbatim = []
+const other = []
+for (const p of walk(join(repo, 'assets')).sort()) {
+  const rel = relative(repo, p)
+  if (/composed\/|\.DS_Store|License\.txt|license\.txt/i.test(rel)) continue
+  const hit = byHash.get(md5(p))
+  if (hit) verbatim.push([rel, hit])
+  else other.push(rel)
+}
+
+if (table) {
+  for (const [rel, hit] of verbatim) {
+    const [pack, ...rest] = hit.split('/')
+    console.log(`| ${rel.replace('assets/', '')} | ${pack.replace('kenney_', '')} | ${rest.join('/')} |`)
+  }
+} else {
+  console.log(`${verbatim.length} files are byte-identical to a file in ${packs}`)
+  console.log(`${other.length} are not (explain each in docs/art-provenance.md):`)
+  for (const rel of other) console.log('  ' + rel)
+}