desenvolvemos o origo como parte de um desafio focado em solucionar problemas de profissões específicas. a ideia era substituir as pranchetas e papéis usados em sítios arqueológicos por uma solução digital robusta. o aplicativo permite o cadastro detalhado de artefatos, incluindo dados técnicos como materiais, técnica de produção e estado de conservação, além de informações do sítio e número do processo.
mais do que um simples formulário, o origo atua como um companheiro de campo multimídia, permitindo anexar fotos e gravações de áudio a cada ficha, consolidando todas as informações da escavação em um único dispositivo.
do ponto de vista técnico, o origo foi um mergulho profundo no SwiftData para persistência local, lidando com modelos complexos que conectam artefatos a mídias variadas. a integração com o Google Maps SDK foi essencial para capturar coordenadas precisas, que convertemos para o formato UTM (padrão na arqueologia).
outro destaque foi a implementação da API de Speech, que transcreve automaticamente as notas de áudio gravadas pelo usuário em texto, economizando tempo valioso de digitação. a interface, construída 100% em SwiftUI, gerencia fluxos de entrada de dados densos sem sacrificar a clareza e a usabilidade.
design choices
palette
bedrock#472500rust#C54302dust#F6D2B2river#436187
typography
Brasilero 2018 Free/onboarding e logotipo
Zebras jogam xadrez com o velho faquir
SF Pro Display/interface primária
Zebras jogam xadrez com o velho faquir
some fonts used in this project are proprietary and may not display correctly if they are not installed on your system.
rationale
origo é um aplicativo feito para ajudar arqueólogos com o trabalho de registro e catalogação de artefatos achados em campo.
considerando o propósito do app, a paleta de cores foi inspirada em tons terrosos e naturais, remetendo à terra e aos artefatos encontrados durante escavações.
as cores escolhidas transmitem uma sensação de conexão com a natureza e o passado histórico.
a tipografia busca inspiração na cultura popular brasileira para o onboarding e a escrita do nome do aplicativo, por meio da fonte Brasilêro, criada a partir da análise de milhares de placas e sinais escritos à mão em comunidades urbanas e rurais por todo o Brasil.
escolhemos essa fonte por remeter à cultura nacional e trazer um toque humano e artesanal ao design.
para o restante do aplicativo, utilizamos a fonte SF Pro Display, que é moderna, limpa e altamente legível em telas digitais, garantindo uma experiência prática e nativa de leitura para os usuários.
além disso, o aplicativo conta com mais um detalhe artesanal que remete ao trabalho em campo:
escaneamos diversas folhas e pequenas plantas, cujas silhuetas foram vetorizadas e utilizadas como ornamentos e detalhes visuais no onboarding e no logotipo do app, reforçando a conexão com a natureza e o ambiente arqueológico.
tech stack
SwiftUI
framework de UI
SwiftData
persistência local
Google Maps SDK
serviços de localização
AVFoundation
manuseio de áudio
code snippets
Gerenciamento de Estado de Rascunho
swift
class RecordDraft: ObservableObject { @Published var id: UUID = UUID() @Published var name: String = "" @Published var createdAt: Date = Date() @Published var location: LocationInfoModel? = nil @Published var artifactData: ArtifactDataModel? = nil @Published var artifactDetails: ArtifactDetailsModel? = nil @Published var audios: [AudioModel] = [] @Published var photos: [CapturedImageModel] = [] @Published var geolocation: MapMarkerModel? = nil var asRecordModel: RecordModel { let artifact = ArtifactModel( location: location, artifactData: artifactData, artifactDetails: artifactDetails ) return RecordModel( id: id, name: name, createdAt: createdAt, artifact: artifact, audios: audios, photos: photos, geolocation: geolocation ) }}
Transcrição de Fala
swift
class AudioTranscriber: ObservableObject { @Published var transcription: String = "" private let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "pt-BR")) private var request: SFSpeechRecognitionRequest? func transcribeAudio(url: URL) { SFSpeechRecognizer.requestAuthorization { [weak self] authStatus in guard authStatus == .authorized else { return } self?.request = SFSpeechURLRecognitionRequest(url: url) self?.request?.requiresOnDeviceRecognition = true guard let recognizer = self?.recognizer, recognizer.isAvailable else { return } guard let request = self?.request else { return } recognizer.recognitionTask(with: request) { result, error in DispatchQueue.main.async { if let result = result { if result.isFinal { self?.transcription = result.bestTranscription.formattedString } } else if let error = error { self?.transcription = "" } } } } }}