diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cd9a716..d4f57966 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ ## v1.8.2-alpha (2026-08-13) - **An app that can't be shown inside the dashboard now becomes a tab app by itself.** A few apps refuse to render inside another page no matter what — they break out with their own code or insist on owning the whole browser window. Opening one used to mean staring at a grey pane. Now the dashboard notices, offers the app in its own tab, and remembers: from then on that app's button opens a tab directly (with the little launch icon that tab apps carry), first click, every time. If a later update makes the app embeddable after all, the dashboard notices that too and goes back to embedding it. -- **The screensaver and login emblem are back to their clean black finish.** A glossy paint experiment on the circle behind the logo shipped by mistake in the previous update; it's removed everywhere. +- **The logo emblem got its glossy black paint finish — properly this time.** The circle behind the A on the screensaver, intro, and login now wears a deep wet-paint look: warm light blooming from the top edge, fine grain so the dark tones stay smooth instead of banding, and no more ring border. (An earlier rougher version of this experiment briefly shipped by accident and then vanished depending on which screen you were on — this is the finished, deliberate one, everywhere.) +- **New app icons now match the store's look, on every screen.** Alby Hub and phoenixd arrived with edge-to-edge logos that ignored the breathing room every other app icon has, and the app detail page skipped the icon backdrop entirely. Both icons are re-set on the standard canvas, the detail page now applies the same icon treatment as the store tiles, and app developers get a one-command tool that puts any logo onto the house canvas automatically. ## v1.8.1-alpha (2026-08-13) diff --git a/docs/app-developer-guide.md b/docs/app-developer-guide.md index 5dead61e..11d61770 100644 --- a/docs/app-developer-guide.md +++ b/docs/app-developer-guide.md @@ -531,6 +531,20 @@ The broader app update policy for `1.8-alpha` is still being finalized. Until th ## App Icon +- **The tile plate (dark rounded background, border, sheen) is applied by + the system** — every surface renders your icon with the house + `archy-app-icon` treatment automatically. What the system deliberately + does NOT add is an inner margin (icons that already carry whitespace + would double-margin), so your file needs it baked in: **square canvas, + ~12% margin per side**. Edge-to-edge marks look wrong next to every + other tile. Don't hand-tune it: run your mark through the normalizer + and commit its output — + ```bash + scripts/normalize-app-icon.py your-mark.svg apps-icon-output.svg + ``` + It wraps any SVG (full-bleed upstream logos included) onto the house + canvas with the standard margin, preserving the original artwork + untouched inside. - Provide a URL to your app icon (PNG, WebP, or SVG) - Recommended size: 256x256 pixels - Square aspect ratio diff --git a/neode-ui/public/assets/img/app-icons/alby-hub.svg b/neode-ui/public/assets/img/app-icons/alby-hub.svg index 3649a900..a5ac1825 100644 --- a/neode-ui/public/assets/img/app-icons/alby-hub.svg +++ b/neode-ui/public/assets/img/app-icons/alby-hub.svg @@ -1,5 +1,9 @@ - + + + - \ No newline at end of file + + + diff --git a/neode-ui/public/assets/img/app-icons/phoenixd.svg b/neode-ui/public/assets/img/app-icons/phoenixd.svg index 2324e437..5122fcb8 100644 --- a/neode-ui/public/assets/img/app-icons/phoenixd.svg +++ b/neode-ui/public/assets/img/app-icons/phoenixd.svg @@ -1,7 +1,11 @@ - + + + - \ No newline at end of file + + + diff --git a/neode-ui/src/views/MarketplaceAppDetails.vue b/neode-ui/src/views/MarketplaceAppDetails.vue index cfbe6bdd..d856cfea 100644 --- a/neode-ui/src/views/MarketplaceAppDetails.vue +++ b/neode-ui/src/views/MarketplaceAppDetails.vue @@ -23,7 +23,7 @@ v-if="app.icon" :src="app.icon" :alt="app.title" - class="w-20 h-20 rounded-xl shadow-xl flex-shrink-0" + class="w-20 h-20 rounded-xl shadow-xl flex-shrink-0 archy-app-icon" @error="handleImageError" />
@@ -99,7 +99,7 @@ v-if="app.icon" :src="app.icon" :alt="app.title" - class="w-20 h-20 rounded-xl shadow-xl" + class="w-20 h-20 rounded-xl shadow-xl archy-app-icon" @error="handleImageError" />
diff --git a/neode-ui/src/views/settings/AccountInfoSection.vue b/neode-ui/src/views/settings/AccountInfoSection.vue index 0aad7e3a..9d43a625 100644 --- a/neode-ui/src/views/settings/AccountInfoSection.vue +++ b/neode-ui/src/views/settings/AccountInfoSection.vue @@ -370,7 +370,8 @@ init()

**An app that can't be shown inside the dashboard now becomes a tab app by itself.** A few apps refuse to render inside another page no matter what — they break out with their own code or insist on owning the whole browser window. Opening one used to mean staring at a grey pane. Now the dashboard notices, offers the app in its own tab, and remembers: from then on that app's button opens a tab directly (with the little launch icon that tab apps carry), first click, every time. If a later update makes the app embeddable after all, the dashboard notices that too and goes back to embedding it.

-

**The screensaver and login emblem are back to their clean black finish.** A glossy paint experiment on the circle behind the logo shipped by mistake in the previous update; it's removed everywhere.

+

**The logo emblem got its glossy black paint finish — properly this time.** The circle behind the A on the screensaver, intro, and login now wears a deep wet-paint look: warm light blooming from the top edge, fine grain so the dark tones stay smooth instead of banding, and no more ring border. (An earlier rougher version of this experiment briefly shipped by accident and then vanished depending on which screen you were on — this is the finished, deliberate one, everywhere.)

+

**New app icons now match the store's look, on every screen.** Alby Hub and phoenixd arrived with edge-to-edge logos that ignored the breathing room every other app icon has, and the app detail page skipped the icon backdrop entirely. Both icons are re-set on the standard canvas, the detail page now applies the same icon treatment as the store tiles, and app developers get a one-command tool that puts any logo onto the house canvas automatically.

diff --git a/scripts/normalize-app-icon.py b/scripts/normalize-app-icon.py new file mode 100755 index 00000000..3c92aeee --- /dev/null +++ b/scripts/normalize-app-icon.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +"""Normalize a third-party SVG mark onto the Archipelago app-icon canvas. + +Store tiles render icons as-is — there is deliberately no runtime inset +(it would double-margin every icon that already ships whitespace), so the +margin must be baked into the file. House icons carry it naturally; +third-party marks are usually full-bleed (Alby Hub's tile icon was the +first to land edge-to-edge in the store, 2026-08-14). This wraps any SVG +in a square canvas with a uniform inner margin, preserving the original +untouched as a nested . + +Usage: + scripts/normalize-app-icon.py in.svg out.svg [--margin 0.12] + +Margin is a fraction of the canvas per side (default 12%, the house look). +""" + +import argparse +import re +import sys + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("src") + ap.add_argument("dst") + ap.add_argument("--margin", type=float, default=0.12, + help="inner margin per side, fraction of canvas (default 0.12)") + args = ap.parse_args() + + svg = open(args.src, encoding="utf-8").read() + + m = re.search(r"]*>", svg, re.S) + if not m: + print("error: no root element found", file=sys.stderr) + return 1 + root = m.group(0) + + vb = re.search(r'viewBox\s*=\s*["\']([\d.eE+\s,-]+)["\']', root) + if vb: + nums = [float(x) for x in re.split(r"[\s,]+", vb.group(1).strip())] + if len(nums) != 4: + print("error: unparseable viewBox", file=sys.stderr) + return 1 + _, _, w, h = nums + inner_viewbox = vb.group(1).strip() + else: + wm = re.search(r'width\s*=\s*["\']([\d.]+)', root) + hm = re.search(r'height\s*=\s*["\']([\d.]+)', root) + if not (wm and hm): + print("error: no viewBox and no width/height to derive one", file=sys.stderr) + return 1 + w, h = float(wm.group(1)), float(hm.group(1)) + inner_viewbox = f"0 0 {w} {h}" + + # Square canvas fitting the larger dimension; the mark centers in it. + side = max(w, h) + canvas = 100.0 + margin = canvas * args.margin + avail = canvas - 2 * margin + scale_w = avail * (w / side) + scale_h = avail * (h / side) + x = (canvas - scale_w) / 2 + y = (canvas - scale_h) / 2 + + # Strip any XML prolog from the original; it nests inside the wrapper. + inner = re.sub(r"^\s*<\?xml[^>]*\?>\s*", "", svg) + + out = ( + f'\n' + f' \n' + f' \n' + f'{inner}\n' + f' \n' + f'\n' + ) + open(args.dst, "w", encoding="utf-8").write(out) + print(f"wrote {args.dst}: {canvas:g}x{canvas:g} canvas, mark {scale_w:.1f}x{scale_h:.1f} at {args.margin:.0%} margin") + return 0 + + +if __name__ == "__main__": + sys.exit(main())