Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,15 @@ jobs:
path: |
build/avr/avr.ino.with_bootloader.bin
build/avr/avr.ino.hex
build/avr/avr.ino.with_bootloader.hex
build/SHA256SUMS
build/avr-busy-wire/avr.ino.with_bootloader.bin
build/avr-busy-wire/avr.ino.hex
build/avr-busy-wire/avr.ino.with_bootloader.hex
build/firmware-report.json
build/avr-buffered/avr.ino.with_bootloader.bin
build/avr-buffered/avr.ino.hex
build/avr-buffered/avr.ino.with_bootloader.hex
build/esp32s3-buffered/esp32s3.ino.bin
build/esp32s3-buffered/esp32s3.ino.merged.bin
build/esp32s3-buffered/esp32s3.ino.partitions.bin
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ Engineering packages are attached to successful [Build workflow runs](https://gi
Select the intended commit, not just the newest timestamp. Firmware, Windows and
Android outputs are separate artifacts; release packaging adds SHA-256 manifests
and provenance. A successful build is not a deployment or a stable-release claim.
The firmware artifact includes AVR application-only `avr.ino.hex` and verified
full-flash `avr.ino.with_bootloader.hex` for polling, busy-wire and buffered
links. Draft release ZIPs include both as well. The latter contains Urboot and
is intended for explicit full-flash/ISP recovery; neither HEX writes EEPROM or
fuses. ESP32-S3 application/OTA images remain raw `.bin`, not Intel HEX.
See [release policy and verification](docs/REPOSITORY-GOVERNANCE.md).

<details>
Expand Down
4 changes: 3 additions & 1 deletion assets/branding/BOARD-ICONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ signature and uses the same generic-artwork fallback. Renaming a hostname does
not switch identity; fresh capability metadata does. No new protocol selector.

OS launcher packaging is separate: these are board identities, not two new
applications. Existing Pakar launcher assets remain unchanged. Dedicated Apple
applications. Pakar's application mark is now app-icon.svg with a 1024px native/
README/Android master and a bounded 64px peer derivative; see BRANDING-PARITY.md.
Dedicated Apple
layered/tinted icon catalogs, Android role shortcuts, and per-role Windows
launcher resources are not implemented or tested by this change. Platform
references: Apple HIG App icons; Android adaptive icons; Microsoft Windows app
Expand Down
Binary file added assets/branding/app-icon-1024.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/branding/app-icon-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/branding/app-icon-24.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/branding/app-icon-256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/branding/app-icon-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/branding/app-icon-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/branding/app-icon-64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion assets/branding/app-icon.png.base64
Original file line number Diff line number Diff line change
@@ -1 +1 @@
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
44 changes: 44 additions & 0 deletions assets/branding/app-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions assets/branding/application-artwork.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"source": "assets/branding/app-icon.svg",
"source_sha256": "9f554d00ecb84361f5371a1c800db0040b3fec4c63244550905bbad9c9b006ac",
"outputs": {
"assets/branding/app-icon-24.png": "e19239958b712562c6a5914dabc456de5a62cac089aae6334a1c6f0d4056178a",
"assets/branding/app-icon-32.png": "629c70966b7aa843afd473b5c7861fba267e0230b1611bd208224add21ea3111",
"assets/branding/app-icon-64.png": "cdb7ea4ccf02e71eb01107b70e3267e47241b5f2155db070878129fc402bfd0b",
"assets/branding/app-icon.png.base64": "71b8cf5cb03da6097d0776f9e5401a5b5c808ad72bf289e56297e68d413bccdf",
"assets/branding/app-icon-128.png": "1ee56481ded568155c0d5d81a4676db6d2cd9c823b485561e6e51beca0fdc6a2",
"assets/branding/app-icon-256.png": "6ab3f51ac979232a5892d7324d962a33018c8eaf9a81db634169da704f7a105e",
"assets/branding/app-icon-512.png": "383b2cbd51db540c1e3cfb079dd44902a6ae648ae103a46f67b97e7f7c67417e",
"assets/branding/app-icon-1024.png": "35cb15b03ac789701ac0b2e0b0970ac1a0b3a758ce061ec99b365cec2a274fe7"
}
}
1 change: 1 addition & 0 deletions desktop/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,5 @@ fn main() {
println!("cargo:rerun-if-changed=src/platform/windows_quick_actions.rs");
println!("cargo:rerun-if-changed=src/brand_image.rs");
println!("cargo:rerun-if-changed=../assets/branding/app-icon.png.base64");
println!("cargo:rerun-if-changed=../assets/branding/app-icon-1024.png");
}
5 changes: 5 additions & 0 deletions desktop/src/brand_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
use base64::{Engine, engine::general_purpose::STANDARD};

pub fn icon_bytes() -> &'static [u8] {
include_bytes!("../../assets/branding/app-icon-1024.png")
}

/// Bounded identity-wire derivative of the same editable application master.
pub fn compact_icon_bytes() -> &'static [u8] {
static BYTES: std::sync::OnceLock<Vec<u8>> = std::sync::OnceLock::new();
BYTES.get_or_init(|| {
STANDARD
Expand Down
32 changes: 26 additions & 6 deletions desktop/src/branding.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Actual Pealayer image decoder adapted to Pakar's single cross-surface master.
pub use crate::brand_image::icon_bytes;
pub use crate::brand_image::{icon_bytes, compact_icon_bytes};
use eframe::egui;
use std::hash::{Hash, Hasher};
use base64::Engine;
Expand Down Expand Up @@ -29,7 +29,7 @@ pub fn sync_peer(
}
let icon = app
.and_then(|a| a.icon_bytes())
.filter(|b| b.as_slice() != icon_bytes())
.filter(|b| b.as_slice() != icon_bytes() && b.as_slice() != compact_icon_bytes())
.and_then(|b| icon_data_from_bytes(&b))
.or_else(|| {
let encoded = match peer.filter(|p| p.known()).map(|p| p.role.as_str()) {
Expand Down Expand Up @@ -113,6 +113,26 @@ pub fn logo(ui: &mut egui::Ui, size: f32) {
mod tests {
use super::*;
#[test]
fn compact_default_does_not_mask_the_connected_board_role() {
let ctx = egui::Context::default();
let peer = crate::capabilities::Manifest {
board_kind: "controller".into(),
role: "first-wins".into(),
application: Some(crate::identity::Application {
id: "keys.app".into(), name: "Keys".into(), title: "Keys".into(),
icon_png_base64: include_str!("../../assets/branding/app-icon.png.base64").trim().into(),
}),
..Default::default()
};
let expected = base64::engine::general_purpose::STANDARD
.decode(include_str!("../../assets/branding/keys.png.base64").trim()).unwrap();
let expected = icon_data_from_bytes(&expected).unwrap();
let mut output = ctx.run_ui(egui::RawInput::default(), |_| {
assert_eq!(sync_peer(&ctx, Some(&peer)).unwrap().rgba, expected.rgba);
});
output.textures_delta.clear();
}
#[test]
fn peer_icon_lifecycle_reuses_refresh_and_revokes_on_disconnect() {
let ctx = egui::Context::default();
let mut peer = crate::capabilities::Manifest {
Expand Down Expand Up @@ -151,9 +171,9 @@ mod tests {
#[test]
fn bundled_artwork_decodes_without_files_or_theme_specific_replacements() {
let icon = window_icon();
assert_eq!((icon.width, icon.height), (64, 64));
assert_eq!((icon.width, icon.height), (1024, 1024));
assert_eq!(
icon.rgba.as_slice(),
crate::brand_image::rgba_at_size(64).as_slice(),
&include_bytes!(concat!(env!("OUT_DIR"), "/pakar-icon-64.rgba"))[..]
);
assert_eq!(
Expand Down Expand Up @@ -208,7 +228,7 @@ mod tests {
.set
.values()
.flatten()
.any(|delta| delta.image.size() == [64, 64]);
.any(|delta| delta.image.size() == [1024, 1024]);
// Headless tests have no texture backend. Drain before assertions
// so a failed assertion cannot cause a second destructor panic.
output.textures_delta.clear();
Expand All @@ -222,7 +242,7 @@ mod tests {
.set
.values()
.flatten()
.any(|delta| delta.image.size() == [64, 64]);
.any(|delta| delta.image.size() == [1024, 1024]);
output.textures_delta.clear();
assert!(!uploaded_again, "do not decode/upload on every frame");
}
Expand Down
37 changes: 29 additions & 8 deletions docs/BRANDING-PARITY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# One PakarController application icon

## Current high-DPI control-grid design

The prototype Circuitry raster is replaced by the editable
`assets/branding/app-icon.svg`: staggered illuminated white/emerald/mint cells
and a circular button on a deep teal tile. It is original vector artwork,
not an enlarged font glyph. Native resources and README use the rendered
1024px master; Android's adaptive launcher uses the same high-DPI PNG.
Windows ICO retains all seven donor-derived sizes (16–256), rendered directly
from that master. Existing role-specific board artwork and custom peer icons
retain their identity and priority.

`generate-application-artwork.mjs --render` deliberately invokes the external
Sharp rasterizer through PAKAR_SHARP_MODULE. Ordinary generation and `--check`
require no image package: source/output hashes in application-artwork.json
guard every committed derivative. The compact 64px base64 derivative remains
under the 4096-character identity budget for ESP/peer/Web headers. README,
native executable and Android launcher no longer upscale that transport icon.

The following deployment observations describe the historical prototype
checkpoint only; they are not evidence that these new assets are installed.

## Android launcher correction

The previous mobile import covered only the in-app header, leaving all five
Expand All @@ -17,8 +38,8 @@ has SHA-256 05bc6ce48c57eb8bf6c8f1acd98f10389ae2e6fcc40b4bf41b09f9ce39c85783,
byte-identical to the canonical PNG, not a Flutter density fallback. Physical
ADB readback confirms MainActivity in foreground; the actual running UI was
captured and inspected. Launcher-grid pixels are not inferred from header pixels.
The existing 64x64 master limitation remains; a high-DPI editable master is not
claimed. Runtime board artwork cannot rewrite the installed Android launcher.
That historical 64x64 limitation is addressed by the current SVG/high-DPI
pipeline above. Runtime board artwork cannot rewrite the installed Android launcher.

The mismatch was an incomplete integration: the native PE/window/tray generated
Phosphor Circuitry, the native menu/About used a separate theme-tinted font
Expand All @@ -32,7 +53,7 @@ runtime preferences do not silently rewrite executable or pinned icons.

## Canonical master and exact code imports

`assets/branding/app-icon.png.base64` is a 740-byte lossless PNG encoding of the
The former `assets/branding/app-icon.png.base64` was a 740-byte lossless PNG encoding of the
existing 64x64 native Phosphor Circuitry raster. Verified current warm-cache
native pixels SHA-256:
`d24d849f01bfeaa0cffef1cc9b861062b52e1a320f4c943608fb5fd952ded387`.
Expand Down Expand Up @@ -80,12 +101,12 @@ their actual Phosphor vocabulary; they are not application-logo variants.
- Build metadata, external branding manifest/environment override validation,
generic publisher/version/provenance resource fields remain pending. macOS
mpv linker probing is excluded by the requested mpv-free controller.
- The preserved master is currently 64x64, not a claimed 512x512 editable icon
pack/PWA artwork. ICO derivatives retain the donor's seven sizes; high-DPI
editable master and full installable PWA manifest/cache remain open.
- High-DPI artwork is now implemented above. Platform-specific Apple layered/
tinted catalogs and installed/pinned-icon cache refresh still need their
own packaging/runtime acceptance; no OS-wide cache deletion is performed.

`tests/branding_test.mjs` verifies exact preserved native pixels, four identical
embedded Web images, production native consumers and no-write generation.
`tests/branding_test.mjs` verifies high-DPI and bounded derivative identities,
four identical embedded Web images, native consumers and no-write generation.
Three Rust tests verify native pixels/window/tray derivatives, all ICO frames
and shared texture reuse in both themes. Source tests do not certify compiled
resource extraction or deployed runtime/board appearance. CI runs asynchronously;
Expand Down
Loading
Loading