외부 활동에 초점을 맞춘 명상 앱을 만들다
요약
본 글은 외부 활동에 초점을 맞춘 명상 앱을 개발하는 과정을 다루며, 기존의 수면 유도형 명상 앱의 한계를 지적합니다. 사용자가 눈을 뜨고 주변 환경에 집중하며 진행할 수 있도록 설계하여, 화면에서 벗어나 실제 경험과 연결되는 새로운 사용자 경험(UX)을 제시했습니다.
핵심 포인트
- 명상을 위해 '눈을 감는' 전통적인 방식을 탈피함.
- 외부 활동에 초점을 맞춰 시야를 유지하는 명상 가이드를 제공함.
- 스크린 기반의 중독성 요소를 의도적으로 제거하여 사용자 경험을 개선함.
- 위치 접근 권한, 연속 기록 등 앱의 핵심 기능을 최소화하고 본질적인 기능에 집중함.
이 글은 Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass 제출물입니다.
제가 만든 것
제가 사용했던 모든 명상 앱은 같은 방식으로 시작합니다.
눈을 감으세요.
이것을 산책로에서 시도해 보세요.
이 하나의 지침 때문에 가이드 명상과 실제로 야외에 있는 경험은 결합되기 어렵습니다. 이 앱들은 어두운 침실을 가정합니다. 하지만 야외에서는 발 디딜 곳, 교통 상황, 그리고 당신이 이곳에 나와서 바라보려고 온 바로 그 대상이 눈앞에 있다는 사실 때문에 시야가 필요합니다. 따라서 명상을 하려면 실내에 머물거나, 아니면 밖에 나가 진행률 원(progress ring)을 쳐다봐야 합니다.
외부 활동에 초점을 맞춘 앱은 세 번째 선택지입니다. 즉, 눈을 뜨고 실제 3분간의 명상을 안내하는 목소리이며, 작동하지 않는다고 말하면 적응하고, 그리고는 조용히 사라집니다.
순서는 다음과 같습니다:
'명상 시작하기(Begin a meditation)'를 누르고, _'부드러운 호흡(Gentle breathing)'_을 선택하자 목소리가 이렇게 말합니다:
그 보장이 바로 제품입니다. 《내가 이것을 만든 방법(How I Built It)》에 있는 모든 것이 그것이 강제되는 방식입니다.
화면에서 벗어나게 하는 방법
화면 기반 제품에서 스크린을 제거한다는 것은 앱을 중독성 있게 만드는 요소들을 포기하는 것을 의미합니다. 저는 의도적으로 그 대부분의 요소를 포기했습니다:
- 항상 눈을 뜨고 지내기. 모델에게는 절대 "눈을 감으라"고 말하지 않도록 지시했으며, 검증기(validator)의 정규표현식(regex)은 만약 이 말이 새어 나오더라도 응답을 거부합니다. 호흡, 신체, 듣기, 생각으로 휴식하기 등 모든 수련은 눈이 세상에 고정된 상태에서 이루어집니다.
- 호흡 원은 포기하도록 설계되었습니다. 이 기능은 내레이션이 끝난 후에 시작되며, 아래 캡션에는 "몇 번의 호흡을 위해 따라오거나, 시선을 돌려 자연스럽게 숨 쉬세요"라고 적혀 있습니다.
- 녹음 트랙은 잠긴 화면을 위해 제작되었습니다. 두 번째 모드는 고정된 3분, 5분 또는 10분짜리 트랙을 구성합니다. 이 트랙은 JavaScript 타이머가 아닌 FFmpeg에 의해 프롬프트 사이에 실제 침묵이 삽입된 실제 내레이션으로 이루어져 있어, 재생 버튼을 누르고 휴대폰을 잠근 뒤 주머니에 넣을 수 있습니다.
- 홈 화면에는 버튼이 하나만 있습니다. 여러 모드의 메뉴가 아닙니다. 연결되어 있을 때는 라이브 가이드(live guide)를, 그렇지 않을 때는 오프라인 샘플을 제공하는 단 하나의 동작입니다.
- 위치 접근 권한 없음. 요청하지 않았고, Info.plist에도 없으며, 사용되지도 않습니다. "외부(Outside)"는 좌표가 아니라 당신이 하는 행위입니다.
- 계정, 연속 기록(streak), 알림, 피드가 없습니다. 돌아올 만한 것이 아무것도 없습니다.
- 마지막 성찰 기록은 저장되지 않습니다. 마지막 화면에서는 기분이 어떤지 묻고 있으며, 작은 글씨에는 이 내용이 "이 화면에 머무르며 어딘가에 저장되거나 전송되지 않는다"고 진실하게 명시되어 있습니다.
대화 메모리는 백엔드(backend)에서 10분 후에 만료되며, **완료(Finish)**를 탭하면 모든 오디오 클립과 함께 즉시 삭제됩니다.
대상 독자
이미 야외 활동을 하는 사람들—걷기 운동을 하거나, 개를 산책시키거나, 인터벌 트레이닝을 하는 달리기 선수, 점심시간에 벤치에 앉아 있는 사람 등—그리고 그들과 함께 안내된 수련(guided practice)을 가져간 적이 없는 사람들이 있습니다.
특히 표준 버전으로는 작동하지 않는 사람들, 즉 호흡에 초점을 맞춘 명상(breath-focused meditation)이 어지럽거나 불안하게 만드는 사람, 또는 공공장소에서 단순히 눈을 감을 수 없는 사람들을 위한 것입니다. 그런 사람들에게는 다른 앱을 사용해 보라고 권유받습니다. 이 앱은 "그것 말고"라는 말을 듣고 경청하도록 만들어졌습니다.
데모 (Demo)
아이폰으로 녹음된 실제 세션: 호흡 연습, 호흡을 멈추라는 음성 요청, 그리고 가이드가 신체 이완(body relaxation)으로 전환하고 나머지 세션 동안 그 상태를 유지하는 모습입니다.
코드 (Code)
GitHub logo defiantlydefying / outside
오픈 가중치(open-weight) Gemma 모델이 안내하는 짧은 야외 명상. 호흡법이 효과가 없다고 말하면 전환되고, 다시는 그 방법을 제안하지 않습니다. 눈을 뜨고, GPS 없이, 돌아갈 것이 아무것도 없습니다.
Outside
휴대폰을 치우세요. 이곳으로 돌아오세요.
모든 명상 앱은 사용자에게 눈을 감으라고 안내하며 시작합니다. 이것을 트레일에서 시도해 보세요.
Outside는 눈을 뜨고 할 수 있는 짧은 야외 명상을 위한 아이폰 앱입니다. 부드러운 목소리가 호흡, 신체 이완 또는 조용한 주의(quiet attention)를 안내합니다. 언제든지 가이드를 변경하고 싶을 때 말하세요—호흡법이 효과가 없다고 말하면 신체 이완으로 전환되고, 나머지 세션 동안 다시는 호흡법을 제안하지 않습니다.
오픈 가중치 Gemma 모델이 Mastra를 통해 그 결정을 내립니다. 이 모델이 따르는 지침, 충족해야 하는 스키마(schema), 그리고 응답에 대한 안전 점검은 모두 이 저장소에 있으며, 여기서 읽고 수정할 수 있습니다.
외부 활동에 초점을 맞춘 명상 앱을 만들다
[이번 청크]
Hacktoberfest Open Source AI Challenge: Touch Grass를 위해 제작되었습니다(https://dev.to/devteam/join-the-hacktoberfest-open-source-ai-challenge-week-1-touch-grass-2450-in-prizes-across-17-4pom).
경험 (The experience)
- 야외의 편안한 장소에 앉아 명상 시작 · 3분을 누릅니다. 이것이 홈 화면의 유일한 동작입니다.
- …
MIT 라이선스입니다. SETUP.md에는 호스팅된 Gemma 또는 로컬 Ollama를 대상으로 백엔드를 실행하는 방법이 설명되어 있으며, TESTING.md에는 휴대폰에서 테스트하는 방법이 설명되어 있습니다.
제작 과정 (How I Built It)
iPhone (Expo / React Native)
│ 음성 응답 → M4A
▼
...
Gemma가 결정합니다. 모든 적응형 전환은 오픈 웨이트 모델(open-weight model)로 전송되며, 이 모델은 단순히 단어뿐만 아니라 앱이 동작할 수 있는 작은 구조화된 객체(structured object)를 반환합니다:
export const replySchema = z.object({
text: z.string().trim().min(1).max(500),
mode: z.enum(['listen', 'quiet', 'finish']),
...
이 practice 필드가 현기증 이야기(dizziness story)가 작동하게 만드는 요소입니다. 이는 텍스트에 붙은 레이블이 아니라, UI가 읽어서 호흡 원(breathing circle)을 표시할지 풍경화(landscape)를 표시할지를 결정하는 필드이며, mode와 quietSeconds는 앱이 사용자의 목소리를 들을지 아니면 40초 동안 침묵할지를 결정합니다. 모델이 텍스트 상자를 채우는 것이 아니라 인터페이스 자체를 주도하고 있습니다.
Mastra는 이를 타입이 지정된 에이전트(typed agent) 및 워크플로우로 구현합니다. 대화 턴은 Zod structuredOutput 스키마를 대상으로 agent.generate()를 호출하는 createStep을 포함하는 createWorkflow입니다. 녹음 세션 파이프라인은 세 단계의 워크플로우 — personalize-with-gemma → check-guidance → narrate-and-build-quiet-spaces로 구성됩니다. OpenAI와 호환되는 엔드포인트 뒤에 있는 오픈 웨이트 모델(open-weight model)에서, 제공자 설정(provider config)을 일반 데이터 형태로 사용하여 스키마 검증이 완료된 출력을 얻는 부분이 Mastra가 제가 직접 작성해야 할 코드를 진정으로 절약해 준 부분입니다.
모델이 반환하는 어떤 내용도 신뢰하지 않습니다. validateReply는 스키마를 재파싱하고, 발화 답변을 65단어로 제한하여 한 턴이 3분 타이머를 소모하는 것을 막으며, 만약 해당 답변이 /hold your breath|breathe deeply|close your eyes|you are safe|cure|diagnos|guaranteed/i와 일치하면 전체 답변을 거부합니다. 시스템 프롬프트는 또한 사용자가 말한 내용을 지침(instruction)이 아닌 신뢰할 수 없는 설명 데이터로 취급하므로,
ElevenLabs는 양방향 처리를 담당합니다. 전사(transcription)를 위한 Scribe v2와 음성 생성을 위한 Flash v2.5(대화용 Sarah, 녹음 트랙용 River)가 그것입니다. FFmpeg은 Render 컨테이너에서 내레이션과 실제 무음 간격을 하나로 합쳐 연속적인 파일로 만듭니다. Render는 도커 백엔드를 가장 작은 유료 인스턴스에 배포하여, 사용자가 서버가 깨어날 때까지 들판에 서서 기다리는 상황을 방지합니다.
오픈 혁신(Open Innovation)이 중요한 이유?
솔직한 대답은 '개인정보 보호'나 '비용'이 아닙니다. 물론 이 두 가지도 도움이 되지만, 핵심은 **행동의 검사 가능성(inspectability of behavior)**입니다.
이 앱이 약속하는 유일한 것은 사용자가 호흡법이 효과가 없다고 말할 때, 그것이 멈춘다는 것입니다. 단지 한 번의 차례에만 멈추는 것이 아니라 영구적으로 멈춥니다. 이것은 기능(feature)이 아니라 안전 속성(safety property)입니다. 그리고 폐쇄적이고 호스팅되는 모델로는 실제로 그러한 약속을 할 수 없습니다. 저는 제가 설명할 수는 있지만 사용자가 감사(audit)할 수 없는 엔드포인트로부터 행동을 임대하고, 제 귀에 음성을 넣는 그 대상을 고정할 방법이 없기 때문입니다.
Gemma를 사용하면 전체 체인이 읽을 수 있는 하나의 저장소 안에 존재합니다. 지침(instructions), Zod 스키마, 검증자 정규식(validator regex), 단어 제한, 모델 ID가 모두 여기에 있습니다. 만약 제가 불안해하는 사람에게 명상 앱이 무엇을 말해야 하는지에 대한 판단을 믿지 못한다면, 제 말을 믿을 필요가 없습니다. 프롬프트를 읽고 직접 변경할 수 있기 때문입니다. 웰빙 도구의 경우, '무엇에 대해 들었는지(you can read what it was told)'를 읽을 수 있다는 것이 신뢰의 전반적인 기반이 됩니다.
오픈 웨이트(Open weights)는 또한 배포가 고정된 지점이 아님을 의미합니다. GEMMA_BASE_URL은 단지 환경 변수일 뿐입니다. 이를 로컬 Ollama에서 실행되는 gemma3:4b를 가리키도록 설정하면, 전체 적응형 루프(adaptive loop)는 기기 내에서 아무것도 외부로 나가지 않고 노트북에서 실행됩니다. 앱은 차이를 감지할 수 없습니다. 저는 그것을 위해 설계한 것이 아니라, 하나의 공급업체 API 구조에 의존하지 않음으로써 무료로 얻게 된 것입니다. 그리고 서버는 GEMMA_MODEL이 Gemma 모델 이름을 지정하지 않으면 대화를 시작하는 것을 거부함으로써 이를 강제합니다. 폐쇄형 언어 모델로 조용히 대체되는(quiet fallback) 경우는 없습니다.
과장하지 않을 것: 제가 제출하는 배포본은 호스팅된 Gemma 추론(inference)과 독점적인 ElevenLabs 음성을 사용합니다. 이는 오프라인이거나 완전히 오픈 소스 스택이 아닙니다. 오픈 웨이트 모델은 핵심을 이루며 교체 가능하지만, 오늘의 음성은 그렇지 않습니다. 전체를 로컬에서 실행하는 것은 지원되는 구성일 뿐, 제가 배포한 방식은 아닙니다.
나의 에이전트 세션
Codex Session openai
에이전트
당신의 가장 강력한 기회는 스트레스 받는 사람이 최소한의 노력으로 야외 휴식을 시작하도록 돕는 것입니다. 연구들은 이를 탐색하는 것을 지지하지만, 음성 AI와 개인화는 이미 명상 앱에 존재합니다. 차별화되는 부분은 사용자의 실제 주변 환경에 기반을 둔 안내(guidance)를 제공하고, 그 경험을 할 수 있을 만큼 충분한 침묵을 제공하는 것입니다.
저는 공식 앱 설명과 연구 논문들을 검토했습니다. 이것은 책상 위에서의 연구 비교이며, 제가 직접 앱들을 테스트한 것은 아닙니다.
기존 앱들이 이미 제공하는 것들
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기
