From d55f369d28a3c9f4ac97e5747771f09e7693e9b8 Mon Sep 17 00:00:00 2001 From: TakWolf Date: Thu, 12 Jun 2025 23:53:24 +0800 Subject: [PATCH] Simplify workflow --- .github/workflows/pages.yml | 41 +++++++ .github/workflows/release.yml | 28 +++++ .gitignore | 144 +++++++++++++++++++++++ README.md | 2 +- bitroot.ttf | Bin 35065 -> 0 bytes requirements.txt | 2 + preview.png => src/preview.png | Bin tools/__init__.py | 0 tools/build.py | 206 +++++++++++++++++++++++++++++++++ tools/path_define.py | 12 ++ www/css/index.css | 65 +++++++++++ www/index.html | 56 +++++++++ www/js/index.js | 13 +++ 13 files changed, 568 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/pages.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore delete mode 100644 bitroot.ttf create mode 100644 requirements.txt rename preview.png => src/preview.png (100%) create mode 100644 tools/__init__.py create mode 100644 tools/build.py create mode 100644 tools/path_define.py create mode 100644 www/css/index.css create mode 100644 www/index.html create mode 100644 www/js/index.js diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..e1a08a3 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,41 @@ +name: Pages + +on: + push: + branches: [main] + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + pages: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + permissions: + pages: write + id-token: write + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + - name: Install dependencies + run: | + python -m pip install pip --upgrade + python -m pip install -r requirements.txt + - name: Build + run: python -m tools.build + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./www + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..22e0cd8 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,28 @@ +name: Release + +on: + release: + types: [published] + +jobs: + release: + permissions: + contents: write + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + - name: Install dependencies + run: | + python -m pip install pip --upgrade + python -m pip install -r requirements.txt + - name: Build + run: python -m tools.build + - name: Release + uses: softprops/action-gh-release@v2 + with: + files: ./build/releases/*.zip diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..be4413e --- /dev/null +++ b/.gitignore @@ -0,0 +1,144 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +.idea/ + +# www +www/fonts/ diff --git a/README.md b/README.md index e1902c3..a2b126c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ ## Specifications

- Bitroot Typeface Preview + Bitroot Typeface Preview

The characters are packed into a **tiny 5×10-pixel area**, **baseline 7 pixels down from the top**! **Capital letters** use up the full **7-pixel height**, meanwhile regular **lowercases** occupy a **5-pixel x-height** measured from the baseline upward. diff --git a/bitroot.ttf b/bitroot.ttf deleted file mode 100644 index bf5bc4b0b7d40a19c6ace21b7ba8e6b459d2ab47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35065 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 aC=e(RC=e(RC=e(RC=e(RC=j^#5%@pa?jb4w diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c1b2317 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +pixel-font-builder==0.0.36 +pixel-font-knife==0.0.13 diff --git a/preview.png b/src/preview.png similarity index 100% rename from preview.png rename to src/preview.png diff --git a/tools/__init__.py b/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tools/build.py b/tools/build.py new file mode 100644 index 0000000..9e0afbe --- /dev/null +++ b/tools/build.py @@ -0,0 +1,206 @@ +import shutil +import zipfile +from datetime import datetime +from pathlib import Path + +import png +from pixel_font_builder import Glyph, FontBuilder, WeightName, SerifStyle, SlantStyle, WidthStyle, opentype +from pixel_font_knife.mono_bitmap import MonoBitmap + +from tools import path_define + + +def _load_src_png(file_path: Path) -> MonoBitmap: + """ + The source image uses white as pixel, + so we need to customize the loading to convert white to 1 and others to 0 + :param file_path: '.png' file path + :return: MonoBitmap + """ + width, height, pixels, _ = png.Reader(filename=file_path).read() + bitmap = MonoBitmap() + bitmap.width = width + bitmap.height = height + for pixels_row in pixels: + bitmap_row = [] + for i in range(0, width * 4, 4): + red = pixels_row[i] + green = pixels_row[i + 1] + blue = pixels_row[i + 2] + alpha = pixels_row[i + 3] + bitmap_row.append(1 if (red, green, blue, alpha) == (255, 255, 255, 255) else 0) + bitmap.append(bitmap_row) + return bitmap + + +def main(): + # ------------- + # source glyphs + # ------------- + + src_bitmap = _load_src_png(path_define.src_dir.joinpath('font-sheet.png')) + src_alphabet = [ + 'ABCDEFGHIJKLMNOPQR', + 'STUVWXYZ', + 'abcdefghijklmnopqr', + 'stuvwxyz', + '0123456789', + '$₵€£¥¤+-*/÷=%"\'#@&', + '_(),.;:¿?¡!\\{}<>[]', + '§¶µ´^~©®™', + ] + + # ------------------ + # Crop Mono bitmaps + # ------------------ + + bitmap_mapping = {} # code_point -> bitmap + for row, line in enumerate(src_alphabet): + for col, c in enumerate(line): + code_point = ord(c) + bitmap = src_bitmap.crop(7 * col + 2, 12 * row + 2, 5, 10) + bitmap_mapping[code_point] = bitmap + bitmap_mapping[-1] = src_bitmap.crop(7 * 8 + 2, 12 * 0 + 2, 5, 10) # notdef + bitmap_mapping[32] = src_bitmap.crop(7 * 8 + 2, 12 * 1 + 2, 5, 10) # space + + # ----------------------------------------------------- + # Create glyph mapping, this is what the font file need + # Keep glyphs array is sorted as Unicode + # ------------------------------------------------------ + + character_mapping = {} # code_point -> glyph_name + glyphs = [] + for code_point, bitmap in sorted(bitmap_mapping.items()): + if code_point == -1: + glyph_name = '.notdef' + c = '.notdef' + else: + glyph_name = f'u{code_point:04X}' + c = chr(code_point) + character_mapping[code_point] = glyph_name + + glyphs.append(Glyph( + name=glyph_name, + horizontal_offset=(0, -3), + advance_width=6, # Right 1px as char-gap + vertical_offset=(-3, 1), + advance_height=11, # Top 1px as line-gap + bitmap=bitmap.data, + )) + + # Print and check if the bitmap is correct + print('--------------------\n') + print(f'glyph: {glyph_name}, char: {c}\n') + print(bitmap.draw(end='*')) + + # ------------ + # Fill in font + # ------------ + + builder = FontBuilder() + builder.font_metric.font_size = 11 + builder.font_metric.horizontal_layout.ascent = 8 # Top 1px as line-gap + builder.font_metric.horizontal_layout.descent = -3 + builder.font_metric.vertical_layout.ascent = 3 + builder.font_metric.vertical_layout.descent = -3 + builder.font_metric.x_height = 5 + builder.font_metric.cap_height = 7 + builder.font_metric.underline_position = -3 + builder.font_metric.underline_thickness = 1 + builder.font_metric.strikeout_position = 3 + builder.font_metric.strikeout_thickness = 1 + + builder.meta_info.version = '0.0.0' # TODO <-- modify this each release + builder.meta_info.created_time = datetime.fromisoformat('2025-06-12T00:00:00Z') # TODO <-- modify this each release + builder.meta_info.modified_time = builder.meta_info.created_time + builder.meta_info.family_name = 'Bitroot' + builder.meta_info.weight_name = WeightName.REGULAR + builder.meta_info.serif_style = SerifStyle.SERIF + builder.meta_info.slant_style = SlantStyle.NORMAL + builder.meta_info.width_style = WidthStyle.MONOSPACED + builder.meta_info.manufacturer = 'Rio' + builder.meta_info.designer = 'Rio' + builder.meta_info.description = 'Sweet fonts to leave your worries behind you' + builder.meta_info.copyright_info = 'Copyright (c) 2025, Rio (engineer@disroot.org)' + builder.meta_info.license_info = 'SIL Open Font License 1.1' + builder.meta_info.vendor_url = 'https://github.com/serialexperimentsrio/bitroot' + builder.meta_info.designer_url = 'https://github.com/serialexperimentsrio' + builder.meta_info.license_url = 'https://github.com/serialexperimentsrio/bitroot/blob/main/LICENSE.txt' + builder.meta_info.sample_text = 'Jackfruit groves with zinc-fed topsoil maximize bounty' + + builder.character_mapping.update(character_mapping) + builder.glyphs.extend(glyphs) + + # ------------------ + # Clean 'build' dir + # ------------------ + + if path_define.build_dir.exists(): + shutil.rmtree(path_define.build_dir) + path_define.outputs_dir.mkdir(parents=True) + path_define.releases_dir.mkdir(parents=True) + + # ------------------ + # Build normal fonts + # ------------------ + + builder.save_otf(path_define.outputs_dir.joinpath('Bitroot.otf')) + builder.save_otf(path_define.outputs_dir.joinpath('Bitroot.otf.woff'), flavor=opentype.Flavor.WOFF) + builder.save_otf(path_define.outputs_dir.joinpath('Bitroot.otf.woff2'), flavor=opentype.Flavor.WOFF2) + builder.save_ttf(path_define.outputs_dir.joinpath('Bitroot.ttf')) + builder.save_ttf(path_define.outputs_dir.joinpath('Bitroot.ttf.woff'), flavor=opentype.Flavor.WOFF) + builder.save_ttf(path_define.outputs_dir.joinpath('Bitroot.ttf.woff2'), flavor=opentype.Flavor.WOFF2) + builder.save_bdf(path_define.outputs_dir.joinpath('Bitroot.bdf')) + builder.save_pcf(path_define.outputs_dir.joinpath('Bitroot.pcf')) + + # ---------------------- + # Build square dot fonts + # ---------------------- + + builder.meta_info.family_name = 'Bitroot SquareDot' + builder.opentype_config.outlines_painter = opentype.SquareDotOutlinesPainter() + builder.save_otf(path_define.outputs_dir.joinpath('Bitroot-SquareDot.otf')) + builder.save_otf(path_define.outputs_dir.joinpath('Bitroot-SquareDot.otf.woff'), flavor=opentype.Flavor.WOFF) + builder.save_otf(path_define.outputs_dir.joinpath('Bitroot-SquareDot.otf.woff2'), flavor=opentype.Flavor.WOFF2) + builder.save_ttf(path_define.outputs_dir.joinpath('Bitroot-SquareDot.ttf')) + builder.save_ttf(path_define.outputs_dir.joinpath('Bitroot-SquareDot.ttf.woff'), flavor=opentype.Flavor.WOFF) + builder.save_ttf(path_define.outputs_dir.joinpath('Bitroot-SquareDot.ttf.woff2'), flavor=opentype.Flavor.WOFF2) + + # ---------------------- + # Build circle dot fonts + # ---------------------- + + builder.meta_info.family_name = 'Bitroot CircleDot' + builder.opentype_config.outlines_painter = opentype.CircleDotOutlinesPainter() + builder.save_otf(path_define.outputs_dir.joinpath('Bitroot-CircleDot.otf')) + builder.save_otf(path_define.outputs_dir.joinpath('Bitroot-CircleDot.otf.woff'), flavor=opentype.Flavor.WOFF) + builder.save_otf(path_define.outputs_dir.joinpath('Bitroot-CircleDot.otf.woff2'), flavor=opentype.Flavor.WOFF2) + builder.save_ttf(path_define.outputs_dir.joinpath('Bitroot-CircleDot.ttf')) + builder.save_ttf(path_define.outputs_dir.joinpath('Bitroot-CircleDot.ttf.woff'), flavor=opentype.Flavor.WOFF) + builder.save_ttf(path_define.outputs_dir.joinpath('Bitroot-CircleDot.ttf.woff2'), flavor=opentype.Flavor.WOFF2) + + # ------------------- + # Pack release '.zip' + # ------------------- + + with zipfile.ZipFile(path_define.releases_dir.joinpath(f'bitroot-v{builder.meta_info.version}.zip'), 'w') as file: + file.write(path_define.project_root_dir.joinpath('LICENSE.txt'), 'LICENSE.txt') + for font_file_path in path_define.outputs_dir.iterdir(): + if font_file_path.suffix in ('.otf', '.ttf', '.woff', '.woff2', '.bdf', '.pcf'): + file.write(font_file_path, font_file_path.name) + + # ------------------------------------- + # Copy '.otf.woff2' to 'www/fonts' dir + # ------------------------------------- + + if path_define.www_fonts_dir.exists(): + shutil.rmtree(path_define.www_fonts_dir) + path_define.www_fonts_dir.mkdir(parents=True) + + for font_file_path in path_define.outputs_dir.iterdir(): + if font_file_path.name.endswith('.otf.woff2'): + shutil.copyfile(font_file_path, path_define.www_fonts_dir.joinpath(font_file_path.name)) + + +if __name__ == '__main__': + main() diff --git a/tools/path_define.py b/tools/path_define.py new file mode 100644 index 0000000..a6773a4 --- /dev/null +++ b/tools/path_define.py @@ -0,0 +1,12 @@ +from pathlib import Path + +project_root_dir = Path(__file__).parent.joinpath('..').resolve() + +src_dir = project_root_dir.joinpath('src') + +build_dir = project_root_dir.joinpath('build') +outputs_dir = build_dir.joinpath('outputs') +releases_dir = build_dir.joinpath('releases') + +www_dir = project_root_dir.joinpath('www') +www_fonts_dir = www_dir.joinpath('fonts') diff --git a/www/css/index.css b/www/css/index.css new file mode 100644 index 0000000..e7b158e --- /dev/null +++ b/www/css/index.css @@ -0,0 +1,65 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +@font-face { + font-family: Bitroot; + src: url("../fonts/Bitroot.otf.woff2"); +} + +@font-face { + font-family: Bitroot-SquareDot; + src: url("../fonts/Bitroot-SquareDot.otf.woff2"); +} + +@font-face { + font-family: Bitroot-CircleDot; + src: url("../fonts/Bitroot-CircleDot.otf.woff2"); +} + +body { + font-family: sans-serif; +} + +.header { + .title { + margin-top: 16px; + margin-bottom: 16px; + text-align: center; + font-family: Bitroot, sans-serif; + font-size: 66px; + font-weight: normal; + } +} + +.main { + padding: 16px; + + .options { + margin-bottom: 16px; + text-align: center; + + .option { + margin-left: 12px; + margin-right: 12px; + font-size: 16px; + font-weight: bold; + } + } + + .input-box { + width: 100%; + height: 400px; + padding: 16px; + resize: vertical; + font-family: Bitroot, sans-serif; + font-size: 44px; + } +} + +.footer { + text-align: center; + font-size: 16px; +} diff --git a/www/index.html b/www/index.html new file mode 100644 index 0000000..f51cb13 --- /dev/null +++ b/www/index.html @@ -0,0 +1,56 @@ + + + + + + Bitroot + + + + +
+

Bitroot

+
+ +
+
+ + + +
+ + +
+ + + + + + + diff --git a/www/js/index.js b/www/js/index.js new file mode 100644 index 0000000..a09abf7 --- /dev/null +++ b/www/js/index.js @@ -0,0 +1,13 @@ + +window.onFontStyleChange = fontStyle => { + let fontFamily + if (fontStyle === 'SquareDot') { + fontFamily = 'Bitroot-SquareDot, sans-serif' + } else if (fontStyle === 'CircleDot') { + fontFamily = 'Bitroot-CircleDot, sans-serif' + } else { + fontFamily = 'Bitroot, sans-serif' + } + document.getElementById('title').style.fontFamily = fontFamily + document.getElementById('input-box').style.fontFamily = fontFamily +}