Touch Grass: 화면에서 벗어나게 하는 음성 도전 과제, Gemma 3 270M으로 온디바이스 구동
요약
본 글은 사용자의 시간과 에너지를 기반으로 야외 활동을 유도하는 PWA 'Touch Grass'를 소개합니다. 이 앱은 Gemma 3 270M 모델을 활용하여 온디바이스 구동이 가능하며, 오직 하나의 도전 과제에 집중하도록 설계되어 디지털 중독 문제를 해결하려는 목적을 가집니다.
핵심 포인트
- Gemma 3 270M 기반의 온디바이스 AI 구현
- 사용자의 시간/에너지 수준에 맞는 야외 활동 제시
- PWA 형태로 서비스 워커 캐싱 및 오프라인 작동 지원
이것은 Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass에 제출하는 작품입니다.
내가 만든 것 (What I Built)
Touch Grass — 가지고 있는 시간과 에너지를 말하면, 밖에 나가 할 수 있는 짧고 구체적인 도전 과제(dare)를 하나 제공합니다. 그것을 완료하고 증거 사진을 찍으면 일일 연속 기록에 포함됩니다. 피드도 없고, 무한 스크롤도 없으며, "'하나만 더 도전할까?'라는 루프도 없습니다. 하나의 과제에 집중하여 밖에 나갔다가 나중에 돌아옵니다.
이것은 PWA(Progressive Web App)입니다. 설치하면 첫 로딩 후에도 서비스 워커(service worker)에 셸(shell)과 모델이 모두 캐시되어 신호가 없어도 계속 작동합니다.
대상 사용자: 휴대폰을 열어 간단한 한 가지를 하려고 했지만, 40분 후에 아무것도 하지 않은 채 발견하는 모든 사람. "시간이 10분밖에 없고 에너지가 낮다"고 말해도 하프 마라톤을 제시하지 않습니다.
데모 (Demo)
🔗 실시간: https://touch-grass-bkii.onrender.com
💻 코드: https://github.com/ibrahim-iqbal/touch-grass
앱 전체는 사용자가 서 있는 작은 야외 세계입니다. 그려진 픽셀 아트 장면이 화면을 채우고, 캐릭터가 잔디밭에 서 있으며, 컨트롤은 게임 HUD처럼 가장자리에 배치되어 있습니다. 중앙의 박스 안에 떠다니는 요소는 없습니다.
테마를 전환하면 동일한 세계가 아늑한 밤에서 따뜻한 낮으로 재조명됩니다. 배경 아트워크는 크로스페이드(crossfade)되고, 달이 사라지며 해가 떠오릅니다.

마이크를 누르고 자신의 시간과 에너지를 말하면, 대화 리본에서 도전 과제가 아래로 슬라이드되어 나타납니다. 이 도전 과제에는 예상 소요 시간과 비용이 표시되며, 카메라를 여는 “외부에서 증명하기(prove it outside)” 버튼이 있습니다.

GitHub logo ibrahim-iqbal / touch-grass
외부로 나가게 하는 음성 도전 과제 — 로컬 Gemma, 백엔드 제로
touch grass
외부로 나갈 수 있게 해주는 음성 도전 과제입니다. 자신이 가진 시간과 에너지를 말하면 짧은 야외 도전 과제가 주어지고, 완료 후 증거 사진을 찍습니다.
hacktoberfest 오픈 소스 AI 챌린지 1주차: “touch grass”를 위해 제작되었습니다.
왜 공개하는가 (why open)
- 도전 과제 생성은 호스팅된 API가 아닌 transformers.js를 통해 gemma 3 270m에서 온디바이스(on-device)로 실행됩니다.
- 신호가 없어도 첫 로드 후 작동합니다 — 서비스 워커가 페이지와 모델을 캐시합니다.
- 사용자가 말하거나 입력하는 내용은 브라우저를 벗어나지 않습니다. 사용자의 hugging face 토큰과 elevenlabs 키(둘 다 선택 사항)는 로컬에 저장되어 기기에서 직접 사용됩니다.
- 모델을 교체하거나,
dares.json을 편집하거나, 생성 단계를 완전히 제거할 수 있습니다 — 모든 것이 순수 js입니다.
실행 방법 (running it)
빌드 단계가 없는 정적 사이트일 뿐입니다.
python3 -m http.server 8000
localhost:8000을 여세요. 음성 입력에는 Chrome 또는 Edge가 필요합니다 (다른 곳에서는 웹 스피치 API 지원이 불안정할 수 있습니다)...
음성 입력은 Chrome 또는 Edge가 필요합니다 (다른 곳에서는 Web Speech API 지원이 불안정합니다). 카메라 증명(Camera proof)에는 HTTPS 또는 localhost가 필요하며, 이는 라이브 링크에서 모두 충족됩니다.
제작 과정
프레임워크나 빌드 단계, 백엔드 없이 순수 HTML/CSS/JS로 구현했습니다. 몇 가지 의도적인 선택이 있었습니다:
-
기본 모드는 설정이 전혀 필요 없습니다. 시간/에너지/장소를 말하면, 이것이 소규모 큐레이션된 도전 과제 은행(
dares.json)과 일치하는 것을 찾아 브라우저 자체의speechSynthesis로 결과를 음성 출력합니다. 이는 구성할 것이 아무것도 없는 오프라인 상태에서도 항상 작동합니다. -
선택적 스마트 레이어: Gemma 3 270M을 transformers.js를 통해 사용합니다. 설정에 Hugging Face 토큰을 붙여넣으면 도전 과제 생성기가 모델로 전환되며, 이는 호스팅된 API 호출이 아닌 WASM을 통해 브라우저 내에서 완전히 실행됩니다. 요청 내용 중 어느 것도 장치를 벗어나지 않습니다.
-
선택적 음성 레이어: ElevenLabs 역시 같은 패턴입니다. 사용자의 키가 직접 브라우저에서 사용되며, 언제든지 내장된 목소리로 다시 전환할 수 있습니다.
-
UI는 양식(form)이 아니라 게임 HUD입니다. 칠해진 픽셀 아트 세계가 화면을 채우고 캐릭터가 그 안에 서 있으며; 레벨, 스탯, 컨트롤은 RTS처럼 모서리에 고정되고, 각 도전 과제는 RPG처럼 슬라이드업 대화 리본에 나타납니다. 배경 아트는 주야간으로 구성되어 테마를 전환할 때 교차 페이드(crossfade)되며, 미끄러지는 태양/달, 떠다니는 구름과 잎사귀가 스트릭이 늘어남에 따라 채워집니다.
-
서비스 워커(Service Worker)가 앱 쉘(app shell)을 캐시합니다. 따라서 모델을 다운로드한 후에도 연결 없이 전체 애플리케이션이 작동합니다. 이것이 바로
-
Camera proof는
getUserMedia와 canvas를 사용하며 방어적인 타임아웃을 적용했습니다. 이는 카메라가 없는 장치에서getUserMedia가 거부되는 대신 무한정 멈출 수 있다는 점(이 경우 UI에 빠져나갈 방법이 없음)을 직접 확인했기 때문입니다. -
**Render**에 정적 사이트로 배포되었으며, 푸시할 때마다
main브랜치에서 자동 배포됩니다.
Open Innovation이 중요한 이유
이 특정 형태가 오직 모델이 오픈 웨이트(open-weight)이기 때문에만 작동하는 두 가지 이유가 있습니다:
1. 제가 호스팅한 것이 전혀 없어도 실제로 실행될 수 있다는 점입니다. 백엔드도 없고, 제 API 키도 루프에 포함되지 않으며, 사용량에 따라 늘어나는 청구서도 없습니다. 더 똑똑한 도전 과제 생성을 원하는 사용자는 자신만의 무료 Hugging Face 토큰을 가져와 모델이 그들의 장치에서 다운로드되어 실행됩니다. 그 요청은 제가 통제하는 서버에 도달하지 않기 때문에 저는 볼 수 없습니다. 폐쇄형 API를 사용하면 호스팅된 프록시가 강제되는데, 이는 비용 센터를 의미하고, 제가 사용자들에게 신뢰해 달라고 요청해야 하는 개인 정보 보호 경계이며, 청구서를 지불하는 것을 멈추는 순간 단일 실패 지점이 됩니다.
2. '완전히 선택적(fully optional)'이라는 것이 실제로 진실성을 갖게 했습니다. Gemma 3 270M이 클라이언트 측에서 실행할 만큼 작기 때문에,
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기
