Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changeset/loud-donkeys-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@sketchi/cli": patch
---

Paint a legible pencil mark on root help and stop dropping colour on terminals that omit `COLORFGBG`. The lockup is a half-block pixel icon and `sketchi` wordmark; root help collapses to `START HERE` and `WORK WITH A DIAGRAM`. Pipes, `NO_COLOR`, JSON and non-UTF-8 locales still render plain text with no block art.
23 changes: 4 additions & 19 deletions apps/cli/src/__fixtures__/help/root.txt
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
╱██╲
╱████╲
╱████╱
╱████╱
╱████╱
╱___╱

sketchi
describe it. sketchi draws it.
sketchi
describe it. sketchi draws it.

START HERE
generate Start the short wizard, or pass --prompt for direct generation.

EXAMPLE
sketchi generate interactive
sketchi generate --prompt "Map release approval with pass and revise branches"
Writes <generated-id>.png in this directory. No account or API key needed.

Expand All @@ -22,9 +12,4 @@ WORK WITH A DIAGRAM
export Write PNG, Excalidraw, or scene bytes.
share Create an encrypted Excalidraw link.

GO DEEPER
sketchi docs Complete command map and automation contracts.
sketchi generate --help Every generation option.
sketchi <command> --help Targeted help for any command.

Automation: pass --prompt and add --output json. Version: sketchi --version
sketchi docs for every command. Add --output json for automation.
77 changes: 64 additions & 13 deletions apps/cli/src/help-brand.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { describe, expect, it } from "@effect/vitest";
import stringWidth from "string-width";

import {
renderRootHelp,
Expand All @@ -7,41 +8,91 @@ import {
} from "./help-brand.js";

describe("CLI help brand", () => {
it("renders a readable plain fallback without escape sequences", () => {
it("falls back to the plain word without block art or escape sequences", () => {
const output = renderRootHelp({ colors: "none", background: "dark" });

expect(output).toContain("╱████╲");
expect(output).toContain("◢");
expect(output).toContain("sketchi");
expect(output).toContain(" sketchi\n");
expect(output).toContain("describe it. sketchi draws it.");
expect(output).toContain("START HERE");
expect(output).toContain("WORK WITH A DIAGRAM");
expect(output).not.toMatch(/[▀▄█]/u);
expect(output).not.toContain("\u001b");
});

it("styles the complete help hierarchy with a background-aware palette", () => {
const dark = renderRootHelp({ colors: "truecolor", background: "dark" });
it("paints the pencil tile and wordmark when the terminal has colour", () => {
const output = renderRootHelp({
colors: "truecolor",
background: "dark",
unicode: true,
width: 80,
});
const lockup = output.split("\n\n")[0] ?? "";

// Plate, barrel, wood, graphite, ferrule and eraser all reach the screen.
for (const material of [
"38;2;158;124;140",
"38;2;250;248;247",
"38;2;214;186;152",
"38;2;58;50;54",
"38;2;186;190;196",
"38;2;222;152;158",
]) {
expect(lockup).toContain(material);
}
expect(lockup).toContain("48;2;");
expect(lockup.split("\n")).toHaveLength(8);
expect(output).toContain("\u001b[38;2;195;154;172m\u001b[1mSTART HERE");
});

it("keeps the light palette legible against its own background", () => {
const light = renderRootHelp({
colors: "truecolor",
background: "light",
unicode: true,
width: 80,
});

expect(dark).toContain("\u001b[38;2;195;154;172m");
expect(dark).toContain("\u001b[38;2;246;241;231m\u001b[1msketchi");
expect(dark).toContain("\u001b[38;2;195;154;172m\u001b[1mSTART HERE");
expect(light).toContain("38;2;143;112;127");
expect(light).toContain("\u001b[38;2;26;23;18m\u001b[1msketchi");
});

it("uses a strict ASCII pencil and wraps descriptions at narrow widths", () => {
it("keeps every lockup line inside the terminal width", () => {
for (const width of [32, 46, 52, 80, 120]) {
const output = renderRootHelp({
colors: "truecolor",
background: "dark",
unicode: true,
width,
});

for (const line of output.split("\n")) {
expect(stringWidth(line)).toBeLessThanOrEqual(width);
}
}
});

it("drops the tile but keeps the wordmark on narrow terminals", () => {
const output = renderRootHelp({
colors: "truecolor",
background: "dark",
unicode: true,
width: 46,
});

expect(output).toMatch(/[▀▄█]/u);
expect(output).not.toContain("48;2;");
});

it("wraps descriptions and drops block art without UTF-8", () => {
const output = renderRootHelp({
colors: "none",
background: "dark",
unicode: false,
width: 36,
});

expect(output).toContain("/####\\");
expect(output).not.toContain("█");
expect(output).not.toContain("◢");
expect(output).toContain(" sketchi\n");
expect(output).not.toMatch(/[▀▄█]/u);
expect(output.split("\n").every((line) => [...line].length <= 36)).toBe(
true,
);
Expand Down
Loading
Loading