📖

Typstのテンプレートを理解する

に公開

はじめに

Typstのテンプレートについて詳しく解説されている記事がなかったので、調査した内容をここにまとめました。この記事では、Typstのテンプレートがどのように構成されているのか、それぞれがどのような意味を持つのかに焦点を当てて解説しています。

Typstの文法については公式のドキュメントを参照しています。こちらのチュートリアルに一度目を通してから、この記事を読み進めると良いと思います。

https://typst.app/docs/tutorial/writing-in-typst/

テンプレート

この記事で解説するTypstのテンプレートを以下にあげておきます。

テンプレートの全体像
format.typ
#let template(
  header-content: [],
  main: [],
  sub: [],
  student: [],
  stde: [],
  teacher: [],
  teachere: [],
  body
) = {
  let header(content: []) = {
    set align(center)
    text(
      size: 10pt,
      font: "MS Mincho",
    )[#content]
  }

  let title(main: [], sub: []) = {
    v(1cm)
    text(
      size: 20pt,
      font: "MS Gothic",
      weight: "medium",
    )[#main]
    v(0cm)
    text(
      size: 11pt,
      font: "MS Gothic",
      weight: "medium",
    )[#sub]
  }

  let author(student: [], stde: [], teacher: [], teachere: []) = {
    v(0.5cm)
    set align(center)
    text(
      size: 12pt,
      font: "MS Gothic",
    )[#student]
    h(9pt)
    if stde != [] {
      text(
        size: 11pt,
        font: "MS Gothic",
      )[(#stde)]
      h(1cm)
    } else {}
    if teacher != [] {
      text(
        size: 11pt,
        font: "MS Gothic",
      )[指導教員]
      h(0.5cm)
      text(
        size: 12pt,
        font: "MS Gothic",
      )[#teacher]
      h(9pt)
      text(
        size: 11pt,
        font: "MS Gothic",
      )[(#teachere)]
    } else {}
    v(1cm)
  }

  set page(
    paper: "a4",
    numbering: "1",
    number-align: center,
    margin: (
      top: 20mm,
      bottom: 25mm,
      left: 16mm,
      right: 16mm,
    ),
    columns: 2,
    header: header(content: header-content),
  )

  set columns(
    gutter: 8mm,
  )

  set heading(numbering: "1.1")
  show heading: set text(size: 10.5pt, weight: "semibold", font: "MS Gothic")

  set par(justify: true, spacing: 1.73em - 1em, leading: 1.73em - 1em)
  set text(size: 10pt)
  
  set cite(
    form: "prose",
  )

  show figure.where(kind: image): set figure(supplement: "Fig.")

  place(
    top + center,
    scope: "parent",
    float: true,
    {
      title(
        main: main,
        sub: sub,
      )
      author(
        student: student,
        stde: stde,
        teacher: teacher,
        teachere: teachere,
      )
    }
  )
  body
}

テンプレートを使用する場合は以下のようにインポートし、with関数を使って引数を渡します。

main.typ
#import "format.typ": template

#show: template.with(
  header-content: "ヘッダー",
  main: "タイトル",
  sub: "サブタイトル",
  student: "(名前)",
  stde: "(名前の英語表記)",
  teacher: "(教員の名前)",
  teachere: "(教員の名前の英語表記)",
)

#showshowルール と呼ばれ、見出し(heading)や図表(figure)などの要素を変換したり、カスタマイズしたりすることができます。後ほど出てくる setルール とは異なり、特定の条件の要素に対してプロパティを設定することができます。また、showルールの中でsetルールを指定した場合、そのshowルールの中でのみsetルールが適用されます。

引数

#let template(
  header-content: [],
  main: [],
  sub: [],
  student: [],
  stde: [],
  teacher: [],
  teachere: [],
  body
) = {...}

template()関数では、引数と body(ドキュメント自体のコンテンツ) を受け取り、全体の構造とスタイルを定義します。各引数にはデフォルト値として [](空のコンテンツブロック) が設定されていて、この関数を呼び出す際に使わない引数の値を指定する必要がありません(厳密には、引数の値を指定しなくてもエラーにならず、空として扱われます)。

ここからはテンプレートの中身について触れていきます。template()関数の {...} の中には headertitleauthor という3つの関数が定義され、冒頭の部分をスタイルしています。また、ドキュメント全体の設定も含まれています。

ヘッダー

let header(content: []) = {
    set align(center)
    text(
      size: 10pt,
      font: "MS Mincho",
    )[#content]
}

content: [] には引数の header-content が参照され、ヘッダーを中央揃えにしています。set(#set) は setルール と呼ばれ、要素が持っている引数のデフォルト値を設定することができます。ページ全体に適用されますが、showルールなどと併用することで特定の範囲に設定することもできます。

align() によって関数内の全てのコンテンツが中央揃えになります。text()ではヘッダーのテキストサイズを 10pt にして、フォントは、Windowsであれば MS Mincho、Macであれば Hiragino Mincho Pro にしています。文字やブロックのサイズを決める単位である ptcm などは、以下を参照してください。

https://typst.app/docs/reference/layout/length/

メインタイトルとサブタイトル

let title(main: [], sub: []) = {
    v(1cm)
    text(
      size: 20pt,
      font: "MS Gothic",
      weight: "medium",
    )[#main]
    v(0cm)
    text(
      size: 11pt,
      font: "MS Gothic",
      weight: "medium",
    )[#sub]
}

メインタイトルとサブタイトルの書式設定をしています。v(1cm) ではメインタイトルの前に 1cm の垂直方向のスペースを追加しています。メインタイトルの書式設定の下にある v(0cm) は、サブタイトルがメインタイトルの直後にデフォルトの行間が入らずに続くようにしています。書式設定の weight ではフォントの太さを指定していて、フォントは、Macであれば Hiragino Kaku Gothic Pro にしています。

垂直方向のスペース v() や水平方向のスペース h() は以下を参照してください。

https://typst.app/docs/reference/layout/

著者情報

let author(student: [], stde: [], teacher: [], teachere: []) = {
    v(0.5cm)
    set align(center)
    ...
    v(1cm)
}

学生と教員情報の書式設定をしています。著者情報を書くブロックの前に垂直方向のスペース 0.5cm を追加し、全体は中央揃えにしています。最後に 1cm の垂直方向のスペースを入れています。全体を一気に見せると長くなってしまうので、学生情報と教員情報の2つの部分に分けて説明していきます。

学生情報(student, stde)

text(
  size: 12pt,
  font: "MS Gothic",
)[#student]
h(9pt)
if stde != [] {
  text(
    size: 11pt,
    font: "MS Gothic",
  )[(#stde)]
  h(1cm)
} else {}

日本語名と英語名の間に 9pt の水平方向のスペースを追加しています。また、学生の英語名は stde が空でない場合に表示されます。英語名は () で囲まれているので、if stde != [] {...} によって空の括弧が生まれないようにしています。

教員情報(teacher, teachere)

if teacher != [] {
  text(
    size: 11pt,
    font: "MS Gothic",
  )[指導教員]
  h(0.5cm)
  text(
    size: 12pt,
    font: "MS Gothic",
  )[#teacher]
  h(9pt)
  text(
    size: 11pt,
    font: "MS Gothic",
  )[(#teachere)]
} else {}

学生の英語名のスタイリングと同様に、教員名 teacher が空の場合は、教員情報を表示しないようにしています。また、各テキストの間に水平方向のスペースを追加して全体を調整しています。

著者情報では、学生の英語名と教員名の有無を確認することで、学生の名前のみを載せたレポートも作られるようにしています。

ページ全体の設定

set page(
    paper: "a4",
    numbering: "1",
    number-align: center,
    margin: (
      top: 20mm,
      bottom: 25mm,
      left: 16mm,
      right: 16mm,
    ),
    columns: 2,
    header: header(content: header-content),
)

ページの形式や余白、ヘッダーなどの設定をしています。

  • paper: "a4" ページのサイズを A4 に設定
  • numbering: "1" ページ番号を 1 から開始
  • numbering-align: center ページ番号を中央に配置
  • margin ページの上下左右に適切な余白を追加
  • columns: 2 本文のレイアウトを2段組に設定
  • header: header(...) header関数を呼び出し、ヘッダーに引数 header-content を表示

コラム

set columns(gutter: 8mm)

2段組レイアウトの段の間隔を 8mm にしています。

見出し

set heading(numbering: "1.1")
show heading: set text(size: 10.5pt, weight: "semibold", font: "MS Gothic")

見出しの番号付けを 1.1 や 1.2 のように設定し、show heading: set text(...) ではすべての見出しに対して書式設定を適用しています。

テキスト

set par(justify: true, spacing: 1.73em - 1em, leading: 1.73em - 1em)
set text(size: 10pt)
  • par() 段落に関する設定
    • justify テキストを両端揃えにするか
    • spacing ある段落の最後の行と、その次の段落の始めの行との間の距離
    • leading 行送り(文字サイズを含まないため、実質的には行の間隔を指す)
  • text(...) 本文のデフォルトのテキストサイズを設定

行送りとは、ある行のテキストのベースラインからその次の行のベースラインまでの距離のことです。この値を 1.73em - 1em と表記しているのは、「本来は1.73倍であることを明記したいが、Typstの仕様上、フォント自身の1倍分を引かなければならない」ことを示すためです。spacingleading でこの値を同じにすることで、2段組にした際、左右で行の位置がずれません。

行送りを 1.73em にしている理由は、一般的な組版の慣習が基になっています。LaTexを用いて和文の論文を書く際は、jsarticle と呼ばれる文書クラスを使うことが多いです。このクラスのデフォルトの設定では文字サイズに対して行送りが約1.73倍になっているため、それにならってこの値を定めています。

本当に約1.73倍になるのか

行送りが文字の大きさに対して何倍であるかを求めます(単位はmmに揃えます)。

jsarticle の文字サイズの単位には Q(級) が使われます。これは 1Q = 0.25mm であり、デフォルトの文字の大きさは 13Q です。これに対して行送りは 16pt で、TeXでは 72.27pt = 1inch = 25.4mm です。

まず、行送りのミリメートル値を求めます。行送り 16pt を1インチあたりのポイント数 72.27pt で割り、行送りをインチ単位に変換します。1インチは 25.4mmなので、これを掛けてミリメートル単位に変換し、16 / 72.27 \times 25.4 = 5.6233... \text{ [mm]} となります。

次に、文字サイズのミリメートル値は文字サイズ 13Q を4で割って、13 / 4 = 3.25 \text{ [mm]} となります。

よって、5.6233... / 3.25 = 1.730... となり、文字のサイズに対して行送りが約1.73倍になっていることが示されました。

図や写真

show figure.where(kind: image): set figure(supplement: "Fig.")

図のラベル(キャプション)がデフォルトの Figure. から Fig. となります。showルールを使って、画像を含む全ての figure要素 に対して適用しています。

参照

set cite(form: "prose")

引用の種類を散文形式にします。これによって、引用を文章中に表示させることができます。ただし、これを使うには #bibliography関数を定義して、.bib ファイルなどをインポートする必要があります。

冒頭部分

place(
    top + center,
    scope: "parent",
    float: true,
    {
      title(
        main: main,
        sub: sub,
      )
      author(
        student: student,
        stde: stde,
        teacher: teacher,
        teachere: teachere,
      )
    }
)

place関数は、親要素に対して要素を相対的に配置することができます。ここでは、タイトルと著者情報を最初のページに配置しています。

  • top + center コンテンツをページ上部で水平方向に中央揃え
  • scope: "parent", float: true タイトルなどを2列のレイアウトから回避させ、1列に配置
  • titleauthor の2つの関数の呼び出し

このテンプレートの一番最後では body を記述しています。これには、段落や図表などの実際のコンテンツが含まれ、#show でこのテンプレートを呼び出した際、引数の後に記述したものが body に当たります。

おわりに

今回は、Typstのテンプレートの構造について調べてみました。十分理解していないものをよく分からずに使いたくないというモチベーションだけでこの記事を書きましたが、Typstのドキュメントを読むいい機会になりました。

もっとしっかりとした日本語の論文を書きたい際には、木村駿介様が作成したテンプレートを参考にすると良いです。

https://github.com/kimushun1101/typst-jp-conf-template

Discussion