<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>팀·수상·현장 프로젝트 | eecczz's page</title><link>https://eecczz.github.io/ko/contest-projects/</link><atom:link href="https://eecczz.github.io/ko/contest-projects/index.xml" rel="self" type="application/rss+xml"/><description>팀·수상·현장 프로젝트</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>ko</language><lastBuildDate>Wed, 01 Jul 2026 00:00:00 +0000</lastBuildDate><image><url>https://eecczz.github.io/media/icon_hu107733296a429e9339b15589e162cf6f_1739_512x512_fill_lanczos_center_3.png</url><title>팀·수상·현장 프로젝트</title><link>https://eecczz.github.io/ko/contest-projects/</link></image><item><title>Smart CCTV 낙상 감지</title><link>https://eecczz.github.io/ko/contest-projects/smartcctv-fall/</link><pubDate>Thu, 13 Aug 2026 00:00:00 +0000</pubDate><guid>https://eecczz.github.io/ko/contest-projects/smartcctv-fall/</guid><description>&lt;div class="case-study-lead">
&lt;p class="case-study-kicker">BACKEND · AI · SYSTEM CASE STUDY&lt;/p>
&lt;p>자세 추정·낙상 객체 탐지·현장 맥락 zero-shot의 3단 검증으로 요양원 RTSP 오탐을 줄인 Edge-AI 관제 프로젝트입니다.&lt;/p>
&lt;div class="case-study-meta">&lt;span>&lt;b>역할&lt;/b> Edge-AI 현장실습 · 데이터/모델/후처리/현장 검증&lt;/span>&lt;span>&lt;b>검증&lt;/b> 실제 요양원 RTSP 환경 적용&lt;/span>&lt;/div>
&lt;/div>
&lt;h2 id="주요-화면">주요 화면&lt;/h2>
&lt;p>실제 관제 환경에서는 이벤트 스냅샷으로 낙상 후보와 객체 탐지 결과를 확인했습니다. 이후 낙상·비낙상 hard validation set으로 오탐과 미탐을 분리해 점검했으며, 50개의 낙상 장면과 50개의 일반 사람 장면에 대한 2차 객체 탐지 모델의 판정 분포를 비교했습니다. pose와 zero-shot 검증은 이 흐름의 앞뒤 단계에 결합했습니다.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="실제 관제 환경에서 감지한 낙상 이벤트 화면" srcset="
/ko/contest-projects/smartcctv-fall/detail-event_hudffd0ace1323fae8cf715f6cfafcd54b_345728_23ace76d4917943c42bf792adbc6cf68.webp 400w,
/ko/contest-projects/smartcctv-fall/detail-event_hudffd0ace1323fae8cf715f6cfafcd54b_345728_8ecf64543c4d160f6aa4298cad94b5e6.webp 760w,
/ko/contest-projects/smartcctv-fall/detail-event_hudffd0ace1323fae8cf715f6cfafcd54b_345728_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/smartcctv-fall/detail-event_hudffd0ace1323fae8cf715f6cfafcd54b_345728_23ace76d4917943c42bf792adbc6cf68.webp"
width="535"
height="409"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="낙상과 일반 사람 hard validation 정확도" srcset="
/ko/contest-projects/smartcctv-fall/detail-accuracy_hu6bfb617f0dbcb4eebcbf9cccbad93192_14931_83509db0664a856c4d7019987c587f85.webp 400w,
/ko/contest-projects/smartcctv-fall/detail-accuracy_hu6bfb617f0dbcb4eebcbf9cccbad93192_14931_454648e17fd6fead98b41272441ec619.webp 760w,
/ko/contest-projects/smartcctv-fall/detail-accuracy_hu6bfb617f0dbcb4eebcbf9cccbad93192_14931_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/smartcctv-fall/detail-accuracy_hu6bfb617f0dbcb4eebcbf9cccbad93192_14931_83509db0664a856c4d7019987c587f85.webp"
width="590"
height="390"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="낙상과 일반 사람 hard validation 혼동행렬" srcset="
/ko/contest-projects/smartcctv-fall/detail-validation_hudac8ac2239a94d5130476c819919d57e_10690_e2421317263c02aeddeda550d08a0e6e.webp 400w,
/ko/contest-projects/smartcctv-fall/detail-validation_hudac8ac2239a94d5130476c819919d57e_10690_24d59694a0227183e2601417a7e6bce4.webp 760w,
/ko/contest-projects/smartcctv-fall/detail-validation_hudac8ac2239a94d5130476c819919d57e_10690_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/smartcctv-fall/detail-validation_hudac8ac2239a94d5130476c819919d57e_10690_e2421317263c02aeddeda550d08a0e6e.webp"
width="555"
height="310"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;h2 id="트러블-슈팅">트러블 슈팅&lt;/h2>
&lt;h3 id="1-자세-추정만으로는-가림원거리세로-방향-낙상을-안정적으로-판정하지-못함">1. 자세 추정만으로는 가림·원거리·세로 방향 낙상을 안정적으로 판정하지 못함&lt;/h3>
&lt;p>처음에는 관절 위치와 신체 기울기를 이용한 자세 추정 기반 낙상 감지를 구현했습니다. 그러나 침대·가구에 신체 일부가 가려지거나 사람이 멀리 있어 keypoint confidence가 낮아지는 장면, 카메라 화면에서 세로 방향으로 쓰러져 신체 폭이 충분히 넓어지지 않는 장면에서는 판정이 불안정했습니다.&lt;/p>
&lt;p>관절 confidence, 상체 각도, bbox 종횡비와 유지 시간을 조합한 휴리스틱을 반복 조정했지만 카메라 시점과 가림 정도에 따라 기준이 달라졌습니다. 자세 추정은 1차 후보 생성으로 유지하고, 실제 낙상 이미지를 학습한 &lt;code>fall/person&lt;/code> 객체 탐지 모델을 2차 검증기로 연결했습니다.&lt;/p>
&lt;h3 id="2-2차-객체-탐지-모델에서도-앉기허리-숙이기하반신-가림-오탐이-발생함">2. 2차 객체 탐지 모델에서도 앉기·허리 숙이기·하반신 가림 오탐이 발생함&lt;/h3>
&lt;p>객체 탐지 모델은 자세 추정의 누락을 보완했지만, 앉거나 허리만 숙인 사람을 쓰러진 사람으로 판단하거나 하반신이 가구에 가려져 짧고 수평에 가까운 형태만 보일 때 &lt;code>fall&lt;/code>로 오탐했습니다.&lt;/p>
&lt;p>앉음·숙임·부분 가림 장면을 hard negative로 보강하고, &lt;code>person&lt;/code> 비교군을 함께 학습했습니다. 한 사람의 상·하체가 서로 다른 bbox로 검출되는 경우에는 겹치거나 가까운 bbox를 묶어 fall confidence와 신체 coverage가 충분할 때만 낙상으로 유지했습니다.&lt;/p>
&lt;h3 id="3-모델-출력만으로는-현장-구조와-행동-맥락을-구분하기-어려움">3. 모델 출력만으로는 현장 구조와 행동 맥락을 구분하기 어려움&lt;/h3>
&lt;p>마지막 단계에서는 적용 현장에 맞춘 텍스트 프롬프트와 후보 이미지의 시각 특징을 함께 비교하는 zero-shot 검증을 추가했습니다. &lt;code>바닥에 전신이 쓰러진 사람&lt;/code>과 &lt;code>의자에 앉은 사람&lt;/code>, &lt;code>허리를 숙인 사람&lt;/code>, &lt;code>가구에 하반신이 가려진 사람&lt;/code>을 현장 상황에 맞게 기술해 1·2차 모델의 낙상 후보를 다시 판별했습니다.&lt;/p>
&lt;p>이를 통해 하나의 기준을 계속 복잡하게 만드는 대신, 자세의 기하학적 변화·학습된 낙상 형태·현장 의미를 서로 다른 단계에서 검증하도록 역할을 분리했습니다.&lt;/p>
&lt;h2 id="기술-선택과-이유">기술 선택과 이유&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>기술&lt;/th>
&lt;th>선택 이유&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Pose estimation&lt;/strong>&lt;/td>
&lt;td>관절 위치·신체 기울기와 시간 변화를 이용해 낙상 후보를 빠르게 생성하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>YOLO26s detection&lt;/strong>&lt;/td>
&lt;td>pose가 놓친 후보를 실제 낙상 형태와 &lt;code>person&lt;/code> 비교군으로 2차 검증하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>fall/person 2-class&lt;/strong>&lt;/td>
&lt;td>쓰러지지 않은 사람을 비교군으로 제공해 단일 클래스의 배경 편향을 줄이기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>BBox post-processing&lt;/strong>&lt;/td>
&lt;td>한 사람의 상·하체가 fall/person으로 나뉘는 부분 bbox 오류를 보수적으로 통합하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Zero-shot validation&lt;/strong>&lt;/td>
&lt;td>시각 특징과 현장 맞춤 텍스트 프롬프트를 결합해 앉음·숙임·부분 가림을 3차 검증하기 위해&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="검증-결과">검증 결과&lt;/h2>
&lt;ul>
&lt;li>pose 후보→fall/person 객체 탐지→zero-shot 현장 검증의 3단 판정 흐름을 구성했습니다.&lt;/li>
&lt;li>최종 fall 표시 기준을 confidence 0.70으로 높여 완전히 쓰러진 상태 중심으로 판정했습니다.&lt;/li>
&lt;li>실제 요양원 RTSP 카메라에서 부분 가림·원거리·앉음·숙임 장면을 반복 검증했습니다.&lt;/li>
&lt;/ul>
&lt;h2 id="시스템-흐름">시스템 흐름&lt;/h2>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Smart CCTV 낙상 감지 시스템 흐름"
src="https://eecczz.github.io/ko/contest-projects/smartcctv-fall/architecture.svg"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;ol>
&lt;li>RTSP 프레임에서 pose 관절과 신체 기울기로 낙상 후보를 얻습니다.&lt;/li>
&lt;li>YOLO fall/person 모델이 후보 crop의 낙상 형태를 2차 검증합니다.&lt;/li>
&lt;li>같은 사람으로 보이는 중복·인접 bbox를 묶고 confidence·coverage를 계산합니다.&lt;/li>
&lt;li>현장 맞춤 텍스트 프롬프트와 시각 특징을 비교해 zero-shot으로 3차 검증합니다.&lt;/li>
&lt;li>confidence 0.70과 시간 조건을 통과한 이벤트만 낙상으로 확정합니다.&lt;/li>
&lt;li>확정 이벤트를 스냅샷·DB·알림 파이프라인에 전달합니다.&lt;/li>
&lt;/ol>
&lt;h2 id="api--시스템-경계">API · 시스템 경계&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>영역&lt;/th>
&lt;th>API/계약&lt;/th>
&lt;th>책임&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>1차 판정&lt;/code>&lt;/td>
&lt;td>&lt;code>pose keypoints · angle&lt;/code>&lt;/td>
&lt;td>자세 추정 · 시간 조건&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>2차 검증&lt;/code>&lt;/td>
&lt;td>&lt;code>fall/person bbox&lt;/code>&lt;/td>
&lt;td>YOLO26s · bbox grouping&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>3차 검증&lt;/code>&lt;/td>
&lt;td>&lt;code>visual feature · text prompt&lt;/code>&lt;/td>
&lt;td>현장 맥락 zero-shot&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>이벤트&lt;/code>&lt;/td>
&lt;td>&lt;code>confirmed fall&lt;/code>&lt;/td>
&lt;td>snapshot · DB · alert&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="다음-구현-계획">다음 구현 계획&lt;/h2>
&lt;ul>
&lt;li>현장 validation set으로 pose·detector·zero-shot 단계별 precision/recall 비교&lt;/li>
&lt;li>연속 프레임 tracking과 cooldown으로 단발성 오탐 억제&lt;/li>
&lt;li>요양원별 가구·카메라 시점에 맞춘 hard negative와 프롬프트 보강&lt;/li>
&lt;/ul></description></item><item><title>Smart CCTV 차종 분류</title><link>https://eecczz.github.io/ko/contest-projects/smartcctv-car/</link><pubDate>Thu, 30 Jul 2026 00:00:00 +0000</pubDate><guid>https://eecczz.github.io/ko/contest-projects/smartcctv-car/</guid><description>&lt;div class="case-study-lead">
&lt;p class="case-study-kicker">BACKEND · AI · SYSTEM CASE STUDY&lt;/p>
&lt;p>폐차장 RTSP CCTV에서 차량을 탐지하고 NPU 환경에서 차종 단위로 분류하는 Edge-AI 관제 프로젝트입니다.&lt;/p>
&lt;div class="case-study-meta">&lt;span>&lt;b>역할&lt;/b> Edge-AI 현장실습 · 모델 전처리/학습/변환/현장 적용&lt;/span>&lt;span>&lt;b>검증&lt;/b> 실제 폐차장 RTSP 환경 검증&lt;/span>&lt;/div>
&lt;/div>
&lt;h2 id="주요-화면">주요 화면&lt;/h2>
&lt;p>폐차장 RTSP 화면에서 차량 후보를 탐지하고, 관심 영역과 이동 방향을 관제 화면에 함께 표시했습니다. 파손된 차량처럼 전체 외형이 온전히 보이지 않는 경우에도 crop된 부분 특징으로 차종을 분류하도록 연결했습니다.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="실제 폐차장 CCTV에서 차량을 탐지한 관제 화면" srcset="
/ko/contest-projects/smartcctv-car/detail-scrapyard_hu30e79913ce5ab054c3da74a138d89fbb_1831746_e29194117425b740e6f5507a55c648b8.webp 400w,
/ko/contest-projects/smartcctv-car/detail-scrapyard_hu30e79913ce5ab054c3da74a138d89fbb_1831746_5fff45c0394dde986a3614909bcefa45.webp 760w,
/ko/contest-projects/smartcctv-car/detail-scrapyard_hu30e79913ce5ab054c3da74a138d89fbb_1831746_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/smartcctv-car/detail-scrapyard_hu30e79913ce5ab054c3da74a138d89fbb_1831746_e29194117425b740e6f5507a55c648b8.webp"
width="760"
height="472"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;h2 id="트러블-슈팅">트러블 슈팅&lt;/h2>
&lt;h3 id="1-훼손가림이-많은-폐차장-차량에서도-부분-특징으로-차종을-식별해야-함">1. 훼손·가림이 많은 폐차장 차량에서도 부분 특징으로 차종을 식별해야 함&lt;/h3>
&lt;p>폐차장에서는 범퍼·문·적재함이 파손되거나 차량 일부만 카메라에 잡혀 완전한 외형을 보기 어려웠습니다. 차량 bbox를 crop한 약 120만 장의 데이터로 학습해 전체 실루엣뿐 아니라 램프·그릴·창문·차체 비율 같은 부분 특징을 충분히 학습하도록 했고, 실제 현장의 훼손 차량에서도 의미 있는 차종 예측을 확인했습니다.&lt;/p>
&lt;h3 id="2-뒤늦게-추가-학습한-지게차를-문이-닫힌-트럭과-혼동함">2. 뒤늦게 추가 학습한 지게차를 문이 닫힌 트럭과 혼동함&lt;/h3>
&lt;p>운영 도중 지게차를 새로운 차종으로 추가해야 한다는 요구사항이 생겼습니다. 기존 분류기에 지게차 데이터만 이어서 학습하자, 폐쇄형 운전석과 각진 전면부를 가진 지게차를 트럭으로 예측하는 오탐이 반복됐습니다.&lt;/p>
&lt;p>트럭과 유사한 지게차·문이 닫힌 지게차를 hard negative로 추가하고 지게차 이미지를 트럭 클래스와 비슷한 수까지 oversampling했지만, 기존 클래스 경계가 지게차를 모르는 상태에서 이미 형성되어 혼동이 충분히 줄지 않았습니다.&lt;/p>
&lt;h3 id="3-신규-클래스를-포함한-전체-데이터로-처음부터-다시-학습해-클래스-경계를-재구성함">3. 신규 클래스를 포함한 전체 데이터로 처음부터 다시 학습해 클래스 경계를 재구성함&lt;/h3>
&lt;p>기존 모델에 새 클래스만 덧붙이는 방식 대신, 지게차를 처음부터 포함한 전체 데이터셋으로 모델을 재학습했습니다. 트럭·지게차의 공통 특징과 구분 특징을 동시에 보면서 표현과 클래스 경계를 다시 형성하게 하자 문이 닫힌 지게차를 트럭으로 보던 현장 오탐이 해소됐습니다.&lt;/p>
&lt;p>이 경험을 통해 데이터 수를 맞추는 것만으로는 새 클래스가 기존 표현 공간에 안정적으로 들어가지 않을 수 있으며, 요구사항 변경 시 학습 시작점과 전체 클래스 간 관계까지 함께 검토해야 함을 확인했습니다.&lt;/p>
&lt;h2 id="기술-선택과-이유">기술 선택과 이유&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>기술&lt;/th>
&lt;th>선택 이유&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>YOLO26s detector&lt;/strong>&lt;/td>
&lt;td>CCTV 프레임에서 car/truck 위치를 먼저 제한해 분류 입력의 잡음을 줄이기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>YOLO26s classifier&lt;/strong>&lt;/td>
&lt;td>차량 crop을 세부 차종으로 분류하고 top-5 후보까지 비교하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>OpenCV · Python&lt;/strong>&lt;/td>
&lt;td>RTSP 프레임 처리, crop 생성, 결과 overlay를 하나의 파이프라인으로 묶기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>NPU runtime&lt;/strong>&lt;/td>
&lt;td>GPU가 아닌 현장 Edge 장비의 제약 안에서 실시간 추론하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>From-scratch retraining&lt;/strong>&lt;/td>
&lt;td>지게차를 포함한 전체 클래스의 특징과 경계를 처음부터 함께 학습하기 위해&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="검증-결과">검증 결과&lt;/h2>
&lt;ul>
&lt;li>기존 분류 모델의 validation에서 top-1 0.90665, top-5 0.97743을 기록했습니다.&lt;/li>
&lt;li>약 120만 장의 차량 crop으로 학습해 실제 폐차장 훼손 차량의 부분 특징 기반 분류를 확인했습니다.&lt;/li>
&lt;li>지게차를 포함한 전체 데이터 재학습으로 폐쇄형 지게차와 트럭의 현장 혼동을 해소했습니다.&lt;/li>
&lt;/ul>
&lt;h2 id="시스템-흐름">시스템 흐름&lt;/h2>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Smart CCTV 차종 분류 시스템 흐름"
src="https://eecczz.github.io/ko/contest-projects/smartcctv-car/architecture.svg"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;ol>
&lt;li>RTSP 카메라 프레임을 수집합니다.&lt;/li>
&lt;li>COCO 사전학습 detector에서 car/truck bbox만 선택합니다.&lt;/li>
&lt;li>bbox를 차량 crop으로 잘라 classifier 입력으로 정규화합니다.&lt;/li>
&lt;li>AIHub 데이터로 학습한 분류기가 차종명·confidence·top-5를 반환합니다.&lt;/li>
&lt;li>NPU용 형식으로 변환한 모델을 현장 관제 소프트웨어에 연결합니다.&lt;/li>
&lt;li>bbox와 예측값을 화면과 로그에 남겨 오탐을 추적합니다.&lt;/li>
&lt;/ol>
&lt;h2 id="api--시스템-경계">API · 시스템 경계&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>영역&lt;/th>
&lt;th>API/계약&lt;/th>
&lt;th>책임&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>입력&lt;/code>&lt;/td>
&lt;td>&lt;code>RTSP/CCTV frame&lt;/code>&lt;/td>
&lt;td>폐차장 카메라&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>탐지&lt;/code>&lt;/td>
&lt;td>&lt;code>car, truck bbox&lt;/code>&lt;/td>
&lt;td>YOLO26s detector&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>분류&lt;/code>&lt;/td>
&lt;td>&lt;code>class, confidence, top-5&lt;/code>&lt;/td>
&lt;td>YOLO26s classifier&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>출력&lt;/code>&lt;/td>
&lt;td>&lt;code>overlay · 결과 이미지 · CSV&lt;/code>&lt;/td>
&lt;td>현장 관제 UI&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="다음-구현-계획">다음 구현 계획&lt;/h2>
&lt;ul>
&lt;li>다중 차량에서 관심 차량을 안정적으로 선택하는 tracking 추가&lt;/li>
&lt;li>지게차·트럭 hard case 전용 validation set과 confusion matrix로 정량 재평가&lt;/li>
&lt;li>새 클래스 추가 시 기존 클래스 rehearsal set과 class-balanced sampler 비교&lt;/li>
&lt;li>NPU latency/FPS와 CPU·메모리 사용량 계측&lt;/li>
&lt;/ul></description></item><item><title>소울라이크 전투 시스템</title><link>https://eecczz.github.io/ko/contest-projects/soulslike-game/</link><pubDate>Wed, 15 Jul 2026 00:00:00 +0000</pubDate><guid>https://eecczz.github.io/ko/contest-projects/soulslike-game/</guid><description>&lt;div class="case-study-lead">
&lt;p class="case-study-kicker">BACKEND · AI · SYSTEM CASE STUDY&lt;/p>
&lt;p>회피·스태미나·콤보·hitbox timing·보스 AI를 상태 기반으로 구성한 4인 Unity 팀 프로젝트입니다.&lt;/p>
&lt;div class="case-study-meta">&lt;span>&lt;b>역할&lt;/b> 4인 팀 · 전투 조작감/피격/스태미나/연출&lt;/span>&lt;span>&lt;b>검증&lt;/b> 교과 팀 프로젝트&lt;/span>&lt;/div>
&lt;/div>
&lt;h2 id="주요-화면">주요 화면&lt;/h2>
&lt;p>모바일 조작 화면에서 플레이어의 회피·스태미나·연속 공격과 보스의 패턴 전투를 한 흐름으로 구성했습니다. 전투 장면에서는 체력 UI와 공격 이펙트가 실제 판정 시점과 함께 동작합니다.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="보스와 근접 전투를 진행하는 모바일 게임 화면" srcset="
/ko/contest-projects/soulslike-game/featured_huc9101a96c8e5001f64267bf0e701aeb1_661246_7782082344e6c04a43cd21618285a669.webp 400w,
/ko/contest-projects/soulslike-game/featured_huc9101a96c8e5001f64267bf0e701aeb1_661246_d3a9aa8f82861343ea4f7480ac930556.webp 760w,
/ko/contest-projects/soulslike-game/featured_huc9101a96c8e5001f64267bf0e701aeb1_661246_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/soulslike-game/featured_huc9101a96c8e5001f64267bf0e701aeb1_661246_7782082344e6c04a43cd21618285a669.webp"
width="760"
height="458"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="경기장에서 전투 시스템을 확인하는 플레이 화면" srcset="
/ko/contest-projects/soulslike-game/detail-combat_hu1c4b45dc22f9ac56ff407a6f78d81a40_324198_ba990360e71a76cfd51169b51500ccea.webp 400w,
/ko/contest-projects/soulslike-game/detail-combat_hu1c4b45dc22f9ac56ff407a6f78d81a40_324198_177b8c3dab202d734adad15b58b5af16.webp 760w,
/ko/contest-projects/soulslike-game/detail-combat_hu1c4b45dc22f9ac56ff407a6f78d81a40_324198_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/soulslike-game/detail-combat_hu1c4b45dc22f9ac56ff407a6f78d81a40_324198_ba990360e71a76cfd51169b51500ccea.webp"
width="760"
height="344"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;h2 id="트러블-슈팅">트러블 슈팅&lt;/h2>
&lt;h3 id="1-공격-판정과-animation-timing이-어긋나-유효-타격이-불분명">1. 공격 판정과 animation timing이 어긋나 유효 타격이 불분명&lt;/h3>
&lt;p>hitbox lifecycle을 animation event와 연결했습니다.&lt;/p>
&lt;h3 id="2-피격스태미나-처리가-여러-스크립트에서-중복">2. 피격·스태미나 처리가 여러 스크립트에서 중복&lt;/h3>
&lt;p>최근 커밋에서 combat hit와 stamina 흐름을 정리했습니다.&lt;/p>
&lt;h3 id="3-대형-unity-library가-저장소에-포함">3. 대형 Unity Library가 저장소에 포함&lt;/h3>
&lt;p>외부 asset과 생성 파일 범위를 문서화하고 metadata를 정리했습니다.&lt;/p>
&lt;h2 id="기술-선택과-이유">기술 선택과 이유&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>기술&lt;/th>
&lt;th>선택 이유&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Combat state&lt;/strong>&lt;/td>
&lt;td>공격·회피·피격 중 허용되는 입력을 명확히 제한하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Stamina&lt;/strong>&lt;/td>
&lt;td>무한 회피·공격을 막고 위험/보상의 리듬을 만들기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Animation hitbox timing&lt;/strong>&lt;/td>
&lt;td>보이는 무기 궤적과 실제 damage 판정을 맞추기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Cinemachine · VFX&lt;/strong>&lt;/td>
&lt;td>보스 공격 범위와 피격 결과를 즉시 읽게 하기 위해&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="검증-결과">검증 결과&lt;/h2>
&lt;ul>
&lt;li>회피 후 반격·콤보·보스 범위 공격의 핵심 전투 loop를 구현했습니다.&lt;/li>
&lt;li>2022 초기 구현에서 2026 전투 hit/stamina 리팩터링까지 개선 이력이 남아 있습니다.&lt;/li>
&lt;/ul>
&lt;h2 id="시스템-흐름">시스템 흐름&lt;/h2>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="소울라이크 전투 시스템 시스템 흐름"
src="https://eecczz.github.io/ko/contest-projects/soulslike-game/architecture.svg"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;ol>
&lt;li>입력을 attack/dodge 명령으로 변환합니다.&lt;/li>
&lt;li>combat state와 stamina가 실행 가능 여부를 결정합니다.&lt;/li>
&lt;li>animation event가 hitbox 활성 시간을 엽니다.&lt;/li>
&lt;li>Enemy AI가 거리와 상태에 따라 공격을 선택합니다.&lt;/li>
&lt;li>collision이 damage·stagger를 계산합니다.&lt;/li>
&lt;li>camera·sound·VFX가 결과를 피드백합니다.&lt;/li>
&lt;/ol>
&lt;h2 id="api--시스템-경계">API · 시스템 경계&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>영역&lt;/th>
&lt;th>API/계약&lt;/th>
&lt;th>책임&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>Input&lt;/code>&lt;/td>
&lt;td>&lt;code>attack/dodge&lt;/code>&lt;/td>
&lt;td>명령&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>State&lt;/code>&lt;/td>
&lt;td>&lt;code>stamina/combo&lt;/code>&lt;/td>
&lt;td>전투 규칙&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Hit&lt;/code>&lt;/td>
&lt;td>&lt;code>animation event + collider&lt;/code>&lt;/td>
&lt;td>판정&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Feedback&lt;/code>&lt;/td>
&lt;td>&lt;code>camera/VFX/sound&lt;/code>&lt;/td>
&lt;td>결과 전달&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="다음-구현-계획">다음 구현 계획&lt;/h2>
&lt;ul>
&lt;li>state machine과 animation graph의 테스트 가능한 경계 분리&lt;/li>
&lt;li>damage frame·input latency 계측&lt;/li>
&lt;li>보스 패턴별 playtest telemetry&lt;/li>
&lt;/ul></description></item><item><title>TRIPICK — 관광 코스 검증</title><link>https://eecczz.github.io/ko/contest-projects/tripick/</link><pubDate>Wed, 08 Jul 2026 00:00:00 +0000</pubDate><guid>https://eecczz.github.io/ko/contest-projects/tripick/</guid><description>&lt;div class="case-study-lead">
&lt;p class="case-study-kicker">BACKEND · AI · SYSTEM CASE STUDY&lt;/p>
&lt;p>TourAPI 관광지와 GPS 수행·리뷰·완주율을 결합해 검증된 코스를 다시 추천하는 참여형 플랫폼입니다.&lt;/p>
&lt;div class="case-study-meta">&lt;span>&lt;b>역할&lt;/b> Backend 역할 · TourAPI proxy/데이터 흐름/Trust Score/GPS 검증&lt;/span>&lt;span>&lt;b>검증&lt;/b> Web→React Native 확장 프로토타입&lt;/span>&lt;/div>
&lt;/div>
&lt;h2 id="주요-화면">주요 화면&lt;/h2>
&lt;p>홈에서는 현재 위치를 기준으로 주변 코스를 제안하고, 등록 코스·수행자 수와 새로 열린 코스를 한 화면에 배치했습니다. 사용자는 스타일·시간·이동 방식으로 스마트 코스를 만들거나 실제 이용자가 등록한 코스를 바로 탐색할 수 있습니다. 코스 카드에서는 거리·경유지 수·테마를 먼저 비교한 뒤 상세 화면으로 진입합니다.&lt;/p>
&lt;div class="screen-gallery screen-gallery--portrait">
&lt;figure>
&lt;img src="detail-home.webp" alt="현재 위치와 새로 열린 코스를 보여주는 TRIPICK 홈 화면">
&lt;figcaption>현재 위치 추천과 스마트 코스 진입&lt;/figcaption>
&lt;/figure>
&lt;figure>
&lt;img src="detail-courses.webp" alt="전주의 시장·한옥마을·예술마을 코스를 탐색하는 화면">
&lt;figcaption>거리·경유지·테마를 비교하는 코스 목록&lt;/figcaption>
&lt;/figure>
&lt;/div>
&lt;h2 id="트러블-슈팅">트러블 슈팅&lt;/h2>
&lt;h3 id="1-tourapi-cors키-형식실패가-웹과-앱에서-다르게-발생">1. TourAPI CORS·키 형식·실패가 웹과 앱에서 다르게 발생&lt;/h3>
&lt;p>proxy와 직접 호출 계약을 맞추고 mock fallback과 데이터 source 배지를 두었습니다.&lt;/p>
&lt;h3 id="2-별점만으로는-실제-수행-가능한-코스인지-판단하기-어려움">2. 별점만으로는 실제 수행 가능한 코스인지 판단하기 어려움&lt;/h3>
&lt;p>수행자 수·완주율·리뷰를 분리해 Trust Score와 설명 항목을 만들었습니다.&lt;/p>
&lt;h3 id="3-web-프로토타입과-react-native-코드가-갈라짐">3. Web 프로토타입과 React Native 코드가 갈라짐&lt;/h3>
&lt;p>공통 category와 trust 계산 규칙을 TypeScript로 이식하고 monorepo로 정리했습니다.&lt;/p>
&lt;h2 id="기술-선택과-이유">기술 선택과 이유&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>기술&lt;/th>
&lt;th>선택 이유&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>TourAPI proxy&lt;/strong>&lt;/td>
&lt;td>브라우저 CORS와 인증키 노출을 줄이고 응답을 캐시하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>React Native · Expo&lt;/strong>&lt;/td>
&lt;td>GPS check-in을 실제 모바일 사용 흐름에서 검증하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Browser Geolocation&lt;/strong>&lt;/td>
&lt;td>단순 작성자 추천이 아니라 실제 방문·완주 근거를 남기기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Trust Score&lt;/strong>&lt;/td>
&lt;td>별점만이 아니라 수행자 수·완주율·리뷰를 조합하기 위해&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="검증-결과">검증 결과&lt;/h2>
&lt;ul>
&lt;li>TourAPI→코스 생성→GPS 수행→리뷰/Trust→랭킹의 데이터 선순환을 구현했습니다.&lt;/li>
&lt;li>Web에서 React Native로 확장하며 지도 preview·check-in·trace persistence를 커밋 단위로 추가했습니다.&lt;/li>
&lt;/ul>
&lt;h2 id="시스템-흐름">시스템 흐름&lt;/h2>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="TRIPICK — 관광 코스 검증 시스템 흐름"
src="https://eecczz.github.io/ko/contest-projects/tripick/architecture.svg"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;ol>
&lt;li>TourAPI에서 전주 관광지 데이터를 정규화합니다.&lt;/li>
&lt;li>사용자가 후보를 조합해 코스를 만듭니다.&lt;/li>
&lt;li>모바일 GPS check-in이 방문·완주 흔적을 저장합니다.&lt;/li>
&lt;li>리뷰와 수행자 수·완주율을 Trust Score에 반영합니다.&lt;/li>
&lt;li>점수와 추천 사유를 카드·상세 화면에 표시합니다.&lt;/li>
&lt;li>검증된 코스가 랭킹에서 다시 노출됩니다.&lt;/li>
&lt;/ol>
&lt;h2 id="api--시스템-경계">API · 시스템 경계&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>영역&lt;/th>
&lt;th>API/계약&lt;/th>
&lt;th>책임&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>Tour&lt;/code>&lt;/td>
&lt;td>&lt;code>GET /spots&lt;/code>&lt;/td>
&lt;td>TourAPI proxy·cache&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Course&lt;/code>&lt;/td>
&lt;td>&lt;code>create/detail/trace&lt;/code>&lt;/td>
&lt;td>코스·수행 기록&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>GPS&lt;/code>&lt;/td>
&lt;td>&lt;code>check-in&lt;/code>&lt;/td>
&lt;td>방문 검증&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Trust&lt;/code>&lt;/td>
&lt;td>&lt;code>score + reason&lt;/code>&lt;/td>
&lt;td>랭킹 근거&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="다음-구현-계획">다음 구현 계획&lt;/h2>
&lt;ul>
&lt;li>서버 영속 DB와 사용자 인증 연결&lt;/li>
&lt;li>GPS spoofing·중복 check-in 방지&lt;/li>
&lt;li>Trust Score 가중치 A/B 테스트와 운영 지표&lt;/li>
&lt;/ul></description></item><item><title>SpeakUp — AI 발표 코칭</title><link>https://eecczz.github.io/ko/contest-projects/speech-coach/</link><pubDate>Mon, 01 Jun 2026 00:00:00 +0000</pubDate><guid>https://eecczz.github.io/ko/contest-projects/speech-coach/</guid><description>&lt;div class="case-study-lead">
&lt;p class="case-study-kicker">BACKEND · AI · SYSTEM CASE STUDY&lt;/p>
&lt;p>음성·시선·자세·표정 신호를 실시간 집계하고 세션 종료 후 종합 리포트를 만드는 AI 코칭 서비스입니다.&lt;/p>
&lt;div class="case-study-meta">&lt;span>&lt;b>역할&lt;/b> 3인 팀 팀장 · 주제/서비스 구조/실시간 코칭 및 리포트 구현&lt;/span>&lt;span>&lt;b>검증&lt;/b> 교내 AI-SW 경진대회 동상&lt;/span>&lt;/div>
&lt;/div>
&lt;h2 id="주요-화면">주요 화면&lt;/h2>
&lt;p>발표 장면을 녹화하는 동안 시선·표정·자세·음성을 분석하고, 종료 후에는 언어적·비언어적 지표를 점수와 코칭 문장으로 정리합니다.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="카메라 발표 장면과 실시간 분석 항목을 보여주는 화면" srcset="
/ko/contest-projects/speech-coach/detail-dashboard_hubb5bfd13ca2e5c0b5d2894f84361cfca_432942_2237c31b435d7d495fe05470846a138c.webp 400w,
/ko/contest-projects/speech-coach/detail-dashboard_hubb5bfd13ca2e5c0b5d2894f84361cfca_432942_e44d97cd7ca9fe75aa143d5a899e51d2.webp 760w,
/ko/contest-projects/speech-coach/detail-dashboard_hubb5bfd13ca2e5c0b5d2894f84361cfca_432942_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/speech-coach/detail-dashboard_hubb5bfd13ca2e5c0b5d2894f84361cfca_432942_2237c31b435d7d495fe05470846a138c.webp"
width="760"
height="359"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="발표 결과를 요소별 점수와 문장으로 정리한 리포트" srcset="
/ko/contest-projects/speech-coach/detail-ai_hu81b765d77bb3a018a8f1520bb396fb12_259745_bf1f4a5d73677a248cd694fdf72b3269.webp 400w,
/ko/contest-projects/speech-coach/detail-ai_hu81b765d77bb3a018a8f1520bb396fb12_259745_842c9ade81513c7e4264f641d572d4b0.webp 760w,
/ko/contest-projects/speech-coach/detail-ai_hu81b765d77bb3a018a8f1520bb396fb12_259745_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/speech-coach/detail-ai_hu81b765d77bb3a018a8f1520bb396fb12_259745_bf1f4a5d73677a248cd694fdf72b3269.webp"
width="760"
height="365"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="발표 세션의 핵심 지표를 요약한 결과 화면" srcset="
/ko/contest-projects/speech-coach/featured_hu0f13714c8ed805a5cd7d7ed472e67b97_46181_0f625976500b3632cd411ec59fe40e82.webp 400w,
/ko/contest-projects/speech-coach/featured_hu0f13714c8ed805a5cd7d7ed472e67b97_46181_67d38e741dc94e982d2b0052801fd019.webp 760w,
/ko/contest-projects/speech-coach/featured_hu0f13714c8ed805a5cd7d7ed472e67b97_46181_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/speech-coach/featured_hu0f13714c8ed805a5cd7d7ed472e67b97_46181_0f625976500b3632cd411ec59fe40e82.webp"
width="760"
height="433"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;h2 id="트러블-슈팅">트러블 슈팅&lt;/h2>
&lt;h3 id="1-프레임마다-llm을-호출하면-지연비용반복-피드백이-커짐">1. 프레임마다 LLM을 호출하면 지연·비용·반복 피드백이 커짐&lt;/h3>
&lt;p>MediaPipe는 5 FPS로 처리하고 isFinal 문장 경계에서만 LLM을 호출했습니다.&lt;/p>
&lt;h3 id="2-긴-세션에서-payload와-피드백이-누적되어-ui가-불안정">2. 긴 세션에서 payload와 피드백이 누적되어 UI가 불안정&lt;/h3>
&lt;p>최근 구간 window와 최소 2초 코칭 간격을 두고 practice 화면 스크롤 영역을 분리했습니다.&lt;/p>
&lt;h3 id="3-1분-이상-녹화-후-제출하면-리포트-화면으로-넘어가지-않음">3. 1분 이상 녹화 후 제출하면 리포트 화면으로 넘어가지 않음&lt;/h3>
&lt;p>MediaRecorder 중지 자체보다, 커진 WebM Blob을 IndexedDB에 저장하는 비동기 작업과 페이지 이동 사이의 경쟁 조건을 의심했습니다. 기존 helper는 object store의 &lt;code>put()&lt;/code> 성공 시 resolve해 실제 transaction commit 완료 전에 다음 화면으로 이동할 수 있었습니다.&lt;/p>
&lt;p>영상 Blob은 용량 제한이 작은 localStorage가 아닌 IndexedDB에 저장하고, &lt;code>request.onsuccess&lt;/code>가 아니라 transaction의 &lt;code>oncomplete&lt;/code>에서 Promise를 끝내도록 수정했습니다. 그 뒤에만 pending metadata를 localStorage에 기록하고 loading 화면으로 이동하게 순서를 고정했습니다. 분석 완료 후 media key도 지우지 않아 리포트에서 원본 영상을 다시 불러오도록 했습니다.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="SpeakUp 녹화 종료와 IndexedDB 저장 순서"
src="https://eecczz.github.io/ko/contest-projects/speech-coach/code-recording-handoff.svg"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;h3 id="4-녹화와-아바타-캔버스를-함께-남겨야-함">4. 녹화와 아바타 캔버스를 함께 남겨야 함&lt;/h3>
&lt;p>브라우저 녹화 경로를 조정하고 MP4 변환 및 리포트 토글까지 연결했습니다.&lt;/p>
&lt;h2 id="기술-선택과-이유">기술 선택과 이유&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>기술&lt;/th>
&lt;th>선택 이유&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>MediaPipe 5 FPS&lt;/strong>&lt;/td>
&lt;td>브라우저에서 시선·자세·표정 신호를 실시간 처리하되 연산 부하를 통제하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Web Speech API&lt;/strong>&lt;/td>
&lt;td>문장 완료 시점을 빠르게 감지해 코칭 트리거와 전사 맥락에 사용하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>FastAPI microservices&lt;/strong>&lt;/td>
&lt;td>audio·aggregator·coach의 서로 다른 실시간/배치 책임을 분리하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>PostgreSQL · Docker Compose&lt;/strong>&lt;/td>
&lt;td>세션·대화 기록을 보존하고 여러 서비스를 같은 실행 환경으로 묶기 위해&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="검증-결과">검증 결과&lt;/h2>
&lt;ul>
&lt;li>실시간 언어적·비언어적 피드백과 종료 후 복기 흐름을 하나의 서비스로 완성했습니다.&lt;/li>
&lt;li>3인 팀을 이끌어 교내 AI-SW 경진대회 동상을 수상했습니다.&lt;/li>
&lt;li>저장소에는 서비스별 코드, Docker Compose, API endpoint, 수정 커밋이 남아 있습니다.&lt;/li>
&lt;/ul>
&lt;h2 id="시스템-흐름">시스템 흐름&lt;/h2>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="SpeakUp — AI 발표 코칭 시스템 흐름"
src="https://eecczz.github.io/ko/contest-projects/speech-coach/architecture.svg"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;ol>
&lt;li>브라우저가 카메라·마이크를 받고 MediaPipe 신호를 계산합니다.&lt;/li>
&lt;li>WebSocket으로 vision/prosody/STT frame을 aggregator에 전달합니다.&lt;/li>
&lt;li>aggregator가 5초 window를 만들고 live coach 규칙을 호출합니다.&lt;/li>
&lt;li>완료 문장 단위로 LLM 피드백을 요청하며 최소 2초 간격으로 반복을 억제합니다.&lt;/li>
&lt;li>종료 후 faster-whisper·librosa·ffmpeg가 전사/운율/영상 산출물을 만듭니다.&lt;/li>
&lt;li>IndexedDB transaction 완료 뒤 분석 화면으로 이동하고, coach 결과와 보존된 media key를 리포트 UI가 함께 사용합니다.&lt;/li>
&lt;/ol>
&lt;h2 id="api--시스템-경계">API · 시스템 경계&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>영역&lt;/th>
&lt;th>API/계약&lt;/th>
&lt;th>책임&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>WS&lt;/code>&lt;/td>
&lt;td>&lt;code>/ws/signals, /ws/hud&lt;/code>&lt;/td>
&lt;td>실시간 신호·HUD&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Session&lt;/code>&lt;/td>
&lt;td>&lt;code>POST /session/start, /end&lt;/code>&lt;/td>
&lt;td>분석 window lifecycle&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Audio&lt;/code>&lt;/td>
&lt;td>&lt;code>POST /transcribe, /convert/mp4, /analyze&lt;/code>&lt;/td>
&lt;td>STT·운율·미디어&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Coach&lt;/code>&lt;/td>
&lt;td>&lt;code>POST /live, /comprehensive, /agent-feedback&lt;/code>&lt;/td>
&lt;td>실시간/종합 코칭&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="다음-구현-계획">다음 구현 계획&lt;/h2>
&lt;ul>
&lt;li>실사용자 세션으로 코칭 정확도·유용성 평가&lt;/li>
&lt;li>signal/LLM 장애 시 fallback과 재처리 queue 강화&lt;/li>
&lt;li>세션 간 지표 비교와 운영 모니터링 추가&lt;/li>
&lt;/ul></description></item><item><title>전북도청 대도민 음성 챗봇</title><link>https://eecczz.github.io/ko/contest-projects/jeonbuk-chatbot/</link><pubDate>Mon, 01 Jun 2026 00:00:00 +0000</pubDate><guid>https://eecczz.github.io/ko/contest-projects/jeonbuk-chatbot/</guid><description>&lt;div class="case-study-lead">
&lt;p class="case-study-kicker">BACKEND · AI · SYSTEM CASE STUDY&lt;/p>
&lt;p>전북도청·시군 데이터를 GraphRAG로 검색하고 STT/TTS로 전달하는 공공 음성 정보 서비스입니다.&lt;/p>
&lt;div class="case-study-meta">&lt;span>&lt;b>역할&lt;/b> 캡스톤 · FastAPI/음성 파이프라인/GraphRAG/크롤러 운영&lt;/span>&lt;span>&lt;b>검증&lt;/b> 캡스톤 최우수상 · 전북도지사 표창&lt;/span>&lt;/div>
&lt;/div>
&lt;h2 id="주요-화면">주요 화면&lt;/h2>
&lt;p>도청·시군 정보를 질문하면 검색 근거를 바탕으로 답변하고, 음성 대화 중에는 아바타 상태와 사용자 발화 흐름을 함께 표시합니다.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="도청 정보를 답변하는 음성 챗봇 대화 화면" srcset="
/ko/contest-projects/jeonbuk-chatbot/detail-avatar_huadd56ca1c3490bb163ed8cad45c2ad1c_45226_36781687c7b001547a30bb558bf0f59e.webp 400w,
/ko/contest-projects/jeonbuk-chatbot/detail-avatar_huadd56ca1c3490bb163ed8cad45c2ad1c_45226_6193e958071d44c1bb38306f6943365e.webp 760w,
/ko/contest-projects/jeonbuk-chatbot/detail-avatar_huadd56ca1c3490bb163ed8cad45c2ad1c_45226_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/jeonbuk-chatbot/detail-avatar_huadd56ca1c3490bb163ed8cad45c2ad1c_45226_36781687c7b001547a30bb558bf0f59e.webp"
width="377"
height="572"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="음성 응답 상태를 보여주는 챗봇 아바타 화면" srcset="
/ko/contest-projects/jeonbuk-chatbot/featured_huc2e0e8824a413a5e846cf383c911210a_322862_80afd16d2bfe2d078c9c1c891052d5aa.webp 400w,
/ko/contest-projects/jeonbuk-chatbot/featured_huc2e0e8824a413a5e846cf383c911210a_322862_a0c7455d5f99eba44745c4439a50c48e.webp 760w,
/ko/contest-projects/jeonbuk-chatbot/featured_huc2e0e8824a413a5e846cf383c911210a_322862_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/jeonbuk-chatbot/featured_huc2e0e8824a413a5e846cf383c911210a_322862_80afd16d2bfe2d078c9c1c891052d5aa.webp"
width="499"
height="760"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;h2 id="트러블-슈팅">트러블 슈팅&lt;/h2>
&lt;h3 id="1-ai가-말하는-중에도-사용자의-새-발화를-받아야-함">1. AI가 말하는 중에도 사용자의 새 발화를 받아야 함&lt;/h3>
&lt;p>요청 한 번에 STT→답변→TTS를 모두 끝내는 단방향 흐름 대신 socket 기반 실시간 음성 파이프라인으로 재구성했습니다. 사용자 발화가 감지되면 진행 중인 응답·재생을 중단하고 새 발화 처리를 시작하는 barge-in 흐름을 적용했습니다.&lt;/p>
&lt;h3 id="2-일별-전체-수집이-늦어-페이지-누락과-embedding-서버-오류가-발생">2. 일별 전체 수집이 늦어 페이지 누락과 embedding 서버 오류가 발생&lt;/h3>
&lt;p>직접 구현한 사이트별 수집기의 예외를 계속 보강하는 대신 Crawl4AI를 도입해 동적 페이지·본문 정제·비동기 수집을 표준화했습니다. 전체 수집만 반복하지 않고 incremental/full/site 단위 실행을 나눠 실패 범위와 BGE-M3 embedding 부하를 줄였습니다.&lt;/p>
&lt;h3 id="3-rag-답변이-느려-오픈소스-모델의-한계라고-단정하기-쉬움">3. RAG 답변이 느려 오픈소스 모델의 한계라고 단정하기 쉬움&lt;/h3>
&lt;p>파이프라인만 의심하지 않고 서로 다른 크기의 Qwen 3.5 모델로 같은 질의를 비교해 모델 선택이 end-to-end latency에 미치는 영향을 확인하고 응답 모델을 교체했습니다.&lt;/p>
&lt;h3 id="4-stt가-발화-첫-음절을-자주-놓침">4. STT가 발화 첫 음절을 자주 놓침&lt;/h3>
&lt;p>초기 테스트에서 VAD 기본값을 그대로 사용해 음성이 충분히 들어온 뒤에야 STT 구간이 시작됐습니다. VAD의 발화 시작 지연과 confidence 관련 값을 조정해 감지 직후부터 음성 버퍼가 STT로 전달되게 하고, 첫 소리 인식률을 대화 테스트로 반복 확인했습니다.&lt;/p>
&lt;h3 id="5-지자체별-urlspa-구조-차이로-일부-수집-실패">5. 지자체별 URL·SPA 구조 차이로 일부 수집 실패&lt;/h3>
&lt;p>실제 URL과 base path를 사이트별 설정으로 분리하고, 일반 HTML과 브라우저 렌더링이 필요한 페이지를 같은 실패 경로로 묶지 않았습니다.&lt;/p>
&lt;h2 id="기술-선택과-이유">기술 선택과 이유&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>기술&lt;/th>
&lt;th>선택 이유&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>FastAPI&lt;/strong>&lt;/td>
&lt;td>STT·검색·LLM·TTS처럼 지연 특성이 다른 단계를 비동기 API로 조합하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>STT/TTS&lt;/strong>&lt;/td>
&lt;td>웹 탐색이 익숙하지 않은 도민도 자연어 음성으로 정책·민원을 찾게 하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>GraphRAG&lt;/strong>&lt;/td>
&lt;td>도청 대규모 문서의 관계와 출처를 보존하며 답변 근거를 검색하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Incremental crawler&lt;/strong>&lt;/td>
&lt;td>11개 일반 사이트와 SPA 사이트의 갱신 주기와 실패 양상이 달라 부분 재수집하기 위해&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="검증-결과">검증 결과&lt;/h2>
&lt;ul>
&lt;li>도민 대상 실제 서비스 목표로 공공 데이터 수집·검색·음성 응답 전 과정을 구현했습니다.&lt;/li>
&lt;li>캡스톤디자인 최우수상과 전북도청 도지사 표창을 받았습니다.&lt;/li>
&lt;li>크롤러 rollback·증분 배포·사이트별 장애 격리 기록이 실제 운영 경험으로 남아 있습니다.&lt;/li>
&lt;/ul>
&lt;h2 id="시스템-흐름">시스템 흐름&lt;/h2>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="전북도청 대도민 음성 챗봇 시스템 흐름"
src="https://eecczz.github.io/ko/contest-projects/jeonbuk-chatbot/architecture.svg"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;ol>
&lt;li>사용자 음성을 STT로 텍스트화합니다.&lt;/li>
&lt;li>질의를 정규화하고 대화 맥락과 함께 FastAPI에 전달합니다.&lt;/li>
&lt;li>GraphRAG가 도청·시군 데이터에서 관련 노드와 문서를 찾습니다.&lt;/li>
&lt;li>LLM이 검색 근거를 바탕으로 답변을 생성합니다.&lt;/li>
&lt;li>TTS가 답변을 음성으로 변환하고 캐릭터 UI와 동기화합니다.&lt;/li>
&lt;li>크롤러가 incremental/full/site 단위로 원천 데이터를 갱신합니다.&lt;/li>
&lt;/ol>
&lt;h2 id="api--시스템-경계">API · 시스템 경계&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>영역&lt;/th>
&lt;th>API/계약&lt;/th>
&lt;th>책임&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>Crawler&lt;/code>&lt;/td>
&lt;td>&lt;code>POST /api/v1/crawler/trigger/incremental&lt;/code>&lt;/td>
&lt;td>변경분 수집&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Crawler&lt;/code>&lt;/td>
&lt;td>&lt;code>POST /trigger/full&lt;/code>&lt;/td>
&lt;td>전체 재수집&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Crawler&lt;/code>&lt;/td>
&lt;td>&lt;code>POST /trigger/site/{code}&lt;/code>&lt;/td>
&lt;td>사이트별 장애 격리&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Chat&lt;/code>&lt;/td>
&lt;td>&lt;code>STT → GraphRAG → LLM → TTS&lt;/code>&lt;/td>
&lt;td>도민 음성 응답&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="다음-구현-계획">다음 구현 계획&lt;/h2>
&lt;ul>
&lt;li>답변마다 문서 출처와 최신 수집 시각 표시&lt;/li>
&lt;li>SPA 크롤러의 browser pool·timeout·retry 운영 지표 추가&lt;/li>
&lt;li>STT/LLM/TTS 구간별 latency와 실패율 모니터링&lt;/li>
&lt;/ul></description></item><item><title>Gone — 선택형 액션 어드벤처</title><link>https://eecczz.github.io/ko/contest-projects/gone/</link><pubDate>Sat, 06 Apr 2024 00:00:00 +0000</pubDate><guid>https://eecczz.github.io/ko/contest-projects/gone/</guid><description>&lt;div class="case-study-lead">
&lt;p class="case-study-kicker">BACKEND · AI · SYSTEM CASE STUDY&lt;/p>
&lt;p>Fungus 기반 선택 분기와 세로형 액션 진행을 결합한 Coala 동아리 4인 팀 프로젝트입니다.&lt;/p>
&lt;div class="case-study-meta">&lt;span>&lt;b>역할&lt;/b> 4인 팀 · 스토리 흐름/액션 진행/모바일 UI&lt;/span>&lt;span>&lt;b>검증&lt;/b> 동아리 팀 프로젝트&lt;/span>&lt;/div>
&lt;/div>
&lt;h2 id="주요-화면">주요 화면&lt;/h2>
&lt;p>선택형 대화 장면에서 스토리를 진행하고, 분기 이후에는 세로형 전투 화면으로 전환되도록 구성했습니다. 시작 메뉴·대화·전투가 서로 다른 scene이지만 진행 상태는 이어집니다.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="선택지와 캐릭터 대화가 표시되는 스토리 화면" srcset="
/ko/contest-projects/gone/detail-story_hu694b21ae79a4efcf574a3599285bb600_16607_1d3c9acecc0ece1c255045d1c3705add.webp 400w,
/ko/contest-projects/gone/detail-story_hu694b21ae79a4efcf574a3599285bb600_16607_6761770f4a532368e3e633a03293e457.webp 760w,
/ko/contest-projects/gone/detail-story_hu694b21ae79a4efcf574a3599285bb600_16607_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/gone/detail-story_hu694b21ae79a4efcf574a3599285bb600_16607_1d3c9acecc0ece1c255045d1c3705add.webp"
width="196"
height="343"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="세로형 화면에서 진행되는 전투 장면" srcset="
/ko/contest-projects/gone/detail-game_huabefa9c21bfe1f120dbbd37d64f25c71_252768_b48b68be11cb451b8b8dbd0ece7a0370.webp 400w,
/ko/contest-projects/gone/detail-game_huabefa9c21bfe1f120dbbd37d64f25c71_252768_6117ac600c9197c83d43bc19e680a6f8.webp 760w,
/ko/contest-projects/gone/detail-game_huabefa9c21bfe1f120dbbd37d64f25c71_252768_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/gone/detail-game_huabefa9c21bfe1f120dbbd37d64f25c71_252768_b48b68be11cb451b8b8dbd0ece7a0370.webp"
width="760"
height="760"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="모바일 화면 비율에 맞춘 시작 메뉴" srcset="
/ko/contest-projects/gone/detail-mobile_hue3d76723223a2270cc94622238090a51_44920_f11d3227c03253b438b1d7a32fb8619f.webp 400w,
/ko/contest-projects/gone/detail-mobile_hue3d76723223a2270cc94622238090a51_44920_81a468a4fdd9ca520c807808b386aaa1.webp 760w,
/ko/contest-projects/gone/detail-mobile_hue3d76723223a2270cc94622238090a51_44920_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://eecczz.github.io/ko/contest-projects/gone/detail-mobile_hue3d76723223a2270cc94622238090a51_44920_f11d3227c03253b438b1d7a32fb8619f.webp"
width="194"
height="349"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;h2 id="트러블-슈팅">트러블 슈팅&lt;/h2>
&lt;h3 id="1-스토리-분기와-전투-scene이-서로의-상태를-잃기-쉬움">1. 스토리 분기와 전투 scene이 서로의 상태를 잃기 쉬움&lt;/h3>
&lt;p>선택·진행·ending 조건을 명시적인 state로 연결했습니다.&lt;/p>
&lt;h3 id="2-세로-화면에서-게임뷰와-조작-영역이-서로-침범">2. 세로 화면에서 게임뷰와 조작 영역이 서로 침범&lt;/h3>
&lt;p>상·하단을 1:1로 나눠 정보와 입력의 역할을 고정했습니다.&lt;/p>
&lt;h3 id="3-팀원이-동시에-flow를-수정할-때-책임-범위가-불명확">3. 팀원이 동시에 flow를 수정할 때 책임 범위가 불명확&lt;/h3>
&lt;p>Fungus block과 액션 구현을 나눠 통합했습니다.&lt;/p>
&lt;h2 id="기술-선택과-이유">기술 선택과 이유&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>기술&lt;/th>
&lt;th>선택 이유&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Fungus&lt;/strong>&lt;/td>
&lt;td>대화·선택·분기 상태를 빠르게 시각화하고 팀이 함께 수정하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Portrait UI&lt;/strong>&lt;/td>
&lt;td>상단 게임뷰와 하단 입력을 분리해 모바일 한 손 조작을 실험하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Choice state&lt;/strong>&lt;/td>
&lt;td>선택이 이후 전투와 ending 조건에 영향을 주게 하기 위해&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Unity scene flow&lt;/strong>&lt;/td>
&lt;td>스토리 구간과 전투 구간을 상태로 연결하기 위해&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="검증-결과">검증 결과&lt;/h2>
&lt;ul>
&lt;li>선택 기반 서사·멀티 엔딩과 액션 진행을 하나의 모바일 prototype으로 완성했습니다.&lt;/li>
&lt;li>백엔드 핵심 프로젝트는 아니므로 팀 협업과 상태 설계 근거로 보조 배치했습니다.&lt;/li>
&lt;/ul>
&lt;h2 id="시스템-흐름">시스템 흐름&lt;/h2>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Gone — 선택형 액션 어드벤처 시스템 흐름"
src="https://eecczz.github.io/ko/contest-projects/gone/architecture.svg"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;ol>
&lt;li>하단 touch UI가 이동·공격 입력을 만듭니다.&lt;/li>
&lt;li>Fungus block이 대화와 선택지를 실행합니다.&lt;/li>
&lt;li>선택 결과를 진행 state에 기록합니다.&lt;/li>
&lt;li>state에 따라 전투 scene과 몬스터·무기가 바뀝니다.&lt;/li>
&lt;li>완료 조건이 다음 스토리 block을 엽니다.&lt;/li>
&lt;li>누적 선택에 따라 ending을 분기합니다.&lt;/li>
&lt;/ol>
&lt;h2 id="api--시스템-경계">API · 시스템 경계&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>영역&lt;/th>
&lt;th>API/계약&lt;/th>
&lt;th>책임&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>Narrative&lt;/code>&lt;/td>
&lt;td>&lt;code>Fungus blocks&lt;/code>&lt;/td>
&lt;td>대화·분기&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Input&lt;/code>&lt;/td>
&lt;td>&lt;code>portrait touch UI&lt;/code>&lt;/td>
&lt;td>모바일 조작&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Combat&lt;/code>&lt;/td>
&lt;td>&lt;code>enemy/weapon state&lt;/code>&lt;/td>
&lt;td>액션 진행&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>Ending&lt;/code>&lt;/td>
&lt;td>&lt;code>choice conditions&lt;/code>&lt;/td>
&lt;td>멀티 엔딩&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="다음-구현-계획">다음 구현 계획&lt;/h2>
&lt;ul>
&lt;li>분기 graph와 save schema 문서화&lt;/li>
&lt;li>모바일 input usability test&lt;/li>
&lt;li>전투와 narrative state를 event bus로 느슨하게 결합&lt;/li>
&lt;/ul></description></item></channel></rss>