<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://sovichea.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://sovichea.github.io/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-07-18T21:40:35+07:00</updated><id>https://sovichea.github.io/feed.xml</id><title type="html">Sovichea</title><subtitle>Notes on building thoughtful tools for writing, languages, and long documents.</subtitle><entry><title type="html">Why I Rebuilt Typst Preview for Typsastra</title><link href="https://sovichea.github.io/writing/why-i-rebuilt-typst-preview-for-typsastra/" rel="alternate" type="text/html" title="Why I Rebuilt Typst Preview for Typsastra" /><published>2026-07-18T00:00:00+07:00</published><updated>2026-07-18T00:00:00+07:00</updated><id>https://sovichea.github.io/writing/why-i-rebuilt-typst-preview-for-typsastra</id><content type="html" xml:base="https://sovichea.github.io/writing/why-i-rebuilt-typst-preview-for-typsastra/"><![CDATA[<p><a href="https://github.com/Sovichea/typsastra">Typsastra</a> (pronounced <strong>“tip-SAS-tra”</strong>) began with a relatively focused goal: make writing complex scripts easier and more natural in a Typst editor.</p>

<p>The name combines <strong>Typst</strong>, the typesetting system at the center of the project, with <strong>sastra</strong>—a word associated with writing, literature, and knowledge. It reflects the idea that a document editor should support not only typesetting, but also the languages, scripts, and long-form work that give writing its meaning.</p>

<p>Most code editors are designed around programming. They default to monospace fonts, assume relatively simple text boundaries, and optimize editing behavior for source code written primarily in Latin scripts. Those defaults are reasonable for code, but they do not always work well for human-language documents—especially documents written in Khmer, Lao, Arabic, and other complex scripts.</p>

<p>A monospace font may technically contain the necessary characters, but that does not mean the text will look good or remain comfortable to read for hours. Complex-script typography depends on shaping, mark placement, appropriate spacing, and fonts designed specifically for the writing system.</p>

<p>The problem goes deeper than appearance.</p>

<p>Cursor movement, text selection, and deletion must respect grapheme clusters—the sequences of Unicode code points that users perceive as a single written unit. A visible character may contain a base consonant, combining marks, dependent vowels, or script-specific joining sequences.</p>

<p>If an editor moves or deletes through those sequences incorrectly, it may place the cursor inside a cluster or remove only part of a visible character. The text can become malformed even though the editor appears to be working normally.</p>

<p>That was the original reason I started building Typsastra.</p>

<figure>
  <video controls="" muted="" playsinline="" preload="metadata" aria-label="Demonstration of grapheme-aware cursor movement in Typsastra">
    <source src="/assets/media/grapheme-aware-movement.mp4" type="video/mp4" />
  </video>
  <figcaption>Complex-script support requires more than displaying Unicode characters. Navigation, selection, deletion, shaping, and typography must also behave correctly.</figcaption>
</figure>

<h2 id="rendering-was-supposed-to-be-the-easy-part">Rendering was supposed to be the easy part</h2>

<p>At first, I was not particularly concerned about document rendering.</p>

<p>Tinymist already provided the important Typst tooling:</p>

<ul>
  <li>Language Server Protocol support</li>
  <li>Diagnostics and completion</li>
  <li>Live preview</li>
  <li>Forward synchronization</li>
  <li>Inverse synchronization</li>
  <li>PDF export</li>
</ul>

<p>My assumption was simple: integrate Tinymist, use its preview, and call it a day.</p>

<p>For small documents, this worked well. Compilation was fast, the preview was responsive, and the development effort could remain focused on the editor itself—where complex-script navigation, deletion, spellchecking, completion, and font behavior needed the most attention.</p>

<p>Then I started testing larger documents.</p>

<p>A document grew from a few pages to tens of pages, and then to hundreds of pages. As it grew, memory consumption became increasingly difficult to ignore.</p>

<p>The preview was fast, but it was not cheap.</p>

<figure>
  <div class="media-grid">
    <img src="/assets/media/vscode-tinymist-5-page.png" alt="VS Code and Tinymist previewing a five-page document" />
    <img src="/assets/media/vscode-tinymist-50-page.png" alt="VS Code and Tinymist previewing a fifty-page document" />
    <img src="/assets/media/vscode-tinymist-200-page.png" alt="VS Code and Tinymist previewing a two-hundred-page document" />
    <img src="/assets/media/vscode-tinymist-500-page.png" alt="VS Code and Tinymist previewing a five-hundred-page document" />
  </div>
  <figcaption>Design assumptions that work for a short example can break down when the same document grows from 5 to 50, 200, and 500 pages.</figcaption>
</figure>

<h2 id="the-hidden-cost-of-svg-preview">The hidden cost of SVG preview</h2>

<p>Tinymist’s SVG preview is designed for responsiveness. It can partially update the document rather than forcing the entire preview to be replaced after every edit. This makes the connection between typing and visual output feel immediate.</p>

<p>That is a significant advantage. When a user changes a sentence, they do not want to wait several seconds just to see the result.</p>

<p>However, responsiveness is not the only measure of a good preview system.</p>

<p>A preview also needs to remain stable over time and behave predictably as the document grows. It should not require several gigabytes of memory simply because the author is working on a long book, thesis, technical report, or multilingual publication.</p>

<p>During one of my tests, previewing a document of approximately 500 pages in my local VS Code and Tinymist environment caused memory usage to continue climbing. It eventually approached 7 GB before the application crashed.</p>

<p>That result changed the direction of Typsastra.</p>

<p>The problem was no longer just:</p>

<blockquote>
  <p>How can I make complex-script editing work correctly?</p>
</blockquote>

<p>It became:</p>

<blockquote>
  <p>How can I build an environment where people can reliably author genuinely long documents?</p>
</blockquote>

<p>If Typsastra was going to support books, theses, research documents, and multilingual publications, this level of memory consumption was unacceptable—especially for users working on low-end computers.</p>

<p>That question sent me down a much deeper rabbit hole.</p>

<figure>
  <img src="/assets/media/vscode-tinymist-500-page.png" alt="Windows Task Manager showing very high memory consumption during a long-document SVG preview test" />
  <figcaption>In my local 500-page stress test, the VS Code and Tinymist preview environment continued consuming memory until it approached 7 GB and crashed.</figcaption>
</figure>

<h2 id="a-preview-is-part-of-the-document-architecture">A preview is part of the document architecture</h2>

<p>It would have been easy to treat the preview as a separate PDF viewer attached to the editor. But Typsastra is not intended to be only a text editor with a PDF window beside it.</p>

<p>The editor and preview represent the same document.</p>

<p>That relationship must remain intact across:</p>

<ul>
  <li>Multi-file projects</li>
  <li>Included chapters</li>
  <li>Large source files</li>
  <li>Long generated PDFs</li>
  <li>Forward synchronization</li>
  <li>Inverse synchronization</li>
  <li>Zooming and scrolling</li>
  <li>Compilation failures</li>
  <li>Main-document changes</li>
  <li>Preview replacement after recompilation</li>
</ul>

<p>Forward synchronization should take the source cursor directly to the corresponding PDF page. Inverse synchronization should let the user interact with the preview and return to the correct source file and location.</p>

<p>Those features become much harder when a project contains many source files and produces more than a thousand pages.</p>

<p>The challenge was not merely to display a PDF efficiently. It was to preserve the identity of the document across editing, compilation, source mapping, and preview replacement.</p>

<p>This led me to reconsider how a Typst document should be previewed inside Typsastra.</p>

<figure>
  <img src="/assets/media/typsastra-bounded-memory-pdf-preview.png" alt="Architecture comparison between a full-document SVG preview and Typsastra's bounded virtualized PDF preview" />
  <figcaption>Typsastra keeps the complete document structure while rendering only the pages relevant to the current viewport.</figcaption>
</figure>

<h2 id="choosing-bounded-memory-over-maximum-immediacy">Choosing bounded memory over maximum immediacy</h2>

<p>Typsastra moved toward a virtualized PDF preview.</p>

<p>Instead of retaining a rendered representation of the entire document, the viewer prioritizes the pages currently visible to the user and a small number of nearby pages. Pages outside that active window do not need to keep expensive rendered canvases resident in memory.</p>

<p>The preview maintains document geometry so that the scrollbar can still represent the full document, but the number of fully rendered pages remains bounded.</p>

<p>This changes the scaling behavior.</p>

<p>A 1,500-page document still has 1,500 logical pages, but Typsastra does not need to keep 1,500 rendered pages alive simultaneously. The cost of the preview is driven more by the visible page window than by the total length of the document.</p>

<p>Building this required more than simply adding lazy loading. The viewer needed to understand user interaction:</p>

<ul>
  <li>Which pages are currently visible?</li>
  <li>Which direction is the user scrolling?</li>
  <li>Is the gesture accelerating or decelerating?</li>
  <li>Has the user released the scrollbar?</li>
  <li>Which pages should render first when the viewport contains parts of two pages?</li>
  <li>Which previous canvases can be retained?</li>
  <li>Which obsolete render tasks should be cancelled?</li>
  <li>How can the preview be replaced without briefly showing an empty frame?</li>
</ul>

<p>Gesture scrolling and scrollbar dragging also behave differently.</p>

<p>During gesture scrolling, movement gradually accelerates and decelerates. Rendering only after the motion completely stops makes the viewer feel unresponsive. Rendering every intermediate page wastes work and can delay the page the user ultimately wants.</p>

<p>Scrollbar dragging creates another challenge. The user can jump hundreds of pages in a fraction of a second. When the pointer is released, every visible destination page must be promoted immediately. Rendering only one page can leave half the viewport blank.</p>

<p>The final design uses motion-aware scheduling, destination prediction, bounded canvas ownership, and hardware-accelerated PDF rendering. It prioritizes the pages that matter now without allowing abandoned work to consume the rendering queue.</p>

<figure>
  <video controls="" muted="" playsinline="" preload="metadata" aria-label="Typsastra scrolling through and jumping within a long PDF document">
    <source src="/assets/media/typsastra-pdf-preview.mp4" type="video/mp4" />
  </video>
  <figcaption>The render scheduler follows scroll direction and motion, then prioritizes every visible page when the user stops or releases the scrollbar.</figcaption>
</figure>

<h2 id="the-compromise">The compromise</h2>

<p>There is an unavoidable compromise.</p>

<p>A PDF-based preview cannot always feel as immediate as a partial SVG preview. After an edit, Typst must produce updated PDF output, and the viewer must load the new document generation and render the relevant pages.</p>

<p>Trying to hide that reality completely would introduce more complexity, memory pressure, and fragile behavior.</p>

<p>I decided that Typsastra did not need to chase perfection.</p>

<p>A tiny delay after editing can be acceptable. Crashing because the document has grown too large is not.</p>

<p>Typsastra also supports different preview refresh policies. Authors who prioritize stability while working on very large documents can render on save rather than recompiling after every keystroke. The editor should remain responsive even when the document itself is expensive to compile.</p>

<p>This is a deliberate product decision: predictable resource use is more valuable than winning every latency comparison.</p>

<h2 id="what-the-results-mean">What the results mean</h2>

<p>In one manual 200-page test on my Windows development machine, Typsastra’s later production-equivalent memory observation was approximately 743 MiB, including the application, WebView, and Tinymist. The comparison VS Code and Tinymist environment continued growing and reached approximately 4.8 GB in the final capture.</p>

<p>That is roughly 6.5 times the observed memory use.</p>

<p>This was not a controlled universal benchmark. The VS Code process group included its extension environment, and Windows Task Manager reports working-set values rather than a complete laboratory-grade memory trace. Different documents, platforms, extensions, and preview configurations will produce different results.</p>

<p>Nevertheless, the behavior demonstrates the architectural difference.</p>

<p>Typsastra’s preview is designed around a bounded number of resident page canvases. Its memory use should not grow simply because every page in a long document exists.</p>

<p>More importantly, Typsastra can work with source files containing around 20,000 lines and generated documents reaching approximately 1,500 pages while retaining document synchronization and a usable preview.</p>

<p>That matters more to me than making every keystroke appear instant.</p>

<div class="benchmark" role="img" aria-label="Bar chart comparing approximately 743 MiB for Typsastra with 4,798 MiB for VS Code and Tinymist">
  <h3>Manual 200-page memory observation</h3>
  <div class="bar-row"><span>Typsastra</span><div class="bar-track"><div class="bar typsastra"></div></div><strong>743 MiB</strong></div>
  <div class="bar-row"><span>VS Code + Tinymist</span><div class="bar-track"><div class="bar vscode"></div></div><strong>4,798 MiB</strong></div>
  <small>One Windows development machine; working-set values, not a controlled universal benchmark.</small>
</div>

<h2 id="optimization-is-also-an-accessibility-feature">Optimization is also an accessibility feature</h2>

<p>Performance discussions often focus on benchmark scores, rendering speed, or technical elegance. But resource efficiency has a direct effect on who can use an application.</p>

<p>Not everyone owns a recent workstation with large amounts of RAM. Students, researchers, independent writers, and language communities may be working with older laptops or entry-level hardware.</p>

<p>If an editor requires several gigabytes of memory to open a long document, that is not merely a performance issue. It becomes an accessibility barrier.</p>

<p>The same principle that motivates Typsastra’s complex-script support also motivates its performance architecture.</p>

<p>Supporting a language should mean more than rendering its characters. It should include correct editing behavior, appropriate fonts, reliable language tools, and the ability to work on affordable hardware.</p>

<h2 id="what-i-want-typsastra-to-become">What I want Typsastra to become</h2>

<p>Typsastra began as a solution to a complex-script editing problem. That problem led to Unicode-aware navigation and deletion, language-specific segmentation, spellchecking, completion, and better font handling.</p>

<p>Long-document testing then revealed another kind of exclusion: software that works beautifully for small examples but becomes inaccessible when the document or project grows.</p>

<p>Solving that problem required rebuilding a part of the application that I originally expected to delegate entirely to existing tooling.</p>

<p>The result is not perfect, and it does not need to be.</p>

<p>Typsastra may not always match the immediacy of a partial SVG preview. But it can provide a responsive editor, bounded PDF rendering, and reliable source synchronization for documents far larger than the examples most editors are tested against.</p>

<p>That is the direction I want Typsastra to continue following:</p>

<blockquote>
  <p>An authoring environment built for real documents, complex writing systems, long-form work, and the computers people actually own.</p>
</blockquote>

<p>Inclusivity is not only about which languages an application can display.</p>

<p>It is also about whether people can afford the hardware required to use it.</p>

<figure>
  <img src="/assets/media/screenshot-welcome.png" alt="The Typsastra welcome screen on an everyday computer" />
  <figcaption>Efficient software expands who can participate in multilingual and long-form publishing.</figcaption>
</figure>

<h2 id="explore-typsastra">Explore Typsastra</h2>

<p>Typsastra is an open-source, complex-script-first Typst environment for research and long-form multilingual writing. It is currently beta software and is being developed in public under the MIT License.</p>

<ul>
  <li><a href="https://github.com/Sovichea/typsastra">Typsastra on GitHub</a></li>
  <li><a href="https://github.com/Sovichea/typsastra/releases">Download the latest release</a></li>
  <li><a href="https://github.com/Sovichea/typsastra/blob/main/docs/ROADMAP.md">Read the project roadmap</a></li>
  <li><a href="https://github.com/Sovichea/typsastra/blob/main/docs/BENCHMARKS.md">Review the published benchmark notes</a></li>
</ul>

<p>If you work with Typst, complex scripts, multilingual documents, or unusually long publications, feedback and reproducible test cases are welcome. They help shape Typsastra around the documents and hardware people use in practice.</p>

<div class="cta">
  <h3>Follow the work</h3>
  <p>Typsastra is open source. Explore the code, try the beta, or share a document that pushes the preview in an interesting way.</p>
  <a class="read-link" href="https://github.com/Sovichea/typsastra">Visit Typsastra on GitHub →</a>
</div>]]></content><author><name>Sovichea</name></author><category term="Engineering" /><summary type="html"><![CDATA[A journey from complex-script editing to previewing 1,500-page documents on modest hardware.]]></summary></entry></feed>