diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 6602f07c..e173a767 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -6,6 +6,8 @@
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 00000000..078d482d
--- /dev/null
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..3fae266f
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png
new file mode 100644
index 00000000..1f68bd57
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..d113a703
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 00000000..bae75f23
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..e55ea1a2
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png
new file mode 100644
index 00000000..348446d2
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..183254f7
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 00000000..09d774aa
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..65cdd90f
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png
new file mode 100644
index 00000000..df917f08
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..b2a846bf
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..39294f6c
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..29a631ec
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
new file mode 100644
index 00000000..7a76a9e7
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..b2b2729e
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..ff6817dd
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..9c99750a
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
new file mode 100644
index 00000000..c7db04aa
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..d444f172
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..1b58d0e0
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/branding/icon/build_icons.sh b/branding/icon/build_icons.sh
new file mode 100755
index 00000000..3a8dd0cc
--- /dev/null
+++ b/branding/icon/build_icons.sh
@@ -0,0 +1,106 @@
+#!/bin/zsh
+# Renders branding/icon/icon.svg into every platform icon and writes them where the builds pick them up:
+# android/app/src/main/res/mipmap-* legacy ic_launcher / ic_launcher_round (API 24-25) and the
+# adaptive-icon layers (API 26+, mipmap-anydpi-v26/*.xml)
+# branding/icon/macos/AppIcon.icns macOS app icon (Big Sur squircle with drop shadow)
+# branding/icon/ios/AppIcon.appiconset iOS single-size 1024 icon (opaque)
+# The outputs are committed, so building the apps does not need this script. Rerun it after editing the SVG.
+# Needs Google Chrome (SVG filters) and ImageMagick (`brew install imagemagick`); iconutil ships with macOS.
+set -euo pipefail
+here=${0:A:h}
+repo=${here:h:h}
+chrome=${CHROME:-"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"}
+work=$(mktemp -d)
+trap 'rm -rf "$work"' EXIT
+
+# icon.svg -> full / background-only / foreground-only (scaled into the adaptive-icon safe zone) SVGs.
+python3 - "$here/icon.svg" "$work" <<'EOF'
+import re, sys
+src, out = sys.argv[1], sys.argv[2]
+svg = open(src).read()
+# Both layer groups sit at two-space indent; the foreground one is the last element and holds nested groups.
+bg = re.search(r' .*?\n \n', svg, re.S)
+fg = re.search(r' .*\n \n(?=)', svg, re.S)
+assert bg and fg
+open(out + "/full.svg", "w").write(svg)
+open(out + "/background.svg", "w").write(svg.replace(fg.group(0), ""))
+# Adaptive icons show the inner 72 of 108 dp (338 px of the 512 half-width) and launchers mask inside that.
+# Scale the foreground so the ring (outer radius 405 around (512, 500)) sits at the same 79% of the visible
+# radius as in the full icon: 405 * 0.66 = 267 = 0.79 * 338.
+scaled = ' \n' + fg.group(0) + ' \n'
+open(out + "/foreground.svg", "w").write(svg.replace(bg.group(0), "").replace(fg.group(0), scaled))
+EOF
+
+for name in full background foreground; do
+ "$chrome" --headless=new --disable-gpu --hide-scrollbars --default-background-color=00000000 \
+ --window-size=1024,1024 --screenshot="$work/$name.png" "file://$work/$name.svg" >/dev/null 2>&1
+done
+
+# Android
+res=$repo/android/app/src/main/res
+typeset -A legacy=(mdpi 48 hdpi 72 xhdpi 96 xxhdpi 144 xxxhdpi 192)
+for density size in ${(kv)legacy}; do
+ dir=$res/mipmap-$density
+ mkdir -p $dir
+ layer=$(( size * 9 / 4 )) # 108 dp at this density
+ magick "$work/background.png" -resize ${layer}x${layer} "$dir/ic_launcher_background.png"
+ magick "$work/foreground.png" -resize ${layer}x${layer} "$dir/ic_launcher_foreground.png"
+ # Legacy launchers show the bitmap as is: a rounded square and a circle.
+ r=$(( size * 18 / 100 ))
+ magick "$work/full.png" -alpha set -resize ${size}x${size} \
+ \( -size ${size}x${size} xc:none -fill white -draw "roundrectangle 0,0 $((size-1)),$((size-1)) $r,$r" \) \
+ -compose DstIn -composite "$dir/ic_launcher.png"
+ magick "$work/full.png" -alpha set -resize ${size}x${size} \
+ \( -size ${size}x${size} xc:none -fill white -draw "circle $((size/2)),$((size/2)) $((size/2)),0" \) \
+ -compose DstIn -composite "$dir/ic_launcher_round.png"
+done
+mkdir -p $res/mipmap-anydpi-v26
+for name in ic_launcher ic_launcher_round; do
+ cat > $res/mipmap-anydpi-v26/$name.xml <<'EOF'
+
+
+
+
+
+
+EOF
+done
+
+# macOS: 824 px squircle-ish rounded rect (radius 185) centred on 1024 with a soft shadow, per the Big Sur grid.
+magick "$work/full.png" -alpha set -resize 824x824 \
+ \( -size 824x824 xc:none -fill white -draw "roundrectangle 0,0 823,823 185,185" \) \
+ -compose DstIn -composite "$work/tile.png"
+magick -size 1024x1024 xc:none \
+ \( "$work/tile.png" -background black -shadow 50x14+0+10 \) -gravity center -geometry +0+6 -compose Over -composite \
+ "$work/tile.png" -gravity center -geometry +0+0 -compose Over -composite "$work/mac1024.png"
+iconset=$work/AppIcon.iconset
+mkdir -p $iconset
+for s in 16 32 128 256 512; do
+ magick "$work/mac1024.png" -resize ${s}x${s} "$iconset/icon_${s}x${s}.png"
+ magick "$work/mac1024.png" -resize $((s*2))x$((s*2)) "$iconset/icon_${s}x${s}@2x.png"
+done
+mkdir -p $here/macos
+iconutil -c icns -o $here/macos/AppIcon.icns $iconset
+cp "$work/mac1024.png" $here/macos/AppIcon-1024.png
+
+# iOS: opaque, square; the system applies the mask.
+ios=$here/ios/AppIcon.appiconset
+mkdir -p $ios
+magick "$work/full.png" -background '#12050a' -alpha remove -alpha off "$ios/AppIcon-1024.png"
+cat > $ios/Contents.json <<'EOF'
+{
+ "images" : [
+ {
+ "filename" : "AppIcon-1024.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
+EOF
+echo "icons written"
diff --git a/branding/icon/icon.svg b/branding/icon/icon.svg
new file mode 100644
index 00000000..4070d850
--- /dev/null
+++ b/branding/icon/icon.svg
@@ -0,0 +1,124 @@
+
diff --git a/branding/icon/ios/AppIcon.appiconset/AppIcon-1024.png b/branding/icon/ios/AppIcon.appiconset/AppIcon-1024.png
new file mode 100644
index 00000000..333f8cde
Binary files /dev/null and b/branding/icon/ios/AppIcon.appiconset/AppIcon-1024.png differ
diff --git a/branding/icon/ios/AppIcon.appiconset/Contents.json b/branding/icon/ios/AppIcon.appiconset/Contents.json
new file mode 100644
index 00000000..f22e10cd
--- /dev/null
+++ b/branding/icon/ios/AppIcon.appiconset/Contents.json
@@ -0,0 +1,14 @@
+{
+ "images" : [
+ {
+ "filename" : "AppIcon-1024.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/branding/icon/macos/AppIcon-1024.png b/branding/icon/macos/AppIcon-1024.png
new file mode 100644
index 00000000..7809fd02
Binary files /dev/null and b/branding/icon/macos/AppIcon-1024.png differ
diff --git a/branding/icon/macos/AppIcon.icns b/branding/icon/macos/AppIcon.icns
new file mode 100644
index 00000000..9a014141
Binary files /dev/null and b/branding/icon/macos/AppIcon.icns differ
diff --git a/scripts/package_mac_app.sh b/scripts/package_mac_app.sh
new file mode 100755
index 00000000..3dd7ea60
--- /dev/null
+++ b/scripts/package_mac_app.sh
@@ -0,0 +1,52 @@
+#!/bin/zsh
+# Wraps a built mt_native_render into a double-clickable Metin2.app with the branding icon:
+# scripts/package_mac_app.sh [BUILD_DIR=build/release] [CLIENT_DIR=/Client] [OUT=BUILD_DIR/Metin2.app]
+# The bundle is for this machine: the executable still links Homebrew's SDL3 / Vulkan loader / MoltenVK, and
+# the launcher runs the live client from CLIENT_DIR (an absolute path baked in; MT_CLIENT_DIR overrides it
+# at launch). The shaders and python27.zip go to Contents/Resources, which SDL_GetBasePath returns in a bundle.
+set -euo pipefail
+repo=${0:A:h:h}
+build=${1:-$repo/build/release}
+client=${2:-$repo/Client}
+out=${3:-$build/Metin2.app}
+bin=$build/src/host/mt_native_render
+[[ -x $bin ]] || { echo "missing $bin (build the mt_native_render target first)" >&2; exit 1; }
+client=${client:A}
+version=$(git -C $repo describe --always --dirty 2>/dev/null || echo dev)
+
+rm -rf $out
+mkdir -p $out/Contents/MacOS $out/Contents/Resources
+cp $bin $out/Contents/MacOS/
+cp $build/src/host/native.vert.spv $build/src/host/native.frag.spv $build/src/host/python27.zip $out/Contents/Resources/
+cp $repo/branding/icon/macos/AppIcon.icns $out/Contents/Resources/
+
+cat > $out/Contents/MacOS/Metin2 < $out/Contents/Info.plist <
+
+
+
+ CFBundleNameMetin2
+ CFBundleDisplayNameMetin2
+ CFBundleIdentifierorg.metin2port.client
+ CFBundleExecutableMetin2
+ CFBundleIconFileAppIcon
+ CFBundlePackageTypeAPPL
+ CFBundleShortVersionString0.1
+ CFBundleVersion$version
+ LSMinimumSystemVersion12.0
+ LSApplicationCategoryTypepublic.app-category.role-playing-games
+ NSHighResolutionCapable
+
+
+EOF
+# Ad-hoc signature so Gatekeeper on Apple silicon runs the copied binary.
+codesign --force --deep --sign - $out >/dev/null 2>&1 || true
+echo $out