Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
MuTsunTsai committed Jul 26, 2022
0 parents commit 21e456e
Show file tree
Hide file tree
Showing 14 changed files with 826 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"cSpell.words": [
"Pyodide"
]
}
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2022-PRESENT Mu-Tsun Tsai

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
71 changes: 71 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# FontFreeze

<p align="center">
<a href="http://mutsuntsai.github.io/fontfreeze"><img width="400" src="https://github.com/MuTsunTsai/fontfreeze/raw/main/docs/logo.png"></a>
</p>

> Freeze variations and features in font.
## Introduction

Modern OpenType fonts support variations and features that allow customizable fonts.
The problem is that not all environments support these mechanisms.
IDEs such as Visual Studio only support choosing font family and font size,
without any options to select variants or toggle features.
FontFreeze is a tool that allows you to create a customized instance of a given font,
so that you may use exactly the font you want in those environments.

## How to use it

Simply visit https://mutsuntsai.github.io/fontfreeze to launch the app, no installation required!

As you open a .ttf file, it will show you the font info and the available options.
You can then select a particular variant (for variable fonts) by selecting one of the predefined instances,
or customize each variable axis.
You can also select features you want to activate (or deactivate) from the feature list:

- For the meaning of each feature, look up the user manual of your font.
In most cases, the feature you are looking for will be among `cv01`-`cv99`, `ss01`-`ss20`, `zero`, `onum`, etc.
- Most coding fonts have their coding ligatures defined in the `calt` feature.
If you want to completely disable ligatures,
deactivating `calt` will usually do the trick.

leaving a feature blank means keeping its default behavior
(which may or may not be activated depending on the environment).
Finally, click `Generate font!` to generate your font.
It's that simple!

## How it works

FontFreeze uses [fonttools](https://github.com/fonttools/fonttools),
a Python library for manipulating fonts.
In then utilizes [Pyodide](https://pyodide.org/)
to run Python code directly in your browser through WebAssembly,
so it's purely front-end and nothing is stored in the back-end.
The UI part is built with [petite-vue](https://github.com/vuejs/petite-vue) and [Bootstrap](https://getbootstrap.com/).

The way FontFreeze deactivates a feature is by simply removing it,
and it activates a feature by moving everything in it into `calt`,
which is usually activated by default in most environments.
If this doesn't work for a particular environment,
you may also try changing the "Target feature for activation" setting to `rvrn`
(which is more forced than `calt` by the OpenType specification;
note that in this case,
you might also need to activate `calt` as well for some other features to function).

## Acknowledgment

FontFreeze is especially inspired by the project
[vfit](https://github.com/jonpalmisc/vfit),
and I used many parts of the source code from it.
Other projects that inspired FontFreeze include:

- [OpenType Feature Freezer](https://github.com/twardoch/fonttools-opentype-feature-freezer),
for inspiring the name (I used a very different approach to freeze the features though).
- [FontDrop!](https://fontdrop.info/), for inspiring the user interface.
- [Coding Fonts](https://github.com/CSS-Tricks/coding-fonts)
(the original site no longer works,
but [here](https://coding-fonts.netlify.app/) is a clone of it),
for inspiring the default preview text.

The "FontFreeze" banner is generated using [Text Generator](https://www.textfx.co/).
Empty file added docs/.nojekyll
Empty file.
Binary file added docs/favicon.ico
Binary file not shown.
166 changes: 166 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>FontFreeze</title>
<link rel="icon" href="./favicon.ico" type="image/x-icon">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, width=device-width, user-scalable=no">
<meta name="description" content="Freeze variations and features in font.">
<base target="_blank">

<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-4GYC00FPRR"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag('js', new Date());
gtag('config', 'G-4GYC00FPRR');
</script>

<!-- SEO -->
<meta property="og:url" content="https://mutsuntsai.github.io/fontfreeze/">
<meta property="og:type" content="website">
<meta property="og:title" content="FontFreeze">
<meta property="og:image" content="https://mutsuntsai.github.io/fontfreeze/preview.png">
<meta property="og:image:width" content="764">
<meta property="og:image:height" content="511">
<meta property="og:description" content="Freeze variations and features in font.">

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
<script src="https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js"></script>
<script src="https://unpkg.com/[email protected]/dist/petite-vue.iife.js"></script>
<script src="main.js"></script>
</head>

<body>
<div class="container py-5 px-sm-2 px-md-3 px-lg-5">
<div class="card bg-light">
<div class="card-body" v-scope v-cloak>
<div class="text-center my-3">
<img src="logo.png" style="max-width:100%;">
<div class="my-3">
<a class="btn btn-sm btn-secondary me-3" href="https://github.com/mutsuntsai/fontfreeze">GitHub repo</a>
©2022 <a href="https://github.com/mutsuntsai">Mu-Tsun Tsai</a>
</div>
<div class="dropzone mt-3">
<div v-if="!store.font">Drop .ttf file here or click here!</div>
<div v-else>{{store.font.fileName}} ({{store.font.fileSize}})</div>
<input type="file" accept="font/ttf" onchange="openFile(this)" class="mb-3">
</div>
</div>
<div v-if="store.font">
<h5>Font info</h5>
<div>
Font family:&emsp;<span class="pre text-primary">{{store.font.family}}</span>&emsp;{{store.font.version}}
</div>
<div v-if="store.font.description">
Description:&emsp;{{store.font.description}}
</div>
<div v-if="store.font.designer">
Designer:&emsp;<a :href="store.font.designerURL"
v-if="store.font.designerURL">{{store.font.designer}}</a><span v-else>{{store.font.designer}}</span>
</div>
<div v-if="store.font.manufacturer">
Manufacturer:&emsp;<a :href="store.font.vendorURL"
v-if="store.font.vendorURL">{{store.font.manufacturer}}</a><span
v-else>{{store.font.manufacturer}}</span>
</div>
<div v-if="store.font.copyright">
Copyright:&emsp;{{store.font.copyright}}
</div>

<div v-if="store.font.fvar">
<h5>Variations</h5>
<div class="d-flex mb-3">
<label class="col-form-label pe-3">Predefined instances:</label>
<div class="flex-grow-1">
<select @change="setInstance(store.font.fvar.instances[$el.value])" class="form-control">
<option hidden></option>
<option v-for="(i, j) in store.font.fvar.instances" :key="i.name+j" :value="j">
{{i.name}}</button>
</select>
</div>
</div>
<div v-for="a in store.font.fvar.axes" class="mb-1" :key="a">
<input type="range" class="form-range me-4" style="width:10rem;" v-model="store.variations[a.tag]"
:min="a.min" :max="a.max" :step="getStep(a)" @input="clear">
<input type="number" class="form-control form-control-sm d-inline-block me-4" style="width:5rem;"
v-model="store.variations[a.tag]" :min="a.min" :max="a.max" :step="getStep(a)" @input="clear">
<label>{{getAxisName(a)}}</label>
</div>
</div>

<div v-if="store.font.gsub&&store.font.gsub.length">
<h5>Features</h5>
<div class="d-flex flex-wrap">
<div v-for="f in store.font.gsub" style="flex-basis: 5.5rem;" :key="f">
<div class="form-check">
<input type="checkbox" class="form-check-input" :id="'chk'+f"
:indeterminate.prop="store.features[f]===undefined" v-model="store.features[f]"
@change="checkboxChange(f)">
<label class="form-check-label" :for="'chk'+f">{{f}}</label>
</div>
</div>
</div>
</div>

<div class="row align-items-baseline">
<div class="col-4">
<h5>Preview</h5>
</div>
<div class="col-8 text-end">
<span class="me-3">{{store.previewSize}}pt</span>
<input type="range" class="form-range" style="width:10rem;" v-model="store.previewSize" min="9"
max="48" @change="recalcTextAreaHeight">
</div>
</div>
<div :style="getTextAreaStyle()">
<textarea class="pre form-control" v-model="store.sample" @change="recalcTextAreaHeight"></textarea>
</div>

<h5>Output options</h5>
<div class="row">
<div class="col-12 col-md-6 mt-2">
<label>Font family</label>
<input class="form-control" v-model="store.options.family">
</div>
<div class="col-12 col-md-6 mt-2">
<label>Font subfamily</label>
<input class="form-control" v-model="store.options.subfamily">
</div>
</div>
<div class="row">
<div class="col-12 col-md-6 mt-2">
<label>Target feature for activation</label>
<input class="form-control" v-model="store.options.target">
</div>
<div class="col-12 col-md-6 mt-2">
<div class="form-check mt-4">
<input type="checkbox" class="form-check-input" id="chkContour"
v-model="store.options.fixContour">
<label class="form-check-label" for="chkContour">Fix contour overlap issues on macOS.</label>
</div>
</div>
</div>

<div class="mt-5 row">
<div class="col">
<button class="btn btn-lg" type="button" onclick="generate()" :disabled="store.running"
:class="store.message?'btn-success':'btn-primary'">
{{store.message||"Generate font!"}}
<span class="loading ms-2" v-if="store.running"></span>
</button>
</div>
<div class="col text-end" v-if="store.url">
<a class="btn btn-lg btn-success" :href="store.url" :download="store.download">Download font</a>
</div>
</div>
</div>
</div>
</div>
</div>
</body>

</html>
Binary file added docs/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 21e456e

Please sign in to comment.