이게 뭔가요?What is it?
손을 떼면 화면이 목표 위치로 스스로 이동해 멈춥니다.세게 밀든 살살 밀든 설정한 그대로 착지합니다.Let go, and the screen moves to its target on its own and settles there. However hard or lightly you swipe, it lands exactly as configured.
웹툰·전자책·긴 글 서비스와 기기에 적용하는
스크롤 기술, XIY입니다.XIY is a scrolling technology designed for integration into webtoon, e-book, and long-form content services and devices.
손을 떼면 화면이 알아서 착지한다는 말이 무슨 뜻인지, 어디에 쓰는지, 무엇이 좋아지는지.이 세 가지만 보셔도 충분합니다.What "lands on target" means, where it is used, and what gets better. These three answers are enough to start.
손을 떼면 화면이 목표 위치로 스스로 이동해 멈춥니다.세게 밀든 살살 밀든 설정한 그대로 착지합니다.Let go, and the screen moves to its target on its own and settles there. However hard or lightly you swipe, it lands exactly as configured.
독자는 쓸어 넘기기만 하면 됩니다.서비스와 기기에 넣어 쓰니, 화면을 크게 바꾸지 않아도 됩니다.Readers just swipe. It integrates into services and devices without major changes to existing screens.
딱 맞게 착지합니다.속도와 부드러움은 직접 정해 저장해 쓰고, 읽던 자리를 다시 찾는 수고를 줄이는 것이 목표입니다.It lands right on target. You set and save speed and smoothness yourself; the goal is less effort finding your place again.
지금의 스크롤은 손을 뗀 뒤에도 화면이 한참 더 미끄러집니다.
지나치면 되돌리고, 모자라면 다시 밀고,
조금씩 다시 맞추다 보면
어느새 눈은 내용이 아니라 화면을 좇고 있습니다.Today’s scrolling keeps sliding long after you let go. You pull back when it overshoots and push again when it falls short, and while you keep readjusting, your eyes end up chasing the screen instead of the content.
목표를 지나쳤다가 되돌아와 다시 맞추는 움직임이 생깁니다.
손을 떼면 정해진 목표 위치까지 스스로 이동해 한 번에 착지합니다.
긴 글은 문단으로, 웹툰은 컷으로, 쇼핑은 상품 한 칸으로, 지도는 한가운데로.
착지할 곳은 화면마다 다르지만 원리는 하나입니다.
화면마다 조작 방식을 새로 만들 필요가 없습니다.Paragraphs for long reads, panels for webtoons, a single product for shopping, the center for maps. The landing point differs by screen, but the principle is the same, so there is no need to build a new interaction for each screen.
긴 글에는 이런 것들이 있습니다.Long reads come in all of these forms.
눌러서 펼치면 스마트폰·태블릿 예시 화면이 나옵니다.Open any item to see phone and tablet sample screens.
번호가 붙은 소제목과 표가 이어지는 글입니다.
손을 떼면 소제목이 목표 자리에 맞게 착지합니다.
A document with numbered headings and tables.
Let go, and the heading lands right at the target position.
장 제목과 문단이 이어지는 긴 글입니다.
손을 떼면 문장이 목표 자리에 맞게 착지합니다.
A long read of chapters and paragraphs.
Let go, and the sentence lands right at the target position.
짧은 문장과 대사가 빠르게 이어지는 연재 글입니다.
손을 떼면 대사가 목표 자리에 맞게 착지합니다.
A serial episode of short lines and dialogue.
Let go, and the dialogue lands right at the target position.
요약과 표, 근거가 함께 놓인 보고서입니다.
손을 떼면 요약과 표가 목표 자리에 맞게 착지합니다.
A report that brings summaries, tables and evidence together.
Let go, and the summary or table lands right at the target position.
from __future__ import annotations # 아직 정의되지 않은 클래스 이름도 타입 힌트에 쓸 수 있게 한다from dataclasses import dataclass, field # 값 객체를 간결하게 정의하기 위한 표준 라이브러리from datetime import date, timedelta # 반납 기한과 연체 일수 계산에 사용한다 — 날짜 단위로만 다룬다# ---- 설정값 -----------------------------------------------------------------------------------LOAN_DAYS = 14 # 기본 대출 기간(일) — 운영 규정에 따라 14일이며, 연장하면 같은 기간이 다시 더해진다MAX_LOANS_PER_MEMBER = 5 # 회원 1인이 동시에 빌릴 수 있는 최대 권수 (초과하면 LoanError 를 발생시킬 예정)LATE_FEE_PER_DAY = 100 # 연체료는 1일 1권당 100원 — 반납할 때 Loan.fee() 가 연체 일수와 곱해서 계산한다# ---- 예외 -------------------------------------------------------------------------------------class LoanError(Exception): # 대출 규칙을 어겼을 때 발생하는 전용 예외 — 메시지는 화면에 보여 준다 pass # 별도 동작 없이 예외 이름과 메시지만 전달한다 — 필요해지면 오류 코드를 여기에 추가한다# ---- 데이터 모델 -------------------------------------------------------------------------------@dataclass # __init__, __repr__, __eq__ 를 자동으로 만들어 주므로 반복되는 보일러플레이트 코드가 필요 없다class Loan: # 한 권의 대출 기록: 어떤 책을 누가 언제까지 빌렸는지, 몇 번 연장했는지를 담는 값 객체 isbn: str # 도서 고유 번호(ISBN) — 같은 책이면 항상 같은 값이고 문자열로 다룬다 member: str # 회원 식별자 (예: "m-101") — 이름이 아니라 번호를 쓰면 동명이인 문제가 없다 due: date # 반납 기한 — 이 날짜까지 반납하면 연체료가 붙지 않고, 다음 날부터 하루 단위로 부과된다 renewals: int = 0 # 지금까지 연장한 횟수 — 새 기록은 0 에서 시작하고 renew() 마다 1 씩 늘어난다 def days_late(self, today: date) -> int: # 기한을 넘긴 일수를 돌려준다 — 기한 안에서는 항상 0 이다 return max((today - self.due).days, 0) # 기한 전(음수)은 0 으로 잘라 낸다 def fee(self, today: date) -> int: # 연체료 = 연체 일수 × 하루 단가 — 기한 안에 반납하면 0원 return self.days_late(today) * LATE_FEE_PER_DAY # 별도의 조건 분기가 필요 없다# ---- 도서관 -----------------------------------------------------------------------------------class Library: # 소장 도서, 재고 수량, 진행 중인 대출 목록을 한곳에서 관리하는 서비스 객체 def add_book(self, isbn: str, title: str, copies: int = 1) -> None: # 새 도서를 등록한다 book = self.books.get(isbn) # dict.get 은 키가 없어도 KeyError 대신 None 을 돌려준다 if book is None: # 처음 등록하는 ISBN 일 때만 아래 줄이 실행된다 — 재등록 요청은 조용히 무시한다 self.books[isbn], self.copies[isbn] = title, copies # 제목과 권수를 함께 저장한다 def available(self, isbn: str) -> int: # 지금 빌릴 수 있는 남은 권수 = 소장 권수 − 대출 중인 권수 used = sum(1 for ln in self.loans # 제너레이터 식으로 해당 ISBN 의 대출 건만 센다 if ln.isbn == isbn) # 조건에 맞는 항목마다 1 을 더하는 방식이라 카운터 변수가 필요 없다 return self.copies[isbn] - used # 소장 권수는 등록 시점에 검증해 두어 결과가 음수가 되지 않는다 def borrow(self, isbn: str, member: str, today: date | None = None) -> Loan: # 대출 처리 if isbn not in self.books: # 목록에 없는 도서는 대출 자체가 불가능하므로 가장 먼저 걸러 낸다 raise LoanError(f"없는 도서입니다: {isbn} 은(는) 이 도서관에 등록되지 않았습니다.") if self.available(isbn) <= 0: # 재고가 없는 경우 — 예약 대기 안내로 이어지도록 구분한다 raise LoanError(f"모두 대출 중입니다: {isbn} 의 남은 권수가 없어 예약 대기로 안내합니다.") due = (today or date.today()) + timedelta(days=LOAN_DAYS) # 반납 기한 = 오늘 + 14일 loan = Loan(isbn, member, due) # 연장 횟수는 기본값 0 으로 시작한다 — 인자는 순서대로 넘긴다 self.loans.append(loan) # 진행 중인 대출 목록에 추가한다 — 이후 available() 계산에 바로 반영된다 return loan # 호출한 쪽에서 반납 기한을 안내 문구로 쓸 수 있도록 방금 만든 기록을 그대로 돌려준다 def give_back(self, isbn: str, member: str) -> int: # 반납 처리: 기록을 지우고 연체료를 돌려준다 loan = self._find(isbn, member) # 내부 검색 함수 — 밑줄로 시작하는 이름은 밖에서 쓰지 않는 관례 self.loans.remove(loan) # 목록에서 제거하면 재고가 즉시 늘어나 다른 회원이 바로 빌릴 수 있다 return loan.fee(date.today()) # 반납일 기준 연체료(원)를 계산해 돌려준다 — 정상 반납이면 0 def _find(self, isbn: str, member: str) -> Loan: # 도서와 회원이 모두 일치하는 대출 기록 1건 for loan in self.loans: # 진행 중인 모든 대출을 한 번씩 확인한다 — 반납된 기록은 이미 지워져 있다 if loan.isbn == isbn: # 실제 서비스에서는 member 도 함께 비교해야 한다 (예시라서 단순화) return loan # 처음 찾은 기록을 바로 돌려준다 — 같은 책을 두 권 빌린 경우는 다루지 않는다 def renew(self, isbn: str, member: str, today: date | None = None) -> Loan: # 연장 처리 loan = self._find(isbn, member) # 대출 기록 조회 — 반납과 같은 방식으로 찾는다 if loan.days_late(today or date.today()) > 0: # 이미 기한을 넘긴 대출은 연장할 수 없다 raise LoanError(f"연체 중입니다: {loan.days_late(today or date.today())}일 연체") loan.due += timedelta(days=LOAN_DAYS) # 기존 기한에서 14일을 더한다 loan.renewals += 1 # 연장 횟수를 기록한다 — 정책상 상한을 두려면 여기서 검사를 추가하면 된다 return loan # 갱신된 기한이 담긴 기록을 돌려주므로 호출한 쪽에서 바로 안내 문구를 만들 수 있다 def overdue_report(self, today: date) -> list[tuple[str, int]]: # 연체 현황 보고서 rows = [] # 결과를 담을 빈 목록 — 연체가 없으면 그대로 빈 목록이 반환되어 별도 검사가 필요 없다 for loan in self.loans: # 진행 중인 모든 대출을 한 번씩 확인한다 — 반납된 기록은 이미 지워져 있다 late = loan.days_late(today) # 오늘 기준 연체 일수 (기한 안이면 0) if late: # 0 이 아니면 연체 중이라는 뜻이다 — 0 은 거짓으로 취급되므로 이렇게 간단히 쓸 수 있다 rows.append((loan.member, late)) # 회원 식별자와 연체 일수를 묶어 저장한다 rows.sort(key=lambda r: r[1], reverse=True) # 연체 일수가 큰 순서로 정렬한다 return rows # 예: [("m-101", 12), ("m-207", 3)] — 화면 표나 안내 대상 선정에 쓴다# ---- 사용 예시 ---------------------------------------------------------------------------------def demo() -> None: # 간단한 사용 예시: 도서를 등록하고 대출한 뒤 연체 현황을 출력해 본다 (가상의 데이터) lib = Library() # 도서관 객체를 만든다 — 아직 소장 도서와 대출 기록이 모두 비어 있는 상태이다 day = date(2026, 3, 4) # 예시용 기준일 (실제 서비스에서는 date.today() 를 사용한다) lib.add_book("978-0", "바다의 지도") # 예시 도서 등록 — 가상의 데이터이며 실제 도서와 무관하다 lib.borrow("978-0", "m-101", day) # 회원 m-101 이 기준일에 대출한다 — 반납 기한은 14일 뒤로 정해진다 print(lib.overdue_report(day)) # 기준일 당일에는 연체가 없으므로 빈 목록 [] 이 출력된다# ---- 테스트 -----------------------------------------------------------------------------------def test_limit() -> None: # 동시 대출 한도를 확인하는 테스트 — pytest 가 자동으로 찾아 실행한다 lib = Library() # 도서관 객체를 만든다 — 아직 소장 도서와 대출 기록이 모두 비어 있는 상태이다 for n in range(6): # 도서 6종을 등록한다 — 한도(5권)보다 하나 더 많게 준비해 초과 상황을 만든다 lib.add_book(f"b{n}", "책") # f-문자열로 b0 ~ b5 형태의 ISBN 을 만든다 — 제목은 모두 같다 for n in range(5): # 한 회원이 5권까지는 문제없이 빌릴 수 있어야 한다 (한도는 MAX_LOANS_PER_MEMBER) lib.borrow(f"b{n}", "m-1", date.today()) # 다섯 번째까지는 모두 성공해야 한다 try: # 여섯 번째 대출은 한도 초과로 실패해야 한다 — 실패하는 것이 정상 동작이다 lib.borrow("b5", "m-1", date.today()) # 한도를 넘는 대출 시도 — 이 줄에서 예외가 나야 정상이다 except LoanError: # 기대한 예외가 발생하면 통과이며, 다른 종류의 예외는 잡지 않고 그대로 실패로 처리한다 pass # 예외가 나지 않을 때 테스트가 실패하도록 else 절에 assert False 를 추가하는 편이 더 안전하다줄 번호가 붙은 긴 코드입니다.
손을 떼면 함수와 줄이 목표 자리에 맞게 착지합니다.
Long code with line numbers.
Let go, and the function or line lands right at the target position.
예시 화면 · 모두 가상의 내용입니다.Sample screens. All content is fictional.
글의 모양은 달라도 원리는 같습니다.
손을 떼면 목표 자리로 착지합니다.The text takes different shapes, but the principle is the same: let go, and the screen lands on its target.
XIY는 사용자의 마음을 짐작하지 않습니다.
손을 뗀 자리에서 목표 자리까지의 거리만큼
화면이 스스로 이동해 착지합니다.
그래서 짧게 밀든 길게 밀든 도착하는 곳은 같습니다.XIY does not guess what the user intends. The screen moves on its own by exactly the distance from where you let go to the target, and lands there. So whether you swipe short or long, you arrive at the same place.
가까운 칸에 끌어다 붙이는 방식과는 다릅니다.
같은 자리에서 손을 떼면 언제나 같은 결과가 나옵니다.This is not snapping to the nearest slot.
Let go at the same point and you get the same result, every time.
서비스에 맞게 직접 조절합니다.
속도와 부드러움, 착지 위치, 이동이 시작되는 때(손을 뗄 때 · 손가락을 따라 움직이다 뗄 때 · 일정 거리를 넘을 때)를 정해 여러 설정으로 저장해 두고 골라 쓸 수 있고, 엔진은 정한 그대로 오차 없이 착지시킵니다.Tailor it to your service. Set speed, smoothness, landing position, and when movement begins (on release, on release after following the finger, or once a set distance is passed), then save multiple configurations to choose from. The engine lands exactly as configured, without deviation.
이 성질은 미팅 시연에서 직접 확인해 보실 수 있습니다.You can see this for yourself in a live demo, in a meeting.
좋은 기술이라도
고려해야 할 부분이 많으면 결정하기 어렵습니다.
그래서 권리 관계, 안정성, 연동 방법,
적용 이후의 대응까지
검토에 필요한 내용을 정리했습니다.Even a good technology is hard to commit to when there is a lot to consider. So we have organized what you need for review: rights, stability, integration, and support after adoption.
겉으로는 잘 드러나지 않지만, 하나하나 짚어 가며 대응해 온 상황입니다.These situations rarely show on the surface, but we have addressed each one, step by step.
다만 기기 자체의 결함이나 운영체제 오류는 기술이 통제할 수 있는 범위 밖입니다.However, device defects and operating-system errors are outside what the technology can control.
시연을 통해
화면이 정확한 지점에 착지하는 경험을 하실 수 있습니다.
읽고 넘기는 경험이 실제로 얼마나 달라지는지는
소규모 시범 적용(PoC)에서 함께 확인하겠습니다.
화면을 다시 맞추는 횟수, 원하는 곳까지 정확하고 손쉽게 도달하는 시간, 이어 읽기와 끝까지 읽기, 주의력 전환 손실 비용을 비교해 체감하실 수 있습니다.In a demo, you can experience the screen landing right on its target. How much the reading and browsing experience actually changes will be confirmed together in a small-scale pilot (PoC). You can compare and feel the difference in how often you readjust the screen, how quickly and accurately you reach where you want, continued and completed reading, and the cost of attention switching.
개선 폭은 기존 방식과의 비교 체험 및
다양한 검증 방식으로 함께 확인합니다.The degree of improvement will be confirmed together through side-by-side comparison with existing methods and a range of validation approaches.
어린이, 어르신, 장애가 있는 분, 공부에 집중하는 학생까지
손의 리듬은 사람마다 다릅니다.
누구에게 얼마나 도움이 될지는 미리 단정하지 않습니다.From children and older adults to people with disabilities and students deep in study, everyone’s hand rhythm is different. We do not assume in advance how much it will help whom.
섬세한 손놀림에 익숙하지 않아도 원하는 곳에 더 쉽게 닿을 수 있으리라 봅니다.
빠르게 반응하는 것보다 어디에 착지할지 예상할 수 있는 것을 먼저 생각하고, 되풀이를 줄이려 합니다.
손의 움직임이 일정하지 않아도 원하는 곳을 찾는 과정이 단순해지도록 합니다.
긴 글과 학습 자료에서 읽던 자리를 다시 찾는 일을 줄이려 합니다.
누구에게 실제로 도움이 되는지, 접근성에는 어떤 효과가 있는지는 따로 사용자 연구와 비교 실험으로 확인합니다.Who it actually helps, and what effect it has on accessibility, will be confirmed through separate user research and comparative testing.
XIY는 아직 정해지지 않은 손동작(X)에서 시작해,
손동작과 목표의 관계를 맞추고(I),
사용자가 실제로 마주하는 결과(Y)까지를
하나로 봅니다.XIY sees it as one whole: starting from an undetermined gesture (X), aligning the gesture with its target (I), and reaching the result the user actually sees (Y).
보시는 분의 목적에 맞춰 준비한 시연으로 안내드립니다.We tailor the demo to what you need to evaluate.
시연 요청Request a demo→문의 성격을 선택해 주시면
더 빠르게 안내드릴 수 있습니다.