/
Alex_Ural
/
opencode
Обзор
Документация
Войти
/
Alex_Ural
/
opencode
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
packages/tui/src/component/bg-pulse-render.ts
436 строк
15 KB
Dax
refactor(server): canonicalize service API (#31049)
07 июн 2026, 06:27
Не верифицирован
07 июн 2026, 06:27
fe0c4f8
Код
Авторство
О чём код?
import { OptimizedBuffer, RGBA, TextAttributes } from "@opentui/core" import { go } from "../logo" const PERIOD = 4600 const RINGS = 3 const WIDTH = 3.8 const TAIL = 9.5 const AMP = 0.55 const TAIL_AMP = 0.16 const BREATH_AMP = 0.05 const BREATH_SPEED = 0.0008 // Offset so the bg ring emits from the estimated GO center when the logo shimmer peaks. const PHASE_OFFSET = 0.29 const LOGO_GAP = 1 const LOGO_TOP_BIAS = -1 const LOGO_LEFT_WIDTH = go.left[0]?.length ?? 0 const LOGO_LINES = go.left.map((line, index) => line + " ".repeat(LOGO_GAP) + go.right[index]) const LOGO_WIDTH = LOGO_LINES[0]?.length ?? 0 const LOGO_HEIGHT = LOGO_LINES.length const SPACE = " ".codePointAt(0)! const TOP_HALF = "▀".codePointAt(0)! const FULL_BLOCK = "█".codePointAt(0)! const RING_SCALE = 1 / RINGS const TAIL_SCALE = 1 / TAIL const LOGO_REACH = Math.hypot(LOGO_WIDTH, LOGO_HEIGHT * 2) + 3 const enum LogoCellKind { Background, Top, ShadowTop, Solid, Char, } type LogoTemplateCell = { x: number y: number kind: LogoCellKind charCode: number attributes: number topDist: number bottomDist: number } const LOGO_TEMPLATE: LogoTemplateCell[] = LOGO_LINES.flatMap((line, y) => Array.from(line) .map((char, x) => { if (char === " ") return const kind = char === "_" ? LogoCellKind.Background : char === "^" ? LogoCellKind.Top : char === "~" ? LogoCellKind.ShadowTop : char === "█" ? LogoCellKind.Solid : LogoCellKind.Char return { x, y, kind, charCode: char.codePointAt(0) ?? SPACE, attributes: x > LOGO_LEFT_WIDTH ? TextAttributes.BOLD : 0, topDist: Math.hypot(x + 0.5 - LOGO_WIDTH / 2, y * 2 - LOGO_HEIGHT), bottomDist: Math.hypot(x + 0.5 - LOGO_WIDTH / 2, y * 2 + 1 - LOGO_HEIGHT), } }) .filter((cell): cell is LogoTemplateCell => !!cell), ) export type Rgb = [number, number, number] export type GoUpsellArtRenderOptions = { deltaTime?: number rgb?: boolean cache?: boolean } const CACHE_FRAME_COUNT = Math.round(PERIOD / (1000 / 30)) const CACHE_FRAMES_PER_RENDER = 1 export function toRgb(color: RGBA): Rgb { const [r, g, b] = color.toInts() return [r, g, b] } function clamp(n: number) { return Math.max(0, Math.min(1, n)) } function writeRgb(buffer: Uint16Array, offset: number, r: number, g: number, b: number, a = 255) { buffer[offset] = r buffer[offset + 1] = g buffer[offset + 2] = b buffer[offset + 3] = a } function mixChannel(base: number, overlay: number, alpha: number) { return Math.round(base + (overlay - base) * clamp(alpha)) } function writeLogoTint( buffer: Uint16Array, offset: number, base: Rgb, primary: Rgb, primaryMix: number, peakMix: number, ) { const p = clamp(primaryMix) const q = clamp(peakMix) const r = mixChannel(mixChannel(base[0], primary[0], p), 255, q) const g = mixChannel(mixChannel(base[1], primary[1], p), 255, q) const b = mixChannel(mixChannel(base[2], primary[2], p), 255, q) writeRgb(buffer, offset, r, g, b) } function sameRgb(a: Rgb, b: Rgb) { return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] } export class GoUpsellArtPainter { private panelRgb: Rgb = [0, 0, 0] private primaryRgb: Rgb = [255, 255, 255] private logoBaseRgb: Rgb = [180, 180, 180] private elapsed = 0 private distances = new Float32Array(0) private edgeFalloff = new Float32Array(0) private geometryWidth = 0 private geometryHeight = 0 private reach = 1 private logoX = 0 private logoY = 0 private logoIndexes = new Int32Array(0) private logoRgb: boolean | undefined private pulsePeak = 0 private pulsePrimary = 0 private cacheDirty = true private frameCache: Array<{ fg: Uint16Array; bg: Uint16Array }> = [] private cacheBuildIndex = 0 setBackgroundPanel(value: RGBA | Rgb | undefined) { if (!value) return false const next = value instanceof RGBA ? toRgb(value) : value if (sameRgb(this.panelRgb, next)) return false this.panelRgb = next this.invalidateCache() return true } setLogoBase(value: RGBA | Rgb | undefined) { if (!value) return false const next = value instanceof RGBA ? toRgb(value) : value if (sameRgb(this.logoBaseRgb, next)) return false this.logoBaseRgb = next this.invalidateCache() return true } setPrimary(value: RGBA | Rgb | undefined) { if (!value) return false const next = value instanceof RGBA ? toRgb(value) : value if (sameRgb(this.primaryRgb, next)) return false this.primaryRgb = next this.invalidateCache() return true } render(frameBuffer: OptimizedBuffer, options: GoUpsellArtRenderOptions = {}) { const rgb = options.rgb === true this.elapsed = (this.elapsed + (options.deltaTime ?? 0)) % PERIOD this.rebuildGeometry(frameBuffer, rgb) if (options.cache !== false) { this.drawCached(frameBuffer, rgb) return } this.drawBackground(frameBuffer, this.elapsed) this.drawLogo(frameBuffer, this.elapsed, rgb) } private invalidateCache() { this.cacheDirty = true this.cacheBuildIndex = 0 this.frameCache = [] } private rebuildGeometry(frameBuffer: OptimizedBuffer, rgb: boolean) { const width = frameBuffer.width const height = frameBuffer.height const geometryChanged = width !== this.geometryWidth || height !== this.geometryHeight const logoTemplateChanged = this.logoRgb !== rgb if (!geometryChanged && !logoTemplateChanged) return if (geometryChanged) { this.geometryWidth = width this.geometryHeight = height this.logoX = Math.max(0, Math.floor((width - LOGO_WIDTH) / 2)) this.logoY = Math.max( 0, Math.min(Math.max(0, height - LOGO_HEIGHT), Math.round((height - LOGO_HEIGHT) / 2) + LOGO_TOP_BIAS), ) const centerX = this.logoX + LOGO_WIDTH / 2 const centerY = this.logoY + LOGO_HEIGHT / 2 this.reach = Math.hypot(Math.max(centerX, width - centerX), Math.max(centerY, height - centerY) * 2) + TAIL this.distances = new Float32Array(width * height) this.edgeFalloff = new Float32Array(width * height) for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { const index = y * width + x const dist = Math.hypot(x + 0.5 - centerX, (y + 0.5 - centerY) * 2) this.distances[index] = dist this.edgeFalloff[index] = Math.max(0, 1 - (dist / (this.reach * 0.85)) ** 2) } } } this.logoRgb = rgb this.invalidateCache() this.rebuildCellTemplate(frameBuffer, rgb) } private drawCached(frameBuffer: OptimizedBuffer, rgb: boolean) { if (this.cacheDirty) this.startFrameCache(frameBuffer, rgb) if (this.cacheBuildIndex < CACHE_FRAME_COUNT) { this.buildFrameCache(frameBuffer, rgb) this.drawBackground(frameBuffer, this.elapsed) this.drawLogo(frameBuffer, this.elapsed, rgb) return } const frame = this.frameCache[Math.floor((this.elapsed / PERIOD) * CACHE_FRAME_COUNT) % CACHE_FRAME_COUNT] if (frame) { frameBuffer.buffers.fg.set(frame.fg) frameBuffer.buffers.bg.set(frame.bg) } } private startFrameCache(frameBuffer: OptimizedBuffer, rgb: boolean) { this.frameCache = [] this.cacheBuildIndex = 0 this.rebuildCellTemplate(frameBuffer, rgb) this.cacheDirty = false } private buildFrameCache(frameBuffer: OptimizedBuffer, rgb: boolean) { const end = Math.min(CACHE_FRAME_COUNT, this.cacheBuildIndex + CACHE_FRAMES_PER_RENDER) for (; this.cacheBuildIndex < end; this.cacheBuildIndex++) { const t = (this.cacheBuildIndex / CACHE_FRAME_COUNT) * PERIOD this.drawBackground(frameBuffer, t) this.drawLogo(frameBuffer, t, rgb) this.frameCache.push({ fg: new Uint16Array(frameBuffer.buffers.fg), bg: new Uint16Array(frameBuffer.buffers.bg), }) } } private rebuildCellTemplate(frameBuffer: OptimizedBuffer, rgb: boolean) { const buffers = frameBuffer.buffers buffers.char.fill(SPACE) buffers.attributes.fill(0) if (this.geometryWidth < LOGO_WIDTH || this.geometryHeight < LOGO_HEIGHT) { this.logoIndexes = new Int32Array(0) return } this.logoIndexes = new Int32Array(LOGO_TEMPLATE.length) for (let i = 0; i < LOGO_TEMPLATE.length; i++) { const cell = LOGO_TEMPLATE[i]! const index = (this.logoY + cell.y) * this.geometryWidth + this.logoX + cell.x this.logoIndexes[i] = index buffers.attributes[index] = cell.attributes buffers.char[index] = cell.kind === LogoCellKind.Background ? SPACE : cell.kind === LogoCellKind.Top || cell.kind === LogoCellKind.ShadowTop ? TOP_HALF : cell.kind === LogoCellKind.Solid ? rgb ? TOP_HALF : FULL_BLOCK : cell.charCode } } private drawBackground(frameBuffer: OptimizedBuffer, t: number) { const buffers = frameBuffer.buffers const fg = buffers.fg const bg = buffers.bg const distances = this.distances const edgeFalloff = this.edgeFalloff const baseR = this.panelRgb[0] const baseG = this.panelRgb[1] const baseB = this.panelRgb[2] const deltaR = this.primaryRgb[0] - baseR const deltaG = this.primaryRgb[1] - baseG const deltaB = this.primaryRgb[2] - baseB const breath = (0.5 + 0.5 * Math.sin(t * BREATH_SPEED)) * BREATH_AMP const phase0 = (t / PERIOD - PHASE_OFFSET + 1) % 1 const phase1 = (t / PERIOD + 1 / RINGS - PHASE_OFFSET + 1) % 1 const phase2 = (t / PERIOD + 2 / RINGS - PHASE_OFFSET + 1) % 1 const envelope0 = Math.sin(phase0 * Math.PI) const envelope1 = Math.sin(phase1 * Math.PI) const envelope2 = Math.sin(phase2 * Math.PI) const eased0 = envelope0 * envelope0 * (3 - 2 * envelope0) const eased1 = envelope1 * envelope1 * (3 - 2 * envelope1) const eased2 = envelope2 * envelope2 * (3 - 2 * envelope2) const head0 = phase0 * this.reach const head1 = phase1 * this.reach const head2 = phase2 * this.reach for (let index = 0; index < distances.length; index++) { const dist = distances[index] const delta0 = dist - head0 const abs0 = delta0 < 0 ? -delta0 : delta0 const crest0 = abs0 < WIDTH ? 0.5 + 0.5 * Math.cos((delta0 / WIDTH) * Math.PI) : 0 const tail0 = delta0 < 0 && delta0 > -TAIL ? (1 + delta0 * TAIL_SCALE) ** 2.3 : 0 const delta1 = dist - head1 const abs1 = delta1 < 0 ? -delta1 : delta1 const crest1 = abs1 < WIDTH ? 0.5 + 0.5 * Math.cos((delta1 / WIDTH) * Math.PI) : 0 const tail1 = delta1 < 0 && delta1 > -TAIL ? (1 + delta1 * TAIL_SCALE) ** 2.3 : 0 const delta2 = dist - head2 const abs2 = delta2 < 0 ? -delta2 : delta2 const crest2 = abs2 < WIDTH ? 0.5 + 0.5 * Math.cos((delta2 / WIDTH) * Math.PI) : 0 const tail2 = delta2 < 0 && delta2 > -TAIL ? (1 + delta2 * TAIL_SCALE) ** 2.3 : 0 const level = (crest0 * AMP + tail0 * TAIL_AMP) * eased0 + (crest1 * AMP + tail1 * TAIL_AMP) * eased1 + (crest2 * AMP + tail2 * TAIL_AMP) * eased2 const rawStrength = (level * RING_SCALE + breath) * edgeFalloff[index] const strength = (rawStrength > 1 ? 1 : rawStrength) * 0.7 const offset = index * 4 const r = Math.round(baseR + deltaR * strength) const g = Math.round(baseG + deltaG * strength) const b = Math.round(baseB + deltaB * strength) bg[offset] = fg[offset] = r bg[offset + 1] = fg[offset + 1] = g bg[offset + 2] = fg[offset + 2] = b bg[offset + 3] = fg[offset + 3] = 255 } } private setLogoPulse(dist: number, head0: number, eased0: number, head1: number, eased1: number) { let peak = 0.04 let primary = 0 const delta0 = dist - head0 const core0 = Math.exp(-(Math.abs(delta0 / 1.2) ** 1.8)) const soft0 = Math.exp(-(Math.abs(delta0 / 7) ** 1.6)) const tail0 = delta0 < 0 && delta0 > -7 ? (1 + delta0 / 7) ** 2.6 : 0 peak += core0 * 0.65 * eased0 primary += (soft0 * 0.16 + tail0 * 0.22) * eased0 const delta1 = dist - head1 const core1 = Math.exp(-(Math.abs(delta1 / 1.2) ** 1.8)) const soft1 = Math.exp(-(Math.abs(delta1 / 7) ** 1.6)) const tail1 = delta1 < 0 && delta1 > -7 ? (1 + delta1 / 7) ** 2.6 : 0 peak += core1 * 0.65 * eased1 primary += (soft1 * 0.16 + tail1 * 0.22) * eased1 this.pulsePeak = peak > 1 ? 1 : peak this.pulsePrimary = primary > 1 ? 1 : primary } private drawLogo(frameBuffer: OptimizedBuffer, t: number, rgb: boolean) { if (this.logoIndexes.length === 0) return const buffers = frameBuffer.buffers const fg = buffers.fg const bg = buffers.bg const shadow: Rgb = [ mixChannel(this.panelRgb[0], this.logoBaseRgb[0], 0.25), mixChannel(this.panelRgb[1], this.logoBaseRgb[1], 0.25), mixChannel(this.panelRgb[2], this.logoBaseRgb[2], 0.25), ] const phase0 = (t / PERIOD) % 1 const phase1 = (t / PERIOD + 0.5) % 1 const envelope0 = Math.sin(phase0 * Math.PI) const envelope1 = Math.sin(phase1 * Math.PI) const eased0 = envelope0 * envelope0 * (3 - 2 * envelope0) const eased1 = envelope1 * envelope1 * (3 - 2 * envelope1) const head0 = phase0 * LOGO_REACH const head1 = phase1 * LOGO_REACH for (let i = 0; i < LOGO_TEMPLATE.length; i++) { const cell = LOGO_TEMPLATE[i]! const index = this.logoIndexes[i]! const offset = index * 4 this.setLogoPulse(cell.topDist, head0, eased0, head1, eased1) const topPeak = this.pulsePeak const topPrimary = this.pulsePrimary this.setLogoPulse(cell.bottomDist, head0, eased0, head1, eased1) const bottomPeak = this.pulsePeak const bottomPrimary = this.pulsePrimary if (cell.kind === LogoCellKind.Background) { writeLogoTint(bg, offset, shadow, this.primaryRgb, 0, Math.max(topPeak, bottomPeak) * 0.18) continue } if (cell.kind === LogoCellKind.Top) { writeLogoTint(fg, offset, this.logoBaseRgb, this.primaryRgb, topPrimary, topPeak) writeLogoTint(bg, offset, shadow, this.primaryRgb, 0, bottomPeak * 0.18) continue } if (cell.kind === LogoCellKind.ShadowTop) { writeLogoTint(fg, offset, shadow, this.primaryRgb, 0, topPeak * 0.18) continue } if (cell.kind === LogoCellKind.Solid && rgb) { writeLogoTint(fg, offset, this.logoBaseRgb, this.primaryRgb, topPrimary, topPeak) writeLogoTint(bg, offset, this.logoBaseRgb, this.primaryRgb, bottomPrimary, bottomPeak) continue } writeLogoTint( fg, offset, this.logoBaseRgb, this.primaryRgb, (topPrimary + bottomPrimary) / 2, (topPeak + bottomPeak) / 2, ) } } }