feat: wordmark + progress-bar sheen, dark-violet svg base, readme refinements

This commit is contained in:
bairon.dev
2026-06-27 12:42:38 -04:00
parent ea12f2f134
commit 8a9886be9c
11 changed files with 211 additions and 43 deletions
+6 -13
View File
@@ -1,13 +1,9 @@
import { useEffect, useState } from "react";
import { Text } from "ink";
import { COLOR, RULE, lerpHex } from "../theme";
import { SHEEN_PEAK, SHEEN_TICK_MS, sheenCenter, sheenIntensity, sheenPeriod } from "../sheen";
const DEEP = "#7c5cd6";
const SHEEN_PEAK = "#f4efff";
const RADIUS = 3.5;
const GAP = 8;
const MAX_SHEEN = 0.9;
const TICK_MS = 90;
interface Run {
color: string;
@@ -55,7 +51,7 @@ export function ProgressBar({
const [tick, setTick] = useState(0);
useEffect(() => {
if (!animate) return;
const timer = setInterval(() => setTick((v) => v + 1), TICK_MS);
const timer = setInterval(() => setTick((v) => v + 1), SHEEN_TICK_MS);
timer.unref?.();
return () => clearInterval(timer);
}, [animate]);
@@ -76,15 +72,12 @@ export function ProgressBar({
);
}
const period = Math.ceil(width + RADIUS * 2) + GAP;
const center = (tick % period) - RADIUS;
const period = sheenPeriod(width);
const center = sheenCenter(tick, period);
const cells = Array.from({ length: filled }, (_, i) => {
let c = ramp(i / denom, DEEP, COLOR.accent, COLOR.bright);
const d = Math.abs(i - center);
if (d < RADIUS) {
const intensity = 0.5 * (1 + Math.cos((Math.PI * d) / RADIUS)) * MAX_SHEEN;
c = lerpHex(c, SHEEN_PEAK, intensity);
}
const intensity = sheenIntensity(i, center);
if (intensity > 0) c = lerpHex(c, SHEEN_PEAK, intensity);
return c;
});
+1 -1
View File
@@ -14,7 +14,7 @@ import type { Source, TorrentResult } from "../../sources/types";
type Mode = "list" | "search" | "detail";
const PLACEHOLDER = "Search, or paste a magnet…";
const PLACEHOLDER = "Search or paste a magnet link…";
function DetailRow({ label, value }: { label: string; value: ReactNode }) {
return (
+37
View File
@@ -0,0 +1,37 @@
// Single source of truth for the animated progress-bar sheen, shared by the
// live TUI (src/ui/components/ProgressBar.tsx) and the README SVG generator
// (scripts/ansi-to-svg.ts) so the preview renders 1:1 with the terminal.
//
// The highlight is a cosine bell that sweeps across the filled cells. Position
// advances by a fractional SHEEN_SPEED per tick at a fast SHEEN_TICK_MS, so the
// peak glides between cells (intensity-interpolated) instead of stepping a whole
// cell at a time, while the cells themselves stay discrete (pixelated).
export const SHEEN_PEAK = "#f4efff";
export const SHEEN_RADIUS = 4.5; // bell half-width, in cells
export const SHEEN_GAP = 8; // dark cells between sweeps
export const SHEEN_TICK_MS = 40; // frame interval (~25fps)
export const SHEEN_SPEED = 0.45; // cells advanced per tick (~11 cells/sec)
export const SHEEN_MAX = 0.9; // peak blend toward SHEEN_PEAK
/** Total sweep cycle length in cells, for a bar `width` cells wide. */
export function sheenPeriod(width: number): number {
return Math.ceil(width + SHEEN_RADIUS * 2) + SHEEN_GAP;
}
/** Fractional center of the bell at a given tick (loops over `period`). */
export function sheenCenter(tick: number, period: number): number {
return ((tick * SHEEN_SPEED) % period) - SHEEN_RADIUS;
}
/** Sheen intensity (0..SHEEN_MAX) for cell `i` given the bell `center`. */
export function sheenIntensity(i: number, center: number): number {
const d = Math.abs(i - center);
if (d >= SHEEN_RADIUS) return 0;
return 0.5 * (1 + Math.cos((Math.PI * d) / SHEEN_RADIUS)) * SHEEN_MAX;
}
/** Ticks in one full visual loop, for sampling the SVG flipbook 1:1. */
export function sheenLoopTicks(period: number): number {
return Math.round(period / SHEEN_SPEED);
}
+1 -1
View File
@@ -50,7 +50,7 @@ export function Splash() {
width={barWidth}
value=""
editing
placeholder="Search, or paste a magnet…"
placeholder="Search or paste a magnet link…"
onSubmit={submitQuery}
/>
</Box>