Opkle(옵클) - 창작자를 위한 앱과 시스템
옵클(Opkle)은 창작자를 위한 다양한 앱과 시스템을 제공하는 개발사입니다. 전자책 에디터 앱 'Opkle editor'를 출시했고, 관련 전자책 클래스를 제공하고 있습니다.
EDITOR
CLASS
BLOG
LOGIN
표현한다는 것의
무한한 가능성,
새로운 형태로
담아내다.
새로운 형태의 콘텐츠
Opkle은 코드 없이 웹을 마음껏 만들고, 누구나 자기 화면을 그릴 수 있도록 에디터를 만들고, 그 결과물을 어디서나 즐길 수 있게 돕는 팀입니다.
텍스트와 화면과의 조화를 통해, 웹을 짓는다는 것이 그저 단순한 코딩이 아닌, 상상을 펼치고 감각을 깨우는 과정이 될 수 있도록 좋은 도구를 만들어 냅니다.
옵클 에디터 개발기: 그래픽 엔진 안의 선형대수
dev
12
옵클 에디터 개발기: 인디자인처럼 편집하는 레이아웃 편집기
dev
13
옵클 에디터 개발기: 원고가 다음 페이지로 흐르는 편집기
dev
14
옵클 에디터 개발기: EPUB과 IDML을 편집 가능한 페이지로
dev
15
옵클 에디터 개발기: 한 번 만든 레이아웃을 EPUB과 인쇄물로
dev
16
8
9
10
11
12
...
16
옵클 에디터 개발기: 한 번 만든 레이아웃을 EPUB과 인쇄물로
레이아웃 에디터가 외부 문서를 편집 가능한 페이지로 받아들이게 된 다음에는 반대 방향을 완성할 차례였습니다. 편집 결과가 다른 도구에서 바뀌어 돌아와도 같은 대상이라는 정체성을 유지해야 하고, 고정 페이지는 반응형 문서와 물리 출력처럼 서로 다른 의미 공간으로 변환될 수 있어야 했습니다. 내보내기는 파일 생성보다 의미 보존의 문제였습니다.
이 출력들은 같은 문서를 사용하지만 보존해야 하는 불변식이 다릅니다. 원본 편집으로 돌아갈 때는 객체의 정체성과 편집 가능성이 중요합니다. 반응형 문서에서는 고정 좌표보다 reading order와 관계가 중요하고, 인쇄에서는 정확한 page box와 물리 단위, 색과 글꼴이 중요합니다. 하나의 범용 변환이 모든 불변식을 동시에 최적화할 수는 없습니다.
그래서 공통 문서 모델에서 목적별 projection을 만든다고 생각했습니다. 어떤 projection은 좌표를 버리고 의미 구조를 살리며, 다른 projection은 반대로 모든 물리 geometry를 확정합니다. 좋은 변환은 무엇을 보존하고 무엇을 포기하는지 명시합니다. 입력에서 시작한 변환 고리를 편집 원본, 반응형 문서와 인쇄물까지 닫는 과정도 결국 서로 다른 동치관계를 정의하는 일이었습니다.
Identity와 value
편집기 왕복에서 먼저 구분한 것은 객체의 identity와 현재 value였습니다. 이미지의 픽셀이나 벡터 path가 바뀌어도 페이지에서 그 대상이 차지하던 의미는 같은 객체로 남을 수 있습니다. 반대로 우연히 같은 픽셀을 가진 두 이미지는 서로 다른 객체입니다. 값의 동등성과 정체성의 동일성은 별개의 관계였습니다.
수학적으로 value는 어떤 상태 공간 V의 원소이고 identity는 시간에 따라 변하는 값들을 하나의 궤적으로 묶는 표지에 가깝습니다. 객체 o의 시각 상태를 시간 t에서 `v_o(t)`라고 하면 편집은 `v_o(t0) -> v_o(t1)`이지만 o 자체는 유지됩니다. 이 구분이 있어야 주변 배치와 참조는 그대로 두고 내용만 교체할 수 있습니다.
서로 다른 편집 영역이 만나는 경계에서는 전체 내부 상태를 공유할 필요가 없습니다. 필요한 것은 작업 대상의 identity, 입력 revision과 결과의 의미를 설명하는 최소한의 계약입니다. 큰 자산과 작은 제어 정보를 같은 통로에 섞으면 복사 비용과 실패 단위가 결합됩니다. 제어 평면과 데이터 평면을 분리하는 것은 네트워크뿐 아니라 복합 편집기에도 적용되는 일반적인 시스템 원리였습니다.
동시에 두 결과가 같은 객체를 갱신하려는 경우에는 revision 비교가 필요합니다. 늦게 끝났다는 이유만으로 오래된 입력에서 만든 결과가 최신 상태를 덮으면 안 됩니다. 작업 시작 시 읽은 revision과 적용 시점의 revision이 같은지 확인하고, 다르면 병합하거나 다시 계산해야 합니다. 왕복 편집은 화면 전환이 아니라 낙관적 동시성 제어를 가진 identity update였습니다.
Atomic replacement
결과를 제자리로 돌려보내는 일은 mutable object를 조금씩 고치는 것보다 atomic replacement로 보는 편이 안전했습니다. 새 값이 완전히 준비되기 전에 기존 값을 일부 지우면 중간 실패가 사용자에게 보이는 손실이 됩니다. 이전 revision과 새 revision이 각각 완전한 상태로 존재하고, 참조가 한 번에 새 revision을 가리키도록 바뀌어야 합니다.
이는 copy-on-write와 비슷합니다. 기존 자산 A를 직접 덮지 않고 새 자산 B를 만든 뒤 검증하고, 객체 o의 값만 A에서 B로 전환합니다. 전환 전에는 모든 독자가 A를 보고 전환 후에는 B를 보며, 누구도 반쯤 쓰인 자산을 보지 않습니다. 파일시스템의 atomic rename이나 데이터베이스의 commit과 같은 원리입니다.
새 값의 종횡비가 달라질 때 무엇을 보존할지도 constraint로 정해야 합니다. 위치와 폭, 높이, 중심점과 면적을 모두 동시에 유지할 수는 없습니다. 예를 들어 폭 w를 고정하고 새 비율 r을 적용하면 높이는 `h = w/r`로 결정됩니다. 사용자가 직접 결정한 변수와 콘텐츠에서 파생되는 변수를 구분해야 교체가 예측 가능해집니다.
이전 자산의 제거는 참조 가능성에 대한 도달성 문제였습니다. 어떤 자산을 root에서 더 이상 도달할 수 없을 때만 garbage로 판단할 수 있고, 과거 revision이나 다른 문서가 참조한다면 살아 있어야 합니다. reference counting은 cycle에 약하고, mark-and-sweep은 전체 graph를 봐야 합니다. 편집기 자산의 생명주기도 일반적인 garbage collection 이론과 같은 문제였습니다.
Geometric reading order
고정 페이지에서 reading order를 복원하는 문제는 geometry를 문자열 순서로 정렬하는 것보다 어렵습니다. 두 객체 A와 B 중 어느 것이 먼저 읽혀야 하는지는 x와 y의 단일 비교로 결정되지 않습니다. 위아래 관계, 같은 행, column, caption과 image의 결합처럼 여러 단서가 부분순서를 만듭니다. 목표는 이 부분순서를 위반하지 않는 선형 확장을 찾는 것입니다.
각 객체를 정점으로 두고 A가 B보다 먼저라는 근거가 충분하면 directed edge를 만듭니다. y축 분리, 공통 정렬선과 containment가 edge의 근거가 될 수 있지만 불확실한 관계까지 강제로 넣으면 cycle이 생깁니다. cycle은 시각적 배치가 모순이라기보다 heuristic이 서로 충돌했다는 뜻입니다. 약한 edge를 제거하거나 의미 metadata를 더 높은 우선순위로 사용해야 합니다.
페이지의 column 구조는 computational geometry의 clustering 문제입니다. 객체의 x interval과 y interval, 정렬선과 whitespace를 feature로 보고 같은 흐름에 속할 가능성을 추정할 수 있습니다. 그러나 geometry만으로 의미를 완전히 결정할 수는 없습니다. 같은 위치의 도형이 장식인지 본문인지 알 수 없기 때문입니다. 명시된 구조가 있다면 관측 geometry보다 우선해야 합니다.
겹침이 강한 객체 집합은 순차 문서로 풀 수 없는 합성일 수 있습니다. reading order라는 projection은 모든 시각 정보를 보존하지 못합니다. 따라서 의미 구조로 옮길 수 있는 부분과 하나의 visual atom으로 남겨야 하는 부분을 구분해야 합니다. 고정 레이아웃에서 반응형 문서로 가는 변환은 완전한 역함수가 아니라 목적에 맞는 정보 projection이었습니다.
Inverse layout
반응형 구조를 복원하는 일은 렌더러의 역문제였습니다. 일반적인 layout 함수 L은 구조 S와 viewport v를 받아 geometry G를 만듭니다. 여기서는 하나의 관측 결과 G에서 가능한 S를 추정해야 합니다. `L(S, v) = G`를 만족하는 S는 여러 개이므로 문제는 ill-posed합니다. 추가적인 정규화 기준이 필요했습니다.
가장 단순한 구조, 즉 적은 container와 적은 예외 규칙으로 geometry를 설명하는 후보를 선호할 수 있습니다. 이는 minimum description length 원리와 닮았습니다. 모든 객체에 absolute coordinate를 쓰면 현재 G는 완벽히 재현하지만 설명 길이가 길고 다른 viewport에 일반화되지 않습니다. row와 column, relative gap으로 설명되는 구조는 조금의 오차가 있어도 더 짧고 반응형일 가능성이 높습니다.
목적함수는 현재 화면의 재현 오차와 구조 복잡도를 함께 가질 수 있습니다. `E(S) = D(L(S,v), G) + λC(S)`에서 D는 위치와 크기의 차이, C는 container 수와 예외 규칙의 비용입니다. λ가 너무 작으면 absolute layout에 가까워지고 너무 크면 서로 다른 관계를 억지로 하나의 흐름으로 묶습니다. 의미 metadata와 reading order는 추가 constraint로 들어갑니다.
단 하나의 viewport만 보고 반응형 규칙을 완전히 알아낼 수는 없습니다. 그래서 변환 결과는 원본의 모든 숫자를 보존하는 것이 아니라 여러 화면에서도 유지되어야 할 관계를 선택합니다. 텍스트의 의미와 순서, 이미지의 aspect ratio, 같은 행과 column의 관계를 우선하고 장식적인 미세 위치는 완화합니다. responsive conversion의 정확성은 한 화면의 pixel equality보다 새로운 조건에서의 구조적 안정성으로 평가했습니다.
Reproducible output
미리보기와 최종 결과가 같으려면 두 번의 독립된 변환이 우연히 같은 화면을 만들기를 기대해서는 안 됩니다. 같은 source와 같은 환경, 같은 도구 버전에서 build가 결정적인 결과를 만들어야 합니다. 재현 가능한 빌드는 입력 집합과 변환 함수, 환경 변수를 모두 명시하는 데서 시작합니다.
출력을 함수 `B(source, assets, environment, version)`으로 보면 어떤 값이 암묵적으로 들어가는지 찾기 쉬워집니다. 현재 시각, 임의 순서의 파일 탐색, 준비되지 않은 글꼴과 장치별 locale가 함수 밖에서 결과를 바꾸면 같은 문서가 다른 byte를 만듭니다. 비결정적인 입력을 제거하거나 build manifest에 포함해야 preview와 export의 의미가 같아집니다.
시각적 동등성도 정의가 필요했습니다. 압축 순서가 달라 byte가 다르더라도 렌더링이 같을 수 있고, 반대로 HTML 문자열이 같아도 font version이 다르면 줄바꿈이 달라집니다. 문서 구조의 동등성, 자산 hash의 동등성과 최종 pixel 결과의 동등성을 단계별로 검사해야 합니다. 어느 층의 동일성을 보장하는지 명확해야 했습니다.
그래서 preview는 별도의 모의 결과가 아니라 canonical build를 하나의 환경에서 관찰한 projection으로 보았습니다. 최종 산출물도 같은 source graph와 변환 revision에서 나와야 합니다. 사용자가 승인한 상태와 배포된 상태 사이에 독립적인 재해석 단계를 줄이면서 고정 페이지와 반응형 문서의 왕복이 재현 가능한 제작 과정으로 정리되었습니다.
Deterministic rendering
인쇄 렌더링은 편집 화면을 캡처하는 작업이 아니었습니다. 편집 화면에는 selection과 guide, 임시 cache처럼 문서 의미가 아닌 상태가 섞여 있습니다. 출력은 durable document graph에서 시작해 물리 page space로 materialize되어야 합니다. View state를 제거한다는 것은 특정 DOM 요소를 지우는 요령보다 source model과 projection을 분리한 결과였습니다.
렌더러는 scene graph를 painter's order에 따라 순회하고 각 노드의 local transform을 누적해 page coordinate로 바꿉니다. 투명 합성은 순서에 의존하므로 z-order가 달라지면 같은 객체 집합도 다른 이미지가 됩니다. blending color space와 premultiplied alpha 여부까지 고정해야 동일한 scene이 장치마다 비슷한 결과를 냅니다.
벡터로 남길 것과 rasterize할 것도 연산의 폐쇄성으로 판단할 수 있습니다. affine transform과 단순 fill은 벡터 표현 안에서 닫혀 있지만 일부 filter와 혼합 효과는 출력 장치가 같은 의미를 지원하지 않을 수 있습니다. 이때는 해당 부분만 정해진 해상도와 색 공간에서 표본화하고 나머지 geometry는 벡터로 유지하는 것이 품질과 호환성의 균형이 됩니다.
최종 page box에는 화면 zoom과 device pixel ratio가 들어가면 안 됩니다. 문서의 물리 단위와 viewBox가 기준이고 출력 장치는 마지막에 이를 자신의 표본 격자로 바꿉니다. 편집기의 transient state와 장치 의존 변수를 제거하면서 같은 page graph가 언제 렌더되어도 같은 물리 위치를 갖도록 만들었습니다.
Glyph closure
폰트 subset은 문서에 나온 Unicode 문자만 모으는 집합 문제가 아니었습니다. shaping을 거치면 문자 sequence가 ligature glyph로 바뀌고, 한 glyph가 다른 복합 glyph를 참조할 수 있습니다. OpenType substitution과 positioning table도 script와 language에 따라 추가 glyph를 선택합니다. 필요한 집합은 문자 집합의 단순상이 아니라 shaping graph의 도달 가능 폐쇄입니다.
초기 glyph 집합 G에서 composite reference와 substitution edge를 반복해서 따라가며 더 이상 새 glyph가 나오지 않을 때까지 확장하면 least fixed point를 얻을 수 있습니다. `G_(n+1) = G_n ∪ refs(G_n) ∪ subs(G_n)`이고 `G_(n+1)=G_n`이 되는 지점이 closure입니다. 이 집합 밖의 outline과 metric만 제거해야 문서에 필요한 조판 관계가 유지됩니다.
metric table과 glyph index의 재배정도 함께 움직입니다. outline만 남기고 character map, advance width나 kerning pair가 옛 index를 가리키면 파일은 열려도 글자가 달라집니다. subset은 graph induced substructure를 만드는 작업이고, 모든 참조 table을 새 index 공간에 맞춰 동형으로 옮겨야 합니다.
글꼴 준비는 렌더링 barrier이기도 합니다. fallback font에서 계산한 line break는 올바른 글꼴이 들어온 뒤 무효가 됩니다. 따라서 페이지가 준비되었다는 조건은 DOM 생성이 끝났다는 사실보다 shaping에 필요한 face와 metric이 확정되었다는 뜻이어야 합니다. glyph closure와 font readiness를 같은 출력 계약 안에 두면서 화면과 인쇄의 typography가 일치했습니다.
Print geometry
화면 문서와 인쇄 문서는 같은 scene에서 출발하지만 서로 다른 측정 공간을 가집니다. 화면은 논리 pixel과 viewport에 적응하고, 인쇄는 물리 길이와 장치 해상도, 재단 공정을 기준으로 합니다. point, millimeter와 pixel을 섞지 않고 quantity에 dimension을 붙여 계산해야 zoom이나 DPI가 문서 크기를 바꾸지 않습니다.
인쇄 페이지는 하나의 사각형이 아니라 media, trim, bleed와 content box의 포함 관계입니다. `content ⊆ trim ⊆ bleed ⊆ media`가 유지되어야 하고 각 표식은 어느 box를 기준으로 정의되는지 분명해야 합니다. 좌표를 페이지마다 직접 쓰는 대신 box의 경계와 offset에서 유도하면 판형이 바뀌어도 같은 기하 규칙이 유지됩니다.
래스터 해상도는 Nyquist 관점에서도 봐야 합니다. 가장 가는 선과 글자 세부가 가진 공간 주파수보다 표본 주파수가 충분히 높아야 aliasing이 줄어듭니다. 무조건 높은 DPI는 메모리와 처리량만 늘리므로 vector로 보존되는 요소와 raster effect를 분리하고, 실제 표본화되는 부분에 필요한 해상도를 계산하는 편이 맞았습니다.
색 공간 변환도 장치 독립 색에서 출력 장치의 gamut으로 가는 mapping입니다. gamut 밖의 색을 어디로 보낼지에 따라 perceptual과 relative colorimetric 결과가 달라집니다. 화면의 RGB 숫자를 그대로 인쇄 채널로 복사할 수 없고 profile과 rendering intent가 필요합니다. 물리 geometry와 색 관리까지 포함해야 인쇄 출력이 하나의 완결된 수학적 변환이 되었습니다.
Graph isomorphism
프로젝트를 다른 환경으로 옮기는 일은 파일 복사보다 graph isomorphism 문제에 가까웠습니다. 원본 문서를 그래프 `G=(V,E)`라고 할 때 새 환경의 그래프 `G'`는 정점의 실제 이름이 달라도 대응 함수 `φ:V->V'`가 edge 관계와 node type을 보존해야 합니다. 식별자 문자열이 같은 것이 아니라 구조가 같은 것이 핵심입니다.
새 이름 공간에서는 원본의 식별자가 이미 다른 객체에 사용되고 있을 수 있습니다. 따라서 φ는 injective해야 하고, 모든 참조 edge `(u,v)`는 `(φ(u),φ(v))`로 함께 옮겨져야 합니다. 정점만 새로 만들고 edge 안의 옛 이름을 남기면 graph는 겉으로 존재해도 닫혀 있지 않습니다. namespace migration은 구조 전체에 적용되는 치환입니다.
공유 자산도 보존해야 합니다. 두 객체가 원래 같은 정점을 가리켰다면 복원 후에도 같은 새 정점을 가리켜야 합니다. 각 참조를 독립적으로 복사하면 하나였던 자산이 여러 개로 갈라지고 identity 관계가 달라집니다. φ를 전역 함수로 한 번 정의하고 모든 edge가 같은 mapping을 사용해야 graph의 sharing topology가 유지됩니다.
복원은 transaction입니다. 새 graph가 완전히 만들어지고 모든 정점의 type과 edge closure가 검증되기 전에는 기존 정상 graph를 대체할 수 없습니다. 실패한 후보 graph는 폐기하고 이전 revision을 유지합니다. 다른 컴퓨터에서 식별자가 모두 달라져도 페이지와 스타일, 자산의 관계가 같다면 같은 프로젝트라는 의미를 수학적으로 정리할 수 있었습니다.
닫힌 제작 시스템
이 단계까지 오면서 레이아웃 에디터의 역할이 완전히 정리되었습니다. 편집 왕복은 identity와 value를 분리한 revision 교체가 되었고, 자산 변경은 copy-on-write와 도달성 기반 생명주기로 설명할 수 있게 되었습니다. fixed page에서 reading order를 얻는 과정은 부분순서의 선형 확장으로, 반응형 구조는 minimum description length를 가진 inverse layout 문제로 정리되었습니다.
같은 문서는 인쇄 경로에서 전혀 다른 동치관계로 확정됩니다. 재현 가능한 build가 source와 환경을 고정하고, glyph closure가 조판에 필요한 글꼴 그래프를 닫으며, deterministic renderer가 scene graph를 물리 page space로 투영합니다. 인쇄 geometry와 색 공간은 화면과 다른 dimension과 gamut을 가진 변환으로 완성했습니다.
동시 편집 revision, 원자적 자산 교체, 복잡한 reading order, 여러 viewport의 구조 안정성, 글꼴 substitution, 극단적인 page ratio와 graph 이식을 반복 검수했습니다. 미리보기와 최종 결과의 의미가 일치하고, 물리 출력의 box 관계가 유지되며, 새 이름 공간에서도 프로젝트 graph가 동형으로 복원되는 것을 모두 확인했습니다. 벡터 제작에서 시작해 레이아웃, EPUB과 웹, 실제 인쇄물로 이어지는 옵클의 제작 시스템은 이 단계에서 완전하게 닫히고 안정화되었습니다.
이전글
목록으로
다음글
저작권 고시
Copyright Notice
본 웹사이트의 모든 디자인 결과물 및 영상에 대한 저작권은 Abstract Cloud에 있으며, 저작권법 및 관련 법령에 의해 보호받습니다. 웹, 영상, 본문, 표지, 내지 디자인을 포함한 모든 콘텐츠는 저작권자의 자산으로, 사전 동의 없이 무단 복제, 배포, 2차 저작물 제작, 온라인 공유 등을 금지합니다. 이를 위반할 시, 저작권법에 따라 민형사상 책임을 질 수 있습니다. 정당한 구매와 저작권 보호는 창작자의 권리를 지키며, 더 나은 작품으로 보답할 힘이 됩니다.
저작권자: Abstract Cloud | 대표자: 배창규(uragen)
© Abstract Cloud. All Rights Reserved.
HOME
FAQ
이용 약관
개인정보 이용방침
help@opkle.app
010-2747-3403
상호 :
추상적 형상 디자인(Abstract cloud) |
대표자 :
배창규
사업자등록번호 :
249-74-00533
통신판매업 신고번호 :
2025-의정부송산-0634
주소 :
경기도 의정부시 부용로 49, 108동 402호
웹의 모든 콘텐츠, 디자인, 소스 코드에 대한
저작권은 Opkle에게 있습니다.