diff --git a/README.md b/README.md index f9126cf..0121891 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ **A desktop workbench for the Pi coding agent.** **Workspace-first, not chat-first.** -[Quick Start](#quick-start) · [Architecture](docs/pidex-architecture.md) · [Design tokens](#design-tokens) · [Docs](docs/pidex-project-brief.md) +[Quick Start](#quick-start) · [Architecture](docs/pidex-architecture.md) [![CI](https://github.com/echohello-dev/pidex/actions/workflows/ci.yml/badge.svg)](https://github.com/echohello-dev/pidex/actions/workflows/ci.yml) [![Electron 41](https://img.shields.io/badge/electron-41-blue)](https://www.electronjs.org/) @@ -67,53 +67,16 @@ Pi runs out-of-process over RPC so the UI survives a runtime crash. Pretext hand | Package manager | Bun | | Toolchain | mise, all commands via `mise run` | -## Design tokens - -The workbench inherits its palette from the [Pi coding agent](https://pi.dev) so it feels like part of the same family as the runtime. Source of truth: [`scripts/_design.py`](scripts/_design.py), hexes pulled from `pi.dev/style.css`. - -| Token | Hex | Role | -|---|---|---| -| bg-deep | `#0d1116` | Window background | -| bg-canvas | `#161d27` | Canvas surface | -| panel | `#212730` | Sidebar / panel | -| panel-soft | `#252f3d` | Card surface | -| parchment | `#dacbc2` | Named cream, primary mark and text | -| moonstone | `#ebe7e4` | Lighter cream | -| driftwood | `#5c5752` | Warm mid-gray | -| terracotta | `#844f3b` | Warm bronze accent | -| terracotta-light | `#b86b52` | Status dots | -| sunkissed | `#e1b06e` | Warm gold | -| sage | `#a3a473` | Sage accent | -| accent-blue | `#6a9fcc` | Links, focus | - -Regenerate assets after a token edit: - -```bash -uv run --with fonttools python scripts/build-icon.py # assets/icon, mark -uv run --with fonttools python scripts/build-logo.py # assets/logo (composable π + pidex) -uv run --with fonttools python scripts/build-banner.py # docs/assets/banner-bg -``` - -`docs/assets/screenshot.png` is captured from the running app. To refresh: temporarily gate a `webContents.capturePage()` call behind an env var, run `PIDEX_CAPTURE=1 mise run dev`, then revert. The banner composites the screenshot over the design-system background (`docs/assets/banner-bg.png`, built by `scripts/build-banner.py`) with the composable logo watermark, all via `magick`. - -The banner background is procedural: `bg-canvas` field with the blueprint grid (96px minor + 480px major, lifted in opacity for hero scale) and a vertical gradient into `bg-deep`. Strictly rectilinear; no generated imagery. - -Banner and logo use the design system font pairing: **Georgia** (serif, from `--serif` in `tokens.css`) for the wordmark and body, **Commit Mono** (from `--mono`) for the code surfaces visible in the screenshot. - -## What's next - -- [ ] Diff viewer with virtualised summaries -- [ ] Session fork, branch sessions visually -- [ ] Worktree switching from the UI - -## Documentation +## License -| Doc | What it covers | -|---|---| -| [docs/pidex-project-brief.md](docs/pidex-project-brief.md) | Thesis, pain points, positioning, MVP slice | -| [docs/pidex-architecture.md](docs/pidex-architecture.md) | Process boundaries, IPC schema, SDK vs RPC | -| [docs/pidex-pretext-deep-dive.md](docs/pidex-pretext-deep-dive.md) | Why DOM-free text measurement | +[Apache-2.0](./LICENSE): see the file for full text. Personal project, shared in the open. -## License +## Star History -[MIT](./LICENSE) — see the file for full text. Personal project, shared in the open. \ No newline at end of file + + + + + Star History Chart + + diff --git a/assets/logo.png b/assets/logo.png index cd49968..dda71d7 100644 Binary files a/assets/logo.png and b/assets/logo.png differ diff --git a/docs/assets/banner-bg.png b/docs/assets/banner-bg.png deleted file mode 100644 index 951b364..0000000 Binary files a/docs/assets/banner-bg.png and /dev/null differ diff --git a/docs/assets/banner-bg.svg b/docs/assets/banner-bg.svg index 20eb204..676588a 100644 --- a/docs/assets/banner-bg.svg +++ b/docs/assets/banner-bg.svg @@ -1,24 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/docs/assets/banner.png b/docs/assets/banner.png index 8592c8b..8c681f5 100644 Binary files a/docs/assets/banner.png and b/docs/assets/banner.png differ diff --git a/docs/assets/framed-window.svg b/docs/assets/framed-window.svg deleted file mode 100644 index 886a5a8..0000000 --- a/docs/assets/framed-window.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/assets/screenshot.png b/docs/assets/screenshot.png deleted file mode 100644 index b6519b5..0000000 Binary files a/docs/assets/screenshot.png and /dev/null differ diff --git a/scripts/build-banner.py b/scripts/build-banner.py index 60fee2a..f2e1d95 100644 --- a/scripts/build-banner.py +++ b/scripts/build-banner.py @@ -1,85 +1,146 @@ -"""Build the README banner background using the pidex design system. - -The background mirrors the app's own chrome (tokens.css base.css body -background): bg-canvas field with the blueprint grid (96px minor + -480px major, blue-tinted) and a vertical gradient into bg-deep. Shapes -are strictly rectilinear; no organic imagery. The real app screenshot -and the composable logo are laid on top of this background. - -Output: - docs/assets/banner-bg.png (1600x900) - -Compose the final banner with: - magick docs/assets/banner-bg.png \\ - docs/assets/screenshot.png -resize 1000x -geometry +300+80 -composite \\ - assets/logo.png -resize 200x -geometry +70+70 -composite \\ - docs/assets/banner.png +#!/usr/bin/env python +"""Build the README banner: the pidex logo (isometric cube with the +Pi coding agent logo on its top face + wordmark) centered on the +design-system background (bg-canvas with the blueprint grid + vertical +gradient into bg-deep). + +Outputs: + docs/assets/banner.png (1600x600) + assets/logo.png (regenerated as part of the build) + docs/assets/banner-bg.svg (the background SVG, tracked) """ from __future__ import annotations import shutil import subprocess -import sys from pathlib import Path REPO = Path(__file__).resolve().parent.parent -OUT = REPO / "docs" / "assets" - -sys.path.insert(0, str(Path(__file__).resolve().parent)) -from _design import BG_DEEP, BG_CANVAS # noqa: E402 - -W, H = 1600, 900 - - -def svg() -> str: - # Blueprint grid matches tokens.css (96px minor + 480px major, blue - # tint). At hero scale the token opacities would be invisible, so - # they're lifted slightly while keeping the same hue. - return f""" - - - - - - - - - - - - - - - - - - - - - - - -""" +DOCS = REPO / "docs" / "assets" +ASSETS = REPO / "assets" + +BANNER_W, BANNER_H = 1600, 600 + +INK_BRONZE = "#13110f" +PARCHMENT = "#dacbc2" + + +def pi_path(font_path): + from fontTools.ttLib import TTFont + from fontTools.pens.svgPathPen import SVGPathPen + + font = TTFont(font_path) + cmap = font.getBestCmap() + gname = cmap[ord("π")] + pen = SVGPathPen(font.getGlyphSet()) + font.getGlyphSet()[gname].draw(pen) + glyf = font["glyf"][gname] + bbox = (glyf.xMin, glyf.yMin, glyf.xMax, glyf.yMax) + return pen.getCommands(), bbox, font["head"].unitsPerEm + + +def build_logo_svg(width, height): + d, bbox, _ = pi_path("/System/Library/Fonts/Supplemental/Georgia Italic.ttf") + gx = (bbox[0] + bbox[2]) / 2 + gy = (bbox[1] + bbox[3]) / 2 + e = 200 + dx = e * 0.866 + dy = e * 0.5 + cx, cy = width / 2 - 60, height / 2 + top = (cx, cy - dy) + right = (cx + dx, cy) + bot = (cx, cy + dy) + left = (cx - dx, cy) + a = dx / 470.0 + b = dy / 470.0 + # Scale the Pi logo to 65% of the top face so it fits with padding + pad_scale = 0.65 + a *= pad_scale + b *= pad_scale + transform = f"matrix({a} {b} {-a} {b} {cx} {cy - dy})" + p_d = ( + "M165.29 165.29 H517.36 V400 H400 V517.36 H282.65 V634.72 H165.29 Z " + "M282.65 282.65 V400 H400 V282.65 Z" + ) + i_dot_d = "M517.36 400 H634.72 V634.72 H517.36 Z" + word_x = right[0] + 60 + word_y = cy + 20 + word_size = int(height * 0.22) + parts = [] + parts.append( + f'' + ) + parts.append( + f'' + ) + parts.append( + f'' + ) + parts.append(f'') + parts.append(f'') + parts.append(f'') + parts.append("") + parts.append( + f'pidex' + ) + inner = "".join(parts) + return ( + f'{inner}' + ) -def render_png(svg: Path, png: Path, width: int) -> None: +def build_bg_svg(): + return ( + f'' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + f'' + f'' + f'' + f'' + '' + ) + + +def render(svg, out, width): if not shutil.which("inkscape"): - sys.exit("inkscape not found on PATH; install via brew install inkscape") + raise SystemExit("inkscape not found on PATH") + tmp = out.with_suffix(".tmp.svg") + tmp.write_text(svg) subprocess.run( - ["inkscape", str(svg), "--export-type=png", "--export-filename", str(png), "--export-width", str(width)], + ["inkscape", str(tmp), "--export-type=png", "--export-filename", str(out), "--export-width", str(width)], check=True, ) + tmp.unlink() + + +def main(): + bg_svg = build_bg_svg() + (DOCS / "banner-bg.svg").write_text(bg_svg) + bg_png = DOCS / "banner-bg.png" + render(bg_svg, bg_png, BANNER_W) + logo_svg = build_logo_svg(BANNER_W, BANNER_H) + logo_png = ASSETS / "logo.png" + render(logo_svg, logo_png, BANNER_W) -def main() -> None: - OUT.mkdir(parents=True, exist_ok=True) - svg_path = OUT / "banner-bg.svg" - png_path = OUT / "banner-bg.png" - svg_path.write_text(svg()) - render_png(svg_path, png_path, W) - print(f"wrote {svg_path}") - print(f"wrote {png_path}") + subprocess.run( + ["magick", str(bg_png), str(logo_png), "-composite", str(DOCS / "banner.png")], + check=True, + ) + bg_png.unlink() + print(f"wrote {DOCS / 'banner.png'}") if __name__ == "__main__":