(build): add Microsoft Store listing copy and logos; shorten the package display name

This commit is contained in:
Maksym Sadovnychyy 2026-09-28 20:05:25 +02:00
parent 7e481262d5
commit 0668a518da
15 changed files with 336 additions and 1 deletions

View File

@ -47,6 +47,16 @@ Those name, publisher, and publisher display strings are `packageName`, `publish
The `.msix` is not a GitHub release asset.
Store listing copy:
| Field | Document |
|-------|----------|
| Short description, description, extra requirements | [packaging/microsoft-store/description.md](packaging/microsoft-store/description.md) |
| Product features (up to 20 bullets, 200 characters each) | [packaging/microsoft-store/product-features.md](packaging/microsoft-store/product-features.md) |
| Keywords (up to 7, 40 characters each, 21 words total) | [packaging/microsoft-store/keywords.md](packaging/microsoft-store/keywords.md) |
| Copyright, additional license terms, Developed by | [packaging/microsoft-store/additional-info.md](packaging/microsoft-store/additional-info.md) |
| Store logos (9:16 poster, 1:1 box art, app tiles) | [packaging/microsoft-store/logos.md](packaging/microsoft-store/logos.md) |
### System requirements (Properties)
Partner Center → **Properties** → **System requirements**. A blank cell stays unset. Minimum is what the Store may warn on; Recommended does not warn.

View File

@ -0,0 +1,157 @@
# Renders Microsoft Store logo PNGs from the Cluster Console icon geometry.
# Requires Windows PowerShell 5.1 (System.Drawing). Output: packaging/microsoft-store/logos/
$ErrorActionPreference = "Stop"
Add-Type -AssemblyName System.Drawing
$outDir = Join-Path $PSScriptRoot "logos"
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
Add-Type -ReferencedAssemblies System.Drawing -TypeDefinition @"
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
public static class StoreLogos {
static readonly Color Bg0 = Color.FromArgb(0x33, 0xA5, 0xCF);
static readonly Color Bg1 = Color.FromArgb(0x00, 0x2A, 0x6A);
static readonly Color Tile0 = Color.White;
static readonly Color Tile1 = Color.FromArgb(0xC5, 0xE8, 0xF6);
static readonly Color Ink = Color.FromArgb(0x00, 0x2A, 0x6A);
public static void SaveAll(string dir) {
SaveIcon(Path.Combine(dir, "box-1x1-2160x2160.png"), 2160);
SaveIcon(Path.Combine(dir, "box-1x1-1080x1080.png"), 1080);
SaveIcon(Path.Combine(dir, "tile-1x1-300x300.png"), 300);
SaveIcon(Path.Combine(dir, "tile-1x1-150x150.png"), 150);
SaveIcon(Path.Combine(dir, "tile-1x1-71x71.png"), 71);
SavePoster(Path.Combine(dir, "poster-9x16-1440x2160.png"), 1440, 2160);
SavePoster(Path.Combine(dir, "poster-9x16-720x1080.png"), 720, 1080);
}
static void SaveIcon(string path, int size) {
using (var bmp = new Bitmap(size, size, PixelFormat.Format32bppArgb))
using (var g = Graphics.FromImage(bmp)) {
Quality(g);
DrawBackground(g, size, size);
DrawMark(g, 0f, 0f, size / 256f, true);
bmp.Save(path, ImageFormat.Png);
}
}
static void SavePoster(string path, int w, int h) {
using (var bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb))
using (var g = Graphics.FromImage(bmp)) {
Quality(g);
DrawBackground(g, w, h);
float scale = 0.62f * w / 184f;
float markH = 148f * scale;
using (var font = FitFont(g, "Cluster Console", w * 0.84f, w * 0.072f)) {
SizeF text = g.MeasureString("Cluster Console", font);
float gap = h * 0.045f;
float block = markH + gap + text.Height;
float top = (h - block) / 2f;
float ox = (w / 2f) - (128f * scale);
float oy = (top + markH / 2f) - (124f * scale);
DrawMark(g, ox, oy, scale, false);
using (var brush = new SolidBrush(Color.White))
using (var fmt = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Near }) {
g.DrawString("Cluster Console", font, brush, new RectangleF(0f, top + markH + gap, w, text.Height + 4f), fmt);
}
}
bmp.Save(path, ImageFormat.Png);
}
}
static void DrawBackground(Graphics g, int w, int h) {
using (var brush = new LinearGradientBrush(
new PointF(w * 0.2f, 0f),
new PointF(w * 0.9f, h),
Bg0,
Bg1)) {
g.FillRectangle(brush, 0, 0, w, h);
}
}
static void DrawMark(Graphics g, float ox, float oy, float s, bool shine) {
if (shine) {
using (var brush = new SolidBrush(Color.FromArgb(41, 255, 255, 255))) {
float rx = 150f * s;
float ry = 88f * s;
g.FillEllipse(brush, ox + (128f * s) - rx, oy + (8f * s) - ry, rx * 2f, ry * 2f);
}
}
Tile(g, ox, oy, s, 36f, 50f);
Tile(g, ox, oy, s, 132f, 50f);
Tile(g, ox, oy, s, 84f, 110f);
using (var pen = new Pen(Ink, 14f * s)) {
pen.StartCap = LineCap.Round;
pen.EndCap = LineCap.Round;
pen.LineJoin = LineJoin.Round;
g.DrawLines(pen, new[] {
new PointF(ox + 112f * s, oy + 134f * s),
new PointF(ox + 152f * s, oy + 154f * s),
new PointF(ox + 112f * s, oy + 174f * s)
});
}
}
static void Tile(Graphics g, float ox, float oy, float s, float x, float y) {
float rx = ox + x * s;
float ry = oy + y * s;
float side = 88f * s;
float radius = 20f * s;
using (var path = RoundedRect(rx, ry, side, side, radius))
using (var brush = new LinearGradientBrush(
new PointF(rx, ry),
new PointF(rx + side, ry + side),
Tile0,
Tile1)) {
g.FillPath(brush, path);
}
}
static GraphicsPath RoundedRect(float x, float y, float w, float h, float r) {
float d = r * 2f;
var path = new GraphicsPath();
path.AddArc(x, y, d, d, 180f, 90f);
path.AddArc(x + w - d, y, d, d, 270f, 90f);
path.AddArc(x + w - d, y + h - d, d, d, 0f, 90f);
path.AddArc(x, y + h - d, d, d, 90f, 90f);
path.CloseFigure();
return path;
}
static Font FitFont(Graphics g, string text, float maxWidth, float startPx) {
float size = startPx;
Font font = null;
while (size > 12f) {
if (font != null) font.Dispose();
font = new Font("Segoe UI", size, FontStyle.Bold, GraphicsUnit.Pixel);
if (g.MeasureString(text, font).Width <= maxWidth) return font;
size -= 1f;
}
return font;
}
static void Quality(Graphics g) {
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
}
}
"@
[StoreLogos]::SaveAll($outDir)
Add-Type -AssemblyName System.Drawing
Get-ChildItem $outDir -Filter *.png | ForEach-Object {
$img = [System.Drawing.Image]::FromFile($_.FullName)
"{0}`t{1}x{2}`t{3:N0} KB" -f $_.Name, $img.Width, $img.Height, ($_.Length / 1KB)
$img.Dispose()
}

View File

@ -0,0 +1,29 @@
# Microsoft Store additional info
Paste into Partner Center → Store listings. Field limits are from [Add additional information](https://learn.microsoft.com/en-us/windows/apps/publish/publish-your-app/msix/add-additional-information).
## Copyright and trademark info
200 characters.
```text
© Maksym Sadovnychyy (MAKS-IT). Apache License 2.0.
```
## Additional license terms
Leave this blank only when customers should be licensed solely under the Standard Application License Terms. This product is Apache 2.0 ([LICENSE.md](../../LICENSE.md)), so paste the license URL. A single URL is shown to customers as a link. Plain text is limited to 10,000 characters.
```text
http://www.apache.org/licenses/LICENSE-2.0
```
## Developed by
255 characters. This is separate from **Published by**, which stays the publisher display name on the account.
```text
Maksym Sadovnychyy (MAKS-IT)
```
The listing description is in [description.md](description.md). Product features are in [product-features.md](product-features.md). Keywords are in [keywords.md](keywords.md).

View File

@ -0,0 +1,60 @@
# Microsoft Store description
Paste into Partner Center → Store listings. Plain text only. URLs in these fields are not clickable; put the privacy policy, support site, and license in their own submission fields.
Leave **What's new in this version** empty on the first submission. Use it only for a later update (1,500 characters).
Hardware checkboxes (keyboard, memory, processor) stay in [CONTRIBUTING.md](../../CONTRIBUTING.md) under **System requirements (Properties)**.
## Short description
Shown at the top of the listing. The field allows 1,000 characters. Keep this under 270 so every Store view shows the full sentence.
```text
A desktop app for an existing Kubernetes cluster. Connect with your kubeconfig, then browse resources, apply YAML, follow pod logs, open a shell, and forward ports to this PC.
```
## Description
Required. Up to 10,000 characters. This text is different from the short description so the page does not repeat the same paragraph.
```text
Work on a Kubernetes cluster from Windows without keeping a browser dashboard or a terminal open for every task.
Connect with the kubeconfig you already use. What you can see and change is exactly what that identity is allowed to do. Choosing a context in the catalog also sets kubectl's current context, so this app and the command line stay on the same cluster.
Move through the cluster from one navigator: cluster and nodes, applications, workloads, config, network, storage, namespaces, events, Helm releases, Dapr, access control, and custom resources. Tables keep filters and sort for each cluster. Open a row for YAML, events, and status.
Everyday changes stay in the same window. Apply or create YAML, scale and restart workloads, trigger a CronJob, and cordon or drain a node. On a pod, follow the log or open a shell. Port forwards are saved, restored when you reconnect, and a double-click on an active forward opens it in the browser.
CPU and memory appear on the overview, applications, and workload tables when the cluster has metrics-server. Persistent volumes and claims open a file browser for viewing, editing, downloading, and uploading files. Helm and Dapr pages list objects that are already in the cluster.
Chat is optional and stays on this PC. It talks to a local Ollama server and can read issues, YAML, logs, and events for the resource you selected. Apply, restart, and delete stay manual. Cluster data is not sent to a cloud AI service.
Your layout, open clusters, and saved port forwards are stored on this computer. Cluster Console talks to a cluster you already run.
You need 64-bit Windows, a kubeconfig that can reach a running cluster, and a network path to that cluster's API. Install Ollama locally only if you want Chat.
```
Product features (up to 20 bullets) are in [product-features.md](product-features.md). Keywords are in [keywords.md](keywords.md). Copyright, additional license terms, and Developed by are in [additional-info.md](additional-info.md).
## Additional system requirements
Optional text lines, separate from the Properties hardware table. Up to 11 minimum and 11 recommended. Each line is at most 200 characters.
Minimum:
```text
64-bit Windows 10 or Windows 11
A kubeconfig with permission to reach a running Kubernetes cluster
Network access to that cluster's API server
```
Recommended:
```text
metrics-server installed in the cluster, for CPU and memory columns
Ollama on this PC, only if you use Chat
```
Category: Developer tools.

View File

@ -0,0 +1,17 @@
# Microsoft Store keywords
Paste into Partner Center → Store listings → **Keywords**. One keyword per line. Hidden from customers.
Up to 7 keywords. 40 character limit for each keyword. No more than 21 separate words across all keywords.
```text
Kubernetes GUI
kubeconfig
pod logs
YAML
Helm releases
port forwarding
Dapr
```
The listing description is in [description.md](description.md). Product features are in [product-features.md](product-features.md).

View File

@ -0,0 +1,37 @@
# Microsoft Store logos
Upload the PNG files in [logos/](logos/) on Partner Center → Store listings → **Store logos**. They use the same mark as `src/MaksIT.ClusterConsole.UI/Assets/icon.svg`.
Regenerate with `packaging/microsoft-store/New-StoreLogos.ps1` (Windows PowerShell 5.1).
PNG only. Poster and box art must be under 50 MB. App tiles must be under 5 MB.
## 9:16 Poster art
Main logo for Windows 10 and Windows 11. Required for Xbox.
| File | Size |
|------|------|
| [logos/poster-9x16-720x1080.png](logos/poster-9x16-720x1080.png) | 720 × 1080 |
| [logos/poster-9x16-1440x2160.png](logos/poster-9x16-1440x2160.png) | 1440 × 2160 |
## 1:1 Box art
Used in Store layouts. Used as the main logo when the 9:16 poster is missing.
| File | Size |
|------|------|
| [logos/box-1x1-1080x1080.png](logos/box-1x1-1080x1080.png) | 1080 × 1080 |
| [logos/box-1x1-2160x2160.png](logos/box-1x1-2160x2160.png) | 2160 × 2160 |
## Store display images
1:1 app tile icon, shown in the Store for Windows 10 and Windows 11. These replace the logo images from the package when uploaded.
| File | Size |
|------|------|
| [logos/tile-1x1-300x300.png](logos/tile-1x1-300x300.png) | 300 × 300 |
| [logos/tile-1x1-150x150.png](logos/tile-1x1-150x150.png) | 150 × 150 |
| [logos/tile-1x1-71x71.png](logos/tile-1x1-71x71.png) | 71 × 71 |
Listing text is in [description.md](description.md), [product-features.md](product-features.md), [keywords.md](keywords.md), and [additional-info.md](additional-info.md).

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,25 @@
# Microsoft Store product features
Paste into Partner Center → Store listings → **Product features**.
Short summaries of the product's key features. Displayed as a bulleted list. Up to 20 app features. Each feature is at most 200 characters.
```text
Connect with the kubeconfig you already use. Access follows that identity's permissions.
Choose a context in the catalog to set kubectl's current context.
Browse cluster, nodes, workloads, config, network, storage, namespaces, events, access control, and custom resources.
View, apply, create, and delete resource YAML, including force delete.
Scale and restart workloads, and trigger a CronJob.
Cordon and drain nodes.
Follow pod logs and open a shell in a container.
Save port forwards, restore them on reconnect, and open an active forward in the browser.
Show CPU and memory when the cluster has metrics-server.
Group applications by instance and namespace from standard labels.
Browse, edit, download, and upload files on a persistent volume or claim.
List Helm releases that are already installed in the cluster.
List Dapr components, configurations, subscriptions, resiliency, endpoints, sidecars, and the control plane.
Ask a local Ollama model about the selected resource. Chat can read only.
Keep filters, sort, layout, and port forwards on this PC.
```
The listing description and the other Store text fields are in [description.md](description.md).

View File

@ -71,7 +71,7 @@
"packageName": "MAKS-IT.ClusterConsole",
"publisher": "CN=FCC8C0E7-6D5F-4028-B8EE-903B88C0C8F9",
"publisherDisplayName": "MaksIT",
"displayName": "MaksIT Cluster Console",
"displayName": "Cluster Console",
"executableName": "MaksIT.ClusterConsole.UI.exe",
"runtimeIdentifier": "win-x64",
"iconPath": "..\\..\\..\\src\\MaksIT.ClusterConsole.UI\\Assets\\icon.png",