> ## Documentation Index
> Fetch the complete documentation index at: https://chart-spec.enchor.us/llms.txt
> Use this file to discover all available pages before exploring further.

# Syntax

> The structure of a song.ini file: its section, its lines, the order of its keys, and the forms of its values.

`song.ini` is a text file of `key = value` lines in one `[song]` section:

```ini theme={null}
[song]
name = Song Name
artist = Artist
album = Album
genre = Rock
year = 2002
charter = Charter
song_length = 215000
diff_band = 4
diff_guitar = 4
diff_drums = 3
preview_start_time = 45500
preview_end_time = 75500
album_track = 3
```

[Metadata](/ini/metadata) and [Settings](/ini/settings) list the keys. A [.sng file](/sng) holds the same keys in its own metadata, with stricter rules.

## Encoding

A scanner decodes `song.ini` as it decodes a `.chart` file: see [Encoding](/chart/syntax#encoding). **Recommended:** UTF-8.

## The \[song] section

* **Required:** one `[song]` section, on the file's first line. Every key is inside it.
* **Required:** `[song]` alone on its line, with no spaces inside the brackets.
* A scanner matches the section's name in any letter case, as written between the brackets. **Recommended:** `[song]`, in lowercase.

## Lines

**Required:** each line after `[song]` a key line, a comment, or a blank line.

* A line ends at a line feed, or at a carriage return followed by a line feed. A carriage return alone doesn't end a line. **Recommended:** a carriage return and a line feed.
* A scanner ignores blank lines, and white space at the start and the end of each line.
* White space is a space, a tab, or another character that .NET counts as white space, such as a no-break space (U+00A0). A byte order mark (U+FEFF) isn't white space.

### Comments

```ini theme={null}
; Charted for the Example Pack
```

A comment is a line whose first character, after any spaces, is `;`. It takes the whole line. A scanner ignores it.

**Required:** a comment on a line of its own.

### Key lines

```text theme={null}
<key> = <value>
```

* **The key** is the text before the first `=`. A scanner matches keys in any letter case. **Recommended:** in lowercase, as these pages write them. **Required:** a key without spaces, and a value that doesn't start with `=`.
* **The value** is the text after the `=`, without the white space at its start and end.
* **Required:** no quotation marks around a value.
* **Required:** no white space other than spaces and tabs at either end of a value.
* **Recommended:** one space on each side of the `=`.
* **Required:** each key once in a file.
* **Required:** keys and section names of at most 1,024 characters.

### Key order

**Recommended:** the keys a song needs, in this order:

`name`, `artist`, `album`, `genre`, `year`, `charter`, `song_length`, `diff_band`, `diff_guitar`, `diff_guitar_coop`, `diff_rhythm`, `diff_bass`, `diff_drums`, `diff_drums_real`, `diff_keys`, `diff_keys_ghl`, `diff_guitarghl`, `diff_guitar_coop_ghl`, `diff_rhythm_ghl`, `diff_bassghl`, `diff_vocals`, `preview_start_time`, `preview_end_time`, `icon`, `loading_phrase`, `album_track`, `playlist_track`, `playlist`, `sub_playlist`, `modchart`, `explicit_lyrics`, `sustain_cutoff_threshold`, `chord_snap_threshold`, `video_start_time`, `five_lane_drums`, `pro_drums`

* The keys only YARG reads go after `explicit_lyrics`, in the order of [Read by YARG only](/ini/metadata#read-by-yarg-only).
* A [deprecated](/ini/settings#deprecated) key that an older chart still holds goes after them, before `sustain_cutoff_threshold`, in the order `delay`, `hopo_frequency`, `eighthnote_hopo`, `multiplier_note`.
* Other keys, such as `ignored_issues`, come last.
* The order doesn't change how a scanner reads the file. It keeps files alike, so that each key is in the same place in every file.
* scan-chart writes keys in this order. It reports keys out of order as `iniTagOrder`, with its `styleNotes` option, and `fixIssues` puts them in order.

## Values

Each key takes one type of value:

| Type | Form | Example |
| - | - | - |
| Text | Any text on one line | `name = Song Name` |
| Whole number | Digits, with an optional `-` before them, from -2147483648 to 2147483647 | `preview_start_time = 45500` |
| Boolean | `True` or `False`. **Recommended** | `modchart = True` |

* No key takes a decimal number.
* Times are in milliseconds.
* A scanner also reads `true` and `false` in any other letter case, and `1` and `0`, as booleans. They mean the same as `True` and `False`.
* **Required:** each value in the form of its key's type.

### Values that mean not set

A key that isn't in the file isn't set, and a scanner uses its default. [Metadata](/ini/metadata) and [Settings](/ini/settings) give each key's default. **Required:** a value in every key line, and no `-1` in a number key. To leave a value unset, leave its key out.

In a text key, `0` and `-1` are text: `charter = 0` shows the charter as "0".

## Ignored

* **Sections other than `[song]`.** An exporter may keep them. scan-chart reports one as `iniLayout`, and `fixIssues` keeps its lines as `;` comments.
* **Keys a scanner doesn't read.** An exporter should keep them as written. [Metadata](/ini/metadata#ignored) lists the keys of older games.

## Invalid forms

<Accordion title="Lines before [song]">
  Clone Hero, YARG and scan-chart ignore them, and read the `[song]` section after them. scan-chart reports any line that isn't blank before `[song]` as `iniLayout`, comments included, and `fixIssues` writes `[song]` on the first line, with the earlier lines kept as comments after it.
</Accordion>

<Accordion title="No [song] section">
  A scanner reads the folder as if it had no `song.ini`: see [Files in a song folder](/song-folders#invalid-forms). A `[song]` section with no key lines counts as none. scan-chart reports it as `invalidMetadata`.
</Accordion>

<Accordion title="Two [song] sections">
  Clone Hero and scan-chart read them as one section, and the last line of each key counts. YARG reads only the last section. A scanner reads them as Clone Hero does. scan-chart reports the second section as `iniLayout`, and when its `fixIssues` lays out or orders the file, it merges them into one section.
</Accordion>

<Accordion title="A section header with spaces or a comment, such as [ song ]">
  No scanner reads `[ song ]` or `[song] ; comment` as `[song]`, so the key lines after it aren't in a `[song]` section.
</Accordion>

<Accordion title="A comment that starts with #">
  Clone Hero and scan-chart skip it as a comment. YARG reads it as a key that starts with `#`, which it doesn't know, so it has no effect. A scanner ignores the line. scan-chart's `fixIssues` rewrites it as a `;` comment.
</Accordion>

<Accordion title="A line that starts with //">
  No scanner reads it as a comment. A scanner ignores it: Clone Hero skips it when it has no `=`, and reads it as a key that no scanner knows when it has one. scan-chart reports a `//` line without `=` as `badIniLine`, and `fixIssues` rewrites any `//` line as a `;` comment.
</Accordion>

<Accordion title="A comment after a value, such as preview_start_time = 45500 ; ms">
  No scanner reads it as a comment: it's part of the value. A text value shows it, and a number followed by a comment is a number in another form, below.
</Accordion>

<Accordion title="A line without =">
  Clone Hero ignores it. YARG reads the first word as the key, so `name Song` is `name = Song`. A scanner ignores the line. scan-chart reports it as `badIniLine`.
</Accordion>

<Accordion title="A space inside a key, or a value that starts with =">
  Clone Hero reads `diff guitar = 3` as a key named `diff guitar`, which no scanner knows, and `name = = Song` as the value `= Song`. YARG reads them as the key `diff` with the value `guitar = 3`, and as the value `Song`. A scanner reads them as Clone Hero does.
</Accordion>

<Accordion title="A key or section name longer than 1,024 characters">
  Clone Hero can't read the file, so it reads the folder as if it had no `song.ini`: see [Files in a song folder](/song-folders#invalid-forms). YARG and scan-chart read the line as a key or section they don't know. A scanner reads it as YARG and scan-chart do.
</Accordion>

<Accordion title="A value that starts or ends with other white space, such as a no-break space">
  A scanner removes every kind of white space from both ends of a value, as Clone Hero, YARG and scan-chart do. scan-chart doesn't write a value that starts or ends with white space.
</Accordion>

<Accordion title="Quotation marks around a value">
  Unlike in a `.chart` file, a scanner keeps them as part of the value, so a text value shows them. A scanner reads a number or boolean in quotation marks as not set, as Clone Hero and scan-chart do, and YARG reads 0. scan-chart reports quotation marks as `quotedIniValue`, and a quoted difficulty, such as `diff_guitar = "4"`, also as `missingValue`. `fixIssues` removes the quotation marks around text, and leaves a quoted number or boolean for the charter to write as meant.
</Accordion>

<Accordion title="A key written more than once">
  A scanner uses the last line. scan-chart reports it as `duplicateIniKey`, and saving an edited song removes the earlier lines.
</Accordion>

<Accordion title="A number in another form, such as 1.5 or 12abc">
  Clone Hero reads a number as .NET does: an optional sign, then digits, within the 32-bit range, with spaces allowed around them. It uses the key's default for anything else. YARG reads a number's leading digits, so `12abc` is 12 and `1.5` is 1, and reads 0 when there are none. A scanner reads it as Clone Hero does. Clone Hero reads a `delay` with a decimal point as seconds instead: see [Settings](/ini/settings#invalid-forms).

  scan-chart reads the leading number of most keys, so `12abc` is 12, and rounds `1.5` to 2 and reports it as `invalidValue`. It reads `hopo_frequency`, `multiplier_note`, `sustain_cutoff_threshold` and `chord_snap_threshold` as Clone Hero does, and reports anything else as `invalidValue`.
</Accordion>

<Accordion title="A boolean in another form, such as yes or 2">
  Clone Hero and scan-chart read any whole number other than 0 as true, and anything else that isn't `true` or `false` as not set. YARG reads a value that starts with `1` or `true` as true, and anything else as false: `2` is false, and `10` is true. A scanner reads it as Clone Hero does.
</Accordion>

<Accordion title="A blank value">
  Clone Hero reads a blank number or boolean as not set, and blank text as empty. scan-chart reads every blank value as not set. Clone Hero doesn't list a song whose `name` is blank.

  YARG reads a blank number as 0 and a blank boolean as false, and counts the key as set: a blank `preview_start_time` starts the preview at 0:00, a blank `album_track` sorts the song first, a blank difficulty shows 0 instead of no rating, and a blank `sustain_cutoff_threshold` turns off the cutoff of a `.mid` file.

  A scanner reads a blank value as not set, as if the key weren't in the file. A blank `charter` or `album_track` still counts as written, so a scanner doesn't read `frets` or `track` instead: see [Metadata](/ini/metadata#invalid-forms). scan-chart reports a blank number as `blankIniNumber`, and blank text as `blankIniValue` with its `styleNotes` option. `fixIssues` removes the line.
</Accordion>

<Accordion title="-1 in a number key, such as diff_keys = -1">
  Clone Hero, YARG and scan-chart read `-1` in a difficulty, `preview_start_time` or `preview_end_time` as not set. In other number keys, Clone Hero and YARG read it as the number -1: `album_track = -1` sorts the song first, and `delay = -1` moves every note 1 millisecond earlier. scan-chart reads `-1` as not set in every number key.

  A scanner reads `-1` in a number key as not set, as if the key weren't in the file. An `album_track` of `-1` still counts as written, so a scanner doesn't read `track` instead.

  When Clone Hero creates a `song.ini` for a folder without one, it writes `-1` for each difficulty without a rating. Tens of thousands of song folders hold these values. scan-chart reports `-1` as `blankIniValue` with its `styleNotes` option, and `fixIssues` removes the line.
</Accordion>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.