EDITORCLASSBLOGLOGINimg default descriptionimg default descriptionimg default description표현한다는 것의무한한 가능성,새로운 형태로
담아내다.
img default descriptionimg default descriptionimg default descriptionimg default descriptionimg default descriptionimg default descriptionimg default description새로운 형태의 콘텐츠Opkle은 코드 없이 웹을 마음껏 만들고, 누구나 자기 화면을 그릴 수 있도록 에디터를 만들고, 그 결과물을 어디서나 즐길 수 있게 돕는 팀입니다.텍스트와 화면과의 조화를 통해, 웹을 짓는다는 것이 그저 단순한 코딩이 아닌, 상상을 펼치고 감각을 깨우는 과정이 될 수 있도록 좋은 도구를 만들어 냅니다.
옵클 에디터 개발기: 첫 번째 구현은 코드 편집기였습니다dev2옵클 에디터 개발기: 미리보기는 곧 또 하나의 편집기였습니다dev3옵클 에디터 개발기: 미디어쿼리까지 편집하는 EPUB 에디터dev4옵클 에디터 개발기: CSS 애니메이션으로 영상을 흡수하는 방식dev5옵클 에디터 개발기: 책을 만들기 위한 LLM을 설계하다dev6678910...5 옵클 에디터 개발기: CSS 애니메이션으로 영상을 흡수하는 방식미디어쿼리 대응이 유통사 리더기에서도 안정적으로 표현되는 것을 확인하고 나니, EPUB3에 대한 확신이 더 분명해졌습니다. EPUB은 단순히 글을 reflow하는 파일이 아니라, HTML과 CSS가 가진 표현력을 책 안으로 가져올 수 있는 형식이었습니다. 모바일, 태블릿, 데스크탑과 라이트, 다크 모드를 동시에 검수하고, 이미지와 표가 각 조건에 맞춰 자연스럽게 바뀌는 것을 보면서, 다음으로 시도할 수 있는 영역은 명확했습니다. CSS 애니메이션이었습니다.CSS는 미디어쿼리보다 훨씬 많은 일을 할 수 있습니다. `transition`, `animation`, `transform`, `opacity`, `filter`, `@keyframes` 같은 기능을 조합하면, 단순한 등장 효과부터 레이어별 움직임, 반복 재생, 장면 전환까지 만들 수 있습니다. 일반 웹에서는 너무 익숙한 기능이지만, EPUB 안에서 이것을 창작자가 직접 다루게 만드는 일은 완전히 다른 의미가 있었습니다. 전자책 내부에서 움직임을 만들고, 그 움직임이 유통사 리더기에서도 그대로 재생된다면, EPUB은 훨씬 더 넓은 표현 매체가 될 수 있었습니다.그래서 다음 구현은 GUI 애니메이션 생성기였습니다. 사용자가 CSS를 직접 작성하지 않아도 레이어를 고르고, 시간과 지연, 반복, 투명도, 위치, 크기, 회전 같은 값을 조정하면 에디터가 CSS animation과 keyframes를 생성하는 구조였습니다. 미디어쿼리 대응에서 만들었던 preview target과 document state 구조가 여기에서도 그대로 이어졌습니다. 애니메이션은 화면에서 보이는 효과이지만, 결국 EPUB 안에서는 CSS 문자열과 리소스, XHTML 구조로 안정적으로 직렬화되어야 했습니다.블록과 레이어, 그리고 애니메이션처음부터 애니메이션을 CSS 코드 입력 기능으로 만들 생각은 없었습니다. 사용자가 `@keyframes`를 직접 쓰고, `animation-duration`이나 `animation-delay`를 손으로 조정하게 하면 다시 코드 편집기로 돌아가는 셈입니다. 제가 원한 것은 화면 위의 layer를 선택하고, 그 layer가 언제 어떻게 움직일지 GUI로 정하면, 에디터가 CSS를 생성하는 방식이었습니다.그래서 애니메이션의 기본 단위를 block과 layer로 잡았습니다. 이미지 block, 텍스트 block, group block, overlay block 같은 요소가 있고, 각 요소는 animation state를 가질 수 있습니다. animation state에는 duration, delay, easing, iteration count, fill mode, transform 값, opacity 값, start/end position 같은 속성이 들어갑니다. 사용자는 패널에서 값을 바꾸지만, 내부적으로는 이 state가 CSS keyframe과 animation rule로 직렬화됩니다.이 방식은 앞서 만든 문서 상태 구조와 잘 맞았습니다. XHTML은 요소의 의미 구조를 유지하고, CSS는 표현과 움직임을 담당합니다. Shadow DOM preview는 현재 state를 렌더링하고, CodeMirror 6의 CSS 문자열은 생성된 animation rule을 보존합니다. IndexedDB에는 block state와 CSS state가 함께 저장됩니다. 사용자가 GUI에서 시간을 조정하면 preview에서 바로 움직임이 바뀌고, 동시에 CSS 문자열도 갱신되는 흐름입니다.레이어별 애니메이션을 만들 때 중요한 것은 독립성과 조합이었습니다. 한 이미지가 천천히 나타나고, 다른 텍스트가 0.3초 뒤에 위로 올라오며, 배경 레이어는 약하게 확대되는 식의 장면을 만들려면 각 layer가 자기 animation state를 가져야 합니다. 동시에 전체 scene은 하나의 timeline처럼 움직여야 합니다. 그래서 개별 layer state와 scene-level timing을 나누어 관리했습니다.CSS 애니메이션 GUI애니메이션 GUI를 만들 때 가장 중요한 기준은 CSS를 숨기는 것이 아니라, 정확한 CSS를 생성하는 것이었습니다. 창작자는 타임라인과 슬라이더, 토글, easing 선택으로 움직임을 조정하지만, 결과물은 결국 EPUB 안에 들어갈 CSS입니다. 따라서 GUI에서 만든 값은 언제든 `@keyframes`와 class rule로 재현 가능해야 했습니다.예를 들어 사용자가 어떤 이미지 layer에 fade-in과 translateY를 설정하면, 내부 state는 단순히 “페이드 인”이라는 문자열로 저장되지 않습니다. 시작 frame의 `opacity: 0`, `transform: translateY(...)`, 끝 frame의 `opacity: 1`, `transform: translateY(0)` 같은 값으로 보존됩니다. 그리고 CSS serializer가 이 값을 기반으로 keyframes 이름을 만들고, 해당 block에 animation class를 부여합니다.keyframes 이름도 관리 대상이었습니다. EPUB 안에는 여러 장과 여러 block이 있고, 같은 이름의 keyframes가 충돌하면 안 됩니다. 그래서 block id나 animation id를 기준으로 unique한 keyframes name을 만들고, CSS rule을 생성했습니다. layer가 삭제되거나 animation이 바뀌면 사용하지 않는 rule도 정리되어야 했습니다. 그렇지 않으면 CSS가 계속 불어나고, 나중에 export된 EPUB 안에 죽은 keyframes가 남습니다.이 구조를 잡으니 GUI와 CSS 사이의 거리가 사라졌습니다. 사용자는 시각적으로 애니메이션을 조정하지만, 에디터는 내부적으로 정확한 CSS animation rule을 만들고 있었습니다. preview에서 보이는 움직임과 export된 EPUB 안의 움직임이 같은 rule에서 나오기 때문에, 편집기와 결과물 사이의 차이도 줄어들었습니다.EPUB 안에서의 video 태그 한계 돌파애니메이션을 만들다 보니 자연스럽게 영상 문제로 이어졌습니다. EPUB3는 video 태그를 지원합니다. 스펙만 보면 전자책 안에 영상을 넣고 재생하는 것이 가능합니다. 하지만 실제 유통사 리더기와 reading system에서는 video 재생이 안정적이지 않은 경우가 많습니다. 어떤 리더기는 재생 컨트롤이 다르게 보이고, 어떤 환경에서는 아예 재생이 되지 않거나, 파일 크기와 코덱 조건에서 문제가 생길 수 있습니다.그래서 저는 video 태그를 그대로 믿는 방식으로 가지 않았습니다. EPUB 안에서 확실히 보장되는 쪽은 여전히 이미지와 CSS였습니다. 이미지 리소스는 대부분의 reading system에서 안정적으로 처리되고, CSS animation은 제한이 있더라도 video보다 예측 가능한 경우가 많았습니다. 그렇다면 영상을 이미지 시퀀스로 바꾸고, 그 이미지들을 CSS animation으로 재생하면 어떨까 하는 생각이 자연스럽게 나왔습니다.이 방식은 개념적으로 단순합니다. 사용자가 mp4를 넣으면 서버에서 ffmpeg로 프레임을 추출합니다. 추출된 frame은 JPEG 이미지 시퀀스가 됩니다. 에디터는 이 frame들을 하나의 animation component로 묶고, CSS keyframes나 step animation을 사용해 순서대로 보여 줍니다. 결과적으로 EPUB 안에는 video 태그가 아니라 여러 장의 이미지와 CSS animation rule이 들어갑니다.핵심은 재생 경험을 충분히 부드럽게 만드는 것이었습니다. 모든 프레임을 무조건 다 넣으면 파일 크기가 커집니다. 반대로 프레임을 너무 줄이면 움직임이 끊겨 보입니다. 그래서 원본 영상의 길이, 목표 fps, 리더기에서 감당 가능한 이미지 수, JPEG 압축 품질, viewport별 이미지 크기를 함께 조정해야 했습니다. 이 역시 영상 처리 문제이면서 동시에 EPUB 패키징 문제였습니다.Mp4를 프레임 시퀀스로서버 쪽에서는 ffmpeg를 사용했습니다. 사용자가 mp4를 업로드하거나 드롭하면, 서버가 해당 파일을 받아 프레임 단위로 분해합니다. 출력은 `frame_0001.jpg`, `frame_0002.jpg` 같은 이미지 시퀀스로 만들 수 있고, 필요하면 해상도와 품질도 조정합니다. EPUB에 들어갈 리소스이기 때문에 원본 해상도를 그대로 유지하기보다, 실제 preview target과 reading 환경에 맞는 크기로 줄이는 것이 중요했습니다.프레임 시퀀스가 만들어지면 에디터는 그것을 일반 이미지 묶음으로 보지 않고, animation component의 resource set으로 등록합니다. 각 frame은 OPF manifest에 들어가야 하고, media-type은 image/jpeg로 맞춰야 합니다. resource store에는 frame list와 순서, duration, fps, target size 같은 메타데이터가 함께 저장됩니다. IndexedDB에도 이 component state가 저장되어야 나중에 프로젝트를 다시 열었을 때 같은 애니메이션을 복원할 수 있습니다.CSS 재생 방식은 여러 가지가 가능합니다. 하나는 keyframes에서 background-image를 단계적으로 바꾸는 방식이고, 다른 하나는 frame 이미지를 sprite처럼 구성해 background-position을 움직이는 방식입니다. EPUB 환경에서는 reading system별 CSS 지원 차이를 고려해야 하므로, 가장 안정적으로 표현되는 방식을 기준으로 잡아야 했습니다. 중요한 것은 결과물이 video decode에 의존하지 않고, 이미지 로딩과 CSS animation만으로 움직인다는 점이었습니다.이 구조가 만들어지면서 영상은 더 이상 video 태그에 묶이지 않았습니다. 사용자는 mp4를 넣지만, 에디터 내부에서는 그것을 EPUB 친화적인 이미지 애니메이션으로 변환합니다. 유통사 리더기에서 video가 불안정하더라도, 이미지와 CSS로 구성된 animation은 훨씬 안정적으로 재생될 수 있었습니다.이미지 시퀀스 영상이미지 시퀀스 방식의 장점은 앞서 만든 이미지 component 구조와 잘 맞는다는 데 있었습니다. 이미 4편에서 이미지 variant를 component로 다루고 있었기 때문에, frame sequence도 같은 resource 관리 체계 안으로 넣을 수 있었습니다. 차이는 단일 이미지 variant가 아니라 시간 순서를 가진 이미지 묶음이라는 점이었습니다.animation component는 frame list를 갖고, CSS state는 해당 frame list를 어떤 시간 간격으로 보여 줄지 결정합니다. preview target은 현재 viewport와 theme 조건에 맞는 frame 크기와 표현을 렌더링합니다. export 시에는 frame 이미지들이 모두 EPUB 패키지에 들어가고, OPF manifest에도 빠짐없이 등록됩니다. 본문 XHTML에는 animation component를 나타내는 구조가 들어가고, CSS에는 재생 규칙이 들어갑니다.이 방식은 미디어쿼리와도 결합할 수 있었습니다. 모바일에서는 더 작은 frame sequence를 쓰고, 데스크탑에서는 더 큰 frame sequence를 쓸 수 있습니다. 다크 모드에서 다른 색감의 frame을 쓰는 것도 구조적으로 가능합니다. 결국 영상조차도 이미지 variant component의 확장으로 다룰 수 있었습니다. mp4 하나를 그대로 넣는 방식보다 EPUB의 실제 읽기 환경에 더 잘 맞았습니다.물론 리소스 수가 늘어나면 패키지 크기와 로딩 타이밍을 관리해야 합니다. 그래서 frame 개수, 압축률, preload 여부, animation duration, 반복 여부를 component state 안에서 함께 관리했습니다. 에디터 preview에서는 실제 재생 감각을 확인하고, export 전 검수에서는 manifest 누락, 경로 오류, CSS rule 누락, frame 순서 오류를 확인할 수 있게 했습니다.CSS animation은 EPUB 표현의 중심 기능이 구현을 하고 나니 CSS animation은 단순한 장식 기능이 아니었습니다. EPUB 안에서 안전하게 움직임을 표현하기 위한 핵심 기술이 되었습니다. 텍스트가 천천히 나타나는 장면, 이미지가 레이어별로 움직이는 장면, 짧은 영상이 이미지 시퀀스로 재생되는 장면이 모두 CSS animation 구조로 들어왔습니다.에디터 안에서는 사용자가 레이어와 타이밍을 직접 조정합니다. 내부적으로는 animation state가 바뀌고, CSS serializer가 keyframes와 class rule을 생성하며, Shadow DOM preview가 즉시 결과를 보여 줍니다. CodeMirror 6에는 생성된 CSS 문자열이 반영되고, IndexedDB에는 state와 resource가 저장됩니다. 이 흐름은 3편과 4편에서 만든 동기화, 미디어쿼리, 리소스 관리 구조 위에서 자연스럽게 돌아갔습니다.특히 mp4를 frame sequence로 변환하는 방식은 옵클 에디터의 방향을 더 분명하게 만들었습니다. 사용자는 영상을 넣지만, EPUB 안에는 유통사 리더기가 안정적으로 처리할 수 있는 이미지와 CSS가 들어갑니다. 겉으로는 영상처럼 보이지만 내부적으로는 EPUB 친화적인 animation package입니다. 이 방식은 video 태그 지원이 들쭉날쭉한 환경에서도 표현을 유지할 수 있게 해 주었습니다.결과는 확실히 성공적이었습니다. GUI 애니메이션 생성기는 레이어별 CSS animation을 안정적으로 만들었고, 생성된 keyframes와 animation rule은 preview와 export 결과에서 일관되게 동작했습니다. mp4를 ffmpeg로 JPEG frame sequence로 변환해 CSS animation으로 재생하는 흐름도 유통사 리더기 검수에서 막힘없이 통과했습니다. 이 단계에서 옵클 에디터는 이미지와 표를 넘어, 움직임과 영상까지 EPUB3 안으로 흡수할 수 있는 에디터로 진화했습니다.이전글목록으로다음글저작권 고시Copyright Notice본 웹사이트의 모든 디자인 결과물 및 영상에 대한 저작권은 Abstract Cloud에 있으며, 저작권법 및 관련 법령에 의해 보호받습니다. 웹, 영상, 본문, 표지, 내지 디자인을 포함한 모든 콘텐츠는 저작권자의 자산으로, 사전 동의 없이 무단 복제, 배포, 2차 저작물 제작, 온라인 공유 등을 금지합니다. 이를 위반할 시, 저작권법에 따라 민형사상 책임을 질 수 있습니다. 정당한 구매와 저작권 보호는 창작자의 권리를 지키며, 더 나은 작품으로 보답할 힘이 됩니다.저작권자: Abstract Cloud | 대표자: 배창규(uragen)
© Abstract Cloud. All Rights Reserved.
HOMEFAQ이용 약관개인정보 이용방침help@opkle.app
010-2747-3403
상호 :추상적 형상 디자인(Abstract cloud)  |  대표자 :배창규사업자등록번호 :249-74-00533통신판매업 신고번호 :2025-의정부송산-0634주소 :경기도 의정부시 부용로 49, 108동 402호웹의 모든 콘텐츠, 디자인, 소스 코드에 대한
저작권은 Opkle에게 있습니다.
img default description