feat: rebrand to website design, Apple HIG icons, ASCII onboarding animation
Build & Release / Lint & Typecheck (push) Successful in 38s
Build & Release / Unit Tests (push) Successful in 31s
Build & Release / Windows (arm64) (push) Failing after 11s
Build & Release / Windows (x64) (push) Failing after 27s
Build & Release / Linux (arm64) (push) Canceled after 0s
Build & Release / Linux (x64) (push) Canceled after 0s
Build & Release / Publish Release (push) Canceled after 0s
Build & Release / macOS (arm64) (push) Canceled after 0s
Build & Release / macOS (x64) (push) Canceled after 0s

- Align Electron CSS with website design schema (Inter font, #FBFAF5/#191919
  palette, #213448/#94B4C1 accent)
- Generate proper app icons from logo.svg via cairosvg (no more Pillow ladder)
- Square bg icons for Electron/tray (Apple HIG — OS applies squircle mask)
- Circle bg icons for website favicon only
- Add scrolling ASCII agent-activity animation to onboarding hero left panel
- Remove dock.setIcon() — let macOS use bundle .icns with system mask
- Fix goal title overflow with min-w-0 for flex truncation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 4.6 committed 2026-03-24 16:39:28 -04:00
1 parent 273244817a
commit eda0e26adb
18 files changed
+337 -237

No files matched your search

@@ -0,0 +1,85 @@
import { memo } from "react";
/**
* Scrolling ASCII agent-activity backdrop for the onboarding hero panel.
* Pure CSS animation (translateY on compositor thread) — no JS ticks.
* Content is doubled for seamless looping.
*/
const LINES = [
"",
" ╭──────────╮",
" │ CEO │",
" ╰────┬─────╯",
" ┌────┴─────┐",
" ╭──┴──╮ ╭──┴──╮",
" │ CTO │ │ CMO │",
" ╰──┬──╯ ╰──┬──╯",
" ╭──┴──╮ ╭──┴──╮",
" │ Eng │ │ Mkt │",
" ╰─────╯ ╰─────╯",
"",
" $ deploy --agents 12",
" ████████████████████ 100%",
" [OK] all agents online",
"",
" CEO │ analyzing requirements",
" CEO │ identifying deliverables",
" CEO │ delegating to leads",
"",
" CTO │ reviewing architecture",
" CTO │ → Dev.01: auth module",
" CTO │ → Dev.02: API layer",
" CTO │ → QA: test strategy",
"",
" CMO │ go-to-market strategy",
" CMO │ → Mkt.01: launch copy",
" CMO │ → Mkt.02: social plan",
"",
" ┌─ SPRINT 1 ────────────────┐",
" │ tasks ████████░░ 80% │",
" │ agents 12 active │",
" │ tests 128 passing │",
" └──────────────────────────┘",
"",
" Dev.01 │ scaffolding auth",
" Dev.02 │ REST endpoints",
" Design │ component library",
" QA │ integration tests",
" Mkt.01 │ blog post drafted",
"",
" CEO │ sprint review: ✓",
" CTO │ code review: merged",
" Dev.01 │ PR #12 → main",
" QA │ all tests green",
" CMO │ brief approved",
"",
" [INFO] Sprint 1 complete",
" [INFO] Advancing to Sprint 2",
"",
];
const BLOCK = LINES.join("\n");
export const AsciiAnimation = memo(function AsciiAnimation() {
return (
<div className="pointer-events-none absolute inset-0 select-none overflow-hidden">
{/* Fade masks */}
<div
className="absolute inset-x-0 top-0 z-10 h-32"
style={{ background: "linear-gradient(to bottom, var(--bg), transparent)" }}
/>
<div
className="absolute inset-x-0 bottom-0 z-10 h-32"
style={{ background: "linear-gradient(to top, var(--bg), transparent)" }}
/>
{/* Scrolling track — doubled for seamless loop */}
<div className="ascii-scroll-track whitespace-pre font-mono text-[11px] leading-[1.8] text-[color:var(--accent)] opacity-[0.08]">
{BLOCK}
{"\n"}
{BLOCK}
</div>
</div>
);
});
@@ -8,6 +8,7 @@ import {
import type { ProfileSnapshot } from "@shared/types";
import type { AppLocale } from "@shared/locale";
import { ConnectorReadiness } from "./ConnectorReadiness";
import { AsciiAnimation } from "./AsciiAnimation";
type Step = "language" | "company" | "mission" | "launch";
@@ -57,6 +58,9 @@ export function OnboardingHero({
}}
/>
{/* ASCII agent activity backdrop */}
<AsciiAnimation />
<motion.div
initial={{ opacity: 0, y: 24 }}
animate={{ opacity: 1, y: 0 }}
@@ -22,12 +22,12 @@ export function GoalProgress({ goals, tasks, onNavigate }: { goals: GoalRecord[]
onClick={() => onNavigate("goals")}
className="focus-ring w-full rounded-[8px] border border-[color:var(--line)] bg-[color:var(--panel)] px-4 py-3.5 text-left transition hover:border-[color:var(--line-strong)] hover:shadow-sm"
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Target size={15} weight="fill" className="text-[color:var(--accent)]" />
<div className="flex items-center justify-between gap-3">
<div className="flex min-w-0 items-center gap-2">
<Target size={15} weight="fill" className="shrink-0 text-[color:var(--accent)]" />
<span className="truncate text-[13px] font-medium text-[color:var(--text)]">{goal.title}</span>
</div>
<span className="whitespace-nowrap text-[13px] font-bold tabular-nums text-[color:var(--accent)]">{pct}%</span>
<span className="shrink-0 whitespace-nowrap text-[13px] font-bold tabular-nums text-[color:var(--accent)]">{pct}%</span>
</div>
<div className="mt-2.5 h-2 w-full overflow-hidden rounded-full bg-[color:var(--panel-soft)]">
<div
@@ -32,10 +32,10 @@ export function GoalList({
onClick={() => onSelect(goal.id)}
className={`cursor-pointer transition-colors duration-100 ${isSelected ? "bg-[color:var(--accent-soft)]" : "hover:bg-[color:var(--panel-soft)]"}`}
>
<div className="mb-2 flex items-center justify-between">
<div className="flex items-center gap-2">
<div className="mb-2 flex items-center justify-between gap-3">
<div className="flex min-w-0 items-center gap-2">
{isSelected && (
<CheckCircle size={16} weight="fill" className="text-[color:var(--accent)]" />
<CheckCircle size={16} weight="fill" className="shrink-0 text-[color:var(--accent)]" />
)}
<div className="truncate text-[14px] font-semibold text-[color:var(--text)]">{goal.title}</div>
</div>
+2
View File
@@ -1,4 +1,6 @@
import "@fontsource-variable/inter";
import "@fontsource-variable/jetbrains-mono";
import "@fontsource/instrument-serif";
import "./styles.css";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
+66 -53
View File
@@ -1,30 +1,32 @@
@import "tailwindcss";
@theme {
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Microsoft YaHei", "PingFang SC", "Hiragino Sans GB",
--font-sans: "Inter Variable", -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB",
"Noto Sans CJK SC", Helvetica, Arial, sans-serif;
--font-serif: "Instrument Serif", Georgia, "Times New Roman", serif;
--font-mono: "JetBrains Mono Variable", "Microsoft YaHei", ui-monospace,
SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
/* ─── Light theme — aligned with website ─── */
:root {
color-scheme: light;
--bg: #f7f8fa;
--bg-subtle: #ffffff;
--panel: #ffffff;
--panel-soft: #f0f2f5;
--panel-strong: #f7f8fa;
--line: rgba(50, 65, 85, 0.08);
--line-strong: rgba(50, 65, 85, 0.15);
--text: #1a1d24;
--muted: #6b7280;
--muted-strong: #4b5563;
--accent: #4a5d7a;
--accent-text: #3d5070;
--accent-soft: #edf1f7;
--accent-hover: #3d4f6d;
--text-on-accent: #ffffff;
--bg: #FBFAF5;
--bg-subtle: #FFFFFF;
--panel: #FFFFFF;
--panel-soft: #F3F2ED;
--panel-strong: #FBFAF5;
--line: rgba(25, 25, 25, 0.08);
--line-strong: rgba(25, 25, 25, 0.15);
--text: #191919;
--muted: #7a7a72;
--muted-strong: #565650;
--accent: #213448;
--accent-text: #213448;
--accent-soft: rgba(33, 52, 72, 0.07);
--accent-hover: #192838;
--text-on-accent: #FBFAF5;
--danger: #c53030;
--danger-soft: #fef2f2;
--warn: #b45309;
@@ -37,23 +39,24 @@
color-scheme: light;
}
/* ─── Dark theme — aligned with website ─── */
:root[data-theme="dark"] {
color-scheme: dark;
--bg: #16181f;
--bg-subtle: #1a1c24;
--panel: #1e2028;
--panel-soft: #24262e;
--panel-strong: #1c1e26;
--line: rgba(148, 163, 190, 0.12);
--line-strong: rgba(148, 163, 190, 0.2);
--text: #edf0f7;
--muted: #8b95a5;
--muted-strong: #b0b8c8;
--accent: #7b9cc4;
--accent-text: #7b9cc4;
--accent-soft: rgba(123, 156, 196, 0.14);
--accent-hover: #93b0d4;
--text-on-accent: #ffffff;
--bg: #191919;
--bg-subtle: #1e1e1e;
--panel: #222222;
--panel-soft: #2a2a2a;
--panel-strong: #1c1c1c;
--line: rgba(251, 250, 245, 0.08);
--line-strong: rgba(251, 250, 245, 0.15);
--text: #FBFAF5;
--muted: #8a8a84;
--muted-strong: #b8b8b2;
--accent: #94B4C1;
--accent-text: #94B4C1;
--accent-soft: rgba(148, 180, 193, 0.12);
--accent-hover: #a8c4cf;
--text-on-accent: #191919;
--danger: #f87171;
--danger-soft: rgba(248, 113, 113, 0.12);
--warn: #f59e0b;
@@ -65,21 +68,21 @@
@media (prefers-color-scheme: dark) {
:root[data-theme="system"] {
color-scheme: dark;
--bg: #16181f;
--bg-subtle: #1a1c24;
--panel: #1e2028;
--panel-soft: #24262e;
--panel-strong: #1c1e26;
--line: rgba(148, 163, 190, 0.12);
--line-strong: rgba(148, 163, 190, 0.2);
--text: #edf0f7;
--muted: #8b95a5;
--muted-strong: #b0b8c8;
--accent: #7b9cc4;
--accent-text: #7b9cc4;
--accent-soft: rgba(123, 156, 196, 0.14);
--accent-hover: #93b0d4;
--text-on-accent: #ffffff;
--bg: #191919;
--bg-subtle: #1e1e1e;
--panel: #222222;
--panel-soft: #2a2a2a;
--panel-strong: #1c1c1c;
--line: rgba(251, 250, 245, 0.08);
--line-strong: rgba(251, 250, 245, 0.15);
--text: #FBFAF5;
--muted: #8a8a84;
--muted-strong: #b8b8b2;
--accent: #94B4C1;
--accent-text: #94B4C1;
--accent-soft: rgba(148, 180, 193, 0.12);
--accent-hover: #a8c4cf;
--text-on-accent: #191919;
--danger: #f87171;
--danger-soft: rgba(248, 113, 113, 0.12);
--warn: #f59e0b;
@@ -133,11 +136,11 @@ select {
::-webkit-scrollbar-thumb {
border-radius: 999px;
background: rgba(60, 75, 100, 0.2);
background: rgba(25, 25, 25, 0.15);
}
::-webkit-scrollbar-thumb:hover {
background: rgba(60, 75, 100, 0.32);
background: rgba(25, 25, 25, 0.25);
}
.mono {
@@ -147,7 +150,7 @@ select {
.surface {
background: var(--panel);
border: 1px solid var(--line);
box-shadow: 0 1px 3px rgba(26, 29, 36, 0.06), 0 0 0 0.5px rgba(26, 29, 36, 0.03);
box-shadow: 0 1px 3px rgba(25, 25, 25, 0.06), 0 0 0 0.5px rgba(25, 25, 25, 0.03);
}
.focus-ring {
@@ -160,9 +163,19 @@ select {
.focus-ring:focus-visible {
box-shadow:
0 0 0 1px rgba(74, 93, 122, 0.5),
0 0 0 4px rgba(74, 93, 122, 0.12);
border-color: rgba(74, 93, 122, 0.35);
0 0 0 1px rgba(33, 52, 72, 0.5),
0 0 0 4px rgba(33, 52, 72, 0.12);
border-color: rgba(33, 52, 72, 0.35);
}
/* ─── ASCII animation ─── */
@keyframes ascii-scroll-up {
0% { transform: translateY(0); }
100% { transform: translateY(-50%); }
}
.ascii-scroll-track {
animation: ascii-scroll-up 80s linear infinite;
}
@media (prefers-reduced-motion: reduce) {