점검 중입니다
문의: 2026icoach@gmail.com
2026.5.1 (금) ~ 5.31 (일)
프로야구 선수 싸인볼
수상 상품(프로야구 선수 싸인볼)을 받으시려면
아래 연락처 정보를 입력해주세요
images/headers/ 폴더로 정리.sw.js ASSETS_TO_CACHE에 헤더 이미지 2장 추가, CACHE_NAME icoach-v207 → icoach-v208 갱신.preVerifyDrillVideoLocal() 이 VIDEO 모드로 생성된 poseLandmarker 에 IMAGE-모드 전용 메서드 .detect() 를 호출해서 매 프레임 silent failure 발생. try/catch 가 에러를 삼키고 결과를 null 로 처리 → 검출 0건 → "0/6프레임. 전신이 보이도록 다시 촬영" 오해 유발.quickDrillAnalysis() (드릴 영상에 즉시 관절각도 표시) · analyzeDrillVideo() (다중 프레임 드릴 폼 분석) 도 동일하게 .detect() 잘못 호출. 두 함수 모두 silent failure 로 항상 null 반환 → 드릴 폼 분석 결과 미표시 버그가 있었으나 오류 메시지 없이 묻혀 있었음. 이번 릴리스에서 함께 수정.poseLandmarker 가 null 이라 사전검증을 스킵해서 통과됨(그래서 일관성 없게 보이는 버그였음).window._poseLandmarkerMode 추적 변수 도입. 사전검증에서 모드를 읽고 분기: VIDEO 모드면 detectForVideo(canvas, ts) 호출(단조증가 ms 타임스탬프 전달), IMAGE 모드면 detect(canvas), LIVE_STREAM 모드면 사전검증을 스킵하고 Gemini 검증으로 위임.performance.now() 를 베이스로 사용, 프레임마다 +100ms 증가. 페이지 로드 후 항상 증가하는 값이라 영상 분석이 이미 사용한 어떤 타임스탬프 범위와도 충돌하지 않음.catch(e) 블록에 console.error 추가. 같은 종류의 silent failure 가 다시 생기면 콘솔에서 즉시 식별 가능 (이전엔 영구히 묻혀 있었음).checkModeMismatch() 의 투구 모드 검증을 4-조건 AND 로 강화. 기존 (swingR>0.3, oneArmR<0.1) 두 조건만으로는 측면 카메라 와인드업이 양손 중심점을 어깨너비 1.5배 넘게 이동시켜 오탐 발생.peakArmExtension: 영상 전체에서 한 팔이 어깨너비 대비 가장 멀리 뻗은 비율 (피크값). 한 프레임이라도 어깨×2 이상 뻗어지면 투구로 인정. (2) wristAsymmetryX: 좌·우 손목 X 이동 범위의 비대칭도(0~1). 0에 가까우면 배트 그립처럼 두 손이 함께 움직임, 1에 가까우면 던지는 팔만 멀리 이동._icoachCropActive) 임계값 — 0.5 → 0.7 로 더 보수적으로 조정. 줌인 영상에서 false-positive 가능성을 추가로 낮춤.showEventPopupForce(), _isEventPeriod()는 코드에 남겨둠. 향후 동일 카드 재추가 시 즉시 활용 가능.EVENT_ANALYST · EVENT_BATTER · EVENT_PITCHER · EVENT_DEFENDER · EVENT_BUG · EVENT_TRAINER · EVENT_SIGNBALL. 기존 TROPHY · BATTING · FIRE 등은 다른 화면에서 그대로 사용.showEventPopup() 호출. 일회성 강제 표시이지만 닫을 때는 다시 일반 동작.closeEventPopup()이 "확인"·"오늘 그만 보기" 어느 쪽으로 닫혀도 무조건 today 키를 localStorage에 저장 → 한 번이라도 확인을 누르면 그날은 팝업이 다시 안 뜸. 사용자 의도는 "확인=일단 닫기, 다음 진입 시 또 보기" / "오늘 그만 보기=오늘은 더 안 보기" 가 분리되어야 정상.closeEventPopup(): 단순 닫기(키 저장 X) · dismissEventPopupForToday(): 오늘 그만 보기 전용(키 저장 O). "확인" 버튼은 단순 닫기, "오늘 그만 보기" 버튼만 today 키 저장.Object.keys(localStorage).filter(k=>k.startsWith('icoach_event_popup_')).forEach(k=>localStorage.removeItem(k)) 입력해 키 제거 가능 (또는 자정 지나면 자동 해제).BUG_REPORT 신규 키 추가(./icon_bug_report.png 매핑). sw.js 캐시 자산 목록에 이미 등록돼 있어 PWA 오프라인에서도 정상 표시.inp-age 드롭다운에 옵션만 추가.localStorage에 저장 (icoach_sound_volume, icoach_bgm_volume, icoach_bgm_enabled). 다음 실행에도 자동 적용.tap 효과음이 바로 재생되어 볼륨 미리듣기 가능.window.__icoach_throwarm_debug 글로벌에 종합 점수와 5개 raw 지표를 모두 노출. 관리자 콘솔에서 던지는 팔 오선택 의심 시 즉시 수치 확인 가능.todayKey() 가 UTC 기준 날짜를 반환해 한국(UTC+9) 사용자의 로컬 날짜와 불일치, 주간 스케줄·커스텀 드릴 모두 "오늘" 을 찾지 못해 빈 화면이 되던 문제. 로컬 시간 기반으로 전환.getCustomDrillsForToday() 와 날짜 불일치. todayKey() 통일.getWeeklySchedule() 의 JSON.parse 에 try/catch 추가. 손상된 캐시는 자동 삭제 후 재생성.ReferenceError 방지를 위해 typeof 가드 추가.every() 가 vacuous truth 를 반환하는 JS 특성 때문에 드릴 없이도 완료 판정. drills.length>0 가드 추가._added / _addedH 함수의 dateKey 도 todayKey() 로 통일.icoach_install_dismissed_forever 정책 폐기. 새 정책 icoach_install_dismissed_at 타임스탬프 기반 — 7일 경과 시 자동 재노출. 기존 사용자의 영구 차단 키는 마이그레이션으로 제거되어 다음 방문 시 다시 안내받습니다.setTimeout(...5000) → 1000ms.window.appinstalled 이벤트가 발생, 모든 안내 UI 즉시 숨김 + "🎉 홈 화면에 추가됐어요!" 성공 토스트.padding:6px 12~14px · font-size:11px · white-space:nowrap · line-height:1. 폰트 두께는 골드 강조(백업: 700) / 중립(펼치기: 600) 로 차등해 시선 유도 유지.<br> 으로 아래 줄로 내려 깔끔한 2줄 레이아웃
white-space:nowrap 추가 → 항상 1줄 유지
<span display:block> 2개로 의도적으로 "수동" / "백업" 2줄 스택
flex:1 min-width:0, 버튼 영역 flex-shrink:0 으로 모바일 폭이 좁아도 버튼이 찌그러지지 않음.<details> 접힘으로 숨김. 일반 사용자에게는 2개만 보이고 고급 옵션은 필요할 때만 열림. 기능은 그대로 유지되지만 "어디서 시작해야 하는지" 명확해짐.syncHistoryBoth(), manualSaveVersionBackup(), exportData(), importData() 는 모두 기존 동작 그대로. 순수 UI 재구성.localStorage.icoach_user_armslot 에 저장되어 다음 번에도 유지. 기본값은 '오버핸드' (한국 초중등 야구에서 가장 흔함). 투구 모드에서만 표시되고 타격·수비에는 영향 없음.사용자=overhand · 적용=overhand · 원판정(자동)=sidearm 처럼 3개 값이 모두 표시되어 경계 케이스 데이터 계속 수집 가능.classScore = peakUpAng/200 + (-avgElev) × 1.5 단일 스칼라를 도출 — 오버핸드 최고 1.05, 사이드암 최저 1.18 로 자연스러운 경계 1.15 발견. 기존 수많은 임계값을 이 한 줄로 대체.classScore < 1.15 → 오버핸드 (V1~V7 케이스 커버)
classScore ≥ 1.15 → 사이드암 (S1~S5 케이스 커버)
classScore ≥ 1.80 AND avgElev < -0.55 → 언더핸드 (극단적 케이스만, 거의 사용 X)
detectCameraView()(β 1.4.38) 가 'side' 를 반환한 경우에만 분류기 가동. 정면/뒷면/사선/불명 카메라는 측정값 자체가 왜곡되므로 자동으로 오버핸드 고정 — 별도 사용자 조작 없이 안전하게 보호됩니다. 명시적 강제 OFF 가 필요하면 콘솔에서 window.__icoach_detect_armslot = false.classScore 와 view 추가. 한눈에 "분류 근거 점수" 와 "카메라 각도" 를 확인 가능. text 영역에는 새 공식과 임계값을 명시.|LS.x - RS.x| / |avgShoulderY - avgAnkleY| 의 중앙값을 계산. 측면 촬영은 어깨가 카메라 기준 edge-on 이라 비율 < 0.20, 정면/뒷면은 양 어깨가 다 드러나 비율 > 0.30, 그 사이는 사선으로 분류. 연산은 프레임당 O(1) 이라 전체 오버헤드 무시 가능.pitchA, batA, fieldA(땅볼), fieldA_fly(플라이), catcherA(포수), outfield(외야) 6개 분석기 모두에 카메라 안내 카드 인젝션. 진단 덤프는 window.__icoach_view_debug 에 중앙값·샘플 수 저장.return 'underhand' 해버려 자동 감지 OFF 상태임에도 언더핸드 라벨이 튀어나오는 버그. 오버핸드 투구 영상을 "언더핸드 투구폼 감지"로 오분류하는 리포트 재발.detectArmSlot() 의 12단계 캐스케이드에서 (4)~(9) 오버핸드 확정과 (10) 언더핸드 확정은 조기 return, (11) 사이드암만 wouldBe 변수 경유 → SAFE MODE 적용을 받았습니다. 즉 SAFE MODE 는 사이드암은 막았지만 언더핸드는 못 막는 비대칭 구조였습니다. 또한 조기 return 으로 인해 진단 카드의 원판정 필드가 언더핸드 케이스에서 n/a 로 찍혔습니다 (wouldBe 를 저장하는 코드에 도달하기 전에 함수 종료).wouldBe 변수에 누적, 맨 마지막에 SAFE MODE 체크 한 곳에서만 최종 return. 모든 분류 결과가 SAFE MODE 를 반드시 통과.wouldBe 가 항상 window.__icoach_armslot_debug 에 포함됨. 이제 관리자 카드 제목에 원판정=overhand / sidearm / underhand 가 실제 판정대로 찍혀 SAFE MODE 가 어떤 내부 판정을 차단했는지 확인 가능.getRuleBasedResponse 의 switch 문이 default 로 먼저 떨어지면서 drills=getGeneralDrills(...) 로 드릴이 세팅되고, 그 뒤의 thanks/encouragement 처리는 response 만 덮어쓰고 drills 는 그대로 두는 구조였습니다. 이제 thanks/encouragement/affirm/negate/warmup_q/frequency_q/why_q 분기에서 모두 drills=[] 로 초기화.getGeneralBattingResponse/PitchingResponse/FieldingResponse 를 모두 점수대 × 4개 템플릿 풀로 확장하고 icoach_chat_rot_<key> localStorage 카운터로 순차 로테이션. 같은 점수대여도 매번 다른 멘트.recognizeIntent 에 warmup_q(스트레칭/준비운동/웜업) · frequency_q(매번/매일/자주/얼마나/몇 번) · why_q(왜/이유/어째) · affirm(네/응/오케이) · negate(아니/안/싫어) 5종 추가. "스윙 준비 스트레칭도 매번 해야되나요?" → warmup_q + frequency_q 범위로 들어와 실제 준비운동 빈도 지침을 응답하도록 함..screen.active(선택자 2개, 특수성 0,0,2,0) 가 display:block 을 강제, .chat-screen(0,0,1,0) 의 display:flex 를 특수성 밀려서 덮어쓰지 못했습니다. 결과적으로 채팅 화면이 실제로는 block 으로 렌더링되어 .chat-messages 의 flex:1 이 무력화됨. 메시지가 쌓이면 컨테이너 높이가 내용만큼 계속 늘어나고, 그만큼 전체 스크린 높이도 늘어나 chat-input-area 가 뷰포트 밖으로 밀려난 것. 스크롤 JS 는 정상 동작해도 입력창이 눈에 안 보이니 채팅을 이어갈 수 없었습니다..screen.chat-screen 선택자로 display:flex + padding-bottom:0 + height:calc(100dvh - 65px) 재선언. .screen.chat-screen.active(0,0,3,0) 에도 display:flex 명시로 최종 확정. 안전장치로 !important 병행. 이제 chat-header/chat-messages/chat-input-area 가 제대로 flex 기반으로 배치되어 chat-messages 만 내부 스크롤되고 input 은 항상 바닥에 고정.100vh 는 모바일 브라우저의 URL 바 표시/숨김에 따라 값이 요동쳐 가상 키보드 띄웠을 때 입력창이 사라지는 부수 문제가 있었는데, 100dvh(dynamic viewport height) 로 교체해 안정화. 구형 브라우저는 기존 100vh 규칙이 폴백으로 남아있습니다.scrollChatToBottom() 은 scrollTop = scrollHeight 를 동기적으로 한 번만 호출했는데, 코치 아바타나 드릴 아이콘 <img> 가 비동기로 로드되면서 실제 높이는 그 뒤에 확정 → 최초 스크롤 시점에는 아직 늘어나지 않은 높이만 반영돼 중간쯤에서 멈췄습니다.requestAnimationFrame 중첩 2회 (레이아웃 반영 후) (3) 200ms · 600ms 지연 타이머 (4) 로드되지 않은 <img> 에 load·error 리스너 부착해 실제 이미지 로드 시 재스크롤. 모바일의 느린 네트워크에서도 확실히 바닥에 붙습니다.🔧 관리자 진단 카드가 일반 피드백 카드 렌더러를 타면서 "현상 / 원인 / 교정" 3단 템플릿에 억지로 끼워맞춰져, 원인·교정 자리에 "이 부분을 개선하면 부상 예방..." 같은 상용구가 자동 생성되고 있었습니다. 진단 정보가 코칭 피드백처럼 표시돼 혼란을 줬습니다.🔧 로 시작하면 렌더러가 이를 감지해 3단 템플릿을 건너뛰고, 제목 / text / detail 을 모노스페이스 한 블록으로 표시합니다. 접힘 토글과 화살표를 제거해 항상 펼친 상태로 노출 — 관리자가 스크린샷 한 장으로 모든 수치를 캡처할 수 있도록. 메인 분석 결과 렌더러와 히스토리 상세 렌더러 양쪽에 동일하게 적용.detectArmSlot() 의 측정·분류 코드는 그대로 유지한 채, 최종 리턴 직전에 window.__icoach_detect_armslot === true 플래그가 없으면 항상 'overhand' 로 오버라이드. 결과적으로 "사이드암 투구폼 감지" 카드와 사이드암·언더핸드 롤모델 추천이 더 이상 나타나지 않습니다. 원래 내부 판정 결과(wouldBe)는 진단에 보존되므로 나중에 실측 데이터로 재조정 가능.🔧 원판정=overhand/sidearm/underhand · peakUp=XX° · minUp=XX° · pE=X.XX · aE=X.XX 형태로 핵심 4개 값을 직접 노출해 스크린샷 한 장으로 상태 파악 가능. 세부는 접은 상태로 유지.window.__icoach_detect_armslot = true 입력 후 재분석하면 β 1.4.31 의 12단계 캐스케이드 판정기가 다시 작동합니다. 실제 사이드암/언더핸드 투수 영상의 진단 값을 수집해 임계값을 실측 기반으로 재설정한 뒤 전체 재활성화 여부 결정 예정.elev = (sh.y - el.y) / torso) 는 카메라 각도·거리·피사체 줌에 의해 분모가 요동쳐 근본적으로 불안정한 스칼라였습니다.upAng = atan2(|el.x - sh.x|, sh.y - el.y) × 180/π. 0°=팔꿈치가 어깨 바로 위(팔 수직), 90°=어깨와 같은 높이(팔 수평), 180°=바로 아래(팔 수직 아래). 프레임 스케일·줌에 완전히 독립이라 훨씬 안정적. 오버핸드 코킹 10~45°, 사이드암 65~105°, 언더핸드 120°~.🔧 관리자 진단 (암슬롯) 노란색 카드가 뜹니다. 판정에 쓰인 실제 수치 — armSlot, isRight(R/L), releaseF(프레임%), 수집창 범위, aboveShoulder 프레임 수, peakElev/releaseElev/avgElev, peakUpAng/releaseUpAng/minUpAng — 를 한 줄로 노출해 다음 오탐 발생 시 정확한 수치 기반으로 임계값을 조준 튜닝할 수 있습니다. 콘솔에서도 window.__icoach_armslot_debug 로 접근 가능.onVideoSelected 의 중복 체크 호출부를 관리자 상태 확인 후 우회하도록 수정 — _adminUnlocked === true 또는 localStorage.icoach_admin === '1' 이면 다이얼로그 없이 바로 진행합니다.🔓 관리자 모드: 같은 영상 재분석 허용 토스트를 띄워 우회 동작이 일어났음을 알려줍니다. 영상 지문(fingerprint) 자체는 계속 저장되므로 관리자 모드를 해제하면 일반 사용자 흐름(중복 경고 다이얼로그)이 그대로 돌아옵니다.checkDailyLimit() 에서 이미 검증된 관리자 판정 로직(_adminUnlocked 변수 + icoach_admin localStorage) 을 동일하게 적용. 추후 isAdminUnlocked() 헬퍼로 통합 여지 있음.사이드암 투구폼 감지 라벨이 잘못 붙던 문제를 해결했습니다. 기존 분류는 keyElev > -0.05 단 한 줄로 "팔꿈치가 어깨 기준 몸통 길이의 5% 이하로만 내려가도 사이드암" 으로 취급했는데, 실제 정상 오버핸드 릴리스에서도 팔꿈치가 어깨보다 살짝 아래(-0.07~-0.15)에 위치하는 경우가 흔해 지속적으로 오분류됐습니다. Safety Net 들도 있었지만 단일 프레임 keyElev 한 번만 임계값 밑으로 떨어지면 즉시 사이드암 라벨이 찍히는 구조적 약점이 있었습니다.peakElev 오버핸드 확정 임계값 0.08→0.04, (B) 어깨 위 프레임 절대수 3→2 로 완화해 정상 오버핸드는 Safety Net 단계에서 빠르게 확정. (C) 경계 구간 진입 시 peakElev < 0.05 AND keyElev ≤ -0.18 두 조건을 동시에 요구해야만 사이드암 — 피크가 어깨 근처까지라도 올라왔으면 오버핸드. (D) keyElev > -0.15 면 오버핸드(정상 오버핸드 릴리스의 자연스러운 하강 포용). (E) 언더핸드 기준 -0.30→-0.38 로 엄격화. (F) 애매한 중간 구간은 기본값 오버핸드 — 가장 흔한 폼이므로 오분류 비용이 최소.⚠️ 크라우칭(포수) 자세가 많이 감지 경고가 잘못 뜨던 문제 해결. 기존 조건 hipY > kneeY * 0.82 는 이미지 절대 좌표 비율이라 피사체가 프레임에 어떻게 잡혔느냐(크게/작게/위쪽/아래쪽)에 따라 값이 요동쳤습니다. 투수가 프레임 중상단에 잡히면 hipY/kneeY 가 자연스레 0.82 를 넘어 상시 오탐.(ankleY - hipY) / (ankleY - shoulderY) — 발목-어깨 축에서 엉덩이가 얼마나 아래쪽에 위치하는지를 몸 전체 길이로 정규화합니다. 서 있으면 0.5, 크라우칭이면 0.45 미만. 여기에 무릎 각도 < 115° (실제 굽혀진 상태) 조건을 AND 로 결합해, 두 지표 모두 만족해야만 크라우칭으로 카운트. 경고 발동 임계값도 crouchR > 0.4 → 0.55 로 상향해 잔존 노이즈를 한 번 더 거릅니다.(lk?.y||1+rk?.y||1)/2 는 연산자 우선순위 때문에 lk?.y || (1 + rk?.y) || 1 / 2 로 해석되어 kneeY 가 쓸모없는 값(2 또는 NaN)이 되던 숨은 버그를 함께 고쳤습니다..drill-suggest-title-line / .drill-suggest-desc 클래스명에만 의존하고 있었습니다. 하지만 이전 버전(β 1.4.17 이하)의 채팅 히스토리는 <span>아이콘 제목<span>설명</span></span> 형태라 두 클래스가 존재하지 않았고, 결과적으로 "+ 추가" 클릭 시 제목·설명을 전혀 뽑아내지 못해 토스트만 떴습니다. addChatDrill() 에 3-tier 폴백 체인(①data-* 속성 → ②새 클래스 파싱 → ③레거시 중첩 span 파싱 → ④button/img 제거 후 textContent)을 심어 모든 히스토리 포맷에서 복원되도록 했습니다.getGeneralDrills(mode) 는 모드별로 하드코딩된 3개 드릴만 반환해 대화가 단조로웠습니다. 새 버전은 (1) 분석 페이즈가 있으면 gBD/gPD/gFD/gCD/gOD/gFD_fly 분석기를 재사용해 실제 사용자 폼 약점에 맞춘 드릴을 우선 내놓고, (2) 페이즈가 없으면 모드별 8종 풀에서 3종씩 회전(icoach_drill_rot_<mode> localStorage 카운터) 합니다. 투구·타격·수비 채팅 모두 동일 구조로 적용..drill-card 에는 영상 보기 버튼만 있고 커스텀 드릴에 추가할 버튼이 없어, 채팅으로 다시 물어봐야 훈련 메뉴에 반영되는 흐름이었습니다. 이제 각 드릴 카드 하단에 drill-card-add-btn 이 노출되어 한 번의 탭으로 오늘의 커스텀 훈련에 담깁니다. 이미 담긴 드릴은 "추가됨" (비활성) 라벨로 표시.drill-card-add-btn 을 동일하게 배치. 내부적으로는 addChatDrill(btn, mode) 를 공유해 저장 경로가 한 군데로 수렴합니다.icoach_* 키의 문자열 길이를 합쳐 임의의 4.5MB 가상 상한 으로 나눠 퍼센트를 계산했습니다. 실제 브라우저가 허용하는 localStorage 한도는 보통 5~10MB 이상이라, 데이터가 가상 상한만 넘으면 브라우저에서는 멀쩡히 저장되는데 화면에는 107%·120%·150% 같은 말이 안 되는 수치가 찍혔습니다. 분석 24~30건만 쌓여도 매번 경고가 떠 불필요한 불안을 줬습니다.navigator.storage.estimate() 를 호출해 실제 usage/quota 비율을 계산합니다. 이 API 는 Chrome·Safari·삼성인터넷 모두 지원.0~99 로 제한되어 "107%" 가 원천적으로 발생하지 않습니다.80% → 90% 로 상향, 한 번 경고가 뜨면 24시간 동안 재표시 억제 (icoach_storage_warn_at). 단, safeSave 에서 실제로 저장 실패가 일어난 경우는 force 로 스로틀 우회.onclick 이 메모리 상의 chatSuggestedDrills[idx] 배열 인덱스를 참조하는 구조였는데, 이 배열은 실제로는 한 번도 채워지지 않고 있었고, 채팅 히스토리는 HTML 문자열로 localStorage 에 저장되기 때문에 페이지를 새로고침하거나 세션을 다시 열면 메모리 배열이 항상 비어 있어서 모든 인덱스가 undefined 가 되는 구조적 결함이 있었습니다. β 1.4.25 에 추가한 가드가 이 결함을 표면화시켜 매번 "드릴 정보를 찾을 수 없습니다" 가 뜬 것입니다.data-drill-title / data-drill-desc / data-mode 속성에 HTML 엔티티 이스케이프(&·"·<·>)로 내장하도록 바꿨습니다. 속성이 비어 있는 구버전 히스토리의 버튼을 만나더라도 부모 .drill-suggest-item 요소의 .drill-suggest-title-line / .drill-suggest-desc 텍스트를 직접 파싱해 폴백합니다. 두 경로 모두 완전히 DOM 기반이라 리로드 · 히스토리 복원 · 다른 탭 재열기 이후에도 항상 동작.addChatDrill(btnEl, mode) 신형과 addChatDrill(idx, mode, this) 구형을 첫 인자 타입(HTMLElement 여부)으로 자동 감지해 처리합니다. 이미 localStorage 에 남아 있는 예전 채팅 HTML 이라도 곧바로 새 로직을 타고 정상 추가됩니다.icoach_custom_drills 라는 별도 로컬 버킷에만 저장될 뿐 어느 화면도 그 버킷을 읽지 않아서 훈련 메뉴에는 아무것도 뜨지 않았습니다. 이번 릴리즈에서 getTodayDrillListGrouped() 가 오늘 날짜로 필터한 커스텀 드릴을 해당 모드(투구/타격/수비) 그룹 끝에 자동으로 합류 시키도록 고쳤습니다. 채팅에서 "+ 추가" 를 누르면 → 토스트 + 훈련 메뉴의 해당 섹션 맨 아래에 체크박스/훈련방법 버튼까지 포함해 즉시 표시됩니다. 훈련 탭이 열려 있으면 재렌더까지 바로 수행.dateKey(YYYY-MM-DD) 를 함께 저장하므로 추가한 그 날의 훈련 리스트에만 나타나고, 자정이 지나면 자동으로 사라집니다. 로컬 스토리지 누적 방지를 위해 30일 초과 엔트리는 저장 시점에 프루닝. 같은 날/같은 모드/같은 제목 중복 입력은 1회만 반영.β 1.4.14 같은 버전 번호가 메인 라벨이던 문제 수정 — β 1.4.23 에서 dedupe 키를 날짜로 바꿨지만 라벨 포맷 은 "날짜 엔트리면 날짜, 레거시 버전 엔트리면 버전" 식으로 분기되어 있어서, 실제 사용자의 목록에는 β 1.4.23 이전에 쌓인 레거시 엔트리가 대부분이라 화면에는 여전히 버전 번호가 크게 보였습니다. 이번 릴리즈에서 모든 엔트리는 예외 없이 날짜(2026.4.21 (수))를 메인 라벨 로, 버전 번호(있다면)와 시각·분석 횟수는 작은 부제로 표시하도록 통일했습니다._vb_migrate() 이 한 번 돌며 (1) 레거시 엔트리의 date ISO 문자열에서 dateKey(YYYY-MM-DD)를 파생하고, (2) 같은 dateKey 에 속한 엔트리 중 타임스탬프가 가장 최신인 1개만 남기며, (3) 최근 14일 범위로 잘라 저장합니다. 따라서 2026.4.21 자리에는 당일 마지막에 저장된 스냅샷만 남고 나머지는 정리됩니다.← 이전 / N·M / 다음 → 버튼을 추가했습니다. 페이지가 1장(엔트리 ≤ 5개) 이면 컨트롤은 숨김. 수동 백업을 누르면 첫 페이지(가장 최신 쪽)로 점프합니다.version → dateKey (YYYY-MM-DD) 로 바꾸고, 앱 실행 시점에 오늘 날짜의 스냅샷이 없으면 자동으로 1장을 저장 하는 정책으로 교체했습니다.checkDailyBackup() 이 icoach_version_backups 배열을 스캔해서 오늘 날짜(dateKey) 항목이 없으면 즉시 한 장을 저장합니다. 기존 버전 기반 체크 (checkVersionAndBackup) 는 제거했습니다. 백업 상한은 10개 → 14일 로 상향해 "지난 2주 내 어느 날로도 복구 가능" 을 보장하고, 이 상한을 넘으면 가장 오래된 엔트리부터 드롭됩니다. 수동 수동 백업 버튼은 오늘 날짜 스냅샷을 최신 데이터로 덮어쓰기 (같은 날 여러 번 눌러도 리스트가 불지 않음) 하며, 완료 토스트는 2026.04.21 백업 완료 형태로 날짜를 노출합니다.version 키 엔트리는 마이그레이션/삭제 없이 목록에 그대로 남고, 라벨만 다르게 렌더됩니다: 날짜 엔트리는 2026.04.21 (수) 를 메인 라벨로, β 1.4.23 을 작은 부제로 표시하고, 레거시 버전 엔트리는 기존처럼 β 1.4.22 를 메인 라벨로 유지합니다. 사용자가 과거 롤백 기록을 "잃어버렸다" 고 오인하는 일이 없도록 하는 것이 목적입니다.saveVersionBackup() 은 매 클릭마다 append 만 했기 때문에, 브라우저가 이전 캐시된 JS 를 쓰거나 또는 이미 "최신" 으로 표시되던 다른 버전이 있으면 사용자가 추가된 항목을 인지하기 어려웠습니다. 이번 릴리즈에서는 저장 시 같은 버전의 기존 항목을 제거(dedupe)한 뒤 새로 push 하도록 변경했고, 확인 토스트에도 β X.Y.Z 백업 완료 처럼 버전을 명시해 실제 저장 여부를 즉시 확인할 수 있게 했습니다.▼ 펼치기 버튼으로 전체 목록을 열 수 있습니다. 펼친 상태는 섹션 재진입 시 유지되지 않고 항상 접힘으로 리셋됩니다(사용자가 필요할 때만 연다는 철학).syncHistoryBoth()(내려받기 → 올리기) 를 수행하고, 새 분석 시 자동 업로드 · 앱 실행 시 자동 다운로드도 별도로 돌고 있어서 아래 두 방향 버튼은 거의 사용되지 않으면서 UI 만 어지럽혔습니다. 두 버튼은 ▸ 고급: 한 방향만 동기화 토글 뒤로 숨겨, 평상시에는 한 개의 지금 동기화 버튼만 보이게 정리했습니다.pass:true 로 통과. (B) Gemini 프롬프트가 "관대하게 판별해. 야구 관련 동작이면 대부분 pass:true"라고 명시적으로 느슨하게 지시되어 있음. (C) 응답 파싱 실패·네트워크 오류·JSON 포맷 오류 등 모든 예외가 pass:true 로 폴백 — 즉 기본값이 통과. 3개 중 하나라도 걸리면 이후 검사는 무의미했습니다.preVerifyDrillVideoLocal): API 호출 전 단계에서 브라우저 내장 MediaPipe 포즈 추정기로 6 프레임을 샘플링 → "사람이 실제로 움직이는가?" 확인. 사람 감지 프레임이 절반 미만이거나 총 이동량이 0.05 아래면 즉시 차단. 정지 화면·풍경·반려동물 영상을 API 비용 없이 거름. (2) Gemini 2차 검증 강화: 프레임 2장→4장, 해상도 384px→480px, temperature 0.2→0.1, 드릴 제목/태그에서 핵심 동작 키워드를 추출해 프롬프트에 주입(투구/타격/수비/워밍업/체력), 프롬프트 어조를 "엄격하게 판별한다. 기본값은 pass:false" 로 반전. (3) fail-closed 정책: 파싱 실패·JSON 포맷 오류·pass 가 boolean 이 아닐 때 모두 pass:false. 진짜 네트워크 에러만 skipped:true 로 사용자 편의상 통과 허용.detectArmSlot() 이 투구 전체 30~85% 구간을 스캔하는 과정에서 팔로스루(릴리스 이후 팔이 몸 반대쪽 무릎까지 크게 휘둘려 내려가는 구간) 프레임이 분석에 섞여 들어갔기 때문입니다. 오버핸드 투수의 팔로스루는 팔꿈치가 어깨보다 한참 아래로 떨어지므로, 여기서 손목 속도가 재상승해 릴리스 프레임이 팔로스루 후반으로 잘못 잡히면 keyElev 가 깊은 음수(-0.30 미만) → "언더핸드" 로 결론 나는 회로가 있었습니다.elev) 수집 창을 "릴리스 전후의 팔 스윙 윈도우"로 락([release-12, release+2]). ★ 릴리스 이후는 최대 2 프레임까지만 허용 → 팔로스루 프레임이 통계를 오염할 수 없음. (C) 오버핸드 확정 임계치 peakElev 를 0.12 → 0.08 로 하향(창이 좁아 노이즈 없음). (D) 어깨 위 프레임 비율 20% 방식을 절대 3장 이상 방식으로 전환(짧은 스윙에서도 안정적으로 트리거). (E) 릴리스 값이 없고 피크가 양수면 오버핸드 고정(폴백 경로 보강).last.coachComment 의 인-앱 HTML 문자열(<span class="coach-good">, <b>, <img src="data:image/png;base64,..."> 등)을 그대로 splitTextToSize 에 넘겨 렌더하다 보니, 화면에서는 보이지 않던 태그/긴 base64 문자열이 PDF 본문에 통째로 출력되었습니다. 신규 헬퍼 stripHtmlForPDF() 를 도입해 이미지·태그·HTML 엔티티를 정리한 평문만 PDF 로 출력하도록 변경.needH=6+5+reasonLines×4+strengthLines×4+6 이 카드 맨 아래 "유튜브 검색: ..." 라인의 baseline(+3) 과 폰트 descender·하단 패딩을 빠뜨려, 다음 섹션 헤더가 카드 위로 올라타며 가독성을 망가뜨리는 현상이 있었습니다. +12 로 보정하고 ensureSpace 도 여유분 +3 추가.보폭(%신장) · 어깨 MER 처럼 내부 유닛 표기/영문 약어가 사용자 화면에 그대로 노출되던 문제를 고쳤습니다. 각각 보폭, 어깨 외회전 으로 정리.getProIdealAngles() 의 label 필드 6곳 + getProCoachComment() 의 코멘트 테이블 key 2곳을 동시 수정해 분석 결과 카드와 코치 코멘트가 일치하도록 맞췄습니다.label: 필드를 전수 검사했고, 다른 영문 약어/내부 단위 표기는 확인되지 않았습니다.gBD) 에 적용한 약점 우선순위 알고리즘을 투구(gPD) · 내야땅볼(gFD) · 내야플라이(gFD_fly) · 포수(gCD) · 외야(gOD) 전 영역에 동일하게 이식. warmup 1 + 점수<75 인 phase 상위 3개(낮은 점수 우선) + 실전 기본 연습 1 + (평균<60 시 코어 1) 구조로 통일.gPD: 6 phase(코킹·스트라이드·와인드업·가속·릴리스·팔로스루) 중 약점 상위 3개만, avg<85 무조건 심화 드릴 제거. (2) gFD: 5 phase(준비자세·어프로치·글러브·트랜지션·송구) 중 상위 3개. (3) gFD_fly: 5 phase + 베이스 실전 연습 1개만 유지, 선라이트 드릴 제거. (4) gCD: base drill 전체를 채워 넣던 fallback 제거 — 점수와 무관하게 8개 고정되던 문제 해결. (5) gOD: 인접 드릴 자동 push 로직 제거."손목-어깨 거리 최대" 방식이라 팔로스루에서 손이 몸통 반대편으로 크게 돌 때 팔로스루 프레임을 릴리스로 오판하고, 그 ±3 프레임 평균이 이미 팔꿈치가 내려온 구간 중심으로 잡히면서 음수 elev 가 나오는 것이었습니다.-0.15 → -0.30으로 2배 엄격히 (팔꿈치가 몸통의 1/3 이상 아래로 내려갈 때만). (4) 탐색 구간 60~85% → 30~85%로 확장하여 코킹 피크 포착. (5) 애매한 경우 오버핸드 default 원칙 유지.splice/re-push 처리가 들어가 있었는데, 롤모델이 리스트에서 빠지면서 단순 sort + _extra 플래그만 남겨 가독성을 개선했습니다.+ 드릴 더 보기 (N개) 버튼이 나타나 원하는 선수만 나머지 드릴을 펼쳐볼 수 있습니다.DRILL_VIDEO_MAP 에서 푸시 타이틀과 맵 키의 괄호 suffix 불일치로 영상이 연결되지 않던 5건(런지 워크, 스트라이드 연습, 스텝 드릴, 드라이 스윙, 하프 스쿼트 드릴)에 짧은 별칭 엔트리를 추가했습니다. 이제 훈련 카드에서 동영상이 정상적으로 나옵니다.app.html 끝부분 truncation (DRILL_VIDEO_MAP 중간에서 잘림 → </script></body></html> 누락)을 bak_histdet 꼬리 splice 로 복구. 5개 스크립트 블록 node --check 통과 확인.icoImg is not defined 참조 에러로 앱이 시작 단계에서 튕기는 현상 보고. applyIcons()를 try/catch로 격리하고, 하위 스크립트 블록이 파싱 실패해도 icoImg가 정의되지 않은 상태에서 호출되지 않도록 얼리 스텁을 삽입했습니다.app.html 의 2번째 스크립트 블록이 잘려 있어 전체 스크립트 파싱이 실패하던 문제를 백업 splice로 복구했습니다. 이로 인해 일부 사용자가 경험한 "데이터 소실" 체감은 실제 데이터 삭제가 아니라 localStorage 에서 읽기 실패로 화면만 비어 보이던 증상이었음을 확인했습니다.fetchLeaderboard() 가 rankings.orderBy('score','desc').limit(50) 로 전체 모드의 상위 50명만 받은 뒤 클라이언트에서 모드 필터를 적용하던 구조였습니다. 상위 50이 특정 모드(예: 분석왕) 에 편중되면, 다른 모드 탭에는 내 문서 말고 아무것도 남지 않았습니다. 이번 릴리즈에서 서버측 where('mode','==',X) 필터를 쓰도록 바꾸고, 복합 인덱스가 없으면 limit(300) 폴백으로 받아와 클라이언트에서 거르도록 이중 안전장치를 넣었습니다. 전체 모드 리밋도 50 → 200, 최종 슬라이스도 20 → 50 으로 상향했습니다.localStorage 에만 있어, 기기를 바꾸거나 캐시를 지우면 데이터가 사라지는 구조적 위험이 있었습니다. 이번 릴리즈부터 모든 분석 기록이 Firestore users/{uid}/history/{date} 에 자동 저장됩니다. 분석 완료 시 자동 업로드, 앱 시작 시 자동 다운로드(기존 사용자만), 설정 → ☁ 클라우드 동기화 메뉴에서 수동으로 올리기/내려받기/양방향 동기화 가능.checkVersionAndBackup() 이 importData() 안에서만 호출되던 버그를 수정. 앱 시작 시 init() 에서 자동 호출되도록 바꿔, 업데이트만 받은 사용자도 이전 버전의 분석 기록이 자동으로 버전 백업 리스트에 남도록 보강했습니다.rankings 컬렉션의 모드별 문서 수, 고유 UID 수, 점수 분포, 최근 등록 10건을 한눈에 확인. "실제로 다른 사용자 데이터가 있는지 / 내 필터 버그인지" 빠른 판별용.users/{uid}/history/{docId} 에 대한 Firestore 규칙이 아직 없으면 동기화가 실패할 수 있습니다. FIRESTORE_AUTH_SETUP.md 에 추가된 규칙 블록을 Firebase Console → Rules 에 반영해주세요.Spoqa Han Sans Neo Regular/Bold TTF 2종을 앱의 ./fonts/ 폴더에 배치하고, PDF 버튼을 누른 순간 fetch → base64 인코딩 → doc.addFileToVFS() + doc.addFont() 로 jsPDF 에 주입하는 로직을 loadPDFKoreanFonts() 헬퍼로 구현했습니다. 첫 호출 이후에는 window.__pdfKoreanFonts 에 캐시되어 재호출 시 fetch 하지 않습니다.▸ 가 Spoqa 폰트에 없어 → 로 대체했습니다. 오프라인 PWA 도 정상 작동하도록 서비스워커 ASSETS_TO_CACHE 에 TTF 2종을 프리캐시 목록에 추가했습니다.feedback, drills, armSlot, coachComment, fieldingType 을 icoach_history localStorage 에 함께 저장하도록 addHistory() 호출부 두 곳을 모두 보강했습니다. 앞으로 기록되는 모든 분석은 상세화면에서 원본 전체를 바로 복원합니다.feedback/drills 가 비어 있지만, 저장된 phases(단계별 점수) 와 mode/fieldingType 을 기반으로 gPD·gBD·gFD·gFD_fly·gCD·gOD 드릴 생성 함수를 재호출해 추천 훈련 카드를 실시간 재구성합니다. 피드백이 완전히 없는 초기 기록에는 "이 분석은 피드백/훈련 추천이 저장되기 전 기록입니다" 안내가 표시됩니다.d.tag/d.cat 이 비어 있는 드릴(특히 gFD_fly() 팝플라이 드릴 7종) 에서 "undefined · 훈련" 으로 표시되던 현상이 있었습니다. cat → category 순서로 조회하고, 없을 때는 {warmup:'쉬움', form:'기본', strength:'보통', practice:'실전', advanced:'심화'} 매핑으로 자동 폴백되도록 렌더러를 보강했습니다.app.html 이 파일 끝(약 8.72MB, 11,907줄)에서 UTF-8 문자 중간에 잘린 채로 올라가 있었습니다. 이 때문에 거대한 인라인 스크립트 블록의 </script> 닫힘 태그와 </body></html> 이 전부 사라져, DRILL_YOUTUBE 정의 이후 openDrillGuide/closeDrillGuide 같은 보조 함수가 실행되지 못했습니다. 그 결과 홈 탭의 총 분석 수·점수, 전국 랭킹 리스트, 성장기록 화면이 모두 빈 상태로 나타나던 것입니다. 이번 릴리즈에서 최종 완전본 백업(app_20260419_060149_pre_analyst_img.html)의 꼬리 블록을 이어 붙여 파일을 복구했고, JS 구문 검사(node --check)도 통과했습니다.DOMContentLoaded 이벤트가 이미 발생해, 아이콘을 채워주는 initializeIcons() 의 리스너가 한 박자 늦게 등록되면서 한 번도 실행되지 않던 문제가 원인이었습니다. 이제 스크립트 끝에서 document.readyState 를 확인해 이미 DOM 이 준비되어 있으면 즉시 initializeIcons() 를 실행하도록 보강했습니다.icon_bug_report / legal / support / form / email)을 ASSETS_TO_CACHE 에 추가해 오프라인에서도 깨지지 않도록 했습니다.drill-suggest-item 레이아웃을 flex + 스택 제목/설명 구조로 바꾸고 word-break:keep-all을 적용해 한글 단어가 어색하게 잘리지 않도록 했습니다.icoach_uid 를 공유합니다.<datalist> 자동완성을 제공합니다. "군베이스볼" / "군 베이스볼" / "군BB" 같은 표기 차이로 인한 오인식이 크게 줄었습니다.icoach_uid 는 그대로 유지되어 분석 히스토리·랭킹 기록은 보존됩니다.autoSubmitRanking() 이 birth + pinHash 존재 여부를 선검사하고, 미보호 계정은 즉시 마이그레이션 모달로 안내합니다.accounts 컬렉션) — 문서 ID = uid, pinHash 변경 금지, 이름/생년월일 변경 금지, 삭제 금지. 자세한 내용은 프로젝트 루트의 FIRESTORE_AUTH_SETUP.md 참조.config/maintenance 문서를 관리자가 켜면, 앱 진입 시 즉시 점검 안내 모달이 뜨고 필요 시 전면 차단도 가능합니다. 클라이언트 재배포 없이 실시간 대응이 가능해졌습니다..active → .show) 상시화 및 모달 문구 버전 표기 보정.limit(100)→limit(50), 새로고침 버튼 추가 + 5초 쿨다운, 30초 메모리 캐시로 중복 호출 차단. 예상 DAU 30명 기준 Spark 무료 한도의 15% 내에서 운영.3회 → 5회, 20점 이상 유효 분석 2회 → 3회. 상위 5회 평균을 산출하기 위한 표본 요건입니다.eventNetScore 기준으로 재정렬됩니다.recent30Count · improvementDelta · eventWeeklyMisses · eventDailyMisses · eventPenalty · eventNetScore · scoreFormula 필드 추가. 구버전 문서는 하위 호환(분석왕은 0.5× 대체, 훈련왕은 자연 배제).Math.abs()로 앞뒤 방향 정보가 소실되며, (c) 우완 투수만 처리하여 좌완은 오분류되는 구조적 결함이 있었습니다.60%~88%(팔로스루 배제)로 좁히고, 던지는 팔 손목이 어깨에서 가장 먼 릴리스 프레임을 찾아 ±3 프레임 평균으로 (어깨-팔꿈치)/몸통길이 비율을 계산합니다. 양수(어깨 위)는 오버핸드, 0 근처(어깨 레벨)는 사이드암, 음수(어깨 아래)는 언더핸드.x 이동 범위를 비교해 던지는 팔 자동 감지. 좌완 투수도 같은 알고리즘으로 정확히 분류됩니다.source 인자('bonus' | 기본) 추가. 보너스 드릴은 window.__bonusDrills 캐시를 참조해 오늘의 훈련 목록과 인덱스 충돌 없이 독립적으로 동작합니다.●●○ 진행 도트와 "랭킹까지 N회 더!" 안내 문구를 추가했습니다. 재방문 동기부여를 위한 UX.validAnalysisCount 필드 추가 (20점 이상 분석 수). 기존 데이터는 analysisCount 로 대체 계산하여 하위 호환성 유지.<input type=password> 를 가로채 Enter 시점에 페이지를 멈추게 하던 것을 차단 속성(autocomplete=off · data-lpignore · data-1p-ignore · data-bwignore)으로 막고, DOM 토글을 requestAnimationFrame 으로 비동기화했습니다.adminOn('ironarm0529') / adminOff()
?admin=ironarm0529 를 주소 끝에 붙이면 자동 진입
unlockAdmin() 진행 단계마다 [admin] unlock 타임 마커가 콘솔에 찍혀 혹시 또 멈추더라도 정확한 freeze 지점을 식별할 수 있습니다.uid == docId 검사가 실제 문서ID 스키마(uid + '_' + mode)와 일치하지 않아 모든 쓰기가 Missing or insufficient permissions 로 거부되던 것을 수정했습니다.'defense' mode 허용값을 추가. 이전에는 수비 분석 결과가 Firestore에 전혀 저장되지 않았습니다.score is int → is number (소수점 평균 점수 허용)chrome-extension:// 스킴 요청을 SW가 캐시하려다 TypeError 가 폭주해 메인 스레드를 막던 것을 차단했습니다.ontimeupdate(약 4회/초)에만 의존해 프레임 간 공백이 생겼고,
② 와이드샷·모션블러로 특정 프레임에서 MediaPipe 검출이 실패하면 해당 프레임이 통째로 비어 있었습니다.
사진을 탭하여 업로드
아이 정보를 입력하면 맞춤 분석이 가능합니다
아빠 폰 / 아들 폰에서 같은 계정으로 로그인할 때 사용합니다.
이벤트 공정성을 위한 본인 확인용이에요.
🤝 이용 동의
※ 분석 결과는 참고용이며 의학적 진단이 아닙니다. β 베타 기간 중 데이터가 유실될 수 있습니다.
AI가 자세를 분석하고 맞춤 훈련을 추천합니다
던지기 자세
스윙 자세
수비 자세
실전 영상 분석
영상을 업로드하면 AI가 자세를 분석하고
맞춤 훈련법을 추천해드립니다
수비 위치를 선택하세요
측면에서 전신이 보이도록 촬영하세요.
3~5m, 머리~발끝
밝은 곳, 단순 배경, 720p+
한 동작, 3~10초
촬영한 영상 분석
라이브 카메라
처음 실행 시 AI 모델 다운로드에
30초~1분 정도 소요됩니다
실시간으로 자세를 분석합니다
탭 전환·분석 시작·훈련 완료 등 주요 동작에 효과음이 재생됩니다. BGM은 분석 진행 중에만 재생됩니다.
AI 코치란?
아이코치 앱에는 기본 코치 기능이 들어있어서 바로 질문할 수 있어요. 여기에 Google의 AI(Gemini)를 연결하면, 코치가 우리 아이의 분석 결과를 더 깊이 이해하고 진짜 대화하듯이 맞춤 조언을 해줘요.
API 키는 Google AI 서비스를 사용하기 위한 일종의 비밀번호예요. 한 번만 발급받아 아래에 붙여넣으면 끝! 발급도 사용도 완전 무료이고, 개인정보는 수집되지 않아요.
⏱ 1분이면 끝나는 간단 등록
Google 계정만 있으면 누구나 무료로 발급받을 수 있어요.
아래 단계를 그대로 따라해 보세요!
Google 계정으로 로그인
평소 사용하는 Gmail 계정으로 로그인하세요.
별도 회원가입이나 결제 정보는 필요 없어요!
"Get API key" 버튼 찾기
화면에서 Get API key 또는 API 키 가져오기 버튼을 찾아 클릭하세요.
"Create API key" 클릭
+ Create API key 버튼을 누르면 API 키가 자동으로 생성돼요.
키 복사 → 위 입력란에 붙여넣기
생성된 키 옆의 📋 복사 버튼을 누르세요.
그리고 이 화면 위쪽의 입력란에 길게 눌러 붙여넣기 하면 끝!
🎉 완료! 이제 AI 경기 분석을 사용할 수 있어요
키는 자동 저장되며, 다시 입력할 필요 없어요
✅ 완전 무료 · Google 계정만 있으면 OK · 결제정보 필요없음
개인 사용 수준에서 비용이 발생하지 않습니다
API 키가 없어도 기본 코치 기능은 사용할 수 있어요.
키를 입력하면 더 자연스럽고 상세한 AI 대화가 가능합니다.
설치하면 앱 아이콘 한 번 탭으로 바로 실행되고, 매번 주소창 입력하거나 링크 찾을 필요가 없어요.
💡 설치는 무료 · 개인정보 수집 없음 · 언제든 홈 화면에서 길게 눌러 삭제 가능해요.
분석 기록을 안전하게 지키는 3가지 방법입니다. 아래 두 가지는 자동으로 동작하므로 평소에는 신경 쓸 필요가 없어요.
언제 쓰나요? 휴대폰을 바꾸거나 브라우저 캐시를 지웠을 때. 새 기기에서 앱을 열면 자동으로 복원돼요.
✓ 새 분석할 때 자동 업로드 · 앱 열 때 자동 다운로드 — 평소엔 버튼 안 눌러도 됨
언제 쓰나요? 실수로 기록을 지웠거나 데이터가 이상해졌을 때 어제 이전 상태로 되돌릴 수 있어요.
✓ 하루 1회 자동 저장 · 최근 14일 보존 — 같은 기기 내 타임머신
언제 쓰나요? 클라우드 계정 없이 전체 데이터를 수동 파일로 보관하거나, 다른 사람에게 전달할 때. 대부분은 위 두 기능으로 충분해요.
⚠️ 가져오기는 현재 로컬 데이터를 덮어쓰기합니다. 신중히 사용하세요.
버그를 발견하셨거나 새로운 기능 아이디어가 있으시면 알려주세요!
오픈베타 이벤트 기간(5.1~5.31) 동안 가장 많이 제보한 분에게 제보왕 상을 드립니다.
아이코치 이용과 개인정보 처리에 관한 방침입니다. 이용 전 반드시 한 번 읽어주세요.
운영: 김아빠 · 연락처: 2026icoach@gmail.com
오류 제보·기능 제안·이용 문의를 한 곳에서 받아요. 답변은 이메일 또는 단톡방 공지로 드립니다.
2026icoach@gmail.com
연속 훈련일수
각 훈련을 완료하고 인증 영상을 올려주세요. 꾸준한 훈련에 보너스 스탯이 부여됩니다!
이전 분석 대비 어떤 부분이 좋아졌는지, 추가로 어떤 훈련이 필요한지 확인하세요.
최종 개정일: 2026-04-19 (β 1.3.0)
아이코치(이하 "서비스")는 이용자의 개인정보를 소중히 여기며, 수집하는 정보를 최소화하기 위해 노력합니다.
랭킹·분석 기능 이용 시(필수): 닉네임, 만 나이, 활동 지역(시·도, 선택), 분석 결과 점수·능력치, 기기 식별자(UID).
버그 제보·기능 제안 시(선택): 이용자가 입력한 본문 텍스트, 닉네임, UID.
이벤트 상품 수령 시(필요할 때만): 실명, 카카오톡 ID, 배송 관련 메시지.
촬영한 분석 영상은 기기(브라우저) 내에만 저장되며, 서버/외부 저장소로 업로드되지 않습니다. 학교명·실명·생년월일·주소·전화번호는 이벤트 상품 수령 시를 제외하고 수집하지 않습니다. 위치정보(GPS)·연락처·사진첩·녹음 권한은 요청하지 않습니다.
랭킹 표시, 본인 분석 기록 저장 및 성장 추이, 서비스 품질 개선, 이벤트 상품 발송.
랭킹·이력: 이용자가 "데이터 삭제"를 요청하거나 브라우저 저장소를 비울 때까지. 버그 제보: 해결 후 최대 6개월. 이벤트 실명·연락처: 상품 수령 확인 후 30일 이내 즉시 파기.
제3자에게 판매·공유하지 않습니다. 처리 위탁: ① Google Firebase(Firestore) — 랭킹 데이터 저장·조회. ② Google Gemini API — 경기 분석 시 영상에서 추출된 정지 이미지(프레임) 최대 20장이 AI 분석용으로 Google에 전송됩니다. 영상 원본은 전송되지 않습니다.
만 14세 미만 이용자의 개인정보 수집에는 법정대리인(부모) 동의가 필요합니다. 최초 이용 시 체크박스로 확인하며, 미동의 시 분석·랭킹 기능을 이용할 수 없습니다.
언제든지 본인 정보 조회·수정·삭제·동의 철회를 요청할 수 있습니다. 요청: 앱 내 "문의하기" 또는 2026icoach@gmail.com.
버그 제보·기능 제안 입력란에 실명·학교명·전화번호·주소 등 개인을 식별할 수 있는 정보를 입력하지 않도록 주의해주세요.
Firestore는 Firebase Security Rules로 접근이 제한되며, 통신은 HTTPS로 암호화됩니다. 민감정보(주민번호·금융정보 등)는 일절 수집하지 않습니다. 본 서비스는 비공식 β 버전이며 데이터 유실 가능성이 있고, 분석 결과는 의학적·발달적 진단이 아닙니다.
운영자: 김아빠 · 연락처: 2026icoach@gmail.com
최종 개정일: 2026-04-19 (β 1.3.0)
본 약관은 아이코치 앱(이하 "서비스")을 이용하는 모든 이용자에게 적용됩니다.
본 서비스는 비공식 베타(β) 버전으로 개인이 개발·운영하는 실험적 웹 앱입니다. 언제든지 중단·수정될 수 있습니다.
만 14세 미만 이용자는 법정대리인(부모) 동의가 있어야 합니다. 최초 접속 시 본 약관·처리방침·법정대리인 동의 체크박스를 선택해야 합니다.
분석 결과(점수·능력치·코치 조언)는 참고용 정보이며 의학적·발달적·진단적 판단이 아닙니다. 의사결정 책임은 이용자(또는 보호자)에게 있습니다. 부상·발달 문제가 의심되면 반드시 전문가와 상담하세요.
β 기간 동안 기록이 유실·초기화될 가능성이 있습니다. 중요 기록은 별도 보관(스크린샷 등)을 권장합니다. 복구 의무를 지지 않습니다.
타인에게 불쾌감을 주지 않는 닉네임을 사용해야 합니다. 욕설·비속어·성적 표현·혐오 표현 등 부적절한 닉네임은 관리자가 사전 고지 없이 삭제할 수 있으며, 해당 기기는 재참여가 제한될 수 있습니다.
허위/조작된 분석 결과 제출을 통한 랭킹 조작, 타인의 사진·영상 무단 업로드, 자동화 스크립트 등 서비스 방해 행위, 타인 개인정보 수집·공개는 금지되며 위반 시 이용이 제한될 수 있습니다.
촬영 영상은 이용자의 기기에만 저장됩니다. 단, 경기 분석 이용 시 추출된 정지 이미지(프레임) 최대 20장이 Google Gemini API로 전송됩니다. 제3자가 식별 가능한 상태로 포함되지 않도록 주의해주세요.
운영자는 서비스를 사전 예고 없이 중단·수정·종료할 수 있으며, 이로 인한 손해에 대해 법적 책임을 지지 않습니다.
본 서비스는 개인이 비영리로 운영합니다. 군베이스볼·최동원기념사업단 등 공식 기관의 공식 서비스가 아니며 법적 관계가 없습니다. 이벤트 상품은 개인 비용으로 준비되며 수량이 한정적일 수 있습니다.
분쟁은 대한민국 법률을 따르며 운영자의 주소지 관할 법원을 제1심 관할 법원으로 합니다. 상호 신뢰를 바탕으로 성실하게 협의합니다.
2026icoach@gmail.com · 앱 내 "문의하기" 버튼
아이코치 β 1.3.1 부터 개인정보 처리방침과 이용약관이 정식으로 고지됩니다. 계속 이용하시려면 아래 3가지에 모두 동의해 주세요.
※ β 기간 동안 기록이 유실될 수 있으며, 분석 결과는 참고용이고 의학적 진단이 아닙니다. 촬영 영상은 기기에만 저장됩니다.
선수 님, 5월 오픈베타 이벤트의 공정성을 위해 계정 보호를 적용해 주세요.
아빠 폰과 아들 폰에서 같은 계정으로 로그인할 수 있고, 다른 사람이 같은 이름으로 가입할 수 없게 막아줍니다.
⚠️ PIN은 가족만 알 수 있도록 정해 주세요. 분실 시 복구가 어렵습니다.
※ 같은 가족 두 번째 폰은 가입 시 PIN을 입력하면 자동 연결됩니다.
문의: 2026icoach@gmail.com
홈 화면에 추가하면 더 빠르게!
"안전하지 않은 앱" 경고가 뜰 수 있습니다.
아이코치는 웹사이트 바로가기(PWA)로 설치되며,
개인정보 수집이나 악성코드가 없으니 안심하세요.
"무시하고 설치하기"를 눌러 진행하면 됩니다.
홈 화면에 추가하면 앱처럼 빠르게 실행할 수 있어요!
설치 시 "안전하지 않은 앱" 경고가 뜰 수 있습니다. 아이코치는 웹사이트 바로가기(PWA)로 설치되며, 개인정보 수집이나 악성코드가 없으니 안심하세요. "세부정보 더보기" → "무시하고 설치하기"를 눌러 진행하면 됩니다.
하단의 ⬆️ 공유 버튼을 탭하세요
스크롤하여 "홈 화면에 추가"를 선택하세요
오른쪽 상단 "추가"를 탭하면 완료!