9 C
Canberra
Friday, June 19, 2026

SwiftText Learns to Write | Cocoanetics


It began with a bedtime drawback.

There’s a manuscript on my disk — a middle-grade fantasy a younger author in the home has been drafting. Fifteen chapters and a prologue, all in Markdown. The ask was easy and fully cheap: may it’s a actual PDF, the type you’ll be able to maintain, with each chapter beginning on a recent web page like a correct e-book?

So I requested for precisely that. One sentence. A minute later there was a 152-page PDF, every chapter opening on the prime of its personal web page, plus a bit shell script I may re-run each time the draft modified. It modified 3 times that night.

That function — render --page-break-before h2 — is about forty traces, and it’s the smallest factor I shipped this week. I’m opening with it as a result of every little thing beneath it’s the actual story. Within the 5 days since my final put up, SwiftText quietly stopped being a factor that reads paperwork and have become a factor that writes them. Phrase, Pages, PDF. On each platform. With no single heavy dependency.

However first, the sincere half — how does one week produce all of that? It isn’t that I out of the blue obtained quicker at typing.

I don’t know what Anthropic did just a few months in the past. I swear I saved bumping into the speed restrict — particularly the 5-hour one. Then they should have accomplished some optimization with the caching or related, as a result of now, regardless that I sometimes run two or three brokers in parallel, the utilization solely goes upwards very slowly. The Claude Max plan is a flat month-to-month charge, and someplace in there it stopped feeling like a funds I spend rigorously and became a faucet I depart working — not truly infinite, I nonetheless bump the bounds, however inexhaustible sufficient that it quietly modifications which concepts you let your self have. When each experiment is metered you ration your individual curiosity; take the meter away and the bottleneck strikes from price to curiosity.

So it emboldens me to offer any odd thought to some agent to analysis, construct a prototype, or simply go and implement it — as a result of more often than not it simply works. What additionally helps loads is that there are such a lot of already-solved issues to be discovered on GitHub — changing the options to Swift is a straightforward activity. None of which modifications the precise loop: I nonetheless maintain the imaginative and prescient, and the agent nonetheless does the mechanics — good at how, utterly with out opinion about what.

Let me again up, although, as a result of the inspiration for all of it obtained poured on Monday.

One illustration to rule all of them

The week started with some unglamorous housekeeping that turned out to matter greater than the rest. SwiftText had a hand-rolled renderer that walked an HTML DOM and assembled Markdown by gluing strings collectively — about 450 traces of “now emit two areas, except we’re in a listing, except the record is nested, except…” I changed the entire thing with a converter that builds an actual swift-markdown doc and lets its formatter personal all of the fiddly spacing and escaping.

The purpose wasn’t the deleted traces, satisfying as they had been. The purpose is that the swift-markdown AST is now the single illustration every little thing pivots by means of — HTML in, Markdown out, DOCX, Pages, PDF, attributed strings. One backbone, many limbs. As soon as that was true, each new format turned “educate the backbone to speak to at least one other thing” as a substitute of “write one other parser.” That call quietly paid for the remainder of the week.

(swift-markdown has no node for footnotes, which is the type of element that eats a day. So there’s now a small layer that detects footnote HTML — GitHub’s, Pandoc’s, ours — and even an attribute-free fallback that acknowledges a footnote by its form. It’s the kind of factor I’d by no means have bothered with if I had been being cautious about my time. Maintain that thought.)

Educating it to learn Pages

Then I pointed it at Apple Pages.

There is no such thing as a public spec for the iWork format. A .pages file is a zipper of Snappy-compressed protobuf streams — the IWA format — and the one approach to know what’s in it’s to take plenty of actual paperwork aside and infer the grammar. In order that’s what the brand new SwiftTextPages module does: it reads fashionable .iwa and the legacy iWork ’09 XML, pulls out headings, daring, italics, strikethrough, nested lists, footnotes, and the precise embedded photos, and arms you again Markdown.

The half I’m quietly happy with: it’s self-sufficient. The Snappy decompression and the protobuf decoding are applied in-module, so it provides no new dependency and runs anyplace. I threw 136 actual Pages information at it — 135 parsed, zero crashes, and the one “failure” was an empty folder. All the things that can’t be resolved degrades politely to plain textual content somewhat than throwing. Reverse-engineering rewards the paranoid.

After which to jot down Pages

Studying a proprietary format is detective work. Writing one is forgery.

MarkdownToPages builds a .pages file from scratch — no Apple frameworks, nothing bundled at runtime. That meant hand-writing a protobuf encoder, the IWA chunk framing, a stored-zip author, and — my favourite — a Snappy compressor that byte-matches Apple’s personal output, so a doc can round-trip by means of us and are available again bit-for-bit an identical.

That is the place the week stopped being wise. To put in writing Pages properly — native tables with actual cell borders, real page-bottom footnotes, clickable hyperlinks, inline photos — I wanted typed fashions for the iWork wire format. So I wrote a proto2-to-Swift generator that produced 483 typed fashions with zero protobuf-runtime dependency, then checked them in opposition to actuality: 3,004 of three,004 modeled objects throughout six actual paperwork round-trip byte-identical. On prime of that sits a bit typed object-graph framework for synthesizing paperwork — constructing the factor in reminiscence and letting it serialize itself.

The tip state: SwiftText reads and writes Pages, each instructions, excessive constancy, verified on display screen in Pages 14. A local iWork desk, written by a Swift bundle that has by no means as soon as linked in opposition to something Apple ships. I nonetheless discover that humorous.

Phrase, introduced as much as parity

With Pages setting the bar, DOCX appeared out of the blue shabby, so it obtained three fast passes to catch up. Markdown photos now embed as actual OOXML footage — byte-identical to the supply file, sized to suit the web page — as a substitute of italic placeholder textual content. Strikethrough survives the journey. And [^1] footnotes, which used to land in Phrase as literal [^1], now emit as native Phrase footnotes that round-trip cleanly again by means of the reader.

That final one got here virtually without cost, as a result of the footnote scanner I’d grudgingly written again on day one had been pulled out right into a shared, format-agnostic piece. HTML, DOCX, and Pages all draw from the identical properly now. The afternoon I “wasted” on footnote detection became three options.

A PDF engine, from scratch, as a result of the choice aggravated me

Right here is the one the place I’d perceive for those who stopped studying and assumed I’d misplaced it.

SwiftText made PDFs by handing HTML to WebKit. That works superbly — on a Mac. It does nothing on Linux, nothing on a server, nothing the place there’s no system browser to lean on. And the entire arc of SwiftCross and the latest extracted kits has been about not leaning on the platform.

So I ported WeasyPrint. The entire pipeline — HTML, CSS cascade, field tree, structure, paint, PDF — in pure Swift, no WebKit, no new dependencies. WeasyPrint arms its onerous components to different libraries: PDF bytes to pydyf, textual content shaping to HarfBuzz, fonts to fontconfig. I reimplemented these too, due to course I did:

  • SwiftTextPDFWriter — the PDF object and stream author (pydyf’s job).
  • SwiftTextOpenType — a pure-Swift OpenType reader: cmap, metrics, glyph embedding (the fontconfig/HarfBuzz metrics job).
  • SwiftTextCSS — a CSS Syntax Degree 3 tokenizer, colour, selectors, and the precise cascade right into a typed computed type (tinycss2 + cssselect2’s job).
  • SwiftTextRender — the field tree, line breaking, tables, the painter.

After which, as a result of the text-shaping rabbit gap has no backside, this session’s focus drifted into internationalization: the Unicode Bidirectional Algorithm (UAX #9) in pure Swift, so Hebrew and Arabic Markdown lay out right-to-left with no markup; an Arabic shaper that does cursive becoming a member of and lam-alef ligatures by hand — the half WeasyPrint delegates to HarfBuzz; and per-character font fallback when the chosen face is lacking a glyph. 387 checks, an actual end-to-end render by means of a system Arabic font, and an sincere record of what’s nonetheless tough (glyph subsetting, a full GSUB/GPOS shaper). SwiftText now has a PDF path that doesn’t care what working system you’re on.

…and AttributedString, in every single place

Yet another, smaller and sneakier. There’s now a module that renders Markdown right into a Basis AttributedString on macOS, iOS, Linux, and Home windows. The catch is that the apparent manner — PresentationIntent — solely exists in Apple’s Basis; on Linux the construct simply fails to search out the sort. So the renderer carries all of the block-and-inline construction in moveable customized attributes that compile in every single place, and moreover units the native intents on Apple platforms so SwiftUI and TextKit nonetheless perceive it. Cross-platform first, native as a bonus. That’s been the entire posture currently.

The actual superpower

I hold coming again to that manuscript.

The ask was small — “Dad, are you able to make my e-book an actual one?” — and the half I need to bear in mind about this week isn’t something I constructed to tug it off. It’s that I may, in a sentence, the identical night, and that she obtained to carry a correct e-book along with her title on the duvet.

That’s the superpower AI truly handed me. Not pace, not cleverness — permission to say sure. Sure to the e-book, sure to the following half-formed thought one in every of my daughters goals up and asks me to assist make actual. I’m a Swift-wielding dad, and the hole between what they’ll think about and what I can construct them has quietly closed to virtually nothing. Their creativity units the spec now. I simply get to maintain up.

AI didn’t substitute my creativity. It eliminated the funds on curiosity!


Classes: Updates

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

[td_block_social_counter facebook="tagdiv" twitter="tagdivofficial" youtube="tagdiv" style="style8 td-social-boxed td-social-font-icons" tdc_css="eyJhbGwiOnsibWFyZ2luLWJvdHRvbSI6IjM4IiwiZGlzcGxheSI6IiJ9LCJwb3J0cmFpdCI6eyJtYXJnaW4tYm90dG9tIjoiMzAiLCJkaXNwbGF5IjoiIn0sInBvcnRyYWl0X21heF93aWR0aCI6MTAxOCwicG9ydHJhaXRfbWluX3dpZHRoIjo3Njh9" custom_title="Stay Connected" block_template_id="td_block_template_8" f_header_font_family="712" f_header_font_transform="uppercase" f_header_font_weight="500" f_header_font_size="17" border_color="#dd3333"]
- Advertisement -spot_img

Latest Articles