diff --git a/packages/preview/measured-jair/0.1.0/LICENSE b/packages/preview/measured-jair/0.1.0/LICENSE new file mode 100644 index 0000000000..df92f3659b --- /dev/null +++ b/packages/preview/measured-jair/0.1.0/LICENSE @@ -0,0 +1,49 @@ +This package is licensed under the MIT License, except for the contents of +the `template/` directory, which are licensed under the MIT No Attribution +License (MIT-0) so that documents created from the template can be modified +and distributed without restriction. + +-------------------------------------------------------------------------- +MIT License (applies to lib.typ, README.md, typst.toml and thumbnail.png) +-------------------------------------------------------------------------- + +Copyright (c) 2026 Kirill Groshenkov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +-------------------------------------------------------------------------- +MIT No Attribution (applies to everything under template/) +-------------------------------------------------------------------------- + +Copyright (c) 2026 Kirill Groshenkov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/preview/measured-jair/0.1.0/README.md b/packages/preview/measured-jair/0.1.0/README.md new file mode 100644 index 0000000000..4cb36db7ba --- /dev/null +++ b/packages/preview/measured-jair/0.1.0/README.md @@ -0,0 +1,248 @@ +# measured-jair + +A Typst template for the **Journal of Artificial Intelligence Research (JAIR)**. + +JAIR ships a LaTeX-only author kit. This package reproduces that layout in +Typst so you can draft and submit in Typst — JAIR accepts submissions as PDF — +without hand-porting a LaTeX class. + +It is called *measured* because every dimension in it was measured on PDFs +compiled with the real `jair.cls`, not copied from the class by eye. This is a +community port, not an official JAIR package. + +```sh +typst init @preview/measured-jair:0.1.0 +``` + +## Provenance + +The template follows `jair.cls` (2025/08/15), the class JAIR adopted for volume +83 onward. `jair.cls` loads `acmart` with `[acmlarge, natbib=false, screen]`, +and acmart in turn loads **`amsart`** at 10pt — *not* `article`. That matters: +amsart's size ladder differs from the familiar one at every step, so a template +built on `article`'s sizes is wrong everywhere. + +Every value below was read out of the class files and then **verified by +measuring compiled reference PDFs** — the sample in the JAIR Author Kit and a +second document compiled with `jair.cls` on an unfilled page, so that TeX's +stretchable glue sits at its natural size. Positions were taken from the +glyph outlines of a 600 dpi render, so they do not depend on font metrics. + +### Type + +| Element | LaTeX | amsart 10pt | Reference | Template | +| --- | --- | --- | --- | --- | +| Body | `\normalsize` | 10 / 12 | 9.96, b2b 11.95 | 9.96, b2b 11.95 | +| Abstract | `\small` | 9 / 11 | 8.97 | 8.97 | +| Sections and subsections | `\large` | 10.95 / 13 | 10.91 | 10.91 | +| Author names | `\Large` | 12 / 14 | 11.96 | 11.96 | +| Title | `\LARGE` | 14.4 / 17 | 14.35 | 14.35 | +| Head, foot, footnotes | `\footnotesize` | 8 / 10 | 7.97 | 7.97 | +| Line numbers (`review`) | `\scriptsize` | 7 / 8 | 6.97 | 6.97 | + +jair.cls overrides both `\@secfont` and `\@subsecfont`, so sections and +subsections share one size — unlike stock acmart. Levels 3 and 4 use the +class's run-in faces (sans italic and serif italic, each with a trailing +period); see Known deviations for how far the run-in behavior is reproduced. + +### Layout + +acmart's dimensions are TeX points (1/72.27 in); Typst's `pt` is the big point +(1/72 in), so every copied value is scaled by 72/72.27. `includeheadfoot` means +the 78pt/114pt margins bound header + text + foot, not the text alone: the 13pt +head and 14pt headsep come out of the top margin. + +| Element | Reference | Template | +| --- | --- | --- | +| Page | 612 × 792, two-sided, one column | ✓ | +| Text left edge | 80.7 | 80.7 | +| Running head | 79.70 | 79.70 | +| First body line | 106.93 | 106.86 | +| Title | 103.57 | 103.44 | +| Running foot | 670.35 | 670.37 | +| Line numbers (`review`) | x 54.6, pure red, none on p.1 | x 54.6, pure red, none on the p.1 title block | +| Running-head separator | 7.97 each side of the bullet | 7.97 | +| First-page footnote block | flush at the text edge | flush | + +### Vertical spacing + +Typst has no stretchable glue and gives text lines a fixed 1em box, so the +class values cannot be copied directly. Each transition below was fitted so +that the ink-to-ink distance matches a `jair.cls` document on an unfilled page. + +| Transition | Class value | Reference | Template | +| --- | --- | --- | --- | +| Text → display equation | `0.35\baselineskip` plus stretch | 6.1–6.7 | 6.2 | +| Display equation → text | same | 6.1–6.8 | 6.7 | +| Text → figure | `\intextsep` 12pt | 12.1 | 12.1 | +| Figure → caption | `\abovecaptionskip` 10pt | 13.3 | 13.4 | +| Figure caption → text | | 15.8 | 16.1 | +| Table caption → top rule | | 13.2 | 12.7 | +| Table rule → row → rule | booktabs | 4.7 / 5.3 / 4.9 / 5.4 | 4.1 / 5.9 / 4.7 / 5.6 | +| Subsection → level-3 heading | `-.5\baselineskip` | 7.8 | 7.8 | +| Text → level-4 heading | `-.5\baselineskip` | 8.5 | 8.5 | +| Text → list | `\topsep` = `\smallskipamount` | 4.8 | 4.9 | +| Last author → abstract | | 9.2 | 9.5 | +| Abstract and JAIR blocks | `\medskip` | 7.1 / 7.2 | 6.8 / 7.2 | +| JAIR reference format → first heading | `\bigskip` merged with the section skip | 12.4 | 12.4 | + +The baseline grid is pinned with `top-edge`/`bottom-edge` rather than left to +font metrics, so spacing holds at amsart's values whichever font resolves — +checked to give the same grid with Linux Libertine and Libertinus Serif. That +matters on the Typst web app, where the font set differs. + +## Usage + +```typ +#import "@preview/measured-jair:0.1.0": jair, toprule, midrule, botrule + +#show: jair.with( + title: "Your Article Title", + short-title: "Short Title", // running head + authors: ( + ( + name: "Ada Lovelace", + affiliation: "Analytical Engine Institute, United Kingdom", + contact-affiliation: "Analytical Engine Institute, London, United Kingdom", + email: "ada@example.org", + orcid: "0000-0000-0000-0000", + corresponding: true, + ), + ), + short-authors: "Lovelace", // running head + abstract: [Your abstract. JAIR prints it with no "Abstract" heading.], + track: "Insert JAIR Track Name Here", // omit unless in a special track + associate-editor: "Insert JAIR AE Name", + volume: "83", article: "1", + pubdate: "August 2025", year: "2025", + doi: "10.1613/jair.1.xxxxx", + review: true, // line numbers, as the JAIR example does + received: "Received 20 February 2007; accepted 5 June 2009", + acknowledgements: [Thanks to ...], + bibliography: bibliography("refs.bib", title: [References], + style: "american-psychological-association"), + appendix: [ = Supplementary material ], +) + += Introduction +... + +#figure( + table(columns: 2, toprule, table.header[*A*][*B*], midrule, [1], [2], botrule), + caption: [Tables are captioned above.], +) +``` + +### Parameters + +| Parameter | Default | Purpose | +| --- | --- | --- | +| `title` | required | Article title; used in the running head and the JAIR reference format. | +| `short-title` | `title` | Running-head form of the title. Give one whenever the title is longer than a line; the running head does not truncate. | +| `authors` | `()` | Array of dictionaries. `name` (a string) is required; `affiliation`, `email`, `orcid`, `corresponding` and `contact-affiliation` (the longer form printed in the contact footnote) are optional. | +| `short-authors` | derived | Running-head author list. acmart's default is the full names — "A", "A and B", "A, B, and C" — and that is what the template derives; the JAIR sample overrides it with surnames, so pass e.g. `"Xu, Hutter, Hoos & Leyton-Brown"` for that look. | +| `abstract` | `none` | Printed in `\small` with no heading. | +| `track` | `none` | JAIR Track line; printed only when given. | +| `associate-editor` | `"Insert JAIR AE Name"` | JAIR Associate Editor line. Printed unconditionally, as jair.cls does; replace the placeholder. | +| `volume`, `article` | `"1"`, `"1"` | Running head/foot and the reference format. Placeholders until the journal assigns them. | +| `pubdate`, `year` | `none` | Publication month and year for the foot, the reference format and the copyright line. Each is omitted from the output while `none`. | +| `doi` | `none` | Printed in the reference format and the license notice when given. | +| `received` | `none` | Printed in `\small` at the end, e.g. "Received … ; accepted …". | +| `acknowledgements` | `none` | Unnumbered section before the references. | +| `appendix` | `none` | Set after the references, headings lettered. | +| `copyright-holder` | `none` | Replaces "Copyright held by the owner/author(s)." with "*holder*." | +| `review` | `false` | Line numbers restarting on every page, like `\documentclass[review]{jair}`. | +| `anonymous` | `false` | One "ANONYMOUS AUTHOR(S)" line, no contact footnote, "Anonymous" in the running head. JAIR does not use blind review; for preprints or other venues. | +| `bibliography` | `none` | Pass a `bibliography(...)` call. | +| `keywords`, `ccs` | `()`, `none` | Exist because acmart supports them. See the next section. | + +Headings: levels 1–3 are numbered (`1`, `1.1`, `1.1.1`), level 4 and below +are not, matching `secnumdepth` 3. Levels 5 and 6 fall back to the level-4 +face. + +`toprule`, `midrule` and `botrule` are the booktabs rules acmart loads: +0.08em heavy for the top and bottom, 0.05em light in between. + +### CCS concepts and keywords + +**JAIR's own kit says: "Do not include ACM CCS Concepts or Keywords."** The +`ccs` and `keywords` parameters exist because acmart supports them, and are +left unset in the shipped example. Do not use them for a JAIR submission. + +## Citation style + +JAIR uses author–year citations (`acmauthoryear` in the LaTeX kit). Typst has +no bundled ACM author–year CSL, so the example uses +`american-psychological-association`, which is close but not identical. For an +exact match, put an ACM author–year CSL file beside your document and pass it +as `style: "acm-author-year.csl"`. + +## Fonts + +acmart sets JAIR in Linux Libertine, with Linux Biolinum for sans-serif and +Inconsolata for monospace; math is a Libertine-matched face. The template asks +for those first, then for Libertinus, then for TeX Gyre Heros as the sans of +last resort. + +Typst's compiler embeds Libertinus Serif, New Computer Modern with its math +face and DejaVu Sans Mono, but **no sans-serif family**. Without one, the +title, byline, headings, running heads and captions silently fall back to the +serif. On a TeX Live machine Linux Biolinum O is present. In the Typst web app +check the font list of your project; if no Biolinum, Libertinus Sans or TeX +Gyre Heros is offered, upload the Linux Biolinum O files (they are free) to +the project. + +Typst warns once per use about each family it cannot find; the warnings are +harmless as long as one family per list resolves. + +## Known deviations + +Stated plainly, because this is a reimplementation and not the class itself: + +- **Not byte-identical.** TeX and Typst break lines and hyphenate differently, + so text will not fall identically even where every dimension matches. +- **No glue.** acmlarge pages are flush-bottom and stretch the space around + displays, floats and headings to fill each page; Typst pages are + ragged-bottom and use the fitted natural values above. +- **Run-in headings.** acmart makes levels 3 and 4 run-in: the heading sits on + the same line as the paragraph that follows it. Typst always starts a new + paragraph after a heading, so the face, the trailing period and the space + above are matched but the text begins on the next line. +- **Consecutive lists.** LaTeX puts two `\topsep`s between a list that directly + follows another; Typst collapses them to one, so that gap is about 2pt + tighter than in the class. +- **Footnote rules.** acmart draws a full-width rule above the first-page + contact/copyright block and a 4pc rule above ordinary footnotes. Typst has + one footnote separator per document, so the 4pc rule is used throughout. +- **CC BY badge** is drawn as a boxed "CC BY" rather than the official 88×31 + image, to keep the package free of binary assets. +- **Line numbers.** acmart's `review` option draws a fixed ruler in the margin, + numbering 12pt slots regardless of where text actually falls; Typst numbers + real lines. Color (pure red), size, left alignment, margin position and + restart on every page match; the numbers correspond to lines rather than + slots. acmart shows no ruler on page 1; here the title block carries no + numbers but body lines that start on page 1 do. Hiding them would need a + per-line `context` lookup of the page counter, which keeps documents of a + few dozen pages from converging. +- **Author grouping.** acmart can put several authors sharing an affiliation on + one byline row; here every author gets a line of their own, which is what jair.cls's + `\@mkauthors@i` does for the journal formats anyway. +- **Theorem environments** are not styled to acmart's `acmplain`/`acmdefinition`. +- **Teaser figures, subtitles and `\titlenote`/`\authornote`** are not + implemented; the only note mechanism is the corresponding-author asterisk. + +## Before you submit + +- JAIR accepts **PDF only** at submission; the LaTeX class is used to produce + the published version. Confirm with the editors if you intend to stay in + Typst through acceptance. +- Fill in the JAIR associate editor and replace the placeholder DOI. +- JAIR asks authors to be concise but sets no page limit. + +## License + +MIT for the package (`lib.typ` and the documentation); MIT-0 for everything +under `template/`, so a document started from the template carries no +attribution obligation. Both texts are in `LICENSE`. The layout parameters are +derived from `jair.cls` and `acmart.cls`, both distributed under the LaTeX +Project Public License; no code from either is included. diff --git a/packages/preview/measured-jair/0.1.0/lib.typ b/packages/preview/measured-jair/0.1.0/lib.typ new file mode 100644 index 0000000000..dde3e33d6d --- /dev/null +++ b/packages/preview/measured-jair/0.1.0/lib.typ @@ -0,0 +1,450 @@ +// measured-jair — a Typst template for the Journal of Artificial Intelligence Research +// +// Reproduces the layout of `jair.cls` (2025/08/15), the class JAIR adopted for +// volume 83 onward. jair.cls loads `acmart` with [acmlarge, natbib=false, +// screen], and acmart in turn loads *amsart* at 10pt -- not `article` -- so the +// size ladder below is amsart's, which differs from the familiar one at every +// step. All dimensions were read from the class files and then verified by +// measuring the compiled reference PDF character by character. +// +// acmart's dimensions are TeX points (1/72.27in); Typst's `pt` is the big point +// (1/72in). Every copied value is scaled by 72/72.27. +// +// Licensed under the MIT License. + +// acmart's faces first, then fallbacks. Typst's compiler embeds Libertinus +// Serif, New Computer Modern (+ Math) and DejaVu Sans Mono but no sans-serif +// at all, so a sans must come from the system or the project; TeX Gyre Heros +// is the last resort because the web app ships the TeX Gyre family. Typst +// warns once per use for every family it cannot find, so the lists are short. +#let _serif = ("Linux Libertine O", "Libertinus Serif") +#let _sans = ("Linux Biolinum O", "Libertinus Sans", "TeX Gyre Heros") +#let _mono = ("Inconsolata", "DejaVu Sans Mono") +#let _math = ("Libertinus Math", "New Computer Modern Math") + +// amsart 10pt \@typesizes: (size, baselineskip), in TeX pt. +#let _tex = 72 / 72.27 +#let _normalsize = 10pt * _tex // 10/12 +#let _small = 9pt * _tex // 9/11 +#let _footnotesize = 8pt * _tex // 8/10 +#let _scriptsize = 7pt * _tex // 7/8 +#let _large = 10.95pt * _tex // 10.95/13 — section headings (jair.cls @secfont) +#let _Large = 12pt * _tex // 12/14 — author names +#let _LARGE = 14.4pt * _tex // 14.4/17 — title + +// Typst's `leading` is the gap between lines; LaTeX's \baselineskip is measured +// baseline to baseline. Pinning top-edge/bottom-edge to a 1em box makes the +// conversion exact and independent of which font actually resolves, so the +// baseline grid survives a font substitution on the Typst web app. +#let _lead(baselineskip, size) = baselineskip * _tex - size + +#let _cc-badge = box( + stroke: 0.6pt + rgb("#333"), + radius: 2pt, + inset: (x: 3pt, y: 1pt), + text(size: 6.5pt, weight: "bold", font: _sans)[CC BY], +) + +/// booktabs rules, as acmart loads booktabs: \toprule and \bottomrule are +/// 0.08em heavy, \midrule is 0.05em light. Use them inside `table(...)`. +#let toprule = table.hline(stroke: 0.08em) +#let midrule = table.hline(stroke: 0.05em) +#let botrule = table.hline(stroke: 0.08em) + +/// The JAIR article template. +/// +/// JAIR's own kit states: "Do not include ACM CCS Concepts or Keywords." The +/// `ccs` and `keywords` parameters exist because acmart supports them, but +/// leave them unset for a JAIR submission. +/// +/// - title: the article title. +/// - short-title: running-head form of the title (`\title[short]{...}`). +/// - authors: array of dictionaries with `name` and `affiliation`, optionally +/// `email`, `orcid`, `corresponding`, and `contact-affiliation` for the +/// longer form the class prints in the contact footnote. +/// - short-authors: running-head form of the author list. +/// - abstract: printed in \small with no heading, as JAIR does. +/// - track, associate-editor: the JAIR metadata block. +/// - volume, article, pubdate, year, doi: running head/foot and the JAIR +/// reference format string. +/// - received: e.g. "Received 20 February 2007; accepted 5 June 2009". +/// - acknowledgements: unnumbered section before the references. +/// - appendix: content set after the references, with lettered headings. +/// - review: adds line numbers, like `\documentclass[review]{jair}`. The +/// official JAIR example is compiled with this option. +/// - anonymous: strips author identity. JAIR does not use blind review; the +/// switch is for preprints and other venues. +#let jair( + title: none, + short-title: none, + authors: (), + short-authors: none, + abstract: none, + keywords: (), + ccs: none, + track: none, + associate-editor: "Insert JAIR AE Name", + volume: "1", + article: "1", + pubdate: none, + year: none, + doi: none, + received: none, + acknowledgements: none, + appendix: none, + copyright-holder: none, + review: false, + anonymous: false, + bibliography: none, + body, +) = { + let journal = "Journal of Artificial Intelligence Research" + + assert( + type(authors) == array, + message: "`authors` must be an array of dictionaries, got " + str(type(authors)), + ) + for a in authors { + assert( + type(a) == dictionary and "name" in a and type(a.name) == str, + message: "each entry of `authors` must be a dictionary with a `name` string, got " + repr(a), + ) + } + // 3. a title is needed for the running head and the reference format + assert(title != none, message: "`title` is required") + + set document( + title: title, + author: if anonymous { () } else { authors.map(a => a.name) }, + ) + + // acmart builds \shortauthors from the full author names joined by + // \andify: "A", "A and B", "A, B, and C". The sample overrides it with + // surnames; pass `short-authors` to do the same. + let short-auth = if anonymous { "Anonymous" } else if short-authors != none { + short-authors + } else { + let names = authors.map(a => a.name) + if names.len() == 0 { "" } else if names.len() == 1 { names.first() } else if names.len() == 2 { + names.join(" and ") + } else { names.slice(0, -1).join(", ") + ", and " + names.last() } + } + let short-tit = if short-title != none { short-title } else { title } + + // acmlarge asks for top=78pt, bottom=114pt (TeX pt) with `includeheadfoot`, + // so those margins bound header + text + foot and the 13pt head and 14pt + // headsep come out of the top one. The values below are what that works + // out to, measured on the reference: head at y=79.1/79.7, first body line + // 106.93, last 654.72, foot 670.35. + set page( + width: 8.5in, + height: 11in, + margin: (inside: 80.7pt, outside: 80.7pt, top: 106.9pt, bottom: 138pt), + binding: left, + header-ascent: 19.2pt, + footer-descent: 16.4pt, + header: context { + let n = counter(page).get().first() + if n == 1 { return } + set text(font: _sans, size: _footnotesize) + let folio = [#article:#n] + if calc.odd(n) { + align(right)[#short-tit#h(1em)#sym.bullet#h(1em)#folio] + } else if short-auth == "" { + align(left, folio) + } else { + align(left)[#folio#h(1em)#sym.bullet#h(1em)#short-auth] + } + }, + footer: context { + let n = counter(page).get().first() + let l = text(size: _footnotesize)[ + #journal, Vol. #volume, Article #article. + #if pubdate != none [Publication date: #pubdate.] + ] + if calc.odd(n) { align(right, l) } else { align(left, l) } + }, + ) + + // \documentclass[review] turns on lineno at \scriptsize. A `set` inside an + // `if` block would only apply within that block, so the switch lives in the + // argument. The reference prints them at x=54.6 on both odd and even pages. + // The callback deliberately uses no `context`: a per-line introspection of + // the page counter keeps a long document from converging ("layout did not + // converge within 5 attempts"). The title block below opts out of the + // numbers instead; body lines on page 1 are numbered, which acmart's + // ruler does not do (see README). + set par.line( + numbering: if review { + n => text(size: _scriptsize, font: _serif, fill: rgb(255, 0, 0), str(n)) + } else { none }, + number-align: left, + number-margin: left, + number-clearance: 19.6pt, + numbering-scope: "page", + ) + + set text(font: _serif, size: _normalsize, lang: "en", top-edge: 0.75em, bottom-edge: -0.25em) + // acmart: \parindent 10pt, \parskip 0pt, so paragraph spacing == leading. + set par( + justify: true, + leading: _lead(12pt, _normalsize), + spacing: _lead(12pt, _normalsize), + first-line-indent: 10pt * _tex, + ) + // Typst sets raw at 0.8em; \texttt runs at the surrounding size, so undo it. + show raw: set text(font: _mono, size: 1.25em) + show math.equation: set text(font: _math) + set math.equation(numbering: "(1)") + // Paragraph spacing equals the leading (about 2pt), and blocks inherit it, + // so displays and floats need their own. amsart sets \abovedisplayskip = + // \belowdisplayskip = 0.35\baselineskip plus 0.35\baselineskip (4.2pt) and + // \intextsep = 12pt plus 6pt minus 4pt. Typst has no glue, so the values + // below were fitted to a jair.cls document compiled on an unfilled page: + // ink-to-ink gaps of 6.1-6.8pt around displays, 12.1pt above a figure, + // 15.8pt from its caption to the next line. + show math.equation.where(block: true): set block(above: 6.2pt, below: 6.2pt) + show figure: set block(above: 12pt * _tex, below: 15.4pt) + + // The `screen` option: ACMPurple for internal links and citations, + // ACMDarkBlue for URLs. + show link: set text(fill: cmyk(100%, 58%, 0%, 21%)) + show ref: set text(fill: cmyk(55%, 100%, 0%, 15%)) + show cite: set text(fill: cmyk(55%, 100%, 0%, 15%)) + + // secnumdepth is 3, so levels 1-3 are numbered. \@seccntformat appends + // \quad after the number; that quad is added by the show rules below rather + // than by the numbering itself, so `@label` references stay clean. + set heading(numbering: "1.1.1") + show heading.where(level: 4): set heading(numbering: none) + show heading.where(level: 5): set heading(numbering: none) + show heading.where(level: 6): set heading(numbering: none) + show heading: set par(justify: false, first-line-indent: 0pt, leading: _lead(13pt, _large)) + let _number(it) = if it.numbering != none { + counter(heading).display(it.numbering) + h(1em) + } + // jair.cls overrides \@secfont AND \@subsecfont to the same thing, so levels + // 1 and 2 share one size, unlike stock acmart. The block spacing is + // \vskip .75\baselineskip / .25\baselineskip *plus* the interline glue that + // Typst's edge-to-edge text boxes do not contribute. + let _section(it) = block(above: 11.3pt, below: 4.7pt, width: 100%, sticky: true, { + set text(font: _sans, weight: "bold", size: _large) + _number(it) + it.body + }) + show heading.where(level: 1): _section + show heading.where(level: 2): _section + // Levels 3 and 4 are run-in in acmart: \@subsubsecfont is \sffamily\itshape + // and \@parfont is \itshape, both with a dot after and a negative afterskip + // followed by \hskip 3.5pt. Typst starts a new paragraph after any heading, + // so the text cannot join the same line; the fonts, the trailing period and + // the -.5\baselineskip beforeskip are matched, and the difference is stated + // in the README. Levels 5 and 6 fall back to the level-4 face. + show heading.where(level: 3): it => block(above: 4.8pt, below: 0pt, sticky: true, { + set text(font: _sans, style: "italic", weight: "regular", size: _normalsize) + _number(it) + it.body + [.] + }) + let _paragraph(it) = block(above: 7.9pt, below: 0pt, sticky: true, { + h(10pt * _tex) + set text(style: "italic", weight: "regular", size: _normalsize) + it.body + [.] + }) + show heading.where(level: 4): _paragraph + show heading.where(level: 5): _paragraph + show heading.where(level: 6): _paragraph + + // \abovecaptionskip 10pt; measured 13.3pt ink-to-ink from a figure to its + // caption and from a table caption to the rule below it. + set figure(gap: 13pt) + show figure.caption: set text(font: _sans, size: _small) + set figure.caption(separator: [. ]) + show figure.where(kind: image): set figure(supplement: [Fig.]) + show figure.where(kind: table): set figure.caption(position: top) + // Row pitch of a booktabs table in the reference is 17.3pt at 10pt, which + // Typst reaches with a 3.6pt vertical inset. + set table(stroke: none, inset: (x: 5pt, y: 3.6pt)) + + // acmart list geometry: \labelsep 4pt, label width 6.5pt. + // Measured on the reference: marker at margin+20.2, body at margin+30.1. + // `body-indent` is measured from the end of the marker, hence the smaller + // value. acmlarge inherits amsart's "(1)" enumerator. + set list(indent: 20.2pt, body-indent: 6.4pt) + set enum(indent: 20.2pt, body-indent: 6.4pt, numbering: "(1)") + set terms(indent: 20.2pt, separator: h(6.4pt)) + + show std.bibliography: set heading(numbering: none) + // Ordinary footnotes use acmart's 4pc rule. + set footnote.entry(separator: line(length: 48pt * _tex, stroke: 0.4pt), indent: 0pt) + show footnote.entry: set text(size: _footnotesize) + show footnote.entry: set par(leading: _lead(10pt, _footnotesize)) + + // --- Title block --------------------------------------------------------- + // LaTeX puts the first baseline \topskip below the text-block top, so the + // title's larger face starts 3.4pt higher than a 10pt body line would. + // acmart's review ruler is absent from page 1; the topmatter is excluded + // from the line numbers here. + set par.line(numbering: none) + v(-3.4pt) + block(width: 100%, { + set par(justify: false, first-line-indent: 0pt, leading: _lead(17pt, _LARGE)) + text(font: _sans, weight: "bold", size: _LARGE, title) + v(6.3pt) + + // jair.cls \@mkauthors@i: one author per line, NAME in caps, affiliation + // inline after a comma. + if anonymous { + block(spacing: 2pt, text(font: _sans, size: _Large, upper("Anonymous Author(s)"))) + } else { + for a in authors { + block(spacing: 2pt, { + text(font: _sans, size: _Large, upper(a.name)) + if a.at("corresponding", default: false) { + text(size: 8.8pt, baseline: -2pt, "*") + } + if a.at("affiliation", default: none) != none { + text(font: _sans, size: _Large)[,] + text(size: _normalsize)[ #a.affiliation] + } + }) + } + } + }) + + v(6.4pt) + + // \@mkabstract sets the abstract in \small with no heading. + if abstract != none { + block(width: 100%, { + set text(size: _small) + set par( + leading: _lead(11pt, _small), + spacing: _lead(11pt, _small), + first-line-indent: 0pt, + ) + abstract + }) + } + + // \@specialsection prints these labels unbolded, unlike the JAIR blocks. + // JAIR asks authors not to use them at all. The \medskip between the blocks + // measures 7.1pt ink-to-ink on the reference; 4.2pt of block spacing gives + // the same on top of the 1em text boxes. + let _medskip = 4.2pt + if ccs != none { + v(_medskip) + block(text(size: _small)[CCS Concepts: #ccs]) + } + if keywords.len() > 0 { + v(_medskip) + block(text(size: _small)[Additional Key Words and Phrases: #keywords.join(", ")]) + } + + // --- JAIR metadata block, separated by \medskip --------------------------- + if track != none { + v(_medskip) + block(text(size: _small)[*JAIR Track:* #track]) + } + v(_medskip) + block(text(size: _small)[*JAIR Associate Editor:* #associate-editor]) + + // The first-page footnotes (corresponding author, contact information, + // license) are attached to the end of this block. As separate calls each + // would open an empty paragraph and cost a full line above the body. + let first-page-notes = { + if not anonymous and authors.any(a => a.at("corresponding", default: false)) { + footnote(numbering: _ => "")[ + #set text(size: _footnotesize) + \* Corresponding Author. + ] + } + if not anonymous { + let contacts = authors.map(a => { + let orcid = if a.at("orcid", default: none) != none { + [, #smallcaps("orcid:") #link("https://orcid.org/" + a.orcid)[#a.orcid]] + } + let mail = if a.at("email", default: none) != none { [, #a.email] } + let aff = a.at("contact-affiliation", default: a.at("affiliation", default: none)) + [#a.name#orcid#mail#if aff != none [, #aff]] + }) + if contacts.len() > 0 { + footnote(numbering: _ => "")[ + #set text(size: _footnotesize) + #if contacts.len() > 1 [Authors'] else [Author's] Contact Information: + #contacts.join("; "). + ] + } + } + footnote(numbering: _ => "")[ + #set text(size: _footnotesize) + #_cc-badge + #h(0.5em) + #link("https://creativecommons.org/licenses/by/4.0/")[ + This work is licensed under a Creative Commons Attribution International 4.0 License. + ] + #linebreak() + ©#if year != none [ #year] + #if copyright-holder != none [#copyright-holder.] else [Copyright held by the owner/author(s).] + #if doi != none [#linebreak() #smallcaps("doi:") #link("https://doi.org/" + doi)[#doi]] + ] + } + + v(_medskip) + block(text(size: _small)[ + *JAIR Reference Format:* \ + #{ + let names = if anonymous { ("Anonymous",) } else { authors.map(a => a.name) } + let joined = if names.len() == 0 { "" } else if names.len() == 1 { + names.first() + } else if names.len() == 2 { names.join(" and ") } else { + names.slice(0, -1).join(", ") + ", and " + names.last() + } + [#joined. #if year != none [#year. ]#title. _#journal _ #volume, Article #article#if pubdate != none [ (#pubdate)], ] + } + #context { + let n = counter(page).final().first() + [#text(fill: cmyk(55%, 100%, 0%, 15%))[#n] #if n == 1 { "page" } else { "pages" }.] + } + #if doi != none [ #smallcaps("doi:") #link("https://doi.org/" + doi)[#doi]] + #first-page-notes + ]) + + // acmart resets the footnote counter after the topmatter, so the synthetic + // footnotes above do not renumber the author's first real one. + counter(footnote).update(0) + + // \@printendtopmatter inserts \par\bigskip before the body, which + // \addvspace merges with the first heading's own skip. A weak skip of the + // same size as the heading's `above` collapses with it, so a first heading + // sits 12.4pt ink-to-ink below the reference-format block, as in the + // reference, while a body that starts with plain text gets the bigskip. + v(11.6pt, weak: true) + + { + set par.line(numbering: if review { + n => text(size: _scriptsize, font: _serif, fill: rgb(255, 0, 0), str(n)) + } else { none }) + body + } + + if acknowledgements != none { + heading(numbering: none, outlined: false)[Acknowledgments] + acknowledgements + } + + if bibliography != none { bibliography } + + if appendix != none { + counter(heading).update(0) + set heading(numbering: "A.1.1") + appendix + } + + if received != none { + v(12pt * _tex) + block(text(size: _small, received)) + } +} diff --git a/packages/preview/measured-jair/0.1.0/template/main.typ b/packages/preview/measured-jair/0.1.0/template/main.typ new file mode 100644 index 0000000000..c182cdc15e --- /dev/null +++ b/packages/preview/measured-jair/0.1.0/template/main.typ @@ -0,0 +1,92 @@ +#import "@preview/measured-jair:0.1.0": jair, toprule, midrule, botrule + +#show: jair.with( + title: "A Typst Template for the Journal of Artificial Intelligence Research", + short-title: "A Typst Template for JAIR", + short-authors: "Lovelace & Turing", + authors: ( + ( + name: "Ada Lovelace", + affiliation: "Analytical Engine Institute, United Kingdom", + contact-affiliation: "Analytical Engine Institute, London, United Kingdom", + email: "ada@example.org", + orcid: "0000-0000-0000-0001", + corresponding: true, + ), + ( + name: "Alan Turing", + affiliation: "National Physical Laboratory, United Kingdom", + contact-affiliation: "National Physical Laboratory, Teddington, United Kingdom", + email: "turing@example.org", + orcid: "0000-0000-0000-0002", + ), + ), + abstract: [ + This example exercises the template: the title block, the JAIR metadata + blocks, author-year citations, a numbered equation, a table and a figure, + a run-in third-level heading, a footnote, an appendix, and the first-page + contact and license notices. Replace it with your own abstract. + ], + track: "Insert JAIR Track Name Here", + associate-editor: "Insert JAIR AE Name", + volume: "83", + article: "1", + pubdate: "August 2025", + year: "2025", + doi: "10.1613/jair.1.xxxxx", + review: true, + received: "Received 20 February 2007; accepted 5 June 2009", + bibliography: bibliography("refs.bib", title: [References], style: "american-psychological-association"), + appendix: [ + = Supplementary material + + Content passed as `appendix:` is set after the reference list and its + headings are lettered. + ], +) + += Introduction + +This document shows the Typst port of the JAIR article style. The layout +follows `jair.cls`, which extends ACM's `acmart` in its `acmlarge` +configuration: US Letter, a single column of 10pt Linux Libertine, sans-serif +headings, and a running foot naming the journal, volume and article.#footnote[ + Body footnotes are numbered from 1; the first-page notices do not count. +] + +== A subsection + +Cite sources in the author-year style JAIR uses @knuth1984texbook. Equations +are numbered on the right: + +$ sum_(i=1)^n i = (n (n+1)) / 2 $ + +=== A third-level heading + +Levels 3 and 4 use acmart's run-in faces with a trailing period. Tables take +their captions above and figures below, as in `acmart`. + +#figure( + table( + columns: 3, + toprule, + table.header([*Solver*], [*Solved*], [*Mean time*]), + midrule, + [SATzilla], [1,204], [12.4 s], + [Baseline], [987], [31.8 s], + botrule, + ), + caption: [A table, captioned above the content, with booktabs rules.], +) + +#figure( + rect(width: 60%, height: 48pt, fill: luma(235), stroke: 0.5pt)[ + #set align(center + horizon) + Your figure here + ], + caption: [A figure, captioned below the content.], +) + += Conclusion + +Replace this file's contents with your article. diff --git a/packages/preview/measured-jair/0.1.0/template/refs.bib b/packages/preview/measured-jair/0.1.0/template/refs.bib new file mode 100644 index 0000000000..f4917741ee --- /dev/null +++ b/packages/preview/measured-jair/0.1.0/template/refs.bib @@ -0,0 +1,6 @@ +@book{knuth1984texbook, + title = {The {\TeX}book}, + author = {Knuth, Donald E.}, + publisher = {Addison-Wesley}, + year = {1984} +} diff --git a/packages/preview/measured-jair/0.1.0/thumbnail.png b/packages/preview/measured-jair/0.1.0/thumbnail.png new file mode 100644 index 0000000000..4e2f0c0fe7 Binary files /dev/null and b/packages/preview/measured-jair/0.1.0/thumbnail.png differ diff --git a/packages/preview/measured-jair/0.1.0/typst.toml b/packages/preview/measured-jair/0.1.0/typst.toml new file mode 100644 index 0000000000..baa1beec2f --- /dev/null +++ b/packages/preview/measured-jair/0.1.0/typst.toml @@ -0,0 +1,16 @@ +[package] +name = "measured-jair" +version = "0.1.0" +entrypoint = "lib.typ" +authors = ["Kirill Groshenkov "] +license = "MIT AND MIT-0" +description = "Article for the Journal of Artificial Intelligence Research (JAIR)." +repository = "https://github.com/veryviolet/jair-typst" +keywords = ["jair", "Journal of Artificial Intelligence Research", "journal", "article", "acm", "acmart", "paper"] +categories = ["paper"] +compiler = "0.13.0" + +[template] +path = "template" +entrypoint = "main.typ" +thumbnail = "thumbnail.png"