diff --git a/docs/deployment.md b/docs/deployment.md new file mode 100644 index 0000000..cba0bd9 --- /dev/null +++ b/docs/deployment.md @@ -0,0 +1,21 @@ +# Deployment + +The NAS deployment should leave one canonical web directory: + +- `/volume1/web/heros_web` + +Use the checked-in script instead of ad-hoc deploy commands: + +```powershell +pnpm deploy:nas +``` + +By default, `scripts/deploy-nas.ps1` builds the project, uploads `dist`, swaps the remote directory, and removes transient deploy or backup folders. This keeps `/volume1/web` from filling with `heros_web.backup-*` and `.heros_web_deploy_*` directories. + +Optional backup retention: + +```powershell +powershell -NoProfile -ExecutionPolicy Bypass -File scripts/deploy-nas.ps1 -Build -BackupRetention 3 +``` + +Use nonzero retention only for a temporary release window. The normal project default is `0`, so only `/volume1/web/heros_web` remains after deployment. diff --git a/docs/propfix-wei-strategist-v2-animation.gif b/docs/propfix-wei-strategist-v2-animation.gif new file mode 100644 index 0000000..181bc29 Binary files /dev/null and b/docs/propfix-wei-strategist-v2-animation.gif differ diff --git a/docs/propfix-wei-strategist-v2-battle-browser-check.png b/docs/propfix-wei-strategist-v2-battle-browser-check.png new file mode 100644 index 0000000..29ac765 Binary files /dev/null and b/docs/propfix-wei-strategist-v2-battle-browser-check.png differ diff --git a/docs/propfix-wei-strategist-v2-battle-composite.png b/docs/propfix-wei-strategist-v2-battle-composite.png new file mode 100644 index 0000000..62274db Binary files /dev/null and b/docs/propfix-wei-strategist-v2-battle-composite.png differ diff --git a/docs/propfix-wei-strategist-v2-before-after.png b/docs/propfix-wei-strategist-v2-before-after.png new file mode 100644 index 0000000..87dd5f7 Binary files /dev/null and b/docs/propfix-wei-strategist-v2-before-after.png differ diff --git a/docs/propfix-wei-strategist-v2-contact.png b/docs/propfix-wei-strategist-v2-contact.png new file mode 100644 index 0000000..a39be94 Binary files /dev/null and b/docs/propfix-wei-strategist-v2-contact.png differ diff --git a/docs/propfix-wei-strategist-v2-report.md b/docs/propfix-wei-strategist-v2-report.md new file mode 100644 index 0000000..90517bb --- /dev/null +++ b/docs/propfix-wei-strategist-v2-report.md @@ -0,0 +1,26 @@ +# Wei Strategist identity v2 report + +- identity note: replaced the Zhuge-like white feather fan with a Wei court analyst read built around blue-gray robes, a bronze command tablet, a war ledger, and a compact map board. +- source: `propfix-wei-strategist-v2-source.png` +- base status: ok +- action status: ok +- base partial alpha: 0, opaque pixels: 2040220 +- action partial alpha: 0, opaque pixels: 4137270 +- base frame border hits: 0 +- action frame border hits: 0 +- base empty frames: 0 +- action empty frames: 0 +- base bbox width range: 162..208 +- base bbox height range: 282..290 +- base bottom range: 303..303 +- action bbox width range: 136..212 +- action bbox height range: 282..295 +- action bottom range: 303..303 +- contact: `propfix-wei-strategist-v2-contact.png` +- animation: `propfix-wei-strategist-v2-animation.gif` +- before/after: `propfix-wei-strategist-v2-before-after.png` +- scale compare: `propfix-wei-strategist-v2-scale-compare.png` +- battle composite: `propfix-wei-strategist-v2-battle-composite.png` +- local browser battle check: `propfix-wei-strategist-v2-battle-browser-check.png` +- manual checks: build and local browser verification passed after generation +- note: battle composite is a scale review image; gameplay roster is unchanged during sample approval diff --git a/docs/propfix-wei-strategist-v2-scale-compare.png b/docs/propfix-wei-strategist-v2-scale-compare.png new file mode 100644 index 0000000..2a1a0b8 Binary files /dev/null and b/docs/propfix-wei-strategist-v2-scale-compare.png differ diff --git a/docs/propfix-wei-strategist-v2-source.png b/docs/propfix-wei-strategist-v2-source.png new file mode 100644 index 0000000..5057477 Binary files /dev/null and b/docs/propfix-wei-strategist-v2-source.png differ diff --git a/docs/strategist-character-direction.md b/docs/strategist-character-direction.md new file mode 100644 index 0000000..32f7c51 --- /dev/null +++ b/docs/strategist-character-direction.md @@ -0,0 +1,43 @@ +# Strategist Character Direction + +This guide prevents strategist units from collapsing into the same white-robed, feather-fan silhouette. + +## Core Rule + +Zhuge Liang owns the large white feather fan and white-robed sage read. Other strategist, civil-official, and shaman units should keep their own readable identity through color, posture, and prop choice. + +## Identity Matrix + +| unit | identity read | primary colors | allowed props | avoid | +| --- | --- | --- | --- | --- | +| `unit-zhuge-liang` | white-robed master strategist | white, pale blue, silver | large white feather fan, scroll | removing the signature fan | +| `unit-ma-liang` | white-eyebrow civil official | olive, sage green, tan, brown | white eyebrows, bamboo slips, letters, document case | white robe/fan read | +| `unit-pang-tong` | eccentric dark tactician | dark brown, muted plum, black | dark folded fan, wood slips, scroll bundles | bright white fan | +| `unit-fa-zheng` | cold legal strategist | deep green, charcoal, muted gold | map board, tally baton, command slips | sage-white costume | +| `unit-sima-yi` | black court conspirator | black, gray, dark violet | command tablet, sealed order, small dark fan | white fan, pale robe | +| `unit-yi-ji` | envoy and letter carrier | cream-tan, muted green, brown | sealed letter, bamboo slips, travel scroll | feather fan | +| `unit-huang-quan` | quartermaster official | blue, dark teal, muted gold | map board, records, baton | white fan | +| `unit-shu-strategist` | Shu field tactician | olive, tan, dark green | brush, bamboo slips, compact map | white-robed sage silhouette | +| `unit-shu-strategist-field` | frontline staff officer | green, leather brown, brass | field map, short baton, scroll case | large sleeves and white fan | +| `unit-shu-strategist-white` | pale-robed civil aide | warm tan, muted jade, limited cream | paper bundle, brush case, small tablet | Zhuge-style white robe/fan pairing | +| `unit-wei-strategist` | Wei court analyst | blue-gray, steel, black | bronze command tablet, war map, folded order | white feather fan | +| `unit-wei-strategist-black` | Wei covert adviser | black, violet, steel | black tablet, sealed order | white fan | +| `unit-wei-strategist-blue` | Wei records officer | blue, gray, bronze | map scroll, registry book | white fan | +| `unit-wu-strategist` | Wu river adviser | red-brown, teal, lacquer black | naval chart, command baton, small red fan | white feather fan | +| `unit-wu-strategist-fire` | fire-plan tactician | ember red, charcoal, bronze | fire tally, oil map, torch talisman | white fan | +| `unit-wu-strategist-river` | river-route tactician | blue-green, red trim, dark wood | water chart, oar-like baton, scroll tube | white fan | +| `unit-nanman-shaman` | ritual shaman | ochre, bone, dark red | ritual staff, talisman, tribal ornaments | Han scholar fan | +| `unit-nanman-shaman-ember` | ember shaman | ember red, bone, smoke black | ember staff, charm strips | white feather fan | +| `unit-nanman-shaman-storm` | storm shaman | storm blue, bone, dark leather | storm staff, charms | white feather fan | + +## Next Representative Fixes + +1. `unit-wu-strategist`: replace the white-fan read with a Wu river adviser using a naval chart and lacquer command baton. +2. `unit-shu-strategist-white`: preserve a lighter civil-aide read, but remove the Zhuge-style white robe plus fan pairing. +3. `unit-wu-strategist-fire`: replace the white-fan read with a fire tally, oil map, or talisman. + +Completed representative pass: + +- `unit-wei-strategist`: changed from white-fan strategist to blue-gray Wei court analyst with bronze command tablet, war ledger, and compact map board. + +Every representative fix should include contact sheet, animation GIF, battle preview, before/after, alpha audit, build, and browser check. diff --git a/docs/strategist-prop-audit.md b/docs/strategist-prop-audit.md index ac5b383..6c60dc7 100644 --- a/docs/strategist-prop-audit.md +++ b/docs/strategist-prop-audit.md @@ -2,6 +2,7 @@ This audit keeps Zhuge Liang's large white feather fan as a unique signature prop. It also keeps character-specific scholar traits intact: Ma Liang should read as the white-eyebrow civil official, not as another white-robed feather-fan strategist. +Detailed per-unit visual direction lives in `strategist-character-direction.md`. ## Prop Rule @@ -23,14 +24,14 @@ It also keeps character-specific scholar traits intact: Ma Liang should read as | `unit-yi-ji` | letter, bamboo slips, scroll | distinct civil envoy | keep | | `unit-huang-quan` | bamboo slips, map board, baton | distinct quartermaster official | keep | | `unit-shu-strategist` | writing brush, bamboo slips, compact field map | white feather fan removed | fixed in batch 1 | -| `unit-shu-strategist-field` | likely strategist prop variant | needs later batch check | later | -| `unit-shu-strategist-white` | likely pale strategist prop variant | needs later batch check | later | -| `unit-wei-strategist` | white feather fan in several poses | too close to Zhuge Liang | later prop cleanup | -| `unit-wei-strategist-black` | dark strategist prop variant | needs later batch check | later | -| `unit-wei-strategist-blue` | strategist prop variant | needs later batch check | later | -| `unit-wu-strategist` | white feather fan in several poses | too close to Zhuge Liang | later prop cleanup | -| `unit-wu-strategist-fire` | white fan in fire strategist poses | too close to Zhuge Liang | later prop cleanup | -| `unit-wu-strategist-river` | white fan in river strategist poses | too close to Zhuge Liang | later prop cleanup | +| `unit-shu-strategist-field` | field map / staff officer variant | must stay practical and green, not sage-white | later identity pass | +| `unit-shu-strategist-white` | pale civil-aide variant | high risk if it pairs white robe with fan | representative fix candidate | +| `unit-wei-strategist` | bronze command tablet, war ledger, compact map board | white feather fan removed; Wei court analyst identity restored | fixed in representative pass | +| `unit-wei-strategist-black` | dark strategist prop variant | acceptable if fan stays dark and compact | later identity pass | +| `unit-wei-strategist-blue` | blue records officer variant | acceptable if props are records/maps | later identity pass | +| `unit-wu-strategist` | white feather fan in several poses | too close to Zhuge Liang | representative fix candidate | +| `unit-wu-strategist-fire` | white fan in fire strategist poses | should become fire tally / oil map / talisman | later prop cleanup | +| `unit-wu-strategist-river` | white fan in river strategist poses | should become water chart / oar-like baton | later prop cleanup | | `unit-nanman-shaman` | ritual staff / tribal ornaments | not a white feather fan | keep | | `unit-nanman-shaman-ember` | ritual staff / ember ornaments | not a white feather fan | keep | | `unit-nanman-shaman-storm` | ritual staff / storm ornaments | not a white feather fan | keep | @@ -45,4 +46,10 @@ The first correction batch changes: - `unit-fa-zheng` - `unit-shu-strategist` -Later cleanup should remove white-feather-fan reads from remaining generic strategist variants after this representative batch is verified. +Next representative cleanup order: + +1. `unit-wu-strategist` +2. `unit-shu-strategist-white` +3. `unit-wu-strategist-fire` + +Later cleanup should remove white-feather-fan reads from remaining generic strategist variants after the representative fixes are verified. diff --git a/docs/unit-sprite-batch-queue.json b/docs/unit-sprite-batch-queue.json index 7230acf..b869346 100644 --- a/docs/unit-sprite-batch-queue.json +++ b/docs/unit-sprite-batch-queue.json @@ -650,9 +650,9 @@ "baseStatus": "ok", "actionStatus": "ok", "battleBasePx": [ - 25.6, - 37.2, - 46.3, + 25.9, + 33.2, + 45.0, 46.3 ], "spec": null diff --git a/docs/unit-sprite-batch-queue.md b/docs/unit-sprite-batch-queue.md index 224e65c..8caf3b2 100644 --- a/docs/unit-sprite-batch-queue.md +++ b/docs/unit-sprite-batch-queue.md @@ -89,7 +89,7 @@ No next unit is currently defined. | `unit-wei-officer` | approved reference | approved-baseline | technical ok | 25.4..33.1 x 46.0..47.1 | | | `unit-wei-officer-gate` | approved reference | approved-baseline | technical ok | 28.1..33.4 x 46.0..46.0 | | | `unit-wei-officer-iron` | approved reference | approved-baseline | technical ok | 34.2..36.6 x 44.2..46.0 | | -| `unit-wei-strategist` | approved reference | approved-baseline | technical ok | 25.6..37.2 x 46.3..46.3 | | +| `unit-wei-strategist` | approved reference | approved-baseline | technical ok | 25.9..33.2 x 45.0..46.3 | | | `unit-wei-strategist-black` | approved reference | approved-baseline | technical ok | 23.3..34.0 x 43.1..46.0 | | | `unit-wei-strategist-blue` | approved reference | approved-baseline | technical ok | 26.4..33.5 x 46.0..46.0 | | | `unit-wei-yan` | approved reference | approved-baseline | technical ok | 27.6..35.0 x 44.2..46.3 | | diff --git a/docs/unit-sprite-review-approved-and-pending.png b/docs/unit-sprite-review-approved-and-pending.png index ef7a3dd..a8109a9 100644 Binary files a/docs/unit-sprite-review-approved-and-pending.png and b/docs/unit-sprite-review-approved-and-pending.png differ diff --git a/docs/unit-sprite-review-batch3-wei.png b/docs/unit-sprite-review-batch3-wei.png index 81dbcdb..340d5a3 100644 Binary files a/docs/unit-sprite-review-batch3-wei.png and b/docs/unit-sprite-review-batch3-wei.png differ diff --git a/docs/unit-sprite-review-index.png b/docs/unit-sprite-review-index.png index b22c621..963799c 100644 Binary files a/docs/unit-sprite-review-index.png and b/docs/unit-sprite-review-index.png differ diff --git a/docs/unit-sprite-rework-audit.json b/docs/unit-sprite-rework-audit.json index 949be62..bc0f024 100644 --- a/docs/unit-sprite-rework-audit.json +++ b/docs/unit-sprite-rework-audit.json @@ -3788,21 +3788,21 @@ 1252 ], "partial_alpha": 0, - "opaque_pixels": 2514754, + "opaque_pixels": 2040220, "border_hits": 0, - "min_width": 160, - "max_width": 233, - "min_height": 290, + "min_width": 162, + "max_width": 208, + "min_height": 282, "max_height": 290, "min_bottom": 303, "max_bottom": 303, "empty_frames": 0, - "width_swing": 73, - "height_swing": 0, + "width_swing": 46, + "height_swing": 8, "bottom_swing": 0, - "battle_min_width_px": 25.6, - "battle_max_width_px": 37.2, - "battle_min_height_px": 46.3, + "battle_min_width_px": 25.9, + "battle_max_width_px": 33.2, + "battle_min_height_px": 45.0, "battle_max_height_px": 46.3, "status": "ok" }, @@ -3814,22 +3814,22 @@ 1252 ], "partial_alpha": 0, - "opaque_pixels": 5501514, + "opaque_pixels": 4137270, "border_hits": 0, - "min_width": 160, - "max_width": 243, - "min_height": 288, - "max_height": 290, + "min_width": 136, + "max_width": 212, + "min_height": 282, + "max_height": 295, "min_bottom": 303, "max_bottom": 303, "empty_frames": 0, - "width_swing": 83, - "height_swing": 2, + "width_swing": 76, + "height_swing": 13, "bottom_swing": 0, - "battle_min_width_px": 25.6, - "battle_max_width_px": 38.8, - "battle_min_height_px": 46.0, - "battle_max_height_px": 46.3, + "battle_min_width_px": 21.7, + "battle_max_width_px": 33.9, + "battle_min_height_px": 45.0, + "battle_max_height_px": 47.1, "status": "ok" } }, diff --git a/docs/unit-sprite-rework-audit.md b/docs/unit-sprite-rework-audit.md index 4956db1..a707713 100644 --- a/docs/unit-sprite-rework-audit.md +++ b/docs/unit-sprite-rework-audit.md @@ -117,7 +117,7 @@ Visual review boards are generated by `scripts/render-unit-sprite-review-boards. | batch3-wei | approved-baseline | `unit-wei-officer` | ok | ok | 159..207 x 288..295 | 158..255 x 288..295 | 25.4..33.1 x 46.0..47.1 | w48 h7 b0 | | batch3-wei | approved-baseline | `unit-wei-officer-gate` | ok | ok | 176..209 x 288..288 | 176..257 x 262..288 | 28.1..33.4 x 46.0..46.0 | w33 h0 b0 | | batch3-wei | approved-baseline | `unit-wei-officer-iron` | ok | ok | 214..229 x 277..288 | 201..258 x 230..288 | 34.2..36.6 x 44.2..46.0 | w15 h11 b0 | -| batch3-wei | approved-baseline | `unit-wei-strategist` | ok | ok | 160..233 x 290..290 | 160..243 x 288..290 | 25.6..37.2 x 46.3..46.3 | w73 h0 b0 | +| batch3-wei | approved-baseline | `unit-wei-strategist` | ok | ok | 162..208 x 282..290 | 136..212 x 282..295 | 25.9..33.2 x 45.0..46.3 | w46 h8 b0 | | batch3-wei | approved-baseline | `unit-wei-strategist-black` | ok | ok | 146..213 x 270..288 | 146..240 x 249..288 | 23.3..34.0 x 43.1..46.0 | w67 h18 b0 | | batch3-wei | approved-baseline | `unit-wei-strategist-blue` | ok | ok | 165..210 x 288..288 | 165..246 x 264..288 | 26.4..33.5 x 46.0..46.0 | w45 h0 b0 | | batch3-wei | approved-baseline | `unit-wei-yan` | ok | ok | 173..219 x 277..290 | 173..264 x 232..290 | 27.6..35.0 x 44.2..46.3 | w46 h13 b0 | diff --git a/package.json b/package.json index df2c948..3d92ca1 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "verify:flow": "node scripts/verify-flow.mjs", "verify:save-flow": "node scripts/verify-save-retry-flow.mjs", "verify:release": "node scripts/verify-release-candidate.mjs", - "qa:representative": "node scripts/qa-representative-battles.mjs" + "qa:representative": "node scripts/qa-representative-battles.mjs", + "deploy:nas": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/deploy-nas.ps1 -Build" }, "dependencies": { "phaser": "^3.90.0" diff --git a/scripts/deploy-nas.ps1 b/scripts/deploy-nas.ps1 new file mode 100644 index 0000000..80206fd --- /dev/null +++ b/scripts/deploy-nas.ps1 @@ -0,0 +1,145 @@ +param( + [switch]$Build, + [int]$BackupRetention = 0, + [string]$SshUser = "y2keui", + [string]$SshHost = "comtropy.synology.me", + [int]$SshPort = 50022, + [string]$SshKey = "$env:USERPROFILE\.ssh\nas_msix_ed25519", + [string]$RemoteRoot = "/volume1/web", + [string]$SiteName = "heros_web" +) + +$ErrorActionPreference = "Stop" +Set-StrictMode -Version Latest + +function Assert-Command { + param([string]$Name) + if (-not (Get-Command $Name -ErrorAction SilentlyContinue)) { + throw "Required command not found: $Name" + } +} + +function Quote-Sh { + param([string]$Value) + return "'" + ($Value -replace "'", "'\''") + "'" +} + +Assert-Command "ssh" +Assert-Command "scp" +Assert-Command "git" + +if ($Build) { + Assert-Command "pnpm" + pnpm build + if ($LASTEXITCODE -ne 0) { + throw "pnpm build failed with exit code $LASTEXITCODE" + } +} + +$dist = Join-Path (Get-Location) "dist" +$index = Join-Path $dist "index.html" +$assets = Join-Path $dist "assets" + +if (-not (Test-Path $index -PathType Leaf)) { + throw "Missing dist/index.html. Run pnpm build first or pass -Build." +} + +if (-not (Test-Path $assets -PathType Container)) { + throw "Missing dist/assets. Run pnpm build first or pass -Build." +} + +if ($BackupRetention -lt 0) { + throw "BackupRetention must be 0 or greater." +} + +$timestamp = Get-Date -Format "yyyyMMddHHmmss" +$commit = (git rev-parse --short=8 HEAD).Trim() +$userHost = "$SshUser@$SshHost" +$remoteTemp = "$RemoteRoot/.$($SiteName)_deploy_$timestamp" +$remotePrevious = "$RemoteRoot/.$($SiteName)_previous_$timestamp" +$remoteBackup = "$RemoteRoot/$SiteName.backup-$timestamp-$commit" + +$quotedRemoteRoot = Quote-Sh $RemoteRoot +$quotedSiteName = Quote-Sh $SiteName +$quotedTemp = Quote-Sh $remoteTemp +$quotedPrevious = Quote-Sh $remotePrevious +$quotedBackup = Quote-Sh $remoteBackup +$retention = $BackupRetention + +$prepareRemote = @" +set -e +remote_root=$quotedRemoteRoot +temp=$quotedTemp +site_name=$quotedSiteName +test -d "`$remote_root" +rm -rf -- "`$temp" +mkdir -p -- "`$temp" +printf 'Prepared %s/%s via %s\n' "`$remote_root" "`$site_name" "`$temp" +"@ + +ssh -o BatchMode=yes -o ConnectTimeout=8 -i $SshKey -p $SshPort $userHost $prepareRemote +if ($LASTEXITCODE -ne 0) { + throw "Failed to prepare remote deploy directory." +} + +scp -O -i $SshKey -P $SshPort -r "$dist\*" "$userHost`:$remoteTemp/" +if ($LASTEXITCODE -ne 0) { + throw "Failed to upload dist to remote deploy directory." +} + +$installRemote = @" +set -e +remote_root=$quotedRemoteRoot +site_name=$quotedSiteName +temp=$quotedTemp +previous=$quotedPrevious +backup=$quotedBackup +retention=$retention +site="`$remote_root/`$site_name" + +test -f "`$temp/index.html" +test -d "`$temp/assets" +rm -rf -- "`$previous" + +if [ -d "`$site" ]; then + mv -- "`$site" "`$previous" +fi + +if ! mv -- "`$temp" "`$site"; then + if [ -d "`$previous" ]; then + mv -- "`$previous" "`$site" + fi + exit 1 +fi + +chmod -R a+rX "`$site" + +if [ -d "`$previous" ]; then + if [ "`$retention" -gt 0 ]; then + mv -- "`$previous" "`$backup" + else + rm -rf -- "`$previous" + fi +fi + +find "`$remote_root" -maxdepth 1 -type d \( -name ".`$site_name`_deploy_*" -o -name "`$site_name`_deploy_*" -o -name ".`$site_name`_previous_*" \) -exec rm -rf -- {} + + +if [ "`$retention" -eq 0 ]; then + find "`$remote_root" -maxdepth 1 -type d -name "`$site_name.backup-*" -exec rm -rf -- {} + +else + keep_count=`$retention + find "`$remote_root" -maxdepth 1 -type d -name "`$site_name.backup-*" -printf '%f\n' | sort -r | tail -n +`$((keep_count + 1)) | while IFS= read -r old_backup; do + [ -n "`$old_backup" ] && rm -rf -- "`$remote_root/`$old_backup" + done +fi + +printf 'Deployed %s at %s\n' "`$site_name" "`$site" +printf 'Backup retention: %s\n' "`$retention" +printf 'Remaining site directories:\n' +find "`$remote_root" -maxdepth 1 -type d -name "*`$site_name*" -printf '%f\n' | sort +"@ + +ssh -o BatchMode=yes -o ConnectTimeout=8 -i $SshKey -p $SshPort $userHost $installRemote +if ($LASTEXITCODE -ne 0) { + throw "Failed to install remote deploy directory." +} diff --git a/src/assets/images/units/unit-wei-strategist-actions.png b/src/assets/images/units/unit-wei-strategist-actions.png index 5a97871..a4eee1e 100644 Binary files a/src/assets/images/units/unit-wei-strategist-actions.png and b/src/assets/images/units/unit-wei-strategist-actions.png differ diff --git a/src/assets/images/units/unit-wei-strategist.png b/src/assets/images/units/unit-wei-strategist.png index ae7b6b0..3ca0b47 100644 Binary files a/src/assets/images/units/unit-wei-strategist.png and b/src/assets/images/units/unit-wei-strategist.png differ