@@ -107,6 +107,18 @@ jobs:
|
|||||||
SKIP_INTEGRATION: '1'
|
SKIP_INTEGRATION: '1'
|
||||||
run: npm test
|
run: npm test
|
||||||
|
|
||||||
|
- name: Verify branding icons
|
||||||
|
timeout-minutes: 2
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
test -f build/icon.png
|
||||||
|
test -f build/icon.ico
|
||||||
|
test -f assets/favicons/favicon.ico
|
||||||
|
test -f assets/logo/peardata-icon-64.png
|
||||||
|
node scripts/build-branding.cjs --sync-only
|
||||||
|
ls -la build/icon.png build/icon.ico assets/logo/peardata-icon-64.png
|
||||||
|
file build/icon.png build/icon.ico || true
|
||||||
|
|
||||||
- name: Install rcodesign (macOS codesign on Linux)
|
- name: Install rcodesign (macOS codesign on Linux)
|
||||||
timeout-minutes: 2
|
timeout-minutes: 2
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -66,6 +66,19 @@ jobs:
|
|||||||
SKIP_INTEGRATION: '1'
|
SKIP_INTEGRATION: '1'
|
||||||
run: npm test
|
run: npm test
|
||||||
|
|
||||||
|
- name: Verify branding icons
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
# Committed runtime copies (master package is peardata-branding/)
|
||||||
|
test -f build/icon.png
|
||||||
|
test -f build/icon.ico
|
||||||
|
test -f assets/favicons/favicon.ico
|
||||||
|
test -f assets/logo/peardata-icon-64.png
|
||||||
|
# Sync is a no-op when masters already exist (no sharp required)
|
||||||
|
node scripts/build-branding.cjs --sync-only
|
||||||
|
ls -la build/icon.png build/icon.ico assets/logo/peardata-icon-64.png
|
||||||
|
file build/icon.png build/icon.ico
|
||||||
|
|
||||||
- name: Install rcodesign
|
- name: Install rcodesign
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# PearData
|
# PearData
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="peardata-branding/logo/peardata-icon-512.png" alt="PearData" width="160" />
|
||||||
|
</p>
|
||||||
|
|
||||||
**Decentralized, P2P, real-time monitoring for the Pear / Holepunch ecosystem.**
|
**Decentralized, P2P, real-time monitoring for the Pear / Holepunch ecosystem.**
|
||||||
|
|
||||||
Each machine runs a lightweight **PearMonitor agent**. A Pear desktop client dials agents by public key and shows fleet + per-node live dashboards. Agents also expose an **agent-compatible REST API** (`/api/v1`, `/api/v2`, `/api/v3`) for scripts, Grafana, and Prometheus.
|
Each machine runs a lightweight **PearMonitor agent**. A Pear desktop client dials agents by public key and shows fleet + per-node live dashboards. Agents also expose an **agent-compatible REST API** (`/api/v1`, `/api/v2`, `/api/v3`) for scripts, Grafana, and Prometheus.
|
||||||
@@ -15,6 +19,18 @@ Built from the [pear-app-template](https://github.com/snxraven) HyperDHT + proto
|
|||||||
| HTTP | agent-style REST on `127.0.0.1:18888` |
|
| HTTP | agent-style REST on `127.0.0.1:18888` |
|
||||||
| Desktop | **Pear** (`pear-electron` + `pear-bridge` + `<pear-ctrl>`) |
|
| Desktop | **Pear** (`pear-electron` + `pear-bridge` + `<pear-ctrl>`) |
|
||||||
|
|
||||||
|
### Branding
|
||||||
|
|
||||||
|
Master assets live in **`peardata-branding/`** (logo ladder, app icons, favicons, social/web).
|
||||||
|
Runtime copies: `build/icon.{png,icns,ico}`, `assets/logo/`, `assets/favicons/`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build:branding # regenerate from masters (needs sharp)
|
||||||
|
npm run sync:branding # copy masters → build/ + assets/
|
||||||
|
```
|
||||||
|
|
||||||
|
See [docs/BRANDING.md](./docs/BRANDING.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"name": "PearData",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Decentralized P2P real-time monitoring and fleet observability",
|
||||||
|
"colors": {
|
||||||
|
"background": {
|
||||||
|
"primary": "#0a0c10",
|
||||||
|
"secondary": "#0f131a",
|
||||||
|
"tertiary": "#151b24",
|
||||||
|
"elevated": "#1a222e",
|
||||||
|
"hover": "#232d3b"
|
||||||
|
},
|
||||||
|
"accent": {
|
||||||
|
"primary": "#34d399",
|
||||||
|
"secondary": "#2dd4bf",
|
||||||
|
"success": "#4ade80",
|
||||||
|
"warning": "#fbbf24",
|
||||||
|
"danger": "#f87171",
|
||||||
|
"info": "#38bdf8"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"primary": "#f4f7fb",
|
||||||
|
"secondary": "#c8d1df",
|
||||||
|
"muted": "#9aa8bc",
|
||||||
|
"faint": "#7d8b9f"
|
||||||
|
},
|
||||||
|
"logo": {
|
||||||
|
"peer": "#34d399",
|
||||||
|
"peerSecondary": "#2dd4bf",
|
||||||
|
"link": "#2dd4bf",
|
||||||
|
"sparkline": "#34d399",
|
||||||
|
"core": "#0a0c10",
|
||||||
|
"text": "#f4f7fb"
|
||||||
|
},
|
||||||
|
"border": "rgba(255,255,255,0.1)"
|
||||||
|
},
|
||||||
|
"typography": {
|
||||||
|
"fontFamily": "'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
|
||||||
|
"monoFamily": "'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace",
|
||||||
|
"baseSize": "14px",
|
||||||
|
"lineHeight": 1.5
|
||||||
|
},
|
||||||
|
"radius": {
|
||||||
|
"default": "14px",
|
||||||
|
"small": "10px",
|
||||||
|
"large": "18px"
|
||||||
|
},
|
||||||
|
"logoUsage": {
|
||||||
|
"minSize": "24px",
|
||||||
|
"clearSpace": "0.5x logo height",
|
||||||
|
"preferredBg": "dark #0a0c10 or pure white",
|
||||||
|
"source": "logo/peardata-icon-master.svg — flat P2P mesh + metrics sparkline"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/* PearData brand color tokens — matches ui/styles.css */
|
||||||
|
:root {
|
||||||
|
--pd-bg-primary: #0a0c10;
|
||||||
|
--pd-bg-secondary: #0f131a;
|
||||||
|
--pd-bg-tertiary: #151b24;
|
||||||
|
--pd-bg-elevated: #1a222e;
|
||||||
|
--pd-bg-hover: #232d3b;
|
||||||
|
|
||||||
|
--pd-accent-primary: #34d399;
|
||||||
|
--pd-accent-secondary: #2dd4bf;
|
||||||
|
--pd-accent-success: #4ade80;
|
||||||
|
--pd-accent-warning: #fbbf24;
|
||||||
|
--pd-accent-danger: #f87171;
|
||||||
|
--pd-accent-info: #38bdf8;
|
||||||
|
|
||||||
|
--pd-text-primary: #f4f7fb;
|
||||||
|
--pd-text-secondary: #c8d1df;
|
||||||
|
--pd-text-muted: #9aa8bc;
|
||||||
|
--pd-text-faint: #7d8b9f;
|
||||||
|
|
||||||
|
--pd-border: rgba(255, 255, 255, 0.1);
|
||||||
|
|
||||||
|
--pd-logo-peer: #34d399;
|
||||||
|
--pd-logo-peer-secondary: #2dd4bf;
|
||||||
|
--pd-logo-link: #2dd4bf;
|
||||||
|
--pd-logo-sparkline: #34d399;
|
||||||
|
--pd-logo-core: #0a0c10;
|
||||||
|
|
||||||
|
--pd-radius: 14px;
|
||||||
|
--pd-radius-sm: 10px;
|
||||||
|
--pd-radius-lg: 18px;
|
||||||
|
--pd-theme-color: #34d399;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<browserconfig>
|
||||||
|
<msapplication>
|
||||||
|
<tile>
|
||||||
|
<square150x150logo src="mstile-150x150.png"/>
|
||||||
|
<TileColor>#0a0c10</TileColor>
|
||||||
|
</tile>
|
||||||
|
</msapplication>
|
||||||
|
</browserconfig>
|
||||||
|
After Width: | Height: | Size: 477 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "PearData",
|
||||||
|
"short_name": "PearData",
|
||||||
|
"description": "Decentralized P2P real-time monitoring — fleet observability on Holepunch",
|
||||||
|
"start_url": "/",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#0a0c10",
|
||||||
|
"theme_color": "#34d399",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "android-chrome-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "android-chrome-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "apple-touch-icon.png",
|
||||||
|
"sizes": "180x180",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 477 B |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 88 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 64" width="320" height="64" role="img" aria-label="PearData">
|
||||||
|
<text x="0" y="46" font-family="Outfit, Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-weight="700" font-size="44" fill="#0f172a" letter-spacing="-0.03em">PearData</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 362 B |
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 64" width="320" height="64" role="img" aria-label="PearData">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
||||||
|
<stop offset="0%" stop-color="#34d399"/>
|
||||||
|
<stop offset="100%" stop-color="#2dd4bf"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<text x="0" y="46" font-family="Outfit, Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-weight="700" font-size="44" fill="url(#g)" letter-spacing="-0.03em">PearData</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 555 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 64" width="320" height="64" role="img" aria-label="PearData">
|
||||||
|
<text x="0" y="46" font-family="Outfit, Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-weight="700" font-size="44" fill="#f4f7fb" letter-spacing="-0.03em">PearData</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 362 B |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 361 KiB |
|
After Width: | Height: | Size: 56 KiB |
@@ -0,0 +1,42 @@
|
|||||||
|
# PearData branding
|
||||||
|
|
||||||
|
Master brand package: **`peardata-branding/`** (source of truth).
|
||||||
|
Runtime copies used by the desktop app and Electron packager:
|
||||||
|
|
||||||
|
| Path | Role |
|
||||||
|
|------|------|
|
||||||
|
| `build/icon.png` / `icon.icns` / `icon.ico` | Electron Forge packager + window icon |
|
||||||
|
| `assets/logo/` | Titlebar mark, README, UI |
|
||||||
|
| `assets/favicons/` | Browser / PWA icons + webmanifest |
|
||||||
|
| `assets/brand/` | `colors.css` + `brand-tokens.json` |
|
||||||
|
|
||||||
|
## Regenerate
|
||||||
|
|
||||||
|
Requires `sharp` + `png-to-ico` (not a production dependency — install when regenerating):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install --no-save sharp png-to-ico
|
||||||
|
npm run build:branding
|
||||||
|
```
|
||||||
|
|
||||||
|
Sync existing masters into `build/` + `assets/` without regenerating:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run sync:branding
|
||||||
|
```
|
||||||
|
|
||||||
|
## Wire-up
|
||||||
|
|
||||||
|
- **HTML** — favicons, theme-color, titlebar `<img src="assets/logo/peardata-icon-64.png">`
|
||||||
|
- **Electron** — `electron/main.cjs` → `resolveAppIcon()` reads `build/icon.*`
|
||||||
|
- **Forge** — `packagerConfig.icon = build/icon`; `prePackage` warns if missing; ignores `peardata-branding/`
|
||||||
|
- **make / CI** — client builds ensure icons; release workflows verify `build/icon.png` + favicons
|
||||||
|
- **install.sh** — Linux desktop entry picks packaged `icon.png`
|
||||||
|
|
||||||
|
## Brand mark
|
||||||
|
|
||||||
|
**Minimal flat design:** P2P mesh (three peer nodes linked) + metrics sparkline.
|
||||||
|
Master: `peardata-branding/logo/peardata-icon-master.svg` (raster ladder built from SVG).
|
||||||
|
Colors match `ui/styles.css` (`#0a0c10` bg, `#34d399` / `#2dd4bf` accents).
|
||||||
|
|
||||||
|
See `peardata-branding/README.md` for the full package map.
|
||||||
@@ -73,7 +73,12 @@ Pear provides a custom element **`<pear-ctrl>`** for platform window controls:
|
|||||||
<div id="titlebar" role="banner">
|
<div id="titlebar" role="banner">
|
||||||
<div class="titlebar-left">
|
<div class="titlebar-left">
|
||||||
<pear-ctrl></pear-ctrl>
|
<pear-ctrl></pear-ctrl>
|
||||||
<div class="app-brand">…</div>
|
<div class="app-brand">
|
||||||
|
<div class="app-brand-mark">
|
||||||
|
<img src="assets/logo/peardata-icon-64.png" alt="" width="22" height="22">
|
||||||
|
</div>
|
||||||
|
<div class="app-brand-text">PearData <span>P2P observability</span></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="titlebar-right">
|
<div class="titlebar-right">
|
||||||
<!-- status chips, non-drag interactive bits -->
|
<!-- status chips, non-drag interactive bits -->
|
||||||
|
|||||||
@@ -161,9 +161,19 @@ function buildPreloadPath() {
|
|||||||
|
|
||||||
function resolveAppIcon() {
|
function resolveAppIcon() {
|
||||||
const appRoot = app.isPackaged ? app.getAppPath() : path.resolve(__dirname, '..')
|
const appRoot = app.isPackaged ? app.getAppPath() : path.resolve(__dirname, '..')
|
||||||
|
const preferred =
|
||||||
|
process.platform === 'win32'
|
||||||
|
? 'icon.ico'
|
||||||
|
: process.platform === 'darwin'
|
||||||
|
? 'icon.icns'
|
||||||
|
: 'icon.png'
|
||||||
const candidates = [
|
const candidates = [
|
||||||
path.join(appRoot, 'build', process.platform === 'win32' ? 'icon.ico' : 'icon.png'),
|
path.join(appRoot, 'build', preferred),
|
||||||
path.join(appRoot, 'build', 'icon.png'),
|
path.join(appRoot, 'build', 'icon.png'),
|
||||||
|
path.join(appRoot, 'build', 'icon.ico'),
|
||||||
|
// Fallbacks when packaged under resources
|
||||||
|
path.join(appRoot, 'assets', 'logo', 'peardata-icon-512.png'),
|
||||||
|
path.join(appRoot, 'assets', 'logo', 'peardata-icon-256.png'),
|
||||||
]
|
]
|
||||||
for (const p of candidates) {
|
for (const p of candidates) {
|
||||||
if (fs.existsSync(p)) return p
|
if (fs.existsSync(p)) return p
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ const IGNORE_PREFIXES = [
|
|||||||
'/.cache',
|
'/.cache',
|
||||||
'/build/stubs',
|
'/build/stubs',
|
||||||
'/build/shims',
|
'/build/shims',
|
||||||
|
// Master brand package (runtime copies live in build/ + assets/)
|
||||||
|
'/peardata-branding',
|
||||||
'/README.md',
|
'/README.md',
|
||||||
'/LICENSE',
|
'/LICENSE',
|
||||||
// Packaging / Bare server toolchain (not needed at Electron runtime)
|
// Packaging / Bare server toolchain (not needed at Electron runtime)
|
||||||
@@ -465,6 +467,27 @@ module.exports = {
|
|||||||
`[forge] rebuild: ${skipRebuild ? 'skip (onlyModules:[])' : 'enabled'}`
|
`[forge] rebuild: ${skipRebuild ? 'skip (onlyModules:[])' : 'enabled'}`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Branding: packager uses build/icon.{png,icns,ico} when present
|
||||||
|
const iconPng = path.join(__dirname, 'build', 'icon.png')
|
||||||
|
if (!fs.existsSync(iconPng)) {
|
||||||
|
try {
|
||||||
|
require('child_process').execFileSync(
|
||||||
|
process.execPath,
|
||||||
|
[path.join(__dirname, 'scripts', 'build-branding.cjs'), '--sync-only'],
|
||||||
|
{ stdio: 'inherit', cwd: __dirname }
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('[forge] branding sync failed:', err?.message || err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fs.existsSync(iconPng)) {
|
||||||
|
console.log('[forge] app icon:', iconPng)
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
'[forge] missing build/icon.png — run: npm run build:branding (or npm run sync:branding)'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// QVAC Bare worker needs bare-runtime + platform binary in the app package.
|
// QVAC Bare worker needs bare-runtime + platform binary in the app package.
|
||||||
// On Linux CI, optional deps skip darwin/win32 — force-install the target host.
|
// On Linux CI, optional deps skip darwin/win32 — force-install the target host.
|
||||||
if (qvacEnabled) {
|
if (qvacEnabled) {
|
||||||
|
|||||||
@@ -4,6 +4,26 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>PearData — P2P Fleet Monitoring</title>
|
<title>PearData — P2P Fleet Monitoring</title>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Decentralized P2P real-time monitoring — fleet observability on the Holepunch stack"
|
||||||
|
/>
|
||||||
|
<meta name="theme-color" content="#0a0c10" />
|
||||||
|
<meta name="msapplication-TileColor" content="#0a0c10" />
|
||||||
|
<meta name="msapplication-config" content="assets/favicons/browserconfig.xml" />
|
||||||
|
<link rel="icon" href="assets/favicons/favicon.ico" sizes="any" />
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="assets/favicons/favicon-16x16.png" />
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="assets/favicons/favicon-32x32.png" />
|
||||||
|
<link rel="icon" type="image/png" sizes="48x48" href="assets/favicons/favicon-48x48.png" />
|
||||||
|
<link rel="apple-touch-icon" href="assets/favicons/apple-touch-icon.png" />
|
||||||
|
<link rel="manifest" href="assets/favicons/site.webmanifest" />
|
||||||
|
<meta property="og:title" content="PearData" />
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content="Decentralized P2P real-time monitoring for the Pear / Holepunch ecosystem"
|
||||||
|
/>
|
||||||
|
<meta property="og:image" content="peardata-branding/website/og-image.png" />
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
<link
|
<link
|
||||||
@@ -16,6 +36,12 @@
|
|||||||
var s = JSON.parse(raw)
|
var s = JSON.parse(raw)
|
||||||
var theme = s.theme || (s.settings && s.settings.theme)
|
var theme = s.theme || (s.settings && s.settings.theme)
|
||||||
if (theme) document.documentElement.dataset.theme = theme
|
if (theme) document.documentElement.dataset.theme = theme
|
||||||
|
if (theme === 'light') {
|
||||||
|
var meta = document.querySelector('meta[name="theme-color"]')
|
||||||
|
if (meta) meta.setAttribute('content', '#f3f5f8')
|
||||||
|
var tile = document.querySelector('meta[name="msapplication-TileColor"]')
|
||||||
|
if (tile) tile.setAttribute('content', '#f3f5f8')
|
||||||
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" href="./ui/styles.css" />
|
<link rel="stylesheet" href="./ui/styles.css" />
|
||||||
@@ -26,7 +52,15 @@
|
|||||||
<div class="titlebar-left">
|
<div class="titlebar-left">
|
||||||
<pear-ctrl></pear-ctrl>
|
<pear-ctrl></pear-ctrl>
|
||||||
<div class="app-brand" aria-hidden="true">
|
<div class="app-brand" aria-hidden="true">
|
||||||
<div class="app-brand-mark">◈</div>
|
<div class="app-brand-mark">
|
||||||
|
<img
|
||||||
|
src="assets/logo/peardata-icon-64.png"
|
||||||
|
alt=""
|
||||||
|
width="22"
|
||||||
|
height="22"
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div class="app-brand-text">
|
<div class="app-brand-text">
|
||||||
PearData <span>P2P observability</span>
|
PearData <span>P2P observability</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"gui": {
|
"gui": {
|
||||||
"main": "index.html",
|
"main": "index.html",
|
||||||
"backgroundColor": "#0a0c10",
|
"backgroundColor": "#0a0c10",
|
||||||
|
"icon": "build/icon.png",
|
||||||
"height": 860,
|
"height": 860,
|
||||||
"width": 1280,
|
"width": 1280,
|
||||||
"minWidth": 900,
|
"minWidth": 900,
|
||||||
@@ -55,6 +56,8 @@
|
|||||||
"release:notes": "node -e \"console.log('See docs/RELEASE.md')\"",
|
"release:notes": "node -e \"console.log('See docs/RELEASE.md')\"",
|
||||||
"build:client-bundle": "node scripts/build-client-bundle.cjs",
|
"build:client-bundle": "node scripts/build-client-bundle.cjs",
|
||||||
"build:qvac-worker": "node scripts/build-qvac-worker.cjs",
|
"build:qvac-worker": "node scripts/build-qvac-worker.cjs",
|
||||||
|
"build:branding": "node scripts/build-branding.cjs",
|
||||||
|
"sync:branding": "node scripts/build-branding.cjs --sync-only",
|
||||||
"ensure:qvac-bare-runtimes": "node scripts/ensure-qvac-bare-runtimes.cjs --all",
|
"ensure:qvac-bare-runtimes": "node scripts/ensure-qvac-bare-runtimes.cjs --all",
|
||||||
"start:client": "npm run build:client-bundle && electron electron/main.cjs",
|
"start:client": "npm run build:client-bundle && electron electron/main.cjs",
|
||||||
"package:client": "electron-forge package",
|
"package:client": "electron-forge package",
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# PearData Branding Package v1.0.0
|
||||||
|
|
||||||
|
Master brand assets for **PearData** — decentralized P2P real-time monitoring.
|
||||||
|
|
||||||
|
Source of truth: `logo/peardata-icon-master.svg` — **P2P peer triangle** + **metrics sparkline** (flat, no fruit motif).
|
||||||
|
Raster sizes are regenerated from the SVG (true alpha).
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
logo/ Master icon + size ladder + wordmarks + mono/dark/light
|
||||||
|
app-icons/ electron/ linux/ windows/ macos iconset + store icons
|
||||||
|
favicons/ ico + PWA sizes + webmanifest + browserconfig
|
||||||
|
website/ og-image, twitter-card, hero/banner assets
|
||||||
|
social/ avatars + banner
|
||||||
|
brand-assets/ colors.css + brand-tokens.json (matches ui/styles.css)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Color tokens
|
||||||
|
|
||||||
|
| Token | Hex | Role |
|
||||||
|
|-------|-----|------|
|
||||||
|
| `--bg-primary` | `#0a0c10` | Main bg |
|
||||||
|
| `--accent-primary` | `#34d399` | Emerald CTA / live |
|
||||||
|
| `--accent-secondary` | `#2dd4bf` | Teal secondary |
|
||||||
|
| `--text-primary` | `#f4f7fb` | Body text |
|
||||||
|
|
||||||
|
See `brand-assets/colors.css` and `brand-assets/brand-tokens.json`.
|
||||||
|
|
||||||
|
## Drop-in usage
|
||||||
|
|
||||||
|
This package is the **source of truth**. Runtime copies:
|
||||||
|
|
||||||
|
| Destination | Contents |
|
||||||
|
|-------------|----------|
|
||||||
|
| `../build/icon.{png,icns,ico}` | Electron Forge / packager icons |
|
||||||
|
| `../assets/logo/` | Titlebar + README logos |
|
||||||
|
| `../assets/favicons/` | Favicons + webmanifest |
|
||||||
|
| `../assets/brand/` | colors.css + brand-tokens.json |
|
||||||
|
|
||||||
|
Regenerate + sync:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build:branding
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link rel="icon" href="assets/favicons/favicon.ico" sizes="any">
|
||||||
|
<link rel="apple-touch-icon" href="assets/favicons/apple-touch-icon.png">
|
||||||
|
<link rel="manifest" href="assets/favicons/site.webmanifest">
|
||||||
|
<meta name="theme-color" content="#34d399">
|
||||||
|
```
|
||||||
|
|
||||||
|
Electron Forge:
|
||||||
|
|
||||||
|
```js
|
||||||
|
icon: path.join(__dirname, 'build', 'icon')
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quality
|
||||||
|
|
||||||
|
- Masters use soft alpha keyed from near-black backgrounds (LANCZOS resize)
|
||||||
|
- Prefer `logo/peardata-icon-master.svg` as the only resize source
|
||||||
|
- Wordmarks are SVG (crisp at any size)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
© 2026 snxraven · AGPL-3.0
|
||||||
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 477 B |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 477 B |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 477 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 361 KiB |
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"name": "PearData",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Decentralized P2P real-time monitoring and fleet observability",
|
||||||
|
"colors": {
|
||||||
|
"background": {
|
||||||
|
"primary": "#0a0c10",
|
||||||
|
"secondary": "#0f131a",
|
||||||
|
"tertiary": "#151b24",
|
||||||
|
"elevated": "#1a222e",
|
||||||
|
"hover": "#232d3b"
|
||||||
|
},
|
||||||
|
"accent": {
|
||||||
|
"primary": "#34d399",
|
||||||
|
"secondary": "#2dd4bf",
|
||||||
|
"success": "#4ade80",
|
||||||
|
"warning": "#fbbf24",
|
||||||
|
"danger": "#f87171",
|
||||||
|
"info": "#38bdf8"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"primary": "#f4f7fb",
|
||||||
|
"secondary": "#c8d1df",
|
||||||
|
"muted": "#9aa8bc",
|
||||||
|
"faint": "#7d8b9f"
|
||||||
|
},
|
||||||
|
"logo": {
|
||||||
|
"peer": "#34d399",
|
||||||
|
"peerSecondary": "#2dd4bf",
|
||||||
|
"link": "#2dd4bf",
|
||||||
|
"sparkline": "#34d399",
|
||||||
|
"core": "#0a0c10",
|
||||||
|
"text": "#f4f7fb"
|
||||||
|
},
|
||||||
|
"border": "rgba(255,255,255,0.1)"
|
||||||
|
},
|
||||||
|
"typography": {
|
||||||
|
"fontFamily": "'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
|
||||||
|
"monoFamily": "'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace",
|
||||||
|
"baseSize": "14px",
|
||||||
|
"lineHeight": 1.5
|
||||||
|
},
|
||||||
|
"radius": {
|
||||||
|
"default": "14px",
|
||||||
|
"small": "10px",
|
||||||
|
"large": "18px"
|
||||||
|
},
|
||||||
|
"logoUsage": {
|
||||||
|
"minSize": "24px",
|
||||||
|
"clearSpace": "0.5x logo height",
|
||||||
|
"preferredBg": "dark #0a0c10 or pure white",
|
||||||
|
"source": "logo/peardata-icon-master.svg — flat P2P mesh + metrics sparkline"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/* PearData brand color tokens — matches ui/styles.css */
|
||||||
|
:root {
|
||||||
|
--pd-bg-primary: #0a0c10;
|
||||||
|
--pd-bg-secondary: #0f131a;
|
||||||
|
--pd-bg-tertiary: #151b24;
|
||||||
|
--pd-bg-elevated: #1a222e;
|
||||||
|
--pd-bg-hover: #232d3b;
|
||||||
|
|
||||||
|
--pd-accent-primary: #34d399;
|
||||||
|
--pd-accent-secondary: #2dd4bf;
|
||||||
|
--pd-accent-success: #4ade80;
|
||||||
|
--pd-accent-warning: #fbbf24;
|
||||||
|
--pd-accent-danger: #f87171;
|
||||||
|
--pd-accent-info: #38bdf8;
|
||||||
|
|
||||||
|
--pd-text-primary: #f4f7fb;
|
||||||
|
--pd-text-secondary: #c8d1df;
|
||||||
|
--pd-text-muted: #9aa8bc;
|
||||||
|
--pd-text-faint: #7d8b9f;
|
||||||
|
|
||||||
|
--pd-border: rgba(255, 255, 255, 0.1);
|
||||||
|
|
||||||
|
--pd-logo-peer: #34d399;
|
||||||
|
--pd-logo-peer-secondary: #2dd4bf;
|
||||||
|
--pd-logo-link: #2dd4bf;
|
||||||
|
--pd-logo-sparkline: #34d399;
|
||||||
|
--pd-logo-core: #0a0c10;
|
||||||
|
|
||||||
|
--pd-radius: 14px;
|
||||||
|
--pd-radius-sm: 10px;
|
||||||
|
--pd-radius-lg: 18px;
|
||||||
|
--pd-theme-color: #34d399;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<browserconfig>
|
||||||
|
<msapplication>
|
||||||
|
<tile>
|
||||||
|
<square150x150logo src="mstile-150x150.png"/>
|
||||||
|
<TileColor>#0a0c10</TileColor>
|
||||||
|
</tile>
|
||||||
|
</msapplication>
|
||||||
|
</browserconfig>
|
||||||
|
After Width: | Height: | Size: 477 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "PearData",
|
||||||
|
"short_name": "PearData",
|
||||||
|
"description": "Decentralized P2P real-time monitoring — fleet observability on Holepunch",
|
||||||
|
"start_url": "/",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#0a0c10",
|
||||||
|
"theme_color": "#34d399",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "android-chrome-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "android-chrome-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "apple-touch-icon.png",
|
||||||
|
"sizes": "180x180",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 477 B |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 88 KiB |
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
PearData — professional flat mark.
|
||||||
|
Hub + three peers (P2P). Metric columns only inside the hub (data).
|
||||||
|
Solid geometry, no crossing decorative lines.
|
||||||
|
-->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512" role="img" aria-label="PearData">
|
||||||
|
<!-- Links: hub → peers only (star topology reads as P2P fabric when combined with outer ring) -->
|
||||||
|
<g fill="none" stroke="#2DD4BF" stroke-width="20" stroke-linecap="round">
|
||||||
|
<line x1="256" y1="248" x2="256" y2="128"/>
|
||||||
|
<line x1="256" y1="268" x2="148" y2="372"/>
|
||||||
|
<line x1="256" y1="268" x2="364" y2="372"/>
|
||||||
|
</g>
|
||||||
|
<!-- Outer peer ring (fleet mesh) -->
|
||||||
|
<g fill="none" stroke="#14B8A6" stroke-width="16" stroke-linecap="round" opacity="0.75">
|
||||||
|
<line x1="256" y1="112" x2="140" y2="380"/>
|
||||||
|
<line x1="256" y1="112" x2="372" y2="380"/>
|
||||||
|
<line x1="140" y1="380" x2="372" y2="380"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Peers — solid, no hollow cores -->
|
||||||
|
<circle cx="256" cy="112" r="44" fill="#34D399"/>
|
||||||
|
<circle cx="140" cy="380" r="44" fill="#2DD4BF"/>
|
||||||
|
<circle cx="372" cy="380" r="44" fill="#2DD4BF"/>
|
||||||
|
|
||||||
|
<!-- Hub plate -->
|
||||||
|
<circle cx="256" cy="258" r="72" fill="#0F131A" stroke="#34D399" stroke-width="18"/>
|
||||||
|
<!-- Metric columns (data) — contained, not overlapping links -->
|
||||||
|
<g fill="#34D399">
|
||||||
|
<rect x="222" y="250" width="16" height="40" rx="4"/>
|
||||||
|
<rect x="248" y="230" width="16" height="60" rx="4"/>
|
||||||
|
<rect x="274" y="242" width="16" height="48" rx="4"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 53 KiB |