├── .gitignore ├── .prettierrc ├── 404.html ├── README.md ├── apple-touch-icon.png ├── bun.lockb ├── favicon.ico ├── index.html ├── manifest.webmanifest ├── package-lock.json ├── package.json └── src ├── css ├── loading.css ├── mobile.css ├── non_essential.css ├── section_1.css ├── section_10.css ├── section_2.css ├── section_3.css ├── section_4.css ├── section_5.css ├── section_6.css ├── section_7.css ├── section_8.css ├── section_9.css └── style.css ├── favicon ├── icon-192.png ├── icon-512.png └── icon-512.svg ├── features ├── aalt.fea ├── balance.fea ├── barhyphen.fea ├── colon.fea ├── cv04.fea ├── frac.fea ├── kern_smartkerning.fea ├── liga.fea ├── none.fea ├── pipe.fea ├── posa.fea ├── progress.fea ├── ss01_less_equal-copy.fea ├── ss01_less_equal.fea ├── ss02_arrows.fea ├── ss03_case.fea ├── ss03_case_inter.fea ├── ss04_ellipsis.fea ├── ss05_smartkerning copy 2.fea ├── ss05_smartkerning copy.fea ├── ss05_smartkerning.fea ├── ss06_smartkerning.fea ├── test.fea └── zero.fea ├── fonts ├── CommitMono-1.143.zip ├── fontlab │ ├── CommitMonoV143-200Italic.otf │ ├── CommitMonoV143-200Regular.otf │ ├── CommitMonoV143-225Italic.otf │ ├── CommitMonoV143-225Regular.otf │ ├── CommitMonoV143-250Italic.otf │ ├── CommitMonoV143-250Regular.otf │ ├── CommitMonoV143-275Italic.otf │ ├── CommitMonoV143-275Regular.otf │ ├── CommitMonoV143-300Italic.otf │ ├── CommitMonoV143-300Regular.otf │ ├── CommitMonoV143-325Italic.otf │ ├── CommitMonoV143-325Regular.otf │ ├── CommitMonoV143-350Italic.otf │ ├── CommitMonoV143-350Regular.otf │ ├── CommitMonoV143-375Italic.otf │ ├── CommitMonoV143-375Regular.otf │ ├── CommitMonoV143-400Italic.otf │ ├── CommitMonoV143-400Regular.otf │ ├── CommitMonoV143-425Italic.otf │ ├── CommitMonoV143-425Regular.otf │ ├── CommitMonoV143-450Italic.otf │ ├── CommitMonoV143-450Regular.otf │ ├── CommitMonoV143-475Italic.otf │ ├── CommitMonoV143-475Regular.otf │ ├── CommitMonoV143-500Italic.otf │ ├── CommitMonoV143-500Regular.otf │ ├── CommitMonoV143-525Italic.otf │ ├── CommitMonoV143-525Regular.otf │ ├── CommitMonoV143-550Italic.otf │ ├── CommitMonoV143-550Regular.otf │ ├── CommitMonoV143-575Italic.otf │ ├── CommitMonoV143-575Regular.otf │ ├── CommitMonoV143-600Italic.otf │ ├── CommitMonoV143-600Regular.otf │ ├── CommitMonoV143-625Italic.otf │ ├── CommitMonoV143-625Regular.otf │ ├── CommitMonoV143-650Italic.otf │ ├── CommitMonoV143-650Regular.otf │ ├── CommitMonoV143-675Italic.otf │ ├── CommitMonoV143-675Regular.otf │ ├── CommitMonoV143-700Italic.otf │ ├── CommitMonoV143-700Regular.otf │ ├── CommitMonoV143-VF.ttf │ └── CommitMonoV143-VF.woff2 └── other │ ├── CascadiaCode.woff2 │ ├── Consolas.woff2 │ ├── FiraCode.woff2 │ ├── JetBrainsMono.woff2 │ ├── Menlo.woff2 │ └── SourceCodePro.woff2 ├── img ├── commitmono.png └── familiar │ ├── commit_mono.svg │ ├── fira_mono.svg │ ├── franklin_gothic.svg │ ├── letter_gothic.svg │ └── untitled_sans.svg ├── js ├── code_section.js ├── distinct_section.js ├── docs_section.js ├── download_wizard.js ├── dynamic_favicon.js ├── example_section.js ├── familiar_section.js ├── intelligent_section.js ├── nav.js ├── opentype.min.js ├── section.js ├── start_functions.js ├── table_section.js ├── utility_functions.js ├── website_data.js └── zip.min.js ├── language_examples ├── brainfuck.bf ├── c++.cpp ├── fortran.f ├── html.html ├── java.java ├── javascript.js ├── kotlin.kts ├── php.php ├── python.py ├── ruby_example.rb ├── rust.rs └── typescript.ts ├── tests ├── braille.html ├── braille.js ├── calt.js ├── classes.html ├── f.js ├── instances.html ├── letter_group_test.js └── tables.html └── txt ├── featuretest.txt ├── installation.txt ├── license.txt ├── todo.txt ├── ttfautohint.txt └── woff2_conversion_guide.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | bun.lockb 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "tabWidth": 4, 4 | "semi": false 5 | } 6 | -------------------------------------------------------------------------------- /404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Commit Mono. Neutral programming typeface. 17 | 18 | 19 | 50 | 51 | 52 |

404

53 |

page not found

54 |
55 | Press ENTER to go to home page. 56 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Commit Mono 2 | 3 | Commit Mono is an anonymous and neutral programming typeface focused on creating a better reading experience. 4 | 5 | [**Customize download, explore the font**](https://commitmono.com/) 6 | 7 | [**Download latest default version**](https://github.com/eigilnikolajsen/commit-mono/releases/latest/) 8 | 9 |
10 | 11 | If you wish to support this project directly [**buy me a coffee**](https://www.buymeacoffee.com/eigilnikolajsen). 12 | 13 | ![Commit Mono concept image](/src/img/commitmono.png) 14 | -------------------------------------------------------------------------------- /apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/apple-touch-icon.png -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/bun.lockb -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/favicon.ico -------------------------------------------------------------------------------- /manifest.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "icons": [ 3 | { "src": "/src/favicon/icon-192.png", "type": "image/png", "sizes": "192x192" }, 4 | { "src": "/src/favicon/icon-512.png", "type": "image/png", "sizes": "512x512" } 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "commit-webtests", 3 | "version": "0.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "commit-webtests", 9 | "version": "0.0.0", 10 | "devDependencies": { 11 | "vite": "^5.0.12" 12 | } 13 | }, 14 | "node_modules/@esbuild/darwin-x64": { 15 | "version": "0.19.11", 16 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz", 17 | "integrity": "sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==", 18 | "cpu": [ 19 | "x64" 20 | ], 21 | "dev": true, 22 | "optional": true, 23 | "os": [ 24 | "darwin" 25 | ], 26 | "engines": { 27 | "node": ">=12" 28 | } 29 | }, 30 | "node_modules/@rollup/rollup-darwin-x64": { 31 | "version": "4.9.6", 32 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz", 33 | "integrity": "sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==", 34 | "cpu": [ 35 | "x64" 36 | ], 37 | "dev": true, 38 | "optional": true, 39 | "os": [ 40 | "darwin" 41 | ] 42 | }, 43 | "node_modules/@types/estree": { 44 | "version": "1.0.5", 45 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", 46 | "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", 47 | "dev": true 48 | }, 49 | "node_modules/esbuild": { 50 | "version": "0.19.11", 51 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.11.tgz", 52 | "integrity": "sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==", 53 | "dev": true, 54 | "hasInstallScript": true, 55 | "bin": { 56 | "esbuild": "bin/esbuild" 57 | }, 58 | "engines": { 59 | "node": ">=12" 60 | }, 61 | "optionalDependencies": { 62 | "@esbuild/aix-ppc64": "0.19.11", 63 | "@esbuild/android-arm": "0.19.11", 64 | "@esbuild/android-arm64": "0.19.11", 65 | "@esbuild/android-x64": "0.19.11", 66 | "@esbuild/darwin-arm64": "0.19.11", 67 | "@esbuild/darwin-x64": "0.19.11", 68 | "@esbuild/freebsd-arm64": "0.19.11", 69 | "@esbuild/freebsd-x64": "0.19.11", 70 | "@esbuild/linux-arm": "0.19.11", 71 | "@esbuild/linux-arm64": "0.19.11", 72 | "@esbuild/linux-ia32": "0.19.11", 73 | "@esbuild/linux-loong64": "0.19.11", 74 | "@esbuild/linux-mips64el": "0.19.11", 75 | "@esbuild/linux-ppc64": "0.19.11", 76 | "@esbuild/linux-riscv64": "0.19.11", 77 | "@esbuild/linux-s390x": "0.19.11", 78 | "@esbuild/linux-x64": "0.19.11", 79 | "@esbuild/netbsd-x64": "0.19.11", 80 | "@esbuild/openbsd-x64": "0.19.11", 81 | "@esbuild/sunos-x64": "0.19.11", 82 | "@esbuild/win32-arm64": "0.19.11", 83 | "@esbuild/win32-ia32": "0.19.11", 84 | "@esbuild/win32-x64": "0.19.11" 85 | } 86 | }, 87 | "node_modules/fsevents": { 88 | "version": "2.3.3", 89 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 90 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 91 | "dev": true, 92 | "hasInstallScript": true, 93 | "optional": true, 94 | "os": [ 95 | "darwin" 96 | ], 97 | "engines": { 98 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 99 | } 100 | }, 101 | "node_modules/nanoid": { 102 | "version": "3.3.7", 103 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", 104 | "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", 105 | "dev": true, 106 | "funding": [ 107 | { 108 | "type": "github", 109 | "url": "https://github.com/sponsors/ai" 110 | } 111 | ], 112 | "bin": { 113 | "nanoid": "bin/nanoid.cjs" 114 | }, 115 | "engines": { 116 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 117 | } 118 | }, 119 | "node_modules/picocolors": { 120 | "version": "1.0.0", 121 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 122 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 123 | "dev": true 124 | }, 125 | "node_modules/postcss": { 126 | "version": "8.4.33", 127 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", 128 | "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", 129 | "dev": true, 130 | "funding": [ 131 | { 132 | "type": "opencollective", 133 | "url": "https://opencollective.com/postcss/" 134 | }, 135 | { 136 | "type": "tidelift", 137 | "url": "https://tidelift.com/funding/github/npm/postcss" 138 | }, 139 | { 140 | "type": "github", 141 | "url": "https://github.com/sponsors/ai" 142 | } 143 | ], 144 | "dependencies": { 145 | "nanoid": "^3.3.7", 146 | "picocolors": "^1.0.0", 147 | "source-map-js": "^1.0.2" 148 | }, 149 | "engines": { 150 | "node": "^10 || ^12 || >=14" 151 | } 152 | }, 153 | "node_modules/rollup": { 154 | "version": "4.9.6", 155 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.6.tgz", 156 | "integrity": "sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==", 157 | "dev": true, 158 | "dependencies": { 159 | "@types/estree": "1.0.5" 160 | }, 161 | "bin": { 162 | "rollup": "dist/bin/rollup" 163 | }, 164 | "engines": { 165 | "node": ">=18.0.0", 166 | "npm": ">=8.0.0" 167 | }, 168 | "optionalDependencies": { 169 | "@rollup/rollup-android-arm-eabi": "4.9.6", 170 | "@rollup/rollup-android-arm64": "4.9.6", 171 | "@rollup/rollup-darwin-arm64": "4.9.6", 172 | "@rollup/rollup-darwin-x64": "4.9.6", 173 | "@rollup/rollup-linux-arm-gnueabihf": "4.9.6", 174 | "@rollup/rollup-linux-arm64-gnu": "4.9.6", 175 | "@rollup/rollup-linux-arm64-musl": "4.9.6", 176 | "@rollup/rollup-linux-riscv64-gnu": "4.9.6", 177 | "@rollup/rollup-linux-x64-gnu": "4.9.6", 178 | "@rollup/rollup-linux-x64-musl": "4.9.6", 179 | "@rollup/rollup-win32-arm64-msvc": "4.9.6", 180 | "@rollup/rollup-win32-ia32-msvc": "4.9.6", 181 | "@rollup/rollup-win32-x64-msvc": "4.9.6", 182 | "fsevents": "~2.3.2" 183 | } 184 | }, 185 | "node_modules/source-map-js": { 186 | "version": "1.0.2", 187 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 188 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 189 | "dev": true, 190 | "engines": { 191 | "node": ">=0.10.0" 192 | } 193 | }, 194 | "node_modules/vite": { 195 | "version": "5.0.12", 196 | "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.12.tgz", 197 | "integrity": "sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==", 198 | "dev": true, 199 | "dependencies": { 200 | "esbuild": "^0.19.3", 201 | "postcss": "^8.4.32", 202 | "rollup": "^4.2.0" 203 | }, 204 | "bin": { 205 | "vite": "bin/vite.js" 206 | }, 207 | "engines": { 208 | "node": "^18.0.0 || >=20.0.0" 209 | }, 210 | "funding": { 211 | "url": "https://github.com/vitejs/vite?sponsor=1" 212 | }, 213 | "optionalDependencies": { 214 | "fsevents": "~2.3.3" 215 | }, 216 | "peerDependencies": { 217 | "@types/node": "^18.0.0 || >=20.0.0", 218 | "less": "*", 219 | "lightningcss": "^1.21.0", 220 | "sass": "*", 221 | "stylus": "*", 222 | "sugarss": "*", 223 | "terser": "^5.4.0" 224 | }, 225 | "peerDependenciesMeta": { 226 | "@types/node": { 227 | "optional": true 228 | }, 229 | "less": { 230 | "optional": true 231 | }, 232 | "lightningcss": { 233 | "optional": true 234 | }, 235 | "sass": { 236 | "optional": true 237 | }, 238 | "stylus": { 239 | "optional": true 240 | }, 241 | "sugarss": { 242 | "optional": true 243 | }, 244 | "terser": { 245 | "optional": true 246 | } 247 | } 248 | } 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "commit-webtests", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "commonjs", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "vite": "^5.0.12" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/css/loading.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "CommitMonoLoading"; 3 | src: url("data:font/woff2;charset=url-8;base64,d09GMk9UVE8AAAVoAAoAAAAACRAAAAUgAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAADYcqGhYGYACCcgE2AiQDIgQGBYQhByAbVAgRZJPTIvuRkLnpo1niWFGcZNnEK1FCUU4/x8PT2u/PnZ3dh6g3CJGQRBORpJVGg67f6q9Ns3ed4+/dNQeGD6Q1Nv+/r3HXBE48osgCyvt7NvUTYnINZZJwUNelEzGpqkxUH92fDB0zXaUP82xFMJQsXXOHVdpANttEIhM32xM/y6P+MHZhAh4hJxTKBbrhm89nfEyZeMKSimREp600nifplvNJJ34a/VkBz5F8L+EFZeCFSvKWUsig+NR/R0ZgyZDGIvDSwGSjyt9iLXIEIdUwnqN2Eiag0Go3YpZ2uyOTcHUKJe4KKRInfhZA3BH3KPTa1jUwMjW34E8oZC3tOm14RybSiV8CM8EswZ2BYK7G3WoT1eM4OBCww4CQ/0grvTR5bXZ2cnJ2ztqkpUvXrlvCqo+2rtrF72jXPnwM5x5SebwLrKI9x4/tO2lFSnl5RkqXP9vhF3Ul/HqgT++reCFN7bm85urm6zukd8WH8k80PNbBHMnbfi1Ygsk+Ewyn2MfivKuFiQ361vzVM1du3zn/BDf0iAjL9o2Z7Kaj8lzaxn2+WZ1am9An5uYS0pab2kJMyaNISGuk3cc/AwUa3/jsxbNaA1Zj1eQ+7hzYJknff3H9xQ2X10rviU83nGku0fFVXjj3lKRp3YzUkXqsdcIK7MlRebjPGywHbWdlRmsSq8ar2qD/nYftsKFtQpe269bK+0M6YduD7Q+pd0egDK7T4xblNzXn5TU15i0a6//gheO5RryXpn4MaUzfumjq+JV2jhNSy3PSk4u5wcn0rF1rF8/Uub+bADqw+Nr59fHICkywWC+mvh7ZsjskJtw/ONybOxYRfSpWD8SDuz8zjqTsjuUeteER4r7GX9u189IOPSYHDDabGjkvYx1XZeXVe3auX6lbE7Q5dh+rPn+TZ25+ASst7DVeZPWQegNkD97hJjbwq/CJoeD2h8EGMfUF5N3G9PKkdZlZiUm69/rEZcvXrV+2kBPb+W83Cdj1iIR6GEvzleUvdf2zV4KN6saCJDP1ekAs2yY5sGnDiY364WsyHnLqsB33IgA9hIPie6f1gCbJx/L2Ow0ZC4aw+PcjnpAAOfam9ahZa6dsYk8/GvQnTaw+eot3ukU0PYKqxySUHaWB+QwyMKhka5BhRmuDLakBSj/BFsBwt4SuEx+DCnLUP375st6AVedNNLhy6qPe3VO8n5zHhd5ivMo7ylty1Js/4w3T4gopc6PsthzOKW7fViozCyOr7ihV/Adj6KaLIAu6KMJTL+80vZKGuIJqm/Gc4ARBye4ep2gcIxAk2uHOt6z2oeI+AnMMHrwKfRBX1Yn/XgiqV+jDEvAAaUpQVMbhQqVPiQYFmGITYUPjK626Tk2Kq04ULit/PgOKGsEbWgtt27SjQ6fsHBgRZstv321OjERlQLEZl0IalH5zlJ/leblVov5H/A/7H/o/GFkrVe6Hj7cN3r2/07C4d8BPVfUG4UvYu0B7XoTTKBQvTgILkkKgWl1ZeII95O98bdJy+6Y6fmDlb51Xaocv2hU3QDqOGmDnfJm6PNe1hP6x6pJWSEiBbFwE1Lptypq0/jU2kWUoLNhDkPS4AZUzL5Bt+YHaRHDSBhKjb+N2c7H+U0jpsxD/Imn8NZKvzdrGzuo09DDFCJvgDVwXEcOKxvB0IrnZ0UzDHZbzF5JiEhhaTrOlQlHaWpaS0GVp19ozUcDlJtuojBhThsdj6sLDGy/MoCNODT2409BVrVsWGh9kAA=="); 4 | font-style: normal; 5 | font-weight: 400; 6 | font-display: swap; 7 | } 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | margin: 0; 13 | padding: 0; 14 | } 15 | :root { 16 | --text: #111; 17 | --middle: #555; 18 | --bg: #aaa; 19 | --max-width: 54ch; 20 | font-size: 16px; 21 | } 22 | body { 23 | background: var(--bg); 24 | color: var(--text); 25 | font-family: "CommitMono", monospace; 26 | -webkit-font-smoothing: antialiased; 27 | -moz-osx-font-smoothing: grayscale; 28 | font-size: 0.75rem; 29 | line-height: 1rem; 30 | font-feature-settings: "ss01", "ss03", "ss04", "ss05"; 31 | overflow: hidden; 32 | } 33 | 34 | #loading { 35 | position: fixed; 36 | inset: 0; 37 | display: grid; 38 | place-content: center; 39 | background-color: var(--bg); 40 | z-index: 200; 41 | } 42 | 43 | #loading p { 44 | width: 10ch; 45 | font-family: "CommitMonoLoading"; 46 | } 47 | 48 | #loading p::after { 49 | content: "..."; 50 | animation: 500ms forwards infinite loading_animation; 51 | } 52 | 53 | @keyframes loading_animation { 54 | 0% { 55 | content: ""; 56 | } 57 | 25% { 58 | content: "."; 59 | } 60 | 50% { 61 | content: ".."; 62 | } 63 | 75% { 64 | content: "..."; 65 | } 66 | 100% { 67 | content: ""; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/css/mobile.css: -------------------------------------------------------------------------------- 1 | @media (pointer: coarse) and (max-width: 1000px) { 2 | body { 3 | overflow: visible; 4 | } 5 | #main_scale, 6 | main { 7 | position: relative; 8 | } 9 | header #keyboard_section { 10 | visibility: hidden; 11 | } 12 | #footer_hint { 13 | display: none; 14 | } 15 | #footer_hint_mobile { 16 | display: block; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/css/non_essential.css: -------------------------------------------------------------------------------- 1 | button { 2 | vertical-align: top; 3 | border: none; 4 | background: transparent; 5 | font-family: inherit; 6 | font-size: 0.75rem; 7 | font-variation-settings: inherit; 8 | line-height: 1rem; 9 | width: max-content; 10 | white-space: nowrap; 11 | text-align: left; 12 | position: relative; 13 | font-feature-settings: inherit; 14 | } 15 | 16 | button:active { 17 | background: var(--bg75); 18 | } 19 | 20 | #app_root.no_focus { 21 | opacity: 0.5; 22 | } 23 | 24 | :focus, 25 | input:focus + label { 26 | animation: flicker 50ms 2; 27 | } 28 | 29 | @keyframes flicker { 30 | 0%, 31 | 49% { 32 | opacity: 0; 33 | } 34 | 50%, 35 | 100% { 36 | opacity: 1; 37 | } 38 | } 39 | 40 | @keyframes flicker_reverse { 41 | 0%, 42 | 49% { 43 | opacity: 1; 44 | } 45 | 50%, 46 | 100% { 47 | opacity: 0; 48 | } 49 | } 50 | 51 | .top_container p { 52 | white-space: pre-wrap; 53 | } 54 | 55 | .line-through { 56 | text-decoration: line-through; 57 | } 58 | 59 | h2 { 60 | font-size: 0.75rem; 61 | line-height: 1rem; 62 | font-weight: normal; 63 | width: fit-content; 64 | font-variation-settings: "wght" 700; 65 | } 66 | 67 | a, 68 | a:visited { 69 | color: var(--text); 70 | } 71 | 72 | p:focus a, 73 | a:focus { 74 | text-decoration: none; 75 | background-color: var(--text); 76 | color: var(--bg); 77 | text-decoration: none; 78 | } 79 | 80 | #click_focus, 81 | #change_setting { 82 | inset: 0; 83 | position: fixed; 84 | z-index: 999; 85 | display: grid; 86 | place-content: center; 87 | visibility: hidden; 88 | pointer-events: none; 89 | } 90 | 91 | .span_key.pressed_key { 92 | position: relative; 93 | background: var(--bg25); 94 | } 95 | 96 | ul:focus .span_key.pressed_key { 97 | background: var(--bg25-i); 98 | } 99 | 100 | .span_key.pressed_key::after { 101 | content: " ✓"; 102 | position: absolute; 103 | right: -1ch; 104 | top: -0.5rem; 105 | } 106 | 107 | #keyboard_container.use_keyboard_animation { 108 | animation: flicker 140ms 8; 109 | } 110 | -------------------------------------------------------------------------------- /src/css/section_1.css: -------------------------------------------------------------------------------- 1 | #keyboard_container { 2 | font-size: 0.75rem; 3 | display: flex; 4 | width: max-content; 5 | gap: 4ch; 6 | align-items: end; 7 | } 8 | 9 | .key_group { 10 | display: flex; 11 | flex-direction: column; 12 | } 13 | 14 | .keys { 15 | display: flex; 16 | gap: 0.5ch; 17 | margin-bottom: 0.125rem; 18 | } 19 | 20 | .key { 21 | line-height: 0.85rem; 22 | display: inline; 23 | border: 0.0625rem solid var(--text); 24 | border-bottom: 0.125rem solid var(--text); 25 | padding: 0 calc(0.5ch - 0.0625rem); 26 | user-select: none; 27 | } 28 | 29 | .key:hover { 30 | cursor: pointer; 31 | } 32 | 33 | .key[data-noclick="true"]:hover { 34 | cursor: not-allowed; 35 | } 36 | 37 | .key.active_key, 38 | .key:active { 39 | background: var(--text); 40 | color: var(--bg); 41 | line-height: 0.75rem; 42 | margin-top: 0.1rem; 43 | } 44 | 45 | #tutorial li { 46 | margin-top: 0.3rem; 47 | } 48 | 49 | .span_key { 50 | display: inline; 51 | border: 0.0625rem solid var(--text); 52 | border-bottom: 0.125rem solid var(--text); 53 | padding: 0 calc(0.5ch - 0.0625rem); 54 | } 55 | 56 | *:focus .span_key { 57 | border: 0.0625rem solid var(--bg); 58 | border-bottom: 0.125rem solid var(--bg); 59 | } 60 | -------------------------------------------------------------------------------- /src/css/section_10.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/css/section_10.css -------------------------------------------------------------------------------- /src/css/section_2.css: -------------------------------------------------------------------------------- 1 | table { 2 | margin: 4rem 0 2rem 0; 3 | border-collapse: collapse; 4 | } 5 | 6 | th > div > p, 7 | td > div > p { 8 | font-size: 0.5rem; 9 | font-weight: normal; 10 | text-align: center; 11 | } 12 | 13 | th > div, 14 | td > div { 15 | width: 6rem; 16 | aspect-ratio: 1 / 1; 17 | display: grid; 18 | justify-content: center; 19 | } 20 | 21 | tr:first-of-type th > div { 22 | width: 6rem; 23 | aspect-ratio: 3 / 1; 24 | } 25 | 26 | td > div > input, 27 | td > div > label, 28 | td > div > p { 29 | grid-row: 1; 30 | grid-column: 1; 31 | display: inline-block; 32 | margin: auto; 33 | white-space: pre; 34 | text-align: center; 35 | line-height: 1.1; 36 | } 37 | 38 | tr th:first-of-type > div { 39 | font-size: 0.5rem; 40 | width: 2rem; 41 | justify-content: start; 42 | } 43 | 44 | tr th:first-of-type > div > p { 45 | font-size: 0.5rem; 46 | text-align: start; 47 | } 48 | 49 | td > div > input + label { 50 | font-size: 4rem; 51 | height: auto; 52 | } 53 | 54 | #section_2 fieldset { 55 | border: none; 56 | display: block; 57 | } 58 | 59 | #section_2 input[type="radio"] { 60 | width: 0; 61 | height: 0; 62 | opacity: 0; 63 | -webkit-user-modify: read-only; 64 | } 65 | #section_2 input[type="radio"]:focus:checked + label { 66 | background: var(--text); 67 | color: var(--bg); 68 | scale: 4; 69 | z-index: 2; 70 | } 71 | #section_2 input[type="radio"]:checked + label { 72 | scale: 1; 73 | background: var(--bg); 74 | color: var(--text); 75 | } 76 | -------------------------------------------------------------------------------- /src/css/section_3.css: -------------------------------------------------------------------------------- 1 | #familiar_form fieldset { 2 | border: none; 3 | display: flex; 4 | gap: 1rem; 5 | position: relative; 6 | width: fit-content; 7 | } 8 | 9 | #familiar_form fieldset::before { 10 | content: ""; 11 | position: absolute; 12 | height: 0.0625rem; 13 | bottom: 0.125rem; 14 | left: 1rem; 15 | right: 1rem; 16 | background-color: var(--text); 17 | } 18 | 19 | #familiar_form fieldset div { 20 | display: flex; 21 | flex-direction: column-reverse; 22 | align-items: center; 23 | gap: 0.5rem; 24 | } 25 | 26 | #familiar_form input[type="radio"] { 27 | -webkit-appearance: none; 28 | appearance: none; 29 | background-color: var(--text); 30 | 31 | display: block; 32 | width: 0.375rem; 33 | height: 0.375rem; 34 | 35 | opacity: 1; 36 | 37 | /* display: grid; */ 38 | /* place-content: center; */ 39 | } 40 | 41 | #familiar_form label { 42 | display: inline; 43 | height: auto; 44 | } 45 | 46 | #familiar_form input[type="radio"]:checked { 47 | transform: scale(1.5); 48 | } 49 | 50 | #familiar_form input[type="radio"]:focus { 51 | transform: scale(2); 52 | } 53 | 54 | #familiar_form fieldset > div:nth-child(2) { 55 | margin-left: 16rem; 56 | } 57 | 58 | #familiar_form fieldset > div:nth-child(3) { 59 | margin-left: 15rem; 60 | } 61 | 62 | #familiar_form fieldset > div:nth-child(5) { 63 | margin-left: 1rem; 64 | } 65 | 66 | cite { 67 | font-style: normal; 68 | } 69 | 70 | figure { 71 | width: max-content; 72 | } 73 | 74 | blockquote, 75 | cite { 76 | font-variation-settings: "ital" 1; 77 | } 78 | 79 | blockquote, 80 | blockquote ~ * { 81 | font-size: 0.75rem; 82 | padding-left: 2ch; 83 | position: relative; 84 | border-left: 0.0625rem solid var(--text); 85 | max-width: var(--max-width); 86 | } 87 | 88 | blockquote::before { 89 | content: "“"; 90 | left: -0.5ch; 91 | top: 0; 92 | font-size: 1.5rem; 93 | line-height: 2rem; 94 | } 95 | 96 | #familiar_container svg { 97 | width: 100rem; 98 | height: 20rem; 99 | } 100 | 101 | #familiar_container svg { 102 | width: 100rem; 103 | height: 20rem; 104 | } 105 | 106 | .svg_container { 107 | width: 100rem; 108 | height: 20rem; 109 | } 110 | 111 | #familiar_container svg path { 112 | fill: var(--text); 113 | } 114 | 115 | #familiar_container .svg_container:focus svg path { 116 | fill: var(--bg); 117 | } 118 | -------------------------------------------------------------------------------- /src/css/section_4.css: -------------------------------------------------------------------------------- 1 | #original figure > div, 2 | #smart_kerning figure > div { 3 | display: flex; 4 | } 5 | 6 | #original p, 7 | #smart_kerning p { 8 | font-size: 24rem; 9 | line-height: 1; 10 | position: relative; 11 | border-right: 0.0625rem solid var(--text); 12 | border-left: 0.0625rem solid var(--text); 13 | margin-left: -0.0625rem; 14 | } 15 | 16 | #original p::after, 17 | #smart_kerning p::after { 18 | font-size: 0.75rem; 19 | text-align: center; 20 | display: block; 21 | width: 100%; 22 | } 23 | 24 | #original p:nth-child(1)::after, 25 | #smart_kerning p:nth-child(1)::after { 26 | content: "Wide letter"; 27 | } 28 | 29 | #original p:nth-child(2)::after { 30 | content: "Smart kerning OFF"; 31 | } 32 | 33 | #smart_kerning p:nth-child(2)::after { 34 | content: "Smart kerning ON"; 35 | } 36 | 37 | #original p:nth-child(3)::after, 38 | #smart_kerning p:nth-child(3)::after { 39 | content: "Narrow letter"; 40 | } 41 | 42 | #smart_kerning p:nth-child(2) { 43 | transform: translateX(calc(24rem / 1000 * 44)); 44 | border-right: 0.0625rem solid transparent; 45 | border-left: 0.0625rem solid transparent; 46 | } 47 | 48 | #intelligent_container figure > div:focus p { 49 | border-right: 0.0625rem solid var(--bg); 50 | border-left: 0.0625rem solid var(--bg); 51 | } 52 | 53 | #intelligent_container figure > div:focus p:nth-child(2) { 54 | border-right: 0.0625rem solid transparent; 55 | border-left: 0.0625rem solid transparent; 56 | } 57 | 58 | #before p, 59 | #after p { 60 | font-size: 8rem; 61 | line-height: 1; 62 | max-width: none; 63 | white-space: nowrap; 64 | } 65 | 66 | #before p { 67 | font-feature-settings: "ss05" 0; 68 | font-variant-ligatures: none; 69 | } 70 | 71 | #after p { 72 | font-feature-settings: "ss05" 1; 73 | } 74 | -------------------------------------------------------------------------------- /src/css/section_5.css: -------------------------------------------------------------------------------- 1 | #code_form fieldset { 2 | font-size: 1.5rem; 3 | line-height: 1.65rem; 4 | gap: 1ch; 5 | } 6 | 7 | form fieldset { 8 | border: none; 9 | display: flex; 10 | gap: 4ch; 11 | font-size: 0.75rem; 12 | line-height: 1rem; 13 | background-color: var(--bg); 14 | width: max-content; 15 | } 16 | 17 | form > div { 18 | position: relative; 19 | } 20 | 21 | #canvas { 22 | transform-origin: top left; 23 | } 24 | 25 | #code_description { 26 | height: 4rem; 27 | } 28 | -------------------------------------------------------------------------------- /src/css/section_6.css: -------------------------------------------------------------------------------- 1 | #waterfall { 2 | display: flex; 3 | width: min-content; 4 | gap: 2rem; 5 | } 6 | 7 | .waterfall_texts_container { 8 | display: flex; 9 | flex-direction: column; 10 | justify-content: end; 11 | height: 10rem; 12 | } 13 | 14 | .waterfall_texts_container > div { 15 | height: 2.5rem; 16 | display: flex; 17 | align-items: end; 18 | } 19 | 20 | .waterfall_text { 21 | line-height: 0.6; 22 | white-space: pre; 23 | } 24 | 25 | .waterfall_desc { 26 | width: max-content; 27 | white-space: pre; 28 | } 29 | 30 | .question_container { 31 | display: flex; 32 | align-items: center; 33 | font-size: 0.75rem; 34 | gap: 2ch; 35 | position: relative; 36 | margin-top: 1rem; 37 | } 38 | 39 | .question_character.hide_character { 40 | opacity: 1; 41 | animation: 0ms 0s 3 forwards flicker_reverse; 42 | } 43 | 44 | .question_character.show_character { 45 | opacity: 0; 46 | animation: 100ms 0s 3 forwards flicker; 47 | } 48 | 49 | .button_container button { 50 | display: block; 51 | } 52 | 53 | :root { 54 | --question-character-size: 2rem; 55 | } 56 | 57 | .question_character { 58 | font-size: var(--question-character-size); 59 | line-height: var(--question-character-size); 60 | border: 0.0625rem solid var(--text); 61 | position: relative; 62 | } 63 | .question_character::after { 64 | content: ""; 65 | position: absolute; 66 | left: 0; 67 | right: 0; 68 | bottom: 15%; 69 | /* height: 0.0625rem; */ 70 | background-color: var(--text); 71 | } 72 | 73 | #score_points { 74 | display: none; 75 | } 76 | #score_points.view_score { 77 | display: block; 78 | } 79 | 80 | .question_button:focus::before, 81 | .question_button:hover::before { 82 | content: "<-"; 83 | position: absolute; 84 | left: -2ch; 85 | color: var(--text); 86 | } 87 | .question_button:hover { 88 | background: var(--bg50); 89 | color: var(--bg); 90 | cursor: pointer; 91 | text-decoration: none; 92 | } 93 | .question_button.right_button::before { 94 | content: "<-"; 95 | position: absolute; 96 | left: -2ch; 97 | color: var(--text); 98 | } 99 | .question_button.wrong_button::before { 100 | content: "->"; 101 | position: absolute; 102 | left: auto; 103 | right: -2ch; 104 | color: var(--text); 105 | } 106 | 107 | .question_button.button_choice { 108 | background: var(--bg25); 109 | color: var(--text); 110 | text-decoration: none; 111 | } 112 | .question_button.button_choice:focus { 113 | background: var(--bg75); 114 | color: var(--bg); 115 | text-decoration: none; 116 | } 117 | .question_button.button_choicent { 118 | text-decoration: none; 119 | } 120 | 121 | .answer_feedback { 122 | position: relative; 123 | font-size: 1.5rem; 124 | top: calc(var(--question-character-size) * 0.5); 125 | top: 40%; 126 | width: 0; 127 | margin-left: -1.5ch; 128 | margin-right: 0.5ch; 129 | left: 0; 130 | font-variation-settings: "wght" 350; 131 | } 132 | 133 | .question_container { 134 | pointer-events: none; 135 | } 136 | 137 | .question_container.active_question { 138 | pointer-events: auto; 139 | } 140 | 141 | .question_container.active_question:has(+ .active_question) { 142 | pointer-events: none; 143 | } 144 | 145 | .question_container.active_question ~ .question_container.active_question { 146 | pointer-events: auto; 147 | display: flex; 148 | } 149 | 150 | .question_container.active_question ~ .question_container { 151 | pointer-events: none; 152 | display: none; 153 | } 154 | 155 | #play_again { 156 | opacity: 0; 157 | } 158 | 159 | #score_tally:focus + #play_again, 160 | #play_again:focus { 161 | opacity: 1; 162 | } 163 | -------------------------------------------------------------------------------- /src/css/section_7.css: -------------------------------------------------------------------------------- 1 | #section_7 #alternates_container fieldset, 2 | #section_7 #features_container fieldset { 3 | display: grid; 4 | grid-template-columns: 28ch 3ch 3ch; 5 | gap: 2ch; 6 | } 7 | 8 | #section_7 #examplesettings_form fieldset p { 9 | white-space: pre; 10 | font-variant-ligatures: none; 11 | } 12 | 13 | fieldset.alternates > div { 14 | width: 4ch; 15 | } 16 | 17 | #section_7 form > div { 18 | position: relative; 19 | } 20 | 21 | #examples_container { 22 | width: fit-content; 23 | max-height: 20.6rem; 24 | margin-bottom: 0.4rem; 25 | overflow-y: scroll; 26 | -ms-overflow-style: none; /* Internet Explorer 10+ */ 27 | scrollbar-width: none; /* Firefox */ 28 | } 29 | #examples_container::-webkit-scrollbar { 30 | display: none; 31 | } 32 | 33 | p#code_example { 34 | white-space: pre; 35 | max-width: none; 36 | min-width: 102ch; 37 | padding-left: 5ch; 38 | position: relative; 39 | line-height: 1; 40 | } 41 | p#code_example::before { 42 | content: attr(data-before); 43 | position: absolute; 44 | white-space: pre; 45 | left: 0; 46 | top: 0; 47 | height: 100%; 48 | overflow: hidden; 49 | } 50 | 51 | button:focus a { 52 | color: var(--bg); 53 | text-decoration: none; 54 | } 55 | 56 | .button_link { 57 | width: max-content; 58 | position: relative; 59 | } 60 | .button_link:hover { 61 | background: var(--bg75); 62 | color: var(--bg); 63 | text-decoration: none; 64 | } 65 | .button_link:focus:active, 66 | .button_link:active { 67 | background: var(--bg50); 68 | color: var(--bg); 69 | text-decoration: none; 70 | } 71 | .button_link:focus { 72 | background-color: var(--text); 73 | color: var(--bg); 74 | text-decoration: none; 75 | } 76 | .button_link::after { 77 | position: absolute; 78 | color: var(--text); 79 | right: -2ch; 80 | top: 0; 81 | } 82 | .button_link.loading::after { 83 | content: "."; 84 | animation: 800ms 0ms steps(4, jump-none) infinite loading; 85 | } 86 | .button_link.loaded::after { 87 | content: "✓"; 88 | animation: none; 89 | } 90 | .button_link.error::after { 91 | content: "✕"; 92 | animation: none; 93 | } 94 | .button_link.safari::after { 95 | content: "Safari download not working. Try Chrome or Firefox."; 96 | font-variation-settings: "ital" 1; 97 | right: auto; 98 | left: calc(100% + 1ch); 99 | animation: none; 100 | } 101 | 102 | @keyframes loading { 103 | 0% { 104 | transform: translateX(0); 105 | } 106 | 100% { 107 | transform: translateX(2ch); 108 | } 109 | } 110 | 111 | input.loading_font + label { 112 | animation: flicker 200ms infinite; 113 | } 114 | 115 | input[type="text"] { 116 | width: 10ch; 117 | height: 1rem; 118 | border: 1px solid var(--text); 119 | background-color: var(--bg); 120 | font-family: inherit; 121 | font-size: inherit; 122 | line-height: inherit; 123 | display: inline-block; 124 | } 125 | 126 | input[type="text"][contenteditable="true"] { 127 | animation: none; 128 | } 129 | 130 | input[type="text"]:focus { 131 | color: var(--text); 132 | } 133 | 134 | input[type="text"]:-webkit-autofill, 135 | input[type="text"]:-webkit-autofill:hover, 136 | input[type="text"]:-webkit-autofill:focus, 137 | input[type="text"]:auto-fill, 138 | input[type="text"]:auto-fill:hover, 139 | input[type="text"]:auto-fill:focus { 140 | -webkit-text-fill-color: var(--text); 141 | -webkit-box-shadow: 0 0 0px 40rem var(--bg) inset; 142 | } 143 | 144 | input[type="text"] + p { 145 | display: inline-block; 146 | margin-left: 0ch; 147 | } 148 | 149 | .file_label { 150 | height: 1rem; 151 | border: 1px solid var(--text); 152 | background-color: var(--bg); 153 | font-family: inherit; 154 | font-size: inherit; 155 | line-height: inherit; 156 | display: inline-block; 157 | padding: 0 0.5ch; 158 | } 159 | 160 | input[type="file"]:focus + label { 161 | background-color: var(--text); 162 | color: var(--bg); 163 | text-decoration: none; 164 | } 165 | 166 | #custom-settings-input { 167 | border: none; 168 | width: 17ch; 169 | font-variation-settings: inherit; 170 | opacity: 0.75; 171 | } 172 | 173 | /* #custom-settings-input, */ 174 | #custom-settings-input::placeholder { 175 | opacity: 0.5; 176 | color: var(--text); 177 | font-feature-settings: inherit; 178 | font-variation-settings: inherit; 179 | } 180 | #custom-settings-input:focus::placeholder { 181 | opacity: 0.75; 182 | } 183 | -------------------------------------------------------------------------------- /src/css/section_8.css: -------------------------------------------------------------------------------- 1 | ol { 2 | font-size: 0.75rem; 3 | margin-left: 0; 4 | max-width: max-content; 5 | counter-reset: install; 6 | list-style: none; 7 | } 8 | 9 | ol > li { 10 | margin-left: 3ch; 11 | max-width: calc(var(--max-width) - 3ch); 12 | counter-increment: install; 13 | position: relative; 14 | } 15 | 16 | ol > li > *:first-child:before { 17 | content: "#" counter(install) " "; 18 | position: absolute; 19 | left: -3ch; 20 | } 21 | 22 | ol li p { 23 | max-width: calc(var(--max-width) - 6ch); 24 | } 25 | 26 | ol:focus li p { 27 | color: var(--bg); 28 | } 29 | 30 | ol li ul li p { 31 | position: relative; 32 | } 33 | 34 | ol li ul li p::before { 35 | content: "•"; 36 | position: absolute; 37 | left: -2ch; 38 | } 39 | 40 | details > summary { 41 | cursor: pointer; 42 | list-style: none; 43 | width: fit-content; 44 | max-width: calc(var(--max-width) - 4ch); 45 | position: relative; 46 | margin: 1rem 0 0 4ch; 47 | } 48 | details[open] > summary { 49 | background: var(--bg25); 50 | color: var(--text); 51 | } 52 | details > summary:focus { 53 | background: var(--text); 54 | color: var(--bg); 55 | } 56 | details > p { 57 | max-width: calc(var(--max-width) - 4ch); 58 | margin: 0 0 1rem 4ch; 59 | } 60 | details > ol { 61 | max-width: calc(var(--max-width) - 4ch); 62 | margin: 0 0 1rem 4ch; 63 | counter-reset: reinstall; 64 | } 65 | details > ol li::before { 66 | display: block; 67 | counter-increment: reinstall; 68 | content: "#" counter(reinstall) " "; 69 | position: absolute; 70 | left: -3ch; 71 | } 72 | details > ol li { 73 | position: relative; 74 | } 75 | details > summary::before { 76 | content: "[+]"; 77 | position: absolute; 78 | left: -4ch; 79 | } 80 | details[open] > summary::before { 81 | content: "[-]"; 82 | } 83 | details > summary:focus::before { 84 | color: var(--text); 85 | } 86 | -------------------------------------------------------------------------------- /src/css/section_9.css: -------------------------------------------------------------------------------- 1 | .docs_example { 2 | width: max-content; 3 | font-variant-ligatures: none; 4 | white-space: pre; 5 | font-feature-settings: normal; 6 | } 7 | 8 | .span_off, 9 | .span_on { 10 | cursor: pointer; 11 | } 12 | 13 | .active_feature { 14 | cursor: pointer; 15 | background: var(--bg25); 16 | height: 100%; 17 | display: inline-block; 18 | } 19 | 20 | h2:focus .active_feature { 21 | background: var(--bg25-i); 22 | } 23 | 24 | #section_9 h2 { 25 | max-width: var(--max-width); 26 | } 27 | 28 | .docs_alternate { 29 | margin-right: 2rem; 30 | display: inline-block; 31 | vertical-align: baseline; 32 | } 33 | 34 | #features_docu > div { 35 | width: max-content; 36 | } 37 | 38 | #charset { 39 | width: var(--max-width); 40 | width: 32ch; 41 | font-variant-ligatures: none; 42 | white-space: pre-wrap; 43 | font-size: 5rem; 44 | line-height: 5rem; 45 | display: grid; 46 | grid-template-columns: repeat(10, 1ch); 47 | gap: 1ch; 48 | } 49 | 50 | #charset .charset_letter { 51 | /* background-color: blue; */ 52 | font-size: inherit; 53 | width: fit-content; 54 | line-height: inherit; 55 | } 56 | 57 | .new_label { 58 | position: relative; 59 | } 60 | 61 | .new_label::before { 62 | content: "NEW"; 63 | font-size: 0.66rem; 64 | background: var(--text); 65 | color: var(--bg); 66 | position: relative; 67 | padding: 0 0.5ch; 68 | } 69 | 70 | #language_support { 71 | display: grid; 72 | grid-auto-flow: column; 73 | grid-template-rows: repeat(12, 1fr); 74 | width: max-content; 75 | gap: 0 4ch; 76 | } 77 | 78 | #language_support > p { 79 | /* width: 22ch; */ 80 | } 81 | -------------------------------------------------------------------------------- /src/css/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bg25: repeating-conic-gradient(var(--text) 0% 25%, transparent 0% 100%) 1px 0.5px / 2px 2px; 3 | --bg50: repeating-conic-gradient(var(--text) 0% 25%, transparent 0% 50%, var(--text) 0% 75%, transparent 0% 100%) 4 | 1px 0.5px / 2px 2px; 5 | --bg75: repeating-conic-gradient(transparent 0% 25%, var(--text) 0% 100%) 1px 0.5px / 2px 2px; 6 | --bg25-i: repeating-conic-gradient(var(--bg) 0% 25%, transparent 0% 100%) 1px 0.5px / 2px 2px; 7 | --bg50-i: repeating-conic-gradient(var(--bg) 0% 25%, transparent 0% 50%, var(--bg) 0% 75%, transparent 0% 100%) 1px 8 | 0.5px / 2px 2px; 9 | --bg75-i: repeating-conic-gradient(transparent 0% 25%, var(--bg) 0% 100%) 1px 0.5px / 2px 2px; 10 | } 11 | 12 | ::selection { 13 | color: var(--text); 14 | background-color: var(--middle); 15 | } 16 | 17 | #block_tab_start, 18 | #block_tab_end { 19 | position: absolute; 20 | top: 0; 21 | } 22 | 23 | #main_scale { 24 | inset: 0; 25 | overflow: scroll; 26 | scrollbar-width: none; 27 | -ms-overflow-style: none; 28 | height: 100vh; 29 | height: 100dvh; 30 | padding-bottom: 10rem; 31 | } 32 | #main_scale::-webkit-scrollbar { 33 | display: none; 34 | } 35 | 36 | main { 37 | min-width: 100vw; 38 | width: fit-content; 39 | padding: 4rem 4ch 0 4ch; 40 | } 41 | 42 | header nav { 43 | width: 100vw; 44 | padding: 1rem 4ch 0 4ch; 45 | background-color: var(--bg); 46 | z-index: 100; 47 | position: fixed; 48 | top: 0; 49 | } 50 | 51 | header #keyboard_section { 52 | width: 100%; 53 | padding: 0.25rem 4ch 1rem 4ch; 54 | background-color: var(--bg); 55 | z-index: 100; 56 | position: fixed; 57 | bottom: 0; 58 | } 59 | 60 | @media (max-width: 1000px) { 61 | main { 62 | padding: 4rem 2ch 0 2ch; 63 | } 64 | header nav { 65 | padding: 1rem 2ch 0 2ch; 66 | } 67 | header #keyboard_section { 68 | padding: 0.25rem 2ch 1rem 2ch; 69 | } 70 | } 71 | 72 | header #keyboard_section, 73 | header nav { 74 | overflow-y: scroll; 75 | -ms-overflow-style: none; /* Internet Explorer 10+ */ 76 | scrollbar-width: none; /* Firefox */ 77 | } 78 | header #keyboard_section::-webkit-scrollbar, 79 | header nav::-webkit-scrollbar { 80 | display: none; 81 | } 82 | 83 | #keyboard_section.hidden { 84 | display: none; 85 | } 86 | 87 | #nav_form { 88 | display: flex; 89 | gap: 4ch; 90 | font-size: 0.75rem; 91 | line-height: 1rem; 92 | width: max-content; 93 | } 94 | 95 | #section_container { 96 | inset: 1rem 2rem; 97 | } 98 | 99 | p, 100 | a, 101 | figcaption, 102 | button { 103 | font-size: 0.75rem; 104 | line-height: 1rem; 105 | max-width: var(--max-width); 106 | width: fit-content; 107 | vertical-align: top; 108 | color: inherit; 109 | } 110 | 111 | a, 112 | .button_link, 113 | button { 114 | text-decoration: underline; 115 | text-decoration-skip-ink: none; 116 | text-underline-offset: 0.24ch; 117 | cursor: pointer; 118 | } 119 | a:focus, 120 | .button_link:focus { 121 | text-decoration: none; 122 | } 123 | 124 | i { 125 | font-style: normal; 126 | font-variation-settings: 127 | "wght" 400, 128 | "ital" 1; 129 | } 130 | 131 | h1 { 132 | font-size: 1.5rem; 133 | line-height: 2rem; 134 | font-weight: normal; 135 | width: fit-content; 136 | } 137 | 138 | #change_setting p { 139 | padding: 0 1ch; 140 | background-color: var(--bg); 141 | } 142 | 143 | .faded { 144 | opacity: 0.33; 145 | } 146 | 147 | #mobile { 148 | visibility: hidden; 149 | } 150 | 151 | :focus { 152 | text-decoration: none; 153 | color: var(--bg); 154 | background-color: var(--text); 155 | outline: none; 156 | } 157 | 158 | form input[type="radio"], 159 | input[type="file"] { 160 | -webkit-appearance: none; 161 | appearance: none; 162 | background-color: var(--text); 163 | color: var(--text); 164 | border: none; 165 | width: 0; 166 | height: 0; 167 | opacity: 0; 168 | display: block; 169 | } 170 | form input[type="radio"] + label { 171 | cursor: pointer; 172 | display: inline-block; 173 | } 174 | form input[type="radio"]:focus:checked + label { 175 | background-color: var(--text); 176 | color: var(--bg); 177 | } 178 | form input[type="radio"]:checked + label { 179 | background: var(--bg25); 180 | } 181 | form input[type="radio"]:hover + label, 182 | form input[type="radio"]:checked:hover + label { 183 | background: var(--bg75); 184 | color: var(--bg); 185 | } 186 | form input[type="radio"]:focus:hover + label { 187 | background: var(--text); 188 | } 189 | form input[type="radio"]:focus + label:active, 190 | form input[type="radio"]:checked + label:active, 191 | form input[type="radio"] + label:active { 192 | background: var(--bg50); 193 | color: var(--bg); 194 | } 195 | 196 | ul li, 197 | ol li { 198 | font-size: 0.75rem; 199 | line-height: 1rem; 200 | margin-left: 2ch; 201 | max-width: 54ch; 202 | width: fit-content; 203 | } 204 | 205 | ul { 206 | list-style-type: none; 207 | max-width: max-content; 208 | } 209 | 210 | ol li::before { 211 | display: none; 212 | } 213 | 214 | ul li::before { 215 | content: "• "; 216 | position: absolute; 217 | margin-left: -2ch; 218 | } 219 | 220 | ul li:focus::before { 221 | background-color: transparent; 222 | color: var(--text); 223 | } 224 | 225 | #page_animation { 226 | width: 200vw; 227 | height: 200vh; 228 | height: 200dvh; 229 | position: fixed; 230 | top: 0; 231 | left: 0; 232 | z-index: 99; 233 | background-color: var(--bg); 234 | pointer-events: none; 235 | } 236 | 237 | #page_animation.page_animation { 238 | animation: 440ms steps(10, jump-start) forwards page_animation; 239 | } 240 | 241 | @keyframes page_animation { 242 | 0% { 243 | transform: translateY(0vh); 244 | } 245 | 99.9% { 246 | visibility: visible; 247 | } 248 | 100% { 249 | visibility: hidden; 250 | transform: translateY(200vh); 251 | } 252 | } 253 | 254 | #focus_check { 255 | position: absolute; 256 | } 257 | 258 | #footer_hint_mobile { 259 | display: none; 260 | } 261 | 262 | #section_container section { 263 | display: none; 264 | } 265 | #section_container section.visible { 266 | display: block; 267 | } 268 | 269 | .shake:focus, 270 | .shake, 271 | input:focus + .shake { 272 | animation: 200ms steps(1, jump-start) shake; 273 | } 274 | .shake_left:focus, 275 | .shake_left, 276 | input:focus + .shake_left { 277 | animation: 125ms steps(1, jump-start) shake_left; 278 | } 279 | .shake_right:focus, 280 | .shake_right, 281 | input:focus + .shake_right { 282 | animation: 125ms steps(1, jump-start) shake_right; 283 | } 284 | .shake_up:focus, 285 | .shake_up, 286 | input:focus + .shake_up { 287 | animation: 125ms steps(1, jump-start) shake_up; 288 | } 289 | .shake_down:focus, 290 | .shake_down, 291 | input:focus + .shake_down { 292 | animation: 125ms steps(1, jump-start) shake_down; 293 | } 294 | 295 | @keyframes shake { 296 | 0% { 297 | transform: translate(0); 298 | } 299 | 33% { 300 | transform: translate(0.125rem, 0.125rem); 301 | } 302 | 67% { 303 | transform: translate(-0.125rem, -0.125rem); 304 | } 305 | 100% { 306 | transform: translate(0); 307 | } 308 | } 309 | @keyframes shake_left { 310 | 0% { 311 | transform: translateX(0); 312 | } 313 | 50% { 314 | transform: translateX(-0.25rem); 315 | } 316 | 100% { 317 | transform: translateX(0); 318 | } 319 | } 320 | @keyframes shake_right { 321 | 0% { 322 | transform: translateX(0); 323 | } 324 | 50% { 325 | transform: translateX(0.25rem); 326 | } 327 | 100% { 328 | transform: translateX(0); 329 | } 330 | } 331 | @keyframes shake_up { 332 | 0% { 333 | transform: translateY(0); 334 | } 335 | 50% { 336 | transform: translateY(-0.25rem); 337 | } 338 | 100% { 339 | transform: translateY(0); 340 | } 341 | } 342 | @keyframes shake_down { 343 | 0% { 344 | transform: translateY(0); 345 | } 346 | 50% { 347 | transform: translateY(0.25rem); 348 | } 349 | 100% { 350 | transform: translateY(0); 351 | } 352 | } 353 | 354 | .nav_button { 355 | text-decoration: underline; 356 | } 357 | .nav_button:focus { 358 | text-decoration: none; 359 | } 360 | -------------------------------------------------------------------------------- /src/favicon/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/favicon/icon-192.png -------------------------------------------------------------------------------- /src/favicon/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/favicon/icon-512.png -------------------------------------------------------------------------------- /src/favicon/icon-512.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/features/aalt.fea: -------------------------------------------------------------------------------- 1 | feature aalt { 2 | # Access All Alternates 3 | 4 | #> featur 5 | feature c001; 6 | feature c002; 7 | feature c003; 8 | feature c004; 9 | feature c005; 10 | feature c006; 11 | #< feature 12 | 13 | } aalt; 14 | -------------------------------------------------------------------------------- /src/features/balance.fea: -------------------------------------------------------------------------------- 1 | feature c007 { 2 | # Coding Ligature 001—999 3 | # Letter balancing 4 | 5 | # feature 6 | pos @width_narrow @width_narrow' @width_wide <-30 0 0 0>; 7 | pos @width_wide @width_narrow' @width_narrow <30 0 0 0>; 8 | pos @width_narrow @width_regular' @width_wide <-30 0 0 0>; 9 | pos @width_wide @width_regular' @width_narrow <30 0 0 0>; 10 | pos @width_narrow @width_wide' @width_wide <-30 0 0 0>; 11 | pos @width_wide @width_wide' @width_narrow <30 0 0 0>; 12 | pos @width_regular @width_narrow' @width_wide <-20 0 0 0>; 13 | pos @width_wide @width_narrow' @width_regular <20 0 0 0>; 14 | pos @width_regular @width_regular' @width_wide <-20 0 0 0>; 15 | pos @width_wide @width_regular' @width_regular <20 0 0 0>; 16 | pos @width_regular @width_wide' @width_wide <-20 0 0 0>; 17 | pos @width_wide @width_wide' @width_regular <20 0 0 0>; 18 | pos @width_narrow @width_narrow' @width_regular <-10 0 0 0>; 19 | pos @width_regular @width_narrow' @width_narrow <10 0 0 0>; 20 | pos @width_narrow @width_regular' @width_regular <-10 0 0 0>; 21 | pos @width_regular @width_regular' @width_narrow <10 0 0 0>; 22 | pos @width_narrow @width_wide' @width_regular <-10 0 0 0>; 23 | pos @width_regular @width_wide' @width_narrow <10 0 0 0>; 24 | 25 | } c007; 26 | -------------------------------------------------------------------------------- /src/features/barhyphen.fea: -------------------------------------------------------------------------------- 1 | feature c005 { 2 | # Coding Ligature 001—999 3 | # Bar hyphen, bar equal, bar underscore substitution 4 | 5 | # classes 6 | @b_hyphen = [hyphen hyphen.arrow]; 7 | @b_equal = [equal equal.arrow]; 8 | 9 | # feature 10 | sub @b_hyphen bar' @b_hyphen by bar.hy_start_hy_end; 11 | sub @b_hyphen bar' by bar.hy_start; 12 | sub bar' @b_hyphen by bar.hy_end; 13 | 14 | sub @b_equal bar' @b_equal by bar.eq_start_eq_end; 15 | sub @b_equal bar' by bar.eq_start; 16 | sub bar' @b_equal by bar.eq_end; 17 | 18 | sub underscore bar' underscore by bar.un_start_un_end; 19 | sub underscore bar' by bar.un_start; 20 | sub bar' underscore by bar.un_end; 21 | 22 | } c005; -------------------------------------------------------------------------------- /src/features/colon.fea: -------------------------------------------------------------------------------- 1 | feature c004 { 2 | # Coding Ligature 001—999 3 | # Colon equal/hash substitution 4 | 5 | # classes 6 | @colon_ = [colon colon.c2_1 colon.c2_2 colon.c3_1 colon.c3_3]; 7 | @colon_case = [colon.case colon.case.c2_1 colon.case.c2_2 colon.case.c3_1 colon.case.c3_3]; 8 | @colon_square = [colon.square colon.square.c2_1 colon.square.c2_2 colon.square.c3_1 colon.square.c3_3]; 9 | @colon_case_square = [colon.case.square colon.case.square.c2_1 colon.case.square.c2_2 colon.case.square.c3_1 colon.case.square.c3_3]; 10 | @colon_squashed = [colon.squash colon.squash.case colon.squash.square colon.squash.case.square]; 11 | @squashers = [equal equal.case numbersign less less.case less.c2_1 less.c2_2 less.c3_1 less.c3_3 less.case.c2_1 less.case.c2_2 less.case.c3_1 less.case.c3_3 greater greater.case greater.c2_1 greater.c2_2 greater.c3_1 greater.c3_3 greater.case.c2_1 greater.case.c2_2 greater.case.c3_1 greater.case.c3_3]; 12 | 13 | 14 | # feature 15 | lookup Squash_1 { 16 | sub @colon_' @squashers by colon.squash; 17 | sub @colon_case' @squashers by colon.squash.case; 18 | sub @colon_square' @squashers by colon.squash.square; 19 | sub @colon_case_square' @squashers by colon.squash.case.square; 20 | sub @squashers @colon' by colon.squash; 21 | sub @squashers @colon_case' by colon.squash.case; 22 | sub @squashers @colon_square' by colon.squash.square; 23 | sub @squashers @colon_case_square' by colon.squash.case.square; 24 | } Squash_1; 25 | 26 | lookup Squash_2 { 27 | sub @colon_' @colon_squashed by colon.squash; 28 | sub @colon_case' @colon_squashed by colon.squash.case; 29 | sub @colon_square' @colon_squashed by colon.squash.square; 30 | sub @colon_case_square' @colon_squashed by colon.squash.case.square; 31 | sub @colon_squashed @colon_' by colon.squash; 32 | sub @colon_squashed @colon_case' by colon.squash.case; 33 | sub @colon_squashed @colon_square' by colon.squash.square; 34 | sub @colon_squashed @colon_case_square' by colon.squash.case.square; 35 | } Squash_2; 36 | 37 | } c004; 38 | 39 | -------------------------------------------------------------------------------- /src/features/cv04.fea: -------------------------------------------------------------------------------- 1 | feature cv04 { 2 | # Character Variant 01—99 3 | 4 | #> featur 5 | 6 | @four = [four four.dnom four.numr uni2084 uni2074]; 7 | @four_cv04 = [four.cv04 four.dnom.cv04 four.numr.cv04 uni2084.cv04 uni2074.cv04]; 8 | 9 | sub @four by @four_cv04; 10 | 11 | #< feature 12 | } cv04; 13 | -------------------------------------------------------------------------------- /src/features/frac.fea: -------------------------------------------------------------------------------- 1 | feature frac { 2 | # Fractions 3 | 4 | #> featur 5 | 6 | # Arbitrary fractions (based on opentypecookbook.com) 7 | 8 | lookup frac_bar { 9 | ignore sub slash @figs @figs @figs @figs @figs @figs @figs @figs @figs @figs slash'; 10 | ignore sub slash' @figs @figs @figs @figs @figs @figs @figs @figs @figs @figs slash; 11 | ignore sub slash @figs @figs @figs @figs @figs @figs @figs @figs @figs slash'; 12 | ignore sub slash' @figs @figs @figs @figs @figs @figs @figs @figs @figs slash; 13 | ignore sub slash @figs @figs @figs @figs @figs @figs @figs @figs slash'; 14 | ignore sub slash' @figs @figs @figs @figs @figs @figs @figs @figs slash; 15 | ignore sub slash @figs @figs @figs @figs @figs @figs @figs slash'; 16 | ignore sub slash' @figs @figs @figs @figs @figs @figs @figs slash; 17 | ignore sub slash @figs @figs @figs @figs @figs @figs slash'; 18 | ignore sub slash' @figs @figs @figs @figs @figs @figs slash; 19 | ignore sub slash @figs @figs @figs @figs @figs slash'; 20 | ignore sub slash' @figs @figs @figs @figs @figs slash; 21 | ignore sub slash @figs @figs @figs @figs slash'; 22 | ignore sub slash' @figs @figs @figs @figs slash; 23 | ignore sub slash @figs @figs @figs slash'; 24 | ignore sub slash' @figs @figs @figs slash; 25 | ignore sub slash @figs @figs slash'; 26 | ignore sub slash' @figs @figs slash; 27 | ignore sub slash @figs slash'; 28 | ignore sub slash' @figs slash; 29 | ignore sub slash slash'; 30 | ignore sub slash' slash; 31 | sub @figs slash' @figs by fraction; 32 | } frac_bar; 33 | 34 | lookup numr1 { 35 | sub @figs' fraction by @numr; 36 | } numr1; 37 | 38 | lookup numr2 { 39 | sub @figs' @numr fraction by @numr; 40 | } numr2; 41 | 42 | lookup numr3 { 43 | sub @figs' @numr @numr fraction by @numr; 44 | } numr3; 45 | 46 | lookup numr4 { 47 | sub @figs' @numr @numr @numr fraction by @numr; 48 | } numr4; 49 | 50 | lookup numr5 { 51 | sub @figs' @numr @numr @numr @numr fraction by @numr; 52 | } numr5; 53 | 54 | lookup numr6 { 55 | sub @figs' @numr @numr @numr @numr @numr fraction by @numr; 56 | } numr6; 57 | 58 | lookup numr7 { 59 | sub @figs' @numr @numr @numr @numr @numr @numr fraction by @numr; 60 | } numr7; 61 | 62 | lookup numr8 { 63 | sub @figs' @numr @numr @numr @numr @numr @numr @numr fraction by @numr; 64 | } numr8; 65 | 66 | lookup numr9 { 67 | sub @figs' @numr @numr @numr @numr @numr @numr @numr @numr fraction by @numr; 68 | } numr9; 69 | 70 | lookup numr10 { 71 | sub @figs' @numr @numr @numr @numr @numr @numr @numr @numr @numr fraction by @numr; 72 | } numr10; 73 | 74 | lookup dnom { 75 | sub [fraction @dnom] @figs' by @dnom; 76 | } dnom; 77 | 78 | #< feature 79 | 80 | } frac; 81 | -------------------------------------------------------------------------------- /src/features/kern_smartkerning.fea: -------------------------------------------------------------------------------- 1 | feature kern { 2 | # GPOS feature: Kerning 3 | # Lookups: 1 4 | 5 | # Smart kerning with pos 6 | 7 | 8 | # classes 9 | @narrow_letter = [I L f i j l r t]; 10 | @normal_letter = [F J P T Y a b c d e g h k n o p q s u v x y z space comma hyphen period colon semicolon underscore]; 11 | @larger_letter = [A B C D E G H K O Q R S U V X Z]; 12 | @widest_letter = [M N W m w]; 13 | @origin = [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 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]; 14 | 15 | 16 | # feature 17 | lookup kern { 18 | 19 | pos @narrow_letter @origin' @widest_letter <-44 0 0 0>; 20 | pos @narrow_letter @origin' @larger_letter <-30 0 0 0>; 21 | pos @normal_letter @origin' @widest_letter <-30 0 0 0>; 22 | pos @narrow_letter @origin' @normal_letter <-18 0 0 0>; 23 | pos @normal_letter @origin' @larger_letter <-18 0 0 0>; 24 | pos @larger_letter @origin' @widest_letter <-18 0 0 0>; 25 | 26 | pos @widest_letter @origin' @narrow_letter <44 0 0 0>; 27 | pos @larger_letter @origin' @narrow_letter <30 0 0 0>; 28 | pos @normal_letter @origin' @narrow_letter <30 0 0 0>; 29 | pos @widest_letter @origin' @normal_letter <18 0 0 0>; 30 | pos @larger_letter @origin' @normal_letter <18 0 0 0>; 31 | pos @widest_letter @origin' @larger_letter <18 0 0 0>; 32 | 33 | } kern; 34 | 35 | } kern; 36 | -------------------------------------------------------------------------------- /src/features/liga.fea: -------------------------------------------------------------------------------- 1 | feature liga { 2 | # Standard Ligatures 3 | 4 | # feature 5 | lookup CloseUp_1_ { 6 | ignore sub @case_default' @lowercase_actor; 7 | ignore sub @case_default' @case_default @lowercase_actor; 8 | ignore sub @case_default @case_default' @lowercase_actor; 9 | ignore sub @case_default' @case_default @case_default @lowercase_actor; 10 | ignore sub @case_default @case_default' @case_default @lowercase_actor; 11 | ignore sub @case_default @case_default @case_default' @lowercase_actor; 12 | ignore sub @case_default' @case_default @case_default @case_default @lowercase_actor; 13 | ignore sub @case_default @case_default' @case_default @case_default @lowercase_actor; 14 | ignore sub @case_default @case_default @case_default' @case_default @lowercase_actor; 15 | ignore sub @case_default @case_default @case_default @case_default' @lowercase_actor; 16 | ignore sub @case_default' @case_default @case_default @case_default @case_default @lowercase_actor; 17 | ignore sub @case_default @case_default' @case_default @case_default @case_default @lowercase_actor; 18 | ignore sub @case_default @case_default @case_default' @case_default @case_default @lowercase_actor; 19 | ignore sub @case_default @case_default @case_default @case_default' @case_default @lowercase_actor; 20 | ignore sub @case_default @case_default @case_default @case_default @case_default' @lowercase_actor; 21 | sub @uppercase_actor @case_default' by @case_top; 22 | } CloseUp_1_; 23 | 24 | lookup CloseUp_2_ { 25 | ignore sub @lowercase_actor @case_default'; 26 | ignore sub @lowercase_actor @case_default @case_default'; 27 | ignore sub @lowercase_actor @case_default @case_default @case_default'; 28 | ignore sub @lowercase_actor @case_default @case_default @case_default @case_default'; 29 | ignore sub @lowercase_actor @case_default @case_default @case_default @case_default @case_default'; 30 | sub @case_default' @uppercase_actor by @case_top; 31 | sub @case_default' @case_default @uppercase_actor by @case_top; 32 | sub @case_default' @case_default @case_default @uppercase_actor by @case_top; 33 | sub @case_default' @case_default @case_default @case_default @uppercase_actor by @case_top; 34 | sub @case_default' @case_default @case_default @case_default @case_default @uppercase_actor by @case_top; 35 | } CloseUp_2_; 36 | 37 | lookup StartEndSpace_ { 38 | sub @uppercase_actor @space_actor @case_default' @space_actor @uppercase_actor by @case_top; 39 | sub @uppercase_actor @space_actor @case_default' @case_default @space_actor @uppercase_actor by @case_top; 40 | sub @uppercase_actor @space_actor @case_default' @case_default @case_default @space_actor @uppercase_actor by @case_top; 41 | sub @uppercase_actor @space_actor @case_default' @case_default @case_default @case_default @space_actor @uppercase_actor by @case_top; 42 | sub @uppercase_actor @space_actor @case_default' @case_default @case_default @case_default @case_default @space_actor @uppercase_actor by @case_top; 43 | } StartEndSpace_; 44 | 45 | lookup InBetween_ { 46 | sub @case_top @case_default' by @case_top; 47 | } InBetween_; 48 | 49 | lookup Fix_ { 50 | sub @case_default @case_top' by @case_default; 51 | } Fix_; 52 | 53 | 54 | 55 | # classes 56 | 57 | @dflt = [exclam exclam.square period period.square slash slash.case colon colon.square colon.case colon.case.square semicolon semicolon.square question question.square backslash backslash.case bar bar.case less less.case greater greater.case]; 58 | @c2_1 = [exclam.c2_1 exclam.square.c2_1 period.c2_1 period.square.c2_1 slash.c2_1 slash.case.c2_1 colon.c2_1 colon.square.c2_1 colon.case.c2_1 colon.case.square.c2_1 semicolon.c2_1 semicolon.square.c2_1 question.c2_1 question.square.c2_1 backslash.c2_1 backslash.case.c2_1 bar.c2_1 bar.case.c2_1 less.c2_1 less.case.c2_1 greater.c2_1 greater.case.c2_1]; 59 | @c2_2 = [exclam.c2_2 exclam.square.c2_2 period.c2_2 period.square.c2_2 slash.c2_2 slash.case.c2_2 colon.c2_2 colon.square.c2_2 colon.case.c2_2 colon.case.square.c2_2 semicolon.c2_2 semicolon.square.c2_2 question.c2_2 question.square.c2_2 backslash.c2_2 backslash.case.c2_2 bar.c2_2 bar.case.c2_2 less.c2_2 less.case.c2_2 greater.c2_2 greater.case.c2_2]; 60 | @c3_1 = [exclam.c3_1 exclam.square.c3_1 period.c3_1 period.square.c3_1 slash.c3_1 slash.case.c3_1 colon.c3_1 colon.square.c3_1 colon.case.c3_1 colon.case.square.c3_1 semicolon.c3_1 semicolon.square.c3_1 question.c3_1 question.square.c3_1 backslash.c3_1 backslash.case.c3_1 bar.c3_1 bar.case.c3_1 less.c3_1 less.case.c3_1 greater.c3_1 greater.case.c3_1]; 61 | @c3_3 = [exclam.c3_3 exclam.square.c3_3 period.c3_3 period.square.c3_3 slash.c3_3 slash.case.c3_3 colon.c3_3 colon.square.c3_3 colon.case.c3_3 colon.case.square.c3_3 semicolon.c3_3 semicolon.square.c3_3 question.c3_3 question.square.c3_3 backslash.c3_3 backslash.case.c3_3 bar.c3_3 bar.case.c3_3 less.c3_3 less.case.c3_3 greater.c3_3 greater.case.c3_3]; 62 | @exceptions = [numbersign]; 63 | 64 | # exceptions 65 | ignore sub @exceptions @dflt'; 66 | ignore sub @exceptions @dflt @dflt'; 67 | ignore sub @dflt' @exceptions; 68 | ignore sub @dflt' @dflt @exceptions; 69 | 70 | ignore sub @greater' @less @slash; 71 | ignore sub @colon' @slash @slash; 72 | ignore sub @colon @slash' @slash; 73 | 74 | # feature 75 | ignore sub @dflt' @dflt @dflt @dflt; 76 | ignore sub @dflt @dflt' @dflt @dflt; 77 | ignore sub @dflt @dflt @dflt' @dflt; 78 | ignore sub @dflt @dflt @dflt @dflt'; 79 | 80 | sub @dflt' @dflt @dflt by @c3_1; 81 | sub @c3_1 @dflt @dflt' by @c3_3; 82 | 83 | ignore sub @c3_1 @dflt' @dflt; 84 | 85 | sub @dflt' @dflt by @c2_1; 86 | sub @c2_1 @dflt' by @c2_2; 87 | 88 | 89 | 90 | # feature 91 | sub @narrow_letter @origin' @widest_letter by @leftL; 92 | sub @narrow_letter @origin' @larger_letter by @leftM; 93 | sub @normal_letter @origin' @widest_letter by @leftM; 94 | sub @narrow_letter @origin' @normal_letter by @leftS; 95 | sub @normal_letter @origin' @larger_letter by @leftS; 96 | sub @larger_letter @origin' @widest_letter by @leftS; 97 | 98 | sub @widest_letter @origin' @narrow_letter by @rightL; 99 | sub @larger_letter @origin' @narrow_letter by @rightM; 100 | sub @normal_letter @origin' @narrow_letter by @rightS; 101 | sub @widest_letter @origin' @normal_letter by @rightM; 102 | sub @larger_letter @origin' @normal_letter by @rightS; 103 | sub @widest_letter @origin' @larger_letter by @rightS; 104 | 105 | } liga; 106 | 107 | -------------------------------------------------------------------------------- /src/features/none.fea: -------------------------------------------------------------------------------- 1 | feature none { 2 | # Character Variant 01—99 3 | 4 | #> featur 5 | sub nbspace by space; 6 | #< feature 7 | 8 | } none; 9 | -------------------------------------------------------------------------------- /src/features/pipe.fea: -------------------------------------------------------------------------------- 1 | feature c003 { 2 | # Coding Ligature 001—999 3 | # Pipe substitution 4 | 5 | # classes 6 | @less_ = [less less.c2_1 less.c2_2 less.c3_1 less.c3_3]; 7 | @less_case = [less.case less.case.c2_1 less.case.c2_2 less.case.c3_1 less.case.c3_3]; 8 | @greater_ = [greater greater.c2_1 greater.c2_2 greater.c3_1 greater.c3_3]; 9 | @greater_case = [greater.case greater.case.c2_1 greater.case.c2_2 greater.case.c3_1 greater.case.c3_3]; 10 | @bar_pipe = [bar.pipe bar.case.pipe]; 11 | @bar_c = [bar.c2_1 bar.c2_2 bar bar.c3_1 bar.c3_3 bar.pipe]; 12 | @bar_c_case = [bar.case.c2_1 bar.case.c2_2 bar.case bar.case.c3_1 bar.case.c3_3 bar.case.pipe]; 13 | 14 | # feature 15 | lookup BarFix { 16 | sub @less_ @bar_c' by bar.pipe; 17 | sub @bar_c' @bar_c @bar_c @greater_ by bar.pipe; 18 | sub @bar_c' @bar_c @greater_ by bar.pipe; 19 | sub @bar_c' @greater_ by bar.pipe; 20 | 21 | sub @less_ @bar_c_case' by bar.case.pipe; 22 | sub @bar_c_case' @bar_c_case @bar_c_case @greater_ by bar.case.pipe; 23 | sub @bar_c_case' @bar_c_case @greater_ by bar.case.pipe; 24 | sub @bar_c_case' @greater_ by bar.case.pipe; 25 | } BarFix; 26 | 27 | lookup BarToBarPipe { 28 | sub @bar_pipe @bar_c' by bar.pipe; 29 | sub @bar_pipe @bar_c_case' by bar.case.pipe; 30 | } BarToBarPipe; 31 | 32 | lookup Start { 33 | sub @less_' @bar_pipe by less.pipe; 34 | sub @less_case' @bar_pipe by less.pipe.case; 35 | } Start; 36 | 37 | lookup End { 38 | sub @bar_pipe @greater_' by greater.pipe; 39 | sub @bar_pipe @greater_case' by greater.pipe.case; 40 | } End; 41 | 42 | } c003; 43 | 44 | -------------------------------------------------------------------------------- /src/features/posa.fea: -------------------------------------------------------------------------------- 1 | feature c002 { 2 | # Coding Ligature 001—999 3 | # Adjust punctuation 4 | 5 | #> feature 6 | 7 | pos @uppercase_actor @adjust_punctuation' @adjust_punctuation @uppercase_actor <40 0 0 0>; 8 | pos @uppercase_actor @adjust_punctuation @adjust_punctuation' @uppercase_actor <-40 0 0 0>; 9 | pos @uppercase_actor @adjust_punctuation' @adjust_punctuation @adjust_punctuation @uppercase_actor <80 0 0 0>; 10 | pos @uppercase_actor @adjust_punctuation @adjust_punctuation' @adjust_punctuation @uppercase_actor <0 0 0 0>; 11 | pos @uppercase_actor @adjust_punctuation @adjust_punctuation @adjust_punctuation' @uppercase_actor <-80 0 0 0>; 12 | 13 | pos @space_actor @adjust_punctuation' @adjust_punctuation @space_actor <40 0 0 0>; 14 | pos @space_actor @adjust_punctuation @adjust_punctuation' @space_actor <-40 0 0 0>; 15 | pos @space_actor @adjust_punctuation' @adjust_punctuation @adjust_punctuation @space_actor <80 0 0 0>; 16 | pos @space_actor @adjust_punctuation @adjust_punctuation' @adjust_punctuation @space_actor <0 0 0 0>; 17 | pos @space_actor @adjust_punctuation @adjust_punctuation @adjust_punctuation' @space_actor <-80 0 0 0>; 18 | 19 | #< feature 20 | 21 | } c002; 22 | -------------------------------------------------------------------------------- /src/features/progress.fea: -------------------------------------------------------------------------------- 1 | feature c006 { 2 | # Coding Ligature 001—999 3 | # Progress bar substitution 4 | 5 | # classes 6 | @empty = [period period.c2_1 period.c2_2 period.c3_1 period.c3_3 period.square period.square.c2_1 period.square.c2_2 period.square.c3_1 period.square.c3_3 @space_actor]; 7 | @fills = [numbersign equal equal.case equal.arrow equal.arrow.case]; 8 | @indic = [greater greater.case greater.arrow_start_equal greater.arrow_start_equal.case]; 9 | @l_bracket = [bracketleft bracketleft.case parenleft parenleft.case]; 10 | @r_bracket = [bracketright bracketright.case parenright parenright.case]; 11 | 12 | # feature 13 | lookup Progress_start { 14 | sub @l_bracket' @empty @empty @empty @empty @empty by uniEE00; 15 | sub @l_bracket' @fills @empty @empty @empty @empty by uniEE03; 16 | sub @l_bracket' @fills @fills @empty @empty @empty by uniEE03; 17 | sub @l_bracket' @fills @fills @fills @empty @empty by uniEE03; 18 | sub @l_bracket' @fills @fills @fills @fills @empty by uniEE03; 19 | sub @l_bracket' @fills @fills @fills @fills @fills by uniEE03; 20 | sub @l_bracket' @indic @empty @empty @empty @empty by uniEE03; 21 | } Progress_start; 22 | 23 | lookup Progress_middle { 24 | sub uniEE00 @empty' by uniEE01; 25 | sub uniEE01 @empty' by uniEE01; 26 | sub uniEE03 @fills' by uniEE04; 27 | sub uniEE04 @fills' by uniEE04; 28 | sub uniEE04 @empty' by uniEE01; 29 | sub uniEE03 @indic' by uniEE04; 30 | sub uniEE04 @indic' by uniEE04; 31 | } Progress_middle; 32 | 33 | lookup Progress_end { 34 | sub uniEE04 @r_bracket' by uniEE05; 35 | sub uniEE01 @r_bracket' by uniEE02; 36 | } Progress_end; 37 | 38 | lookup Spinner { 39 | sub uniEE02 @space_actor hyphen' by uniEE06; 40 | sub uniEE02 @space_actor backslash' by uniEE07; 41 | sub uniEE02 @space_actor bar' by uniEE08; 42 | sub uniEE02 @space_actor slash' by uniEE09; 43 | sub uniEE02 hyphen' by uniEE06; 44 | sub uniEE02 backslash' by uniEE07; 45 | sub uniEE02 bar' by uniEE08; 46 | sub uniEE02 slash' by uniEE09; 47 | 48 | sub uniEE05 @space_actor hyphen' by uniEE06; 49 | sub uniEE05 @space_actor backslash' by uniEE07; 50 | sub uniEE05 @space_actor bar' by uniEE08; 51 | sub uniEE05 @space_actor slash' by uniEE09; 52 | sub uniEE05 hyphen' by uniEE06; 53 | sub uniEE05 backslash' by uniEE07; 54 | sub uniEE05 bar' by uniEE08; 55 | sub uniEE05 slash' by uniEE09; 56 | 57 | sub hyphen' @space_actor uniEE00 by uniEE06; 58 | sub backslash' @space_actor uniEE00 by uniEE07; 59 | sub bar' @space_actor uniEE00 by uniEE08; 60 | sub slash' @space_actor uniEE00 by uniEE09; 61 | sub hyphen' uniEE00 by uniEE06; 62 | sub backslash' uniEE00 by uniEE07; 63 | sub bar' uniEE00 by uniEE08; 64 | sub slash' uniEE00 by uniEE09; 65 | 66 | sub hyphen' @space_actor uniEE03 by uniEE06; 67 | sub backslash' @space_actor uniEE03 by uniEE07; 68 | sub bar' @space_actor uniEE03 by uniEE08; 69 | sub slash' @space_actor uniEE03 by uniEE09; 70 | sub hyphen' uniEE03 by uniEE06; 71 | sub backslash' uniEE03 by uniEE07; 72 | sub bar' uniEE03 by uniEE08; 73 | sub slash' uniEE03 by uniEE09; 74 | } Spinner; 75 | 76 | } c006; 77 | -------------------------------------------------------------------------------- /src/features/ss01_less_equal-copy.fea: -------------------------------------------------------------------------------- 1 | feature ss01 { 2 | # Coding Feature 00-99 3 | # less_equal, exclam_equal substitution 4 | 5 | # feature 6 | sub @space_actor equal' equal @space_actor by equal_equal.liga; 7 | sub @space_actor equal_equal.liga equal' @space_actor by space; 8 | 9 | sub @space_actor equal' equal equal @space_actor by equal_equal_equal.liga; 10 | sub @space_actor equal_equal_equal.liga equal' equal @space_actor by space; 11 | sub @space_actor equal_equal_equal.liga space equal' @space_actor by space; 12 | 13 | sub @space_actor less' equal @space_actor by less_equal.liga; 14 | sub @space_actor less_equal.liga equal' @space_actor by space; 15 | sub @space_actor [less.arrow_start_equal less.arrow_start_equal.case]' [equal.arrow equal.arrow.case] @space_actor by less_equal.liga; 16 | sub @space_actor less_equal.liga [equal.arrow equal.arrow.case]' @space_actor by space; 17 | 18 | sub @space_actor greater' equal @space_actor by greater_equal.liga; 19 | sub @space_actor greater_equal.liga equal' @space_actor by space; 20 | 21 | sub @space_actor exclam' equal @space_actor by exclam_equal.liga; 22 | sub @space_actor exclam_equal.liga equal' @space_actor by space; 23 | 24 | sub @space_actor exclam' equal equal @space_actor by exclam_equal_equal.liga; 25 | sub @space_actor exclam_equal_equal.liga equal' equal @space_actor by space; 26 | sub @space_actor exclam_equal_equal.liga space equal' @space_actor by space; 27 | 28 | } ss01; 29 | -------------------------------------------------------------------------------- /src/features/ss01_less_equal.fea: -------------------------------------------------------------------------------- 1 | feature ss01 { 2 | # Coding Feature 00-99 3 | # less_equal, exclam_equal substitution 4 | 5 | # feature 6 | ignore sub [exclam exclam.square]' equal' equal' equal; 7 | sub [exclam exclam.square]' equal' equal' by exclam_equal_equal.liga; 8 | sub exclam_equal_equal.liga by exclam_equal_equal.liga space space; 9 | 10 | ignore sub [exclam exclam.square]' equal' equal; 11 | sub [exclam exclam.square]' equal' by exclam_equal.liga; 12 | sub exclam_equal.liga by exclam_equal.liga space; 13 | 14 | ignore sub less' equal' equal; 15 | sub less' equal' by less_equal.liga; 16 | sub less_equal.liga by less_equal.liga space; 17 | 18 | ignore sub greater' equal' equal; 19 | sub greater' equal' by greater_equal.liga; 20 | sub greater_equal.liga by greater_equal.liga space; 21 | 22 | ignore sub less equal' equal' equal'; 23 | ignore sub greater equal' equal' equal'; 24 | ignore sub equal' equal' equal' less; 25 | ignore sub equal' equal' equal' greater; 26 | ignore sub equal' equal' equal' equal; 27 | ignore sub equal equal' equal' equal'; 28 | sub equal' equal' equal' by equal_equal_equal.liga; 29 | sub equal_equal_equal.liga by equal_equal_equal.liga space space; 30 | 31 | ignore sub less equal' equal'; 32 | ignore sub greater equal' equal'; 33 | ignore sub equal' equal' less; 34 | ignore sub equal' equal' greater; 35 | ignore sub equal' equal' equal; 36 | ignore sub equal equal' equal'; 37 | sub equal' equal' by equal_equal.liga; 38 | sub equal_equal.liga by equal_equal.liga space; 39 | 40 | } ss01; 41 | -------------------------------------------------------------------------------- /src/features/ss02_arrows.fea: -------------------------------------------------------------------------------- 1 | feature ss02 { 2 | # Coding Feature 00-99 3 | # Arrows 4 | 5 | # classes 6 | @hyphen = [hyphen hyphen.case]; 7 | @hyphen_arrow = [hyphen.arrow hyphen.arrow.case]; 8 | @equal = [equal equal.case]; 9 | @equal_arrow = [equal.arrow equal.arrow.case]; 10 | @less_arrow_end = [less.arrow_end less.arrow_end.case]; 11 | @less_arrow_start = [less.arrow_start less.arrow_start.case]; 12 | @less_arrow_start_hyphen = [less.arrow_start_hyphen less.arrow_start_hyphen.case]; 13 | @less_arrow_start_equal = [less.arrow_start_equal less.arrow_start_equal.case]; 14 | @greater_arrow_end = [greater.arrow_end greater.arrow_end.case]; 15 | @greater_arrow_start = [greater.arrow_start greater.arrow_start.case]; 16 | @greater_arrow_start_hyphen = [greater.arrow_start_hyphen greater.arrow_start_hyphen.case]; 17 | @greater_arrow_start_equal = [greater.arrow_start_equal greater.arrow_start_equal.case]; 18 | @exclam = [exclam exclam.square]; 19 | 20 | # feature 21 | lookup TipStart_1 { 22 | ignore sub @space_actor @less' @equal @space_actor; 23 | ignore sub @space_actor @greater' @equal @space_actor; 24 | sub @less' @hyphen by @less_arrow_start_hyphen; 25 | sub @less' @equal by @less_arrow_start_equal; 26 | sub @greater' @hyphen by @greater_arrow_end; 27 | sub @greater' @equal by @greater_arrow_end; 28 | } TipStart_1; 29 | 30 | lookup TipStart_2 { 31 | sub @less' @less_arrow_start_hyphen by @less_arrow_start; 32 | sub @less' @less_arrow_start_equal by @less_arrow_start; 33 | sub @greater' @greater_arrow_end by @greater_arrow_end; 34 | } TipStart_2; 35 | 36 | lookup TipStart_3 { 37 | sub @less' @less_arrow_start by @less_arrow_start; 38 | sub @greater' @greater_arrow_end by @greater_arrow_end; 39 | } TipStart_3; 40 | 41 | 42 | 43 | lookup BodyStartA { 44 | sub @less_arrow_start_hyphen @hyphen' by @hyphen_arrow; 45 | sub @less_arrow_start_equal @equal' by @equal_arrow; 46 | sub @greater_arrow_end @hyphen' by @hyphen_arrow; 47 | sub @greater_arrow_end @equal' by @equal_arrow; 48 | } BodyStartA; 49 | 50 | 51 | 52 | lookup BodyStartB_1 { 53 | sub @hyphen' @less by @hyphen_arrow; 54 | sub @equal' @less by @equal_arrow; 55 | sub @hyphen' @greater by @hyphen_arrow; 56 | sub @equal' @greater by @equal_arrow; 57 | } BodyStartB_1; 58 | 59 | lookup BodyStartB_2 { 60 | sub @hyphen' @hyphen_arrow by @hyphen_arrow; 61 | sub @equal' @equal_arrow by @equal_arrow; 62 | } BodyStartB_2; 63 | 64 | lookup BodyStartB_3 { 65 | sub @hyphen' @hyphen_arrow by @hyphen_arrow; 66 | sub @equal' @equal_arrow by @equal_arrow; 67 | } BodyStartB_3; 68 | 69 | lookup BodyStartB_4 { 70 | sub @hyphen' @hyphen_arrow by @hyphen_arrow; 71 | sub @equal' @equal_arrow by @equal_arrow; 72 | } BodyStartB_4; 73 | 74 | lookup BodyStartB_5 { 75 | sub @hyphen' @hyphen_arrow by @hyphen_arrow; 76 | sub @equal' @equal_arrow by @equal_arrow; 77 | } BodyStartB_5; 78 | 79 | 80 | 81 | lookup BodyEnd { 82 | sub @hyphen_arrow @hyphen' by @hyphen_arrow; 83 | sub @equal_arrow @equal' by @equal_arrow; 84 | } BodyEnd; 85 | 86 | 87 | 88 | lookup TipEnd_1 { 89 | sub @hyphen_arrow @less' by @less_arrow_end; 90 | sub @equal_arrow @less' by @less_arrow_end; 91 | sub @hyphen_arrow @greater' by @greater_arrow_start_hyphen; 92 | sub @equal_arrow @greater' by @greater_arrow_start_equal; 93 | } TipEnd_1; 94 | 95 | lookup TipEnd_2 { 96 | sub @greater_arrow_start_hyphen @greater' by @greater_arrow_start; 97 | sub @greater_arrow_start_equal @greater' by @greater_arrow_start; 98 | } TipEnd_2; 99 | 100 | lookup TipEnd_3 { 101 | sub @less_arrow_end @less' by @less_arrow_end; 102 | sub @greater_arrow_start @greater' by @greater_arrow_start; 103 | } TipEnd_3; 104 | 105 | 106 | 107 | lookup HTMLcomment { 108 | sub @less' @exclam @hyphen @hyphen by @less_arrow_start_hyphen; 109 | sub @less_arrow_start_hyphen @exclam @hyphen' @hyphen by @hyphen_arrow; 110 | sub @less_arrow_start_hyphen @exclam @hyphen_arrow @hyphen' by @hyphen_arrow; 111 | } HTMLcomment; 112 | 113 | } ss02; 114 | -------------------------------------------------------------------------------- /src/features/ss03_case.fea: -------------------------------------------------------------------------------- 1 | feature ss03 { 2 | # Coding Feature 00-99 3 | # Case sensitive punctuation 4 | 5 | # feature 6 | lookup CloseUp_1 { 7 | ignore sub @case_default' @lowercase_actor; 8 | ignore sub @case_default' @case_default @lowercase_actor; 9 | ignore sub @case_default @case_default' @lowercase_actor; 10 | ignore sub @case_default' @case_default @case_default @lowercase_actor; 11 | ignore sub @case_default @case_default' @case_default @lowercase_actor; 12 | ignore sub @case_default @case_default @case_default' @lowercase_actor; 13 | ignore sub @case_default' @case_default @case_default @case_default @lowercase_actor; 14 | ignore sub @case_default @case_default' @case_default @case_default @lowercase_actor; 15 | ignore sub @case_default @case_default @case_default' @case_default @lowercase_actor; 16 | ignore sub @case_default @case_default @case_default @case_default' @lowercase_actor; 17 | ignore sub @case_default' @case_default @case_default @case_default @case_default @lowercase_actor; 18 | ignore sub @case_default @case_default' @case_default @case_default @case_default @lowercase_actor; 19 | ignore sub @case_default @case_default @case_default' @case_default @case_default @lowercase_actor; 20 | ignore sub @case_default @case_default @case_default @case_default' @case_default @lowercase_actor; 21 | ignore sub @case_default @case_default @case_default @case_default @case_default' @lowercase_actor; 22 | ignore sub @case_default @uppercase_actor @case_default'; 23 | ignore sub @case_default @case_default @uppercase_actor @case_default'; 24 | sub @uppercase_actor @case_default' by @case_top; 25 | } CloseUp_1; 26 | 27 | lookup CloseUp_2 { 28 | ignore sub @lowercase_actor @case_default'; 29 | ignore sub @lowercase_actor @case_default @case_default'; 30 | ignore sub @lowercase_actor @case_default @case_default @case_default'; 31 | ignore sub @lowercase_actor @case_default @case_default @case_default @case_default'; 32 | ignore sub @lowercase_actor @case_default @case_default @case_default @case_default @case_default'; 33 | ignore sub @case_default' @uppercase_actor @case_default; 34 | ignore sub @case_default' @uppercase_actor @case_default @case_default; 35 | sub @case_default' @uppercase_actor by @case_top; 36 | sub @case_default' @case_default @uppercase_actor by @case_top; 37 | sub @case_default' @case_default @case_default @uppercase_actor by @case_top; 38 | sub @case_default' @case_default @case_default @case_default @uppercase_actor by @case_top; 39 | sub @case_default' @case_default @case_default @case_default @case_default @uppercase_actor by @case_top; 40 | } CloseUp_2; 41 | 42 | lookup StartEndSpace { 43 | sub @uppercase_actor @space_actor @case_default' @space_actor @uppercase_actor by @case_top; 44 | sub @uppercase_actor @space_actor @case_default' @case_default @space_actor @uppercase_actor by @case_top; 45 | sub @uppercase_actor @space_actor @case_default' @case_default @case_default @space_actor @uppercase_actor by @case_top; 46 | sub @uppercase_actor @space_actor @case_default' @case_default @case_default @case_default @space_actor @uppercase_actor by @case_top; 47 | sub @uppercase_actor @space_actor @case_default' @case_default @case_default @case_default @case_default @space_actor @uppercase_actor by @case_top; 48 | } StartEndSpace; 49 | 50 | lookup InBetween { 51 | sub @case_top @case_default' by @case_top; 52 | } InBetween; 53 | 54 | lookup Fix { 55 | sub @case_default @case_top' by @case_default; 56 | } Fix; 57 | 58 | } ss03; 59 | -------------------------------------------------------------------------------- /src/features/ss03_case_inter.fea: -------------------------------------------------------------------------------- 1 | feature ss03 { 2 | # Coding Feature 00-99 3 | # Case sensitive punctuation 4 | 5 | # ------------------------------------------------------------------------------------- 6 | # BEGIN glyph class definitions 7 | 8 | @DASH = [hyphen endash emdash]; 9 | @DASH_CASE = [hyphen.case endash.case emdash.case]; 10 | @DASH_ANY = [@DASH @DASH_CASE]; 11 | 12 | # cap-height tall glyphs 13 | @UC = [ 14 | @Uppercase 15 | @Numeral 16 | 17 | # punctuation 18 | ampersand exclam exclamdbl exclamdown uni2049 question uni2047 uni2048 19 | questiondown interrobang invertedinterrobang bar paragraph 20 | 21 | # currency 22 | dollar cent yen sterling florin uni20BA uni20BD euro uni20B9 tenge peseta 23 | peso kip won lira austral hryvnia naira guarani coloncurrency cedi cruzeiro 24 | tugrik uni20AF mill afii57636 manat rupee lari franc 25 | 26 | # cap-tall symbols 27 | numero triagrt triagdn triagup warningSign blackleftpointingtriangle 28 | circleblack circlewhite 29 | diamondblack diamondblack_x diamondwhite diamondwhite_x 30 | sunWithRays blackSunWithRays 31 | heartWhiteSuit heartBlackSuit heavyBlackHeart 32 | upBlackArrow upWhiteArrow 33 | capslock placeofinterestsign control projective option alternativekeysymbol 34 | brokenCircleNorthWestArrow anticlockwiseOpenCircleArrow 35 | clockwiseOpenCircleArrow 36 | deleteleft deleteright clear ejectsymbol 37 | 38 | # percent and fractions 39 | onehalf onethird onequarter threequarters fivesixths onefraction seveneighths 40 | oneeighth fiveeighths threeeighths percent perthousand pertenthousand uni214D 41 | cadauna careof accountof addresssubject 42 | ]; 43 | 44 | # x-height tall glyphs 45 | @LC = [ 46 | @Lowercase 47 | ]; 48 | 49 | @CASE_DELIM_L = [ 50 | braceleft braceright 51 | bracketleft bracketright 52 | parenleft parenright 53 | ]; 54 | @CASE_NONDELIM_L = [ 55 | at 56 | multiply 57 | minus 58 | plus 59 | plusminus 60 | divide 61 | equal 62 | notequal 63 | endash 64 | figuredash 65 | emdash 66 | hyphen 67 | bullet 68 | openbullet 69 | hyphenbullet 70 | trianglebullet 71 | blackleftbullet 72 | blackrightbullet 73 | blackSmallSquare 74 | leftArrow 75 | leftLongArrow 76 | leftLongArrow2 77 | leftDoubleArrow 78 | leftLongDoubleArrow 79 | rightArrow 80 | rightLongArrow 81 | rightLongArrow2 82 | rightDoubleArrow 83 | rightLongDoubleArrow 84 | leftRightArrow 85 | leftRightLongArrow 86 | leftRightDoubleArrow 87 | leftRightLongDoubleArrow 88 | northEastArrow 89 | southEastArrow 90 | southWestArrow 91 | northWestArrow 92 | colon 93 | approxequal 94 | asciitilde 95 | less 96 | greater 97 | lessequal 98 | greaterequal 99 | ]; 100 | @CASE_L = [ 101 | @CASE_DELIM_L 102 | @CASE_NONDELIM_L 103 | ]; 104 | 105 | @CASE_DELIM_R = [ 106 | braceleft.case braceright.case 107 | bracketleft.case bracketright.case 108 | parenleft.case parenright.case 109 | ]; 110 | @CASE_NONDELIM_R = [ 111 | at.case 112 | multiply.case 113 | minus.case 114 | plus.case 115 | plusminus.case 116 | divide.case 117 | equal.case 118 | notequal.case 119 | endash.case 120 | figuredash.case 121 | emdash.case 122 | hyphen.case 123 | bullet.case 124 | openbullet.case 125 | hyphenbullet.case 126 | trianglebullet.case 127 | blackleftbullet.case 128 | blackrightbullet.case 129 | blackSmallSquare.case 130 | leftArrow.case 131 | leftLongArrow.case 132 | leftLongArrow2.case 133 | leftDoubleArrow.case 134 | leftLongDoubleArrow.case 135 | rightArrow.case 136 | rightLongArrow.case 137 | rightLongArrow2.case 138 | rightDoubleArrow.case 139 | rightLongDoubleArrow.case 140 | leftRightArrow.case 141 | leftRightLongArrow.case 142 | leftRightDoubleArrow.case 143 | leftRightLongDoubleArrow.case 144 | northEastArrow.case 145 | southEastArrow.case 146 | southWestArrow.case 147 | northWestArrow.case 148 | colon.case 149 | approxequal.case 150 | asciitilde.case 151 | less.case 152 | greater.case 153 | lessequal.case 154 | greaterequal.case 155 | ]; 156 | @CASE_R = [ 157 | @CASE_DELIM_R 158 | @CASE_NONDELIM_R 159 | ]; 160 | 161 | @Punctuation = [ 162 | slash bar quoteleft quoteright quotesingle quotedbl 163 | quotedblleft quotedblright quotedblbase quotesinglbase prime doubleprime 164 | tripleprime quadrupleprime primerev doubleprimerev tripleprimerev primemod 165 | doubleprimemod comma period ellipsis twodotleader semicolon underscore 166 | asciicircum circumflex 167 | asterisk 168 | ]; 169 | 170 | # END glyph class definitions 171 | # ------------------------------------------------------------------------------------- 172 | # BEGIN case 173 | 174 | # A foo' -> A foo.case 175 | # 176 | # ignore subs adjacent to lower case 177 | # 178 | # h[1,3] 179 | ignore sub @LC @CASE_DELIM_L @All @CASE_DELIM_L'; # h[X] 180 | ignore sub @LC @CASE_DELIM_L @All @All @CASE_DELIM_L'; # h[XX] 181 | ignore sub @LC @CASE_DELIM_L @All @All @All @CASE_DELIM_L'; # h[XXX] 182 | ignore sub @LC @CASE_DELIM_L @All @All @All @All @CASE_DELIM_L'; # h[XXXX] 183 | # x[]X 184 | ignore sub @LC @CASE_DELIM_L @CASE_DELIM_L' @UC; # x[]X 185 | ignore sub @LC @CASE_DELIM_L' @Whitespace @UC; # x[ X 186 | ignore sub @LC @CASE_DELIM_L' @Whitespace @Whitespace @UC; # x[ X 187 | ignore sub @LC @CASE_DELIM_L @CASE_DELIM_L' @Whitespace @UC; # x[] X 188 | ignore sub @LC @CASE_DELIM_L @CASE_DELIM_L' @Whitespace @Whitespace @UC; # x[] X 189 | ignore sub @LC @CASE_DELIM_L' @UC; # x[X 190 | 191 | # short runs of uc-lc, e.g "(Xx)", "[xxX]" 192 | ignore sub @CASE_DELIM_L' @UC @LC @CASE_DELIM_L; # (Xx) 193 | ignore sub @CASE_DELIM_L' @UC @All @LC @CASE_DELIM_L; # (X.x) 194 | ignore sub @CASE_DELIM_L @LC @UC @CASE_DELIM_L'; # (xX) 195 | ignore sub @CASE_DELIM_L @LC @All @UC @CASE_DELIM_L'; # (x.X) 196 | 197 | # 198 | # e.g. "x-M" 199 | ignore sub @LC @CASE_L'; # x- 200 | ignore sub @LC @CASE_L @CASE_L'; # x-- 201 | ignore sub @LC @CASE_L @CASE_L @CASE_L'; # x--- 202 | # ignore sub @LC [@CASE_L @Whitespace] @CASE_L'; # x--, x - 203 | # ignore sub @LC [@CASE_L @Whitespace] [@CASE_L @Whitespace] @CASE_L'; # x---, x --, x -, x- - 204 | # ignore sub @LC 205 | # [@CASE_L @Whitespace] 206 | # [@CASE_L @Whitespace] 207 | # [@CASE_L @Whitespace] 208 | # @CASE_L'; # x----, x ---, x --, x -, x- --, x- -, x-- - 209 | # ignore sub @LC 210 | # [@CASE_L @Whitespace] 211 | # [@CASE_L @Whitespace] 212 | # [@CASE_L @Whitespace] 213 | # [@CASE_L @Whitespace] 214 | # @CASE_L'; # x----- ... 215 | # 216 | # e.g. "x- " 217 | # ignore sub @LC @CASE_L' @Whitespace; # "x- " 218 | # ignore sub @LC @CASE_L' @Whitespace @Whitespace; # "x- " 219 | # 220 | # e.g. "-x" 221 | ignore sub @CASE_L' @LC; # -x 222 | ignore sub @CASE_L' @CASE_L @LC; # --x 223 | ignore sub @CASE_L' @CASE_L @CASE_L @LC; # ---x 224 | # ignore sub @CASE_L @CASE_L @CASE_L @CASE_L @LC; # ----x 225 | # ignore sub @CASE_L @CASE_L @CASE_L @CASE_L @CASE_L @LC; # -----x 226 | 227 | # 228 | # pairs with space, e.g. "( ) M" since we don't support subbing 229 | # all on the left side. 230 | ignore sub @CASE_DELIM_L @Whitespace @CASE_DELIM_L' @Whitespace [ @UC @CASE_R ]; 231 | # 232 | # e.g. "A-", "A -", "A -" 233 | sub [@UC @CASE_R] @CASE_L' by @CASE_R; 234 | sub [@UC @CASE_R] @Whitespace @CASE_L' by @CASE_R; 235 | sub [@UC @CASE_R] @Whitespace @Whitespace @CASE_L' by @CASE_R; 236 | 237 | # foo' foo foo foo foo A -> foo.case foo foo foo foo A 238 | # foo' foo foo foo A -> foo.case foo foo foo A 239 | # foo' foo foo A -> foo.case foo foo A 240 | # foo' foo A -> foo.case foo A 241 | # foo' A -> foo.case A 242 | # Note: since we look quite far back, sequences like x{}[]M will case both 243 | # the square brackets next to M _and_ the curly braces to become .case 244 | # 245 | # e.g. "-A", "--A", "---A", "----A", "-----A" 246 | sub @CASE_L' [@UC @CASE_R] by @CASE_R; 247 | sub @CASE_L' @CASE_L [@CASE_R @UC] by @CASE_R; 248 | sub @CASE_L' @CASE_L @CASE_L [@CASE_R @UC] by @CASE_R; 249 | sub @CASE_L' @CASE_L @CASE_L @CASE_L [@CASE_R @UC] by @CASE_R; 250 | sub @CASE_L' @CASE_L @CASE_L @CASE_L @CASE_L [@CASE_R @UC] by @CASE_R; 251 | # 252 | # e.g. "- A", "-- A", "--- A", "---- A", "----- A" 253 | sub @CASE_L' @Whitespace [@UC @CASE_R] by @CASE_R; 254 | sub @CASE_L' @CASE_L @Whitespace [@CASE_R @UC] by @CASE_R; 255 | sub @CASE_L' @CASE_L @CASE_L @Whitespace [@CASE_R @UC] by @CASE_R; 256 | sub @CASE_L' @CASE_L @CASE_L @CASE_L @Whitespace [@CASE_R @UC] by @CASE_R; 257 | sub @CASE_L' @CASE_L @CASE_L @CASE_L @CASE_L @Whitespace [@CASE_R @UC] by @CASE_R; 258 | # 259 | # e.g. "- A", "-- A", "--- A", "---- A", "----- A" 260 | sub @CASE_L' @Whitespace @Whitespace [@UC @CASE_R] by @CASE_R; 261 | sub @CASE_L' @CASE_L @Whitespace @Whitespace [@CASE_R @UC] by @CASE_R; 262 | sub @CASE_L' @CASE_L @CASE_L @Whitespace @Whitespace [@CASE_R @UC] by @CASE_R; 263 | sub @CASE_L' @CASE_L @CASE_L @CASE_L @Whitespace @Whitespace [@CASE_R @UC] by @CASE_R; 264 | sub @CASE_L' @CASE_L @CASE_L @CASE_L @CASE_L @Whitespace @Whitespace [@CASE_R @UC] by @CASE_R; 265 | 266 | # X(_) 267 | sub @CASE_DELIM_R @Punctuation @CASE_DELIM_L' by @CASE_DELIM_R; 268 | 269 | # in between number position adjustment, e.g. 3 /multiply 4 -> 3 multiply.case 4 270 | @between_num_L = [multiply asterisk]; 271 | @between_num_R = [multiply.case asterisk.case]; 272 | sub @Numeral @between_num_L' @Numeral by @between_num_R; # 3*9 273 | sub @Numeral @Whitespace @between_num_L' @Numeral by @between_num_R; # 3 *9 274 | sub @Numeral @Whitespace @Whitespace @between_num_L' @Numeral by @between_num_R; # 3 *9 275 | sub @Numeral @between_num_L' @Whitespace @Numeral by @between_num_R; # 3* 9 276 | sub @Numeral @Whitespace @between_num_L' @Whitespace @Numeral by @between_num_R; # 3 * 9 277 | sub @Numeral @Whitespace @Whitespace @between_num_L' @Whitespace @Numeral by @between_num_R; # 3 * 9 278 | sub @Numeral @between_num_L' @Whitespace @Whitespace @Numeral by @between_num_R; # 3* 9 279 | sub @Numeral @Whitespace @between_num_L' @Whitespace @Whitespace @Numeral by @between_num_R; # 3 * 9 280 | sub @Numeral @Whitespace @Whitespace @between_num_L' @Whitespace @Whitespace @Numeral by @between_num_R; # 3 * 9 281 | 282 | # END case 283 | # ------------------------------------------------------------------------------------- 284 | 285 | } ss03; 286 | -------------------------------------------------------------------------------- /src/features/ss04_ellipsis.fea: -------------------------------------------------------------------------------- 1 | feature ss04 { 2 | # Coding Feature 00-99 3 | # Adjust punctuation horizontally 4 | 5 | # classes 6 | 7 | @dflt = [exclam exclam.square period period.square slash slash.case colon colon.square colon.case colon.case.square semicolon semicolon.square question question.square backslash backslash.case bar bar.case less less.case greater greater.case]; 8 | @c2_1 = [exclam.c2_1 exclam.square.c2_1 period.c2_1 period.square.c2_1 slash.c2_1 slash.case.c2_1 colon.c2_1 colon.square.c2_1 colon.case.c2_1 colon.case.square.c2_1 semicolon.c2_1 semicolon.square.c2_1 question.c2_1 question.square.c2_1 backslash.c2_1 backslash.case.c2_1 bar.c2_1 bar.case.c2_1 less.c2_1 less.case.c2_1 greater.c2_1 greater.case.c2_1]; 9 | @c2_2 = [exclam.c2_2 exclam.square.c2_2 period.c2_2 period.square.c2_2 slash.c2_2 slash.case.c2_2 colon.c2_2 colon.square.c2_2 colon.case.c2_2 colon.case.square.c2_2 semicolon.c2_2 semicolon.square.c2_2 question.c2_2 question.square.c2_2 backslash.c2_2 backslash.case.c2_2 bar.c2_2 bar.case.c2_2 less.c2_2 less.case.c2_2 greater.c2_2 greater.case.c2_2]; 10 | @c3_1 = [exclam.c3_1 exclam.square.c3_1 period.c3_1 period.square.c3_1 slash.c3_1 slash.case.c3_1 colon.c3_1 colon.square.c3_1 colon.case.c3_1 colon.case.square.c3_1 semicolon.c3_1 semicolon.square.c3_1 question.c3_1 question.square.c3_1 backslash.c3_1 backslash.case.c3_1 bar.c3_1 bar.case.c3_1 less.c3_1 less.case.c3_1 greater.c3_1 greater.case.c3_1]; 11 | @c3_3 = [exclam.c3_3 exclam.square.c3_3 period.c3_3 period.square.c3_3 slash.c3_3 slash.case.c3_3 colon.c3_3 colon.square.c3_3 colon.case.c3_3 colon.case.square.c3_3 semicolon.c3_3 semicolon.square.c3_3 question.c3_3 question.square.c3_3 backslash.c3_3 backslash.case.c3_3 bar.c3_3 bar.case.c3_3 less.c3_3 less.case.c3_3 greater.c3_3 greater.case.c3_3]; 12 | @exceptions = [numbersign]; 13 | 14 | # exceptions 15 | ignore sub @exceptions @dflt'; 16 | ignore sub @exceptions @dflt @dflt'; 17 | ignore sub @dflt' @exceptions; 18 | ignore sub @dflt' @dflt @exceptions; 19 | 20 | ignore sub @greater' @less @slash; 21 | ignore sub @colon' @slash @slash; 22 | ignore sub @colon @slash' @slash; 23 | 24 | # feature 25 | ignore sub @dflt' @dflt @dflt @dflt; 26 | ignore sub @dflt @dflt' @dflt @dflt; 27 | ignore sub @dflt @dflt @dflt' @dflt; 28 | ignore sub @dflt @dflt @dflt @dflt'; 29 | 30 | sub @dflt' @dflt @dflt by @c3_1; 31 | sub @c3_1 @dflt @dflt' by @c3_3; 32 | 33 | ignore sub @c3_1 @dflt' @dflt; 34 | 35 | sub @dflt' @dflt by @c2_1; 36 | sub @c2_1 @dflt' by @c2_2; 37 | 38 | } ss04; -------------------------------------------------------------------------------- /src/features/ss05_smartkerning copy 2.fea: -------------------------------------------------------------------------------- 1 | feature ss05 { 2 | # Coding Feature 00-99 3 | # Smart kerning 4 | 5 | # feature 6 | # lookup sk_left { 7 | sub @narrow_letter @origin' @widest_letter by @leftL; 8 | sub @narrow_letter @origin' @larger_letter by @leftM; 9 | sub @normal_letter @origin' @widest_letter by @leftM; 10 | sub @narrow_letter @origin' @normal_letter by @leftS; 11 | sub @normal_letter @origin' @larger_letter by @leftS; 12 | # sub @larger_letter @origin' @widest_letter by @leftS; 13 | # } sk_left; 14 | 15 | # lookup sk_right { 16 | sub @widest_letter @origin' @narrow_letter by @rightL; 17 | sub @larger_letter @origin' @narrow_letter by @rightM; 18 | sub @normal_letter @origin' @narrow_letter by @rightS; 19 | sub @widest_letter @origin' @normal_letter by @rightM; 20 | sub @larger_letter @origin' @normal_letter by @rightS; 21 | # sub @widest_letter @origin' @larger_letter by @rightS; 22 | # } sk_right; 23 | 24 | 25 | 26 | } ss05; 27 | -------------------------------------------------------------------------------- /src/features/ss05_smartkerning copy.fea: -------------------------------------------------------------------------------- 1 | feature ss05 { 2 | # Coding Feature 00-99 3 | # Smart kerning 4 | 5 | # feature 6 | # lookup sk_left { 7 | sub @narrow_letter @origin' @widest_letter by @leftL; 8 | sub @narrow_letter @origin' @larger_letter by @leftM; 9 | sub @normal_letter @origin' @widest_letter by @leftM; 10 | sub @narrow_letter @origin' @normal_letter by @leftS; 11 | sub @normal_letter @origin' @larger_letter by @leftS; 12 | sub @larger_letter @origin' @widest_letter by @leftS; 13 | # } sk_left; 14 | 15 | # lookup sk_right { 16 | sub @widest_letter @origin' @narrow_letter by @rightL; 17 | sub @larger_letter @origin' @narrow_letter by @rightM; 18 | sub @normal_letter @origin' @narrow_letter by @rightS; 19 | sub @widest_letter @origin' @normal_letter by @rightM; 20 | sub @larger_letter @origin' @normal_letter by @rightS; 21 | sub @widest_letter @origin' @larger_letter by @rightS; 22 | # } sk_right; 23 | 24 | 25 | 26 | } ss05; 27 | -------------------------------------------------------------------------------- /src/features/ss05_smartkerning.fea: -------------------------------------------------------------------------------- 1 | feature ss05 { 2 | # Coding Feature 00-99 3 | # Smart kerning 4 | 5 | # feature 6 | 7 | sub @narrow_letter @origin' @widest_letter by @leftL; 8 | sub @narrow_letter @origin' @larger_letter by @leftM; 9 | sub @normal_letter @origin' @widest_letter by @leftM; 10 | sub @narrow_letter @origin' @normal_letter by @leftS; 11 | sub @normal_letter @origin' @larger_letter by @leftS; 12 | sub @larger_letter @origin' @widest_letter by @leftS; 13 | 14 | sub @widest_letter @origin' @narrow_letter by @rightL; 15 | sub @larger_letter @origin' @narrow_letter by @rightM; 16 | sub @normal_letter @origin' @narrow_letter by @rightS; 17 | sub @widest_letter @origin' @normal_letter by @rightM; 18 | sub @larger_letter @origin' @normal_letter by @rightS; 19 | sub @widest_letter @origin' @larger_letter by @rightS; 20 | 21 | 22 | ignore sub @narrow_letter @origin' @widest_letter; 23 | ignore sub @narrow_letter @origin' @larger_letter; 24 | ignore sub @narrow_letter @origin' @normal_letter; 25 | ignore sub @narrow_letter @origin' @narrow_letter; 26 | 27 | ignore sub @normal_letter @origin' @widest_letter; 28 | ignore sub @normal_letter @origin' @larger_letter; 29 | ignore sub @normal_letter @origin' @normal_letter; 30 | ignore sub @normal_letter @origin' @narrow_letter; 31 | 32 | ignore sub @larger_letter @origin' @widest_letter; 33 | ignore sub @larger_letter @origin' @larger_letter; 34 | ignore sub @larger_letter @origin' @normal_letter; 35 | ignore sub @larger_letter @origin' @narrow_letter; 36 | 37 | ignore sub @widest_letter @origin' @widest_letter; 38 | ignore sub @widest_letter @origin' @larger_letter; 39 | ignore sub @widest_letter @origin' @normal_letter; 40 | ignore sub @widest_letter @origin' @narrow_letter; 41 | 42 | sub @origin' @widest_letter by @leftL; 43 | sub @origin' @larger_letter by @leftM; 44 | sub @origin' @normal_letter by @leftS; 45 | 46 | sub @widest_letter @origin' by @rightL; 47 | sub @larger_letter @origin' by @rightM; 48 | sub @normal_letter @origin' by @rightS; 49 | 50 | } ss05; 51 | -------------------------------------------------------------------------------- /src/features/ss06_smartkerning.fea: -------------------------------------------------------------------------------- 1 | feature ss06 { 2 | # Coding Feature 00-99 3 | # Smart kerning 4 | 5 | # feature 6 | 7 | lookup nr { 8 | sub @normal_letter @origin' @narrow_letter by @rightS; 9 | sub @larger_letter @origin' @narrow_letter by @rightS; 10 | } nr; 11 | 12 | lookup rl { 13 | sub @narrow_letter @origin' @normal_letter by @leftS; 14 | sub @narrow_letter @origin' @larger_letter by @leftS; 15 | } rl; 16 | 17 | lookup lw { 18 | sub @larger_letter @origin' @widest_letter by @leftS; 19 | sub @widest_letter @origin' @larger_letter by @rightS; 20 | } lw; 21 | 22 | 23 | 24 | } ss06; 25 | -------------------------------------------------------------------------------- /src/features/zero.fea: -------------------------------------------------------------------------------- 1 | feature zero { 2 | # Slashed Zero 3 | 4 | #> featur 5 | 6 | sub [zero zero.square] by zero.zero; 7 | sub [zero.dnom zero.dnom.square] by zero.dnom.zero; 8 | sub [zero.numr zero.numr.square] by zero.numr.zero; 9 | sub [uni2080 uni2080.square] by uni2080.zero; 10 | sub [uni2070 uni2070.square] by uni2070.zero; 11 | 12 | #< feature 13 | 14 | } zero; 15 | -------------------------------------------------------------------------------- /src/fonts/CommitMono-1.143.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/CommitMono-1.143.zip -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-200Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-200Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-200Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-200Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-225Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-225Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-225Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-225Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-250Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-250Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-250Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-250Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-275Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-275Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-275Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-275Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-300Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-300Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-300Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-300Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-325Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-325Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-325Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-325Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-350Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-350Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-350Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-350Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-375Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-375Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-375Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-375Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-400Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-400Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-400Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-400Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-425Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-425Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-425Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-425Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-450Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-450Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-450Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-450Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-475Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-475Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-475Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-475Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-500Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-500Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-500Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-500Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-525Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-525Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-525Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-525Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-550Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-550Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-550Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-550Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-575Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-575Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-575Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-575Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-600Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-600Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-600Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-600Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-625Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-625Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-625Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-625Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-650Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-650Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-650Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-650Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-675Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-675Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-675Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-675Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-700Italic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-700Italic.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-700Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-700Regular.otf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-VF.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-VF.ttf -------------------------------------------------------------------------------- /src/fonts/fontlab/CommitMonoV143-VF.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/fontlab/CommitMonoV143-VF.woff2 -------------------------------------------------------------------------------- /src/fonts/other/CascadiaCode.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/other/CascadiaCode.woff2 -------------------------------------------------------------------------------- /src/fonts/other/Consolas.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/other/Consolas.woff2 -------------------------------------------------------------------------------- /src/fonts/other/FiraCode.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/other/FiraCode.woff2 -------------------------------------------------------------------------------- /src/fonts/other/JetBrainsMono.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/other/JetBrainsMono.woff2 -------------------------------------------------------------------------------- /src/fonts/other/Menlo.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/other/Menlo.woff2 -------------------------------------------------------------------------------- /src/fonts/other/SourceCodePro.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/fonts/other/SourceCodePro.woff2 -------------------------------------------------------------------------------- /src/img/commitmono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eigilnikolajsen/commit-mono/ff532ce10d0107bd3e82a9ea004b4c98f7215ae7/src/img/commitmono.png -------------------------------------------------------------------------------- /src/js/code_section.js: -------------------------------------------------------------------------------- 1 | const codeForm = document.querySelector("#code_form") 2 | const codeFieldset = document.querySelector("#code_form fieldset") 3 | const codeDescription = document.querySelector("#code_description") 4 | 5 | function buildCode() { 6 | // console.log("buildCode") 7 | websiteData.sections.forEach((section) => { 8 | if (section.name == "code") { 9 | section.content.characters.forEach((character, index) => { 10 | const div = document.createElement("div") 11 | const input = document.createElement("input") 12 | input.type = "radio" 13 | input.name = "code" 14 | input.id = character.name 15 | input.classList.add("code_character") 16 | input.value = character.name 17 | input.dataset.forform = "code_form" 18 | // input.tabIndex = 0 19 | if (index == 0) { 20 | input.setAttribute("checked", "true") 21 | } 22 | const label = document.createElement("label") 23 | label.textContent = character.value 24 | label.setAttribute("for", character.name) 25 | div.append(input, label) 26 | codeFieldset.append(div) 27 | 28 | const p = document.createElement("p") 29 | p.tabIndex = 0 30 | p.dataset.edit = "true" 31 | p.classList.add("code_char") 32 | p.dataset.char = character.name 33 | p.textContent = character.description 34 | p.style.display = "none" 35 | codeDescription.append(p) 36 | }) 37 | } 38 | }) 39 | } 40 | 41 | let commitMonoFont 42 | async function updateCodeFont() { 43 | // console.log("updateCodeFont") 44 | opentype 45 | .load( 46 | `/src/fonts/fontlab/CommitMono${versionOfCommitMono}-${websiteData.weight}${ 47 | websiteData.italic ? "Italic" : "Regular" 48 | }.otf` 49 | ) 50 | .then((font) => { 51 | // // console.log(font) 52 | commitMonoFont = font 53 | updateCode(null, codeForm) 54 | }) 55 | .catch((err) => console.log(err)) 56 | 57 | // Promise.all([ 58 | // opentype.load("src/fonts/other/CascadiaCode-Regular.otf"), 59 | // opentype.load("src/fonts/other/CascadiaCode-Italic.otf"), 60 | // opentype.load("src/fonts/other/CascadiaCode-Bold.otf"), 61 | // opentype.load("src/fonts/other/CascadiaCode-BoldItalic.otf"), 62 | // opentype.load("src/fonts/other/CommitMono-400-Regular.otf"), 63 | // opentype.load("src/fonts/other/CommitMono-400-Italic.otf"), 64 | // opentype.load("src/fonts/other/CommitMono-700-Regular.otf"), 65 | // opentype.load("src/fonts/other/CommitMono-700-Italic.otf"), 66 | // ]).then((res) => { 67 | // res.forEach((font) => { 68 | // const { fontFamily, fontSubfamily, fullName, postScriptName } = font.names.windows 69 | // console.log(` 70 | // fontFamily: ${fontFamily?.en} 71 | // fontSubfamily: ${fontSubfamily?.en} 72 | // fullName: ${fullName?.en} 73 | // postScriptName: ${postScriptName?.en}`) 74 | // }) 75 | // }) 76 | } 77 | 78 | function updateCode(event, form) { 79 | // console.log("updateCode") 80 | const data = new FormData(form) 81 | let output = "" 82 | for (const entry of data) { 83 | output = `${entry[1]}` 84 | } 85 | 86 | let displayCharacter = "" 87 | let displayName = "" 88 | websiteData.sections.forEach((section) => { 89 | if (section.name == "code") { 90 | section.content.characters.forEach((character, index) => { 91 | if (character.name == output) { 92 | displayCharacter = character.value 93 | displayName = character.name 94 | const ps = document.querySelectorAll(".code_char") 95 | ps.forEach((p) => 96 | p.dataset.char == character.name ? (p.style.display = "block") : (p.style.display = "none") 97 | ) 98 | } 99 | }) 100 | } 101 | }) 102 | 103 | let selectedGlyphData 104 | if (commitMonoFont) { 105 | Object.values(commitMonoFont.glyphs.glyphs).forEach((glyph) => { 106 | if (glyph.name == output) selectedGlyphData = glyph 107 | }) 108 | updateCanvas(selectedGlyphData, commitMonoFont, displayCharacter, displayName) 109 | } 110 | 111 | if (event) event.preventDefault() 112 | } 113 | 114 | const canvasScale = 16 115 | 116 | const drawFontLine = (GLYPH_SCALE, ctx, upem, width, name, value, yOffset) => { 117 | let scaledValue = mapRange(value, 0, upem, 0, width * GLYPH_SCALE) 118 | scaledValue = width - scaledValue + (yOffset * GLYPH_SCALE * width) / upem 119 | 120 | ctx.strokeStyle = getCssVar("--text") 121 | ctx.beginPath() 122 | ctx.moveTo(7 * canvasScale, scaledValue) 123 | ctx.lineTo(width - 7 * canvasScale, scaledValue) 124 | ctx.closePath() 125 | ctx.stroke() 126 | 127 | ctx.fillStyle = getCssVar("--text") 128 | ctx.font = `${0.75 * canvasScale}px "CommitMono"` 129 | ctx.textAlign = "left" 130 | ctx.fillText(name, 0, scaledValue + 0.25 * canvasScale) 131 | ctx.textAlign = "left" 132 | ctx.fillText(value, width - 4 * canvasScale, scaledValue + 0.25 * canvasScale) 133 | } 134 | const drawFontLineVertical = (GLYPH_SCALE, ctx, upem, width, value, yOffset, ascender, descender) => { 135 | let scaledValue1 = mapRange(ascender, 0, upem, 0, width * GLYPH_SCALE) 136 | scaledValue1 = width - scaledValue1 + (yOffset * GLYPH_SCALE * width) / upem 137 | let scaledValue2 = mapRange(descender, 0, upem, 0, width * GLYPH_SCALE) 138 | scaledValue2 = width - scaledValue2 + (yOffset * GLYPH_SCALE * width) / upem 139 | 140 | ctx.strokeStyle = getCssVar("--text") 141 | ctx.beginPath() 142 | ctx.moveTo(value, scaledValue1) 143 | ctx.lineTo(value, scaledValue2) 144 | ctx.closePath() 145 | ctx.stroke() 146 | } 147 | 148 | function updateCanvas(selectedGlyphData, selectedFont, displayCharacter, displayName) { 149 | // initialize canvas 150 | let CANVAS_SCALE = window.devicePixelRatio 151 | const canvas = document.querySelector("#canvas") 152 | let canvasWidth = 60 * canvasScale 153 | let canvasHeight = 42 * canvasScale 154 | canvas.style.width = `${canvasWidth}px` 155 | canvas.style.height = `${canvasHeight}px` 156 | canvas.width = canvasWidth * CANVAS_SCALE 157 | canvas.height = canvasHeight * CANVAS_SCALE 158 | const ctx = canvas.getContext("2d") 159 | ctx.scale(CANVAS_SCALE, CANVAS_SCALE) 160 | 161 | let GLYPH_SCALE = 0.6 162 | ctx.clearRect(0, 0, canvasWidth, canvasHeight) 163 | 164 | if (selectedGlyphData.path) { 165 | const CANVAS_GLYPH_COMPOSITION_FILL = [ 166 | { 167 | type: "outline", 168 | fill: true, 169 | color: getCssVar("--text"), 170 | pointSize: undefined, 171 | }, 172 | ] 173 | const CANVAS_GLYPH_COMPOSITION_BEZIER = [ 174 | // { 175 | // type: "outline", 176 | // fill: true, 177 | // color: "rgba(0, 0, 0, 0.1)", 178 | // pointSize: undefined, 179 | // }, 180 | { 181 | type: "handles", 182 | fill: false, 183 | color: getCssVar("--middle"), 184 | pointSize: undefined, 185 | }, 186 | { 187 | type: "outline", 188 | fill: false, 189 | color: getCssVar("--text"), 190 | pointSize: undefined, 191 | }, 192 | { 193 | type: "points", 194 | fill: true, 195 | color: getCssVar("--text"), 196 | pointSize: 10, // size of point on bezier glyph 197 | }, 198 | { 199 | type: "handle points", 200 | fill: true, 201 | color: getCssVar("--middle"), 202 | pointSize: 10, // size of handles on bezier glyph 203 | }, 204 | ] 205 | 206 | const upem = selectedFont?.unitsPerEm || 1000 207 | const width = 60 * canvasScale 208 | 209 | const yOffset = -45 * canvasScale 210 | const xOffset = 20 * canvasScale 211 | const ascender = selectedFont?.tables.os2?.sTypoAscender || 750 212 | const capHeight = selectedFont?.tables.os2?.sCapHeight || 700 213 | const xHeight = selectedFont?.tables.os2?.sxHeight 214 | const baseline = 0 215 | const descender = selectedFont?.tables.os2?.sTypoDescender || -200 216 | drawFontLine(GLYPH_SCALE, ctx, upem, width, "Ascender", ascender, yOffset) 217 | drawFontLine(GLYPH_SCALE, ctx, upem, width, "Cap Height", capHeight, yOffset) 218 | drawFontLine(GLYPH_SCALE, ctx, upem, width, "X-height", xHeight || 500, yOffset) 219 | drawFontLine(GLYPH_SCALE, ctx, upem, width, "Baseline", baseline, yOffset) 220 | drawFontLine(GLYPH_SCALE, ctx, upem, width, "Descender", descender, yOffset) 221 | drawFontLineVertical(GLYPH_SCALE, ctx, upem, width, 7 * canvasScale, yOffset, ascender, descender) 222 | drawFontLineVertical(GLYPH_SCALE, ctx, upem, width, 30 * canvasScale, yOffset, ascender, descender) 223 | drawFontLineVertical(GLYPH_SCALE, ctx, upem, width, 53 * canvasScale, yOffset, ascender, descender) 224 | 225 | ctx.fillStyle = getCssVar("--text") 226 | ctx.font = `${0.75 * canvasScale}px "CommitMono"` 227 | ctx.textAlign = "center" 228 | ctx.fillText(displayName, (30 - 11.5) * canvasScale, 2.75 * canvasScale) 229 | ctx.fillText(displayName, (30 + 11.5) * canvasScale, 2.75 * canvasScale) 230 | 231 | // make ready transformation matrixes for manipulating paths 232 | let firstMatrix = new DOMMatrix() 233 | firstMatrix = firstMatrix.scaleSelf(width / upem) 234 | let secondMatrix = new DOMMatrix() 235 | secondMatrix = secondMatrix.scaleSelf(GLYPH_SCALE) 236 | secondMatrix = secondMatrix.translateSelf(-width * 0.5, -width) // translate to left edge, top 237 | secondMatrix = secondMatrix.translateSelf((width * 0.5) / GLYPH_SCALE, width / GLYPH_SCALE) // translate to center, baseline 238 | secondMatrix = secondMatrix.translateSelf(0, (yOffset * width) / upem) // translate yOffset 239 | secondMatrix = secondMatrix.translateSelf((xOffset * width) / upem, 0) // translate xOffset 240 | 241 | // set initial value for glyph composition based on if bezier is switched on or off 242 | // let canvasGlyphComposition = bezier ? CANVAS_GLYPH_COMPOSITION_BEZIER : CANVAS_GLYPH_COMPOSITION_FILL 243 | 244 | CANVAS_GLYPH_COMPOSITION_BEZIER.forEach((composite) => { 245 | const calcPointsize = composite.pointSize * (upem / 1000) 246 | const firstPath2d = glyphBezier(selectedGlyphData, upem, composite.type, calcPointsize) 247 | const secondPath2d = new Path2D() 248 | secondPath2d.addPath(firstPath2d, firstMatrix) 249 | const finalPath2d = new Path2D() 250 | finalPath2d.addPath(secondPath2d, secondMatrix) 251 | 252 | if (composite.fill) { 253 | ctx.fillStyle = composite.color 254 | ctx.fill(finalPath2d) 255 | } else { 256 | ctx.strokeStyle = composite.color 257 | ctx.stroke(finalPath2d) 258 | } 259 | }) 260 | CANVAS_GLYPH_COMPOSITION_FILL.forEach((composite) => { 261 | secondMatrix = secondMatrix.translateSelf((-2 * xOffset * width) / upem, 0) // translate xOffset 262 | 263 | const calcPointsize = composite.pointSize * (upem / 1000) 264 | const firstPath2d = glyphBezier(selectedGlyphData, upem, composite.type, calcPointsize) 265 | const secondPath2d = new Path2D() 266 | secondPath2d.addPath(firstPath2d, firstMatrix) 267 | const finalPath2d = new Path2D() 268 | finalPath2d.addPath(secondPath2d, secondMatrix) 269 | 270 | if (composite.fill) { 271 | ctx.fillStyle = composite.color 272 | ctx.fill(finalPath2d) 273 | } else { 274 | ctx.strokeStyle = composite.color 275 | ctx.stroke(finalPath2d) 276 | } 277 | }) 278 | } 279 | } 280 | 281 | function glyphBezier(glyph, upem, typeOfOutline, pointSize) { 282 | let ps = pointSize 283 | let offsetX = (upem - glyph.advanceWidth) * 0.5 284 | let path2d = new Path2D() 285 | 286 | if (typeOfOutline == "outline") { 287 | let commandString = "" 288 | glyph.path.commands.forEach((command) => { 289 | switch (command.type) { 290 | case "M": 291 | commandString += `${command.type} ` 292 | commandString += `${command.x + offsetX} ${upem - command.y} ` 293 | break 294 | case "L": 295 | commandString += `${command.type} ` 296 | commandString += `${command.x + offsetX} ${upem - command.y} ` 297 | break 298 | case "C": 299 | commandString += `${command.type} ` 300 | commandString += `${command.x1 + offsetX} ${upem - command.y1}, ` 301 | commandString += `${command.x2 + offsetX} ${upem - command.y2}, ` 302 | commandString += `${command.x + offsetX} ${upem - command.y} ` 303 | break 304 | case "Q": 305 | commandString += `${command.type} ` 306 | commandString += `${command.x1 + offsetX} ${upem - command.y1}, ` 307 | commandString += `${command.x + offsetX} ${upem - command.y} ` 308 | break 309 | case "Z": 310 | commandString += `${command.type} ` 311 | break 312 | } 313 | }) 314 | path2d.addPath(new Path2D(commandString)) 315 | } 316 | 317 | if (typeOfOutline == "points") { 318 | glyph.path.commands.forEach((command) => { 319 | let p = new Path2D() 320 | const x = command.x + offsetX 321 | const y = upem - command.y 322 | switch (command.type) { 323 | case "M": 324 | p.rect(x - ps * 0.5, y - ps * 0.5, ps, ps) 325 | break 326 | case "L": 327 | p.rect(x - ps * 0.5, y - ps * 0.5, ps, ps) 328 | break 329 | case "C": 330 | p.rect(x - ps * 0.5, y - ps * 0.5, ps, ps) 331 | break 332 | case "Q": 333 | p.rect(x - ps * 0.5, y - ps * 0.5, ps, ps) 334 | break 335 | } 336 | path2d.addPath(p) 337 | }) 338 | } 339 | 340 | if (typeOfOutline == "handles") { 341 | let p = new Path2D() 342 | glyph.path.commands.forEach((command) => { 343 | switch (command.type) { 344 | case "M": 345 | p.moveTo(command.x + offsetX, upem - command.y) 346 | break 347 | case "L": 348 | p.moveTo(command.x + offsetX, upem - command.y) 349 | break 350 | case "C": 351 | p.lineTo(command.x1 + offsetX, upem - command.y1) 352 | p.moveTo(command.x + offsetX, upem - command.y) 353 | p.lineTo(command.x2 + offsetX, upem - command.y2) 354 | p.moveTo(command.x + offsetX, upem - command.y) 355 | break 356 | case "Q": 357 | p.lineTo(command.x1 + offsetX, upem - command.y1) 358 | p.moveTo(command.x1 + offsetX, upem - command.y1) 359 | p.lineTo(command.x + offsetX, upem - command.y) 360 | break 361 | case "Z": 362 | p.moveTo(command.x + offsetX, upem - command.y) 363 | break 364 | } 365 | }) 366 | path2d.addPath(p) 367 | } 368 | 369 | if (typeOfOutline == "handle points") { 370 | glyph.path.commands.forEach((command) => { 371 | let p = new Path2D() 372 | const x1 = command.x1 + offsetX 373 | const x2 = command.x2 + offsetX 374 | const y1 = upem - command.y1 375 | const y2 = upem - command.y2 376 | switch (command.type) { 377 | case "C": 378 | p.rect(x1 - ps * 0.5, y1 - ps * 0.5, ps, ps) 379 | p.rect(x2 - ps * 0.5, y2 - ps * 0.5, ps, ps) 380 | break 381 | case "Q": 382 | p.rect(x1 - ps * 0.5, y1 - ps * 0.5, ps, ps) 383 | break 384 | } 385 | path2d.addPath(p) 386 | }) 387 | } 388 | 389 | return path2d 390 | } 391 | -------------------------------------------------------------------------------- /src/js/distinct_section.js: -------------------------------------------------------------------------------- 1 | let waterfall, gtc 2 | websiteData.sections.forEach((section) => { 3 | if (section.name == "distinct") { 4 | waterfall = section.content.waterfall 5 | gtc = section.content.gtc.Easy 6 | } 7 | }) 8 | 9 | function updateWaterfall() { 10 | // console.log("updateWaterfall") 11 | const waterfallContainer = document.querySelector("#waterfall") 12 | waterfallContainer.innerHTML = "" 13 | waterfall.sizes.forEach((size) => { 14 | const div = document.createElement("div") 15 | div.id = `size_${size}` 16 | 17 | const desc = document.createElement("p") 18 | desc.classList.add("waterfall_desc") 19 | desc.textContent = `${size}rem\n${Math.round(size * rem * 100) / 100}px` 20 | 21 | const textsContainer = document.createElement("div") 22 | textsContainer.classList.add("waterfall_texts_container") 23 | waterfall.texts.forEach((text) => { 24 | const div2 = document.createElement("div") 25 | const p = document.createElement("p") 26 | p.classList.add("waterfall_text") 27 | p.style.fontSize = `${Math.round(size * rem * 100) / 100}px` 28 | p.textContent = text 29 | div2.append(p) 30 | textsContainer.append(div2) 31 | }) 32 | div.append(desc, textsContainer) 33 | 34 | waterfallContainer.append(div) 35 | }) 36 | } 37 | 38 | const gtcForm = document.querySelector("#gtc_form") 39 | const gtcFieldset = document.querySelector("#gtc_form fieldset") 40 | 41 | function buildDistinction() { 42 | // console.log("buildDistinction") 43 | gtcFieldset.innerHTML = "" 44 | websiteData.sections.forEach((section) => { 45 | if (section.name == "distinct") { 46 | section.content.gtcDifficulties.forEach((difficulty, index) => { 47 | const div = document.createElement("div") 48 | const input = document.createElement("input") 49 | input.type = "radio" 50 | input.name = "difficulty" 51 | input.id = `difficulty_${difficulty.name}` 52 | input.classList.add("gtc_difficulty") 53 | input.value = difficulty.name 54 | input.dataset.forform = "gtc_form" 55 | // input.tabIndex = 0 56 | if (index == 0) { 57 | input.setAttribute("checked", "true") 58 | } 59 | const label = document.createElement("label") 60 | label.textContent = difficulty.name 61 | label.setAttribute("for", `difficulty_${difficulty.name}`) 62 | div.append(input, label) 63 | gtcFieldset.append(div) 64 | }) 65 | } 66 | }) 67 | } 68 | 69 | function updateGTC(event, form) { 70 | // console.log("updateGTC") 71 | const data = new FormData(form) 72 | let output = "" 73 | for (const entry of data) { 74 | output = `${entry[1]}` 75 | } 76 | websiteData.sections.forEach((section) => { 77 | if (section.name == "distinct") { 78 | section.content.gtcDifficulties.forEach((difficulty) => { 79 | if (difficulty.name == output) { 80 | gtc = section.content.gtc[output] 81 | setCssVar(["--question-character-size", `${difficulty.size}rem`]) 82 | buildGTC() 83 | } 84 | }) 85 | } 86 | }) 87 | 88 | if (event) event.preventDefault() 89 | } 90 | 91 | let answers = [] 92 | let score = -1 93 | let currentQuestion = -1 94 | let firstButtons = [] 95 | function buildGTC() { 96 | // console.log("buildGTC") 97 | const gtcContainer = document.querySelector("#gtc_questions_container") 98 | gtcContainer.innerHTML = "" 99 | answers = [] 100 | score = -1 101 | currentQuestion = -1 102 | firstButtons = [] 103 | gtc.forEach((question, index) => { 104 | const div = document.createElement("div") 105 | div.classList.add("question_container") 106 | div.dataset.index = index 107 | 108 | const answer = Math.round(Math.random()) 109 | const wrongAnswer = (answer + 1) % 2 110 | answers.push(answer) 111 | 112 | const p = document.createElement("p") 113 | p.classList.add("question_character") 114 | p.textContent = question.value[answer] 115 | const pWrong = document.createElement("p") 116 | pWrong.classList.add("question_character", "wrong_character", "hide_character") 117 | pWrong.textContent = question.value[wrongAnswer] 118 | const buttonContainer = document.createElement("div") 119 | buttonContainer.classList.add("button_container") 120 | const option0 = document.createElement("button") 121 | option0.classList.add("question_button") 122 | option0.textContent = question.options[0] 123 | option0.dataset.questionIndex = index 124 | option0.tabIndex = -1 125 | firstButtons.push(option0) 126 | const option1 = document.createElement("button") 127 | option1.classList.add("question_button") 128 | option1.textContent = question.options[1] 129 | option1.dataset.questionIndex = index 130 | option1.tabIndex = -1 131 | 132 | const options = [option0, option1] 133 | options[answer].addEventListener("click", (e) => nextQuestion(true, answer, wrongAnswer, e.pointerType)) 134 | options[wrongAnswer].addEventListener("click", (e) => nextQuestion(false, answer, wrongAnswer, e.pointerType)) 135 | 136 | const answerFeedback = document.createElement("p") 137 | answerFeedback.classList.add("answer_feedback") 138 | 139 | buttonContainer.append(option0, option1) 140 | const br = document.createElement("br") 141 | div.append(answerFeedback, p, buttonContainer, pWrong) 142 | gtcContainer.append(div) 143 | }) 144 | nextQuestion(true, 0, 1) 145 | } 146 | 147 | function nextQuestion(correct, answer, wrongAnswer, pointerType) { 148 | // console.log(pointerType) 149 | const scoreTally = document.querySelector("#score_tally") 150 | const allQuestions = document.querySelectorAll(".question_container") 151 | let answerFeedback 152 | 153 | if (correct) score++ 154 | 155 | allQuestions.forEach((question, index) => { 156 | const wrongCharacter = question.querySelector(".wrong_character") 157 | 158 | if (index == currentQuestion) { 159 | question.classList.add("active_question") 160 | const rightButton = question.querySelector(`.button_container .question_button:nth-child(${answer + 1})`) 161 | const wrongButton = question.querySelector( 162 | `.button_container .question_button:nth-child(${wrongAnswer + 1})`, 163 | ) 164 | correct ? rightButton.classList.add("button_choice") : wrongButton.classList.add("button_choice") 165 | !correct ? rightButton.classList.add("button_choicent") : wrongButton.classList.add("button_choicent") 166 | rightButton.classList.add("right_button") 167 | rightButton.tabIndex = -1 168 | wrongButton.classList.add("wrong_button") 169 | wrongButton.tabIndex = -1 170 | 171 | answerFeedback = question.querySelector(".answer_feedback") 172 | answerFeedback.textContent = correct ? "✓" : "✕" 173 | 174 | wrongCharacter.classList.remove("hide_character") 175 | wrongCharacter.classList.add("show_character") 176 | } else if (index == currentQuestion + 1) { 177 | question.classList.add("active_question") 178 | } else { 179 | question.classList.remove("active_question") 180 | } 181 | }) 182 | 183 | currentQuestion++ 184 | 185 | allQuestions.forEach((question, index) => { 186 | if (index == currentQuestion) { 187 | question.querySelectorAll(".question_button").forEach((button) => (button.tabIndex = 0)) 188 | } 189 | }) 190 | scoreTally.textContent = `Score: ${score}/${gtc.length}` 191 | 192 | if (currentQuestion < gtc.length) { 193 | if (!isMobile && pointerType === "") setTimeout(() => firstButtons[currentQuestion]?.focus(), 10) 194 | } else { 195 | scoreTally.tabIndex = 0 196 | setTimeout(() => scoreTally.focus(), 10) 197 | } 198 | } 199 | 200 | function onPlayAgain(button) { 201 | button.classList.remove("shake") 202 | const gtc = document.querySelector("#gtc") 203 | gtc.style.opacity = 0 204 | buildGTC() 205 | setTimeout(() => { 206 | document.querySelector("#gtc_form input:checked").focus() 207 | gtc.style.opacity = 1 208 | }, 100) 209 | } 210 | -------------------------------------------------------------------------------- /src/js/docs_section.js: -------------------------------------------------------------------------------- 1 | const docsForm = document.querySelector("#docs_form") 2 | const faqContainerDocs = document.querySelector("#faq_container_docs") 3 | const featuresContainerDocs = document.querySelector("#features_container_docs") 4 | const alternatesContainerDocs = document.querySelector("#alternates_container_docs") 5 | const charsetContainerDocs = document.querySelector("#charset_container_docs") 6 | const languageContainerDocs = document.querySelector("#language_container_docs") 7 | 8 | let customizeContent 9 | let docsContent 10 | websiteData.sections.forEach((section) => { 11 | if (section.name == "customize") customizeContent = section.content 12 | if (section.name == "docs") docsContent = section.content 13 | }) 14 | 15 | function buildDocs() { 16 | // console.log("buildDocs") 17 | customizeContent.features.forEach((feature) => { 18 | const sizes = [ 19 | [3, 4], 20 | [1.5, 2], 21 | [0.5, 1], 22 | ] 23 | const container = document.createElement("div") 24 | const h2 = document.createElement("h2") 25 | const featureDescriptionWithSpan = feature.description 26 | .split("|") 27 | .map((l) => 28 | l == "OFF" || l == "DEF" 29 | ? `[${l}]` 32 | : l == "ON" || l == "ALT" 33 | ? `[${l}]` 36 | : l, 37 | ) 38 | .join("") 39 | h2.innerHTML = featureDescriptionWithSpan 40 | h2.tabIndex = 0 41 | h2.dataset.edit = "true" 42 | const p = document.createElement("p") 43 | p.textContent = `Default: ${feature.on ? "ON" : "OFF"}. Feature in variable font: "${feature.feature}".` 44 | container.append(h2, p) 45 | sizes.forEach((size) => { 46 | const exampleText = document.createElement("p") 47 | exampleText.textContent = feature.docsExample 48 | exampleText.classList.add("docs_example", `docs_${feature.type}`) 49 | exampleText.dataset.feature = feature.feature 50 | exampleText.style.fontSize = `${size[0]}rem` 51 | exampleText.style.lineHeight = `${size[1]}rem` 52 | container.append(exampleText) 53 | }) 54 | const br1 = document.createElement("br") 55 | const br2 = document.createElement("br") 56 | container.append(br1, br2) 57 | if (feature.type == "feature") { 58 | featuresContainerDocs.append(container) 59 | } 60 | if (feature.type == "alternate") { 61 | alternatesContainerDocs.append(container) 62 | } 63 | }) 64 | const charset = document.querySelector("#charset") 65 | const tunedCharset = docsContent.charset.split("").join(" ") 66 | docsContent.charset.split("").forEach((char) => { 67 | const span = document.createElement("p") 68 | span.classList.add("charset_letter") 69 | span.textContent = char 70 | charset.append(span) 71 | }) 72 | // charset.textContent = tunedCharset 73 | 74 | const languageSupport = document.querySelector("#language_support") 75 | docsContent.supportedLanguages.forEach((language) => { 76 | const p = document.createElement("p") 77 | p.classList.add("language_support") 78 | p.textContent = language 79 | languageSupport.append(p) 80 | }) 81 | 82 | updateDocs(null, docsForm) 83 | } 84 | 85 | function changeFeatureDocs(enable) { 86 | // console.log("changeFeatureDocs") 87 | if (enable == "enable") { 88 | websiteData.enableFeaturesInDocs = true 89 | } else if (enable == "disable") { 90 | websiteData.enableFeaturesInDocs = false 91 | } else if (enable == "switch") { 92 | websiteData.enableFeaturesInDocs = !websiteData.enableFeaturesInDocs 93 | } 94 | const enabled = websiteData.enableFeaturesInDocs 95 | const allExampleTexts = document.querySelectorAll(".docs_example") 96 | allExampleTexts.forEach((text) => { 97 | text.style.fontFeatureSettings = `"${text.dataset.feature}" ${enabled ? 1 : 0}` 98 | }) 99 | const allSpanOff = document.querySelectorAll(".span_off") 100 | const allSpanOn = document.querySelectorAll(".span_on") 101 | if (enabled) { 102 | allSpanOff.forEach((span) => span.classList.remove("active_feature")) 103 | allSpanOn.forEach((span) => span.classList.add("active_feature")) 104 | } else { 105 | allSpanOff.forEach((span) => span.classList.add("active_feature")) 106 | allSpanOn.forEach((span) => span.classList.remove("active_feature")) 107 | } 108 | } 109 | 110 | function updateDocs(event, form) { 111 | // console.log("updateDocs") 112 | const data = new FormData(form) 113 | let output = "" 114 | for (const entry of data) { 115 | output = entry[1] 116 | } 117 | const docsContainers = document.querySelectorAll(".docs_container") 118 | docsContainers.forEach((topic) => { 119 | // console.log(topic.id) 120 | topic.style.display = "none" 121 | if (`${output}_container_docs` == topic.id) { 122 | topic.style.display = "block" 123 | } 124 | }) 125 | if (event) event.preventDefault() 126 | } 127 | -------------------------------------------------------------------------------- /src/js/dynamic_favicon.js: -------------------------------------------------------------------------------- 1 | document.onvisibilitychange = () => { 2 | // dynamicFavicon() 3 | if (document.visibilityState === "visible") changeFavicon(true) 4 | else changeFavicon(false) 5 | } 6 | 7 | let faviconIntervalID 8 | let faviconCounter = 0 9 | 10 | // function dynamicFavicon() { 11 | // if (document.visibilityState === "visible") { 12 | // faviconIntervalID = setInterval(changeFav, 500) 13 | // } else { 14 | // clearInterval(faviconIntervalID) 15 | // faviconIntervalID = null 16 | // if (faviconCounter % 2 == 1) changeFav() 17 | // } 18 | 19 | // function changeFav() { 20 | // const link = document.createElement("link"), 21 | // oldLink = document.getElementById("dynamic-favicon") 22 | 23 | // link.id = "dynamic-favicon" 24 | // link.rel = "icon" 25 | // link.href = faviconCounter % 2 == 0 ? "src/favicon/icon-off.svg" : "src/favicon/icon.svg" 26 | // if (oldLink) { 27 | // document.head.removeChild(oldLink) 28 | // } 29 | // document.head.appendChild(link) 30 | // faviconCounter++ 31 | // } 32 | // } 33 | 34 | function changeFavicon(hasFocus) { 35 | // console.log("changeFavicon") 36 | const link = document.createElement("link"), 37 | oldLink = document.getElementById("dynamic-favicon") 38 | 39 | link.id = "dynamic-favicon" 40 | link.rel = "icon" 41 | link.href = hasFocus ? "src/favicon/icon-512.svg" : "src/favicon/icon-512.svg" 42 | if (oldLink) { 43 | document.head.removeChild(oldLink) 44 | } 45 | document.head.appendChild(link) 46 | } 47 | -------------------------------------------------------------------------------- /src/js/example_section.js: -------------------------------------------------------------------------------- 1 | const exampleForm = document.querySelector("#examples_form") 2 | const exampleSettingsForm = document.querySelector("#examplesettings_form") 3 | const weightForm = document.querySelector("#weight_form") 4 | const letterSpacingForm = document.querySelector("#letter_spacing_form") 5 | const lineHeightForm = document.querySelector("#line_height_form") 6 | const fontNameForm = document.querySelector("#font_name_form") 7 | const exampleFieldset = document.querySelector("#examples_form fieldset") 8 | const fontsFieldset = document.querySelector("#fonts_form fieldset") 9 | const weightFieldset = document.querySelector("#weight_form fieldset") 10 | const letterSpacingFieldset = document.querySelector("#letter_spacing_form fieldset") 11 | const lineHeightFieldset = document.querySelector("#line_height_form fieldset") 12 | const alternatesContainer = document.querySelector("#alternates_container") 13 | const featuresContainer = document.querySelector("#features_container") 14 | 15 | function buildExample() { 16 | // console.log("buildExample") 17 | websiteData.sections.forEach((section) => { 18 | if (section.name == "customize") { 19 | fontsFieldset.innerHTML = "" 20 | section.content.fonts.forEach((font, index) => { 21 | const div = document.createElement("div") 22 | const input = document.createElement("input") 23 | input.type = "radio" 24 | input.name = "font" 25 | input.id = font.id 26 | input.classList.add("example_font") 27 | input.value = font.cssName 28 | input.dataset.forform = "fonts_form" 29 | // input.tabIndex = 0 30 | if (index == 0) { 31 | input.setAttribute("checked", "true") 32 | } 33 | const label = document.createElement("label") 34 | label.textContent = font.name 35 | label.setAttribute("for", font.id) 36 | div.append(input, label) 37 | fontsFieldset.append(div) 38 | }) 39 | 40 | exampleFieldset.innerHTML = "" 41 | section.content.languages.forEach((language, index) => { 42 | const div = document.createElement("div") 43 | const input = document.createElement("input") 44 | input.type = "radio" 45 | input.name = "language" 46 | input.id = language.languageName 47 | input.classList.add("example_language") 48 | input.value = language.languageName 49 | input.dataset.forform = "examples_form" 50 | // input.tabIndex = 0 51 | if (index == 0) { 52 | input.setAttribute("checked", "true") 53 | } 54 | const label = document.createElement("label") 55 | label.textContent = language.languageName 56 | label.setAttribute("for", language.languageName) 57 | div.append(input, label) 58 | exampleFieldset.append(div) 59 | }) 60 | 61 | weightFieldset.innerHTML = "" 62 | section.content.weights.forEach((weight, index) => { 63 | const div = document.createElement("div") 64 | const input = document.createElement("input") 65 | input.type = "radio" 66 | input.name = "weight" 67 | input.id = `weight_${weight}` 68 | input.classList.add("example_weight") 69 | input.value = weight 70 | input.dataset.forform = "weight_form" 71 | if (weight == 400) { 72 | input.setAttribute("checked", "true") 73 | } 74 | const label = document.createElement("label") 75 | label.textContent = weight 76 | label.setAttribute("for", `weight_${weight}`) 77 | div.append(input, label) 78 | weightFieldset.append(div) 79 | }) 80 | 81 | letterSpacingFieldset.innerHTML = "" 82 | const ls = section.content.letterSpacings 83 | for (let value = ls.min; value <= ls.max; value += ls.step) { 84 | const div = document.createElement("div") 85 | const input = document.createElement("input") 86 | input.type = "radio" 87 | input.name = "letterSpacing" 88 | input.id = `letter_spacing_${value}` 89 | input.classList.add("example_letter_spacing") 90 | input.value = value 91 | input.dataset.forform = "letter_spacing_form" 92 | if (value == ls.value) input.setAttribute("checked", "true") 93 | const label = document.createElement("label") 94 | label.textContent = `${value}%` 95 | label.setAttribute("for", `letter_spacing_${value}`) 96 | div.append(input, label) 97 | letterSpacingFieldset.append(div) 98 | } 99 | 100 | lineHeightFieldset.innerHTML = "" 101 | const lh = section.content.lineHeights 102 | for (let val = lh.min; val <= lh.max + 0.01; val += lh.step) { 103 | const value = Math.round(val * 1000) / 1000 104 | const div = document.createElement("div") 105 | const input = document.createElement("input") 106 | input.type = "radio" 107 | input.name = "lineHeight" 108 | input.id = `line_height_${value}` 109 | input.classList.add("example_line_height") 110 | input.value = value 111 | input.dataset.forform = "line_height_form" 112 | if (value == lh.value) input.setAttribute("checked", "true") 113 | const label = document.createElement("label") 114 | label.textContent = value 115 | label.setAttribute("for", `line_height_${value}`) 116 | div.append(input, label) 117 | lineHeightFieldset.append(div) 118 | } 119 | 120 | featuresContainer.innerHTML = "" 121 | alternatesContainer.innerHTML = "" 122 | section.content.features.forEach((feature, index) => { 123 | const fieldset = document.createElement("fieldset") 124 | const duo = [0, 0] 125 | const p = document.createElement("p") 126 | p.textContent = `${feature.feature}: ${feature.label}` 127 | p.id = `alt_${feature.name}` 128 | fieldset.append(p) 129 | duo.forEach((_, index) => { 130 | const div = document.createElement("div") 131 | const input = document.createElement("input") 132 | input.type = "radio" 133 | input.name = feature.name 134 | input.id = `${feature.feature}_${!!index}` 135 | input.value = `'${feature.feature}' ${index == 0 ? "off" : "on"}` 136 | input.dataset.forform = "examplesettings_form" 137 | if (!feature.on && index == 0) input.setAttribute("checked", "true") 138 | if (feature.on && index == 1) input.setAttribute("checked", "true") 139 | const label = document.createElement("label") 140 | if (feature.type == "feature") label.textContent = index == 0 ? "OFF" : "ON" 141 | if (feature.type == "alternate") label.textContent = index == 0 ? "DEF" : "ALT" 142 | label.setAttribute("for", `${feature.feature}_${!!index}`) 143 | div.append(input, label) 144 | fieldset.append(div) 145 | }) 146 | if (feature.type == "feature") featuresContainer.append(fieldset) 147 | else alternatesContainer.append(fieldset) 148 | }) 149 | } 150 | }) 151 | 152 | updateExamples(null, exampleForm) 153 | updateExampleSettings(null, exampleSettingsForm, true) 154 | } 155 | 156 | const codeExample = document.querySelector("#code_example") 157 | function updateExamples(event, form) { 158 | // console.log("updateExamples") 159 | const data = new FormData(form) 160 | let output = "" 161 | for (const entry of data) { 162 | output = `${entry[1]}` 163 | } 164 | 165 | websiteData.sections.forEach((section) => { 166 | if (section.name == "customize") { 167 | section.content.languages.forEach((language, index) => { 168 | if (language.languageName == output) { 169 | codeExample.textContent = language.codeExample 170 | let nums = Array.from(new Array(1000), (x, i) => i + 1).join("\n") 171 | codeExample.setAttribute("data-before", nums) 172 | } 173 | }) 174 | } 175 | }) 176 | 177 | if (event) event.preventDefault() 178 | } 179 | 180 | function updateFont(event, form) { 181 | // console.log("updateFont") 182 | const data = new FormData(form) 183 | let output = "" 184 | for (const entry of data) { 185 | output = `${entry[1]}` 186 | } 187 | 188 | if (output !== "CommitMono") codeExample.style.fontFeatureSettings = "normal" 189 | else codeExample.style.fontFeatureSettings = [...new FormData(exampleSettingsForm).values()].join(", ") 190 | 191 | let fontInDocument = false 192 | document.fonts.forEach((font) => (font.family == output ? (fontInDocument = true) : null)) 193 | 194 | if (!fontInDocument) { 195 | const input = document.querySelector(`input[value="${output}"]`) 196 | input.classList.add("loading_font") 197 | const outputFont = new FontFace(output, `url(/src/fonts/other/${output}.woff2)`, { 198 | style: "normal", 199 | weight: "400", 200 | }) 201 | document.fonts.add(outputFont) 202 | outputFont.load() 203 | document.fonts.ready.then(() => { 204 | codeExample.style.fontFamily = output 205 | input.classList.remove("loading_font") 206 | }) 207 | } else { 208 | codeExample.style.fontFamily = output 209 | } 210 | 211 | if (event) event.preventDefault() 212 | } 213 | 214 | function updateWeight(event, form) { 215 | // console.log("updateWeight") 216 | const data = new FormData(form) 217 | let output = "" 218 | for (const entry of data) { 219 | output = +entry[1] 220 | } 221 | 222 | downloadSettingsCustom.weight = output 223 | websiteData.weight = output 224 | document.querySelector("body").style.fontVariationSettings = `"wght" ${websiteData.weight}, "ital" ${ 225 | websiteData.italic ? "1" : "0" 226 | }` 227 | 228 | console.log(downloadSettingsCustom) 229 | 230 | if (event) event.preventDefault() 231 | } 232 | 233 | function updateLetterSpacing(event, form) { 234 | // console.log("updateWeight") 235 | const data = new FormData(form) 236 | let output = "" 237 | for (const entry of data) { 238 | output = +entry[1] 239 | } 240 | downloadSettingsCustom.letterSpacing = output 241 | websiteData.letterSpacing = output 242 | codeExample.style.letterSpacing = `${output / 100}em` 243 | 244 | if (event) event.preventDefault() 245 | } 246 | 247 | function updateLineHeight(event, form) { 248 | // console.log("updateWeight") 249 | const data = new FormData(form) 250 | let output = "" 251 | for (const entry of data) { 252 | output = +entry[1] 253 | } 254 | downloadSettingsCustom.lineHeight = output 255 | websiteData.lineHeight = output 256 | codeExample.style.lineHeight = output 257 | 258 | if (event) event.preventDefault() 259 | } 260 | 261 | function updateFontName(event, form) { 262 | const data = new FormData(form) 263 | let output = "" 264 | for (const entry of data) { 265 | output = entry[1] 266 | } 267 | const customName = document.querySelector("#custom_name") 268 | const suffix = output ? output : "" 269 | const regex = /^[\w-_]*$/ 270 | const label = document.querySelector("#font_name + p") 271 | if (output.match(regex)) { 272 | downloadSettingsCustom.fontName = output 273 | label.textContent = "✓ Valid name." 274 | customName.textContent = `CommitMono${suffix}` 275 | websiteData.fontName = `CommitMono${suffix}` 276 | } else { 277 | downloadSettingsCustom.fontName = "" 278 | label.textContent = "✕ Invalid name, use: A-z 0-9 _ -" 279 | customName.textContent = `CommitMonoYourName` 280 | websiteData.fontName = `CommitMono` 281 | } 282 | 283 | if (event) event.preventDefault() 284 | } 285 | 286 | function updateExampleSettings(event, form, isDefault) { 287 | // console.log("updateExampleSettings") 288 | const data = new FormData(form) 289 | let output = "" 290 | function updateDownloadSettings(type, feature) { 291 | const key = feature.split("' ")[0].slice(1) 292 | const value = feature.split("' ")[1] == "on" 293 | downloadSettingsCustom[type][key] = value 294 | if (isDefault) downloadSettingsDefault[type][key] = value 295 | } 296 | for (const entry of data) { 297 | output += `${entry[1]}, ` 298 | if (entry[1].includes("cv")) updateDownloadSettings("alternates", entry[1]) 299 | if (entry[1].includes("ss")) updateDownloadSettings("features", entry[1]) 300 | 301 | const label = document.querySelector(`#alt_${entry[0]}`) 302 | if (label) label.style.fontFeatureSettings = entry[1] 303 | } 304 | output = output.slice(0, -2) 305 | 306 | const currentFont = [...new FormData(document.forms["fonts_form"]).values()][0] 307 | if (currentFont === "CommitMono") codeExample.style.fontFeatureSettings = output 308 | else codeExample.style.fontFeatureSettings = "normal" 309 | 310 | const customFeatureCode = document.querySelector("#custom_feature_code") 311 | const shortFeatureCode = output 312 | .split(", ") 313 | .filter((f) => f.includes("on")) 314 | .join(", ") 315 | customFeatureCode.textContent = `"${shortFeatureCode}"` 316 | 317 | if (event) event.preventDefault() 318 | } 319 | 320 | function areObjectsIdentical(obj1, obj2) { 321 | return JSON.stringify(obj1) === JSON.stringify(obj2) 322 | } 323 | 324 | async function uploadCustomSettings(event, fileInput) { 325 | event.stopPropagation() 326 | event.preventDefault() 327 | 328 | const file = fileInput.files[0] 329 | const fileType = file?.name.split(".").pop() 330 | 331 | if (fileType == "json") { 332 | const fileText = await file.text() 333 | const uploadedSettings = JSON.parse(fileText) 334 | updateCustomSettings(uploadedSettings) 335 | } 336 | } 337 | 338 | function updateCustomSettings(settings) { 339 | if (settings.weight) { 340 | document.forms["weight_form"][`weight_${settings.weight}`].checked = true 341 | updateWeight(null, weightForm) 342 | } 343 | if (settings.letterSpacing) { 344 | document.forms["letter_spacing_form"][`letter_spacing_${settings.letterSpacing}`].checked = true 345 | updateLetterSpacing(null, letterSpacingForm) 346 | } 347 | if (settings.lineHeight) { 348 | document.forms["line_height_form"][`line_height_${settings.lineHeight}`].checked = true 349 | updateLineHeight(null, lineHeightForm) 350 | } 351 | if (settings.alternates) { 352 | Object.entries(settings.alternates).forEach(([feature, enabled]) => { 353 | document.forms["examplesettings_form"][`${feature}_${enabled}`].checked = true 354 | }) 355 | updateExampleSettings(null, exampleSettingsForm, false) 356 | } 357 | } 358 | 359 | const customSettingsInput = document.querySelector("#custom-settings-input") 360 | customSettingsInput.addEventListener("click", () => { 361 | enterTextField() 362 | customSettingsInput.value = "" 363 | }) 364 | customSettingsInput.addEventListener("blur", exitTextField) 365 | customSettingsInput.addEventListener("input", (e) => { 366 | enterTextField() 367 | try { 368 | const pastedText = JSON.parse(e.target.value) 369 | updateCustomSettings(pastedText) 370 | customSettingsInput.value = "[Imported ✓]" 371 | setTimeout(() => (customSettingsInput.value = ""), 1500) 372 | } catch (error) { 373 | if (customSettingsInput.value.includes("[Error ✕")) customSettingsInput.value = "" 374 | else if (!customSettingsInput.value.includes("[Imported ✓]")) { 375 | customSettingsInput.value = "[Error ✕]" 376 | setTimeout(() => (customSettingsInput.value = ""), 1500) 377 | } 378 | } 379 | }) 380 | 381 | const copyCustomSettings = document.querySelector("#copy-custom-settings") 382 | copyCustomSettings.addEventListener("click", () => { 383 | if (navigator.clipboard) navigator.clipboard.writeText(JSON.stringify(downloadSettingsCustom)) 384 | const text = copyCustomSettings.textContent 385 | copyCustomSettings.textContent = "[Copied ✓]" 386 | setTimeout(() => (copyCustomSettings.textContent = text), 1500) 387 | }) 388 | -------------------------------------------------------------------------------- /src/js/familiar_section.js: -------------------------------------------------------------------------------- 1 | const familiarContainer = document.querySelector("#familiar_container") 2 | 3 | function buildFamiliar() { 4 | // console.log("buildFamiliar") 5 | websiteData.sections.forEach((section) => { 6 | if (section.name == "familiar") { 7 | familiarContainer.innerHTML = "" 8 | section.content.timeline.forEach((example, index) => { 9 | const div = document.createElement("div") 10 | div.style.display = example.name == "commit_mono_example" ? "block" : "none" 11 | div.id = example.name 12 | div.dataset.name = example.name 13 | const svgContainer = document.createElement("div") 14 | svgContainer.innerHTML = section.content.svgs[example.name] 15 | svgContainer.tabIndex = 0 16 | svgContainer.classList.add("svg_container") 17 | const img = document.createElement("img") 18 | img.src = `/src/img/familiar/${example.src}` 19 | const p = document.createElement("p") 20 | p.tabIndex = 0 21 | p.dataset.edit = "true" 22 | example.description.forEach((description) => (p.textContent += description + " ")) 23 | div.append(p) 24 | const br = document.createElement("br") 25 | div.append(br, svgContainer) 26 | familiarContainer.append(div) 27 | }) 28 | } 29 | }) 30 | } 31 | 32 | function updateFamiliar(event, form) { 33 | // console.log("updateFamiliar") 34 | buildFamiliar() 35 | const data = new FormData(form) 36 | let output = "" 37 | for (const entry of data) { 38 | output = entry[1] 39 | } 40 | websiteData.sections.forEach((section) => { 41 | if (section.name == "familiar") { 42 | section.content.timeline.forEach((example) => { 43 | const exampleContainer = familiarContainer.querySelector(`#${example.name}`) 44 | if (exampleContainer.dataset.name == output) { 45 | exampleContainer.style.display = "block" 46 | } else { 47 | exampleContainer.style.display = "none" 48 | } 49 | }) 50 | } 51 | }) 52 | event.preventDefault() 53 | } 54 | -------------------------------------------------------------------------------- /src/js/intelligent_section.js: -------------------------------------------------------------------------------- 1 | function updateIntelligent(event, form) { 2 | // console.log("updateIntelligent") 3 | const data = new FormData(form) 4 | let output = "" 5 | for (const entry of data) { 6 | output = `${entry[1]}` 7 | } 8 | const examples = ["original", "smart_kerning", "before", "after"] 9 | examples.forEach((example) => { 10 | const exampleContainer = document.querySelector(`#${example}`) 11 | if (exampleContainer.id == output) { 12 | exampleContainer.style.display = "block" 13 | } else { 14 | exampleContainer.style.display = "none" 15 | } 16 | }) 17 | event.preventDefault() 18 | } 19 | -------------------------------------------------------------------------------- /src/js/section.js: -------------------------------------------------------------------------------- 1 | function fillSectionData() { 2 | // console.log("fillSectionData") 3 | websiteData.sections.forEach((section, index) => { 4 | const topContainer = document.querySelector(`#section_${index + 1} .top_container`) 5 | if (topContainer) { 6 | const h1 = document.createElement("h1") 7 | h1.textContent = `${index + 1 < 10 ? `0${index + 1}` : index + 1} ${capitalize(section.name)}` 8 | h1.tabIndex = 0 9 | h1.dataset.edit = "true" 10 | const br = document.createElement("br") 11 | const p = document.createElement("p") 12 | p.innerHTML = section.description 13 | p.tabIndex = 0 14 | p.dataset.edit = "true" 15 | topContainer.append(h1, br, p) 16 | } 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /src/js/start_functions.js: -------------------------------------------------------------------------------- 1 | let waitingForLoadIntervalID = null 2 | let allCssLoaded = false 3 | function startAll() { 4 | // console.log("startAll") 5 | 6 | // websiteData.invert = isDarkMode 7 | 8 | appendStyleSheets() 9 | 10 | waitingForLoadIntervalID = setInterval(() => { 11 | if (allCssLoaded) { 12 | document.querySelector("#navigate_description").focus() 13 | document.querySelector("#loading").style.display = "none" 14 | clearInterval(waitingForLoadIntervalID) 15 | waitingForLoadIntervalID = null 16 | } 17 | }, 100) 18 | 19 | fillSectionData() 20 | 21 | buildNav() 22 | 23 | buildTable() 24 | 25 | buildFamiliar() 26 | 27 | buildCode() 28 | 29 | buildDistinction() 30 | 31 | buildGTC() 32 | 33 | buildExample() 34 | 35 | buildDocs() 36 | 37 | updateCodeFont() 38 | 39 | updateWaterfall() 40 | 41 | changeFavicon(true) 42 | 43 | sectionNavigation(0) 44 | 45 | setInterval(checkDocumentFocus, 100) 46 | } 47 | 48 | if (fontsLoaded) { 49 | // console.log("fontsLoaded startAll()") 50 | startAll() 51 | } 52 | -------------------------------------------------------------------------------- /src/js/table_section.js: -------------------------------------------------------------------------------- 1 | function buildTable() { 2 | // console.log("buildTable") 3 | const table = document.querySelector("#section_2 .content_container table") 4 | 5 | for (let i = 0; i <= 6; i++) { 6 | const tr = document.createElement("tr") 7 | const fieldset = document.createElement("fieldset") 8 | tr.append(fieldset) 9 | for (let j = 0; j <= 16; j++) { 10 | if (i == 0 || j == 0) { 11 | const th = document.createElement("th") 12 | const div = document.createElement("div") 13 | const p = document.createElement("p") 14 | if (i != 0 && j == 0) { 15 | p.textContent = createBinaryString(i + 1, 3) 16 | } else if (i == 0 && j != 0) { 17 | p.textContent = createBinaryString(j - 1, 4) 18 | } else { 19 | p.textContent = "" 20 | } 21 | div.append(p) 22 | th.append(div) 23 | fieldset.append(th) 24 | } else { 25 | const charCode = (i - 1) * 16 + j + 31 26 | 27 | const td = document.createElement("td") 28 | td.id = `td_${charCode}` 29 | const div = document.createElement("div") 30 | const input = document.createElement("input") 31 | input.type = "radio" 32 | input.id = `char_${charCode}` 33 | input.name = `row_${i}` 34 | input.value = charCode 35 | // input.tabIndex = 0 36 | input.dataset.forform = "table_form" 37 | // input.tabIndex = 0 38 | if (j == 2) input.setAttribute("checked", "true") 39 | const label = document.createElement("label") 40 | label.textContent = i == 6 && j == 16 ? "" : String.fromCharCode(charCode) 41 | label.setAttribute("for", `char_${charCode}`) 42 | // label.dataset.edit = "true" 43 | div.append(input, label) 44 | td.append(div) 45 | fieldset.append(td) 46 | } 47 | } 48 | table.append(tr) 49 | } 50 | } 51 | const createBinaryString = (number, length) => parseInt(number, 10).toString(2).padStart(length, "0") 52 | 53 | let previousOutput = [33, 49, 65, 81, 97, 113] 54 | function updateTable(event, form) { 55 | // console.log("updateTable") 56 | const data = new FormData(form) 57 | let output = [] 58 | for (const entry of data) output.push(+entry[1]) 59 | let indexOfChange = 0 60 | let offset = 0 61 | output.forEach((row, index) => (row != previousOutput[index] ? (indexOfChange = index) : null)) 62 | output.forEach((row, index) => (index == indexOfChange ? (offset = row - previousOutput[index]) : null)) 63 | output.forEach((row, index) => { 64 | if (index != indexOfChange) { 65 | document.forms["table_form"][`char_${row + offset}`].checked = true 66 | output[index] += offset 67 | } 68 | }) 69 | previousOutput = [...output] 70 | event.preventDefault() 71 | } 72 | -------------------------------------------------------------------------------- /src/js/utility_functions.js: -------------------------------------------------------------------------------- 1 | // takes a string and returns a string, where the first letter is uppercase 2 | function capitalize(string) { 3 | const stringArray = string.split("") 4 | return stringArray.shift().toUpperCase() + stringArray.join("") 5 | } 6 | 7 | const mapRange = (value, x1, y1, x2, y2) => ((value - x1) * (y2 - x2)) / (y1 - x1) + x2 8 | 9 | const getCssVar = (property) => getComputedStyle(document.documentElement).getPropertyValue(property) 10 | const setCssVar = ([property, value]) => document.documentElement.style.setProperty(property, value) 11 | 12 | const isMobileTest = () => { 13 | if (window.matchMedia("(pointer: coarse) and (max-width: 1000px").matches) { 14 | // console.log("(pointer: coarse) and (max-width: 1000px)") 15 | return true 16 | } else return false 17 | } 18 | 19 | const mobileMediaQuery = "(pointer: coarse) and (max-width: 1000px)" 20 | const mqlMobile = window.matchMedia(mobileMediaQuery) 21 | let isMobile = mqlMobile.matches 22 | mqlMobile.addEventListener("change", (e) => { 23 | isMobile = e.matches 24 | changedFocus(true) 25 | }) 26 | 27 | // const darkModeMediaQuery = "(prefers-color-scheme: dark)" 28 | // const mqlDarkMode = window.matchMedia(darkModeMediaQuery) 29 | // let isDarkMode = mqlDarkMode.matches 30 | // mqlDarkMode.addEventListener("change", changeMode) 31 | function changeMode(isDarkMode, isHighContrast) { 32 | // console.log("CHANGE THEME") 33 | websiteData.invert = isDarkMode 34 | websiteData.highContrast = isHighContrast 35 | if (isHighContrast) { 36 | if (websiteData.invert) { 37 | setCssVar(["--bg", "#000"]) 38 | setCssVar(["--text", "#fff"]) 39 | } else { 40 | setCssVar(["--bg", "#fff"]) 41 | setCssVar(["--text", "#000"]) 42 | } 43 | } else { 44 | if (websiteData.invert) { 45 | setCssVar(["--bg", "#111"]) 46 | setCssVar(["--text", "#aaa"]) 47 | } else { 48 | setCssVar(["--bg", "#aaa"]) 49 | setCssVar(["--text", "#111"]) 50 | } 51 | } 52 | updateCode(null, codeForm) 53 | } 54 | 55 | function wait(milliseconds) { 56 | return new Promise((resolve) => { 57 | setTimeout(resolve, milliseconds) 58 | }) 59 | } 60 | 61 | let checkCssLoadIntervalIDs = [] 62 | function appendStyleSheets() { 63 | // console.log("appendStyleSheets") 64 | const stylesheetIndexes = [ 65 | "style", 66 | "mobile", 67 | "non_essential", 68 | "section_1", 69 | "section_2", 70 | "section_3", 71 | "section_4", 72 | "section_5", 73 | "section_6", 74 | "section_7", 75 | "section_8", 76 | "section_9", 77 | "section_10", 78 | ] 79 | const head = document.querySelector("head") 80 | stylesheetIndexes.forEach((stylesheet, index) => { 81 | const link = document.createElement("link") 82 | link.setAttribute("rel", "stylesheet") 83 | link.setAttribute("href", `src/css/${stylesheet}.css`) 84 | head.append(link) 85 | checkCssLoadIntervalIDs[index] = setInterval(() => { 86 | const cssLoaded = Boolean(link.sheet) 87 | if (cssLoaded) { 88 | // console.log(`${stylesheet} CSS loaded`) 89 | clearInterval(checkCssLoadIntervalIDs[index]) 90 | checkCssLoadIntervalIDs[index] = null 91 | if (index == 3) { 92 | allCssLoaded = true 93 | // console.log("ALL CSS LOADED") 94 | } 95 | } 96 | }, 100) 97 | }) 98 | } 99 | 100 | function showHideChangeSettings(text, ms, dim) { 101 | const changeSetting = document.querySelector("#change_setting p") 102 | changeSetting.textContent = text 103 | changeSetting.style.visibility = "visible" 104 | if (dim) { 105 | document.querySelector("#nav_form").classList.add("faded") 106 | document.querySelector("#main_scale").classList.add("faded") 107 | } 108 | clearTimeout(changeSettingTimeoutID) 109 | changeSettingTimeoutID = setTimeout(() => { 110 | changeSetting.style.visibility = "hidden" 111 | if (dim) { 112 | document.querySelector("#nav_form").classList.remove("faded") 113 | document.querySelector("#main_scale").classList.remove("faded") 114 | } 115 | }, ms ?? 1000) 116 | } 117 | 118 | const consol = { 119 | log: function (message) { 120 | // console.log(message) 121 | }, 122 | } 123 | -------------------------------------------------------------------------------- /src/language_examples/brainfuck.bf: -------------------------------------------------------------------------------- 1 | ++++++++++>>++++++++++[<++++++++++>-]<[>>+>>+++>>>>+>+>+<<<<<<<<[>+>->+<[>]>[<+> 2 | -]<<[<]>-]>>>[>>>-<<<[-]][-]<[-]+++++<[<+>-]<[>+>->+<[>]>[<+>-]<<[<]>-]>>>[>>>>- 3 | <<<<[-]]>>>[>>>-[------->+<]>---.[-->+++<]>.-[--->+<]>++..[-]<<<<[-]<<[-]]>[>>++ 4 | ++[++++>---<]>-.++[----->+<]>+.+++++..[-]<<<[-]<[-]]>[<<<<<<<[>>>>>>>>+>>>>>>>>+ 5 | <<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>-]<<<<<<++++ 6 | ++++++<<[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>>[-]>>>++++++++++<[->-[>+>>]>[+[-<+>]> 7 | +>>]<<<<<]>[-]>>[>++++++[-<++++++++>]<.<<+>+>[-]]<[<[->-<]++++++[->++++++++<]>.[ 8 | -]]<<++++++[-<++++++++>]<.[-]<<[-<+>]<[-]<[-]]<<<<<[-]<[-]<[<+>-]<<<<.>-] -------------------------------------------------------------------------------- /src/language_examples/c++.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int main(int argc, char **argv) 8 | { 9 | if (argc == 1) 10 | { 11 | cout << "Usage: please input a non-negative integer\n"; 12 | return 1; 13 | } 14 | string tmp = argv[1]; 15 | if (argc == 1 || argv[1][0] == '\0' || (atoi(argv[1]) == 0 && strcmp(argv[1], "0") != 0) || atoi(argv[1]) < 0 || tmp.find(".") != string::npos) 16 | { 17 | cout << "Usage: please input a non-negative integer\n"; 18 | } 19 | else 20 | { 21 | int input = atoi(argv[1]); 22 | if (input == 0 || input == 1) 23 | { 24 | cout << "composite\n"; 25 | return 0; 26 | } 27 | for (int i = 2; i < input; ++i) 28 | { 29 | if (input % i == 0) 30 | { 31 | cout << "composite\n"; 32 | return 0; 33 | } 34 | } 35 | cout << "Prime\n"; 36 | } 37 | 38 | return 0; 39 | } -------------------------------------------------------------------------------- /src/language_examples/fortran.f: -------------------------------------------------------------------------------- 1 | ! upcase and to_upper didn't work, 2 | ! had to resort to check ASCII value of first letter & then 3 | ! subtract 32 from it, ... 4 | program capitalize 5 | character(len=100) :: cmd 6 | character(len=1) :: firstletter 7 | character(len=:), allocatable :: printoutput 8 | 9 | ! Anything not equal to single argument, Print Error 10 | IF(COMMAND_ARGUMENT_COUNT().NE.1)THEN 11 | write(*,'(g0.8)')"Usage: please provide a string" 12 | STOP 13 | ENDIF 14 | 15 | CALL GET_COMMAND_ARGUMENT(1,cmd) 16 | if (cmd == "") then 17 | write(*,'(g0.8)')"Usage: please provide a string" 18 | STOP 19 | endif 20 | ! Get first letter 21 | firstletter = cmd(1:1) 22 | ! Check if first letter is between ASCII Value of a and z 23 | if (iachar(firstletter)>= iachar("a") .and. iachar(firstletter)<=iachar("z") ) then 24 | ! Subtract 32 from ASCII Value, to convert it to respective capital letter 25 | firstletter = achar(iachar(firstletter)-32) 26 | ! Overwrite the first letter 27 | cmd(1:1) = firstletter 28 | end if 29 | printoutput = adjustl(trim(cmd)) 30 | write(*,'(g0.8)')printoutput 31 | end program capitalize -------------------------------------------------------------------------------- /src/language_examples/html.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/language_examples/java.java: -------------------------------------------------------------------------------- 1 | class PrimeNumberException extends Exception { 2 | } 3 | 4 | public class PrimeNumber { 5 | 6 | public static boolean isPrime(int number) { 7 | if ((number % 2 == 0 && number != 2) || number == 1) { 8 | return false; 9 | } 10 | 11 | boolean foundFactor = false; 12 | for (int n = 3; n <= (int) Math.ceil(Math.sqrt(number)); ++n) { 13 | if ((number % n) == 0) { 14 | foundFactor = true; 15 | break; 16 | } 17 | } 18 | return !foundFactor; 19 | } 20 | 21 | public static void main(String[] args) { 22 | try { 23 | 24 | if (args.length < 1 || args[0].indexOf('-') != -1) { 25 | throw new PrimeNumberException(); 26 | } 27 | 28 | if (isPrime(Integer.valueOf(args[0]))) { 29 | System.out.println("Prime"); 30 | 31 | } else { 32 | System.out.println("Composite"); 33 | } 34 | 35 | } catch (NumberFormatException | PrimeNumberException e) { 36 | System.err.println("Usage: please input a non-negative integer"); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/language_examples/javascript.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Main Code for Longest Commmon Subsequence 3 | * 4 | * @param {Integer[]} arr1 5 | * @param {Integer[]} arr2 6 | */ 7 | 8 | function lcs(arr1, arr2) { 9 | let matrix = [...Array(arr1.length + 1)].fill(0).map(() => Array(arr2.length + 1).fill(0)) 10 | 11 | for (let rowIndex = 1; rowIndex <= arr1.length; rowIndex++) { 12 | for (let columnIndex = 1; columnIndex <= arr2.length; columnIndex++) { 13 | if (arr1[rowIndex - 1] === arr2[columnIndex - 1]) { 14 | matrix[rowIndex][columnIndex] = 1 + matrix[rowIndex - 1][columnIndex - 1] 15 | } else { 16 | matrix[rowIndex][columnIndex] = Math.max( 17 | matrix[rowIndex - 1][columnIndex], 18 | matrix[rowIndex][columnIndex - 1], 19 | ) 20 | } 21 | } 22 | } 23 | //If there is no match, printing empty string 24 | if (matrix[arr1.length][arr2.index] === 0) { 25 | console.log("") 26 | return 27 | } 28 | 29 | let result = [] 30 | let rowIndex = arr1.length 31 | let columnIndex = arr2.length 32 | 33 | while (rowIndex > 0 && columnIndex > 0) { 34 | if (arr1[rowIndex - 1] === arr2[columnIndex - 1]) { 35 | //Prepending everytime a new character is matched in both strings 36 | result.unshift(arr1[rowIndex - 1]) 37 | rowIndex-- 38 | columnIndex-- 39 | } else if (matrix[rowIndex - 1][columnIndex] === matrix[rowIndex][columnIndex]) { 40 | rowIndex-- 41 | } else { 42 | columnIndex-- 43 | } 44 | } 45 | //Converting the LCS array into a comma separated string 46 | console.log(result.join(", ")) 47 | } 48 | 49 | //Usage Text 50 | const usage = 'Usage: please provide two lists in the format "1, 2, 3, 4, 5"' 51 | if (process.argv.length < 4 || process.argv[2] == "" || process.argv[3] == "") { 52 | console.log(usage) 53 | return 54 | } else { 55 | const input1 = process.argv[2] 56 | const input2 = process.argv[3] 57 | //Parsing into integers after trimming extra blank spaces 58 | const array1 = input1.split(",").map((x) => parseInt(x.trim(), 10)) 59 | const array2 = input2.split(",").map((y) => parseInt(y.trim(), 10)) 60 | lcs(array1, array2) 61 | } 62 | -------------------------------------------------------------------------------- /src/language_examples/kotlin.kts: -------------------------------------------------------------------------------- 1 | fun main(args: Array) 2 | { 3 | if (args.isNullOrEmpty() || args[0].isBlank() || args[0].toIntOrNull()?.takeIf { it >= 0 } == null) { 4 | println("Usage: please input a non-negative integer") 5 | return 6 | } 7 | 8 | val num = args[0].toInt() 9 | if(num>1) 10 | { 11 | for(i in 2 until num) 12 | { 13 | if(num%i == 0) 14 | { 15 | println("Composite") 16 | return 17 | } 18 | } 19 | println("Prime") 20 | } 21 | else 22 | { 23 | println("Composite") 24 | } 25 | } -------------------------------------------------------------------------------- /src/language_examples/php.php: -------------------------------------------------------------------------------- 1 | 4 10 | end 11 | 12 | counter_numbers.reject { |k| k == 'M' }.all? { |(_, counter)| counter <= 3 } 13 | end 14 | 15 | def roman_to_decimal(full_roman_number) 16 | return 'Usage: please provide a string of roman numerals' if full_roman_number.nil? 17 | return 0 if full_roman_number.empty? 18 | 19 | roman_numbers = full_roman_number.upcase.split('') 20 | return 'Error: invalid string of roman numerals' unless roman_valid?(roman_numbers) 21 | 22 | total = 0 23 | 24 | roman_numbers.each_with_index do |roman_number, index| 25 | current_value = ROMAN_VALUES[roman_number.to_sym] 26 | next_value = ROMAN_VALUES[roman_numbers[index+1]&.to_sym] || 0 27 | 28 | if (current_value >= next_value) 29 | total += current_value 30 | else 31 | total -= current_value 32 | end 33 | end 34 | 35 | total 36 | end 37 | 38 | print(roman_to_decimal(ARGV[0])) -------------------------------------------------------------------------------- /src/language_examples/rust.rs: -------------------------------------------------------------------------------- 1 | // Requirement https://sample-programs.therenegadecoder.com/projects/prime-number/ 2 | // Accept a number on command line and print if it is Composite or Prime 3 | // Works till 39 digits, ... 4 | 5 | use std::env::args; 6 | use std::process::exit; 7 | use std::str::FromStr; 8 | 9 | fn usage() -> ! { 10 | println!("Usage: please input a non-negative integer"); 11 | exit(0); 12 | } 13 | 14 | fn parse_int(s: &str) -> Result::Err> { 15 | s.trim().parse::() 16 | } 17 | 18 | fn main() { 19 | let mut args = args().skip(1); 20 | 21 | // Exit if 1st command-line argument not an positive integer 22 | let input_num: u128 = args 23 | .next() 24 | .and_then(|s| parse_int(&s).ok()) 25 | .unwrap_or_else(|| usage()); 26 | 27 | if input_num < 2 || (input_num != 2 && input_num % 2 == 0) { 28 | println!("Composite"); 29 | exit(0); 30 | } 31 | 32 | let mut n = 3u128; 33 | while n * n <= input_num { 34 | if input_num % n == 0 { 35 | println!("Composite"); 36 | exit(0); 37 | } 38 | n += 2; 39 | } 40 | println!("Prime"); 41 | } -------------------------------------------------------------------------------- /src/language_examples/typescript.ts: -------------------------------------------------------------------------------- 1 | function fibonacci(num: number) { 2 | let n = Number(num) 3 | let elementOne: number = 0 4 | let elementTwo: number = 1 5 | let result: number = 0 6 | 7 | for (let i: number = 1; i <= n; i++) { 8 | result = elementOne + elementTwo 9 | elementOne = elementTwo 10 | elementTwo = result 11 | console.log(`${i}: ${elementOne}`) 12 | } 13 | } 14 | 15 | let num_str = process.argv.length >= 3 ? process.argv[2] : "" 16 | let num: number = parseInt(num_str) 17 | if (isNaN(num)) { 18 | console.log("Usage: please input the count of fibonacci numbers to output") 19 | process.exit(0) 20 | } 21 | 22 | fibonacci(num) 23 | -------------------------------------------------------------------------------- /src/tests/braille.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Braille Glyph Recipes 8 | 50 | 51 | 52 |
53 |
54 |
55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/tests/braille.js: -------------------------------------------------------------------------------- 1 | function brailleRecipes() { 2 | // 1 4 3 | // 2 5 4 | // 3 6 5 | // 7 8 6 | const positionOf1 = [190, 570] 7 | const offset = 220 8 | const positions = { 9 | 1: [0, 0], 10 | 2: [0, "bd1"], 11 | 3: [0, "bd2"], 12 | 4: ["bd1", 0], 13 | 5: ["bd1", "bd1"], 14 | 6: ["bd1", "bd2"], 15 | 7: [0, "bd3"], 16 | 8: ["bd1", "bd3"], 17 | } 18 | const container = document.querySelector("#container") 19 | 20 | const blank = document.createElement("div") 21 | blank.innerHTML = `

brblank

${String.fromCharCode(10240)}

` 22 | container.append(blank) 23 | for (let i = 1; i < 256; i++) { 24 | const name = 25 | "dots" + 26 | i 27 | .toString(2) 28 | .split("") 29 | .reverse() 30 | .map((n, i) => (n == 1 ? i + 1 : null)) 31 | .filter(Boolean) 32 | .join("") 33 | const recipe = 34 | "=" + 35 | i 36 | .toString(2) 37 | .split("") 38 | .reverse() 39 | .map((n, i) => (n == 1 ? i + 1 : null)) 40 | .filter(Boolean) 41 | .map((dotNumber) => positions[dotNumber]) 42 | .map(([x, y]) => `_bdot@${x ? "`origin+" + x + "`" : "origin"},${y ? "`origin-" + y + "`" : "origin"}`) 43 | .join("+") 44 | const div = document.createElement("div") 45 | div.innerHTML = `

${name}

${String.fromCharCode(10240 + i)}

` 46 | div.addEventListener("click", () => { 47 | div.classList.toggle("clicked") 48 | navigator.clipboard.writeText(recipe) 49 | }) 50 | container.append(div) 51 | // console.log(name, recipe) 52 | } 53 | // console.log(positions) 54 | } 55 | brailleRecipes() 56 | -------------------------------------------------------------------------------- /src/tests/calt.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | const readline = require("readline") 3 | 4 | function pbcopy(data) { 5 | var proc = require("child_process").spawn("pbcopy") 6 | proc.stdin.write(data) 7 | proc.stdin.end() 8 | } 9 | 10 | async function featuresToCalt() { 11 | // const features = ["ss01_arrows", "ss02_less_equal", "ss03_case", "ss04_ellipsis", "ss05_smartkerning"] 12 | const features = ["ss03_case", "ss04_ellipsis", "ss05_smartkerning"] 13 | 14 | let calt = [] 15 | 16 | for await (const feature of features) { 17 | const fileStream = fs.createReadStream(`../features/${feature}.fea`) 18 | 19 | const rl = readline.createInterface({ 20 | input: fileStream, 21 | crlfDelay: Infinity, 22 | }) 23 | // Note: we use the crlfDelay option to recognize all instances of CR LF 24 | // ('\r\n') in input.txt as a single line break. 25 | 26 | const lines = [] 27 | 28 | lines.push(`### feature ${feature} ###`) 29 | 30 | for await (const line of rl) { 31 | // Each line in input.txt will be successively available here as `line`. 32 | // console.log(`Line from file: ${line}`) 33 | lines.push(line) 34 | } 35 | 36 | calt.push(lines) 37 | } 38 | 39 | calt = calt.flat().filter((ln) => !ln.includes("feature") && !ln.includes("} ss")) 40 | calt = calt.map((ln) => { 41 | if (ln.includes("lookup")) return ln.split("lookup ").join("lookup _") 42 | if (ln.includes("} ")) return ln.split("} ").join("} _") 43 | return ln 44 | }) 45 | 46 | // calt.forEach((ln) => console.log(ln)) 47 | pbcopy(` 48 | feature calt { 49 | # Contextual Alternates 50 | # Contains all 'cxxx' features 51 | 52 | ${calt.join("\n")} 53 | 54 | } calt;`) 55 | } 56 | 57 | featuresToCalt() 58 | -------------------------------------------------------------------------------- /src/tests/classes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Generate Axis Value 8 | 9 | 10 |
11 | 12 |
13 |
14 | 15 |
16 |
17 | 18 |
19 |
20 |

21 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/tests/f.js: -------------------------------------------------------------------------------- 1 | // @dflt = [exclam comma period slash colon semicolon question backslash bar]; 2 | // @c2_1 = [exclam.c2_1 comma.c2_1 period.c2_1 slash.c2_1 colon.c2_1 semicolon.c2_1 question.c2_1 backslash.c2_1 bar.c2_1]; 3 | // @c2_2 = [exclam.c2_2 comma.c2_2 period.c2_2 slash.c2_2 colon.c2_2 semicolon.c2_2 question.c2_2 backslash.c2_2 bar.c2_2]; 4 | // @c3_1 = [exclam.c3_1 comma.c3_1 period.c3_1 slash.c3_1 colon.c3_1 semicolon.c3_1 question.c3_1 backslash.c3_1 bar.c3_1]; 5 | // @c3_2 = [exclam comma period slash colon semicolon question backslash bar]; 6 | // @c3_3 = [exclam.c3_3 comma.c3_3 period.c3_3 slash.c3_3 colon.c3_3 semicolon.c3_3 question.c3_3 backslash.c3_3 bar.c3_3]; 7 | 8 | const input = 9 | "exclam exclam.square comma period period.square slash slash.case colon colon.square colon.case colon.case.square semicolon semicolon.square semicolon.case semicolon.case.square question question.square backslash backslash.case bar bar.case less less.case greater greater.case asterisk asterisk.case plus plus.case hyphen hyphen.case equal equal.case asciitilde asciitilde.case" 10 | function c002(input) { 11 | const s = input.split(" ") 12 | return ` 13 | @dflt = [${input}]; 14 | @c2_1 = [${s.join(".c2_1 ")}.c2_1]; 15 | @c2_2 = [${s.join(".c2_2 ")}.c2_2]; 16 | @c3_1 = [${s.join(".c3_1 ")}.c3_1]; 17 | @c3_3 = [${s.join(".c3_3 ")}.c3_3]; 18 | ` 19 | } 20 | 21 | function classExcess(c) { 22 | return [...new Set(c.split(" "))].join(" ") 23 | } 24 | 25 | function buildGlyphs(g) { 26 | return g 27 | .split(", ") 28 | .map((gl) => gl.split("=")[0]) 29 | .join(", ") 30 | } 31 | 32 | function pbcopy(data) { 33 | var proc = require("child_process").spawn("pbcopy") 34 | proc.stdin.write(data) 35 | proc.stdin.end() 36 | } 37 | 38 | pbcopy(c002(input)) 39 | console.log(c002(input)) 40 | 41 | // pbcopy(classExcess(classContent)) 42 | // console.log(classExcess(classContent)) 43 | 44 | // pbcopy(buildGlyphs(input)) 45 | // console.log(buildGlyphs(input)) 46 | -------------------------------------------------------------------------------- /src/tests/instances.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Generate Axis Value 8 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | 20 | 21 |
22 |
23 | 24 | 25 |
26 |
27 | 28 |
29 |
30 |

31 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/tests/tables.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | School timetable 7 | 33 | 34 | 35 |

School timetable

36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
 MonTuesWedThursFriSatSun
1st periodEnglish  GermanDutch  
2nd periodEnglishEnglish GermanDutch  
3rd period German GermanDutch  
4th period English EnglishDutch  
89 | 90 | 91 | -------------------------------------------------------------------------------- /src/txt/featuretest.txt: -------------------------------------------------------------------------------- 1 | Commit Mono: Normal 2 | programming typeface 3 | 4 | 5 | FEATURES 6 | => <= H:H ... immi 7 | 8 | 9 | ALTERNATES 10 | a g . i @ 6 0 y * 11 | 12 | 13 | SMART KERNING 14 | iom oom Hom moH 15 | ioH ooH Hoo moo 16 | ioo ooi Hoi moi 17 | 18 | tmmt tCCt toot gttg CttC mttm 19 | gmmg gCCg CggC mggm 20 | CmmC mCCm 21 | 22 | 23 | ARROWS 24 | <- <------ 25 | <= <====== 26 | -> ------> 27 | => ======> 28 | <<-----<< 29 | >>----->> 30 | <<----->> 31 | >>-----<< 32 | <<=====<< 33 | >>=====>> 34 | <<=====>> 35 | >>=====<< 36 | 37 | 38 | CASE 39 | H: H : 40 | e: H:o 41 | H : H H: o H : o 42 | H :::::H ::::::H 43 | H ::::: H :::::: H 44 | H-----H H------H 45 | H-----n H------n 46 | n-----H n------H 47 | n-----n n------n 48 | H----- n H------ n 49 | n -----H n ------H 50 | 51 | 52 | LIGATURES 53 | x <= x >= x == x === x != x !== x 54 | x <= X >= x == X === x != X !== x 55 | X <= X >= X == X === X != X !== X 56 | -------------------------------------------------------------------------------- /src/txt/installation.txt: -------------------------------------------------------------------------------- 1 | A short guide for how to install and enable your shiny new version of Commit Mono. 2 | This is taken from section 08 Install from https://commitmono.com/ 3 | 4 | #1 (Download the fonts) 5 | #2 Unzip the fonts. You'll see 4 font files. These 4 fonts make up a 'Style Group': 6 | * CommitMono-Regular: Base version with settings and weight of your choice. 7 | * CommitMono-Italic: An italic version, same weight as regular. 8 | * CommitMono-Bold: A bold version, weight 700. 9 | * CommitMono-BoldItalic: A bold version, weight 700, that is also italic. 10 | #3 Install all 4 fonts on your system: 11 | * Windows: Right click the font in the folder and click "Install". 12 | * Mac: Open fonts with Font Book from the folder and click "Install". 13 | * Linux: Unpack fonts to ~/.local/share/fonts (or /usr/share/fonts to install 14 | fonts system-wide) then fc-cache -f -v 15 | #4 Restart your editor/IDE. 16 | #5 Activate Commit Mono in your editor. 17 | Settings/Preferences → Editor → Font: Pick ‘CommitMono’ from the list (notice: 18 | there is no space). If you’re using VS Code, simply add these two lines to the 19 | settings.json file: 20 | "editor.fontFamily": "CommitMono", 21 | "editor.fontLigatures": true, 22 | 23 | For a comprehensive guide on how to enable features/ligatures in your specific 24 | editor/IDE, refer to Fira Code wiki: 25 | https://github.com/tonsky/FiraCode/wiki#enabling-ligatures -------------------------------------------------------------------------------- /src/txt/license.txt: -------------------------------------------------------------------------------- 1 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 2 | This license is copied below, and is also available with a FAQ at: 3 | http://scripts.sil.org/OFL 4 | 5 | ----------------------------------------------------------- 6 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 7 | ----------------------------------------------------------- 8 | 9 | PREAMBLE 10 | The goals of the Open Font License (OFL) are to stimulate worldwide 11 | development of collaborative font projects, to support the font creation 12 | efforts of academic and linguistic communities, and to provide a free and 13 | open framework in which fonts may be shared and improved in partnership 14 | with others. 15 | 16 | The OFL allows the licensed fonts to be used, studied, modified and 17 | redistributed freely as long as they are not sold by themselves. The 18 | fonts, including any derivative works, can be bundled, embedded, 19 | redistributed and/or sold with any software provided that any reserved 20 | names are not used by derivative works. The fonts and derivatives, 21 | however, cannot be released under any other type of license. The 22 | requirement for fonts to remain under this license does not apply 23 | to any document created using the fonts or their derivatives. 24 | 25 | DEFINITIONS 26 | "Font Software" refers to the set of files released by the Copyright 27 | Holder(s) under this license and clearly marked as such. This may 28 | include source files, build scripts and documentation. 29 | 30 | "Reserved Font Name" refers to any names specified as such after the 31 | copyright statement(s). 32 | 33 | "Original Version" refers to the collection of Font Software components as 34 | distributed by the Copyright Holder(s). 35 | 36 | "Modified Version" refers to any derivative made by adding to, deleting, 37 | or substituting -- in part or in whole -- any of the components of the 38 | Original Version, by changing formats or by porting the Font Software to a 39 | new environment. 40 | 41 | "Author" refers to any designer, engineer, programmer, technical 42 | writer or other person who contributed to the Font Software. 43 | 44 | PERMISSION & CONDITIONS 45 | Permission is hereby granted, free of charge, to any person obtaining 46 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 47 | redistribute, and sell modified and unmodified copies of the Font 48 | Software, subject to the following conditions: 49 | 50 | 1) Neither the Font Software nor any of its individual components, 51 | in Original or Modified Versions, may be sold by itself. 52 | 53 | 2) Original or Modified Versions of the Font Software may be bundled, 54 | redistributed and/or sold with any software, provided that each copy 55 | contains the above copyright notice and this license. These can be 56 | included either as stand-alone text files, human-readable headers or 57 | in the appropriate machine-readable metadata fields within text or 58 | binary files as long as those fields can be easily viewed by the user. 59 | 60 | 3) No Modified Version of the Font Software may use the Reserved Font 61 | Name(s) unless explicit written permission is granted by the corresponding 62 | Copyright Holder. This restriction only applies to the primary font name as 63 | presented to the users. 64 | 65 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 66 | Software shall not be used to promote, endorse or advertise any 67 | Modified Version, except to acknowledge the contribution(s) of the 68 | Copyright Holder(s) and the Author(s) or with their explicit written 69 | permission. 70 | 71 | 5) The Font Software, modified or unmodified, in part or in whole, 72 | must be distributed entirely under this license, and must not be 73 | distributed under any other license. The requirement for fonts to 74 | remain under this license does not apply to any document created 75 | using the Font Software. 76 | 77 | TERMINATION 78 | This license becomes null and void if any of the above conditions are 79 | not met. 80 | 81 | DISCLAIMER 82 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 83 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 84 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 85 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 86 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 87 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 88 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 89 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 90 | OTHER DEALINGS IN THE FONT SOFTWARE. -------------------------------------------------------------------------------- /src/txt/todo.txt: -------------------------------------------------------------------------------- 1 | High priority 2 | [x] Make instances available 3 | [x] Make variable font available 4 | [x] Include license in download 5 | [x] Add links to Mads Brodt 6 | [x] Bold & space out FAQ 7 | [x] Fix != ligature 8 | [ ] Fix download in Safari 9 | [x] Update 08 Install to include "editor.fontLigatures": true, somewhere 10 | 11 | Medium priority 12 | [ ] Make open source and add good README.md file 13 | [ ] Improve drawing quality of italic version 14 | [ ] ?? Delete other features in code version 15 | [ ] Make Cyrillic and Greek characterset 16 | [ ] Update 08 Install with bold text 17 | [ ] Spread the word 18 | [ ] Submit website to FWA and Awwwards 19 | 20 | Low priority 21 | [ ] Make changes made in 07 Customize site wide 22 | [ ] Update GTC with more games 23 | [ ] ?? distinquish code version from web version 24 | [ ] Add support to type your own character in code section 25 | [ ] Write article to publish in some typography magazine 26 | [ ] Make Commit Sans -------------------------------------------------------------------------------- /src/txt/ttfautohint.txt: -------------------------------------------------------------------------------- 1 | # step 1: export default from website an place in src/fonts/website-export/CommitMono.zip 2 | # step 2: make sure fontforge and ttfautohint is installed 3 | # step 3: run this from the root directory 4 | 5 | rm src/fonts/*.zip 6 | mkdir src/fonts/CommitMono-1.143 7 | mv src/fonts/website-export/CommitMono.zip src/fonts/CommitMono-1.143/CommitMono.zip 8 | cd src/fonts/CommitMono-1.143 9 | unzip CommitMono.zip 10 | rm CommitMono.zip 11 | mkdir ttfautohint 12 | fontforge -lang ff -c 'Open("CommitMono-400-Regular.otf"); Generate("CommitMono-400-Regular-unhinted.ttf")' 13 | fontforge -lang ff -c 'Open("CommitMono-400-Italic.otf"); Generate("CommitMono-400-Italic-unhinted.ttf")' 14 | fontforge -lang ff -c 'Open("CommitMono-700-Regular.otf"); Generate("CommitMono-700-Regular-unhinted.ttf")' 15 | fontforge -lang ff -c 'Open("CommitMono-700-Italic.otf"); Generate("CommitMono-700-Italic-unhinted.ttf")' 16 | ttfautohint -R CommitMono-400-Regular-unhinted.ttf -a sss CommitMono-400-Regular-unhinted.ttf ttfautohint/CommitMono-400-Regular.ttf 17 | ttfautohint -R CommitMono-400-Regular-unhinted.ttf -a sss CommitMono-400-Italic-unhinted.ttf ttfautohint/CommitMono-400-Italic.ttf 18 | ttfautohint -R CommitMono-400-Regular-unhinted.ttf -a sss CommitMono-700-Regular-unhinted.ttf ttfautohint/CommitMono-700-Regular.ttf 19 | ttfautohint -R CommitMono-400-Regular-unhinted.ttf -a sss CommitMono-700-Italic-unhinted.ttf ttfautohint/CommitMono-700-Italic.ttf 20 | rm CommitMono-400-Regular-unhinted.ttf 21 | rm CommitMono-400-Italic-unhinted.ttf 22 | rm CommitMono-700-Regular-unhinted.ttf 23 | rm CommitMono-700-Italic-unhinted.ttf 24 | cd .. 25 | zip -vr CommitMono-1.143.zip CommitMono-1.143/ -x "*.DS_Store" 26 | rm -R CommitMono-1.143 27 | cd .. 28 | cd .. 29 | 30 | # step 4: upload src/fonts/CommitMono.zip to GitHub -------------------------------------------------------------------------------- /src/txt/woff2_conversion_guide.txt: -------------------------------------------------------------------------------- 1 | #1 Rename variable font to "CommitMonoV143-VF.ttf" 2 | #2 Navigate to /Developer/woff2 3 | #3 4 | ~/Developer/woff2/woff2_compress ~/Library/CloudStorage/Dropbox/Privat/Eigils\ ting/projects/typography/Font\ Projects/code-mono-font/commit-mono/export/CommitMonoV143/CommitMonoV143-VF.ttf --------------------------------------------------------------------------------