README as a small game website in Crookfinger's voice; INSTALL.md, BESTIARY.md, playable standalone file

- README: logo, badges (Rust, WebAssembly, Claude Code, MIT), intro addressed to the master, features with screenshots, the household, how to play, licences and credits
- INSTALL.md: server, PWA, building, tests, savegame service and API, languages, how to refresh generated files
- BESTIARY.md generated from the game's data (tools/make_bestiary.py) with exported sprites and icons (docs/img, test export_doc_images)
- play/DungeonCraft.html: the whole game in one file to download and play offline

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-04 07:46:37 +01:00
1 parent 4ce2c2919e
commit b3583f5e7e
124 files changed
+1178 -104

No files matched your search

+47
View File
@@ -1975,3 +1975,50 @@ impl Gfx {
}
}
}
#[cfg(test)]
mod doc_images {
use super::*;
// writes a picture scaled up with nearest pixels
fn save(img: &Image, src: Rect, scale: u32, path: &str) {
let (w, h) = (src.w as u32 * scale, src.h as u32 * scale);
let mut out = Image::gen_image_color(w as u16, h as u16, Color::new(0.0, 0.0, 0.0, 0.0));
for y in 0..h {
for x in 0..w {
let p = img.get_pixel(src.x as u32 + x / scale, src.y as u32 + y / scale);
out.set_pixel(x, y, p);
}
}
out.export_png(path);
}
// `cargo test --release export_doc_images -- --ignored` refreshes the pictures in docs/img
#[test]
#[ignore]
fn export_doc_images() {
std::fs::create_dir_all("docs/img/units").unwrap();
std::fs::create_dir_all("docs/img/icons").unwrap();
let sprites = gen_sprites();
for &k in SPRITE_KINDS.iter() {
let id = crate::game::st(k).name.trim_start_matches("unit.");
for (lv, tag) in [(1u32, "1"), (5, "5"), (10, "10")] {
save(&sprites, Gfx::sprite_cell(k, false, lv), 8, &format!("docs/img/units/{}_{}.png", id, tag));
}
}
let atlas = gen_atlas();
for (k, t) in crate::traps::TRAP_KINDS.iter().enumerate() {
save(&atlas, Gfx::cell(I_TRAPS + k as u32), 4, &format!("docs/img/icons/{}.png", t.id()));
}
for (k, s) in crate::spells::SPELLS.iter().enumerate() {
save(&atlas, Gfx::cell(I_SPELLS + k as u32), 4, &format!("docs/img/icons/{}.png", s.id()));
}
for (id, cell) in [("lightning", I_BOLT), ("heal", I_HEAL), ("summon", I_SUMMON), ("arrow", I_ARROW), ("cannon", I_CANNON), ("magic", I_MAGIC), ("rune", I_RUNE)] {
save(&atlas, Gfx::cell(cell), 4, &format!("docs/img/icons/{}.png", id));
}
for (k, id) in crate::game::ROOM_NAMES.iter().enumerate() {
let tex = crate::ui::tool_info(crate::ui::Tool::Room(k)).icon;
save(&atlas, Gfx::cell(tex), 4, &format!("docs/img/icons/{}.png", id.trim_start_matches("room.")));
}
}
}