Cloud Typesetting Engine
The typesetting engine
made for serious books.
Built by a team that wrote its own programming language for publishing layout.
Cloud-native, engineered for print-grade output.
Free to start.
To move a single word to the next line,
we recompute the entire paragraph.
Why ATLAS
The depth a serious book deserves.
- 01 / Paragraph Optimization
We solve the paragraph, not the line.
Knuth–Plass optimization decides line breaks for the entire paragraph at once — eliminating the uneven, jarring word spacing that standard greedy line-breaking leaves behind.
- 02 / Built for the Hardest Scripts
We started where typography breaks.
Korean composes by syllable blocks, breaks lines between characters rather than at spaces, and offers little elastic word spacing for justification. We built the engine to that bar. Latin manuscripts run on the same engine, with room to spare.
- 03 / Deterministic Preview
What you see is exactly what prints.
Browser preview line breaks and page boundaries match the final PDF byte-for-byte. The most common frustration of any author — “the preview was fine, the PDF wasn’t” — is structurally impossible.
- 04 / Print-Spec Native
Typeset to your trim, by default.
Pick a trim like Bookk 46 and the margins, folio, and chapter openings follow it from the first page. Nothing to recalculate before you export.
Built by TAFO
We published a book ourselves. Then we built the tool we needed.
ATLAS began after TAFO published an essay as both an ebook and a print book. Finishing the manuscript turned out to be only the start. The ebook required Sigil, and the print interior required InDesign.
Outsourcing was expensive. Doing it ourselves meant learning a production process far removed from writing. At first, we thought publishing our finished source files might help other writers. But even with the files in hand, every writer would still have to learn the same software and process from scratch.
So we decided to build a tool instead of handing over files. It had to let a writer add a manuscript, review a properly typeset interior, and export a print-ready PDF. ATLAS is the tool we needed and could not find.
Written in Topaz
We built a language, then wrote ATLAS's line-breaking rules in it.
Topaz is our general-purpose programming language. In ATLAS, it spells out the decisions behind line breaking, from kinsoku classification and line badness to spacing penalties and whole-paragraph optimization. The complete source below is 나쁨도.tpz, which turns the balance of a line into a score. Names such as 여유, 목표너비, and 글자수 are used directly in the calculation.
The grammar, playground, and compiler binaries are available at topaz.ooo.
// ATLAS 나쁨도. 한 줄의 나쁨도를 고정소수로 매기는 명세다(fixed-point line badness).
// 통합 줄바꿈기 `줄바꿈.tpz`의 2단계(한 줄이 목표너비에 견줘 얼마나 헐겁거나 빡빡한지를 점수로
// 매기는 일)를 따로 떼어 적었으며, 영어 PoC badness.tpz의 한국어 식별자 번역이다.
// 동작은 바이트 단위로 같다(badness_fp.rs ≡ ATLAS Rust).
// 입출력. 표준입력으로 "<너비>|<목표너비>|<글자수>|<공백수>|<분할종류>|<마지막인가(0/1)>" 꼴의 줄을 받아 줄마다 나쁨도(B 단위)를 낸다.
let R = 100000000 // 1e8 비율 스케일 (ratio scale)
let B = 1000000 // 1e6 나쁨도 스케일 (badness scale)
function 반올림나눗셈(분자: int, 분모: int) -> int { // round-half-up, 음이 아닌 값만
let 몫 = 분자 / 분모
let 나머지 = 분자 % 분모
if 나머지 >= (분모 + 1) / 2 { 몫 + 1 } else { 몫 }
}
function 절댓값(값: int) -> int { if 값 < 0 { -값 } else { 값 } }
function 나쁨도(너비: int, 목표너비: int, 글자수: int, 공백수: int, 분할종류: string, 마지막인가: bool) -> int {
let 여유 = 목표너비 - 너비
let 절대여유 = 절댓값(여유)
let 원시R = if 절대여유 >= 4 * 목표너비 { 4 * R } else { 절대여유 * R / 목표너비 }
let 조정상한센티 = if 여유 >= 0 { 100 + 공백수 * 45 } else { 100 + 공백수 * 25 }
let 비례R = 반올림나눗셈(원시R * 100, 조정상한센티)
let 제곱 = 비례R * 비례R
let 몫 = 반올림나눗셈(제곱, R)
let mut 기본B = 반올림나눗셈(몫 * (1000 * B), R)
if 마지막인가 {
기본B = 반올림나눗셈(기본B * 2, 5)
if 너비 * 100 < 목표너비 * 52 && 글자수 > 0 { 기본B += 500 * B }
}
if 여유 < 0 {
기본B += 20000 * B + 반올림나눗셈(20000 * B * 비례R, R)
}
if 분할종류 == "latin_hyphen" { 기본B += 65 * B }
if 분할종류 == "hard_fallback" { 기본B += 50000 * B }
if 글자수 <= 2 { 기본B += 275 * B }
기본B += 10 * B
기본B
}
function 처리(입력: string) -> string {
let mut 출력 = ""
for 줄 in 입력.split("\n") {
let 칸 = 줄.split("|")
let 너비 = toInt(칸[0]) ?? 0
let 목표 = toInt(칸[1]) ?? 0
let 글자수 = toInt(칸[2]) ?? 0
let 공백수 = toInt(칸[3]) ?? 0
let 분할종류 = 칸[4]
let 마지막인가 = 칸[5] == "1"
let 값 = 나쁨도(너비, 목표, 글자수, 공백수, 분할종류, 마지막인가)
출력 = if 출력 == "" { "{값}" } else { "{출력}\n{값}" }
}
출력
}
print(처리(input()))
Complete source of 나쁨도.tpz
How it works
From manuscript to interior PDF
in three steps.
- 01
Paste your manuscript
Plain text, Markdown, or direct paste — whichever way you write.
- 02
Automatic typesetting
ATLAS solves each paragraph with publication-grade typography rules to find the optimal line breaks and pagination.
- 03
Export the interior PDF
An interior PDF, typeset to the trim you chose.
Output Specimen
The fastest way to show what we mean.

An interior spread typeset entirely with ATLAS