make-portraits: draw the body plan, not the species
portraitSvg read `spec.species` for both the silhouette and the hit-location table. Every creature with a non-human body carries `species: "baseline"` and says what it is in `bodyPlan`, so the guildhall gryphon's own generated portrait described it as "baseline, 7 hit locations" and drew a human figure for an eagle-lion with wings. 48 creatures were affected — 32 quadrupeds and 16 winged. It is the same defect, in the same shape, as the anatomy clause in mj-queue.mjs: that one read `species` where the shape lives in `bodyPlan`, and drew a wingless gryphon. I fixed it there earlier tonight and did not look one file over, in the other tool that draws a creature from its statblock. R-264 settled this rule for the harness — `bodyPlan ?? species` — and build-packs:294 writes it to the actor's speciesProfile. Only two files change on disk, because 46 of the 48 already have hand-drawn plates and are correctly skipped. Those two are martlet and moor_cat, whose Midjourney art has now failed twice, so they are exactly the creatures falling back on the generated figure: martlet is winged with 10 locations and moor_cat quadruped with 8, where both were human before. The other 139 rewrote byte-identically, which is what a deterministic generator should do and is worth knowing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e7a584cc60
commit
45df79d712
+13
-10
@@ -1,17 +1,20 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="256" height="256">
|
||||
<title>The martlet</title>
|
||||
<desc>The martlet — baseline, SIZ 3, 7 hit locations, natural armour 0, antique. Generated by tools/make-portraits.mjs; do not edit by hand.</desc>
|
||||
<desc>The martlet — winged, SIZ 3, 10 hit locations, natural armour 0, antique. Generated by tools/make-portraits.mjs; do not edit by hand.</desc>
|
||||
<rect width="256" height="256" rx="30" fill="hsl(22 38% 27%)"/>
|
||||
<path d="M0 0h52L0 52z" fill="hsl(22 44% 17%)"/>
|
||||
<ellipse cx="128.0" cy="230.4" rx="30.3" ry="4.2" fill="hsl(22 44% 17%)" opacity="0.8"/>
|
||||
<g transform="translate(98.87 132.66) scale(0.4855 0.4987)">
|
||||
<ellipse cx="60" cy="21" rx="15" ry="17" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="40" y="42" width="40" height="40" rx="9" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="44" y="84" width="32" height="30" rx="8" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="18" y="45" width="17" height="64" rx="8" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="85" y="45" width="17" height="64" rx="8" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="43" y="117" width="15" height="72" rx="7" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="62" y="117" width="15" height="72" rx="7" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<ellipse cx="128.0" cy="230.4" rx="78.0" ry="10.9" fill="hsl(22 44% 17%)" opacity="0.8"/>
|
||||
<g transform="translate(53.03 132.66) scale(0.7209 0.7405)">
|
||||
<path d="M96 40 L44 6 L18 26 L74 52 Z" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<path d="M100 44 L58 92 L82 116 L114 62 Z" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="34" y="44" width="56" height="40" rx="13" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="86" y="40" width="60" height="46" rx="13" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<path d="M138 46 L172 26 L184 42 L150 64 Z" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<ellipse cx="184" cy="30" rx="18" ry="13" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="42" y="82" width="12" height="40" rx="6" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="60" y="82" width="12" height="40" rx="6" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="102" y="84" width="12" height="38" rx="6" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="120" y="84" width="12" height="38" rx="6" fill="hsl(22 50% 78%)" stroke="hsl(22 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
|
||||
</g>
|
||||
<g transform="translate(194 198) scale(1.15)" opacity="0.92"><path d="M6 8c8 6 12 16 12 30M18 6c8 6 12 16 12 30M30 8c6 6 9 14 9 26" fill="none" stroke="hsl(22 38% 48%)" stroke-width="4" stroke-linecap="round"/></g>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.3 KiB |
+19
-17
@@ -1,24 +1,26 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="256" height="256">
|
||||
<title>The moor cat</title>
|
||||
<desc>The moor cat — baseline, SIZ 14, 7 hit locations, natural armour 2, antique. Generated by tools/make-portraits.mjs; do not edit by hand.</desc>
|
||||
<desc>The moor cat — quadruped, SIZ 14, 8 hit locations, natural armour 2, antique. Generated by tools/make-portraits.mjs; do not edit by hand.</desc>
|
||||
<rect width="256" height="256" rx="30" fill="hsl(33 38% 27%)"/>
|
||||
<path d="M0 0h52L0 52z" fill="hsl(33 44% 17%)"/>
|
||||
<ellipse cx="128.0" cy="230.4" rx="57.2" ry="8.0" fill="hsl(33 44% 17%)" opacity="0.8"/>
|
||||
<g transform="translate(72.97 64.43) scale(0.9172 0.8468)">
|
||||
<ellipse cx="60" cy="21" rx="15" ry="17" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="40" y="42" width="40" height="40" rx="9" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="44" y="84" width="32" height="30" rx="8" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="18" y="45" width="17" height="64" rx="8" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="85" y="45" width="17" height="64" rx="8" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="43" y="117" width="15" height="72" rx="7" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="62" y="117" width="15" height="72" rx="7" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<ellipse cx="60" cy="21" rx="15" ry="17" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<rect x="40" y="42" width="40" height="40" rx="9" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<rect x="44" y="84" width="32" height="30" rx="8" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<rect x="18" y="45" width="17" height="64" rx="8" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<rect x="85" y="45" width="17" height="64" rx="8" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<rect x="43" y="117" width="15" height="72" rx="7" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<rect x="62" y="117" width="15" height="72" rx="7" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<ellipse cx="128.0" cy="230.4" rx="147.3" ry="20.6" fill="hsl(33 44% 17%)" opacity="0.8"/>
|
||||
<g transform="translate(-13.64 64.43) scale(1.3620 1.2573)">
|
||||
<rect x="34" y="42" width="58" height="44" rx="14" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="88" y="38" width="62" height="50" rx="14" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<path d="M142 44 L176 24 L188 40 L154 62 Z" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<ellipse cx="186" cy="28" rx="19" ry="14" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="40" y="84" width="13" height="44" rx="6" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="60" y="84" width="13" height="44" rx="6" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="104" y="86" width="13" height="42" rx="6" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="124" y="86" width="13" height="42" rx="6" fill="hsl(33 50% 78%)" stroke="hsl(33 44% 17%)" stroke-width="3" stroke-linejoin="round"/>
|
||||
<rect x="34" y="42" width="58" height="44" rx="14" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<rect x="88" y="38" width="62" height="50" rx="14" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<path d="M142 44 L176 24 L188 40 L154 62 Z" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<ellipse cx="186" cy="28" rx="19" ry="14" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<rect x="40" y="84" width="13" height="44" rx="6" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<rect x="60" y="84" width="13" height="44" rx="6" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<rect x="104" y="86" width="13" height="42" rx="6" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
<rect x="124" y="86" width="13" height="42" rx="6" fill="none" stroke="hsl(33 78% 62%)" stroke-width="3.70" opacity="0.46" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<g transform="translate(194 198) scale(1.15)" opacity="0.92"><path d="M6 8c8 6 12 16 12 30M18 6c8 6 12 16 12 30M30 8c6 6 9 14 9 26" fill="none" stroke="hsl(33 38% 48%)" stroke-width="4" stroke-linecap="round"/></g>
|
||||
<rect x="6" y="6" width="244" height="244" rx="26" fill="none" stroke="hsl(33 78% 62%)" stroke-width="5"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.2 KiB |
@@ -1 +1 @@
|
||||
MANIFEST-000013
|
||||
MANIFEST-000004
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -250,9 +250,20 @@ function part(shape, attrs) {
|
||||
}
|
||||
|
||||
export function portraitSvg(spec, kind = "npc") {
|
||||
/* THE BODY PLAN, not the species — `spec.bodyPlan ?? spec.species`, which is the rule
|
||||
R-264 settled for the harness and build-packs:294 writes to the actor's
|
||||
speciesProfile. This read `species` alone, and every creature with a non-baseline
|
||||
body has `species: "baseline"`: the guildhall gryphon's own generated portrait
|
||||
described it as "baseline, 7 hit locations" and drew a human silhouette for an
|
||||
eagle-lion with wings. 48 creatures were affected, 32 quadrupeds and 16 winged.
|
||||
|
||||
The same defect, in the same shape, as the one in mj-queue's anatomy clause — fixed
|
||||
there earlier and not looked for here, one file away, in the other tool that draws a
|
||||
creature from its statblock. */
|
||||
const species = spec.species ?? "baseline";
|
||||
const art = BODY_ART[species] ?? BODY_ART.baseline;
|
||||
const table = LOCATION_TABLES[species] ?? LOCATION_TABLES.baseline;
|
||||
const plan = spec.bodyPlan ?? species;
|
||||
const art = BODY_ART[plan] ?? BODY_ART[species] ?? BODY_ART.baseline;
|
||||
const table = LOCATION_TABLES[plan] ?? LOCATION_TABLES[species] ?? LOCATION_TABLES.baseline;
|
||||
const era = eraOf(spec);
|
||||
const muted = era === "antique";
|
||||
|
||||
@@ -329,7 +340,7 @@ export function portraitSvg(spec, kind = "npc") {
|
||||
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${S} ${S}" width="${S}" height="${S}">
|
||||
<title>${esc(spec.name)}</title>
|
||||
<desc>${esc(spec.name)} — ${species}, SIZ ${spec.ch?.siz ?? "?"}, `
|
||||
<desc>${esc(spec.name)} — ${plan}, SIZ ${spec.ch?.siz ?? "?"}, `
|
||||
+ `${table.locations.length} hit locations, natural armour ${nat}, ${era}. `
|
||||
+ `Generated by tools/make-portraits.mjs; do not edit by hand.</desc>
|
||||
<rect width="${S}" height="${S}" rx="30" fill="${bg1}"/>
|
||||
|
||||
Reference in New Issue
Block a user