design/warp
Warp: Terminal na nowo
„Wierzymy, że terminal jest jednym z najpotężniejszych narzędzi, jakie kiedykolwiek stworzono, ale jest też jednym z najbardziej onieśmielających." — Zach Lloyd, CEO Warp
Warp to nowoczesny terminal, który łączy surową moc CLI z użytecznością współczesnych aplikacji. Dowodzi, że narzędzia dla programistów nie muszą poświęcać znajomości na rzecz innowacji.
Dlaczego Warp ma znaczenie
Warp wziął najczcigodniejsze narzędzie programisty — terminal — i przemyślał je na nowo dla współczesnej ery, nie porzucając tego, co czyniło go potężnym.
Kluczowe osiągnięcia: - Architektura blokowa, która traktuje polecenia jako obiekty pierwszej klasy - Integracja AI, która wydaje się natywna, a nie doklejona - Nowoczesne doświadczenie edycji (zaznaczanie, cofanie, wiele kursorów) - Funkcje współpracy (Warp Drive, współdzielone przepływy pracy) - Zbudowany w Rust dla wydajności bez kompromisów w funkcjonalności
Kluczowe wnioski
- Blokowe wyjście przekształca chaos w obiekty - Traktowanie każdego polecenia+wyjścia jako dyskretnej, zaznaczalnej jednostki umożliwia kopiowanie, udostępnianie, nawigację i kontekst AI, czego ciągłe strumienie tekstu nie mogą zapewnić
- Wejście zakotwiczone na dole odzwierciedla znajomość czatu - Ustalona pozycja wejścia eliminuje obciążenie poznawcze związane z szukaniem promptu; użytkownicy zawsze wiedzą, gdzie pisać
- Integracja AI musi być opt-in i przejrzysta - Pokazuj rzeczywiste wygenerowane polecenie, oferuj tryb wyjaśniania i pozwalaj odrzucić każdą sugestię AI jednym klawiszem
- Addytywna innowacja zachowuje moc - Dodawaj nowoczesne udogodnienia bez usuwania możliwości; eksperci mogą ignorować nowe funkcje, podczas gdy nowicjusze z nich korzystają
- Narzędzia programistyczne mogą być kolaboracyjne - Współdzielone bloki i przepływy pracy dowodzą, że nawet tradycyjnie solowe narzędzia zyskują na funkcjach społecznościowych
Główna filozofia projektowania
Problem mostu
Terminale stoją przed unikalnym wyzwaniem: muszą służyć zarówno ekspertom, którzy używają ich od dziesięcioleci, JAK I nowicjuszom, którzy uważają je za onieśmielające. Rozwiązanie Warp jest addytywne — dodaje nowoczesne udogodnienia bez usuwania mocy.
TRADYCYJNY TERMINAL
┌─────────────────────────────────────────────────────────────┐
│ $ git status │
│ On branch main │
│ Your branch is up to date with 'origin/main'. │
│ │
│ Changes not staged for commit: │
│ (use "git add <file>..." to update what will be...) │
│ modified: src/app.py │
│ │
│ $ _ │
│ │
│ (wszystko jest niezróżnicowanym tekstem) │
└─────────────────────────────────────────────────────────────┘
PODEJŚCIE WARP
┌─────────────────────────────────────────────────────────────┐
│ ┌─ Blok 1 ──────────────────────────────────────────────┐ │
│ │ $ git status [^] [Kopiuj] │ │
│ ├───────────────────────────────────────────────────────┤ │
│ │ On branch main │ │
│ │ Your branch is up to date with 'origin/main'. │ │
│ │ │ │
│ │ Changes not staged for commit: │ │
│ │ modified: src/app.py │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Wejście ─────────────────────────────────────────────┐ │
│ │ Wpisz polecenie... [AI] [Cmd+P] │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Kluczowy wniosek: Każde polecenie+wyjście to zaznaczalny, współdzielony blok
Biblioteka wzorców
1. Architektura blokowego wyjścia
Najbardziej znaczącą innowacją Warp jest traktowanie każdego polecenia i jego wyjścia jako dyskretnego „bloku" zamiast ciągłego tekstu.
Co czyni bloki potężnymi:
| Funkcja | Tradycyjne | Bloki Warp |
|---|---|---|
| Zaznaczanie | Tylko znak/linia | Całe wyjście jako jednostka |
| Kopiowanie | Ręczne zaznaczanie | Kopiowanie jednym kliknięciem |
| Udostępnianie | Zrzut ekranu lub wklejenie | Link do bloku |
| Nawigacja | Przewijanie tekstu | Skakanie między blokami |
| Kontekst AI | Brak | Blok jest oknem kontekstu |
Wzorzec implementacji:
// Struktura danych bloku
const Block = {
id: 'block-uuid',
command: 'git status',
timestamp: Date.now(),
output: {
text: '...',
exitCode: 0,
duration: 234, // ms
},
metadata: {
cwd: '/Users/dev/project',
env: { /* snapshot */ },
}
};
// Interakcje z blokiem
const BlockActions = {
copy: (block) => copyToClipboard(block.output.text),
share: (block) => generateShareableLink(block),
rerun: (block) => executeCommand(block.command, block.metadata.cwd),
edit: (block) => openCommandEditor(block.command),
};
Wizualne traktowanie:
/* Stylowanie kontenera bloku */
.block {
--block-bg: var(--surface-secondary);
--block-border: 1px solid var(--border-subtle);
--block-radius: 8px;
background: var(--block-bg);
border: var(--block-border);
border-radius: var(--block-radius);
margin-bottom: 12px;
/* Hover ujawnia akcje */
&:hover .block-actions {
opacity: 1;
}
}
.block-command {
font-family: var(--font-mono);
font-size: 14px;
padding: 8px 12px;
border-bottom: 1px solid var(--border-subtle);
display: flex;
justify-content: space-between;
align-items: center;
}
.block-output {
padding: 12px;
font-family: var(--font-mono);
font-size: 13px;
line-height: 1.5;
white-space: pre-wrap;
}
.block-actions {
opacity: 0;
transition: opacity 150ms ease;
display: flex;
gap: 4px;
}
2. Wejście zakotwiczone na dole
W przeciwieństwie do tradycyjnych terminali, gdzie wejście pojawia się w linii z wyjściem, Warp zakotwicza obszar wejścia na dole, podobnie jak aplikacje czatowe.
Dlaczego to działa:
TRADYCYJNE (Wejście podąża za wyjściem)
┌────────────────────────────────────────┐
│ linia wyjścia 1 │
│ linia wyjścia 2 │
│ linia wyjścia 3 │
│ $ _ ← Wejście przesuwa się z wyjściem │
│ │
│ │
│ │
└────────────────────────────────────────┘
WARP (Ustalona pozycja wejścia)
┌────────────────────────────────────────┐
│ linia wyjścia 1 │
│ linia wyjścia 2 │
│ linia wyjścia 3 │
│ │
├────────────────────────────────────────┤
│ $ _ ← Wejście zawsze tutaj (spójne) │
└────────────────────────────────────────┘
Korzyści dla modelu mentalnego: - Przewidywalne: Wejście jest zawsze w tym samym miejscu - Znajome: Odzwierciedla interfejsy czatowe (Wiadomości, Slack) - Efektywne: Bez przewijania w poszukiwaniu promptu - Przestronne: Pełnofunkcyjny edytor z obsługą wielu linii
Implementacja:
.terminal-layout {
display: flex;
flex-direction: column;
height: 100vh;
}
.output-area {
flex: 1;
overflow-y: auto;
padding: 16px;
}
.input-area {
flex-shrink: 0;
border-top: 1px solid var(--border-primary);
padding: 12px 16px;
background: var(--surface-primary);
/* Nowoczesne wrażenie edytora tekstu */
min-height: 48px;
max-height: 200px; /* Rozszerzalny dla wielu linii */
}
3. Wzorce integracji AI
Funkcje AI Warp pokazują, jak zintegrować AI z narzędziem dla zaawansowanych użytkowników bez tworzenia wrażenia kuli u nogi.
Trzy tryby asystenta AI:
1. WEJŚCIE W JĘZYKU NATURALNYM
┌────────────────────────────────────────────────────────────┐
│ „znajdź wszystkie pliki pythona zmodyfikowane w │
│ ostatnim tygodniu" │
│ │
│ ↓ AI tłumaczy na: │
│ │
│ find . -name "*.py" -mtime -7 │
│ │
│ [Uruchom] [Edytuj] [Wyjaśnij] │
└────────────────────────────────────────────────────────────┘
2. AKTYWNE AI (Kontekstowe sugestie)
┌────────────────────────────────────────────────────────────┐
│ $ git push origin main │
│ error: failed to push some refs │
│ │
│ ┌─ Sugestia AI ───────────────────────────────────────┐ │
│ │ 💡 Twoja gałąź jest w tyle. Spróbuj: │ │
│ │ git pull --rebase origin main │ │
│ │ [Zastosuj] [×] │ │
│ └─────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘
3. TRYB WYJAŚNIANIA (Edukacja)
┌────────────────────────────────────────────────────────────┐
│ $ tar -xzvf archive.tar.gz │
│ [Wyjaśnij to polecenie] │
│ │
│ ┌─ Wyjaśnienie ───────────────────────────────────────┐ │
│ │ tar: Narzędzie archiwizacyjne │ │
│ │ -x: Wypakuj pliki │ │
│ │ -z: Dekompresuj gzipem │ │
│ │ -v: Szczegółowo (pokaż pliki) │ │
│ │ -f: Określ nazwę pliku │ │
│ └─────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘
Kluczowe decyzje projektowe:
- Opt-in, nie opt-out: Sugestie AI pojawiają się kontekstowo, ale nie przerywają przepływu
- Przejrzyste tłumaczenie: Gdy AI generuje polecenie, pokaż rzeczywiste polecenie
- Edukacyjne: Tryb wyjaśniania uczy użytkowników zamiast tworzyć zależność
- Odrzucalne: Każdy element AI może być zignorowany jednym klawiszem
4. Wzorzec palety poleceń
Warp implementuje nowoczesną paletę poleceń (Cmd+P), która udostępnia funkcje bez zapamiętywania skrótów.
┌────────────────────────────────────────────────────────────────────┐
│ Szukaj poleceń, ustawień, przepływów pracy... │
├────────────────────────────────────────────────────────────────────┤
│ Ostatnie │
│ ├─ Podziel panel w prawo Cmd+D │
│ ├─ Przełącz sugestie AI Cmd+Shift+A │
│ └─ Otwórz ustawienia Cmd+, │
│ │
│ Polecenia │
│ ├─ Nowa karta Cmd+T │
│ ├─ Zamknij kartę Cmd+W │
│ ├─ Przejdź do bloku... Cmd+G │
│ └─ Udostępnij blok Cmd+Shift+S │
│ │
│ Przepływy pracy │
│ ├─ Wdróż na produkcję │
│ ├─ Uruchom zestaw testów │
│ └─ Zaktualizuj zależności │
└────────────────────────────────────────────────────────────────────┘
Zasady projektowania:
- Rozmyte wyszukiwanie: „podz pan" pasuje do „Podziel panel"
- Pokazuj skróty: Ucz użytkowników podczas wyszukiwania
- Ostatnie elementy najpierw: Spersonalizowane według wzorców użycia
- Skategoryzowane: Grupuj powiązane polecenia
5. Przepływy pracy: Współdzielone sekwencje poleceń
Funkcja Workflows Warp pozwala użytkownikom zapisywać i udostępniać sekwencje poleceń, łącząc skrypty i zakładki.
# Przykładowy przepływ pracy: Wdrożenie na produkcję
name: "Wdróż na produkcję"
description: "Uruchom testy, zbuduj i wdróż"
author: "@team"
steps:
- command: "npm test"
description: "Uruchom zestaw testów"
- command: "npm run build"
description: "Zbuduj dla produkcji"
- command: "git push origin main"
description: "Wypchnij, aby uruchomić wdrożenie"
Traktowanie UI:
┌─ Przepływ pracy: Wdróż na produkcję ─────────────────────────────┐
│ │
│ Krok 1 z 3 │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ $ npm test │ │
│ │ │ │
│ │ Uruchom zestaw testów │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ [Uruchom] [Pomiń] [Anuluj przepływ] (*) ( ) ( ) │
└──────────────────────────────────────────────────────────────────┘
System projektowania wizualnego
System kolorów
:root {
/* Ciemny motyw (domyślny) */
--bg-primary: #0D0D0D;
--bg-secondary: #1A1A1A;
--bg-tertiary: #262626;
--text-primary: #FFFFFF;
--text-secondary: #A3A3A3;
--text-muted: #737373;
--border-subtle: rgba(255, 255, 255, 0.08);
--border-primary: rgba(255, 255, 255, 0.12);
/* Kolory semantyczne */
--color-success: #22C55E;
--color-error: #EF4444;
--color-warning: #F59E0B;
--color-info: #3B82F6;
/* Akcent AI */
--color-ai: #A855F7; /* Fioletowy dla funkcji AI */
/* Zaznaczenie i fokus */
--color-selection: rgba(59, 130, 246, 0.3);
--color-focus: #3B82F6;
}
Typografia
:root {
/* Monospace dla wyjścia terminala */
--font-mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', monospace;
/* Sans-serif dla elementów UI */
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
/* Rozmiary */
--text-xs: 11px;
--text-sm: 13px;
--text-base: 14px;
--text-lg: 16px;
/* Wysokości linii zoptymalizowane dla kodu */
--line-height-tight: 1.3;
--line-height-normal: 1.5;
--line-height-relaxed: 1.7;
}
/* Wyjście terminala */
.terminal-text {
font-family: var(--font-mono);
font-size: var(--text-base);
line-height: var(--line-height-normal);
font-variant-ligatures: contextual;
font-feature-settings: 'calt' 1; /* Włącz ligatury */
}
/* Elementy UI */
.ui-text {
font-family: var(--font-sans);
font-size: var(--text-sm);
font-weight: 500;
}
Wzorce animacji
Pojawienie się bloku
@keyframes block-enter {
from {
opacity: 0;
transform: translateY(-4px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.block {
animation: block-enter 150ms ease-out;
}
Ujawnienie sugestii AI
@keyframes suggestion-reveal {
from {
opacity: 0;
transform: translateY(8px);
max-height: 0;
}
to {
opacity: 1;
transform: translateY(0);
max-height: 200px;
}
}
.ai-suggestion {
animation: suggestion-reveal 200ms ease-out;
}
.ai-suggestion.dismissing {
animation: suggestion-reveal 150ms ease-in reverse;
}
Stany ładowania
/* Wskaźnik strumieniowego wyjścia */
.block.executing::after {
content: '';
display: inline-block;
width: 8px;
height: 16px;
background: var(--color-focus);
animation: cursor-blink 1s step-end infinite;
}
@keyframes cursor-blink {
50% { opacity: 0; }
}
/* Wskaźnik myślenia AI */
.ai-thinking {
display: flex;
gap: 4px;
}
.ai-thinking span {
width: 6px;
height: 6px;
background: var(--color-ai);
border-radius: 50%;
animation: thinking-pulse 1.4s infinite ease-in-out both;
}
.ai-thinking span:nth-child(1) { animation-delay: 0s; }
.ai-thinking span:nth-child(2) { animation-delay: 0.16s; }
.ai-thinking span:nth-child(3) { animation-delay: 0.32s; }
@keyframes thinking-pulse {
0%, 80%, 100% { transform: scale(0.6); opacity: 0.5; }
40% { transform: scale(1); opacity: 1; }
}
Lekcje dla naszej pracy
1. Addytywna innowacja
Dodawaj nowoczesne funkcje bez usuwania mocy. Eksperci mogą ignorować nowe funkcje; nowicjusze z nich korzystają.
2. Strukturyzuj chaos
Architektura blokowa przekształca niezróżnicowany tekst w manipulowalne obiekty. Szukaj okazji do dodania struktury do nieustrukturyzowanej treści.
3. Stałe kotwice UI
Ustalona pozycja wejścia zmniejsza obciążenie poznawcze. Użytkownicy nie szukają, gdzie pisać.
4. AI jako asystent, nie zamiennik
Pokazuj rzeczywiste polecenie, nie tylko wynik. Tryb wyjaśniania uczy, zamiast tworzyć zależność.
5. Kolaboracyjne CLI
Współdzielone bloki i przepływy pracy dowodzą, że nawet tradycyjnie solowe narzędzia mogą mieć funkcje społecznościowe.
Często zadawane pytania
Czym jest architektura blokowa Warp?
Zamiast traktować wyjście terminala jako ciągły przewijany tekst, Warp strukturyzuje każde polecenie i jego wyjście jako dyskretny „blok". Każdy blok to zaznaczalna, kopiowalna, współdzielna jednostka z metadanymi (znacznik czasu, kod wyjścia, czas trwania). Umożliwia to kopiowanie jednym kliknięciem, udostępnianie linków, skakanie między poleceniami i dostarczanie AI skoncentrowanych okien kontekstu.
Dlaczego Warp umieszcza wejście na dole zamiast w linii?
Tradycyjne terminale umieszczają kursor wejścia w linii z wyjściem, co oznacza, że przesuwa się on wraz z rośnięciem wyjścia. Warp zakotwicza obszar wejścia na dole (jak aplikacje czatowe), zapewniając przewidywalną lokalizację, która eliminuje obciążenie poznawcze związane ze znajdowaniem miejsca do pisania. Umożliwia to również pełnofunkcyjny edytor wieloliniowy z nowoczesnymi możliwościami edycji.
Jak Warp integruje AI bez tworzenia zależności?
AI Warp działa w trzech trybach: tłumaczenie języka naturalnego (pokazując rzeczywiste wygenerowane polecenie), kontekstowe sugestie (opt-in i odrzucalne) oraz tryb wyjaśniania (uczący, co robią polecenia). Kluczową zasadą jest przejrzystość — AI zawsze pokazuje, co generuje, więc użytkownicy uczą się zamiast polegać.
Czym są Warp Workflows?
Workflows to współdzielne sekwencje poleceń zapisane w formacie YAML. Łączą lukę między jednorazowymi poleceniami a pełnymi skryptami, pozwalając zespołom dzielić się typowymi procedurami (jak kroki wdrożenia) z opisami dla każdego kroku. Workflows można odkrywać przez paletę poleceń i wykonywać krok po kroku.
Dlaczego Warp wybrał Rust do implementacji?
Rust zapewnia bezpieczeństwo pamięci i wydajność bez pauz garbage collectora, co jest krytyczne dla terminala, gdzie opóźnienia mają znaczenie. Umożliwia również architekturę Warp traktującą bloki jako ustrukturyzowane dane z bogatymi metadanymi, przy zachowaniu responsywności, jakiej użytkownicy oczekują od natywnych aplikacji.