├── .gitignore ├── LICENSE.md ├── Makefile ├── README.md ├── images ├── fontforge │ └── Dockerfile └── iosevka │ └── Dockerfile ├── private-build-plans.toml ├── punctuation.py └── sample.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/macos,windows,linux,node 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=macos,windows,linux,node 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### macOS ### 20 | # General 21 | .DS_Store 22 | .AppleDouble 23 | .LSOverride 24 | 25 | # Icon must end with two \r 26 | Icon 27 | 28 | 29 | # Thumbnails 30 | ._* 31 | 32 | # Files that might appear in the root of a volume 33 | .DocumentRevisions-V100 34 | .fseventsd 35 | .Spotlight-V100 36 | .TemporaryItems 37 | .Trashes 38 | .VolumeIcon.icns 39 | .com.apple.timemachine.donotpresent 40 | 41 | # Directories potentially created on remote AFP share 42 | .AppleDB 43 | .AppleDesktop 44 | Network Trash Folder 45 | Temporary Items 46 | .apdisk 47 | 48 | ### macOS Patch ### 49 | # iCloud generated files 50 | *.icloud 51 | 52 | ### Node ### 53 | # Logs 54 | logs 55 | *.log 56 | npm-debug.log* 57 | yarn-debug.log* 58 | yarn-error.log* 59 | lerna-debug.log* 60 | .pnpm-debug.log* 61 | 62 | # Diagnostic reports (https://nodejs.org/api/report.html) 63 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 64 | 65 | # Runtime data 66 | pids 67 | *.pid 68 | *.seed 69 | *.pid.lock 70 | 71 | # Directory for instrumented libs generated by jscoverage/JSCover 72 | lib-cov 73 | 74 | # Coverage directory used by tools like istanbul 75 | coverage 76 | *.lcov 77 | 78 | # nyc test coverage 79 | .nyc_output 80 | 81 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 82 | .grunt 83 | 84 | # Bower dependency directory (https://bower.io/) 85 | bower_components 86 | 87 | # node-waf configuration 88 | .lock-wscript 89 | 90 | # Compiled binary addons (https://nodejs.org/api/addons.html) 91 | build/Release 92 | 93 | # Dependency directories 94 | node_modules/ 95 | jspm_packages/ 96 | 97 | # Snowpack dependency directory (https://snowpack.dev/) 98 | web_modules/ 99 | 100 | # TypeScript cache 101 | *.tsbuildinfo 102 | 103 | # Optional npm cache directory 104 | .npm 105 | 106 | # Optional eslint cache 107 | .eslintcache 108 | 109 | # Optional stylelint cache 110 | .stylelintcache 111 | 112 | # Microbundle cache 113 | .rpt2_cache/ 114 | .rts2_cache_cjs/ 115 | .rts2_cache_es/ 116 | .rts2_cache_umd/ 117 | 118 | # Optional REPL history 119 | .node_repl_history 120 | 121 | # Output of 'npm pack' 122 | *.tgz 123 | 124 | # Yarn Integrity file 125 | .yarn-integrity 126 | 127 | # dotenv environment variable files 128 | .env 129 | .env.development.local 130 | .env.test.local 131 | .env.production.local 132 | .env.local 133 | 134 | # parcel-bundler cache (https://parceljs.org/) 135 | .cache 136 | .parcel-cache 137 | 138 | # Next.js build output 139 | .next 140 | out 141 | 142 | # Nuxt.js build / generate output 143 | .nuxt 144 | dist 145 | 146 | # Gatsby files 147 | .cache/ 148 | # Comment in the public line in if your project uses Gatsby and not Next.js 149 | # https://nextjs.org/blog/next-9-1#public-directory-support 150 | # public 151 | 152 | # vuepress build output 153 | .vuepress/dist 154 | 155 | # vuepress v2.x temp and cache directory 156 | .temp 157 | 158 | # Docusaurus cache and generated files 159 | .docusaurus 160 | 161 | # Serverless directories 162 | .serverless/ 163 | 164 | # FuseBox cache 165 | .fusebox/ 166 | 167 | # DynamoDB Local files 168 | .dynamodb/ 169 | 170 | # TernJS port file 171 | .tern-port 172 | 173 | # Stores VSCode versions used for testing VSCode extensions 174 | .vscode-test 175 | 176 | # yarn v2 177 | .yarn/cache 178 | .yarn/unplugged 179 | .yarn/build-state.yml 180 | .yarn/install-state.gz 181 | .pnp.* 182 | 183 | ### Node Patch ### 184 | # Serverless Webpack directories 185 | .webpack/ 186 | 187 | # Optional stylelint cache 188 | 189 | # SvelteKit build / generate output 190 | .svelte-kit 191 | 192 | ### Windows ### 193 | # Windows thumbnail cache files 194 | Thumbs.db 195 | Thumbs.db:encryptable 196 | ehthumbs.db 197 | ehthumbs_vista.db 198 | 199 | # Dump file 200 | *.stackdump 201 | 202 | # Folder config file 203 | [Dd]esktop.ini 204 | 205 | # Recycle Bin used on file shares 206 | $RECYCLE.BIN/ 207 | 208 | # Windows Installer files 209 | *.cab 210 | *.msi 211 | *.msix 212 | *.msm 213 | *.msp 214 | 215 | # Windows shortcuts 216 | *.lnk 217 | 218 | # End of https://www.toptal.com/developers/gitignore/api/macos,windows,linux,node 219 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2022, Renzhi Li (aka. Belleve Invis, belleve@typeof.net) 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | 5 | This license is copied below, and is also available with a FAQ at: 6 | http://scripts.sil.org/OFL 7 | 8 | -------------------------- 9 | 10 | 11 | SIL Open Font License v1.1 12 | ==================================================== 13 | 14 | 15 | Preamble 16 | ---------- 17 | 18 | The goals of the Open Font License (OFL) are to stimulate worldwide 19 | development of collaborative font projects, to support the font creation 20 | efforts of academic and linguistic communities, and to provide a free and 21 | open framework in which fonts may be shared and improved in partnership 22 | with others. 23 | 24 | The OFL allows the licensed fonts to be used, studied, modified and 25 | redistributed freely as long as they are not sold by themselves. The 26 | fonts, including any derivative works, can be bundled, embedded, 27 | redistributed and/or sold with any software provided that any reserved 28 | names are not used by derivative works. The fonts and derivatives, 29 | however, cannot be released under any other type of license. The 30 | requirement for fonts to remain under this license does not apply 31 | to any document created using the fonts or their derivatives. 32 | 33 | 34 | Definitions 35 | ------------- 36 | 37 | `"Font Software"` refers to the set of files released by the Copyright 38 | Holder(s) under this license and clearly marked as such. This may 39 | include source files, build scripts and documentation. 40 | 41 | `"Reserved Font Name"` refers to any names specified as such after the 42 | copyright statement(s). 43 | 44 | `"Original Version"` refers to the collection of Font Software components as 45 | distributed by the Copyright Holder(s). 46 | 47 | `"Modified Version"` refers to any derivative made by adding to, deleting, 48 | or substituting -- in part or in whole -- any of the components of the 49 | Original Version, by changing formats or by porting the Font Software to a 50 | new environment. 51 | 52 | `"Author"` refers to any designer, engineer, programmer, technical 53 | writer or other person who contributed to the Font Software. 54 | 55 | 56 | Permission & Conditions 57 | ------------------------ 58 | 59 | Permission is hereby granted, free of charge, to any person obtaining 60 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 61 | redistribute, and sell modified and unmodified copies of the Font 62 | Software, subject to the following conditions: 63 | 64 | 1. Neither the Font Software nor any of its individual components, 65 | in Original or Modified Versions, may be sold by itself. 66 | 67 | 2. Original or Modified Versions of the Font Software may be bundled, 68 | redistributed and/or sold with any software, provided that each copy 69 | contains the above copyright notice and this license. These can be 70 | included either as stand-alone text files, human-readable headers or 71 | in the appropriate machine-readable metadata fields within text or 72 | binary files as long as those fields can be easily viewed by the user. 73 | 74 | 3. No Modified Version of the Font Software may use the Reserved Font 75 | Name(s) unless explicit written permission is granted by the corresponding 76 | Copyright Holder. This restriction only applies to the primary font name as 77 | presented to the users. 78 | 79 | 4. The name(s) of the Copyright Holder(s) or the Author(s) of the Font 80 | Software shall not be used to promote, endorse or advertise any 81 | Modified Version, except to acknowledge the contribution(s) of the 82 | Copyright Holder(s) and the Author(s) or with their explicit written 83 | permission. 84 | 85 | 5. The Font Software, modified or unmodified, in part or in whole, 86 | must be distributed entirely under this license, and must not be 87 | distributed under any other license. The requirement for fonts to 88 | remain under this license does not apply to any document created 89 | using the Font Software. 90 | 91 | 92 | 93 | Termination 94 | ----------- 95 | 96 | This license becomes null and void if any of the above conditions are 97 | not met. 98 | 99 | 100 | DISCLAIMER 101 | 102 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 103 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 104 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 105 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 106 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 107 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 108 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 109 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 110 | OTHER DEALINGS IN THE FONT SOFTWARE. 111 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: help, images 2 | help: ## Show this help 3 | @egrep -h '\s##\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' 4 | 5 | images: ## Create Docker image dependencies 6 | make builder 7 | make scripter 8 | 9 | builder: ## Create the `iosevka` builder Docker image 10 | docker build --no-cache -t iosevka/builder ./images/iosevka 11 | 12 | scripter: ## Create the `fontforge` scripter Docker image 13 | docker build --no-cache -t fontforge/scripter ./images/fontforge 14 | 15 | font: ## Run all build steps in correct order 16 | make --ignore-errors ttf 17 | make --ignore-errors nerd 18 | make --ignore-errors package 19 | 20 | ttf: ## Build ttf font from `Pragmasevka` custom configuration 21 | docker run --rm \ 22 | -v pragmasevka-volume:/builder/dist/pragmasevka/TTF \ 23 | -v $(CURDIR)/private-build-plans.toml:/builder/private-build-plans.toml \ 24 | iosevka/builder \ 25 | npm run build -- ttf::pragmasevka 26 | docker run --rm \ 27 | -v pragmasevka-volume:/scripter \ 28 | -v $(CURDIR)/punctuation.py:/scripter/punctuation.py \ 29 | fontforge/scripter \ 30 | python /scripter/punctuation.py ./pragmasevka 31 | docker container create \ 32 | -v pragmasevka-volume:/ttf \ 33 | --name pragmasevka-dummy \ 34 | alpine 35 | mkdir -p $(CURDIR)/dist/ttf 36 | docker cp pragmasevka-dummy:/ttf $(CURDIR)/dist 37 | docker rm pragmasevka-dummy 38 | docker volume rm pragmasevka-volume 39 | rm -rf $(CURDIR)/dist/ttf/*semibold*.ttf 40 | rm -rf $(CURDIR)/dist/ttf/*black*.ttf 41 | rm -rf $(CURDIR)/dist/ttf/punctuation.py 42 | mv "$(CURDIR)/dist/ttf/pragmasevka-normalbolditalic.ttf" "$(CURDIR)/dist/ttf/pragmasevka-bolditalic.ttf" 43 | mv "$(CURDIR)/dist/ttf/pragmasevka-normalboldupright.ttf" "$(CURDIR)/dist/ttf/pragmasevka-bold.ttf" 44 | mv "$(CURDIR)/dist/ttf/pragmasevka-normalregularitalic.ttf" "$(CURDIR)/dist/ttf/pragmasevka-italic.ttf" 45 | mv "$(CURDIR)/dist/ttf/pragmasevka-normalregularupright.ttf" "$(CURDIR)/dist/ttf/pragmasevka-regular.ttf" 46 | 47 | nerd: ## Patch with Nerd Fonts glyphs 48 | docker run --rm \ 49 | -v $(CURDIR)/dist/ttf:/in \ 50 | -v pragmasevka-volume:/out \ 51 | nerdfonts/patcher --complete --careful 52 | docker container create \ 53 | -v pragmasevka-volume:/nerd \ 54 | --name pragmasevka-dummy \ 55 | alpine 56 | docker cp pragmasevka-dummy:/nerd $(CURDIR)/dist 57 | docker rm pragmasevka-dummy 58 | docker volume rm pragmasevka-volume 59 | mv "$(CURDIR)/dist/nerd/PragmasevkaNerdFont-Regular.ttf" "$(CURDIR)/dist/nerd/pragmasevka-nf-regular.ttf" 60 | mv "$(CURDIR)/dist/nerd/PragmasevkaNerdFont-Italic.ttf" "$(CURDIR)/dist/nerd/pragmasevka-nf-italic.ttf" 61 | mv "$(CURDIR)/dist/nerd/PragmasevkaNerdFont-Bold.ttf" "$(CURDIR)/dist/nerd/pragmasevka-nf-bold.ttf" 62 | mv "$(CURDIR)/dist/nerd/PragmasevkaNerdFont-BoldItalic.ttf" "$(CURDIR)/dist/nerd/pragmasevka-nf-bolditalic.ttf" 63 | 64 | package: ## Pack fonts to ready-to-distribute archives 65 | zip -jr $(CURDIR)/dist/Pragmasevka.zip $(CURDIR)/dist/ttf/*.ttf 66 | zip -jr $(CURDIR)/dist/Pragmasevka_NF.zip $(CURDIR)/dist/nerd/*.ttf 67 | 68 | clean: 69 | rm -rf $(CURDIR)/dist/* 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pragmasevka Font 2 | 3 | Here is comparison with PragmataPro (black, the image taken from [Wikipedia](https://en.wikipedia.org/wiki/PragmataPro)): 4 | 5 | ![Comparison with PragmataPro](https://github.com/shytikov/pragmasevka/blob/main/sample.png?raw=true) 6 | 7 | Yes, it's not a carbon copy. But metrics are pretty close. 8 | 9 | ## The story 10 | 11 | Do you love [PragmataPro](https://fsd.it/shop/fonts/pragmatapro/) as I am? Probabbly you do, if you're reading this. 12 | 13 | `PragmataPro` is awesome. It's condensed enough, but not too much. Its `xHeight` is spot on. Every character seems to be of the best possible shape for readability. There is no better font if you want to make most out of the screen real estate. But there is a catch: although it worth every penny, `PragmataPro` is not free. 14 | 15 | There were many attemps to achieve same goals as `PragmataPro` did: condensed with increased `xHeight`. I can name a few: 16 | 17 | - [Input](https://input.djr.com/); 18 | - [Monoid](https://larsenwork.com/monoid/); 19 | - [Victor Mono](https://rubjo.github.io/victor-mono/); 20 | - [JetBrains Mono](https://www.jetbrains.com/lp/mono/); 21 | 22 | But [Iosevka](https://github.com/be5invis/Iosevka) stands out of the crowd the most. The sole intention from very beginning of this font was to immitate `PragmataPro` as closely as possible. And first public versions proves that. But with time the font matured to a framework that able to provide much more than just a copy of very good font. 23 | 24 | Till the day we have `SS08` stylistic set of `Iosevka` that mimics `PragmataPro`. But does it the best possible job? 25 | 26 | ## Improving Iosevka SS08 27 | 28 | Investigating public images of text written in `PragmataPro` and having quite limited time and resources I was able to spot following differences between The Original and `SS08`: 29 | 30 | - `xHeight` of `SS08` seems to be smaller; 31 | - The line height of `SS08` seems to be larger; 32 | - `SS08` Regular looks a tiny bit thinner; 33 | - `SS08` Bold looks noticeably thinner; 34 | - `SS08` punctuation marks are consistent with the rest of the font, while PragmataPro has them slightly bolder; 35 | - There are slight differences in programming ligatures used; 36 | 37 | Luckly `Iosevka` allows some very sophisticated tweaking, so I have tried my best to improve on "poor man's Pragmata" by fixing these. 38 | 39 | ## I want one 40 | 41 | Head to [Releases](https://github.com/shytikov/pragmasevka/releases) and pick the archive you like: the bare build or [Nerd Fonts](https://www.nerdfonts.com/) enabled one. 42 | 43 | You can also build it locally by running: 44 | 45 | ```sh 46 | make images && make font 47 | ``` 48 | 49 | If you want to use the font for web development, as a webfont, please use following instructions (shout out to @aperturerobotics): 50 | 51 | 52 | ```bash 53 | # npm 54 | npm install @aptre/pragmasevka 55 | 56 | # yarn 57 | yarn add @aptre/pragmasevka 58 | 59 | # pnpm 60 | pnpm add @aptre/pragmasevka 61 | ``` 62 | 63 | ## Usage 64 | 65 | ```js 66 | // Import in JS/TS 67 | import '@aptre/pragmasevka'; 68 | ``` 69 | 70 | ```css 71 | @import "@aptre/pragmasevka/font.css"; 72 | 73 | /* Use in CSS */ 74 | font-family: 'Pragmasevka', monospace; 75 | ``` 76 | 77 | ## Improving it 78 | 79 | Let's face it – `PragmataPro` is perfect. And we all should buy it. And I will go it too exactly that day I would get bored from playing with `Iosevka`. And meanwhile if you have spotted something that could be improved, please file an [issue](https://github.com/shytikov/pragmasevka/issues). 80 | 81 | ## Thank you awesome community! 82 | 83 | I have been away from the repo using the font happily day to day, and returning noticed several forks appeared addressing issues starting piling up with time. I went on a Easter Quest collecting all these improvements and bringing it back together. Special thank you: 84 | 85 | - [@gdubois](https://github.com/gdubois) – for solving issues which would took me hours to figure out! 86 | - [@aperturerobotics](https://github.com/aperturerobotics) - for packaging webfont! 87 | 88 | ## Also worth checking 89 | 90 | - [NRK-Mono](https://github.com/N-R-K/NRK-Mono) - All benefits of [JetBrains Mono](https://github.com/JetBrains/JetBrainsMono) with more condensed option; 91 | - [Iosvmata](https://github.com/N-R-K/Iosvmata) - More extended version of Pragmasevka; 92 | - [Iosevka Tree Lig](https://www.jonashietala.se/iosevka/) - Very sane set of choices were made there! 93 | - [CommitMono](https://commitmono.com/) - Overall very boring, but surprisingly very usable font; 94 | -------------------------------------------------------------------------------- /images/fontforge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | 3 | RUN apk add python3 fontforge py3-fontforge 4 | 5 | WORKDIR /scripter -------------------------------------------------------------------------------- /images/iosevka/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:slim 2 | 3 | RUN \ 4 | apt-get update && \ 5 | apt-get install --yes git ttfautohint && \ 6 | apt-get clean autoclean && \ 7 | apt-get autoremove --yes && \ 8 | rm -rf /var/lib/{apt,dpkg,cache,log}/ 9 | 10 | WORKDIR /builder 11 | 12 | RUN \ 13 | git clone -b main --depth 1 https://github.com/be5invis/Iosevka /tmp/Iosevka && \ 14 | mv /tmp/Iosevka/* /builder && \ 15 | npm install 16 | -------------------------------------------------------------------------------- /private-build-plans.toml: -------------------------------------------------------------------------------- 1 | [buildPlans.pragmasevka] 2 | family = "Pragmasevka" 3 | spacing = "term" 4 | serifs = "sans" 5 | noCvSs = true 6 | exportGlyphNames = true 7 | 8 | hintParams = ["-a", "qqq"] 9 | 10 | [buildPlans.pragmasevka.widths.normal] 11 | shape = 500 12 | menu = 5 13 | css = "normal" 14 | 15 | [buildPlans.pragmasevka.metricOverride] 16 | leading = 1100 17 | xHeight = 550 18 | 19 | [buildPlans.pragmasevka.ligations] 20 | inherits="default-calt" 21 | enables = [ 22 | "eqslasheq", 23 | "kern-dotty", 24 | "kern-bars", 25 | "llggeq", 26 | "--fast-chaining--" 27 | ] 28 | disables = ["slash-asterisk"] 29 | 30 | [buildPlans.pragmasevka.variants] 31 | inherits = "ss08" 32 | 33 | [buildPlans.pragmasevka.weights.regular] 34 | shape = 425 35 | menu = 400 36 | css = 400 37 | 38 | [buildPlans.pragmasevka.weights.semibold] 39 | shape = 600 40 | menu = 600 41 | css = 600 42 | 43 | [buildPlans.pragmasevka.weights.bold] 44 | shape = 800 45 | menu = 700 46 | css = 700 47 | 48 | [buildPlans.pragmasevka.weights.black] 49 | shape = 900 50 | menu = 900 51 | css = 900 52 | 53 | [buildPlans.pragmasevka.slopes] 54 | upright = "default.Upright" 55 | italic = "default.Italic" 56 | -------------------------------------------------------------------------------- /punctuation.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import fontforge 3 | 4 | if len(sys.argv) < 2: 5 | print("Please provide path prefix of the font to update!") 6 | exit() 7 | 8 | prefix = sys.argv[1] 9 | 10 | glyphs = [ 11 | "colon", 12 | "comma", 13 | "period", 14 | "semicolon", 15 | ] 16 | 17 | pairs = [ 18 | ['regularupright', 'semiboldupright'], 19 | ['regularitalic', 'semibolditalic'], 20 | ['boldupright', 'blackupright'], 21 | ['bolditalic', 'blackitalic'], 22 | ] 23 | 24 | for [recipient, donor] in pairs: 25 | font = f"{prefix}-normal{recipient}.ttf" 26 | 27 | target = fontforge.open(font) 28 | # Finding all punctuation 29 | target.selection.select(*glyphs) 30 | # and deleting it to make space 31 | for i in target.selection.byGlyphs: 32 | target.removeGlyph(i) 33 | 34 | source = fontforge.open(f"{prefix}-normal{donor}.ttf") 35 | source.selection.select(*glyphs) 36 | source.copy() 37 | target.paste() 38 | 39 | target.generate(font) 40 | -------------------------------------------------------------------------------- /sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shytikov/pragmasevka/394103287e14d20482a299d56dcca66161ae58d4/sample.png --------------------------------------------------------------------------------