{"id":50694515,"url":"https://github.com/varunbpatil/typst-go-wasm","last_synced_at":"2026-06-09T05:32:46.593Z","repository":{"id":357983762,"uuid":"1238726948","full_name":"varunbpatil/typst-go-wasm","owner":"varunbpatil","description":"Go library for PDF generation from Typst templates, powered by WebAssembly","archived":false,"fork":false,"pushed_at":"2026-06-08T12:53:23.000Z","size":11475,"stargazers_count":16,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-08T14:25:21.251Z","etag":null,"topics":["golang","pdf-generation","rust","typst","wasm"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/varunbpatil.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-14T11:50:12.000Z","updated_at":"2026-06-08T12:53:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/varunbpatil/typst-go-wasm","commit_stats":null,"previous_names":["varunbpatil/typst-go-wasm"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/varunbpatil/typst-go-wasm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varunbpatil%2Ftypst-go-wasm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varunbpatil%2Ftypst-go-wasm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varunbpatil%2Ftypst-go-wasm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varunbpatil%2Ftypst-go-wasm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/varunbpatil","download_url":"https://codeload.github.com/varunbpatil/typst-go-wasm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varunbpatil%2Ftypst-go-wasm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34093774,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","pdf-generation","rust","typst","wasm"],"created_at":"2026-06-09T05:32:42.350Z","updated_at":"2026-06-09T05:32:46.586Z","avatar_url":"https://github.com/varunbpatil.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# typst-go-wasm\n\nPDF generation from [Typst](https://typst.app) templates, running entirely in-process via WebAssembly (WASM).\n\nNo external processes, no network calls, no Typst CLI binary required.\n\n![Portfolio PDF preview](assets/preview.png)\n\n## Installation\n\n```sh\ngo get github.com/varunbpatil/typst-go-wasm@latest\n```\n\nRequires Go 1.25+. No CGo, no external binaries.\n\n## How it works\n\n```\ncaller (Go)\n  │  CompileRequest{Template, Files, Data, Fonts, PDFOpts}\n  ▼\nCompiler.Compile()\n  │  JSON-encodes envelope {main, files, data, fonts (base64), pdf_options}\n  │  writes it into WASM linear memory\n  ▼\ntypst_compiler.wasm  (Rust + typst-as-lib, compiled to WASM)\n  │  decodes envelope\n  │  decodes base64 fonts → TypstEngine\n  │  resolves aux file imports from the files map\n  │  injects data as sys.inputs\n  │  compiles template → PagedDocument\n  │  applies PdfOptions (ident, timestamp, page ranges, standards, tagged)\n  │  renders PDF bytes\n  ▼\nCompiler.Compile() returns []byte (PDF)\n```\n\nThe WASM module is embedded in the Go binary at compile time via `//go:embed`. A single `Compiler` instance can serve concurrent requests safely — each call instantiates a fresh WASM module.\n\n## Usage\n\n```go\nimport \"github.com/varunbpatil/typst-go-wasm\"\n\ncompiler, err := typst.NewCompiler(ctx)\nif err != nil { ... }\ndefer compiler.Close(ctx)\n\n// Load fonts from disk (or embed them in your binary).\nregularTTF, _ := os.ReadFile(\"fonts/MyFont-Regular.ttf\")\nboldTTF, _    := os.ReadFile(\"fonts/MyFont-Bold.ttf\")\n\npdf, err := compiler.Compile(ctx, typst.CompileRequest{\n    // Main .typ source.\n    Template: mainTemplateContent,\n    // Auxiliary files the template may #import by name.\n    Files: map[string]string{\n        \"layout.typ\": layoutTypContent,\n    },\n    // Any JSON-serializable value; available in the template as sys.inputs.\n    Data: map[string]any{\n        \"title\": \"Hello\",\n        \"items\": []string{\"a\", \"b\", \"c\"},\n    },\n    // Raw TTF/OTF bytes. At least one font required.\n    Fonts: [][]byte{regularTTF, boldTTF},\n    // Optional PDF output settings (all fields optional; zero value = typst defaults).\n    PDFOpts: typst.PDFOptions{\n        Ident:     \"my-doc-stable-id\", // reproducible PDF document ID\n        Timestamp: \u0026now,               // time.Time; nil = no timestamp\n        PageRanges: []typst.PageRange{\n            {Start: 1, End: 3}, // pages 1–3\n            {Start: 5, End: 0}, // page 5 to end (0 = no bound)\n        },\n        Standards: []string{\"a-2b\"}, // PDF/A-2b conformance\n        Tagged:    \u0026tagged,          // false to disable tagged PDF\n    },\n})\n```\n\nInside the Typst template, access data via `sys.inputs`:\n\n```typst\n#set text(font: \"MyFont\")\n\n#let data = sys.inputs\n#data.title        // \"Hello\"\n#data.items.at(0)  // \"a\"\n```\n\n## Bring your own fonts\n\nThe WASM binary contains no embedded fonts. You must supply at least one font via `CompileRequest.Fonts`; any font name referenced in a template that is not present in the provided bytes will cause a compile error.\n\nFont bytes are sent through the JSON envelope as base64 strings (Go's `encoding/json` handles this automatically for `[][]byte`) and decoded inside WASM before the engine is built.\n\nThe repository ships three [Rubik](https://fonts.google.com/specimen/Rubik) weights (OFL license) in `fonts/` as a ready-to-use example:\n\n```go\n//go:embed fonts/Rubik-Regular.ttf\nvar rubikRegular []byte\n\n//go:embed fonts/Rubik-Medium.ttf\nvar rubikMedium []byte\n\n//go:embed fonts/Rubik-SemiBold.ttf\nvar rubikSemiBold []byte\n\npdf, err := compiler.Compile(ctx, typst.CompileRequest{\n    ...\n    Fonts: [][]byte{rubikRegular, rubikMedium, rubikSemiBold},\n})\n```\n\n## PDF options\n\n`CompileRequest.PDFOpts` accepts a `PDFOptions` struct to control the PDF output. All fields are optional; the zero value of `PDFOptions` produces the same result as the typst defaults.\n\n| Field        | Type          | Default       | Description                                                                                                                                       |\n|--------------|---------------|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------|\n| `Ident`      | `string`      | `\"\"` (auto)   | Stable document identifier. Used to derive a reproducible PDF document ID. If empty, typst hashes the document title and author instead.          |\n| `Timestamp`  | `*time.Time`  | `nil`         | Creation timestamp embedded in the PDF. `nil` means no timestamp.                                                                                 |\n| `PageRanges` | `[]PageRange` | `nil` (all)   | Which pages to include. 1-indexed; `Start`/`End` of `0` mean \"no bound\". `nil` exports all pages. **Requires `Tagged: ptr(false)`** (see below).  |\n| `Standards`  | `[]string`    | `nil` (none)  | PDF standards to conform to. Accepted values: `\"1.4\"`, `\"1.5\"`, `\"1.6\"`, `\"1.7\"`, `\"2.0\"`, `\"a-1b\"`, `\"a-1a\"`, `\"a-2b\"`, `\"a-2u\"`, `\"a-2a\"`, `\"a-3b\"`, `\"a-3u\"`, `\"a-3a\"`, and others supported by typst. |\n| `Tagged`     | `*bool`       | `nil` (true)  | Whether to write a tagged PDF for accessibility. `nil` uses the typst default (`true`). Pass a pointer to `false` to disable.                     |\n\n### PageRanges and tagged PDF\n\n`PageRanges` and tagged PDF (`Tagged: nil` or `Tagged: ptr(true)`) are mutually exclusive. Passing both returns an error immediately. Set `Tagged` to `false` whenever you use `PageRanges`:\n\n```go\ntagged := false\npdf, err := compiler.Compile(ctx, typst.CompileRequest{\n    ...\n    PDFOpts: typst.PDFOptions{\n        PageRanges: []typst.PageRange{{Start: 1, End: 3}},\n        Tagged:     \u0026tagged,\n    },\n})\n```\n\nThis is a [known typst limitation](https://github.com/typst/typst/issues/7743) — the underlying typst-pdf library does not support the combination.\n\n## Concurrency and memory\n\nEach `Compile` call instantiates a fresh WASM module, which allocates ~48 MB of linear memory for the duration of the call. That memory is released as soon as the call returns.\n\nPeak memory scales linearly with the number of concurrent compilations. For high-throughput services, cap concurrency with a semaphore:\n\n```go\nsem := make(chan struct{}, 8)\n\nsem \u003c- struct{}{}\npdf, err := compiler.Compile(ctx, req)\n\u003c-sem\n```\n\nA `Compiler` instance is safe for concurrent use — the semaphore only controls how many calls run simultaneously, not access to the `Compiler` itself.\n\n## Rebuilding the WASM\n\nThe committed `typst_compiler.wasm` is a convenience artifact. CI verifies the Rust source compiles cleanly but does not assert the binary matches — Rust WASM builds are not reproducible across machines or toolchain versions.\n\nThe Rust source lives in `wasm/`. After modifying it:\n\n```sh\ncd wasm\nCARGO_TARGET_DIR=/tmp/cargo-target cargo build --target wasm32-wasip1 --release\ncp /tmp/cargo-target/wasm32-wasip1/release/typst_compiler.wasm ../typst_compiler.wasm\n```\n\nCommit both the source change and the updated `typst_compiler.wasm`.\n\nRequires Rust stable with the `wasm32-wasip1` target:\n\n```sh\nrustup target add wasm32-wasip1\n```\n\nThe committed binary was built with **rustc 1.95.0**. Using a different toolchain version will produce a functionally equivalent but byte-for-byte different binary.\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE).\n\nThe bundled Rubik fonts (`fonts/`) are licensed under the [SIL Open Font License 1.1](https://scripts.sil.org/OFL).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvarunbpatil%2Ftypst-go-wasm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvarunbpatil%2Ftypst-go-wasm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvarunbpatil%2Ftypst-go-wasm/lists"}