design/craft
Craft: Excelência em Documentos Native-First
“Acreditamos que ferramentas para o pensamento devem parecer uma extensão dos seus pensamentos, não um obstáculo.”
O Craft prova que apps nativos podem entregar experiências que apps web não conseguem igualar. Construído com integração profunda de plataforma, ele alcança a responsividade e o polimento que fazem anotações digitais parecerem tão naturais quanto papel.
Principais Conclusões
- Nativo supera Electron - Tempo de resposta abaixo de 50ms requer UI específica por plataforma, não wrappers web
- Páginas dentro de páginas - Qualquer bloco pode se tornar uma página, permitindo que a estrutura emerja do conteúdo
- Múltiplos layouts, mesmos dados - Listas, cards, galerias e quadros dão aos usuários a visualização certa para cada contexto
- Publicação web com um clique - Páginas compartilhadas funcionam sem contas de destinatários ou downloads de apps
- Apropriado à plataforma, não idêntico - Craft no Mac parece Mac; Craft no iOS parece iOS
Por Que o Craft Importa
O Craft ganhou o Apple Design Award 2021 e consistentemente recebe reconhecimento da App Store por se recusar a comprometer performance nativa por conveniência cross-platform.
Conquistas principais: - Apps verdadeiramente nativos no iOS, macOS, Windows (não Electron) - Tempo de resposta abaixo de 50ms em todas as interações - Offline-first com sincronização perfeita - Arquitetura baseada em blocos sem a lentidão de apps web - Páginas de compartilhamento bonitas que funcionam sem contas
Filosofia Central de Design
Native-First, Não Web-Wrapped
A escolha definidora do Craft: construir apps nativos para cada plataforma, usando lógica de negócios compartilhada mas UI específica por plataforma.
ABORDAGEM ELECTRON/WEB ABORDAGEM NATIVA DO CRAFT
───────────────────────────────────────────────────────────────────
Código único (JavaScript) UI específica por plataforma (Swift, etc.)
Motor de renderização web Renderização nativa
"Consistência" cross-platform Comportamento apropriado à plataforma
~200ms de latência de input ~16ms de latência de input
Atalhos de teclado genéricos Atalhos nativos da plataforma
Seleção de texto padrão web Motor de texto nativo
Insight chave: Usuários não querem apps que pareçam iguais em todo lugar—eles querem apps que pareçam certos na sua plataforma.
macOS via Catalyst (Feito Corretamente)
O Craft usa Mac Catalyst mas o customiza pesadamente para parecer verdadeiramente nativo do Mac:
// Abordagem de customização Catalyst do Craft
#if targetEnvironment(macCatalyst)
extension SceneDelegate {
func scene(_ scene: UIScene, willConnectTo session: UISceneSession) {
guard let windowScene = scene as? UIWindowScene else { return }
// Habilitar toolbar nativa do Mac
if let titlebar = windowScene.titlebar {
titlebar.titleVisibility = .hidden
titlebar.toolbar = createNativeToolbar()
}
// Dimensionamento de janela específico do Mac
windowScene.sizeRestrictions?.minimumSize = CGSize(width: 800, height: 600)
// Habilitar abas de janela
UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.forEach { $0.titlebar?.toolbar?.showsBaselineSeparator = false }
}
private func createNativeToolbar() -> NSToolbar {
let toolbar = NSToolbar(identifier: "CraftToolbar")
toolbar.displayMode = .iconOnly
toolbar.delegate = self
return toolbar
}
}
#endif
Biblioteca de Padrões
1. Arquitetura de Conteúdo Baseada em Blocos
Todo elemento no Craft é um bloco. Todo bloco com conteúdo é potencialmente uma página, criando aninhamento infinito sem sobrecarga cognitiva.
Tipos de blocos:
BLOCOS DE TEXTO
├── Parágrafo (padrão)
├── Título 1, 2, 3
├── Citação
├── Destaque (info, aviso, sucesso)
└── Código (com realce de sintaxe)
BLOCOS DE MÍDIA
├── Imagem (com legenda)
├── Vídeo
├── Anexo de arquivo
├── Desenho (Apple Pencil)
└── Gravação de áudio
BLOCOS ESTRUTURAIS
├── Toggle (recolhível)
├── Página (documento aninhado)
├── Divisor
└── Tabela
Conceito de implementação:
protocol CraftBlock: Identifiable {
var id: UUID { get }
var content: BlockContent { get set }
var style: BlockStyle { get set }
var children: [any CraftBlock] { get set }
var metadata: BlockMetadata { get }
}
enum BlockContent {
case text(AttributedString)
case image(ImageData)
case page(PageReference)
case toggle(isExpanded: Bool)
case code(language: String, content: String)
case table(TableData)
}
struct BlockMetadata {
let created: Date
let modified: Date
let createdBy: UserReference?
}
// Todo bloco pode conter outros blocos
class PageBlock: CraftBlock {
var id = UUID()
var content: BlockContent
var style: BlockStyle
var children: [any CraftBlock] = []
var metadata: BlockMetadata
// Uma página é apenas um bloco que pode ser aberto em tela cheia
var canOpenAsPage: Bool { true }
}
Insight chave: Quando todo bloco pode ser uma página, a arquitetura da informação emerge do conteúdo, não de uma estrutura predeterminada.
2. Páginas Aninhadas (Páginas Dentro de Páginas)
A funcionalidade característica do Craft: qualquer bloco pode se tornar uma página, e páginas se aninham infinitamente.
ESTRUTURA DO DOCUMENTO
───────────────────────────────────────────────────────────────────
📄 Projeto Alpha
├── 📝 Parágrafo de introdução
├── 📄 Notas de Pesquisa ← Esta é uma página (documento aninhado)
│ ├── 📝 Entrevistas com usuários
│ ├── 📄 Entrevista: Sarah ← Outra página aninhada
│ │ └── 📝 Insights principais
│ └── 📝 Análise competitiva
├── 📝 Visão geral do cronograma
└── 📄 Notas de Reunião ← Outra página
└── 📝 Itens de ação
Navegação: Trilha de breadcrumb mostra o caminho
Projeto Alpha > Notas de Pesquisa > Entrevista: Sarah
Padrão de implementação SwiftUI:
struct PageView: View {
@Bindable var page: PageDocument
@State private var selectedBlock: CraftBlock?
var body: some View {
ScrollView {
LazyVStack(alignment: .leading, spacing: 0) {
ForEach(page.blocks) { block in
BlockView(block: block, onTap: { tapped in
if tapped.canOpenAsPage {
navigateToPage(tapped)
} else {
selectedBlock = tapped
}
})
}
}
}
.navigationTitle(page.title)
.toolbar {
// Navegação breadcrumb
ToolbarItem(placement: .principal) {
BreadcrumbView(path: page.ancestorPath)
}
}
}
}
struct BreadcrumbView: View {
let path: [PageReference]
var body: some View {
HStack(spacing: 4) {
ForEach(Array(path.enumerated()), id: \.element.id) { index, page in
if index > 0 {
Image(systemName: "chevron.right")
.font(.caption)
.foregroundStyle(.secondary)
}
Button(page.title) {
navigateTo(page)
}
.buttonStyle(.plain)
.foregroundStyle(index == path.count - 1 ? .primary : .secondary)
}
}
}
}
3. Sistema de Layout de Cards
O Craft oferece 5 estilos visuais para páginas, tornando documentos escaneáveis num relance.
Estilos de cards:
ESTILO 1: LISTA (Padrão)
┌────────────────────────────────────────┐
│ 📄 Título da Página │
│ Texto de preview aparece aqui... │
└────────────────────────────────────────┘
ESTILO 2: CARD (Médio)
┌──────────────────┐
│ ┌──────────────┐ │
│ │ [Imagem] │ │
│ └──────────────┘ │
│ Título da Página │
│ Texto preview... │
└──────────────────┘
ESTILO 3: CARD (Grande)
┌────────────────────────────────────────┐
│ ┌────────────────────────────────────┐ │
│ │ │ │
│ │ [Imagem de Capa] │ │
│ │ │ │
│ └────────────────────────────────────┘ │
│ Título da Página │
│ Texto preview mais longo com espaço... │
└────────────────────────────────────────┘
ESTILO 4: GALERIA (Grid)
┌────────┐ ┌────────┐ ┌────────┐
│ [Img] │ │ [Img] │ │ [Img] │
│ Título │ │ Título │ │ Título │
└────────┘ └────────┘ └────────┘
ESTILO 5: QUADRO (Estilo Kanban)
│ A Fazer │ Fazendo │ Feito │
├──────────┼──────────┼──────────┤
│ Tarefa 1 │ Tarefa 3 │ Tarefa 5 │
│ Tarefa 2 │ Tarefa 4 │ │
Implementação:
enum PageLayoutStyle: String, CaseIterable {
case list = "list"
case cardMedium = "card_medium"
case cardLarge = "card_large"
case gallery = "gallery"
case board = "board"
}
struct PageGridView: View {
let pages: [PageReference]
let style: PageLayoutStyle
var body: some View {
switch style {
case .list:
LazyVStack(spacing: 8) {
ForEach(pages) { page in
ListRowView(page: page)
}
}
case .cardMedium, .cardLarge:
let columns = style == .cardMedium ? 3 : 2
LazyVGrid(columns: Array(repeating: .init(.flexible()), count: columns)) {
ForEach(pages) { page in
CardView(page: page, size: style == .cardLarge ? .large : .medium)
}
}
case .gallery:
LazyVGrid(columns: Array(repeating: .init(.flexible()), count: 4)) {
ForEach(pages) { page in
GalleryThumbnail(page: page)
}
}
case .board:
BoardView(pages: pages)
}
}
}
4. Fundos de Página e Temas
Cada página pode ter sua própria identidade visual através de fundos e cores de destaque.
struct PageAppearance {
// Opções de fundo
enum Background {
case solid(Color)
case gradient(Gradient)
case image(ImageReference)
case paper(PaperTexture)
}
// Texturas de papel para sensação de escrita
enum PaperTexture: String {
case none
case lined
case grid
case dotted
}
var background: Background = .solid(.white)
var accentColor: Color = .blue
var iconEmoji: String?
var coverImage: ImageReference?
}
// Aplicado à página
struct PageContainer: View {
let page: PageDocument
var body: some View {
ZStack {
// Camada de fundo
backgroundView(for: page.appearance.background)
// Camada de conteúdo
PageContentView(page: page)
}
}
@ViewBuilder
private func backgroundView(for background: PageAppearance.Background) -> some View {
switch background {
case .solid(let color):
color.ignoresSafeArea()
case .gradient(let gradient):
LinearGradient(gradient: gradient, startPoint: .top, endPoint: .bottom)
.ignoresSafeArea()
case .image(let ref):
AsyncImage(url: ref.url) { image in
image.resizable().scaledToFill()
} placeholder: {
Color.gray.opacity(0.1)
}
.ignoresSafeArea()
.overlay(.ultraThinMaterial)
case .paper(let texture):
PaperTextureView(texture: texture)
}
}
}
5. Páginas de Compartilhamento (Publicação Web)
O Craft gera páginas web bonitas e responsivas a partir de documentos. Não é necessária conta para visualizar.
DOCUMENTO NO CRAFT PÁGINA DE COMPARTILHAMENTO NA WEB
───────────────────────────────────────────────────────────────────
📄 Proposta de Projeto https://www.craft.do/s/abc123
├── 📝 Resumo Executivo →
├── 📄 Detalhes do Orçamento Layout limpo e responsivo
├── 📝 Cronograma Tipografia preservada
└── 📄 Bios da Equipe Imagens otimizadas
Modo escuro suportado
Não precisa de conta Craft
Recursos principais: - Publicação com um clique - Domínios personalizados disponíveis - Opção de proteção por senha - Analytics de visualizações - Renderização amigável para SEO - Responsivo em todos os dispositivos
Sistema de Design Visual
Paleta de Cores
extension Color {
// Paleta característica do Craft
static let craftPurple = Color(hex: "#6366F1") // Destaque primário
static let craftBackground = Color(hex: "#FAFAFA") // Modo claro
static let craftSurface = Color(hex: "#FFFFFF")
// Cores semânticas
static let craftSuccess = Color(hex: "#10B981")
static let craftWarning = Color(hex: "#F59E0B")
static let craftError = Color(hex: "#EF4444")
static let craftInfo = Color(hex: "#3B82F6")
// Hierarquia de texto
static let craftTextPrimary = Color(hex: "#111827")
static let craftTextSecondary = Color(hex: "#6B7280")
static let craftTextMuted = Color(hex: "#9CA3AF")
}
Tipografia
struct CraftTypography {
// Tipografia do documento
static let title = Font.system(size: 32, weight: .bold, design: .default)
static let heading1 = Font.system(size: 28, weight: .semibold)
static let heading2 = Font.system(size: 22, weight: .semibold)
static let heading3 = Font.system(size: 18, weight: .medium)
static let body = Font.system(size: 16, weight: .regular)
static let caption = Font.system(size: 14, weight: .regular)
// Blocos de código
static let code = Font.system(size: 14, weight: .regular, design: .monospaced)
// Alturas de linha (generosas para legibilidade)
static let bodyLineSpacing: CGFloat = 8
static let headingLineSpacing: CGFloat = 4
}
Sistema de Espaçamento
struct CraftSpacing {
// Espaçamento de blocos
static let blockGap: CGFloat = 4 // Entre blocos
static let sectionGap: CGFloat = 24 // Entre seções
static let pageMargin: CGFloat = 40 // Bordas da página (desktop)
static let mobileMargin: CGFloat = 16 // Bordas da página (mobile)
// Largura do conteúdo
static let maxContentWidth: CGFloat = 720 // Leitura ideal
static let wideContentWidth: CGFloat = 960 // Tabelas, galerias
}
Filosofia de Animação
Transições de Página Suaves
// Navegação entre páginas usa matched geometry
struct NavigationTransition: View {
@Namespace private var namespace
@State private var selectedPage: PageReference?
var body: some View {
ZStack {
// Lista de páginas
PageListView(
onSelect: { page in
withAnimation(.spring(response: 0.35, dampingFraction: 0.85)) {
selectedPage = page
}
},
namespace: namespace
)
// Página selecionada expande da posição do card
if let page = selectedPage {
PageDetailView(page: page)
.matchedGeometryEffect(id: page.id, in: namespace)
.transition(.scale.combined(with: .opacity))
}
}
}
}
Animações de Blocos
// Blocos animam ao reordenar
struct AnimatedBlockList: View {
@Binding var blocks: [CraftBlock]
var body: some View {
LazyVStack(spacing: CraftSpacing.blockGap) {
ForEach(blocks) { block in
BlockView(block: block)
.transition(.asymmetric(
insertion: .move(edge: .top).combined(with: .opacity),
removal: .move(edge: .bottom).combined(with: .opacity)
))
}
}
.animation(.spring(response: 0.3, dampingFraction: 0.8), value: blocks)
}
}
Lições para Nosso Trabalho
1. Performance Nativa Vale o Investimento
Usuários sentem a diferença entre latência de 16ms e 200ms. Apps nativos vencem na sensação.
2. Páginas Dentro de Páginas Permitem Organização Orgânica
Deixe a estrutura emergir do conteúdo. Não force usuários a decidir hierarquia antecipadamente.
3. Múltiplos Layouts Visuais para o Mesmo Conteúdo
Cards, listas, galerias—mesmos dados, visualizações diferentes para contextos diferentes.
4. Compartilhar Sem Atrito
Publicação web com um clique remove completamente o problema "como compartilho isso?".
5. Apropriado à Plataforma, Não Idêntico à Plataforma
Craft no Mac parece um app de Mac. Craft no iOS parece um app de iOS. Esse é o objetivo.
Perguntas Frequentes
Como o Craft é diferente do Notion?
O Craft é nativo (construído especificamente para plataformas Apple), enquanto o Notion é baseado em web. Isso significa que o Craft alcança tempos de resposta abaixo de 50ms, funciona totalmente offline e se integra profundamente com recursos do iOS/macOS como Apple Pencil, Atalhos e busca do sistema. O Notion oferece mais recursos de banco de dados; o Craft prioriza a experiência de escrita.
Posso usar o Craft offline?
Sim. O Craft armazena todos os documentos localmente e sincroniza via iCloud quando conectado. Você pode criar, editar e organizar documentos sem internet. As alterações sincronizam automaticamente quando você reconecta.
O que acontece quando compartilho uma página do Craft?
O Craft gera uma página web responsiva em uma URL craft.do. Os destinatários visualizam em qualquer navegador sem criar uma conta ou instalar o app. A página preserva a tipografia, imagens e estrutura de páginas aninhadas do seu documento.
O Craft suporta Markdown?
O Craft usa seu próprio formato de blocos mas exporta para Markdown. Você pode copiar conteúdo como Markdown ou exportar documentos inteiros. Alguns atalhos de Markdown funcionam durante a edição (como # para títulos), mas o Craft enfatiza edição visual sobre marcação de texto puro.
Como funcionam as páginas aninhadas no Craft?
Qualquer bloco de texto pode se tornar uma página pressionando o ícone de página ou digitando /page. Páginas aninhadas aparecem inline no documento pai e podem ser abertas em tela cheia. A navegação breadcrumb mostra sua localização na hierarquia. Isso cria organização natural sem forçar estruturas de pastas antecipadamente.