[
  {
    "path": ".gitignore",
    "content": ".DS_Store\nbuild/\narchive/\n.venv\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2022, Qwerasd\n\nThis Font Software is licensed under the SIL Open Font License, Version 1.1.\nThis license is copied below, and is also available with a FAQ at:\nhttps://scripts.sil.org/OFL\n\n\n-----------------------------------------------------------\nSIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\n-----------------------------------------------------------\n\nPREAMBLE\nThe goals of the Open Font License (OFL) are to stimulate worldwide\ndevelopment of collaborative font projects, to support the font creation\nefforts of academic and linguistic communities, and to provide a free and\nopen framework in which fonts may be shared and improved in partnership\nwith others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and\nredistributed freely as long as they are not sold by themselves. The\nfonts, including any derivative works, can be bundled, embedded,\nredistributed and/or sold with any software provided that any reserved\nnames are not used by derivative works. The fonts and derivatives,\nhowever, cannot be released under any other type of license. The\nrequirement for fonts to remain under this license does not apply\nto any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\"Font Software\" refers to the set of files released by the Copyright\nHolder(s) under this license and clearly marked as such. This may\ninclude source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the\ncopyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as\ndistributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting,\nor substituting -- in part or in whole -- any of the components of the\nOriginal Version, by changing formats or by porting the Font Software to a\nnew environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical\nwriter or other person who contributed to the Font Software.\n\nPERMISSION & CONDITIONS\nPermission is hereby granted, free of charge, to any person obtaining\na copy of the Font Software, to use, study, copy, merge, embed, modify,\nredistribute, and sell modified and unmodified copies of the Font\nSoftware, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components,\nin Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled,\nredistributed and/or sold with any software, provided that each copy\ncontains the above copyright notice and this license. These can be\nincluded either as stand-alone text files, human-readable headers or\nin the appropriate machine-readable metadata fields within text or\nbinary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font\nName(s) unless explicit written permission is granted by the corresponding\nCopyright Holder. This restriction only applies to the primary font name as\npresented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\nSoftware shall not be used to promote, endorse or advertise any\nModified Version, except to acknowledge the contribution(s) of the\nCopyright Holder(s) and the Author(s) or with their explicit written\npermission.\n\n5) The Font Software, modified or unmodified, in part or in whole,\nmust be distributed entirely under this license, and must not be\ndistributed under any other license. The requirement for fonts to\nremain under this license does not apply to any document created\nusing the Font Software.\n\nTERMINATION\nThis license becomes null and void if any of the above conditions are\nnot met.\n\nDISCLAIMER\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\nOF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\nCOPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nINCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\nDAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\nOTHER DEALINGS IN THE FONT SOFTWARE."
  },
  {
    "path": "README.md",
    "content": "![Pixel Code](https://qwerasd205.github.io/PixelCode/examples/banner.png)\n![Example image](https://qwerasd205.github.io/PixelCode/examples/quick_brown_fox.js.png)\n\nPixel Code is a pixel font designed to actually be good for programming.\n\nYou can read more about the font [here](https://qwerasd205.github.io/PixelCode).\n"
  },
  {
    "path": "activate.sh",
    "content": "#!/bin/sh -e\n\ncd \"$(readlink -f $(dirname \"$0\"))\"\n\necho \"Creating virtual environment...\"\npython3 -m venv .venv\necho \"Activating...\"\nsource .venv/bin/activate\necho \"\"\necho \"================\"\necho \"\"\necho \"Installing requirements...\"\npip3 install -r ./requirements.txt\necho \"\"\necho \"================\"\necho \"\"\necho \"Done setting up virtual environment.\"\necho \"Use the venv in your shell by calling \\`source .venv/bin/activate\\`, or \\`. .venv/bin/activate.fish\\` for fish shell.\"\necho \"Deactivate with \\`deactivate\\`.\"\n\n"
  },
  {
    "path": "dist/css/PixelCode-Black.css",
    "content": "@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-Black.woff2\") format(\"woff2\");\n  font-weight: 900;\n  font-style: normal;\n}\n@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-Black-Italic.woff2\") format(\"woff2\");\n  font-weight: 900;\n  font-style: oblique;\n}\n"
  },
  {
    "path": "dist/css/PixelCode-Bold.css",
    "content": "@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-Bold.woff2\") format(\"woff2\");\n  font-weight: 700;\n  font-style: normal;\n}\n@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-Bold-Italic.woff2\") format(\"woff2\");\n  font-weight: 700;\n  font-style: oblique;\n}\n"
  },
  {
    "path": "dist/css/PixelCode-DemiBold.css",
    "content": "@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-DemiBold.woff2\") format(\"woff2\");\n  font-weight: 600;\n  font-style: normal;\n}\n@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-DemiBold-Italic.woff2\") format(\"woff2\");\n  font-weight: 600;\n  font-style: oblique;\n}\n"
  },
  {
    "path": "dist/css/PixelCode-ExtraBlack.css",
    "content": "@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-ExtraBlack.woff2\") format(\"woff2\");\n  font-weight: 950;\n  font-style: normal;\n}\n@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-ExtraBlack-Italic.woff2\") format(\"woff2\");\n  font-weight: 950;\n  font-style: oblique;\n}\n"
  },
  {
    "path": "dist/css/PixelCode-ExtraBold.css",
    "content": "@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-ExtraBold.woff2\") format(\"woff2\");\n  font-weight: 800;\n  font-style: normal;\n}\n@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-ExtraBold-Italic.woff2\") format(\"woff2\");\n  font-weight: 800;\n  font-style: oblique;\n}\n"
  },
  {
    "path": "dist/css/PixelCode-ExtraLight.css",
    "content": "@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-ExtraLight.woff2\") format(\"woff2\");\n  font-weight: 200;\n  font-style: normal;\n}\n@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-ExtraLight-Italic.woff2\") format(\"woff2\");\n  font-weight: 200;\n  font-style: oblique;\n}\n"
  },
  {
    "path": "dist/css/PixelCode-Light.css",
    "content": "@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-Light.woff2\") format(\"woff2\");\n  font-weight: 300;\n  font-style: normal;\n}\n@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-Light-Italic.woff2\") format(\"woff2\");\n  font-weight: 300;\n  font-style: oblique;\n}\n"
  },
  {
    "path": "dist/css/PixelCode-Medium.css",
    "content": "@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-Medium.woff2\") format(\"woff2\");\n  font-weight: 500;\n  font-style: normal;\n}\n@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-Medium-Italic.woff2\") format(\"woff2\");\n  font-weight: 500;\n  font-style: oblique;\n}\n"
  },
  {
    "path": "dist/css/PixelCode-Regular.css",
    "content": "@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode.woff2\") format(\"woff2\");\n  font-weight: 400;\n  font-style: normal;\n}\n@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-Italic.woff2\") format(\"woff2\");\n  font-weight: 400;\n  font-style: oblique;\n}\n"
  },
  {
    "path": "dist/css/PixelCode-Thin.css",
    "content": "@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-Thin.woff2\") format(\"woff2\");\n  font-weight: 100;\n  font-style: normal;\n}\n@font-face {\n  font-family: \"Pixel Code\";\n  src: url(\"../woff2/PixelCode-Thin-Italic.woff2\") format(\"woff2\");\n  font-weight: 100;\n  font-style: oblique;\n}\n"
  },
  {
    "path": "dist/css/all.css",
    "content": "@import './PixelCode-Thin.css';\n@import './PixelCode-ExtraLight.css';\n@import './PixelCode-Light.css';\n@import './PixelCode-Regular.css';\n@import './PixelCode-Medium.css';\n@import './PixelCode-DemiBold.css';\n@import './PixelCode-Bold.css';\n@import './PixelCode-ExtraBold.css';\n@import './PixelCode-Black.css';\n@import './PixelCode-ExtraBlack.css';\n"
  },
  {
    "path": "examples/oembed.json",
    "content": "{\"title\":\"Pixel Code\",\"author_name\":\"Qwerasd\"}\n"
  },
  {
    "path": "examples/quick_brown_fox.js",
    "content": "class Animal {\n    constructor (options) {\n        this.type = options?.type ?? 'dog';\n        this.adjectives = options?.adjectives;\n    }\n\n    get description () {\n        return `${this.adjectives.join(' ')} ${this.type}`;\n    }\n\n    describe_action (verb, object) {\n        return `${this.description} ${verb} ${object.description}.`;\n    }\n}\n\nconst adjective_prepender = adjective => animal => new Animal({\n    type: animal.type,\n    adjectives: [adjective].concat(animal.adjectives)\n});\n\nconst The = adjective_prepender('The');\nconst the = adjective_prepender('the');\n\nconst quick_brown_fox = new Animal({ type: 'fox', adjectives: ['quick', 'brown'] });\nconst lazy_dog        = new Animal({ adjectives: ['lazy'] });\n\nconsole.log(The(quick_brown_fox).describe_action('jumps over', the(lazy_dog)));\n// \"The quick brown fox jumps over the lazy dog.\""
  },
  {
    "path": "examples/specimen.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <meta http-equiv=\"Refresh\" content=\"0; url='../index.html'\" />\n  <title>Moved</title>\n</head>\n<body>\n  This page has been moved. <a id=\"redirect\" href=\"../\">Click here</a> if you are not redirected automatically.\n  <script>\n    setTimeout(() => document.getElementById(\"redirect\").click(), 1e3);\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta content=\"A pixel font that's actually good for programming.\" property=\"og:description\">\n    <meta content=\"https://qwerasd205.github.io/PixelCode/examples/quick_brown_fox.js.png\" property=\"og:image\">\n    <link type=\"application/json+oembed\" href=\"https://qwerasd205.github.io/PixelCode/examples/oembed.json\">\n    <link rel=\"canonical\" href=\"https://qwerasd205.github.io/PixelCode\" />\n    <meta name=\"theme-color\" content=\"#FFFFFF\">\n    <meta name=\"twitter:card\" content=\"summary_large_image\">\n    <title>Pixel Code</title>\n    <style>\n      @import './dist/css/all.css';\n\n      :root {\n        --bg:   #1f1b1a;\n        --bg-2: #2e2827;\n        --fg:   #fffae5;\n        --fg-2: #d9d1b2;\n        --accent: #feb4d5;\n      }\n\n      html {\n        display: grid;\n        justify-items: center;\n      }\n\n      body {\n        font-family: \"Pixel Code\", \"Comic Sans MS\";\n        line-height: 1.33333;\n        filter: contrast(1);\n        background-color: var(--bg);\n        color: var(--fg);\n        width: 80ch;\n        margin-left: 3ch;\n        margin-right: 3ch;\n        margin-top: 4em;\n        font-weight: 400;\n        font-size: 18px;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n      }\n\n      @media (max-width: 720px) {\n        body {\n          font-size: 9px;\n        }\n      }\n\n      p {\n        margin: 2ex 0;\n      }\n\n      .r {\n        font-weight: normal !important;\n        color: var(--fg);\n      }\n\n      h1, h2, h3, h4 {\n        text-align: center;\n        font-weight: normal;\n      }\n\n      h3 {\n        color: var(--accent);\n      }\n\n      h2, h4 {\n        margin-top: -1em;\n        font-weight: normal;\n      }\n\n      .ex {\n        font-family: \"Pixel Code\", \"Comic Sans MS\";\n        outline: 0.125em solid var(--fg-2);\n        padding: 1.5em;\n        background-color: var(--bg-2);\n        box-shadow: 0 0.25em 0.5em #000000;\n        white-space: pre-line;\n      }\n\n      .ex > * {\n        white-space: pre;\n      }\n\n      .hi {\n        color: var(--accent);\n        position: relative;\n      }\n\n      label {\n        user-select: none;\n        -webkit-user-select: none;\n      }\n\n      input[type=\"checkbox\"] {\n        -webkit-appearance: none;\n        -moz-appearance: none;\n        appearance: none;\n        font-size: 100%;\n        width: 1.5em; height: 1.5em;\n        background-color: #000000;\n        vertical-align: -0.5em;\n        font-family: \"Pixel Code\", \"Comic Sans MS\";\n        position: relative;\n        outline: 0.125em solid var(--fg-2);\n        cursor: pointer;\n      }\n      input[type=\"checkbox\"]::after {\n        font-size: 150%;\n        content: \"X\";\n        color: var(--fg);\n        position: absolute;\n        width: 100%;\n        height: 100%;\n        text-align: center;\n        line-height: 1;\n        left: 0.0625em;\n      }\n      input:checked {\n        background-color: var(--fg);\n      }\n      input:checked::after {\n        content: \"✓\";\n        color: #000000;\n      }\n      input + label {\n        cursor: pointer;\n      }\n\n      a {\n        color: var(--accent);\n        text-decoration-style: dotted;\n      }\n\n      a:hover,\n      a:focus-visible {\n        text-decoration-style: solid;\n      }\n\n      a.button {\n        font-size: 125%;\n        border: 0.125em solid var(--fg);\n        padding: 0.5em 1.5em;\n        margin: 0 1em;\n        background-color: var(--accent);\n        color: #000000;\n        font-weight: 400;\n        text-shadow: none;\n        box-shadow: 0 0 1em #000000;\n        text-decoration: none;\n      }\n\n      a.button:hover,\n      a.button:focus-visible {\n        background-color: var(--fg);\n        text-decoration: underline;\n      }\n\n      details {\n        background-color: var(--bg-2);\n        position: relative;\n        overflow: hidden;\n        box-shadow: inset 0 0 0.5em #000000;\n      }\n\n      details summary {\n        cursor: pointer;\n        text-decoration: underline;\n        text-decoration-style: dashed;\n        padding: 1em;\n      }\n\n      details summary:hover,\n      details summary:focus-visible {\n        text-decoration-style: solid;\n      }\n\n      details summary::-webkit-details-marker,\n      details summary::marker {\n        content: none;\n        display: none;\n      }\n\n      details summary::before {\n        content: '->';\n        width: 3em;\n        text-align: center;\n        float: left;\n      }\n\n      details summary:hover::before,\n      details summary:focus-visible::before {\n        color: var(--accent);\n      }\n\n      details[open] summary {\n        text-decoration: none;\n      }\n\n      details[open] summary::before {\n        content: '\\\\/';\n      }\n\n      details summary > * {\n        display: inline;\n      }\n\n      details > :not(summary) {\n        margin: 0 1.5em 1.5em;\n      }\n\n\n      .bottom-spacer {\n        height: 16em;\n      }\n\n      .justified {\n        text-align: justify;\n        text-justify: distribute;\n        text-justify: inter-character;\n      }\n\n      .download-section {\n        text-align: center;\n        margin: 1ex 0;\n        padding: 5ex 0;\n        box-shadow: inset 0 0 0.5em #000000;\n        background-color: var(--bg-2);\n      }\n\n      .noliga {\n              font-feature-settings: \"liga\" 0;\n      }\n\n      .w100 {\n        font-weight: 100;\n      }\n      .w200 {\n        font-weight: 200;\n      }\n      .w300 {\n        font-weight: 300;\n      }\n      .w400 {\n        font-weight: 400;\n      }\n      .w500 {\n        font-weight: 500;\n      }\n      .w600 {\n        font-weight: 600;\n      }\n      .w700 {\n        font-weight: 700;\n      }\n      .w800 {\n        font-weight: 800;\n      }\n      .w900 {\n        font-weight: 900;\n      }\n      .w950 {\n        font-weight: 950;\n      }\n\n      .prop {\n        color: #fbec68;\n      }\n      .keyword {\n        color: #df98fe;\n      }\n      .verb {\n        font-style: italic;\n        color: #e88484;\n      }\n      .key {\n        color: #5ee89e;\n      }\n      .comment {\n        color: #777;\n        font-style: italic;\n      }\n    </style>\n  </head>\n  <body>\n    <h1>Pixel Code</h1>\n    <h2>A pixel font that's actually good for programming.</h2>\n    <p class=\"justified\">\n      Pixel Code is a monospace pixel art style programming font which is designed to maximize readability\n      and code-friendliness, while sticking to a pixel grid.\n    </p>\n    <p class=\"justified\">\n      Each glyph was carefully designed to be as legible as possible, with special consideration given to\n      their roles in programming. Furthermore, the OpenType Contextual Alternates feature has been leveraged\n      to provide pseudo-kerning, eliminating uneven gaps caused by thin letters like 'i' and 'l', while\n      avoiding the need to reduce their legibility by making them wider.\n    </p>\n    <p class=\"justified\">\n      Pixel Code also includes a full set of programming ligatures inspired by those in fonts like <a href=\"https://github.com/tonsky/FiraCode\" rel=\"noreferrer noopener\">Fira Code</a>.\n      Ligatures reduce visual noise, consolidating the meanings of multi-glyph structures automatically, so\n      that the programmer's brain can spend more of its resources on actually programming.\n    </p>\n    <p>\n      I hope you enjoy the font, I put a lot of work in to it!\n    </p>\n    <p class=\"download-section\">\n      <a href=\"https://github.com/qwerasd205/PixelCode/releases/latest\" rel=\"noreferrer noopener\" class=\"button\">Download</a>\n    </p>\n    <h3>Quick Start</h3>\n    <h4>How do I use this?</h4>\n    <p>\n      <details>\n        <summary><b>Local Installation</b> (for code editors, IDEs, etc.)</summary>\n        <p>\n          Download the latest release from GitHub and install your desired weights\n          and styles on your computer. If you don't know which format to install, I\n          recommend using the TTF versions.\n        </p>\n        <p>\n          Once the font is installed you should be able to configure your editor to\n          use it using the name \"Pixel Code\".\n        </p>\n      </details>\n    </p>\n    <br>\n    <h3>Weights and Styles</h3>\n    <h4>Comes in a complete range of weights and regular/italic styles.</h4>\n    <p>\n      These alternate weights are automatically generated from the default (400).\n    </p>\n    <div class=\"ex\"><!--\n-->   <span class=\"w100\">   100        Thin <i>+ Italic</i>   |  * The Five Boxing Wizards Jump Quickly *</span>\n      <span class=\"w200\">   200  ExtraLight <i>+ Italic</i>   |  * The Five Boxing Wizards Jump Quickly *</span>\n      <span class=\"w300\">   300       Light <i>+ Italic</i>   |  * The Five Boxing Wizards Jump Quickly *</span>\n      <span class=\"w400\">   400     Regular <i>+ Italic</i>   |  * The Five Boxing Wizards Jump Quickly *</span>\n      <span class=\"w500\">   500      Medium <i>+ Italic</i>   |  * The Five Boxing Wizards Jump Quickly *</span>\n      <span class=\"w600\">   600    DemiBold <i>+ Italic</i>   |  * The Five Boxing Wizards Jump Quickly *</span>\n      <span class=\"w700\">   700        Bold <i>+ Italic</i>   |  * The Five Boxing Wizards Jump Quickly *</span>\n      <span class=\"w800\">   800   ExtraBold <i>+ Italic</i>   |  * The Five Boxing Wizards Jump Quickly *</span>\n      <span class=\"w900\">   900       Black <i>+ Italic</i>   |  * The Five Boxing Wizards Jump Quickly *</span>\n      <span class=\"w950\">   950  ExtraBlack <i>+ Italic</i>   |  * The Five Boxing Wizards Jump Quickly *</span>\n    </div>\n    <br>\n    <h3>Unicode Coverage</h3>\n    <h4>Language support &amp; various useful glyphs.</h4>\n    <p>\n      Pixel Code supports Latin, Greek, Cyrillic, and Hebrew alphabets.\n    </p>\n    <div class=\"ex justified\"><!--\n-->   Í stórum hring vegarins, margir fólk leitar að ljósi sem leiðbeinir þeim. Some find it in the gentle breeze of the Caribbean sea, while others discover it in the vastness of the Siberian tundra. La vie est une aventure, une quête perpétuelle de bonheur et de sens. In dem großen Weg des Lebens suchen viele Menschen nach dem Licht, das sie führen wird. En el corazón de la selva amazónica, hay una calma inquebrantable que te invita a reflexionar. Em coração de Lisboa, há um fado que ecoa pelas vielas estreitas, contando histórias de amor e saudade. La vita è un'avventura, una ricerca perpetua di felicità e significato. A l'ànima del Barri Gòtic de Barcelona, hi ha un silenci serè que t'invita a reflexionar. В большом мире много красоты и удивительных моментов, которые ожидают нас впереди. У дворишту старог дворца, под широким небом, стоји стара храстова капија, која сведочи о прошлим временима. В големия свят има толкова много красота и чудесни моменти, които ни очакват напред. У великому світі багато краси та дивовижних моментів, які чекають нас вперед. Во големиот свет има толку многу убавина и чудесни моменти, кои не чекаат напред. Στον μεγάλο δρόμο της ζωής, πολλοί άνθρωποι ψάχνουν για το φως που θα τους καθοδηγήσει.\n      במסע הגדול של החיים, הרבים מחפשים את האור שינחיל אותם.\n    </div>\n    <i style=\"float: right\">Sample text courtesy of ChatGPT</i>\n    <br>\n    <p>\n      And has box drawing characters, geometric shapes, dingbats, and various technical symbols.\n    </p>\n    <div class=\"ex\"><!--\n-->   <span>╭─ Box Drawing ──────────╮</span>\n      <span>│ ┌─┬┐  ╔═╦╗  ╓─╥╖  ╒═╤╕ │</span>\n      <span>│ │ ││  ║ ║║  ║ ║║  │ ││ │</span>\n      <span>│ ├─┼┤  ╠═╬╣  ╟─╫╢  ╞═╪╡ │</span>\n      <span>│ └─┴┘  ╚═╩╝  ╙─╨╜  ╘═╧╛ │</span>\n      <span>│ ╭───────────────────╮  │</span>\n      <span>│ │  ╔═══╗  ╭───────╮ │▒ │</span>\n      <span>│ │  ╚═╦═╝  ╰───────╯ │▒ │</span>\n      <span>│ ╞═╤══╩══╤═══════════╡▒ │</span>\n      <span>│ │ ├──┬──┤           │▒ │</span>\n      <span>│ │ └──┴──┘           │▒ │</span>\n      <span>│ ╰───────────────────╯▒ │</span>\n      <span>│  ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ │</span>\n      <span>╰────────────────────────╯</span>\n\n      <span>╭─ Geometric Shapes ──╮</span>\n      <span>│ ■ □ ▢ ▣ ▤ ▥ ▦ ▧ ▨ ▩ │</span>\n      <span>│ ▪ ▫ ▬ ▭ ▮ ▯     ▲ △ │</span>\n      <span>│ ▴ ▵ ▶ ▷ ▸ ▹ ► ▻ ▼ ▽ │</span>\n      <span>│ ▾ ▿ ◀ ◁ ◂ ◃ ◄ ◅ ◆ ◇ │</span>\n      <span>│ ◈ ◉ ◊ ○ ◌ ◍ ◎ ● ◐ ◑ │</span>\n      <span>│ ◒ ◓ ◔ ◕ ◖ ◗ ◘ ◙ ◚ ◛ │</span>\n      <span>│ ◜ ◝ ◞ ◟ ◠ ◡ ◢ ◣ ◤ ◥ │</span>\n      <span>│ ◦ ◧ ◨ ◩ ◪ ◫   ◭ ◮ ◯ │</span>\n      <span>│ ◰ ◱ ◲ ◳ ◴ ◵ ◶ ◷ ◸ ◹ │</span>\n      <span>│ ◺ ◻ ◼     ◿         │</span>\n      <span>╰─────────────────────╯</span>\n\n      <span>╭─ Dingbats ───────╮</span>\n      <span>│      ✅   ✉✊✋✌ │</span>\n      <span>│       ✓✔✕✖✗✘✙✚✛✜ │</span>\n      <span>│     ✡✢✣✤✥✦✧✨    │</span>\n      <span>│        ✳✴        │</span>\n      <span>│    ✿❀      ❇❈    │</span>\n      <span>│ ❌ ❎❏❐❑❒❓❔❕  │</span>\n      <span>│ ❗❘❙❚❛❜❝❞  ❡❢❣❤❥ │</span>\n      <span>│ ❦❧❨❩❪❫❬❭❮❯❰❱❲❳❴❵ │</span>\n      <span>│ ❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅ │</span>\n      <span>│ ➆➇➈➉➊➋➌➍➎➏➐➑➒➓➔  │</span>\n      <span>│ ➕➖➗➘➙➚➛➜➝➞➟➠➡ │</span>\n      <span>│ ➢➣➤➥➦➧➨➩➪➫➬➭➮➯➰ │</span>\n      <span>│ ➱➲➳➴➵➶➷➸➹➺➻➼➽➾➿ │</span>\n      <span>╰──────────────────╯</span>\n\n      ──── Misc. ────\n\n      # Powerline\n                        \n\n      # Fira Progress Bar\n       \n       \n       \n       \n       \n       \n       ✓\n    </div>\n    <br>\n    <p>\n      The full set of glyphs in Pixel Code can be viewed below.\n    </p>\n    <div class=\"ex\" style=\"line-height: 1.4815\"><!--\n  --->&nbsp; ! &quot; # $ % &amp; &#x27; ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; &lt; = &gt;\n      ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \\ ] ^\n      _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~\n      ¡ ¢ £ ¤ ¥ ¦ § ¨ ª « ¬ ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã\n      Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã\n      ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ Ā ā Ă ă\n      Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Đ đ Ē ē Ĕ ĕ Ė ė Ę ę Ě ě Ĝ ĝ Ğ ğ Ġ ġ Ģ ģ\n      Ĥ ĥ Ħ ħ Ĩ ĩ Ī ī Ĭ ĭ Į į İ ı Ĳ ĳ Ĵ ĵ Ķ ķ ĸ Ĺ ĺ Ļ ļ Ľ ľ Ŀ ŀ Ł ł Ń\n      ń Ņ ņ Ň ň ŉ Ŋ ŋ Ō ō Ŏ ŏ Ő ő Œ œ Ŕ ŕ Ŗ ŗ Ř ř Ś ś Ŝ ŝ Ş ş Š š Ţ ţ\n      Ť ť Ŧ ŧ Ũ ũ Ū ū Ŭ ŭ Ů ů Ű ű Ų ų Ŵ ŵ Ŷ ŷ Ÿ Ź ź Ż ż Ž ž ʰ ʱ ʲ ʳ ʴ\n      ʶ ʷ ʸ ˀ ˁ ˂ ˃ ˄ ˅ ˆ ˇ ˈ ˉ ˊ ˋ ˌ ˍ ˎ ˏ ː ˑ ˔ ˕ ˖ ˗ ˘ ˙ ˚ ˜ ˝ ˟ ˡ\n      ˢ ˣ ˤ ˥ ˦ ˧ ˨ ˩ ˪ ˫ ˬ ˭ ˯ ˰ ˱ ˲ ˳ ˴ ˵ ˶ ˷ ˸ ˹ ˺ ˻ ˼ ˽ ˾ Ͱ ͱ Ͳ ͳ\n      ʹ ͵ Ͷ ͷ ͺ ͻ ͼ ͽ ; Ϳ ΄ ΅ Ά · Έ Ή Ί Ό Ύ Ώ ΐ Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ\n      Μ Ν Ξ Ο Π Ρ Σ Τ Υ Φ Χ Ψ Ω Ϊ Ϋ ά έ ή ί ΰ α β γ δ ε ζ η θ ι κ λ μ\n      ν ξ ο π ρ ς σ τ υ φ χ ψ ω ϊ ϋ ό ύ ώ Ϗ ϐ ϑ ϒ ϓ ϔ ϕ ϖ ϗ Ϙ ϙ Ϛ ϛ Ϝ\n      ϝ Ϟ ϟ Ϡ ϡ ϱ ϲ ϳ ϴ ϵ ϶ Ϸ ϸ Ϲ Ϻ ϻ ϼ Ͻ Ͼ Ͽ Ѐ Ё Ђ Ѓ Є Ѕ І Ї Ј Љ Њ Ћ\n      Ќ Ѝ Ў Џ А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы\n      Ь Э Ю Я а б в г д е ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ы\n      ь э ю я ѐ ё ђ ѓ є ѕ і ї ј љ њ ћ ќ ѝ ў џ א ב ג ד ה ו ז ח ט י ך כ\n      ל ם מ ן נ ס ע ף פ ץ צ ק ר ש ת ׳ ״ ᴬ ᴭ ᴮ ᴰ ᴱ ᴲ ᴳ ᴴ ᴵ ᴶ ᴷ ᴸ ᴹ ᴺ ᴻ\n      ᴼ ᴽ ᴾ ᴿ ᵀ ᵁ ᵂ ᵃ ᵅ ᵇ ᵈ ᵉ ᵍ ᵎ ᵏ ᵐ ᵑ ᵒ ᵖ ᵗ ᵘ ᵛ ᵝ ᵢ ᵣ ᵤ ᵥ ᵦ ‐ ‑ ‒ –\n      — ― ‖ ‘ ’ ‚ ‛ “ ” „ ‟ † ‡ • ‣ ․ ‥ … ‧ ′ ″ ‴ ‵ ‶ ‷ ‸ ‹ › ‼ ‽ ‾ ‿\n      ⁀ ⁁ ⁂ ⁃ ⁅ ⁆ ⁇ ⁈ ⁉ ⁋ ⁌ ⁍ ⁎ ⁐ ⁑ ⁒ ⁓ ⁔ ⁕ ⁖ ⁘ ⁙ ⁚ ⁛ ⁜ ⁝ ⁞ ⁰ ⁱ ⁴ ⁵ ⁶\n      ⁷ ⁸ ⁹ ⁺ ⁻ ⁼ ⁽ ⁾ ⁿ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₊ ₋ ₌ ₍ ₎ ₐ ₑ ₒ ₓ ₕ ₖ ₗ ₘ\n      ₙ ₚ ₛ ₜ ← ↑ → ↓ ↕ ↖ ↗ ↘ ↙ ↩ ↪ ↰ ↱ ↲ ↳ ↴ ↵ ↶ ↷ ↸ ↺ ↻ ↼ ↽ ↾ ↿ ⇀ ⇁\n      ⇂ ⇃ ⇠ ⇡ ⇢ ⇣ ⇦ ⇧ ⇨ ⇩ ⇪ ─ ━ │ ┃ ┄ ┅ ┆ ┇ ┊ ┋ ┌ ┍ ┎ ┏ ┐ ┑ ┒ ┓ └ ┕ ┖\n      ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟ ┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯ ┰ ┱ ┲ ┳ ┴ ┵ ┶\n      ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿ ╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏ ═ ║ ╒ ╓ ╔ ╕ ╖\n      ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟ ╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯ ╰ ╱ ╲ ╳ ╴ ╵ ╶\n      ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿ ▀ ▁ ▂ ▃ ▄ ▅ ▆ ▇ ▉ ▊ ▋ ▌ ▍ ▎ ▏ ▐ ░ ▒ ▓ ▔ ▕ ▖ ▗\n      ▘ ▙ ▚ ▛ ▜ ▝ ▞ ▟ ■ □ ▢ ▣ ▤ ▥ ▦ ▧ ▨ ▩ ▪ ▫ ▬ ▭ ▮ ▯ ▲ △ ▴ ▵ ▶ ▷ ▸ ▹\n      ► ▻ ▼ ▽ ▾ ▿ ◀ ◁ ◂ ◃ ◄ ◅ ◆ ◇ ◈ ◉ ◊ ○ ◌ ◍ ◎ ● ◐ ◑ ◒ ◓ ◔ ◕ ◖ ◗ ◘ ◙\n      ◚ ◛ ◜ ◝ ◞ ◟ ◠ ◡ ◢ ◣ ◤ ◥ ◦ ◧ ◨ ◩ ◪ ◫ ◭ ◮ ◯ ◰ ◱ ◲ ◳ ◴ ◵ ◶ ◷ ◸ ◹ ◺\n      ◻ ◼ ◿ ✅✉ ✊✋✌ ✓ ✔ ✕ ✖ ✗ ✘ ✙ ✚ ✛ ✜ ✡ ✢ ✣ ✤ ✥ ✦ ✧ ✨✳ ✴ ✿ ❀ ❇ ❈\n      ❌❎❏ ❐ ❑ ❒ ❓❔❕❗❘ ❙ ❚ ❛ ❜ ❝ ❞ ❡ ❢ ❣ ❤ ❥ ❦ ❧ ❨ ❩ ❪ ❫ ❬ ❭ ❮ ❯\n      ❰ ❱ ❲ ❳ ❴ ❵ ❶ ❷ ❸ ❹ ❺ ❻ ❼ ❽ ❾ ❿ ➀ ➁ ➂ ➃ ➄ ➅ ➆ ➇ ➈ ➉ ➊ ➋ ➌ ➍ ➎ ➏\n      ➐ ➑ ➒ ➓ ➔ ➕➖➗➘ ➙ ➚ ➛ ➜ ➝ ➞ ➟ ➠ ➡ ➢ ➣ ➤ ➥ ➦ ➧ ➨ ➩ ➪ ➫ ➬ ➭ ➮ ➯\n      ➰➱ ➲ ➳ ➴ ➵ ➶ ➷ ➸ ➹ ➺ ➻ ➼ ➽ ➾ ➿⟲ ⟳ ⟵ ⟶ ⠁ ⠂ ⠃ ⠄ ⠅ ⠆ ⠇ ⠈ ⠉ ⠊ ⠋ ⠌\n      ⠍ ⠎ ⠏ ⠐ ⠑ ⠒ ⠓ ⠔ ⠕ ⠖ ⠗ ⠘ ⠙ ⠚ ⠛ ⠜ ⠝ ⠞ ⠟ ⠠ ⠡ ⠢ ⠣ ⠤ ⠥ ⠦ ⠧ ⠨ ⠩ ⠪ ⠫ ⠬\n      ⠭ ⠮ ⠯ ⠰ ⠱ ⠲ ⠳ ⠴ ⠵ ⠶ ⠷ ⠸ ⠹ ⠺ ⠻ ⠼ ⠽ ⠾ ⠿ ⡀ ⡁ ⡂ ⡃ ⡄ ⡅ ⡆ ⡇ ⡈ ⡉ ⡊ ⡋ ⡌\n      ⡍ ⡎ ⡏ ⡐ ⡑ ⡒ ⡓ ⡔ ⡕ ⡖ ⡗ ⡘ ⡙ ⡚ ⡛ ⡜ ⡝ ⡞ ⡟ ⡠ ⡡ ⡢ ⡣ ⡤ ⡥ ⡦ ⡧ ⡨ ⡩ ⡪ ⡫ ⡬\n      ⡭ ⡮ ⡯ ⡰ ⡱ ⡲ ⡳ ⡴ ⡵ ⡶ ⡷ ⡸ ⡹ ⡺ ⡻ ⡼ ⡽ ⡾ ⡿ ⢀ ⢁ ⢂ ⢃ ⢄ ⢅ ⢆ ⢇ ⢈ ⢉ ⢊ ⢋ ⢌\n      ⢍ ⢎ ⢏ ⢐ ⢑ ⢒ ⢓ ⢔ ⢕ ⢖ ⢗ ⢘ ⢙ ⢚ ⢛ ⢜ ⢝ ⢞ ⢟ ⢠ ⢡ ⢢ ⢣ ⢤ ⢥ ⢦ ⢧ ⢨ ⢩ ⢪ ⢫ ⢬\n      ⢭ ⢮ ⢯ ⢰ ⢱ ⢲ ⢳ ⢴ ⢵ ⢶ ⢷ ⢸ ⢹ ⢺ ⢻ ⢼ ⢽ ⢾ ⢿ ⣀ ⣁ ⣂ ⣃ ⣄ ⣅ ⣆ ⣇ ⣈ ⣉ ⣊ ⣋ ⣌\n      ⣍ ⣎ ⣏ ⣐ ⣑ ⣒ ⣓ ⣔ ⣕ ⣖ ⣗ ⣘ ⣙ ⣚ ⣛ ⣜ ⣝ ⣞ ⣟ ⣠ ⣡ ⣢ ⣣ ⣤ ⣥ ⣦ ⣧ ⣨ ⣩ ⣪ ⣫ ⣬\n      ⣭ ⣮ ⣯ ⣰ ⣱ ⣲ ⣳ ⣴ ⣵ ⣶ ⣷ ⣸ ⣹ ⣺ ⣻ ⣼ ⣽ ⣾ ⣿ ⤌ ⤍ ⤎ ⤏ ⤙ ⤚ ⤛ ⤜ ⤡ ⤢ ⤣ ⤤ ⤥\n      ⤦ ⤴ ⤵ ⤶ ⤷ ⤸ ⤹ ⤺ ⤻ ⤾ ⤿ ⥢ ⥣ ⥤ ⥥ ⥦ ⥧ ⥨ ⥩ ⥪ ⥫ ⥬ ⥭ ⥮ ⥯ ⥰ ⬀ ⬁ ⬂ ⬃ ⬅ ⬆\n      ⬇ ⬈ ⬉ ⬊ ⬋ ⬎ ⬏ ⬐ ⬑ ⬒ ⬓ ⬔ ⬕ ⬖ ⬗ ⬘ ⬙ ⬚ ⬛⬜⬝ ⬞ ⬥ ⬦ ⬧ ⬨ ⭕⭠ ⭡ ⭢ ⭣ ⭥\n      ⭦ ⭧ ⭨ ⭩ ⭮ ⭯ ⮌ ⮍ ⮎ ⮏ ⮐ ⮑ ⮒ ⮓ ⮕ ⮬ ⮭ ⮮ ⮯ ⮺ ⮻ ⮼ ⯀ ⯁ ⯅ ⯆ ⯇ ⯈ ⯊ ⯋ ⯑ ⯒\n      ⯾ ⯿ ⱼ ⱽ ꟲ ꟳ ꟴ ꟹ                        \n             � 🬀 🬁 🬂 🬃 🬄 🬅 🬆 🬇 🬈 🬉 🬊 🬋 🬌 🬍 🬎 🬏 🬐 🬑 🬒 🬓 🬔 🬕 🬖 🬗\n      🬘 🬙 🬚 🬛 🬜 🬝 🬞 🬟 🬠 🬡 🬢 🬣 🬤 🬥 🬦 🬧 🬨 🬩 🬪 🬫 🬬 🬭 🬮 🬯 🬰 🬱 🬲 🬳 🬴 🬵 🬶 🬷\n      🬸 🬹 🬺 🬻 🬼 🬽 🬾 🬿 🭀 🭁 🭂 🭃 🭄 🭅 🭆 🭇 🭈 🭉 🭊 🭋 🭌 🭍 🭎 🭏 🭐 🭑 🭒 🭓 🭔 🭕 🭖 🭗\n      🭘 🭙 🭚 🭛 🭜 🭝 🭞 🭟 🭠 🭡 🭢 🭣 🭤 🭥 🭦 🭧 🭨 🭩 🭪 🭫 🭬 🭭 🭮 🭯 🮌 🮍 🮎 🮏 🮐 🮑 🮒 🮔\n      🮕 🮖 🮗 🮘 🮙 🮚 🮛 🮜 🮝 🮞 🮟 🮠 🮡 🮢 🮣 🮤 🮥 🮦 🮧 🮨 🮩 🮪 🮫 🮬 🮭 🮮 🮯 🮰 🮱 🮲 🮳 🮴\n      🮵 🮶 🮷 🮸 🮹 🮺 🮻 🮼 🮽 🮾 🮿 🯀 🯁 🯂 🯃 🯄 🯅 🯆 🯇 🯈 🯉 🯊 🯰 🯱 🯲 🯳 🯴 🯵 🯶 🯷 🯸 🯹\n    </div>\n    <br>\n    <p>\n      You can explore the togglable OpenType features of this font below.\n    </p>\n    <br>\n    <h3>Programming Ligatures</h3>\n    <h4>(to reduce visual noise)</h4>\n    <p>\n      Can be toggled with the \"Ligatures\" OpenType feature.<br><br>\n      (liga) <input type=\"checkbox\" name=\"liga\" id=\"liga\" checked> <label for=\"liga\">Enabled</label>\n    </p>\n    <h4>Ligatures</h4>\n    <div class=\"ex\"><!--\n-->   Comments:\n      <span class=\"hi\">//</span> Single-line\n      <span class=\"hi\">/*</span> Multi-line <span class=\"hi\">*/</span>\n      <span class=\"hi\">///</span> Triple slash\n      <span class=\"hi\">&lt;!--</span> HTML-style <span class=\"hi\">--&gt;</span>\n\n      Comparisons:\n      x <span class=\"hi\">&gt;=</span> y\n      x <span class=\"hi\">&lt;=</span> y\n      x <span class=\"hi\">!=</span> y\n      x <span class=\"hi\">==</span> y\n      x <span class=\"hi\">!==</span> y\n      x <span class=\"hi\">===</span> y\n\n      Arrows:\n      <span class=\"hi\">=&gt;</span>\n      <span class=\"hi\">-&gt;</span>\n      <span class=\"hi\">&lt;-</span>\n\n      Assignments:\n      a <span class=\"hi\">:=</span> b\n      a <span class=\"hi\">*=</span> b\n      a <span class=\"hi\">/=</span> b\n      a <span class=\"hi\">|=</span> b\n      a <span class=\"hi\">&gt;&gt;=</span> b\n      a <span class=\"hi\">&lt;&lt;=</span> b\n      a <span class=\"hi\">+|=</span> b\n      a <span class=\"hi\">-|=</span> b\n      a <span class=\"hi\">*|=</span> b\n      a <span class=\"hi\">&lt;&lt;|=</span> b\n\n      Bitwise:\n      p<span class=\"hi\"> &gt;&gt; </span>q\n      p<span class=\"hi\"> &lt;&lt; </span>q\n      p<span class=\"hi\"> &gt;&gt;&gt; </span>q\n      p<span class=\"hi\"> &lt;&lt;&lt; </span>q\n\n      Miscellaneous:\n      j <span class=\"hi\">||</span> k\n      j <span class=\"hi\">**</span> k\n      std<span class=\"hi\">::</span>namespace\n      optional<span class=\"hi\">?.</span>chaining\n      https<span class=\"hi\">://</span>example.com\n    </div>\n    <br><br>\n    <h3>Context Aware Punctuation</h3>\n    <h4>for better visual flow.</h4>\n    <p>\n      Can be toggled with the \"Contextual Alternates\" OpenType feature.<br><br>\n      (calt) <input type=\"checkbox\" name=\"calt\" id=\"calt\" checked> <label for=\"calt\">Enabled</label>\n    </p>\n    <div class=\"ex\"><!--\n-->   0xFF 1920x1080 | Simplified x for hexadecimal and dimensions.\n\n      *EQ *eq | Asterisks, colons, hyphens and plus signs\n      A:E a:e | will move up or down depending on if they\n      C-O c-o | follow (or precede) an uppercase or lower\n      X+Z x+z | case letter.\n    </div>\n    <br><br>\n    <h3>Pseudo-Kerning</h3>\n    <h4>to avoid unseemly gaps.</h4>\n    <p>\n      Most monospace fonts simply use wide serifs on the i and l characters in order to\n      make them fit nicely in with other glyphs without creating unnatural gaps on either\n      side. I was not satisfied with this, as doing so reduces their legibility by making\n      the letterforms less identifiable. So instead, I implemented \"pseudo-kerning\" that\n      uses contextual subsitution of the l character to push it to the left by a pixel\n      when it follows a letter with a wide right bearing like i and u.\n    </p>\n    <p>\n      I recommend enabling this feature for static text, but not for editable text, where\n      it can be jarring to have the characters jump around as you type.\n    </p>\n    <p>\n      Can be enabled with the \"Stylistic Set 20\" OpenType feature.<br><br>\n      (ss20) <input type=\"checkbox\" name=\"ss20\" id=\"ss20\" checked> <label for=\"ss20\">Enabled</label>\n    </p>\n    <div class=\"ex\"><!--\n-->   w<span class=\"hi\">ill</span> ......|. Notice, that even though\n      h<span class=\"hi\">ull</span> ......| toggling the calt feature\n      fr<span class=\"hi\">ill</span> .....|.. moves these 'l's to the\n      ta<span class=\"hi\">ili</span>ng ...|.. left, the characters to\n      mod<span class=\"hi\">ule</span> ....|. the right remain unmoved.\n      cas<span class=\"hi\">tle</span> ....|..........................\n      sol<span class=\"hi\">ilo</span>quy .|... Monospace is preserved.\n    </div>\n    <br><br>\n    <h3>Stylistic Alternates</h3>\n    <h4>(for those who prefer)</h4>\n    <p>\n      There are some alternate styles available for certain sets of glyphs.<br><br>\n      (onum) <input type=\"checkbox\" name=\"onum\" id=\"onum\"> <label for=\"onum\">Disabled</label>\n    </p>\n    <h4>Oldstyle Figures (onum)</h4>\n    <div class=\"ex\"><!--\n-->   <span class=\"hi\">10</span>, <span class=\"hi\">9</span>, <span class=\"hi\">8</span>, <span class=\"hi\">7</span>, <span class=\"hi\">6</span>, <span class=\"hi\">5</span>, <span class=\"hi\">4</span>, <span class=\"hi\">3</span>, <span class=\"hi\">2</span>, <span class=\"hi\">1</span> -- Lift-off!\n\n      What was it? <span class=\"hi\">525</span>_<span class=\"hi\">600</span> minutes in a year?\n\n      const PI = <span class=\"hi\">3</span>.<span class=\"hi\">14159265358979323846264338</span>; // TODO: Increase precision.\n\n      let [x<span class=\"hi\">1</span>, y<span class=\"hi\">1</span>] = [<span class=\"hi\">0</span>.<span class=\"hi\">12569</span>, <span class=\"hi\">0</span>.<span class=\"hi\">45780</span>];\n    </div>\n    <br>\n    <p>(ss01) <input type=\"checkbox\" name=\"ss01\" id=\"ss01\"> <label for=\"ss01\">Disabled</label></p>\n    <h4>Straight Comma (ss01)</h4>\n    <div class=\"ex\"><!--\n-->   {a:b.c,d:e}; | Originally, when Pixel Code was first released, it had a\n      :;:;:;:;:;:; | less distinct style for the comma and semicolon; the old\n      ,.,.,.,.,.,. | style has been made available as a togglable feature, so\n      .:;,.:;,.:;, | that it can still be used if you preferred it.\n    </div>\n    <br><br>\n    <div class=\"bottom-spacer\"></div>\n\n    <script>\n      let calt = true;\n      let ss20 = true;\n      let onum = false;\n      let liga = true;\n      let ss01 = false;\n      const update_style = () => {\n        document.body.style.fontFeatureSettings\n        = `\"calt\" ${+calt\n        }, \"ss20\" ${+ss20\n        }, \"onum\" ${+onum\n        }, \"liga\" ${+liga\n        }, \"ss01\" ${+ss01\n        }`;\n      }\n      update_style();\n      const liga_toggle = document.getElementById('liga');\n      liga_toggle.addEventListener('input', () => {\n        liga = liga_toggle.checked;\n        liga_toggle.nextElementSibling.textContent = liga ? 'Enabled' : 'Disabled';\n        update_style();\n      });\n      const calt_toggle = document.getElementById('calt');\n      calt_toggle.addEventListener('input', () => {\n        calt = calt_toggle.checked;\n        calt_toggle.nextElementSibling.textContent = calt ? 'Enabled' : 'Disabled';\n        update_style();\n      });\n      const ss20_toggle = document.getElementById('ss20');\n      ss20_toggle.addEventListener('input', () => {\n        ss20 = ss20_toggle.checked;\n        ss20_toggle.nextElementSibling.textContent = ss20 ? 'Enabled' : 'Disabled';\n        update_style();\n      });\n      const onum_toggle = document.getElementById('onum');\n      onum_toggle.addEventListener('input', () => {\n        onum = onum_toggle.checked;\n        onum_toggle.nextElementSibling.textContent = onum ? 'Enabled' : 'Disabled';\n        update_style();\n      });\n      const ss01_toggle = document.getElementById('ss01');\n      ss01_toggle.addEventListener('input', () => {\n        ss01 = ss01_toggle.checked;\n        ss01_toggle.nextElementSibling.textContent = ss01 ? 'Enabled' : 'Disabled';\n        update_style();\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "pyrightconfig.json",
    "content": "{\n  \"venv\": \".venv\",\n  \"venvPath\": \".\"\n}\n"
  },
  {
    "path": "requirements.txt",
    "content": "fontmake\nfonttools\nufolib2\npillow\nwatchdog\n"
  },
  {
    "path": "src/build.sh",
    "content": "#!/bin/sh -e\n\ncd \"$(readlink -f $(dirname \"$0\"))\"\n\n# Pixel Code build script\n\n# Activate python virtual environment.\n../activate.sh\nsource ../.venv/bin/activate\n\n# Build UFOs from images and fea files.\npython3 build_from_images.py\n\n# Variable font (experimental)\n# fontmake ../build/PixelCode.designspace -o variable --output-dir ../dist/variable\n# woff2_compress ../dist/variable/*.ttf\n\n# Call fontmake to build the UFOs in to OTF and TTF fonts.\nfontmake -u ../build/*.ufo -o otf --output-dir ../dist/otf\nfontmake -u ../build/*.ufo -o ttf --output-dir ../dist/ttf\n\n# Create woff2 fonts from the TTFs.\nls ../dist/ttf/*.ttf | xargs -I {} woff2_compress {}\nmv ../dist/ttf/*.woff2 ../dist/woff2\n"
  },
  {
    "path": "src/build_from_images.py",
    "content": "import os\nimport sys\nimport math\nfrom math import sqrt\n# from fontTools.designspaceLib import DesignSpaceDocument\nfrom fontTools.pens.areaPen import AreaPen\nfrom fontTools.agl import UV2AGL, AGL2UV\nfrom fontTools.unicodedata import east_asian_width\nfrom ufoLib2.objects import Contour, Glyph, Info, Features, Point\nfrom ufoLib2 import Font\nfrom PIL import Image\nfrom typing import Dict, List, Any\n\nfrom ufoLib2.objects.info import GaspBehavior, GaspRangeRecord\n\nWEIGHT_NAMES = {\n    100: 'Thin',\n    200: 'ExtraLight',\n    300: 'Light',\n    400: 'Regular',\n    500: 'Medium',\n    600: 'DemiBold',\n    700: 'Bold',\n    800: 'ExtraBold',\n    900: 'Black',\n    950: 'ExtraBlack',\n}\n\nTOTAL_HEIGHT = 12\nADVANCE      = 6\nBASELINE     = 10\nASCENT       = BASELINE\nDESCENT      = 2\nX_HEIGHT     = 5\nCAP_HEIGHT   = 7\nLINE_GAP     = (TOTAL_HEIGHT - ASCENT - DESCENT)\nSCALE        = 112\nscaleFactor  = 1\n\ndef adjustCoords(x, y):\n    x *= scaleFactor\n    y *= scaleFactor\n    return (x * SCALE, (BASELINE - y) * SCALE)\n\ndef makeGlyph(name: str, img: Image.Image):\n    # glyphPen = TTGlyphPen(None)\n    glyph = Glyph(name)\n    pen = glyph.getPen() #TransformPen(glyphPen, (1.1, 0, 0, 1.0, 0, 0))\n    vectors: List[List[Any]] = [[list([0, 0]) for _ in range(img.height + 1)] for _ in range(img.width + 1)]\n    for y in range(0, img.height):\n        for x in range(0, img.width):\n            if not img.getpixel((x, y)) == 0:\n                vectors[x][y][0] -= 1\n                vectors[x][y][1] += 1\n                vectors[x][y+1][0] += 1\n                vectors[x+1][y][1] -= 1\n\n    def getMag(x, y, vert):\n        if x >= len(vectors):\n            return None\n        if y >= len(vectors[x]):\n            return None\n        return vectors[x][y][vert]\n\n    def next(x, y, vert):\n        if vert:\n            offset = vectors[x][y][1]\n            n = 0 if offset == -1 else 1\n            s = 0 if offset == 1 else 1\n            if getMag(x, y+offset, 1) == offset:\n                return (x, y+offset, True)\n            if getMag(x-n, y+n, 0) == -offset:\n                return (x-n, y+n, False)\n            if getMag(x-s, y+n, 0) == offset:\n                return (x-s, y+n, False)\n        else:\n            offset = vectors[x][y][0]\n            n = 0 if offset == -1 else 1\n            s = 0 if offset == 1 else 1\n            if getMag(x+offset, y, 0) == offset:\n                return (x+offset, y, False)\n            if getMag(x+n, y-s, 1) == offset:\n                return (x+n, y-s, True)\n            if getMag(x+n, y-n, 1) == -offset:\n                return (x+n, y-n, True)\n        return None\n\n    def follow(x, y, vert):\n        nextPosition = next(x, y, vert)\n        if vert:\n            vectors[x][y][1] = 0\n        else:\n            vectors[x][y][0] = 0\n        if nextPosition is not None:\n            (nx, ny, nv) = nextPosition\n            px = x\n            py = y\n            if nv:\n                if (px != nx):\n                    px = nx\n                    pen.lineTo(adjustCoords(px, py))\n                if (py != ny):\n                    py = ny\n                    pen.lineTo(adjustCoords(px, py))\n            else:\n                if (py != ny):\n                    py = ny\n                    pen.lineTo(adjustCoords(px, py))\n                if (px != nx):\n                    px = nx\n                    pen.lineTo(adjustCoords(px, py))\n\n            follow(nx, ny, nv)\n\n    for y in range(0, img.height):\n        for x in range(0, img.width):\n            if vectors[x][y][0] != 0:\n                pen.moveTo(adjustCoords(x, y))\n                follow(x, y, False)\n                pen.closePath()\n                continue\n            if vectors[x][y][1] != 0:\n                pen.moveTo(adjustCoords(x, y))\n                follow(x, y, True)\n                pen.closePath()\n                continue\n\n    return glyph\n    # return glyphPen.glyph(\n    #     dropImpliedOnCurves = True,\n    # )\n\ndef isClockwise(g: Contour):\n    area = AreaPen()\n    g.draw(area)\n    return area.value < 0\n\ndef dot(ax, ay, bx, by):\n    return ax*bx + ay*by\n\ndef sign(n):\n    return n / abs(n)\n\ndef thicken(g: Glyph, amount: int):\n    factor = amount / 2500\n    xfactor = 1\n    yfactor = 0.5 if amount > 0 else 1\n    for contour in g.contours:\n        clockwise = isClockwise(contour)\n        s = factor * (0.5 if amount > 0 and clockwise else 1)\n        ln = len(contour.points)\n        px = contour.points[ln - 1].x\n        py = contour.points[ln - 1].y\n        sx = contour.points[0].x\n        sy = contour.points[0].y\n        for i in range(ln):\n            point = contour.points[i]\n            next  = contour.points[i + 1] if i < ln - 1 else Point(sx, sy)\n            pnx = next.x - point.x\n            pny = next.y - point.y\n            ppx = px - point.x\n            ppy = py - point.y\n            lnp = sqrt(ppx*ppx + ppy*ppy)\n            lnn = sqrt(pnx*pnx + pny*pny)\n            d = dot(ppx/lnp, ppy/lnp, pnx/lnn, pny/lnn)\n            xo = s * (next.y - py) * (2 if d == 0 else 1) * xfactor\n            yo = s * (px - next.x) * (2 if d == 0 else 1) * yfactor\n            px = point.x\n            py = point.y\n            # Keep ligature parts touching the edge correctly:\n            if amount > 0 or (g.name is not None and \"_\" not in g.name) or point.x != 0 and point.x != ADVANCE * SCALE:\n                point.x += xo\n            point.y += yo\n\n    # Re-align the so the glyph to have a pixel-perfect\n    # left side bearing and baseline placement.\n    g.move((2 * SCALE * factor * xfactor, 2 * SCALE * factor * yfactor))\n    return g\n\ndef thin(g: Glyph, amount: int):\n    thicken(g, -amount)\n    return g\n\ndef italicize(g: Glyph, slope: float):\n    for contour in g.contours:\n        # We skew the x coordinate of points\n        # from the baseline to italicize.\n        for point in contour.points:\n            point.x += point.y * slope\n    return g\n\ndef glyphName(c):\n    return UV2AGL[c] if c in UV2AGL else f\"uni{c:02X}\"\n\ndef charWidth(c):\n    ch = chr(c)\n    east_asian_class = east_asian_width(ch)\n    # For Full Width and Wide characters, return 2, otherwise return 1.\n    if east_asian_class == \"F\" or east_asian_class == \"W\":\n        return 2\n    return 1\n\nSTRIDE_X = 6\nSTRIDE_Y = 12\n\nWHITESPACE_GLYPHS = [ord(' ')]\n\nglyphs: Dict[str, Glyph] = {}\nligaGlyphOrder = []\ncharacterMap = {}\naltCharacterMap = {}\nadvanceWidths = {}\n\nfeatures = {}\nligatures = []\n\ndef getOrd(c):\n    if len(c) == 1:\n        return ord(c)\n    return AGL2UV[c]\n\ndef addLigature(parts, path, suffix, lazy = False):\n    names = [glyphName(getOrd(c)) for c in parts]\n    ligaName = \"_\".join(names)\n    if suffix:\n        ligaName = f\"{ligaName}{suffix}\"\n    partNames = [f\"{ligaName}.{i}\" for i in range(len(parts))]\n    with Image.open(path) as atlas:\n        print(f\"\\\"{\"\".join([chr(getOrd(c)) for c in parts])}\\\": {atlas.width}x{atlas.height}\")\n        atlas = atlas.convert(\"1\")\n\n        x_stride = int(STRIDE_X / scaleFactor)\n        y_stride = int(STRIDE_Y / scaleFactor)\n\n        i = 0\n        for x in range(0, atlas.width, x_stride):\n            glyph = atlas.crop((x, 0, x + x_stride, y_stride))\n            name = partNames[i]\n            glyphs[name] = makeGlyph(name, glyph)\n            ligaGlyphOrder.append(name)\n            advanceWidths[name] = ADVANCE * SCALE\n            i += 1\n\n        glyphs[ligaName] = makeGlyph(ligaName, atlas.crop((0, 0, 0, 0)))\n        ligaGlyphOrder.append(ligaName)\n        advanceWidths[ligaName] = ADVANCE * SCALE\n\n        ligatures.append({\n            \"name\": ligaName,\n            \"from\": names,\n            \"to\": partNames,\n            \"lazy\": lazy,\n        })\n\ndef addGlyphsFromDir(dir, suffix = \"\"):\n    global scaleFactor\n    for file in os.listdir(dir):\n        fullPath = f\"{dir}/{file}\"\n        if os.path.isdir(fullPath):\n            if file.startswith(\"+\"):\n                addGlyphsFromDir(fullPath, suffix = f\"{suffix}.{file[1:]}\")\n            else:\n                addGlyphsFromDir(fullPath, suffix = suffix)\n            continue\n        if file.endswith(\".fea\"):\n            with open(fullPath) as file:\n                features[fullPath] = \"\\n\".join(file.readlines())\n            continue\n        if file.endswith(\".png\"):\n            name: str = file.rsplit(\".\", 1)[0]\n            if \"@\" in name:\n                # e.g. \"name@2X.png\"\n                name, scale = name.split(\"@\")\n                scaleFactor = 1 / int(scale[:-1])\n            else:\n                scaleFactor = 1\n            if name.startswith('\"'):\n                if name.endswith(\"?\"):\n                    addLigature(name[1:-2], fullPath, suffix, True)\n                else:\n                    addLigature(name[1:-1], fullPath, suffix)\n                continue\n            if \"_\" in name and not name.startswith(\"_\"):\n                if name.endswith(\"?\"):\n                    addLigature(name[:-1].split(\"_\"), fullPath, suffix, True)\n                else:\n                    addLigature(name.split(\"_\"), fullPath, suffix)\n                continue\n            if \"-\" in name:\n                (start, end) = name.split(\"-\")\n                start = ord(start[1]) if start.startswith(\"'\") else int(start, 16)\n                end   = ord(end[1]) if end.startswith(\"'\") else int(end, 16)\n                with Image.open(fullPath) as atlas:\n                    print(f\"{file}: {atlas.width}x{atlas.height}, {start}-{end}\")\n                    atlas = atlas.convert(\"1\")\n\n                    x_stride = int(STRIDE_X / scaleFactor)\n                    y_stride = int(STRIDE_Y / scaleFactor)\n\n                    c = start\n                    for y in range(0, atlas.height, y_stride):\n                        x = 0\n                        while x < atlas.width:\n                            width = charWidth(c)\n                            # Safety checks for wide characters\n                            if width > 1:\n                                # Wrap to next row early if wide char would be split by edge of atlas.\n                                if x + x_stride * width > atlas.width:\n                                    break\n                                # If the left half is completely empty, but the right half isn't, the\n                                # author probably didn't realize there was a wide glyph. Warn them.\n                                left_half = atlas.crop((x, y, x + x_stride, y + y_stride))\n                                right_half = atlas.crop((x + x_stride, y, x + x_stride * 2, y + y_stride))\n                                if len(left_half.getcolors() or ()) == 1 and len(right_half.getcolors() or ()) > 1:\n                                    print(f\"WARNING! Potential misalignment in atlas at codepoint {c:02X} due to wide character!\")\n                                    print(\"WARNING! To avoid such misalignments, use gen_template.py for a reference template!\")\n                            glyph = atlas.crop((x, y, x + x_stride * width, y + y_stride))\n                            if c in WHITESPACE_GLYPHS or len(glyph.getcolors() or ()) > 1:\n                                name = glyphName(c)\n                                if suffix:\n                                    name = f\"{name}{suffix}\"\n                                glyphs[name] = makeGlyph(name, glyph)\n                                advanceWidths[name] = ADVANCE * SCALE * width\n                                if not suffix:\n                                    characterMap[c] = name\n                                else:\n                                    altCharacterMap[c] = name\n                            c += 1\n                            x += x_stride * width\n                            if c > end:\n                                break\n                        if c > end:\n                            break\n                continue\n            continue\n\nwith Image.open(\"./glyphs/_.notdef.png\") as notdef:\n    print(f\"_.notdef.png: {notdef.width}x{notdef.height}\")\n    glyphs[\".notdef\"] = makeGlyph(\".notdef\", notdef)\n    advanceWidths[\".notdef\"] = ADVANCE * SCALE\n    characterMap[0] = \".notdef\"\n\naddGlyphsFromDir(\"./glyphs\")\n\n# Duplicate .notdef for U+FFFD (Replacement Character)\nglyphs[\"uniFFFD\"] = glyphs[\".notdef\"]\nadvanceWidths[\"uniFFFD\"] = ADVANCE * SCALE\ncharacterMap[0xFFFD] = \"uniFFFD\"\n\ndef getFamilyName():\n    return \"Pixel Code\"\n\ndef getStyleName(weight: int = 400, italicAngle: float = 0.0):\n    return f\"{WEIGHT_NAMES[weight]}{\" Italic\" if italicAngle > 0.0 else \"\"}\"\n\ndef getStyleNameShort(weight: int = 400, italicAngle: float = 0.0):\n    return f\"{\"Italic\" if italicAngle > 0.0 else \"\"}\" if weight == 400 else getStyleName(weight, italicAngle)\n\ndef getFullNameShort(weight: int = 400, italicAngle: float = 0.0):\n    return f\"{getFamilyName().replace(\" \", \"\")} {getStyleNameShort(weight, italicAngle)}\".rstrip().replace(\" \", \"-\")\n\ndef writeUFO(weight: int = 400, italicAngle: float = 0.0):\n    ufo = Font()\n    ufo.glyphOrder = (\n        [name for _, name in characterMap.items()] +\n        [name for _, name in altCharacterMap.items()] +\n        ligaGlyphOrder\n    )\n    for name, glyph in glyphs.items():\n        g = Glyph(name)\n        g.copyDataFromGlyph(glyph)\n        if weight > 400:\n            thicken(g, weight - 400)\n        elif weight < 400:\n            thin(g, 400 - weight)\n        if italicAngle > 0:\n            italicize(g, math.tan((math.pi / 180) * italicAngle))\n        g.width = advanceWidths[name]\n        ufo.addGlyph(g)\n    for c, name in characterMap.items():\n        ufo[name].unicodes = [c]\n\n    isItalic = italicAngle > 0\n\n    familyName     = getFamilyName()\n    styleName      = getStyleName(weight, italicAngle)\n    styleNameShort = getStyleNameShort(weight, italicAngle)\n    fullName       = f\"{familyName} {styleNameShort}\".strip()\n    majorVersion   = 2\n    minorVersion   = 2\n\n    styleMapFamilyName = f\"{familyName} {WEIGHT_NAMES[weight]}\"\n    styleMapStyleName  = \"regular\"\n    if weight > 400:\n        styleMapStyleName = \"bold\"\n        if italicAngle > 0:\n            styleMapStyleName += \" italic\"\n    elif italicAngle > 0:\n        styleMapStyleName = \"italic\"\n\n    ufo.info = Info(\n        versionMajor = majorVersion,\n        versionMinor = minorVersion,\n\n        # Names\n        familyName           = familyName,\n        styleName            = styleName,\n        postscriptFullName   = fullName,\n\n        # Stylemap\n        styleMapFamilyName = styleMapFamilyName,\n        styleMapStyleName  = styleMapStyleName,\n\n        # Copyright\n        copyright = \"Copyright (c) Qwerasd 2024\",\n\n        # Name Table (name)\n        openTypeNamePreferredFamilyName    = familyName,\n        openTypeNamePreferredSubfamilyName = styleNameShort,\n        openTypeNameCompatibleFullName     = fullName,\n        openTypeNameDescription            = \"A pixel font that's actually good for programming.\",\n        openTypeNameVersion                = f\"Version {majorVersion}.{minorVersion}\",\n        openTypeNameDesigner               = \"Qwerasd\",\n\n        # Metrics\n        unitsPerEm  = 1008,\n        descender   =    DESCENT * SCALE,\n        ascender    =     ASCENT * SCALE,\n        xHeight     =   X_HEIGHT * SCALE,\n        capHeight   = CAP_HEIGHT * SCALE,\n        # Italic angle in counter-clockwise degrees from the vertical.\n        # Zero for upright text, negative for text that leans to the right (forward).\n        italicAngle = -italicAngle,\n\n        # Horizontal Header (hhea)\n        openTypeHheaAscender  = BASELINE * SCALE - 1,\n        openTypeHheaDescender = -DESCENT * SCALE + 1,\n        openTypeHheaLineGap   = LINE_GAP * SCALE,\n\n        # OS/2\n        openTypeOS2Selection     = [7], # bit 7: USE_TYPO_METRICS\n        openTypeOS2TypoAscender  =   ASCENT * SCALE - 1,\n        openTypeOS2TypoDescender = -DESCENT * SCALE + 1,\n        openTypeOS2TypoLineGap   = LINE_GAP * SCALE,\n        openTypeOS2WinAscent     = BASELINE * SCALE,\n        openTypeOS2WinDescent    = (DESCENT + LINE_GAP) * SCALE,\n        openTypeOS2Panose        = [\n            # https://monotype.github.io/panose/pan2.htm\n            # Family Kind\n            # (2 = Latin Text)\n            2,\n            # Serif Style Classification\n            # (0 = Any)\n            0,\n            # Weight\n            # (0 = Any)\n            0,\n            # Proportion\n            # (9 = Monospaced)\n            9,\n            # Contrast\n            # (0 = Any)\n            0,\n            # Stroke Variation\n            # (0 = Any)\n            0,\n            # Arm Style\n            # (0 = Any)\n            0,\n            # Letterform\n            # (5 = Oblique/Square, 8 = Normal/Square)\n            5 if isItalic else 8,\n            # Midline\n            # (0 = Any)\n            0,\n            # X-height\n            # (3 = Constant/Standard)\n            3\n        ],\n        openTypeOS2WeightClass   = weight,\n        openTypeOS2VendorID      = \"qwer\",\n\n        # Postscript (post)\n        postscriptUnderlinePosition  = int(-2 * SCALE),\n        postscriptUnderlineThickness = int(SCALE),\n        postscriptIsFixedPitch       = True,\n    )\n\n    # Grid-fitting and Scan-conversion Procedure (gasp)\n    ufo.info.openTypeGaspRangeRecords = [\n        GaspRangeRecord(\n            0xFFFF,\n            [GaspBehavior.GRIDFIT]\n        )\n    ]\n\n    combinedFea = \"\"\n    afterLiga = \"\"\n\n    for file, fea in features.items():\n        if fea.startswith(\"# AFTER_LIGATURES\"):\n            afterLiga += f\"# {file}\\n\"\n            afterLiga += f\"{fea}\\n\"\n            continue\n        combinedFea += f\"# {file}\\n\"\n        combinedFea += f\"{fea}\\n\"\n\n    ligaFea = \"# GENERATED/LIGATURES\\n\"\n    ligaFea += \"feature liga {\\n\"\n    ligatures.sort(key = lambda liga: len(liga[\"from\"]), reverse = True)\n    for ligature in ligatures:\n        if ligature[\"lazy\"]:\n            ligaFea += f\"sub space {\" \".join([f\"{c}'\" for c in ligature[\"from\"]])} space by {ligature[\"name\"]};\\n\"\n        else:\n            ligaFea += f\"sub {\" \".join(ligature[\"from\"])} by {ligature[\"name\"]};\\n\"\n    for ligature in ligatures:\n        ligaFea += f\"sub {ligature[\"name\"]} by {\" \".join(ligature[\"to\"])};\\n\"\n    ligaFea += \"} liga;\\n\"\n    combinedFea += ligaFea\n    combinedFea += afterLiga\n\n    ufo.features = Features(combinedFea)\n\n    ufoPath = os.path.abspath(f\"../build/{getFullNameShort(weight, italicAngle)}.ufo\")\n\n    ufo.save(ufoPath, overwrite = True)\n\n    return ufoPath\n\n# Ensure the build directory exists.\nif not os.path.exists(\"../build\"):\n    os.mkdir(\"../build\")\n\nif not os.path.exists(\"../build/instances\"):\n    os.mkdir(\"../build/instances\")\n\n# doc = DesignSpaceDocument()\n# doc.addAxisDescriptor(\n#     maximum = 950,\n#     minimum = 100,\n#     default = 400,\n#     name    = \"weight\",\n#     tag     = \"wght\",\n# )\n# doc.addAxisDescriptor(\n#     maximum = 14,\n#     minimum = 0,\n#     default = 0,\n#     name    = \"slant\",\n#     tag     = \"slnt\",\n# )\n\nMASTER_WEIGHTS = [100, 400, 950]\n\ngenWeights = WEIGHT_NAMES.keys() if len(sys.argv) < 2 else map(int, sys.argv[1:])\n\nfor weight in genWeights:\n    regularPath = writeUFO(weight)\n    italicPath  = writeUFO(weight, 14)\n    #\n    # if weight in MASTER_WEIGHTS:\n    #     doc.addSourceDescriptor(\n    #         path = regularPath,\n    #         name = f\"master.PixelCode.{getStyleName(weight)}\",\n    #         familyName = getFamilyName(),\n    #         styleName  = getStyleName(weight),\n    #         location = dict(weight = weight, slant = 0),\n    #         copyLib = True,\n    #         copyInfo = True,\n    #         copyGroups = True,\n    #         copyFeatures = True,\n    #     )\n    #     doc.addSourceDescriptor(\n    #         path = italicPath,\n    #         name = f\"master.PixelCode.{getStyleName(weight, 14)}\",\n    #         familyName = getFamilyName(),\n    #         styleName  = getStyleName(weight, 14),\n    #         location = dict(weight = weight, slant = 14),\n    #         copyLib = True,\n    #         copyInfo = True,\n    #         copyGroups = True,\n    #         copyFeatures = True,\n    #     )\n    #\n    # doc.addInstanceDescriptor(\n    #     name = f\"instance_{getStyleName(weight)}\",\n    #     familyName = getFamilyName(),\n    #     styleName  = getStyleName(weight),\n    #     path       = os.path.abspath(f\"../build/instances/{getFullNameShort(weight)}.ufo\"),\n    #     location   = dict(weight = weight, slant = 0),\n    #     kerning    = False,\n    #     info       = True,\n    #     postScriptFontName = getFullNameShort(weight),\n    #     styleMapFamilyName = getFamilyName(),\n    #     styleMapStyleName  = getStyleName(weight),\n    # )\n    # doc.addInstanceDescriptor(\n    #     name = f\"instance_{getStyleName(weight, 14)}\",\n    #     familyName = getFamilyName(),\n    #     styleName  = getStyleName(weight, 14),\n    #     path       = os.path.abspath(f\"../build/instances/{getFullNameShort(weight, 14)}.ufo\"),\n    #     location   = dict(weight = weight, slant = 14),\n    #     kerning    = False,\n    #     info       = True,\n    #     postScriptFontName = getFullNameShort(weight, 14),\n    #     styleMapFamilyName = getFamilyName(),\n    #     styleMapStyleName  = getStyleName(weight, 14),\n    # )\n#\n# doc.addInstanceDescriptor(\n#     name = \"instance_Italic\",\n#     familyName = getFamilyName(),\n#     styleName  = \"Italic\",\n#     path       = os.path.abspath(f\"../build/instances/{getFamilyName().replace(\" \", \"\")}-Italic.ufo\"),\n#     location   = dict(weight = 400, slant = 14),\n#     kerning    = False,\n#     info       = True,\n#     postScriptFontName = f\"{getFamilyName().replace(\" \", \"\")}-Italic\",\n#     styleMapFamilyName = getFamilyName(),\n#     styleMapStyleName  = \"Italic\",\n# )\n#\n# doc.write(\"../build/PixelCode.designspace\")\n\n\n"
  },
  {
    "path": "src/gen_braille.py",
    "content": "from PIL import Image, ImageDraw\n\nCELL_WIDTH = 6\nCELL_HEIGHT = 12\n\nIMAGE_WIDTH = 16 * CELL_WIDTH\nIMAGE_HEIGHT = 16 * CELL_HEIGHT\n\ncanvas = Image.new('RGB', (IMAGE_WIDTH, IMAGE_HEIGHT), 'black')\ndraw   = ImageDraw.Draw(canvas)\n\ndef drawPattern(i, x, y):\n    if i & 0b00000001:\n        draw.point((x + 1, y + 4), 'white')\n    if i & 0b00000010:\n        draw.point((x + 1, y + 6), 'white')\n    if i & 0b00000100:\n        draw.point((x + 1, y + 8), 'white')\n    if i & 0b00001000:\n        draw.point((x + 3, y + 4), 'white')\n    if i & 0b00010000:\n        draw.point((x + 3, y + 6), 'white')\n    if i & 0b00100000:\n        draw.point((x + 3, y + 8), 'white')\n    if i & 0b01000000:\n        draw.point((x + 1, y + 10), 'white')\n    if i & 0b10000000:\n        draw.point((x + 3, y + 10), 'white')\n\nx = 0\ny = 0\nfor i in range(256):\n    drawPattern(i, x, y)\n    x += CELL_WIDTH\n    if x >= IMAGE_WIDTH:\n        x = 0\n        y += CELL_HEIGHT\n\ncanvas.save(\"./glyphs/2800-28FF.png\")\n"
  },
  {
    "path": "src/gen_charlist.py",
    "content": "from fontTools.unicodedata import east_asian_width\nfrom fontTools.ttLib import TTFont\nfrom html import escape\n\nFONT = TTFont(\"../dist/ttf/PixelCode.ttf\")\n\ndef charWidth(c):\n    ch = chr(c)\n    east_asian_class = east_asian_width(ch)\n    # For Full Width and Wide characters, return 2, otherwise return 1.\n    if east_asian_class == \"F\" or east_asian_class == \"W\":\n        return 2\n    return 1\n\ndef printAllChars(font):\n    chars = {0}\n    for cmap in font['cmap'].tables:\n        if cmap.isUnicode():\n            for c in cmap.cmap:\n                chars.add(c)\n    listed = [c for c in chars]\n    listed.sort()\n    x = 0\n    for c in listed:\n        w = charWidth(c)\n        print(f\"{escape(chr(c))}{\"\" if w > 1 else \" \"}\", end=\"\")\n        x += 2\n        if x >= 64:\n            print(\"\")\n            x = 0\n\n\nprintAllChars(FONT)\n"
  },
  {
    "path": "src/gen_template.py",
    "content": "import sys\nimport os\nfrom PIL import Image, ImageFont, ImageDraw\nfrom fontTools.unicodedata import east_asian_width\nfrom fontTools.ttLib import TTFont\nfrom math import ceil\n\ndef printUsage():\n    print(\"gen_template: Creates a (high resolution) reference template image for a codepoint range.\")\n    print(\"Usage: gen_template <start> <end> [columns]\")\n    print(\"Example: gen_template 0000 007F 16\")\n    exit(1)\n\nif len(sys.argv) < 3:\n    printUsage()\n\nstart   = 0\nend     = 0\ncolumns = 0\n\ntry:\n    start   = int(sys.argv[1], 16)\n    end     = int(sys.argv[2], 16)\n    columns = int(sys.argv[3]) if len(sys.argv) >= 4 else 16\nexcept Exception:\n    printUsage()\n\ndef charWidth(c):\n    ch = chr(c)\n    east_asian_class = east_asian_width(ch)\n    # For Full Width and Wide characters, return 2, otherwise return 1.\n    if east_asian_class == \"F\" or east_asian_class == \"W\":\n        return 2\n    return 1\n\nGLYPH_COUNT = 1 + end - start\n\nCOLS = 0\nROWS = 1\n\nx = 0\nfor c in range(GLYPH_COUNT):\n    cp = c + start\n    w = charWidth(cp)\n    if w > 1 and x == columns - 1:\n        ROWS += 1\n        x = 0\n    x += w\n    if x > columns:\n        x -= columns\n        ROWS += 1\n    COLS = max(x, COLS)\n\nLEFT_BEARING  = 0\nRIGHT_BEARING = 1\nADVANCE       = 6\nNON_SPACE_WIDTH = ADVANCE - RIGHT_BEARING - LEFT_BEARING\n\nBASELINE = 10\nDESCENT  = 1\nLEADING  = 1\nTOTAL_HEIGHT = BASELINE + DESCENT + LEADING\n\nX_HEIGHT   = 5\nCAP_HEIGHT = 7\n\nTEMPLATE_CELL_WIDTH  = 128\nTEMPLATE_CELL_SCALE  = (TEMPLATE_CELL_WIDTH / ADVANCE)\nTEMPLATE_CELL_HEIGHT = ceil(TEMPLATE_CELL_SCALE * TOTAL_HEIGHT)\n\nIMAGE_WIDTH  = TEMPLATE_CELL_WIDTH * COLS\nIMAGE_HEIGHT = TEMPLATE_CELL_HEIGHT * ROWS\n\ncanvas = Image.new('RGB', (IMAGE_WIDTH, IMAGE_HEIGHT), 'black')\ndraw   = ImageDraw.Draw(canvas)\n\nFONT_DIRS = []\nif sys.platform == \"linux\":\n    FONT_DIRS = ['/usr/share/fonts', '/usr/local/share/fonts', os.path.expanduser('~/.fonts')]\nelif sys.platform == \"darwin\":\n    FONT_DIRS = ['/System/Library/Fonts', '/System/Library/Fonts/Supplemental', '/Library/Fonts', os.path.expanduser('~/Library/Fonts')]\n\ndef findFont(name):\n    for fdir in FONT_DIRS:\n        fpath = os.path.join(fdir, name)\n        if os.path.isfile(fpath):\n            return fpath\n\n# Replace this list with one tuned to your system.\nFONTS = [p for p in [findFont(f) for f in [\n    \"FiraCode-VF.ttf\",\n    \"FiraCodeNerdFont-Regular.ttf\",\n    \"Apple Symbols.ttf\",\n    \"ZapfDingbats.ttf\",\n    \"NotoEmoji-Regular.ttf\",\n    \"NotoSans-Regular.ttf\",\n    \"Times New Roman.ttf\",\n    \"Arial Unicode.ttf\",\n    # Last ditch effort\n    \"unifont-15.1.05.otf\",\n    \"unifont_upper-15.1.05.otf\",\n    \"unifont_csur-15.1.05.otf\"\n]] if p is not None]\n\nTT_FONTS = dict()\nfor f in FONTS:\n    TT_FONTS[f] = TTFont(f)\n\nprint(\"Using fonts:\")\nprint(FONTS)\n\ndef charInFont(unicode_char, font):\n    for cmap in font['cmap'].tables:\n        if cmap.isUnicode():\n            if ord(unicode_char) in cmap.cmap:\n                return True\n    return False\n\ndef getFontFor(char):\n    for fontpath in FONTS:\n        font = TT_FONTS[fontpath]\n        if 'cmap' in font and charInFont(char, font):\n            return fontpath\n    # Fallback to default font\n    return FONTS[0]\n\nIMAGE_FONTS = dict()\nfor font in FONTS:\n    IMAGE_FONTS[font] = ImageFont.truetype(font, int((CAP_HEIGHT + DESCENT + LEADING) * TEMPLATE_CELL_SCALE))\n\ndef glyphFontFor(char):\n    return IMAGE_FONTS[getFontFor(char)]\n\nlabel_font = ImageFont.truetype(\"Arial.ttf\", int(TEMPLATE_CELL_WIDTH / 15))\n\nwide_i = 0\nfor i in range(GLYPH_COUNT):\n    cp = start + i\n    if charWidth(cp) > 1 and wide_i % columns == columns - 1:\n        wide_i += 1\n    x = wide_i % columns\n    y = int(wide_i / columns)\n    x *= ADVANCE\n    y *= TOTAL_HEIGHT\n    if charWidth(cp) > 1:\n        draw.rectangle([(x * TEMPLATE_CELL_SCALE, y * TEMPLATE_CELL_SCALE), ((x + ADVANCE * 2) * TEMPLATE_CELL_SCALE, (y + TOTAL_HEIGHT) * TEMPLATE_CELL_SCALE)], '#331212')\n        x += ADVANCE / 2\n    x += LEFT_BEARING + NON_SPACE_WIDTH / 2\n    y += BASELINE\n    x *= TEMPLATE_CELL_SCALE\n    y *= TEMPLATE_CELL_SCALE\n    draw.text((x, y), chr(cp), '#9a9a9a', font = glyphFontFor(chr(cp)), anchor = 'ms')\n    wide_i += charWidth(cp)\n\nfor i in range(COLS):\n    x = i * ADVANCE\n    draw.line([(x * TEMPLATE_CELL_SCALE, 0), (x * TEMPLATE_CELL_SCALE, IMAGE_HEIGHT)], fill = 'white', width = 2)\n\n    x += LEFT_BEARING\n    # draw.line([(x * TEMPLATE_CELL_SCALE, 0), (x * TEMPLATE_CELL_SCALE, IMAGE_HEIGHT)], fill = 'blue', width = 2)\n\n    x += NON_SPACE_WIDTH\n    draw.line([(x * TEMPLATE_CELL_SCALE, 0), (x * TEMPLATE_CELL_SCALE, IMAGE_HEIGHT)], fill = 'blue', width = 2)\n\n    x += RIGHT_BEARING\n    draw.line([(x * TEMPLATE_CELL_SCALE, 0), (x * TEMPLATE_CELL_SCALE, IMAGE_HEIGHT)], fill = 'white', width = 2)\n\nfor i in range(ROWS):\n    y = i * TOTAL_HEIGHT\n    draw.line([(0, y * TEMPLATE_CELL_SCALE), (IMAGE_WIDTH, y * TEMPLATE_CELL_SCALE)], fill = 'white', width = 2)\n\n    y += BASELINE - CAP_HEIGHT\n    draw.line([(0, y * TEMPLATE_CELL_SCALE), (IMAGE_WIDTH, y * TEMPLATE_CELL_SCALE)], fill = 'magenta', width = 2)\n\n    y += CAP_HEIGHT - X_HEIGHT\n    draw.line([(0, y * TEMPLATE_CELL_SCALE), (IMAGE_WIDTH, y * TEMPLATE_CELL_SCALE)], fill = 'darkgray', width = 2)\n\n    y += X_HEIGHT\n    draw.line([(0, y * TEMPLATE_CELL_SCALE), (IMAGE_WIDTH, y * TEMPLATE_CELL_SCALE)], fill = 'orange', width = 2)\n\n    y += DESCENT\n    draw.line([(0, y * TEMPLATE_CELL_SCALE), (IMAGE_WIDTH, y * TEMPLATE_CELL_SCALE)], fill = 'darkgray', width = 2)\n\n    y += LEADING\n    draw.line([(0, y * TEMPLATE_CELL_SCALE), (IMAGE_WIDTH, y * TEMPLATE_CELL_SCALE)], fill = 'white', width = 2)\n\ncanvas.save(f\"./TEMPLATE_{start:04X}-{end:04X}.png\")\nimg = Image.new('RGB', (COLS * ADVANCE, ROWS * TOTAL_HEIGHT), 'black')\nimg.save(f\"./{start:04X}-{end:04X}.png\")\n\n\n\n"
  },
  {
    "path": "src/glyphs/+calt/calt.fea",
    "content": "# AFTER_LIGATURES\n@upper = [ zero one two three four five six seven eight nine A - Z Agrave Aacute Acircumflex Atilde Adieresis Aring AE Ccedilla Egrave Eacute Ecircumflex Edieresis Igrave Iacute Icircumflex Idieresis Eth Ntilde Ograve Oacute Ocircumflex Otilde Odieresis Oslash Ugrave Uacute Ucircumflex Udieresis Yacute Thorn germandbls colon.calt hyphen_greater less_hyphen less_exclam_hyphen_hyphen hyphen_hyphen_greater ];\n@lower = [ a - z agrave aacute acircumflex atilde adieresis aring ae ccedilla egrave eacute ecircumflex edieresis igrave iacute icircumflex idieresis eth ntilde ograve oacute ocircumflex otilde odieresis oslash ugrave uacute ucircumflex udieresis yacute thorn ydieresis zero.onum one.onum two.onum three.onum four.onum five.onum six.onum seven.onum eight.onum nine.onum plus.calt hyphen.calt asterisk.calt l.shifted ];\n@digit = [ zero one two three four five six seven eight nine zero.onum one.onum two.onum three.onum four.onum five.onum six.onum seven.onum eight.onum nine.onum ];\n@hex_digit = [ @digit a b c d e f A B C D E F ];\n@zero = [ zero zero.onum ];\n\nlookup CPUNCT {\n  sub plus by plus.calt;\n  sub hyphen by hyphen.calt;\n  sub asterisk by asterisk.calt;\n  sub colon by colon.calt;\n  sub x by x.calt;\n} CPUNCT;\n\nfeature calt {\n  # *EQ *eq\n  ignore sub @upper asterisk' space @lower;\n  ignore sub @upper space asterisk' space @lower;\n  ignore sub asterisk asterisk' asterisk' @lower;\n  ignore sub asterisk asterisk' asterisk' space @lower;\n  sub asterisk' lookup CPUNCT @lower;\n  sub asterisk' lookup CPUNCT space @lower;\n  sub asterisk' lookup CPUNCT asterisk @lower;\n  sub asterisk' lookup CPUNCT asterisk space @lower;\n\n  # a:e A:E\n  sub @upper colon' lookup CPUNCT @upper;\n  sub @upper space colon' lookup CPUNCT @upper;\n  sub @upper colon' lookup CPUNCT space @upper;\n  sub @upper space colon' lookup CPUNCT space @upper;\n\n  # C-O c-o\n  ignore sub hyphen hyphen' @lower;\n  sub hyphen' lookup CPUNCT @lower;\n\n  # X+Z x+z\n  ignore sub plus plus' @lower;\n  sub plus' lookup CPUNCT @lower;\n\n  # 0xFF 1920x1080\n  sub @zero x' lookup CPUNCT @hex_digit;\n  sub @digit x' lookup CPUNCT @digit;\n} calt;\n"
  },
  {
    "path": "src/glyphs/+onum/onum.fea",
    "content": "@digits = [zero one two three four five six seven eight nine];\n@digits.onum = [zero.onum one.onum two.onum three.onum four.onum five.onum six.onum seven.onum eight.onum nine.onum];\n\nfeature onum {\n  sub @digits by @digits.onum;\n} onum;\n"
  },
  {
    "path": "src/glyphs/+shifted/shifted.fea",
    "content": "@open_right = [i igrave iacute icircumflex idieresis l.shifted u ugrave uacute ucircumflex udieresis q t];\n@shiftable = [l];\n\nlookup SHIFT_LETTER {\n  sub l by l.shifted;\n} SHIFT_LETTER;\n\nfeature ss20 {\n  featureNames {\n    name \"Pseudo-kerning\";\n  };\n  sub @open_right @shiftable' lookup SHIFT_LETTER;\n} ss20;\n"
  },
  {
    "path": "src/glyphs/+ss01/ss01.fea",
    "content": "feature ss01 {\n  featureNames {\n    name \"Straight Comma\";\n  };\n  sub comma by comma.ss01;\n  sub semicolon by semicolon.ss01;\n} ss01;\n"
  },
  {
    "path": "src/glyphs/ligatures/ignore.fea",
    "content": "# AFTER_LIGATURES\n\n@equalish = [equal equal_equal.0 equal_equal_equal.0];\n@equalend = [equal equal_equal.1 equal_equal_equal.2];\n@slashish = [slash slash_slash.0 slash_slash_slash.0];\n@slashend = [slash slash_slash.1 slash_slash_slash.2];\n@asterish = [asterisk asterisk.calt asterisk_asterisk.0];\n@asterend = [asterisk asterisk.calt asterisk_asterisk.1];\n@barish = [bar bar_bar.0];\n@barend = [bar bar_bar.1];\nfeature liga {\n  # == and ===\n  sub @equalend' @equalish by equal;\n  sub equal_equal_equal.1' equal_equal_equal.2 @equalish by equal;\n  sub equal_equal_equal.0' equal_equal_equal.1 equal_equal_equal.2 @equalish by equal;\n\n  sub @equalend @equalish' by equal;\n  sub @equalend equal_equal_equal.1' by equal;\n  sub @equalend equal_equal_equal.2' by equal;\n  sub @equalend @equalish @equalend' by equal;\n\n  # // and ///\n  sub @slashend' @slashish by slash;\n  sub slash_slash_slash.1' slash_slash_slash.2 @slashish by slash;\n  sub slash_slash_slash.0' slash_slash_slash.1 slash_slash_slash.2 @slashish by slash;\n\n  sub @slashend @slashish' by slash;\n  sub @slashend slash_slash_slash.1' by slash;\n  sub @slashend slash_slash_slash.2' by slash;\n  sub @slashend @slashish @slashend' by slash;\n\n  # ** and ||\n  sub @asterend' @asterish by asterisk;\n  sub @asterend @asterish' by asterisk;\n  sub @asterish' @asterend @asterish by asterisk;\n  sub @asterend @asterish @asterend' by asterisk;\n  sub @barend' @barish by bar;\n  sub @barend @barish' by bar;\n  sub @barish' @barend @barish by bar;\n  sub @barend @barish @barend' by bar;\n} liga;\n"
  },
  {
    "path": "src/watch.py",
    "content": "import os\nimport time\nfrom watchdog.observers import Observer\nfrom watchdog.events import FileSystemEvent, FileSystemEventHandler\n\nclass ReloadingHandler(FileSystemEventHandler):\n    def on_any_event(self, event: FileSystemEvent):\n        print(event)\n        print(\"File changed, rebuilding...\")\n        os.system(\"python3 ./build_from_images.py 400\")\n        print(\"Done!\")\n\nobserver = Observer()\nhandler = ReloadingHandler()\nobserver.schedule(handler, \"./glyphs/\", recursive = True)\nobserver.start()\ntry:\n    while True:\n        time.sleep(1)\nexcept KeyboardInterrupt:\n    observer.stop()\nobserver.join()\n"
  }
]