Improve remaining low-detail weapon icons

This commit is contained in:
2026-07-10 00:38:42 +09:00
parent 72253a44d0
commit 7ff5baa12c
5 changed files with 182 additions and 32 deletions

View File

@@ -30,22 +30,24 @@ Generated by `scripts/audit-equipment-icon-quality.mjs`.
- The previous shared armor and robe silhouettes now use item-specific helper shapes with stronger outer contours and material cues.
- accessory charms and tokens: `bravery-token`, `mountain-guide-scroll`, `peach-charm`, `war-manual`, `wind-quiver`, `grain-pouch`, `yellow-scarf-charm`
- Accessory icons now use distinct badge, scroll, charm, pouch, manual, and quiver silhouettes at small camp UI sizes.
- remaining low-detail weapon icons: `leader-axe`, `training-sword`, `yellow-turban-saber`
- The final low-detail common weapons now use dedicated axe, training sword, and Yellow Turban saber silhouettes.
## Next Improvement Target
- Target: remaining low-detail equipment icons
- Item ids: `leader-axe`, `training-sword`, `yellow-turban-saber`
- Reason: All named batches are complete; remaining work should be selected from the low-detail inventory rows.
- Target: no flagged equipment icon batch
- Item ids: none currently flagged
- Reason: No generated equipment icon currently has a low-detail or shared-helper audit concern; choose the next visual asset pass from in-game QA.
## Highest-Risk Shared Silhouette Groups
| score | signature | slots | ranks | items |
| ---: | --- | --- | --- | --- |
| 6 | `drawAxeIcon` | weapon | common | `leader-axe` |
| 6 | `drawSaberIcon` | weapon | common | `yellow-turban-saber` |
| 6 | `drawSwordIcon` | weapon | common | `training-sword` |
| 5 | `drawFanIcon` | weapon | treasure | `white-feather-fan` |
| 5 | `drawGreenDragonGlaiveIcon` | weapon | treasure | `green-dragon-glaive` |
| 5 | `drawSerpentSpearIcon` | weapon | treasure | `serpent-spear` |
| 5 | `drawSkyPiercerHalberdIcon` | weapon | treasure | `sky-piercer-halberd` |
| 5 | `drawSwordIcon+drawSwordIcon` | weapon | treasure | `twin-oath-blades` |
## Full Item Inventory
@@ -57,11 +59,11 @@ Generated by `scripts/audit-equipment-icon-quality.mjs`.
| `twin-oath-blades` | weapon | treasure | `drawSwordIcon`<br>`drawSwordIcon` | 2 | 32 | 4 | none |
| `white-feather-fan` | weapon | treasure | `drawFanIcon` | 1 | 19 | 3 | none |
| `iron-spear` | weapon | common | `drawIronSpearIcon` | 1 | 26 | 7 | none |
| `leader-axe` | weapon | common | `drawAxeIcon` | 1 | 7 | 2 | low primitive detail |
| `leader-axe` | weapon | common | `drawLeaderAxeIcon` | 1 | 26 | 8 | none |
| `short-bow` | weapon | common | `drawBowIcon` | 1 | 18 | 3 | none |
| `training-sword` | weapon | common | `drawSwordIcon` | 1 | 16 | 4 | low primitive detail |
| `training-sword` | weapon | common | `drawTrainingSwordIcon` | 1 | 31 | 7 | none |
| `western-cavalry-spear` | weapon | common | `drawWesternCavalrySpearIcon` | 1 | 27 | 7 | none |
| `yellow-turban-saber` | weapon | common | `drawSaberIcon` | 1 | 12 | 2 | low primitive detail |
| `yellow-turban-saber` | weapon | common | `drawYellowTurbanSaberIcon` | 1 | 35 | 4 | none |
| `oath-robe` | armor | treasure | `drawOathRobeIcon` | 1 | 25 | 6 | none |
| `reinforced-lamellar` | armor | treasure | `drawReinforcedLamellarIcon` | 1 | 24 | 5 | none |
| `cloth-armor` | armor | common | `drawClothArmorIcon` | 1 | 24 | 6 | none |
@@ -77,8 +79,7 @@ Generated by `scripts/audit-equipment-icon-quality.mjs`.
## Recommended Next Batch Definition
- Scope: improve remaining low-detail equipment icons while keeping `item-${itemId}` texture keys stable.
- Item ids: `leader-axe`, `training-sword`, `yellow-turban-saber`
- Success criteria: Clear remaining low-detail concerns without changing stable texture keys.
- Keep the existing 64px texture size unless a UI-wide equipment icon pass is planned.
- Add before/after contact sheets and verify the sortie equipment list and equipment swap panel in a desktop browser.
- Scope: no generated equipment icon is currently below the audit threshold.
- Item ids: none currently flagged
- Success criteria: Keep the generated equipment icon audit green while selecting the next art target from runtime screenshots.
- Suggested next area: map/background or unit sprite assets that still look low-resolution in gameplay.

View File

@@ -0,0 +1,26 @@
# Remaining Weapon Equipment Icon Pass
Generated after the final low-detail weapon icon rework in `src/game/scenes/BootScene.ts`.
## Scope
- `leader-axe`
- `training-sword`
- `yellow-turban-saber`
## Before and After
| item id | previous helper | current helper | previous primitives | current primitives | audit concerns |
| --- | --- | --- | ---: | ---: | --- |
| `leader-axe` | `drawAxeIcon` | `drawLeaderAxeIcon` | 7 | 26 | none |
| `training-sword` | `drawSwordIcon` | `drawTrainingSwordIcon` | 16 | 31 | none |
| `yellow-turban-saber` | `drawSaberIcon` | `drawYellowTurbanSaberIcon` | 12 | 35 | none |
## Browser QA
![Sortie prep remaining weapon icon QA](./equipment-icon-remaining-weapons-sortie-prep.png)
- URL checked: `http://127.0.0.1:4201/heros_web/?debug&debugSortiePrep&renderer=canvas`
- Result: sortie prep opened on a desktop 1280x720 canvas and rendered the generated weapon textures in roster, slot, and detail surfaces.
- Browser console warnings/errors: none observed.
- Follow-up target from the updated audit: no generated equipment icon batch is currently flagged; select the next art pass from runtime screenshots.

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@@ -315,6 +315,7 @@ function buildRecommendations(itemRows, groupedRows) {
];
const armorTargetIds = ['oath-robe', 'reinforced-lamellar', 'cloth-armor', 'lamellar-armor', 'rebel-vest'];
const accessoryIds = itemRows.filter((row) => row.slot === 'accessory').map((row) => row.itemId);
const lowDetailWeaponTargetIds = ['leader-axe', 'training-sword', 'yellow-turban-saber'];
const targets = [
{
title: 'weapon spear/polearm family',
@@ -344,6 +345,15 @@ function buildRecommendations(itemRows, groupedRows) {
openReason: 'Accessories are the smallest UI read and several use compact badge-like shapes.',
successCriteria:
'Each accessory should keep a compact footprint while gaining a distinct readable prop shape at 20px and 30px.'
},
{
title: 'remaining low-detail weapon icons',
itemIds: lowDetailWeaponTargetIds,
completeReason:
'The final low-detail common weapons now use dedicated axe, training sword, and Yellow Turban saber silhouettes.',
openReason:
'These are the last generated equipment icons still below the primitive-detail threshold after the larger weapon, armor, and accessory passes.',
successCriteria: 'Clear the low primitive detail concerns without changing stable item texture keys.'
}
].map((target) => ({
...target,
@@ -356,12 +366,17 @@ function buildRecommendations(itemRows, groupedRows) {
itemIds: target.rows.map((row) => row.itemId),
reason: target.completeReason
}));
const remainingConcernRows = itemRows.filter((row) => row.concerns.length > 0);
const nextTarget =
targets.find((target) => !improvementTargetComplete(target)) ?? {
title: 'remaining low-detail equipment icons',
rows: itemRows.filter((row) => row.concerns.length > 0),
openReason: 'All named batches are complete; remaining work should be selected from the low-detail inventory rows.',
successCriteria: 'Clear remaining low-detail concerns without changing stable texture keys.'
title: remainingConcernRows.length ? 'remaining low-detail equipment icons' : 'no flagged equipment icon batch',
rows: remainingConcernRows,
openReason: remainingConcernRows.length
? 'All named batches are complete; remaining work should be selected from the low-detail inventory rows.'
: 'No generated equipment icon currently has a low-detail or shared-helper audit concern; choose the next visual asset pass from in-game QA.',
successCriteria: remainingConcernRows.length
? 'Clear remaining low-detail concerns without changing stable texture keys.'
: 'Keep the generated equipment icon audit green while selecting the next art target from runtime screenshots.'
};
const nextTargetIndex = targets.findIndex((target) => target.title === nextTarget.title);
const followUps = targets
@@ -426,7 +441,7 @@ function renderReport({ iconSourceSize, iconTextureSize, itemRows, groupedRows,
'## Next Improvement Target',
'',
`- Target: ${recommendations.firstTargetTitle}`,
`- Item ids: ${recommendations.firstTargetIds.map((itemId) => `\`${itemId}\``).join(', ')}`,
`- Item ids: ${formatItemIds(recommendations.firstTargetIds)}`,
`- Reason: ${recommendations.firstTargetReason}`,
'',
...renderFollowUpTargets(recommendations.followUps),
@@ -456,15 +471,37 @@ function renderReport({ iconSourceSize, iconTextureSize, itemRows, groupedRows,
].join(' | ')
).map((line) => `| ${line} |`),
'',
...renderRecommendedNextBatch(recommendations)
].join('\n')}`;
}
function formatItemIds(itemIds) {
return itemIds.length ? itemIds.map((itemId) => `\`${itemId}\``).join(', ') : 'none currently flagged';
}
function renderRecommendedNextBatch(recommendations) {
if (!recommendations.firstTargetIds.length) {
return [
'## Recommended Next Batch Definition',
'',
'- Scope: no generated equipment icon is currently below the audit threshold.',
'- Item ids: none currently flagged',
`- Success criteria: ${recommendations.firstTargetSuccessCriteria}`,
'- Suggested next area: map/background or unit sprite assets that still look low-resolution in gameplay.',
''
];
}
return [
'## Recommended Next Batch Definition',
'',
`- Scope: improve ${recommendations.firstTargetTitle} while keeping \`item-\${itemId}\` texture keys stable.`,
`- Item ids: ${recommendations.firstTargetIds.map((itemId) => `\`${itemId}\``).join(', ')}`,
`- Item ids: ${formatItemIds(recommendations.firstTargetIds)}`,
`- Success criteria: ${recommendations.firstTargetSuccessCriteria}`,
'- Keep the existing 64px texture size unless a UI-wide equipment icon pass is planned.',
'- Add before/after contact sheets and verify the sortie equipment list and equipment swap panel in a desktop browser.',
''
].join('\n')}`;
];
}
function renderCompletedTargets(completedTargets) {

View File

@@ -30,7 +30,7 @@ export class BootScene extends Phaser.Scene {
}
private createEquipmentIconTextures() {
this.createItemIcon('item-training-sword', (graphics) => this.drawSwordIcon(graphics, 0xbfd6e6, 0x6b4a2c));
this.createItemIcon('item-training-sword', (graphics) => this.drawTrainingSwordIcon(graphics));
this.createItemIcon('item-twin-oath-blades', (graphics) => {
this.drawSwordIcon(graphics, 0xe8edf7, 0x8a5a32, -4);
this.drawSwordIcon(graphics, 0xd8b15f, 0x8a5a32, 4);
@@ -41,9 +41,9 @@ export class BootScene extends Phaser.Scene {
this.createItemIcon('item-sky-piercer-halberd', (graphics) => this.drawSkyPiercerHalberdIcon(graphics));
this.createItemIcon('item-western-cavalry-spear', (graphics) => this.drawWesternCavalrySpearIcon(graphics));
this.createItemIcon('item-white-feather-fan', (graphics) => this.drawFanIcon(graphics, 0xf3f0df, 0x6e8eb8));
this.createItemIcon('item-yellow-turban-saber', (graphics) => this.drawSaberIcon(graphics, 0xd8b15f, 0x9c6b2f));
this.createItemIcon('item-yellow-turban-saber', (graphics) => this.drawYellowTurbanSaberIcon(graphics));
this.createItemIcon('item-short-bow', (graphics) => this.drawBowIcon(graphics, 0xc58a4c, 0xe8dfca));
this.createItemIcon('item-leader-axe', (graphics) => this.drawAxeIcon(graphics, 0xd8dfe6, 0x8d5a3a));
this.createItemIcon('item-leader-axe', (graphics) => this.drawLeaderAxeIcon(graphics));
this.createItemIcon('item-cloth-armor', (graphics) => this.drawClothArmorIcon(graphics));
this.createItemIcon('item-lamellar-armor', (graphics) => this.drawLamellarArmorIcon(graphics));
@@ -95,6 +95,43 @@ export class BootScene extends Phaser.Scene {
graphics.fillCircle(8 + offsetX, 23, 2);
}
private drawTrainingSwordIcon(graphics: Phaser.GameObjects.Graphics) {
graphics.lineStyle(5, 0x50606a, 1);
graphics.beginPath();
graphics.moveTo(7, 23);
graphics.lineTo(20, 5);
graphics.strokePath();
graphics.lineStyle(3, 0xbfd6e6, 1);
graphics.beginPath();
graphics.moveTo(8, 22);
graphics.lineTo(20, 6);
graphics.strokePath();
graphics.lineStyle(1, 0xeff7ff, 0.9);
graphics.beginPath();
graphics.moveTo(11, 18);
graphics.lineTo(18, 8);
graphics.strokePath();
graphics.fillStyle(0xd8dfe6, 1);
graphics.fillTriangle(18, 4, 23, 5, 19, 10);
graphics.lineStyle(3, 0xd8b15f, 1);
graphics.beginPath();
graphics.moveTo(5, 18);
graphics.lineTo(13, 23);
graphics.moveTo(8, 16);
graphics.lineTo(15, 20);
graphics.strokePath();
graphics.lineStyle(2, 0x6b4a2c, 1);
graphics.beginPath();
graphics.moveTo(6, 22);
graphics.lineTo(10, 25);
graphics.strokePath();
graphics.fillStyle(0x6b4a2c, 1);
graphics.fillCircle(7, 24, 2);
graphics.fillStyle(0x9b4c3a, 1);
graphics.fillTriangle(10, 22, 15, 24, 12, 27);
graphics.fillCircle(13, 23, 1);
}
private drawGreenDragonGlaiveIcon(graphics: Phaser.GameObjects.Graphics) {
graphics.lineStyle(4, 0x704728, 1);
graphics.beginPath();
@@ -254,19 +291,45 @@ export class BootScene extends Phaser.Scene {
graphics.strokePath();
}
private drawSaberIcon(graphics: Phaser.GameObjects.Graphics, bladeColor: number, gripColor: number) {
graphics.lineStyle(4, bladeColor, 1);
private drawYellowTurbanSaberIcon(graphics: Phaser.GameObjects.Graphics) {
graphics.lineStyle(5, 0x6b4a2c, 1);
graphics.beginPath();
graphics.moveTo(7, 22);
graphics.lineTo(12, 15);
graphics.lineTo(19, 8);
graphics.lineTo(24, 5);
graphics.strokePath();
graphics.lineStyle(4, 0xd8b15f, 1);
graphics.beginPath();
graphics.moveTo(8, 22);
graphics.lineTo(13, 15);
graphics.lineTo(19, 8);
graphics.lineTo(23, 6);
graphics.strokePath();
graphics.lineStyle(3, gripColor, 1);
graphics.lineStyle(2, 0xf2d68b, 0.9);
graphics.beginPath();
graphics.moveTo(12, 17);
graphics.lineTo(19, 9);
graphics.lineTo(22, 7);
graphics.strokePath();
graphics.fillStyle(0xf2d68b, 1);
graphics.fillTriangle(21, 4, 26, 5, 22, 9);
graphics.fillStyle(0x9c6b2f, 1);
graphics.fillTriangle(10, 17, 17, 18, 12, 22);
graphics.lineStyle(3, 0x9c6b2f, 1);
graphics.beginPath();
graphics.moveTo(6, 21);
graphics.lineTo(12, 23);
graphics.strokePath();
graphics.lineStyle(2, 0xd8b15f, 1);
graphics.beginPath();
graphics.moveTo(8, 20);
graphics.lineTo(5, 25);
graphics.moveTo(10, 21);
graphics.lineTo(11, 26);
graphics.strokePath();
graphics.fillStyle(0xd8b15f, 1);
graphics.fillCircle(7, 22, 2);
}
private drawBowIcon(graphics: Phaser.GameObjects.Graphics, bowColor: number, stringColor: number) {
@@ -290,15 +353,38 @@ export class BootScene extends Phaser.Scene {
graphics.strokePath();
}
private drawAxeIcon(graphics: Phaser.GameObjects.Graphics, bladeColor: number, gripColor: number) {
graphics.lineStyle(3, gripColor, 1);
private drawLeaderAxeIcon(graphics: Phaser.GameObjects.Graphics) {
graphics.lineStyle(4, 0x6b4a2c, 1);
graphics.beginPath();
graphics.moveTo(9, 24);
graphics.lineTo(18, 5);
graphics.strokePath();
graphics.fillStyle(bladeColor, 1);
graphics.fillTriangle(16, 5, 25, 8, 16, 15);
graphics.fillTriangle(16, 5, 9, 9, 15, 14);
graphics.lineStyle(1, 0xc99755, 0.9);
graphics.beginPath();
graphics.moveTo(11, 22);
graphics.lineTo(18, 7);
graphics.strokePath();
graphics.fillStyle(0xd8dfe6, 1);
graphics.fillEllipse(20, 10, 12, 12);
graphics.fillTriangle(16, 4, 26, 8, 17, 15);
graphics.fillTriangle(16, 5, 8, 9, 15, 15);
graphics.fillStyle(0xeff7ff, 0.85);
graphics.fillTriangle(18, 6, 24, 8, 18, 11);
graphics.fillTriangle(15, 7, 10, 9, 15, 12);
graphics.fillStyle(0x50606a, 1);
graphics.fillTriangle(17, 11, 22, 14, 15, 16);
graphics.lineStyle(2, 0x8d5a3a, 1);
graphics.beginPath();
graphics.moveTo(14, 7);
graphics.lineTo(20, 13);
graphics.moveTo(12, 14);
graphics.lineTo(18, 16);
graphics.strokePath();
graphics.fillStyle(0xd8b15f, 1);
graphics.fillCircle(17, 10, 2);
graphics.fillCircle(9, 24, 2);
graphics.fillStyle(0x9b4c3a, 1);
graphics.fillTriangle(13, 15, 18, 17, 14, 22);
}
private drawFanIcon(graphics: Phaser.GameObjects.Graphics, featherColor: number, ribColor: number) {