{"id":14868571,"url":"https://github.com/technix/atrament-web-ui","last_synced_at":"2026-02-02T10:30:36.222Z","repository":{"id":65688866,"uuid":"140434410","full_name":"technix/atrament-web-ui","owner":"technix","description":"Atrament UI, an engine for creating feature-rich text games or choice-based interactive fiction for both web and desktop","archived":false,"fork":false,"pushed_at":"2026-01-30T17:20:33.000Z","size":95776,"stargazers_count":25,"open_issues_count":1,"forks_count":4,"subscribers_count":5,"default_branch":"master","last_synced_at":"2026-01-31T01:42:11.152Z","etag":null,"topics":["choice-based-game","game-development","ink","interactive-fiction","javascript"],"latest_commit_sha":null,"homepage":"https://atrament.ink","language":"JavaScript","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/technix.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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":"2018-07-10T13:13:35.000Z","updated_at":"2026-01-30T17:20:37.000Z","dependencies_parsed_at":"2023-10-04T15:15:12.060Z","dependency_job_id":"800e5ea4-f922-4798-8476-fab96c37ff91","html_url":"https://github.com/technix/atrament-web-ui","commit_stats":null,"previous_names":["technix/atrament-preact-ui","technix/atrament-web-ui"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/technix/atrament-web-ui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/technix%2Fatrament-web-ui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/technix%2Fatrament-web-ui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/technix%2Fatrament-web-ui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/technix%2Fatrament-web-ui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/technix","download_url":"https://codeload.github.com/technix/atrament-web-ui/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/technix%2Fatrament-web-ui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29010223,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-02T08:40:12.472Z","status":"ssl_error","status_checked_at":"2026-02-02T08:40:10.926Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["choice-based-game","game-development","ink","interactive-fiction","javascript"],"created_at":"2024-09-20T06:01:19.142Z","updated_at":"2026-02-02T10:30:36.215Z","avatar_url":"https://github.com/technix.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Atrament\n\n\u003cimg src=\"https://atrament.ink/img/atrament-logo.svg\" width=\"200px\"\u003e\n\nAtrament is a modular tool to create text games or interactive fiction stories for the web and desktop.\n\nIt uses [inkjs](https://github.com/y-lohse/inkjs) to interpret Ink scripts, [@atrament/core](https://github.com/technix/atrament-core) as a game engine, and [Preact](https://preactjs.com/) as a Web UI framework.\n\n[Documentation](https://atrament.ink) | [Live Demo](https://technix.github.io/atrament-web-ui/)\n\n## Getting started\n\nBefore proceeding, install [Node.js](https://nodejs.org/) for your platform, version 22.12+ or higher.\n\n### Create a new Atrament project\n\nThe easiest way to create a new Atrament project is to use `atrament-wizard` tool:\n\n```\nnpx atrament-wizard create\n```\n\nBy default, Atrament comes with a minimal Ink story template. If you want to see a demonstration of various Atrament features, copy content of `examples/showcase` into `root/game` folder after creating a project.\n\n#### Expert mode\n\nIf you're an experienced JS developer or want to use development version of Atrament Web UI, you can do all the steps manually:\n\n```\ngit clone https://github.com/technix/atrament-web-ui.git --depth 1\ncd atrament-web-ui\nnpm install\nnpm run install-inklecate\n```\n\nAfter performing these steps, you can customize the game configuration:\n\n1. Remove all files from `root/game` and put your game files there (ink script, images, music etc).\n2. Edit `atrament.config.json`, change the `source` parameter in `game` section to name of your main Ink file. File path for this file is relative to `root/game` folder.\n3. You may change other configuration options in `atrament.config.json`:\n    * \"`name`\": your application name\n    * \"`short_name`\": your application short name, or codename\n    * \"`description`\": your application description\n    * \"`theme`\": default app theme, may be \"`light`\", \"`sepia`\", or \"`dark`\"\n    * \"`font`\": default UI and game font, may be \"`System`\", \"`Sans Serif`\", \"`Serif`\", \"`Monospaced`\", \"`Fira Sans`\", \"`Lora`\", \"`Merriweather`\", or \"`OpenDyslexic`\"\n4. (optionally) replace `root/logo.png` with your project logo. This image is used to generate favicon and application icon.\n\n\n### Run application locally in dev mode\n```\nnpm start\n```\n\nThe application is available at http://localhost:8900. If any source file (Ink or Javascript) is edited, the application automatically restarts with these changes.\n\n### Build application for publishing\nAtrament game can be published as a web application, as a single HTML file, or as a desktop application. See [Publishing](#publishing) section of this document for more details.\n\n## Ink tags handled by Atrament Web UI\n\n### Global tags\n\n| Tag | Description                |\n| :-------- | :------------------------- |\n| `# title: A Story Written In Ink` | Game title |\n| `# author: John Doe` | Author |\n| `# cover: some/image.jpg` | Cover image to display at the main menu screen. You can change its dimensions by adding width value after the image path: `# cover: some/image.jpg 30%` |\n| `# title_screen_layout: cover, title, author` | Order of the components on the title screen. You can remove items from this list or rearrange them. |\n| `# theme: light` | Game color theme: `light`, `sepia`, or `dark` |\n| `# font: System` | Game font: `System`, `Sans Serif`, `Serif`, `Monospaced`, `Fira Sans`, `Lora`, `Merriweather`, or `OpenDyslexic` |\n| `# observe: varName` | Register variable observer for `varName` Ink variable. Variable value is available in `vars` section of the Atrament state. |\n| `# persist: varName` | Save `varName` Ink variable value to the persistent storage, restore before game starts. |\n| `# sessions: 3` | Amount of game sessions. Each session has its own set of saves. |\n| `# autosave: false` | Disables autosaves. |\n| `# saves: 5` | Amount of available slots for saves. |\n| `# load_from_checkpoints` | Show checkpoints in the list of games to load. |\n| `# continue_maximally: false` | Pause the story after each line. |\n| `# single_scene` | Store only the last scene in the Atrament state. |\n| `# scenes_align: center` | Scene alignment on the screen. Can be set to `top`, `center`, or `bottom`. |\n| `# choices: grouped numbered` | Changes the choices appearance. Can be set to any combination of: `grouped` (displayed as button group); `numbered` (displays numbers of choices); `left` or `right` (aligns choice text to the left or right); `row` (show choices in a single row instead of a column); `borderless` (show choice buttons without borders) |\n| `# hypertext` | Use links instead of choices. See \"[Hypertext mode](#hypertext-mode)\". |\n| `# toolbar: toolbar_function` | Use output of this function as a toolbar content. |\n| `# about: about_function` | Use output of this function as an \"About\" screen content. |\n| `# background: some/picture.jpg` | Set background image for the game backdrop. |\n| `# allow_external_function_fallbacks` | If the function defined with EXTERNAL is not found, run Ink function with the same name instead. |\n| `# debug` | Enable Ink story debugger. |\n\n### Knot tags\n| Tag | Description                |\n| :-------- | :------------------------- |\n| `# IMAGE: some/picture.jpg` | Show image before paragraph text. |\n| `# BACKGROUND: some/picture.jpg` | Set background image for the game text. Use `# BACKGROUND: false` to unset it. |\n| `# PAGE_BACKGROUND: some/picture.jpg` | Set background image for the game backdrop. Use `# PAGE_BACKGROUND: false` to unset it. |\n| `# CLEAR` | Clear scenes list before saving current scene to Atrament state. |\n| `# AUDIO: sound.mp3` | Play sound (once). |\n| `# AUDIOLOOP: music.mp3` | Play background music (looped). There can be only one background music track. |\n| `# AUDIOLOOP: false` | Stop playing music. |\n| `# PLAY_SOUND: sound.mp3` | Play sound (once). |\n| `# STOP_SOUND: sound.mp3` | Stop playing specific sound. |\n| `# STOP_SOUND` | Stop playing all sounds. |\n| `# PLAY_MUSIC: music.mp3` | Play background music (looped). There can be multiple background music tracks, played simultaneously. |\n| `# STOP_MUSIC: music.mp3` | Stop playing specific background music. |\n| `# STOP_MUSIC` | Stop playing all background music. |\n| `# CHECKPOINT` | Save game to the 'default' checkpoint. |\n| `# CHECKPOINT: checkpointName` | Save game to checkpoint `checkpointName`. |\n| `# SAVEGAME: saveslot` | Save game to `saveslot`. |\n| `# RESTART` | Start game from beginning. |\n| `# RESTART_FROM_CHECKPOINT` | Restart game from latest checkpoint. |\n| `# RESTART_FROM_CHECKPOINT: checkpointName` | Restart game from named checkpoint. |\n| `# CLASS: classname` | Apply CSS class to the paragraph `\u003cdiv\u003e` element. |\n| `# SHUFFLE_CHOICES` | Shuffle choice order in this knot. |\n| `# PROMPT: What would you like to do?` | Display prompt text before the choices. |\n| `# HYPERTEXT` | Use links instead of choices for this scene. See \"[Hypertext mode](#hypertext-mode)\". |\n| `# CHOICES: grouped numbered` | Changes the choices appearance for this scene only. Uses the same syntax as global `#choices` tag. |\n| `# AUTO_CHOICE` | Make a choice automatically. See \"[Automatic choice](#automatic-choice)\". |\n\n\nNote: For sound effects, please use either AUDIO/AUDIOLOOP or PLAY_SOUND/PLAY_MUSIC/STOP_SOUND/STOP_MUSIC tags. Combining them may lead to unexpected side effects.\n\n### Choice tags\n| Tag | Description                |\n| :-------- | :------------------------- |\n| `# UNCLICKABLE` | The choice can't be selected. Alternative names: `#DISABLED`, `#INACTIVE` |\n| `# HIDDEN` | The choice is not shown to the player, but can be selected with links or buttons. |\n| `# CLASS: classname` | Apply CSS class to the choice `\u003cbutton\u003e` element. |\n\n## Features\n\n### Save management\n\nAtrament Web UI supports the following save types:\n\n1. **Autosave**. By default, game saves its progress after each choice. If autosave is present for the game, player can continue playing by clicking \"Continue\" in the main menu. When global tag `autosave: false` is present, autosaving is disabled. If autosaving is disabled and there are no saved checkpoints, \"Continue\" button will not be available.\n2. **Checkpoints**. They are controlled by knot tags `#CHECKPOINT` and `#RESTART_FROM_CHECKPOINT`. Authors can use named checkpoints, adding names to these tags. If there is no autosave, players can continue playing from latest saved checkpoint by clicking \"Continue\" in the main menu.\n3. **Saves**. They are disabled by default. Authors can set global tag `#saves` to define amount of available save slots. Players can save and load games using the slots provided. If global tag `#load_from_checkpoints` is set, players can also load game from any saved checkpoint.\n\nIn addition to above, Atrament Web UI supports **sessions**, which can be enabled by global tag `#sessions`. If they are enabled, players have to choose game session before starting a game. Each session has its own autosaves, checkpoints, and saves.\n\n### \"Click to continue\"\n\nA single choice with text '\u003e\u003e\u003e' is treated as \"click to continue\". Choice list is not shown, and player can continue story by clicking the screen or pressing \"Space\" or \"Enter\" key. After 3 seconds of inactivity, animated hint is displayed in the bottom of the screen.\n\n```\nThis story will proceed when user clicks screen.\n+ [\u003e\u003e\u003e] -\u003e next_knot\n```\n\nYou can also provide a delay in **seconds** for the \"click to continue\". A timed choice is presented as a slightly different circular button. After the delay, story continues automatically.\n```\nThis story will proceed either after user clicks screen or after 3 seconds.\n+ [\u003e\u003e\u003e3] -\u003e next_knot\n```\n\nClick-to-continue choice can be configured:\n* `clickable` - pause before the choice becomes clickable and player can continue the story. If omitted, player can click and continue story immediately.\n* `animation` - pause before displaying animation. If omitted, the animation displays immediately.\n* `continue` - pause before story continues automatically. If omitted, the game continues only after click or keypress.\n\nAll pauses are set in seconds.\n```\n+ [\u003e\u003e\u003e(clickable=3 animation=5 continue=10)] -\u003e next_knot\n```\n\n### Automatic choice\n\nYou can make specific or random choice automatically with `#AUTO_CHOICE` knot tag:\n\n```# AUTO_CHOICE: delay=10 choice=\"Some choice\"```\n\nOptions of the tag:\n* `delay` - sets a delay before automatic choice and displays a choice timer bar. If omitted, a choice is selected immediately.\n* `choice` - text of the choice to be auto-selected. If omitted, a choice option will be selected randomly.\n\n### Hypertext mode\n\nIf global tag `hypertext` is set, Atrament UI switches to hypertext mode. In this mode choice options are not displayed. However, author can use `[link=target choice text]link text[/link]` to link specific phrases to the choices.\n\nFor better user experience in hypertext mode authors can set global tags `single_scene` and `scenes_align: top`.\n\nAuthor can enable hypertext for a chosen scene with `HYPERTEXT` scene tag.\n\n```\n# hypertext\n# single_scene\n# scenes_align: top\n\nYou are standing in an open field west of a white house, \nwith a boarded [link=Open door]front door[/link]. \nThere is a [link=Examine mailbox]small mailbox[/link] here.\n\n+ [Examine mailbox] -\u003e examine_mailbox\n+ [Open door] -\u003e inside_house\n```\n\n### Custom markup\n| Markup | Description                |\n| :-------- | :------------------------- |\n| `[picture]path/to/image.jpg[/picture]` | Display image (same as `#IMAGE` knot tag). The image is sized automatically to fit the container. When using images inside of the `[block]` tags, you may want to set picture margins.\u003cbr\u003eAttributes:\u003cbr\u003e`width=50%` sets picture width.\u003cbr\u003e`leftmargin=0.5em` sets left margin. \u003cbr\u003e`rightmargin=0.5em` sets right margin.|\n| `[img]path/to/image.jpg[/img]` | Display inline image. |\n| `[button=function]Text[/button]`\u003cbr\u003e`[button onclick=function]Text[/button]` | Display button, call a function when clicked. If function outputs a text, it will be displayed as a new overlay content. If not, current overlay content will be updated.\u003cbr\u003eAttributes:\u003cbr\u003e`onclick=function` function to be called when clicked.\u003cbr\u003e`disabled=true` disables the button\u003cbr\u003e`bordered=false` hide button borders\u003cbr\u003e`display=modal` display modal instead of overlay when clicked |\n| `[link=choice text]Text[/link]` \u003cbr\u003e `[link to=choice text]Text[/link]` \u003cbr\u003e `[link onclick=inkFunction]Text[/link]`| Creates a link. When clicked, the target choice is activated, and game continues. If `onclick` attribute is set, the link behaves like a button and runs corresponding Ink function. Attribute `display=modal` can be added to display a modal overlay instead of fullscreen.|\n| `[progress value={variable}]Inner text[/progress]` | Displays a progress bar.\u003cbr\u003eAttributes:\u003cbr\u003e`value=x` current progressbar value\u003cbr\u003e`min=x` minimal progressbar value\u003cbr\u003e`max=x` maximal progressbar value\u003cbr\u003e`style=accent` highlight progressbar with accent theme color |\n| `[input var=variable]` | Input element, sets value of given variable. Default value of this field is read from the same variable. Disabled on the inactive scenes. \u003cbr\u003eAttributes:\u003cbr\u003e`var=n` variable name to change\u003cbr\u003e`type=number` input type. Possible values: `text`, `number`.\u003cbr\u003e`placeholder=text` placeholder text |\n| `[spoiler]text[/spoiler]` | Hidden text. Text visibility toggles on click. |\n| `[info]text[/info]` | Display text as an information block. Since this is a block element, it is recommended to use it on a whole paragraph.\u003cbr\u003eAttributes:\u003cbr\u003e`align=left` text alignment: `left`, `right`, or `center`\u003cbr\u003e`font=system` use system font\u003cbr\u003e`side=n` add color to the left infobox side. Possible values: `highlight`, `accent`. |\n| `[banner]text[/banner]` | Display text as an banner block. Since this is a block element, it is recommended to use it on a whole paragraph.\u003cbr\u003eAttributes:\u003cbr\u003e`style=accent` use accent color\u003cbr\u003e`allcaps=true` display text in all capitals |\n| `[css]text[/css]` | Applies CSS classed and/or styles to the text.\u003cbr\u003eAttributes:\u003cbr\u003e`class=CSS_class` applies CSS class to the text.\u003cbr\u003e`style=\"CSS style string\"` applies CSS style to the text. |\n| `[font=Courier New]text[/font]` \u003cbr\u003e `[font family=Courier New]text[/font]` | Applies font to the text. |\n| `[highlight]text[/highlight]`\u003cbr\u003e`[highlight color=yellow bgcolor=black]Text[/highlight]` | Highlights text with accent color.\u003cbr\u003eOptional parameters `bgcolor` and `color` allow to set both background and foreground color for text. |\n| `[block]text[/block]` | Defines a text block.\u003cbr\u003eAttributes:\u003cbr\u003e`width=value` block width. Can be defined in percents (recommended) or other CSS units.\u003cbr\u003e`align=left` aligns text horizontally in the block. Possible values: `left`, `center`, `right`\u003cbr\u003e`valign=top` aligns text vertically in the block. Possible values: `top`, `middle`, `bottom` |\n| `[video]path/to/video.mp4[/video]` | Display video. \u003cbr\u003eAttributes:\u003cbr\u003e`loop=false` disable video loop.\u003cbr\u003e`muted=true` play video muted|\n| `[url=https:\\/\\/atrament.ink]link text[/url]`\u003cbr\u003e`[url href=https:\\/\\/atrament.ink]link text[/url]` | Creates a link to an web resource. When clicked, the resource is opened in a new browser tab. *Note: you have to escape \"/\" symbols in the URL, as shown in the example.* |\n| `[---]` | Line separator. \u003cbr\u003eAttributes:\u003cbr\u003e`width=30%` set separator width. |\n\nAll markup tags support `class` attribute to set a CSS class for the element.\n\nNote: it is not possible to wrap multiple paragraphs with these tags. Use `\u003cbr\u003e` tag for line breaks if you need multiline text in tags.\n\n#### Tables\n\nYou can make tables with the following markup:\n```\n[table]\u003c\u003e\n  [header]Header 1[ ]Header 2[ ]Header 3[/header]\u003c\u003e\n\t[row]Cell 1[ ]Cell 2[ ]Cell 3[/row]\u003c\u003e\n\t[row]Cell 4[ ]Cell 5[ ]Cell 6[/row]\u003c\u003e\n[/table]\n```\nPlease note `\u003c\u003e` operator at the end of each table line - this is required to render the table properly.\n\nThe table consists of header `[header][/header]` (optional) and rows `[row][/row]`. The `[ ]` is a cell separator.\n\nAttributes of the `[table]` tag:\n* `border=false` disables table borders.\n* `padding=false` disables table cell paddings.\n* `columns=\"20% 20% 60%\"` sets column width. You have to set width for each column in the table.\n* `fixed=true` forces text wrapping, so columns always have fixed width.\n\n#### Layered images\n\nTo create a multi-layer image, use `[layers]` markup tag:\n```\n[layers]\u003c\u003e\n[picture]southern_fjord.png[/picture]\u003c\u003e\n[picture x=369 y=2669]quill-ink.png[/picture]\u003c\u003e\n[picture x=2261 y=2531]fountain-pen.png[/picture]\u003c\u003e\n[/layers]\n```\n\nFirst `[picture]` tag inside of the `[layers]` is background. Background dimensions are determined automatically to fit the screen.\n\nThe `x` and `y` attributes of other `[picture]` tags determine image coordinates relatively to the top left corner of the background image. These attribute values are set in **pixels**. If omitted, the layer is aligned to the top left corner.\n\nAttributes of the `[layers]` tag:\n* `width=50%` sets layered picture width.\n* `leftmargin=0.5em` sets left margin.\n* `rightmargin=0.5em` sets right margin.\n\nAttributes of the `[picture]` tag inside of a `[layers]` tag:\n* `x=10` set X coordinate relative to top left corner of the background\n* `y=22` set Y coordinate relative to top left corner of the background\n* `to=\"Choice text\"` clicking on this layer links to the choice with this text\n* `onclick=inkFunction` clicking on this layer calls this Ink function\n* `display=modal` when Ink function is called, the result will be displayed in the modal window\n\nYou can have clickable areas on the image with `[area]` markup tag. Attributes are similar to `[picture]` tag, but you have to define width and height of the clickable area explicitly. You can use either \"x, y, width, height\" or \"x,y,x1,y1\" attributes to set the area dimensions.\n\n```\n[layers]\u003c\u003e\n[picture]southern_fjord.png[/picture]\u003c\u003e\n[area x=369 y=2669 width=512 height=512 onclick=inkFunction]\u003c\u003e\n[area x=2261 y=2531 with=300 height=100 onclick=otherInkFunction display=modal]\u003c\u003e\n[area x=123 y=987 width=110 height=222 to=\"Choice Text\"]\u003c\u003e\n[area x=123 y=987 x1=223 y1=1200 to=\"Choice Text 2\"]\u003c\u003e\n[/layers]\n```\n\nAttributes of the `[area]` tag:\n* `x=10` set X coordinate of the top left corner of the area relative to top left corner of the background\n* `y=22` set Y coordinate of the top left corner of the area relative to top left corner of the background\n* `width=10` set width of the area\n* `height=22` set height of the area\n* `x1=20` set X coordinate of the bottom right corner of the area \n* `y1=32` set Y coordinate of the bottom right corner of the area\n* `to=\"Choice text\"` clicking on this layer links to the choice with this text\n* `onclick=inkFunction` clicking on this layer calls this Ink function\n* `display=modal` when Ink function is called, the result will be displayed in the modal window\n\n### Overlay\n\nAtrament UI can display custom data (inventory, character stats etc.) as an overlay. \n\nTo display an overlay, authors need to define a button with the `[button]` tag, which calls an Ink function. If the function returns text content, it will be displayed as an overlay. The overlay content can have buttons too.\n\nIf the first line of the function is a `[title]Overlay Title[/title]` tag, this title will be displayed in the toolbar.\n\nExample of the toolbar and overlays:\n```\n# toolbar: game_toolbar\n\n...\n\n=== function game_toolbar()\n  [button=inventory]Inventory[/button]\n  [button=stats]Stats[/button]\n\n=== function inventory()\n  [title]Inventory[/title]\n  You are carrying:\n  ...\n\n=== function stats()\n  [title]Character: {character_name}[/title]\n  Health: {health}\n  ...\n\n```\n\n### \"About\" screen\n\nAuthor can add an \"About\" screen to the game with the `#about` global tag. When it is set, UI shows \"About\" button on the main game page. Clicking it will display content from the function in the Ink file - see example:\n```\n# about: game_about\n\n...\n\n=== function game_about()\n  \u003ch1\u003eGame Title\u003c/h1\u003e\n  \"About\" screen content\n  ...\n\n```\n\n### HTML templates\n\nAtrament can render custom HTML templates with variable substitution. It uses [mustache](https://mustache.github.io/mustache.5.html) as a template parser.\n\n1. Create a template in the `resources/templates` folder. It should be an `.html` file - for example, `card.html`.\n```\n\u003cdiv class=\"card\"\u003e\n    \u003c!-- Variables are passed like this --\u003e\n    \u003cdiv class=\"card-title\"\u003e{{title}}\u003c/div\u003e\n    \u003c!--\n        Add attribute data-mount=\"content\" to an element\n        where the [template] tag content will be placed\n    --\u003e\n    \u003cdiv class=\"card-content\" data-mount=\"content\"\u003e\u003c/div\u003e\n\u003c/div\u003e\n```\n\n2. Add the template to your Ink script with `[template]` markup tag:\n\n```\nVAR CARD_TITLE=\"Card Title\"\n[template src=card.html var:title=\"{CARD_TITLE}\"]\u003c\u003e\nYour content is [highlight]here[/highlight]\u003c\u003e\n[/template]\n```\n\nVariables are passed via `var:X` attributes. For example, `var:title=\"Header\"` will be passed as template variable `title`. If you need to pass a game asset path (image, sound, video) into the template, prepend it with `GAME_ASSET:` prefix: `var:cardImage=\"GAME_ASSET:yourimage.jpg\"`\n\nTips:\n\n- templates can be without content: `[template src=card.html][/template]`\n- templates are wrapped into a `\u003cdiv\u003e` element. You can add custom class to the wrapper with `class` attribute of the `[template]` tag.\n- if you need an inline template, you can change wrapper to a `\u003cspan\u003e`: `[template src=x.html wrapper=span][/template]`.\n- templates can be nested: `[template src=card.html][template src=title.html var:title=\"Card Title\"][/template][/template]`\n\n\n## Customization\n\n### Themes\nTo add a theme to the application, create a JSON file in the `resources/themes` folder with the following structure:\n```\n{\n  \"name\": \"custom\",\n  \"theme\": {\n    \"bg-color\": \"#FCFCFC\",\n    \"fg-color\": \"#5D576B\",\n    \"shade-color\": \"rgba(0, 0, 0, 0.1)\",\n    \"font-color\": \"#333333\",\n    \"accent-bg-color\": \"#FCFCFC\",\n    \"accent-fg-color\": \"#F7567C\",\n    \"accent-inverse-color\": \"#FCFCFC\",\n    \"border-radius\": \"0.5rem\",\n    \"border-radius-inline\": \"0.25rem\"\n  }\n}\n```\n| Theme parameter | Description                |\n| :-------- | :------------------------- |\n| name | Theme display name. |\n| bg-color | App background color. |\n| fg-color | Primary color for controls. |\n| shade-color | Shadows and highlights. |\n| font-color | App and game text color. |\n| accent-bg-color | Background for accented elements. |\n| accent-fg-color | Foreground for accented elements. |\n| accent-inverse-color | Foreground for active accented elements (accent-fg-color is used as a background then). |\n| border-radius | Round the corners of choices, modals, and boxes. |\n| border-radius-inline | Round the corners of inline buttons. |\n\n*Note: You can use any valid CSS values for the theme.*\n\n### Fonts\nTo add a font to the application, create a folder in the `resources/fonts` folder with the following files:\n* `index.js` with the following content:\n```\nimport('./index.css');\nexport default {\n  name: 'Font Name',\n  fallback: 'sans-serif', // fallback font\n};\n```\n* `index.css`, which includes corresponding `@font-face` directives\n* font files, referenced in the `index.css`\n\nTo remove font from the application, delete the font folder from `resources/fonts`.\n\n### Custom CSS styles and classes\nTo add custom CSS classes or modify styles of existing elements, edit `resources/styles/custom.css` file. It contains a list of modifiable element classes for reference.\n\n### External functions\nIf you add any external functions to your Ink file, the JS function code should be added as a separate `*.js` file to the `resources/externals` folder. See example file `example.js.txt` for details.\n\n## Publishing\n\n### Web application\nDefault Atrament UI build is a progressive web application for web server deployment.\n```\nnpm run build-web\n```\nThe standalone web application files will be in `build/web` folder. Use `npm run preview` command to test it in browser at http://localhost:4173/.\n\n\n### Single file build\n```\nnpm run build-singlefile\n```\nThe game can be exported to a standalone web page, which can be opened locally - similar to Inky or Twine web export.\n\nTo export game in a single file format, run `npm run build-singlefile` command. The resulting web page files will be in the `build/singlefile` folder.\n\n*Please note: single file build uses only system fonts to reduce file size. If you want to include all fonts from the `resources/fonts` folder, use `npm run build-singlefile -- -- --embed-fonts` command to build the game.*\n\n### Standalone executables build\n```\nnpm run build-standalone\n```\nTo build standalone executables for Windows, Linux, and MacOS, use `npm run build-standalone` command. The folder with executables for all platforms will be in the `build/standalone` folder. The build also creates ZIP archives for each platform.\n\n### Zipped game content\nAtrament UI supports zipped game content, when whole game is loaded into browser as a single zip file. The advantage of this mode is instant asset loading at the cost of increased startup time. However, it makes sense only for default web export mode.\n\nTo enable this feature, edit `atrament.config.json` and add `zip` option to it with the name of zip file:\n```\n{\n  ...\n  \"game\": {\n    \"path\": \"game\",\n    \"source\": \"gamefile.ink\",\n    \"zip\": \"yourgame.zip\"\n  }\n}\n```\n*Please note: this option is ignored for development and single file builds.*\n\n### Publishing Atrament games from Inky\nYou can create a single file Atrament games written with Inky, without setting up an Atrament project. Run this command in the project folder with Ink files to create a single file build:\n```\nnpx atrament-wizard publish\n```\n\n## Debugger\nWhen `#debug` global tag is set, debugger can be invoked by pressing debugger button on the screen or double pressing of `~` key.\n\nAtrament Debugger provides the following functionality:\n\n* General information on ink script\n* List of global tags\n* List of ink variables (view and edit)\n* List of visit counts\n* Run Ink function with specified parameters and see the output\n* Navigation to knot/stich path\n\n## Keyboard shortcuts\n| Key | Description                |\n| :-------- | :------------------------- |\n| 1,2,3... | Select corresponding choice option. |\n| Space, Enter | Continue story. |\n| Esc | Show/hide settings dialog. |\n\n## Atrament repositories\n\n- [atrament-web](https://github.com/technix/atrament-web)\n- [atrament-core](https://github.com/technix/atrament-core)\n\nSee also [Atrament core documentation](https://github.com/technix/atrament-core/blob/master/README.md) for additional info on Atrament API.\n\n## LICENSE\n\nAtrament is distributed under [MIT license](LICENSE.md).\n\nCopyright (c) 2023 Serhii \"techniX\" Mozhaiskyi\n\nMade with the support of the [Interactive Fiction Technology Foundation](https://iftechfoundation.org/)\n\n\u003cimg src=\"https://iftechfoundation.org/logo.svg\" width=\"200px\"\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftechnix%2Fatrament-web-ui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftechnix%2Fatrament-web-ui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftechnix%2Fatrament-web-ui/lists"}