diff options
Diffstat (limited to 'docs')
-rw-r--r-- | docs/_config.yml | 10 | ||||
-rw-r--r-- | docs/_data/fontinfo.json (renamed from docs/info.json) | 9 | ||||
-rw-r--r-- | docs/_includes/autoreload-in-debug.html | 46 | ||||
-rw-r--r-- | docs/_layouts/default.html | 88 | ||||
-rwxr-xr-x | docs/_scripts/optimize-resources.sh (renamed from docs/optimize-resources.sh) | 2 | ||||
-rwxr-xr-x | docs/_scripts/serve.sh | 9 | ||||
-rw-r--r-- | docs/dynmetrics/index.css | 262 | ||||
-rw-r--r-- | docs/dynmetrics/index.html | 522 | ||||
-rw-r--r-- | docs/glyphs/index.html | 111 | ||||
-rw-r--r-- | docs/index.html | 686 | ||||
-rw-r--r-- | docs/index.js | 138 | ||||
-rw-r--r-- | docs/res/base.css (renamed from docs/index.css) | 224 | ||||
-rw-r--r-- | docs/res/base.js | 74 | ||||
-rw-r--r-- | docs/res/bindings.js (renamed from docs/samples/bindings.js) | 40 | ||||
-rw-r--r-- | docs/res/favicon.png (renamed from docs/favicon.png) | bin | 700 -> 700 bytes | |||
-rw-r--r-- | docs/res/graphplot.js | 239 | ||||
-rw-r--r-- | docs/samples/index.css | 243 | ||||
-rw-r--r-- | docs/samples/index.html | 524 | ||||
-rwxr-xr-x | docs/serve.sh | 24 |
19 files changed, 2175 insertions, 1076 deletions
diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 000000000..f00875d90 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,10 @@ +port: 3000 +lsi: false +permalink: /:title +markdown: kramdown +# Since GH pages override this to "true", we test this value to see if we are running locally +safe: false +kramdown: + input: GFM + auto_ids: true + hard_wrap: false diff --git a/docs/info.json b/docs/_data/fontinfo.json index 97fde5b79..6d4e8c038 100644 --- a/docs/info.json +++ b/docs/_data/fontinfo.json @@ -1,5 +1,5 @@ -{ - "Inter UI Regular:2018:86daccf": { +[ + { "head": { "checkSumAdjustment": 3690365233, "created": 3563720514, @@ -117,6 +117,7 @@ "minMemType42": 0, "underlinePosition": -422, "underlineThickness": 170 - } + }, + "version": "2.5" } -}
\ No newline at end of file +] diff --git a/docs/_includes/autoreload-in-debug.html b/docs/_includes/autoreload-in-debug.html new file mode 100644 index 000000000..13840defa --- /dev/null +++ b/docs/_includes/autoreload-in-debug.html @@ -0,0 +1,46 @@ +{% if site.safe == false %} +<!-- During authoring, this automatically reloads the post as its changing --> +<script type="text/javascript"> +(function() { +var qs = document.location.search; +var current_etag = qs.match(/etag=("?[a-zA-Z0-9_-]+)/); +if (current_etag !== null) { current_etag = current_etag[1]; } +var scrolly = qs.match(/scrolly=([0-9]+)/); +if (scrolly) { + scrolly = parseInt(scrolly[1]); + if (scrolly > 0) { + window.scrollTo(window.scrollX, scrolly); + setTimeout(function () { + window.scrollTo(window.scrollX, scrolly); + }, 10); + } +} + +function check() { + var r = new XMLHttpRequest(); + var url = document.location.href + ((qs && qs !== '') ? '&' : '?') + 'r=' + Math.random(); + r.open('GET', url, true); + r.onreadystatechange = function() { + if (r.readyState == 4){ + var found_etag = r.getResponseHeader('Etag'); + if (found_etag) { + found_etag = found_etag.replace(/^"|"$/g); + } + //console.log('current_etag:', current_etag, 'found_etag:', found_etag); + if (current_etag === null) { + current_etag = found_etag; + } else if (found_etag !== current_etag) { + document.location.search = + '?etag=' + encodeURIComponent(found_etag) + + '&scrolly=' + window.scrollY; + return; + } + setTimeout(check, 500); + } + }; + r.send(null); +} +check(); +})(); +</script> +{% endif %}
\ No newline at end of file diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html new file mode 100644 index 000000000..d694ce3bd --- /dev/null +++ b/docs/_layouts/default.html @@ -0,0 +1,88 @@ +{% +assign build_version = site.time | date: "%Y%m%d%H%M%S" %}{% +assign description = "Inter UI is a new typeface optimized for computer user interfaces" %}{% + +capture url_root + %}{% if site.safe == false %}/{% else %}/inter/{% endif +%}{% +endcapture %}{% + +capture release_version + %}{{ site.data.fontinfo[0].version }}{% +endcapture %}{% + +capture download_url + %}https://github.com/rsms/inter/releases/download/v{{ release_version }}/Inter-UI-{{ release_version }}.zip{% +endcapture %}{% + +for file in site.static_files %}{% + assign _path = file.path | remove_first: "/inter" %}{% + if _path == "/res/base.css" %}{% + assign base_css_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% + elsif _path == "/res/base.js" %}{% + assign base_js_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% + endif %}{% +endfor + +%}<!DOCTYPE HTML> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>{% if page.title %}{{ page.title }} — Inter UI{% else %}Inter UI font family{% endif %}</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <link rel="stylesheet" href="{{url_root}}inter-ui.css?v={{ release_version }}"> + <link rel="stylesheet" href="{{url_root}}res/base.css?v={{ base_css_v }}"> + <link rel="icon" type="image/png" href="{{url_root}}res/favicon.png"> + <meta name="format-detection" content="telephone=no"> + <meta property="twitter:card" content="summary"> + <meta property="twitter:site" content="@rsms"> + <meta property="twitter:creator" content="@rsms"> + <meta property="description" content="{{description}}"> + <meta property="og:description" content="{{description}}"> + <meta property="twitter:description" content="{{description}}"> + {% if page.title %} + <meta property="og:title" content="{{ page.title }}"> + <meta property="twitter:title" content="{{ page.title }}"> + {% endif %} + {% if page.og_image_url %} + <meta property="og:image" content="{{ page.og_image_url }}"> + <meta property="twitter:image" content="{{ page.og_image_url }}"> + {% else %} + <meta property="og:image" content="https://rsms.me/inter/res/poster.png"> + <meta property="twitter:image" content="https://rsms.me/inter/res/poster.png"> + {% endif %} + <meta property="og:url" content="https://rsms.me/inter/{{ page.url | remove_first:'index.html' }}"> + <meta property="fb:app_id" content="38027689216"> + <meta property="og:site_name" content="rsms.me/inter"> + <meta property="og:type" content="product"> + <meta property="og:locale" content="en_US" /> + </head> + <body> + <script src="{{url_root}}res/base.js?v={{ base_js_v }}"></script> + + <div class="row menu"> + <ul class="menu"> + <li class="home"><a href="{{url_root}}">Inter UI</a></li> + <li><a class="download-link" href="{{ download_url }}" + >Download</a></li> + <li><a href="{{url_root}}samples/" + {% if page.url contains "/samples/" %}class="active"{% endif %} + >Samples</a></li> + <li><a href="{{url_root}}lab/" + {% if page.url contains "/lab/" %}class="active"{% endif %} + >Playground</a></li> + <li><a href="https://github.com/rsms/inter/" + >Source</a></li> + </ul> + </div> + + {{ content }} + + {% if site.safe == true %} + <script async src="https://www.googletagmanager.com/gtag/js?id=UA-105091131-2"></script> + {% endif %} + {% include autoreload-in-debug.html %} + </body> +</html> diff --git a/docs/optimize-resources.sh b/docs/_scripts/optimize-resources.sh index b539d0775..72d45b9f1 100755 --- a/docs/optimize-resources.sh +++ b/docs/_scripts/optimize-resources.sh @@ -1,6 +1,6 @@ #!/bin/sh set -e -cd "$(dirname "$0")" +cd "$(dirname "$0")/.." pushd res >/dev/null diff --git a/docs/_scripts/serve.sh b/docs/_scripts/serve.sh new file mode 100755 index 000000000..a319d8e22 --- /dev/null +++ b/docs/_scripts/serve.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e +cd "$(dirname "$0")/.." + +if [ ! -s lab/fonts ]; then + ln -s ../../build/dist lab/fonts +fi + +jekyll serve --limit_posts 20 --watch --host 127.0.0.1 --port 3002 --open-url diff --git a/docs/dynmetrics/index.css b/docs/dynmetrics/index.css new file mode 100644 index 000000000..c7c98d351 --- /dev/null +++ b/docs/dynmetrics/index.css @@ -0,0 +1,262 @@ +body { + padding-bottom: 0; +} + +const { + display: inline; + font-size: 1.2em; + font-style: italic; + font-family: 'Times New Roman', Times, serif; +} + +sup { + /*background:lightpink;*/ + display: inline-block; + font-size:0.92em; + position: relative; + top:-0.4em; + letter-spacing: 0.001em; + vertical-align: baseline; +} + +.row.first { + padding-bottom:1em; +} + +formula { + display: inline-flex; + align-items: center; + background: white; + border-radius: 5px; + padding: 0 1em; + line-height: 3em; + height: 3em; + overflow: hidden; + margin-right: 1em; + margin-bottom: 1em; +} +.row.white formula { + background: #f5f5f5; +} +formula:last-child { + margin-right: 0; +} +formula.code { + white-space: pre; + font-family: "SFMono-Regular", Menlo, Consolas, Inconsolata, monospace; + font-size:0.96em; +} + formula > * { + margin: 0 0.2em 0 0.2em; + } + formula > const { + margin-bottom: 0.11em; + } + formula > sup { + margin-left: 0; + } + + +.samples { + display: flex; + flex-wrap: wrap; + overflow: auto; + overflow-wrap: break-word; + word-break: break-word; +} + .samples .sample { + /*background: lightpink;*/ + color: #111; + flex: 0 1 auto; + outline: none; + margin-right: 50px; + margin-bottom: 50px; + } + .samples .sample .di { + display: block; + background-color: #ccc; + height: 1px; + width: 100%; + margin-bottom: 8px; + } + .samples .sample .di > span { + display: block; + background-color: #333; + height: 100%; + } + .samples .sample .di.match > span { + background-color: #0d3; + } + .samples .sample .di.unavailable { + background-color: #eee; + } + .samples .sample .di.unavailable > span { + visibility: hidden; + } + .samples .sample .info { + display: block; + font-size: 11px !important; + line-height: 11px; + margin-bottom: 9px; + color: #bbb; + } + + +.font-style-regular { font-weight:400 !important; font-style:normal !important; } +.font-style-italic { font-weight:400 !important; font-style:italic !important; } +.font-style-medium { font-weight:500 !important; font-style:normal !important; } +.font-style-medium-italic { font-weight:500 !important; font-style:italic !important; } +.font-style-bold { font-weight:700 !important; font-style:normal !important; } +.font-style-bold-italic { font-weight:700 !important; font-style:italic !important; } +.font-style-black { font-weight:900 !important; font-style:normal !important; } +.font-style-black-italic { font-weight:900 !important; font-style:italic !important; } + +.row.with-sidebar { + padding: 0; +} + .row.with-sidebar > *:first-child { + flex: 1 1 auto; + padding: 50px 0 0 50px; /* note: samples have 50px right margin */ + } + .row.with-sidebar > .sidebar { + flex: 0 0 auto; + } + +div.controls { + box-sizing: border-box; + width: 250px; + max-width: 250px; + flex: 0 0 auto; + padding: 10px 0; + border-left: 4px solid #f4f4f4; + display: flex; + flex-direction: column; + overflow: hidden; +} +div.controls hr { + border: none; + height: 2px; + background: #f4f4f4; + margin-top: 10px; + margin-bottom: 10px; +} +div.controls hr.without-bottom-margin { margin-bottom: 0; } +div.controls hr.without-top-margin { margin-top: 0; } +div.controls hr.without-margins { margin: 0; } +div.controls .control { + display: flex; + justify-content: space-between; + align-items: center; + overflow: hidden; + height: 30px; + margin: 0 16px; +} +div.controls > h3 { + margin: 0 16px; +} +div.controls > textarea { + border: none; + padding:16px; + height: 400px; + font-family: "SFMono-Regular", Menlo, Consolas, Inconsolata, monospace; + outline: none; +} +div.controls .control > * { + /*max-width: 50%;*/ + flex: 1 1 auto; + margin:0; + margin-right: 16px; + box-sizing: border-box; +} +div.controls .control > :last-child { + margin-right: 0; +} +div.controls .control > select { + min-width: 6em; + align-items: center; + justify-content: center; +} +div.controls .control > input, +div.controls .control > select { + width: 0; + outline: none; +} +div.controls .control > input[type="number"], +div.controls .control > input[type="text"] { + background: none; + border: none; + padding: 4px 0; + font-size: 13px; +} +div.controls .control > input[type="number"] { + max-width: 60px; + -moz-font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; + -ms-font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; + -o-font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; + -webkit-font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; + font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; +} +div.controls .control > input[type=number]::-webkit-inner-spin-button, +div.controls .control > input[type=number]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; +} +div.controls .control > input[type="number"][readonly] { + max-width: 40px; +} +div.controls .control > input.wide[type="number"] { + max-width: 100%; +} +div.controls .control > input[type="range"] { + /*max-width: 80%;*/ + flex: 1 1 auto; + display: block; +} +div.controls .control > img.icon, +div.controls .control > label { + font-family: georgia, serif; + font-style: italic; + line-height: 16px; + color: black; + width: 16px; + height: 16px; + flex: 0 0 auto; + margin-right: 16px; + opacity: 0.6; +} +div.controls canvas { + height: 200px; +} + +.row.small-window { + margin-top:0; + padding-top:0; +} + +@media only screen and (min-width: 541px) { + .small-window { + display: none; + } +} + +@media only screen and (max-width: 540px) { + + .row.with-sidebar { + overflow: auto; + } + + div.controls { + display: none; + } + div.controls .graphplot, + div.controls hr.without-top-margin, + div.controls h3, + div.controls #ideal-values + { + display: none; + } + + .row.with-sidebar { + flex-direction: column; + } +} diff --git a/docs/dynmetrics/index.html b/docs/dynmetrics/index.html new file mode 100644 index 000000000..21bd95d82 --- /dev/null +++ b/docs/dynmetrics/index.html @@ -0,0 +1,522 @@ +--- +layout: default +title: Dynamic Metrics +--- +{% + +capture url_root + %}{% if site.safe == false %}/{% else %}/inter/{% endif +%}{% +endcapture %}{% + +for file in site.static_files %}{% + assign _path = file.path | remove_first: "/inter" %}{% + if _path == "/dynmetrics/index.css" %}{% + assign index_css_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% + elsif _path == "/res/bindings.js" %}{% + assign bindings_js_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% + elsif _path == "/res/graphplot.js" %}{% + assign graphplot_js_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% + endif %}{% +endfor + +%} +<link rel="stylesheet" href="index.css?v={{ index_css_v }}"> +<script src="{{url_root}}res/bindings.js?v={{ bindings_js_v }}"></script> +<script src="{{url_root}}res/graphplot.js?v={{ graphplot_js_v }}"></script> + +<div class="row first"><div> + <h1>Dynamic Metrics</h1> + <p> + There's of course no absolute right or wrong when it comes to expressing + yourself with typography, but Inter UI Dynamic Metrics provides guidelines + for <em>good</em> typography. + You simply provide the optical font size, and the tracking and leading + (letter spacing and line height) will be calculated using the following + formula: + </p> + <p> + <formula> + tracking = + <const>a</const> + <const>b</const> × + <const>e</const><sup>(<const>c</const> × fontSize)</sup> + </formula> + <formula> + leading = <const>l</const> × fontSize + </formula> + <formula> + <const>e</const> ≈ <num>2.718</num> + </formula> + </p> + <p class="small-window"> + <small>View this on a larger screen to enable interactive control.</small> + </p> +</div></div> + +<!-- <div class="row small-window"><div> + Hello +</div></div> --> + +<div class="white full-width row with-sidebar"> + + <div class="samples"> + <p contenteditable class="sample"> + <span class="di"><span></span></span> + <span class="info" + title="size, tracking, (ideal tracking) — progress bar shows distance from ideal" + >15 0.0 ( 0.0 )</span> + Such a riot of sea and wind strews the whole extent of beach with whatever has been lost or thrown overboard, or torn out of sunken ships. Many a man has made a good week’s work in a single day by what he has found while walking along the Beach when the surf was down. + </p> + </div> + + <div class="sidebar controls"> + <div class="control"> + <label title="Number of ideal matches">ni</label> + <input title="Number of ideal matches" type="number" readonly data-binding="ideal-count"> + <label title="Distance from ideal">di</label> + <input title="Distance from ideal" type="number" class="wide" readonly data-binding="ideal-distance"> + </div> + <div class="control"> + <img title="Style" class="icon" src="../samples/icons/style.svg"> + <select data-binding="style"> + <option value="regular" default>Regular</option> + <option value="italic">Italic</option> + <option value="medium" default>Medium</option> + <option value="medium-italic">Medium Italic</option> + <option value="bold" default>Bold</option> + <option value="bold-italic">Bold Italic</option> + <option value="black" default>Black</option> + <option value="black-italic">Black Italic</option> + </select> + </div> + <div class="control"> + <img title="Base tracking" class="icon" src="../samples/icons/letter-spacing.svg"> + <input type="range" min="-0.05" max="0.06" step="0.001" data-binding="base-tracking"> + <input type="number" min="-0.15" max="1" step="0.001" data-binding="base-tracking"> + </div> + <hr> + <div class="control"> + <label title="Constant a">a</label> + <input type="range" min="-0.05" max="0" step="0.001" data-binding="var-a"> + <input type="number" min="-0.05" max="0" step="0.0001" data-binding="var-a"> + </div> + <div class="control"> + <label title="Constant b">b</label> + <input type="range" min="0" max="1" step="0.01" data-binding="var-b"> + <input type="number" min="0" max="1" step="0.001" data-binding="var-b"> + </div> + <div class="control"> + <label title="Constant c">c</label> + <input type="range" min="-1" max="0" step="0.01" data-binding="var-c"> + <input type="number" min="-1" max="0" step="0.001" data-binding="var-c"> + </div> + <hr> + <div class="control"> + <label title="Constant l controls line height">l</label> + <input type="range" min="1" max="2" step="0.1" data-binding="var-l"> + <input type="number" min="1" max="2" step="0.1" data-binding="var-l"> + </div> + <hr class="without-bottom-margin"> + <canvas class="graphplot">Canvas not Supported</canvas> + <hr class="without-top-margin"> + <h3>Ideal values</h3> + <textarea id="ideal-values"></textarea> + <hr class="without-top-margin"> + </div> + +</div> + + +<script type="text/javascript">(function(){ + +// internal variables that are user-controllable, but are not part of +// Dynamic Metrics +var baseTracking = 0 +var weightClass = 400 + +// Ideal values designed one by one, by hand. +// font size => tracking +var idealValues = {} +var idealValuesList = [] +var idealValuesTextArea = $('textarea#ideal-values') + +function setIdealValues(valueMap) { + idealValues = valueMap + idealValuesList = [] + Object.keys(idealValues).forEach(function(fontSize) { + idealValuesList.push([fontSize, idealValues[fontSize]]) + }) + if (idealValuesTextArea.value == '') { + idealValuesTextArea.value = idealValuesList.map(function(t){ + return t[0] + '\t' + t[1] + }).join('\n') + } +} + +function parseValues(s) { + var values = {} + s = s.replace(/^[\s\r\t\n]+|[\s\r\t\n]+$/g, '') // trim whitespace + s.split(/\s*\r?\n\s*/).map(function(line) { + var t = line.split(/\s+/) + if (t.length == 2) { + t[0] = parseInt(t[0]) + t[1] = parseFloat(t[1]) + values[t[0]] = t[1] + } + }) + return values +} + +setIdealValues({ + // set-2018-02-20 + 6: 0.055, + 7: 0.044, + 8: 0.034, + 9: 0.024, + 10: 0.018, + 11: 0.012, + 12: 0.007, + 13: 0.003, + 14: 0.001, + 15: -0.002, + 16: -0.004, + 17: -0.006, + 18: -0.008, + 20: -0.01, + 24: -0.013, +}) + +// setIdealValues({ +// // set-2018-02-19 +// 6: 0.059, +// 7: 0.043, +// 8: 0.032, +// 9: 0.022, +// 10: 0.014, +// 11: 0.009, +// 12: 0.004, +// 13: 0, +// 14: -0.003, +// 15: -0.005, +// 16: -0.0075, +// 17: -0.0084, +// 18: -0.0095, +// 20: -0.012, +// 24: -0.014, +// }) + +// setIdealValues({ +// // set-2018-02-18 +// 6: 0.06, +// 7: 0.04, +// 8: 0.03, +// 9: 0.02, +// 10: 0.01, +// 11: 0.005, +// 12: 0.002, +// 13: 0.001, +// 14: 0, +// 15: -0.002, +// 16: -0.005, +// 17: -0.007, +// 18: -0.009, +// 20: -0.011, +// 24: -0.011, +// }) + + +// Variables for constants involved in Dynamic Metrics +var a = -0.013 +// -0.0119 +// -0.0101 +// -0.0092 +// -0.012 +// -0.013 + +var b = 0.23 +// 0.455 +// 0.421 +// 0.26 +// 0.23 +// 0.251 + +var c = -0.21 +// -0.29 +// -0.23 +// -0.21 +// -0.222 + +// a = -0.012; b = 0.23; c = -0.21; // di=0.002514 on set-2018-02-18 +// a = -0.013; b = 0.251; c = -0.222 // di=0.001742 on set-2018-02-18 +// a = -0.015; b = 0.283; c = -0.23; // di=0.00221 on set-2018-02-18 +// a = -0.0149; b = 0.298; c = -0.23; // di=0.000484 on set-2018-02-19 +a = -0.016; b = 0.21; c = -0.18; // di=0.000532 on set-2018-02-20 + + +// these have a short di, but stray far away from larger font sizes +// a = -0.0077 +// b = 0.377 + +var l = 1.4 + + +// InterUIDynamicTracking takes the font size in points or pixels and returns +// the compensating tracking in EM. +// +function InterUIDynamicTracking(fontSize, weightClass) { + // if (!weightClass) { -- currently unused + // weightClass = 400 + // } + // + // y = -0.01021241 + 0.3720623 * e ^ (-0.2808687 * x) + // [6-35] 0.05877 .. -0.0101309 (13==0; stops growing around 30-35) + // See https://gist.github.com/rsms/8efdbca5f8145a584ed08a7c3d6e5788 + // + return a + b * Math.pow(Math.E, c * fontSize) + // [6 - 38] 0.05798 .. -0.01099 (midpoint = 12.533) + + // y = 0.025 - (ln(x) * 0.01) + // return 0.025 - Math.log(fontSize) * 0.01 +} + + +function InterUIDynamicLineHeight(fontSize, weightClass) { + return Math.round(fontSize * l) +} + + +var NPOS = Number.MAX_SAFE_INTEGER + +function Sample(fontSize) { + this.rootEl = sampleTemplate.cloneNode(true) + this.infoEl = $('.info', this.rootEl) + this.diEl = $('.di', this.rootEl) + this.diEl.classList.add('unavailable') + this.style = this.rootEl.style + this.maxBoxWidth = 0 + this.fontSize = 0 + this.tracking = 0 + this.lineHeight = 0 + this.idealTracking = NPOS + this.matchesIdeal = false + this.setFontSize(fontSize) + this.render() +} + +Sample.prototype.idealDistance = function(fontSize) { + // returns the distance from the ideal (or NPOS if no "ideal" data available) + if (this.idealTracking == NPOS) { + return NPOS + } + return ( + Math.max(this.tracking, this.idealTracking) - + Math.min(this.tracking, this.idealTracking) + ) +} + +Sample.prototype.setFontSize = function(fontSize) { + this.fontSize = fontSize + this.tracking = baseTracking + InterUIDynamicTracking(fontSize, weightClass) + this.lineHeight = InterUIDynamicLineHeight(fontSize, weightClass) + this.maxBoxWidth = Math.round(fontSize * (this.tracking + 1) * 25) + + var idealTracking = idealValues[this.fontSize] + if (idealTracking === undefined) { + if (this.idealTracking != NPOS) { + this.diEl.classList.add('unavailable') + } + this.idealTracking = NPOS + this.matchesIdeal = false + } else { + if (this.idealTracking == NPOS) { + this.diEl.classList.remove('unavailable') + } + this.idealTracking = idealTracking + // match to a precision of 3 + this.matchesIdeal = this.tracking.toFixed(3) == idealTracking.toFixed(3) + var di = 1 + if (this.matchesIdeal) { + this.diEl.classList.add('match') + } else { + this.diEl.classList.remove('match') + di = 1 - Math.min(1, this.idealDistance() * 50) + } + this.diEl.firstChild.style.width = (di * this.maxBoxWidth) + 'px' + } +} + +Sample.prototype.render = function() { + this.style.fontSize = this.fontSize + 'px' + this.style.letterSpacing = this.tracking + 'em' + this.style.lineHeight = this.lineHeight + 'px' + + var SP = '\u00A0\u00A0\u00A0' + this.infoEl.innerText = ( + this.fontSize + + SP + this.tracking.toFixed(3) + + // SP + this.lineHeight.toFixed(3) + + ( + this.idealTracking != NPOS ? ( + SP + '( ' + this.idealTracking + + (this.matchesIdeal ? ' \u2713' : '') + + ' )' + ) : '' + ) + ) + + this.style.maxWidth = this.maxBoxWidth + 'px' +} + + +var bindings = new Bindings() +var sampleTemplate +var samples = [] // Sample[] +var graph = new GraphPlot($('canvas.graphplot')) +graph.setOrigin(-0.2, 0.8) +graph.setScale(0.049, 5) + +function addChildren(targetNode, children) { + targetNode.style.visibility = 'hidden' + var i = 0; + for (; i < children.length; i++) { + targetNode.appendChild(children[i]) + } + targetNode.style.visibility = null +} + +function initSamples() { + var samplesEl = $('.samples') + sampleTemplate = $('.sample', samplesEl) + samplesEl.removeChild(sampleTemplate) + + // small and medium sizes + var i, fontSize = 6, endFontSize = 16 + for (; fontSize <= endFontSize; fontSize++) { + samples.push(new Sample(fontSize)) + } + + // a few select large samples + samples.push(new Sample(17)) + samples.push(new Sample(18)) + samples.push(new Sample(20)) + samples.push(new Sample(24)) + samples.push(new Sample(30)) + samples.push(new Sample(40)) + + // add to dom in one go + addChildren(samplesEl, samples.map(function(s) { return s.rootEl })) +} + + +function updateSample(sample) { + sample.setFontSize(sample.fontSize) // updates derived values + sample.render() +} + +function updateSamples() { + samples.forEach(updateSample) + updateIdealMatches() + updateGraphPlot() +} + +function updateIdealMatches() { + // ideal-distance + var idealCount = 0 + var distance = 0 + var ndistances = 0 + samples.forEach(function(sample) { + if (sample.matchesIdeal) { + idealCount++ + } + var di = sample.idealDistance() + if (di != NPOS) { + distance += di + ndistances++ + } + }) + + distance = distance / ndistances + + bindings.setValue('ideal-distance', distance.toFixed(6)) + bindings.setValue('ideal-count', idealCount) +} + +function updateGraphPlot() { + graph.clear() + graph.plotLine(idealValuesList, '#0d3') + graph.plotf(function(x) { + return InterUIDynamicTracking(x, weightClass) + }) +} + + +bindings.configure('base-tracking', 0, 'float', function (tracking) { + baseTracking = tracking + updateSamples() +}) + +bindings.configure('var-a', a, 'float', function (v) { + a = v + updateSamples() +}) + +bindings.configure('var-b', b, 'float', function (v) { + b = v + updateSamples() +}) + +bindings.configure('var-c', c, 'float', function (v) { + c = v + updateSamples() +}) + +bindings.configure('var-l', l, 'float', function (v) { + l = v + updateSamples() +}) + +bindings.configure('ideal-count', 0, 'int', function (v) {}) +bindings.configure('ideal-distance', 0, 'float', function (v) {}) + +bindings.configure('style', null, null, function (style) { + var cl = $('.samples').classList + cl.remove('font-style-regular') + cl.remove('font-style-italic') + cl.remove('font-style-medium') + cl.remove('font-style-medium-italic') + cl.remove('font-style-bold') + cl.remove('font-style-bold-italic') + cl.remove('font-style-black') + cl.remove('font-style-black-italic') + cl.add('font-style-' + style) + weightClass = ( + style.indexOf('black') != -1 ? 900 : + style.indexOf('bold') != -1 ? 700 : + style.indexOf('medium') != -1 ? 500 : + 400 + ) + updateSamples() +}) + + +bindings.bindAllInputs('.control input') +bindings.bindAllInputs('.control select') + +// double-click base tracking to reset +$('input[type="range"][data-binding="base-tracking"]').addEventListener( + 'dblclick', + function(ev) { bindings.setValue('base-tracking', 0) } +) + +// allow editing of ideal values +idealValuesTextArea.addEventListener('input', function(ev) { + setIdealValues(parseValues(idealValuesTextArea.value)) + updateSamples() +}) + + +// start +initSamples() +updateSamples() + +})();</script> diff --git a/docs/glyphs/index.html b/docs/glyphs/index.html index aa5faeff2..3a47285bb 100644 --- a/docs/glyphs/index.html +++ b/docs/glyphs/index.html @@ -1,39 +1,27 @@ -<!DOCTYPE HTML> -<html lang="en" prefix="og: http://ogp.me/ns#"> - <head> - <meta charset="utf-8"> - <title>Repertoire – Inter UI font family</title> +--- +layout: default +title: Glyphs +--- +{% - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> +capture url_root + %}{% if site.safe == false %}/{% else %}/inter/{% endif +%}{% +endcapture %}{% - <meta property="og:title" content="Inter UI font family"> - <meta property="twitter:title" content="Inter UI font family"> - <meta property="description" content="Inter UI is a new typeface optimized for computer user interfaces"> - <meta property="og:description" content="Inter UI is a new typeface optimized for computer user interfaces"> - <meta property="twitter:description" content="Inter UI is a new typeface optimized for computer user interfaces"> - <meta property="twitter:card" content="summary"> - <meta property="twitter:site" content="@rsms"> - <meta property="twitter:creator" content="@rsms"> - <meta property="og:image" content="https://rsms.me/inter/res/poster.png"> - <meta property="twitter:image" content="https://rsms.me/inter/res/poster.png"> +for file in site.static_files %}{% + assign _path = file.path | remove_first: "/inter" %}{% + if _path == "/glyphs/glyphs.css" %}{% + assign glyphs_css_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% + elsif _path == "/glyphs/glyphs.js" %}{% + assign glyphs_js_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% + endif %}{% +endfor - <meta property="fb:app_id" content="38027689216"> - <meta property="fb:admins" content="728642302"> - <meta property="og:url" content="https://rsms.me/inter/"> - <meta property="og:site_name" content="rsms.me"> - <meta property="og:type" content="product"> - <meta property="og:locale" content="en_US" /> +%} - <link rel="icon" type="image/png" href="../favicon.png" /> - - <link href="../inter-ui.css" rel="stylesheet"> - <link href="../index.css" rel="stylesheet"> - <link href="glyphs.css" rel="stylesheet"> - </head> - <body> - <script src="../index.js"></script> - <div id="svgs"> +<link rel="stylesheet" href="glyphs.css?v={{ glyphs_css_v }}"> +<div id="svgs"> <svg id="svg-A" xmlns="http://www.w3.org/2000/svg" width="176" height="348"><path d="M146 -76.8 L44.8 -76.8 L44.8 -54.8 L146 -54.8z M33.2 0 L94 -172.4 L96.4 -172.4 L157.2 0 L183.2 0 L108 -204.8 L82.4 -204.8 L7.2 0z" transform="translate(-7.2 281.6)"/></svg> <svg id="svg-AE" xmlns="http://www.w3.org/2000/svg" width="264" height="348"><path d="M142.4 -186 L144.8 -204.8 L127.2 -204.8 L6 0 L35.6 0z M164 -76.8 L60.4 -76.8 L60.4 -55.2 L164 -55.2z M269.2 -22 L168.4 -22 L168.4 0 L269.2 0z M164.8 -204.8 L140.4 -204.8 L148.8 0 L173.2 0z M249.6 -115.2 L162.8 -115.2 L162.8 -93.2 L249.6 -93.2z M260.8 -204.8 L160 -204.8 L160 -182.8 L260.8 -182.8z" transform="translate(-6 281.6)"/></svg> <svg id="svg-AEacute" xmlns="http://www.w3.org/2000/svg" width="264" height="348"><path d="M142.4 -186 L144.8 -204.8 L127.2 -204.8 L6 0 L35.6 0z M164 -76.8 L60.4 -76.8 L60.4 -55.2 L164 -55.2z M269.2 -22 L168.4 -22 L168.4 0 L269.2 0z M164.8 -204.8 L140.4 -204.8 L148.8 0 L173.2 0z M249.6 -115.2 L162.8 -115.2 L162.8 -93.2 L249.6 -93.2z M260.8 -204.8 L160 -204.8 L160 -182.8 L260.8 -182.8z M135.2 -223.2 L152.8 -223.2 L183.6 -264 L159.2 -264z" transform="translate(-6 281.6)"/></svg> @@ -2222,37 +2210,34 @@ <svg id="svg-zrthook" xmlns="http://www.w3.org/2000/svg" width="151" height="348"><path d="M112.8 -16.8 L112.8 19.2 C112.8 45.6 130.4 60 153.2 60 C157.6 60 163.2 59.6 166.8 58.4 L166.8 38 C164.8 38.8 161.2 38.8 159.2 38.8 C146.4 38.8 136.4 35.2 136.4 19.2 L136.4 -16.8z M136.4 -22 L28 -22 L28 0 L136.4 0z M134.4 -134.8 L134.4 -153.6 L120.8 -153.6 L17.6 -20 L17.6 0 L31.6 0z M122.4 -153.6 L16 -153.6 L16 -131.6 L122.4 -131.6z" transform="translate(-16 281.6)"/></svg> </div><!--END-SVGS don't remove this comment--> - <div class="row intro"><div> - <h2 class="back"><a href="../">The Inter UI font family</a></h2> - <h1><a href="./">Inter UI glyphs</a></h1> - <p> - This shows the complete set of glyphs in Inter UI Regular. - You can zoom in and out by pressing - <kbd>⌘</kbd><kbd>+</kbd> and - <kbd>⌘</kbd><kbd>−</kbd> on your keyboard. - Click on a glyph to see more details about it. - </p> - </div></div> +<div class="row intro"><div> + <h1><a href="./">Glyphs</a></h1> + <p> + This shows the complete set of glyphs in Inter UI Regular. + You can zoom in and out by pressing + <kbd>⌘</kbd><kbd>+</kbd> and + <kbd>⌘</kbd><kbd>−</kbd> on your keyboard. + Click on a glyph to see more details about it. + </p> +</div></div> - <div id="glyphs"> - <div id="single-info" style="display:none"> - <ul> - <li>Glyph name: <span class="name"></span></li> - <li class="unicode">Unicode: <a><span class="unicodeCodePoint num"></span> <span class="unicodeName"></span></a></li> - <li>Advance width: <span class="advanceWidth num"></span></li> - <li>Left margin: <span class="marginLeft num"></span></li> - <li>Right margin: <span class="marginRight num"></span></li> - <li>Color mark: <span class="colorMark"> </span></li> - <li><a class="svgFile">↓ Download SVG file</a></li> - </ul> - </div> - </div> +<div id="glyphs"> + <div id="single-info" style="display:none"> + <ul> + <li>Glyph name: <span class="name"></span></li> + <li class="unicode">Unicode: <a><span class="unicodeCodePoint num"></span> <span class="unicodeName"></span></a></li> + <li>Advance width: <span class="advanceWidth num"></span></li> + <li>Left margin: <span class="marginLeft num"></span></li> + <li>Right margin: <span class="marginRight num"></span></li> + <li>Color mark: <span class="colorMark"> </span></li> + <li><a class="svgFile">↓ Download SVG file</a></li> + </ul> + </div> +</div> - <div class="row kerning"><div> - <h2 id="kerning"><a href="#kerning">Kerning</a></h2> - <div id="kerning-list"></div> - </div></div> +<div class="row kerning"><div> + <h2 id="kerning"><a href="#kerning">Kerning</a></h2> + <div id="kerning-list"></div> +</div></div> - <script src="glyphs.js"></script> - </body> -</html> +<script src="glyphs.js?v={{ glyphs_js_v }}"></script> diff --git a/docs/index.html b/docs/index.html index 4aadee974..fb2345fc9 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,360 +1,326 @@ -<!DOCTYPE HTML> -<html lang="en" prefix="og: http://ogp.me/ns#"> - <head> - <meta charset="utf-8"> - <title>Inter UI font family</title> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta property="og:title" content="Inter UI font family"> - <meta property="twitter:title" content="Inter UI font family"> - <meta property="description" content="Inter UI is a new typeface optimized for computer user interfaces"> - <meta property="og:description" content="Inter UI is a new typeface optimized for computer user interfaces"> - <meta property="twitter:description" content="Inter UI is a new typeface optimized for computer user interfaces"> - <meta property="twitter:card" content="summary"> - <meta property="twitter:site" content="@rsms"> - <meta property="twitter:creator" content="@rsms"> - <meta property="og:image" content="https://rsms.me/inter/res/poster.png"> - <meta property="twitter:image" content="https://rsms.me/inter/res/poster.png"> - <meta property="fb:app_id" content="38027689216"> - <meta property="og:url" content="https://rsms.me/inter/"> - <meta property="og:site_name" content="rsms.me"> - <meta property="og:type" content="product"> - <meta property="og:locale" content="en_US" /> - <meta name="format-detection" content="telephone=no"> - <link rel="icon" type="image/png" href="favicon.png" /> - <link href="inter-ui.css?v=2.5" rel="stylesheet"> - <link href="index.css?v=5" rel="stylesheet"> - </head> - <body> - - <div class="row menu"> - <ul class="menu"> - <li class="home"><a href="../">Inter UI</a></li> - <li><a class="download-link" - href="https://github.com/rsms/inter/releases/latest/" - >Download</a></li> - <li><a href="samples/">Samples</a></li> - <li><a href="lab/">Playground</a></li> - <li><a href="https://github.com/rsms/inter/">Source</a></li> - </ul> - </div> - - <div class="row"><div> - <h1>The Inter UI font family</h1> - <p> - Inter UI is a typeface specially designed for user interfaces - with focus on high legibility of small-to-medium sized text on computer screens. - </p> - <p> - The family features a tall x-height to aid in readability of mixed-case and - lower-case text. Several OpenType features are provided as well, - like contextual alternates that adjusts punctuation depending on the shape of - surrounding glyphs, slashed zero for when you need to disambiguate "0" from "o", - tabular numbers, etc. - </p> - </div></div> - - <div class="row white" style="padding-bottom:0"><div> - <p id="samples" class="samples items"> - <a href="samples/" class="plain"><img src="samples/img/01.png" srcset="samples/img/01@2x.png 2x" width="888"></a> - </p> - <p style="text-align:center"> - <a href="samples/" class="plain">More samples -></a> - <br><br> - </p> - </div></div> - - <div class="row dark"><div> - - <h2><a id="usage" href="#usage">How do I use it?</a></h2> - <p> - Using the font is as easy as - <a class="download-link" href="https://github.com/rsms/inter/releases/latest/">download & installing</a> locally on your computer. - </p> - <p> - You're free to bundle copies of Inter UI with your software, even if it's - commercial and you charge money for your software. Inter UI can also be used - on the web by either hosting the font files yourself or by including this CSS: - </p> - <code>@import url('https://rsms.me/inter/inter-ui.css');</code> - <p>Use the following CSS rules to specify the Inter UI family:</p> - <code>font-family: 'Inter UI', sans-serif;</code> - - <p> </p> - - <h2><a id="free" href="#free">How much does it cost?</a></h2> - <p> - Inter UI is a <a href="https://github.com/rsms/inter">free and open source</a> font family. You are free to use this font in almost any way imaginable. - Refer to the <a href="https://choosealicense.com/licenses/ofl-1.1/">SIL Open Font License 1.1</a> for exact details on what the conditions and restrictions are. - </p> - - </div></div> - - <div class="row"><div> - <p> - There are currently four <a id="weights" href="#weights">weights</a> - </p> - <img src="res/weights-and-styles.svg" style="opacity:0.76;width:100%;display:block;margin:2em 0 3em 0"> - <h2><a id="features" href="#features">Features</a></h2> - <boxes> - <box> - <h3>Contextual alternates (<q title='OpenType feature ID'>calt</q>)</h3> - <tablex><t> - <h><in>Disabled</in><to></to><out>Enabled</out></h> - <r><in>12<em>:</em>34, FE<em>—</em>X</in><to></to><out>12:34, FE—X</out></r> - <r><in>4<em>.</em>2</in><to></to><out>4.2</out></r> - <r><in>SFO <em>-></em> STO</in><to></to><out>SFO -> STO</out></r> - <r><in>IIA <em>—></em> OGG</in><to></to><out>IIA —> OGG</out></r> - <r><in>M<em>@</em>N m@n</in><to></to><out>M@N m@n</out></r> - </t></tablex> - </box> - - <box> - <h3>Tabular numbers (<q title='OpenType feature ID'>tnum</q>)</h3> - <tablex><t> - <h><in>Disabled</in><to></to><out>Enabled</out></h> - <r><in><em>1</em>23456<em>7</em>890</in><to></to><out class="tnum">1234567890</out></r> - <r><in>1131711<em> </em></in><to></to><out class="tnum">1131711<em> </em></out></r> - <r><in>0040900<em> </em></in><to></to><out class="tnum">0040900<em> </em></out></r> - <r><in>11:31,711<em> </em></in><to></to><out class="tnum">11:31,711<em> </em></out></r> - <r><in>00:40.900<em> </em></in><to></to><out class="tnum">00:40.900<em> </em></out></r> - </t></tablex> - </box> - - <box> - <h3>Slashed zero (<q title='OpenType feature ID'>zero</q>)</h3> - <tablex><t> - <h><in>Disabled</in><to></to><out>Enabled</out></h> - <r><in><em>0</em>123</in><to></to><out class="zero">0123</out></r> - </t></tablex> - </box> - - <box> - <h3>Fractions (<q title='OpenType feature ID'>frac</q>)</h3> - <tablex><t> - <h><in>Disabled</in><to></to><out>Enabled</out></h> - <r> - <in><em>1/3</em> <em>22/9</em> <em>3/4/5</em></in> - <to></to><out class="frac">1/3 22/9 3/4/5</out> - </r> - </t></tablex> - </box> - - <box> - <h3>Stylistic set 1: Alternate digits (<q title='OpenType feature ID'>ss01</q>)</h3> - <tablex><t> - <h><in>Disabled</in><to></to><out>Enabled</out></h> - <r> - <in><em>1</em>23<em>4</em>5<em>6</em>78<em>9</em>0</in> - <to></to><out class="ss01">1234567890</out> - </r> - <r><in><em>1</em></in><to></to><out class="ss01">1</out></r> - <r><in><em>4</em></in><to></to><out class="ss01">4</out></r> - <r><in><em>6</em></in><to></to><out class="ss01">6</out></r> - <r><in><em>9</em></in><to></to><out class="ss01">9</out></r> - </t></tablex> - </box> - - <box> - <h3>Case alternates (<q title='OpenType feature ID'>case</q>)</h3> - <tablex><t> - <h><in>Disabled</in><to></to><out>Enabled</out></h> - <r> - <in><em>(</em>Hello<em>)</em> <em>[</em>World<em>]</em> <em>{</em>9000<em>}</em></in> - <to></to><out class="case">(Hello) [World] {9000}</out> - </r> - <r><in>SCHOOL <em>@</em> RUN</in><to></to><out class="case">SCHOOL @ RUN</out></r> - <r><in>3 <em>+</em> 9 <em>=</em> 12 <em>*</em> 1</in><to></to><out class="case">3 + 9 = 12 * 1</out></r> - <r><in><em>*</em> <em>+</em> <em>÷</em> <em>±</em> <em>×</em> <em>=</em> <em>≠</em> <em>•</em></in><to></to><out class="case">* + ÷ ± × = ≠ •</out></r> - <r><in><em>→</em> <em>←</em> <em>⟶</em> <em>⟵</em> <em>−</em> <em>-</em> <em>–</em> <em>—</em> <em>:</em></in><to></to><out class="case">→ ← ⟶ ⟵ − - – — :</out></r> - </t></tablex> - </box> - - </boxes> - - <p> - Also includes some - Localized Forms (<q title='OpenType feature ID'>locl</q>), - Numerators (<q title='OpenType feature ID'>numr</q>) and - Denominators (<q title='OpenType feature ID'>dnom</q>). - </p> - - <p> </p> - - <h2 class="banner"><a href="glyphs/">Browse all glyphs -></a></h2> - </div></div> - - <div class="row-divider"></div> - - <div class="row"><div> - <h2><a id="story" href="#story">The story behind Inter UI</a></h2> - <p> - Inter UI started out in late 2016 as an experiment to build a perfectly - pixel-fitting font at a specific small size (11px.) The idea was that - by crafting a font in a particular way, with a particular coordinate system - (Units Per EM), and for a particular target rasterization size (11), it would - be possible to get the best of both sharpness and readability. - </p> - <p> - However after a few months of using an early version of Inter UI, it dawned - on everyone exposed to the test that this approach had some serious real-world - problems. Most notably that it was really hard to read longer text. Because of - the pixel-aligning nature of that approach, the font took an almost - <a href="https://www.figma.com/file/HPqDViSCB8fAWuxaV2ousFMv">mono-spaced appearance</a>, - making it really easy to read numbers, punctuation and very short - words, but eye-straining to read anything longer. - </p> - <p> - The project was rebooted with a different approach, sticking with the - specific UPM, but crafting glyphs and kerning in a way that made for - more variation in the rhythm and smoother vertical and horizontal stems. - As Inter UI was being developed, it was tested on an internal version of - <a href="https://www.figma.com/">Figma</a>—where the author of Inter UI works as a designer—and slowly improved upon based on experience and feedback. - </p> - - <p> </p> - - <h2><a id="status" href="#status">Current status & usability</a></h2> - <p> - Inter UI works great for English-language text, and pretty well for other - Latin and Cyrillic languages. There's still a lot of work to be done, and - <a href="https://github.com/rsms/inter/blob/master/CONTRIBUTING.md">contributions are warmly welcomed</a>. The playground contains <a href="lab/?sample=Body%20text%201&size=16">a lot of samples</a>, including some common <a href="lab/?sample=Kerning%20body%20multi-lang&size=16">non English-language words in the playground.</a> - </p> - - <p> - Please refer to the <a href="glyphs/">glyph repertoire</a> - for an overview of currently-available glyphs and their quality. - </p> - - <p> </p> - - <h2><a id="faq" href="#faq">FAQ</a></h2> - <ul class="faq"> - - <li class="q" id="faq-using-features"> - How do I enable and disable font features? - </li> - <li class="a"> - In web browsers you'll want to use - <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/font-feature-settings"><q>font-feature-settings</q></a>. - In Figma you can access features via the - <a href="https://help.figma.com/text/opentype-features">Advanced Typography panel.</a> - In Illustrator, Photoshop and friends, you can access features via the - <a href="https://helpx.adobe.com/illustrator/using/special-characters.html#opentype_panel_overview">Characters and OpenType panels.</a> - Sketch doesn't provide a UI for configuring font features, but there's - <a href="https://sketchtalk.io/discussion/comment/1478/#Comment_1478">a workaround using macOS's native font UI.</a> - </li> - - <li class="q" id="faq-unhinted-vs-hinted"> - What is the difference between "unhinted" and "hinted" font files? - </li> - <li class="a"> - The font files in the "hinted" folders have additional data in them - for assisting - <a href="https://en.wikipedia.org/wiki/ClearType">ClearType</a>, - the text rasterizer used by Microsoft Windows (and some Linux distributions.) - You want to use the "hinted" fonts only if you are targeting Windows users - <em>and</em> prefer the different look of these "hinted" fonts. - Additionally, hinting data makes the font files larger, so if you are - using Inter UI on websites, the extra size of these files is another - consideration to make. - <a href="https://www.typotheque.com/articles/hinting"> - This article explains hinting at a greater length.</a> - </li> - - - <li class="q" id="faq-cdn"> - How reliable are the fonts served from rsms.me/inter? Is it on a CDN? - </li> - <li class="a"> - rsms.me/inter is backed by GitHub's server network and distributed - globally on the CloudFlare CDN, making usage of - <q>https://rsms.me/inter/inter-ui.css</q> and associated font - files very reliable and fast throughout the world. - </li> - - <li class="q" id="faq-contribute"> - Can I help with improving Inter UI? - </li> - <li class="a"> - Yes you can! Inter UI is an open-source project, meaning the source - code—or "source design" if you will—that is used to build the font files - <a href="https://github.com/rsms/inter">are freely available</a> to improve upon. - Font making requires a fair bit of technical work and - depending on what you'd like to do, some things might be more fun - depending on your technical skills. - The <a href="https://github.com/rsms/inter/blob/master/CONTRIBUTING.md">"Contributing" document</a> is a great place to start. The document outlines where - you can have the biggest impact, how things are setup and how to get - started. - </li> - - <li class="q" id="faq-start-date"> - This website claims work started in 2016, but the git repository's log says it started later? - </li> - <li class="a"> - Inter UI was developed in an a private, internal git repository - starting in November 2016, prior to being published on August 22, 2017. - Between November 2016 and August 2017, there were - <num>2 990 150</num> line edits made across 247 versions. - The reason the public GitHub repository does not reflect this is the - fact that the project was initially only internal at the company where - the author works and had some sensitive information "checked in", - like AWS server details and internal author identity in - all commit messages. Maybe one day we can write an elaborate git - filter-branch program and convert the filter the old repository to make - it public, but what would be the point of that? :—) - </li> - - <li class="q" id="faq-contact"> - I've made a cool thing that uses Inter UI, can I share it with you? - <dem>or</dem> - </li> - <li class="q"> - I have a different question - </li> - <li class="a"> - Reach out on <a href="https://twitter.com/rsms">Twitter (@rsms)</a> or over <a href="mailto:rasmus@notion.se">email</a> - </li> - - - </ul> - - </div></div> - - - <div class="row"><div> - — <a href="https://twitter.com/rsms" class="plain">@rsms</a> - </div></div> - - <script src="index.js?v=2"></script> - <script> - (function(){ - - // FAQ anchors - var av = document.querySelectorAll('ul.faq > li.q'), a, i, e, id, tn - for (i = 0; i < av.length; ++i) { - e = av[i] - tn = document.createTextNode('Q ') - e.insertBefore(tn, e.firstChild) - id = e.id - if (id) { - a = document.createElement('a') - // a.id = id - a.href = '#' + id - a.className = 'plain' - a.innerHTML = e.innerHTML - e.innerText = '' - e.appendChild(a) - } - } - av = document.querySelectorAll('ul.faq > li.a') - for (i = 0; i < av.length; ++i) { - e = av[i] - tn = document.createTextNode('A ') - e.insertBefore(tn, e.firstChild) - } - - })(); - </script> - </body> -</html> +--- +layout: default +--- + +<div class="row"><div> + <h1>The Inter UI font family</h1> + <p> + Inter UI is a typeface specially designed for user interfaces + with focus on high legibility of small-to-medium sized text on computer screens. + </p> + <p> + The family features a tall x-height to aid in readability of mixed-case and + lower-case text. Several OpenType features are provided as well, + like contextual alternates that adjusts punctuation depending on the shape of + surrounding glyphs, slashed zero for when you need to disambiguate "0" from "o", + tabular numbers, etc. + </p> +</div></div> + +<div class="row white" style="padding-bottom:0"><div> + <p id="samples" class="samples items sample-images"> + <a href="samples/" class="plain"><img src="samples/img/01.png" srcset="samples/img/01@2x.png 2x" width="888"></a> + </p> + <p style="text-align:center"> + <a href="samples/" class="plain">More samples -></a> + <br><br> + </p> +</div></div> + +<div class="row dark"><div> + + <h2><a id="usage" href="#usage">How do I use it?</a></h2> + <p> + Using the font is as easy as + <a class="download-link" href="https://github.com/rsms/inter/releases/latest/">download & installing</a> locally on your computer. + </p> + <p> + You're free to bundle copies of Inter UI with your software, even if it's + commercial and you charge money for your software. Inter UI can also be used + on the web by either hosting the font files yourself or by including this CSS: + </p> + <code>@import url('https://rsms.me/inter/inter-ui.css');</code> + <p>Use the following CSS rules to specify the Inter UI family:</p> + <code>font-family: 'Inter UI', sans-serif;</code> + + <p> </p> + + <h2><a href="{{url_root}}dynmetrics/">Dynamic Metrics</a></h2> + <p> + There's of course no absolute right or wrong when it comes to expressing yourself with typography, but Inter UI <em>Dynamic Metrics</em> provides guidelines for good typography. You simply provide the optical font size, and the tracking and leading is calculated for you to produce the best results. + <a href="{{url_root}}dynmetrics/">Learn about Dynamic Metrics —></a> + </p> + + <p> </p> + + <h2><a id="free" href="#free">How much does it cost?</a></h2> + <p> + Inter UI is a <a href="https://github.com/rsms/inter">free and open source</a> font family. You are free to use this font in almost any way imaginable. + Refer to the <a href="https://choosealicense.com/licenses/ofl-1.1/">SIL Open Font License 1.1</a> for exact details on what the conditions and restrictions are. + </p> + +</div></div> + +<div class="row"><div> + <p> + There are currently four <a id="weights" href="#weights">weights</a> + </p> + <img src="res/weights-and-styles.svg" style="opacity:0.76;width:100%;display:block;margin:2em 0 3em 0"> + <h2><a id="features" href="#features">Features</a></h2> + <boxes> + <box> + <h3>Contextual alternates (<q title='OpenType feature ID'>calt</q>)</h3> + <tablex><t> + <h><in>Disabled</in><to></to><out>Enabled</out></h> + <r><in>12<em>:</em>34, FE<em>—</em>X</in><to></to><out>12:34, FE—X</out></r> + <r><in>4<em>.</em>2</in><to></to><out>4.2</out></r> + <r><in>SFO <em>-></em> STO</in><to></to><out>SFO -> STO</out></r> + <r><in>IIA <em>—></em> OGG</in><to></to><out>IIA —> OGG</out></r> + <r><in>M<em>@</em>N m@n</in><to></to><out>M@N m@n</out></r> + </t></tablex> + </box> + + <box> + <h3>Tabular numbers (<q title='OpenType feature ID'>tnum</q>)</h3> + <tablex><t> + <h><in>Disabled</in><to></to><out>Enabled</out></h> + <r><in><em>1</em>23456<em>7</em>890</in><to></to><out class="tnum">1234567890</out></r> + <r><in>1131711<em> </em></in><to></to><out class="tnum">1131711<em> </em></out></r> + <r><in>0040900<em> </em></in><to></to><out class="tnum">0040900<em> </em></out></r> + <r><in>11:31,711<em> </em></in><to></to><out class="tnum">11:31,711<em> </em></out></r> + <r><in>00:40.900<em> </em></in><to></to><out class="tnum">00:40.900<em> </em></out></r> + </t></tablex> + </box> + + <box> + <h3>Slashed zero (<q title='OpenType feature ID'>zero</q>)</h3> + <tablex><t> + <h><in>Disabled</in><to></to><out>Enabled</out></h> + <r><in><em>0</em>123</in><to></to><out class="zero">0123</out></r> + </t></tablex> + </box> + + <box> + <h3>Fractions (<q title='OpenType feature ID'>frac</q>)</h3> + <tablex><t> + <h><in>Disabled</in><to></to><out>Enabled</out></h> + <r> + <in><em>1/3</em> <em>22/9</em> <em>3/4/5</em></in> + <to></to><out class="frac">1/3 22/9 3/4/5</out> + </r> + </t></tablex> + </box> + + <box> + <h3>Stylistic set 1: Alternate digits (<q title='OpenType feature ID'>ss01</q>)</h3> + <tablex><t> + <h><in>Disabled</in><to></to><out>Enabled</out></h> + <r> + <in><em>1</em>23<em>4</em>5<em>6</em>78<em>9</em>0</in> + <to></to><out class="ss01">1234567890</out> + </r> + <r><in><em>1</em></in><to></to><out class="ss01">1</out></r> + <r><in><em>4</em></in><to></to><out class="ss01">4</out></r> + <r><in><em>6</em></in><to></to><out class="ss01">6</out></r> + <r><in><em>9</em></in><to></to><out class="ss01">9</out></r> + </t></tablex> + </box> + + <box> + <h3>Case alternates (<q title='OpenType feature ID'>case</q>)</h3> + <tablex><t> + <h><in>Disabled</in><to></to><out>Enabled</out></h> + <r> + <in><em>(</em>Hello<em>)</em> <em>[</em>World<em>]</em> <em>{</em>9000<em>}</em></in> + <to></to><out class="case">(Hello) [World] {9000}</out> + </r> + <r><in>SCHOOL <em>@</em> RUN</in><to></to><out class="case">SCHOOL @ RUN</out></r> + <r><in>3 <em>+</em> 9 <em>=</em> 12 <em>*</em> 1</in><to></to><out class="case">3 + 9 = 12 * 1</out></r> + <r><in><em>*</em> <em>+</em> <em>÷</em> <em>±</em> <em>×</em> <em>=</em> <em>≠</em> <em>•</em></in><to></to><out class="case">* + ÷ ± × = ≠ •</out></r> + <r><in><em>→</em> <em>←</em> <em>⟶</em> <em>⟵</em> <em>−</em> <em>-</em> <em>–</em> <em>—</em> <em>:</em></in><to></to><out class="case">→ ← ⟶ ⟵ − - – — :</out></r> + </t></tablex> + </box> + + </boxes> + + <p> + Also includes some + Localized Forms (<q title='OpenType feature ID'>locl</q>), + Numerators (<q title='OpenType feature ID'>numr</q>) and + Denominators (<q title='OpenType feature ID'>dnom</q>). + </p> + + <p> </p> + + <h2 class="banner"><a href="glyphs/">Browse all glyphs -></a></h2> +</div></div> + +<div class="row-divider"></div> + +<div class="row"><div> + <h2><a id="story" href="#story">The story behind Inter UI</a></h2> + <p> + Inter UI started out in late 2016 as an experiment to build a perfectly + pixel-fitting font at a specific small size (11px.) The idea was that + by crafting a font in a particular way, with a particular coordinate system + (Units Per EM), and for a particular target rasterization size (11), it would + be possible to get the best of both sharpness and readability. + </p> + <p> + However after a few months of using an early version of Inter UI, it dawned + on everyone exposed to the test that this approach had some serious real-world + problems. Most notably that it was really hard to read longer text. Because of + the pixel-aligning nature of that approach, the font took an almost + <a href="https://www.figma.com/file/HPqDViSCB8fAWuxaV2ousFMv">mono-spaced appearance</a>, + making it really easy to read numbers, punctuation and very short + words, but eye-straining to read anything longer. + </p> + <p> + The project was rebooted with a different approach, sticking with the + specific UPM, but crafting glyphs and kerning in a way that made for + more variation in the rhythm and smoother vertical and horizontal stems. + As Inter UI was being developed, it was tested on an internal version of + <a href="https://www.figma.com/">Figma</a>—where the author of Inter UI works as a designer—and slowly improved upon based on experience and feedback. + </p> + + <p> </p> + + <h2><a id="status" href="#status">Current status & usability</a></h2> + <p> + Inter UI works great for English-language text, and pretty well for other + Latin and Cyrillic languages. There's still a lot of work to be done, and + <a href="https://github.com/rsms/inter/blob/master/CONTRIBUTING.md">contributions are warmly welcomed</a>. The playground contains <a href="lab/?sample=Body%20text%201&size=16">a lot of samples</a>, including some common <a href="lab/?sample=Kerning%20body%20multi-lang&size=16">non English-language words in the playground.</a> + </p> + + <p> + Please refer to the <a href="glyphs/">glyph repertoire</a> + for an overview of currently-available glyphs and their quality. + </p> + + <p> </p> + + <h2><a id="faq" href="#faq">FAQ</a></h2> + <ul class="faq"> + + <li class="q" id="faq-using-features"> + How do I enable and disable font features? + </li> + <li class="a"> + In web browsers you'll want to use + <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/font-feature-settings"><q>font-feature-settings</q></a>. + In Figma you can access features via the + <a href="https://help.figma.com/text/opentype-features">Advanced Typography panel.</a> + In Illustrator, Photoshop and friends, you can access features via the + <a href="https://helpx.adobe.com/illustrator/using/special-characters.html#opentype_panel_overview">Characters and OpenType panels.</a> + Sketch doesn't provide a UI for configuring font features, but there's + <a href="https://sketchtalk.io/discussion/comment/1478/#Comment_1478">a workaround using macOS's native font UI.</a> + </li> + + <li class="q" id="faq-unhinted-vs-hinted"> + What is the difference between "unhinted" and "hinted" font files? + </li> + <li class="a"> + The font files in the "hinted" folders have additional data in them + for assisting + <a href="https://en.wikipedia.org/wiki/ClearType">ClearType</a>, + the text rasterizer used by Microsoft Windows (and some Linux distributions.) + You want to use the "hinted" fonts only if you are targeting Windows users + <em>and</em> prefer the different look of these "hinted" fonts. + Additionally, hinting data makes the font files larger, so if you are + using Inter UI on websites, the extra size of these files is another + consideration to make. + <a href="https://www.typotheque.com/articles/hinting"> + This article explains hinting at a greater length.</a> + </li> + + + <li class="q" id="faq-cdn"> + How reliable are the fonts served from rsms.me/inter? Is it on a CDN? + </li> + <li class="a"> + rsms.me/inter is backed by GitHub's server network and distributed + globally on the CloudFlare CDN, making usage of + <q>https://rsms.me/inter/inter-ui.css</q> and associated font + files very reliable and fast throughout the world. + </li> + + <li class="q" id="faq-contribute"> + Can I help with improving Inter UI? + </li> + <li class="a"> + Yes you can! Inter UI is an open-source project, meaning the source + code—or "source design" if you will—that is used to build the font files + <a href="https://github.com/rsms/inter">are freely available</a> to improve upon. + Font making requires a fair bit of technical work and + depending on what you'd like to do, some things might be more fun + depending on your technical skills. + The <a href="https://github.com/rsms/inter/blob/master/CONTRIBUTING.md">"Contributing" document</a> is a great place to start. The document outlines where + you can have the biggest impact, how things are setup and how to get + started. + </li> + + <li class="q" id="faq-start-date"> + This website claims work started in 2016, but the git repository's log says it started later? + </li> + <li class="a"> + Inter UI was developed in an a private, internal git repository + starting in November 2016, prior to being published on August 22, 2017. + Between November 2016 and August 2017, there were + <num>2 990 150</num> line edits made across 247 versions. + The reason the public GitHub repository does not reflect this is the + fact that the project was initially only internal at the company where + the author works and had some sensitive information "checked in", + like AWS server details and internal author identity in + all commit messages. Maybe one day we can write an elaborate git + filter-branch program and convert the filter the old repository to make + it public, but what would be the point of that? :—) + </li> + + <li class="q" id="faq-contact"> + I've made a cool thing that uses Inter UI, can I share it with you? + <dem>or</dem> + </li> + <li class="q"> + I have a different question + </li> + <li class="a"> + Reach out on <a href="https://twitter.com/rsms">Twitter (@rsms)</a> or over <a href="mailto:rasmus@notion.se">email</a> + </li> + + + </ul> + +</div></div> + + +<div class="row"><div> + — <a href="https://twitter.com/rsms" class="plain">@rsms</a> +</div></div> + +<script>(function(){ + + // FAQ anchors + var av = document.querySelectorAll('ul.faq > li.q'), a, i, e, id, tn + for (i = 0; i < av.length; ++i) { + e = av[i] + tn = document.createTextNode('Q ') + e.insertBefore(tn, e.firstChild) + id = e.id + if (id) { + a = document.createElement('a') + // a.id = id + a.href = '#' + id + a.className = 'plain' + a.innerHTML = e.innerHTML + e.innerText = '' + e.appendChild(a) + } + } + av = document.querySelectorAll('ul.faq > li.a') + for (i = 0; i < av.length; ++i) { + e = av[i] + tn = document.createTextNode('A ') + e.insertBefore(tn, e.firstChild) + } + +})();</script> diff --git a/docs/index.js b/docs/index.js deleted file mode 100644 index f7773c537..000000000 --- a/docs/index.js +++ /dev/null @@ -1,138 +0,0 @@ -var isMac = false - -function $$(query, el) { - return [].slice.call((el || document).querySelectorAll(query)) -} - -function $(query, el) { - return (el || document).querySelector(query) -} - -// fetchjson(url string, cb (err Error, d Object)->nil) -// -var fetchjson = ( - typeof window.fetch == 'function' ? ( - function _fetchjson(url, cb) { - return window.fetch(url) - .then(function(r) { return r.json() }) - .then(function(data) { cb(null, data) }) - .catch(cb) - } - ) : - function _fetchjson(url, cb) { - var r = new XMLHttpRequest() - r.addEventListener("load", function(){ - try { - cb(null, JSON.parse(r.responseText)) - } catch (err) { - cb(err) - } - }) - r.open("GET", url) - r.send() - } -) - -;(function(){ -"use strict"; - - -// anim.min.js -var anim=function(h){h=function(a,e,f,b){var g,d,c=[],j=function(a){ -if(a=c.shift())a[1]?h.apply(this,a).anim(j):0<a[0]?setTimeout(j,1E3*a[0]):(a[0](),j())}; -a.charAt&&(a=document.getElementById(a));if(0<a||!a)e={},f=0,j(c=[[a||0]]); -q(e,{padding:0,margin:0,border:"Width"},[l,m,n,p]);q(e,{borderRadius:"Radius"},[l+p,l+m,n+m,n+p]);++r; -for(g in e)d=e[g],!d.to&&0!==d.to&&(d=e[g]={to:d}),h.defs(d,a,g,b);h.iter(e,1E3*f,j); -return{anim:function(){c.push([].slice.call(arguments));return this}}}; -var l="Top", m="Right",n="Bottom",p="Left",r=1,q=function(a,e,f,b,g,d,c){for(b in a)if(b in e){c=a[b]; -for(g=0;d=f[g];g++)a[b.replace(e[b],"")+d+(e[b]||"")]={to:0===c.to?c.to:c.to||c,fr:c.fr,e:c.e}; -delete a[b]}},s=function(w,a){return w["r"+a]||w["webkitR"+a]||w["mozR"+a]||w["msR"+a]||w["oR"+a]}( -window,"equestAnimationFrame");h.defs=function(a,e,f,b,g){g=e.style;a.a=f;a.n=e;a.s=f in g?g:e; -a.e=a.e||b;a.fr=a.fr||(0===a.fr?0:a.s==e?e[f]:(window.getComputedStyle?getComputedStyle(e, null) -:e.currentStyle)[f]);a.u=(/\d(\D+)$/.exec(a.to)||/\d(\D+)$/.exec(a.fr)||[0,0])[1];a.fn=/color/i.test(f)? -h.fx.color:h.fx[f]||h.fx._;a.mx="anim_"+f;e[a.mx]=a.mxv=r;e[a.mx]!=a.mxv&&(a.mxv=null)};h.iter=function(a,e,f){ -var b,g,d,c,h,k=+new Date+e;b=function(){g=k-(new Date).getTime();if(50>g){ -for(d in a)d=a[d],d.p=1,d.fn(d,d.n,d.to,d.fr,d.a,d.e);f&&f()}else{g/=e;for(d in a){d=a[d]; -if(d.n[d.mx]!=d.mxv)return;h=d.e;c=g;"lin"==h?c=1-c:"ease"==h?(c=2*(0.5-c),c=1-(c*c*c-3*c+2)/4): -"ease-in"==h?(c= 1-c,c*=c*c):c=1-c*c*c;d.p=c;d.fn(d,d.n,d.to,d.fr,d.a,d.e)}s?s(b):setTimeout(b,20)}}; -b()};h.fx={_:function(a,e,f,b,g){b=parseFloat(b)||0;f=parseFloat(f)||0;a.s[g]=(1<=a.p?f:a.p*(f-b)+b)+a.u}, -width:function(a,e,f,b,g,d){0<=a._fr||(a._fr=!isNaN(b=parseFloat(b))?b:"width"==g?e.clientWidth:e.clientHeight); -h.fx._(a,e,f,a._fr,g,d)},opacity:function(a,e,f,b,g){if(isNaN(b=b||a._fr))b=e.style,b.zoom=1, -b=a._fr=(/alpha\(opacity=(\d+)\b/i.exec(b.filter)||{})[1]/100||1;b*=1;f=a.p*(f-b)+b;e=e.style;g in e?e[g]= f: -e.filter=1<=f?"":"alpha("+g+"="+Math.round(100*f)+")"},color:function(a,e,f,b,g,d,c,j){ -a.ok||(f=a.to=h.toRGBA(f),b=a.fr=h.toRGBA(b),0==f[3]&&(f=[].concat(b),f[3]=0),0==b[3]&& -(b=[].concat(f),b[3]=0),a.ok=1);j=[0,0,0,a.p*(f[3]-b[3])+1*b[3]];for(c=2;0<=c;c--)j[c]=Math.round( -a.p*(f[c]-b[c])+1*b[c]);(1<=j[3]||h.rgbaIE)&&j.pop();try{a.s[g]=(3<j.length?"rgba(":"rgb(")+j.join(",")+")" -}catch(k){h.rgbaIE=1}}};h.fx.height=h.fx.width; -h.RGBA=/#(.)(.)(.)\b|#(..)(..)(..)\b|(\d+)%,(\d+)%,(\d+)%(?:,([\d\.]+))?|(\d+),(\d+),(\d+)(?:,([\d\.]+))?\b/; -h.toRGBA=function(a,e){e=[0,0,0,0];a.replace(/\s/g,"").replace(h.RGBA,function(a,b,g,d,c,h,k,l,m,n,p,q,r,s,t){ -k=[b+b||c,g+g||h,d+d||k];b=[l,m,n];for(a=0;3>a;a++)k[a]=parseInt(k[a],16),b[a]=Math.round(2.55*b[a]); -e=[k[0]||b[0]||q||0,k[1]||b[1]||r||0,k[2]||b[2]||s||0,p||t||1]});return e};return h}(); - - -if (!window.MSStream && - /mac|ipad|iphone|ipod/i.test(navigator.userAgent)) -{ - isMac = true - document.body.classList.add('mac_or_ios') - if (navigator.userAgent.indexOf('Safari') != -1) { - document.body.classList.add('safari') - } -} - - -// timeNow() :float -var timeNow = ( - window.performance !== undefined && window.performance.now ? function() { - return window.performance.now() - } : Date.now ? function() { - return Date.now() - } : function() { - return (new Date()).getTime() - } -) - - -// download-link -fetchjson('/inter/info.json', function(err, data) { - if (err) { throw err } - var ids = Object.keys(data) - var regularId = ids[0] - ids.forEach(function(id){ - if (id.indexOf('Inter UI Regular:') == 0) { - regularId = id - } - }) - if (ids.length == 0) { - console.error('failed to find Inter UI Regular in info.json', data) - return - } - var regular = data[regularId] - // console.log('info.json:', regular) - if (regular.names && regular.names.version) { - var v = regular.names.version - var p = v.indexOf(';') - if (p != -1) { - v = v.substr(0, p) - } - var directDownloadURL = - 'https://github.com/rsms/inter/releases/download/v' + v + - '/Inter-UI-' + v + '.zip' - var av = document.querySelectorAll('a.download-link'), i, e - for (i = 0; i < av.length; ++i) { - e = av[i] - e.href = directDownloadURL - } - } -}) - - -// Google Analytics -;(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ -(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), -m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) -})(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); -ga('create', 'UA-105091131-2', 'auto'); -ga('send', 'pageview'); - -})(); diff --git a/docs/index.css b/docs/res/base.css index 874725192..5cc6cc39d 100644 --- a/docs/index.css +++ b/docs/res/base.css @@ -6,8 +6,8 @@ body { font: 15px/22px 'Inter UI', system-ui, sans-serif; font-size: 15px; - line-height:1.4; - /*letter-spacing: 0.009em;*/ + line-height: 1.5; + letter-spacing: -0.002em; font-weight: 400; padding-bottom: 30px; @@ -83,11 +83,11 @@ q:after { content: ""; } kbd { - -moz-font-feature-settings: 'kern' 1, 'case' 1; - -ms-font-feature-settings: 'kern' 1, 'case' 1; - -o-font-feature-settings: 'kern' 1, 'case' 1; + -moz-font-feature-settings: 'kern' 1, 'case' 1; + -ms-font-feature-settings: 'kern' 1, 'case' 1; + -o-font-feature-settings: 'kern' 1, 'case' 1; -webkit-font-feature-settings: 'kern' 1, 'case' 1; - font-feature-settings: 'kern' 1, 'case' 1; + font-feature-settings: 'kern' 1, 'case' 1; border: 1px solid rgba(0,0,0,0.18); border-radius: 3px; padding:0.1em 0.2em; @@ -98,14 +98,20 @@ dem { /* de-emphasize */ opacity: 0.7; } num { /* number */ - -moz-font-feature-settings: 'calt' 1, 'ss01' 1; - -ms-font-feature-settings: 'calt' 1, 'ss01' 1; - -o-font-feature-settings: 'calt' 1, 'ss01' 1; + /*-moz-font-feature-settings: 'calt' 1, 'ss01' 1; + -ms-font-feature-settings: 'calt' 1, 'ss01' 1; + -o-font-feature-settings: 'calt' 1, 'ss01' 1; -webkit-font-feature-settings: 'calt' 1, 'ss01' 1; - font-feature-settings: 'calt' 1, 'ss01' 1; + font-feature-settings: 'calt' 1, 'ss01' 1;*/ + letter-spacing:0.02em; white-space: pre; } +small { + font-size: 11px; + letter-spacing: 0.013em; +} + h1, h2, h3 { font-weight: 500; -webkit-font-smoothing: antialiased; @@ -176,11 +182,32 @@ h1 > a, h2 > a, h3 > a { display: flex; justify-content: center; } -.row > * { - width:100%; - max-width: 888px; - flex: 1 0 100%; + .row > * { + width:100%; + max-width: 888px; + flex: 1 0 100%; + } + .row .learn-more { + margin-top: 2em; + text-align: center; + font-size: 11px; + letter-spacing: 0.007em; + } + .row .learn-more a { + color: rgba(0,0,0,0.4); + text-decoration-color: rgba(0, 0, 0, 0); + } + .row .learn-more a:hover { + color: inherit; + } + +.row.full-width { + padding: 50px 0; + justify-content: flex-start; } + .row.full-width > * { + max-width: initial; + } .row-divider { margin:0 auto; @@ -228,77 +255,6 @@ h1 > a, h2 > a, h3 > a { opacity: 1; } -/* narrow windows */ -@media only screen and (max-width: 565px) { - .row.menu ul { - justify-content: space-between; - } - .row.menu ul li { - margin-right: 15px; - } - .row.menu ul li:last-child { - margin-right: 0; - } - .row.menu ul li.home { - /*color: red; - clear: both;*/ - /*display: block;*/ - text-align:center; - margin:0 0 -12px 0; - width: 100%; - } - .row.menu ul li.home > a { - border-bottom: none; - padding: 0 1em; - margin: 0.5em 0; - line-height:34px; - border-radius: 90px; - - /*color: white; - background-color: rgba(3, 102, 214, 1);*/ - } - .row.menu ul li.home > a:hover { - color: white; - background-color: #222; - } -} - -/* small devices (<= iPhone 6+) */ -@media only screen and (max-device-width: 414px) { - body { - font-size: 14px; - line-height: 20px; - } - .row { - padding-left: 20px; - padding-right: 20px; - } - .row.menu ul { - margin-left: 20px; - margin-right: 20px; - } -} - -/* small devices (<= iPhone 5) */ -@media only screen and (max-device-width: 320px) { - .row.menu { - font-size:13px; - } - .row.menu ul { - margin-left: 0; - margin-right: 0; - } - .row.menu ul li { - flex: 1 0 auto; - text-align: center; - border-right: 1px solid rgba(0,0,0,0.1); - margin-left:0; - margin-right:0; - } - .row.menu ul li:last-child { - border-right: none; - } -} .row.white { background: white; @@ -346,13 +302,9 @@ a > img { } .sample-images {} - .sample-images > img, .sample-images > svg { + .sample-images img, .sample-images svg { display: block; - margin:100px 0; - width:100%; - } - .sample-images > img:first-child, .sample-images > svg:first-child { - margin-top:50px; + width: 100%; } @@ -493,16 +445,16 @@ boxes { } box { overflow: auto; - max-width:100%; + flex: 1 1 0; + min-width: 280px; + max-width: 100%; display: flex; flex-direction: column; background: white; - padding:2em; + padding: 2em; border-radius: 3px; margin-right:1em; margin-bottom:1em; - flex: 1 1 10%; - /*width:220px;*/ } body.safari box { /* Fix for broken flex wrap in safari */ @@ -514,3 +466,85 @@ box:first-child { box h3 { margin-bottom:0.8em; } + + +/* ------------------------------------------------------ */ + +/* narrow windows */ +@media only screen and (max-width: 565px) { + .row.menu ul { + justify-content: space-between; + } + .row.menu ul li { + margin-right: 15px; + } + .row.menu ul li:last-child { + margin-right: 0; + } + .row.menu ul li.home { + /*color: red; + clear: both;*/ + /*display: block;*/ + text-align:center; + margin:0 0 -12px 0; + width: 100%; + } + .row.menu ul li.home > a { + border-bottom: none; + padding: 0 1em; + margin: 0.5em 0; + line-height:34px; + border-radius: 90px; + + /*color: white; + background-color: rgba(3, 102, 214, 1);*/ + } + .row.menu ul li.home > a:hover { + color: white; + background-color: #222; + } +} + +/* small devices (<= iPhone 6+) */ +@media only screen and (max-device-width: 414px) { + box { padding: 1em; } + box tablex r { font-size: 0.9em; } + body { + font-size: 14px; + line-height: 20px; + } + .row { + padding-left: 20px; + padding-right: 20px; + } + .row.menu ul { + margin-left: 20px; + margin-right: 20px; + } +} + +/* small devices (<= iPhone 5) */ +@media only screen and (max-device-width: 320px) { + box { + font-size: 0.8em; + min-width: 240px; + } + /*.row.menu { + font-size:13px; + } + .row.menu ul { + margin-left: 0; + margin-right: 0; + } + .row.menu ul li { + flex: 1 0 auto; + text-align: center; + border-right: 1px solid rgba(0,0,0,0.1); + margin-left:0; + margin-right:0; + } + .row.menu ul li:last-child { + border-right: none; + }*/ +} + diff --git a/docs/res/base.js b/docs/res/base.js new file mode 100644 index 000000000..3ef970cc3 --- /dev/null +++ b/docs/res/base.js @@ -0,0 +1,74 @@ + +function $$(query, el) { + return [].slice.call((el || document).querySelectorAll(query)) +} + +function $(query, el) { + return (el || document).querySelector(query) +} + +// fetchjson(url string) :Promise<Object> +// +var fetchjson = ( + typeof window.fetch == 'function' ? ( + function _fetchjson(url, cb) { + return window.fetch(url).then(function(r) { return r.json() }) + } + ) : + function _fetchjson(url, cb) { + return new Promise(function(resolve, reject) { + var r = new XMLHttpRequest() + r.addEventListener("load", function(){ + try { + resolve(JSON.parse(r.responseText)) + } catch (err) { + reject(err) + } + }) + r.addEventListener("error", function(ev) { + reject(ev.error || ev || new Error('network error')) + }) + r.open("GET", url) + r.send() + }) + } +) + + +// timeNow() :float +// +var timeNow = ( + window.performance !== undefined && window.performance.now ? function() { + return window.performance.now() + } : Date.now ? function() { + return Date.now() + } : function() { + return (new Date()).getTime() + } +) + + +// Mac or not? Maybe even a buggy Safari? +var isMac = false +if (!window.MSStream && + /mac|ipad|iphone|ipod/i.test(navigator.userAgent)) +{ + isMac = true + if (navigator.userAgent.indexOf('Safari') != -1 && + navigator.userAgent.indexOf('Chrome') == -1) + { + document.body.classList.add('safari') + } +} + + +// Google Analytics +// ;(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ +// (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), +// m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) +// })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); +// ga('create', 'UA-105091131-2', 'auto'); +// ga('send', 'pageview'); +window.dataLayer = window.dataLayer || []; +window.dataLayer.push(['js', new Date()]) +window.dataLayer.push(['config', 'UA-105091131-2']) diff --git a/docs/samples/bindings.js b/docs/res/bindings.js index cac29e417..eb51b87d5 100644 --- a/docs/samples/bindings.js +++ b/docs/res/bindings.js @@ -1,11 +1,14 @@ // requires index.js +function passThrough(v) { return v } + function Binding(name){ this.name = name this.value = undefined this.inputs = [] this.listeners = [] - this.formatter = undefined + this.parser = undefined + this.formatter = passThrough } @@ -22,7 +25,7 @@ Binding.prototype.addInput = function(el) { if (this.value === undefined) { this.value = el.value } else { - input.el.value = this.value + input.el.value = this.formatter(this.value) } el.addEventListener('input', _onInput, {passive:true}) } @@ -39,8 +42,8 @@ Binding.prototype.addListener = function(listener) { Binding.prototype.setValue = function(nextval, origin) { // console.log('Binding.setValue nextval:', nextval, {origin}) var prevval = this.value - if (this.formatter) { - nextval = this.formatter(nextval, prevval) + if (this.parser) { + nextval = this.parser(nextval, prevval) } if (this.value === nextval) { return @@ -49,7 +52,7 @@ Binding.prototype.setValue = function(nextval, origin) { this.value = nextval this.inputs.forEach(function(input) { if (input.el !== origin) { - input.el.value = nextval + input.el.value = binding.formatter(nextval) } }) this.listeners.forEach(function(listener) { @@ -106,6 +109,11 @@ Bindings.prototype.setValue = function(name, value) { binding.setValue(value) } +Bindings.prototype.setFormatter = function(name, formatter) { + var binding = this.getBinding(name) + binding.formatter = formatter || passThrough +} + Bindings.prototype.value = function(name, defaultValue) { var binding = this.bindings[name] @@ -125,11 +133,11 @@ function fmt_int(nextval, prevval) { // configure is convenience function for setting value, adding a -// listener and associating a formatter with a binding. +// listener and associating a parser with a binding. // If a listener and a value is provided, the value is set and the listener // is immediately invoked. // -Bindings.prototype.configure = function(name, value, formatter, listener) { +Bindings.prototype.configure = function(name, value, parser, listener) { var binding = this.getBinding(name) if (listener) { binding.addListener(listener) @@ -137,23 +145,23 @@ Bindings.prototype.configure = function(name, value, formatter, listener) { if (value !== undefined && value !== null) { binding.setValue(value) } - if (formatter) { - if (typeof formatter == 'string') { - switch (formatter) { + if (parser) { + if (typeof parser == 'string') { + switch (parser) { case 'number': case 'float': - formatter = fmt_float; break; + parser = fmt_float; break; case 'int': case 'integer': - formatter = fmt_int; break; + parser = fmt_int; break; default: - throw new Error('unknown formatter "' + formatter + '"') + throw new Error('unknown parser "' + parser + '"') } - } else if (typeof formatter != 'function') { - throw new Error('formatter should be a string or function') + } else if (typeof parser != 'function') { + throw new Error('parser should be a string or function') } - binding.formatter = formatter + binding.parser = parser } } diff --git a/docs/favicon.png b/docs/res/favicon.png Binary files differindex 5caeaf04a..5caeaf04a 100644 --- a/docs/favicon.png +++ b/docs/res/favicon.png diff --git a/docs/res/graphplot.js b/docs/res/graphplot.js new file mode 100644 index 000000000..b06f67f16 --- /dev/null +++ b/docs/res/graphplot.js @@ -0,0 +1,239 @@ + +function GraphPlot(canvas) { + this.canvas = canvas + const g = canvas.getContext('2d') + if (g == null) { + throw new Error('failed to acquire 2d context') + } + + this.width = 0 // dp + this.height = 0 // dp + this.widthPx = 0 // px + this.heightPx = 0 // px + this.pixelRatio = 1 + this.g = g + this.dataSegments = [] + this.axes = { + x0: .5, // % from left to x=0 + y0: .5, // % from top to y=0 + scalex: 40, // pixels from x=0 to x=1 + scaley: 40, // pixels from y=0 to y=1 + negativeX: true, + } + + if (!this.autosize()) { + this.setSize(256, 256) + } +} + +GraphPlot.prototype.autosize = function() { + try { + this.canvas.width = null + this.canvas.height = null + this.canvas.style.width = null + this.canvas.style.height = null + var cs = window.getComputedStyle(this.canvas) + var width = parseFloat(cs.width) + var height = parseFloat(cs.height) + this.setSize(width, height) + return true + } catch (err) { + if (typeof console != 'undefined' && console.warn) { + console.warn('GraphPlot.autosize failed: ' + err) + } + } + return false +} + +// setOrigin sets the origin of axis x and y +// The values should be in the range [0-1] and maps to the extremes +// of the canvas. +// +GraphPlot.prototype.setOrigin = function(x, y) { + var p = this + p.axes.x0 = x + p.axes.y0 = y +} + +// setScale sets the value scale for x and y axis. +// The values should be provided as display points. +// +GraphPlot.prototype.setScale = function(x, y) { + var p = this + if (y === undefined) { + y = x + } + p.axes.scalex = x + p.axes.scaley = y +} + +// setSize sets the size of canvas in display points +// +GraphPlot.prototype.setSize = function(width, height) { + var p = this + p.width = width + p.height = height + const el = p.canvas, g = p.g + p.pixelRatio = window.devicePixelRatio || 1 + if (p.pixelRatio != 1) { + el.width = p.widthPx = width * p.pixelRatio + el.height = p.heightPx = height * p.pixelRatio + g.scale(p.pixelRatio, p.pixelRatio) + } else { + el.width = p.widthPx = width + el.height = p.heightPx = height + g.scale(1, 1) + } + el.style.width = `${width}px` + el.style.height = `${height}px` +} + + +GraphPlot.prototype.renderAxes = function() { + var p = this + , g = p.g + , x0 = Math.round(p.axes.x0 * p.widthPx) / p.pixelRatio + , y0 = Math.round(p.axes.y0 * p.heightPx) / p.pixelRatio + + g.beginPath() + g.strokeStyle = "rgb(0, 0, 0, 0.2)" + if (y0 > 0 && y0 < p.width) { + g.moveTo(0, y0); g.lineTo(p.width, y0) // X axis + } + if (x0 > 0 && x0 < p.height) { + g.moveTo(x0, 0); g.lineTo(x0, p.height) // Y axis + } + g.stroke() +} + + +// plotf plots an arbitrary function on the graph +// +GraphPlot.prototype.plotf = function(f, color) { + var p = this + , g = p.g + , w = p.width + , h = p.height + , x0 = p.axes.x0 * p.width + , y0 = p.axes.y0 * p.height + , x = 0 + , y = 0 + , dx = 4 / p.pixelRatio // smaller means finer curves and more CPU + , scalex = p.axes.scalex * w + , scaley = p.axes.scaley * h + , iMax = Math.round((w - x0) / dx) + , iMin = p.axes.negativeX ? Math.round(-x0 / dx) : 0 + + g.beginPath() + g.lineWidth = 1 + g.strokeStyle = color || "rgb(0, 0, 0, 0.8)" + + for (var i = iMin; i <= iMax; i++) { + x = dx * i + y = f(x / scalex) * scaley + if (i == iMin) { + g.moveTo(x0 + x, y0 - y) + } else { + g.lineTo(x0 + x, y0 - y) + } + } + + g.stroke() +} + + +// plotLines draws straight lines between a collection of points +// +GraphPlot.prototype.plotLine = function(points, color) { + var p = this + , g = p.g + , x0 = p.axes.x0 * p.width + , y0 = p.axes.y0 * p.height + , x = 0 + , y = 0 + , scalex = p.axes.scalex * p.width + , scaley = p.axes.scaley * p.height + , pt + + g.beginPath() + g.lineWidth = 1 + g.strokeStyle = color || "rgb(0, 0, 0, 0.8)" + + var i = 0 + for (; i < points.length; i++) { + pt = points[i] + x = pt[0] * scalex + y = pt[1] * scaley + if (i == 0) { + g.moveTo(x0 + x, y0 - y) + } else { + g.lineTo(x0 + x, y0 - y) + } + } + + g.stroke() +} + + +// plotPoints draws points +// +GraphPlot.prototype.plotPoints = function(points, color) { + var p = this + , g = p.g + , x0 = p.axes.x0 * p.width + , y0 = p.axes.y0 * p.height + , x = 0 + , y = 0 + , scalex = p.axes.scalex * p.width + , scaley = p.axes.scaley * p.height + , pt + , i = 0 + + g.fillStyle = color || "rgb(0, 0, 0, 0.8)" + + for (; i < points.length; i++) { + pt = points[i] + x = x0 + pt[0] * scalex + y = y0 - pt[1] * scaley + g.beginPath() + g.arc(x, y, 3, 0, Math.PI + (Math.PI * 2) / 2, false) + g.fill() + } +} + + +GraphPlot.prototype.clear = function() { + var p = this + p.g.clearRect(0, 0, p.width, p.height) + p.renderAxes() +} + + +GraphPlot.prototype.renderDemo = function() { + var p = this + , g = p.g + , dpscale = p.pixelRatio + , w = p.widthPx + , h = p.heightPx + + p.clear() + + p.plotf( + function(x) { return Math.sin(x) }, + 'blue' + ) + + p.plotf( + function(x) { return Math.cos(3*x) }, + 'hotpink' + ) + + // var scale = p.height / 4 + // g.moveTo(0, scale) + // var i, sine, lines = 200, frag = p.width / lines + // for (i = 0; i < lines; i++) { + // sine = Math.sin(i / scale * 2) * scale + // g.lineTo(i * frag, -sine + scale) + // } + // g.stroke() +} diff --git a/docs/samples/index.css b/docs/samples/index.css new file mode 100644 index 000000000..2203be989 --- /dev/null +++ b/docs/samples/index.css @@ -0,0 +1,243 @@ +body { + padding-bottom: 0; + background: white; +} + +.row.footer h2 { + margin:0; + text-align:center; +} + +livesample { + display: block; + color: #111; + outline: none; + padding-left: 20px; + border-left: 2px solid transparent; + margin-left:-22px; + margin-top: 1em; + margin-bottom: 1.6em; +} +livesample:hover { + /*color: rgb(3, 102, 214);*/ + border-left-color: rgb(3, 102, 214); +} +livesample:focus { + border-left-color: #eee; +} +livesample > p { + margin-top: 0; +} +livesample.s1 { + padding-left: 16px; + letter-spacing: -0.01em; + font-size: 5em; + font-weight: 600; + line-height: 1.1; + margin-top: 0; + margin-bottom: 0.3em; +} +livesample.s2 { + max-width: 400px; + font-size: 1em; +} +livesample.s3 { + font-size: 13px; + line-height: 18px; +} + livesample.s3 b, livesample.s3 strong { + font-weight:500; + color: black; + } + +livesample.col3 { + -moz-column-width: 20em; + -moz-columns: 20em; + -webkit-columns: 20em; + columns: 20em; + + -moz-column-gap: 2em; + -webkit-column-gap: 2em; + column-gap: 2em; +} +livesample.col2 { + -moz-column-count: 2; + -webkit-column-count: 2; + column-count: 2; +} + +.font-style-regular { font-weight:400 !important; font-style:normal !important; } +.font-style-italic { font-weight:400 !important; font-style:italic !important; } +.font-style-medium { font-weight:500 !important; font-style:normal !important; } +.font-style-medium-italic { font-weight:500 !important; font-style:italic !important; } +.font-style-bold { font-weight:700 !important; font-style:normal !important; } +.font-style-bold-italic { font-weight:700 !important; font-style:italic !important; } +.font-style-black { font-weight:900 !important; font-style:normal !important; } +.font-style-black-italic { font-weight:900 !important; font-style:italic !important; } + +div.live { + margin-top:1em; + margin-bottom:100px; + padding-bottom:20px; + border-bottom: 1px solid #ddd; +} + div.live .learn-more { + margin-top:40px; + user-select: none; + } + div.controls { + position: absolute; + right: 0; + top: 150px; + width: 250px; + padding: 10px 0; + /*background:#eee;*/ + opacity:0.3; + transition: 90ms opacity cubic-bezier(0.25, 0.47, 0.44, 0.93); + /*border:1px solid #bbb;*/ + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + border-right:none; + display: flex; + flex-direction: column; + overflow: hidden; + font-size: 13px; + } + div.controls:hover { + opacity:1; + background:#f5f5f5; + border-color: transparent; + } + div.controls .control { + display: flex; + justify-content: space-between; + align-items: center; + overflow: hidden; + min-height: 30px; + margin: 0 16px; + } + div.controls .control > * { + flex: 1 1 auto; + margin:0; + margin-right: 16px; + box-sizing: border-box; + } + div.controls .control > :last-child { + margin-right: 0; + } + div.controls .control > select { + min-width: 6em; + align-items: center; + justify-content: center; + } + div.controls .control > input, + div.controls .control > select { + width: 0; + outline: none; + } + div.controls .control > input[type="number"], + div.controls .control > input[type="text"] { + background: none; + border: none; + padding: 4px 0; + font-size: inherit; + /*border-radius: 2px;*/ + } + div.controls .control > input[type="number"] { + max-width: 48px; + text-align: right; + -moz-font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; + -ms-font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; + -o-font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; + -webkit-font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; + font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; + } + div.controls .control > input[type=number]::-webkit-inner-spin-button, + div.controls .control > input[type=number]::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } + div.controls .control > input[type="range"] { + /*max-width: 80%;*/ + flex: 1 1 auto; + display: block; + } + div.controls .control > img.icon, + div.controls .control > label { + font-family: georgia, serif; + font-style: italic; + color: black; + width: 16px; + height: 16px; + flex: 0 0 auto; + margin-right: 16px; + opacity: 0.6; + } + div.controls canvas { + height: 200px; + } + div.controls .control.info, + div.controls canvas { + transition: 390ms opacity cubic-bezier(0.25, 0.47, 0.44, 0.93); + opacity: 0; + } + div.controls:hover .control.info, + div.controls:hover canvas { + opacity: 1; + } + + +/* narrow windows */ +@media only screen and (max-width: 1200px) { + div.controls { + width: 210px; + font-size: 12px; + } +} +@media only screen and (max-width: 1024px) { + div.controls { + width: 140px; + font-size: 11px; + } + div.controls canvas { + display: none; + } + div.controls .control.info { + margin-top: 0.5em; + margin-bottom: 0.5em; + } + div.controls .control > input[type="range"] { + width: 0; + flex: 0 1 0%; + display: none; + } + div.controls .control > input[type="number"] { + max-width: 100%; + flex: 1 1 auto; + } +} +@media only screen and (max-width: 740px) { + livesample.s1 { + font-size:4.5em; + } + div.controls { + display: none; + } +} +@media only screen and (max-width: 565px) { + livesample.s1 { + font-size:4em; + } +} +@media only screen and (max-width: 414px) { + livesample.s1 { + font-size:3.4em; + } +} + +.sample-images img, .sample-images svg { + margin: 100px 0; +} +.sample-images > img:first-child, .sample-images > svg:first-child { + margin-top:50px; +} diff --git a/docs/samples/index.html b/docs/samples/index.html index 08de84f72..a56b6aa60 100644 --- a/docs/samples/index.html +++ b/docs/samples/index.html @@ -1,300 +1,73 @@ -<!DOCTYPE HTML> -<html lang="en" prefix="og: http://ogp.me/ns#"> - <head> - <meta charset="utf-8"> - <title>Inter UI font family</title> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta http-equiv="X-UA-Compatible" content="IE=edge"> - <meta property="og:title" content="Inter UI font family"> - <meta property="twitter:title" content="Inter UI font family"> - <meta property="description" content="Inter UI is a new typeface optimized for computer user interfaces"> - <meta property="og:description" content="Inter UI is a new typeface optimized for computer user interfaces"> - <meta property="twitter:description" content="Inter UI is a new typeface optimized for computer user interfaces"> - <meta property="twitter:card" content="summary"> - <meta property="twitter:site" content="@rsms"> - <meta property="twitter:creator" content="@rsms"> - <meta property="og:image" content="https://rsms.me/inter/res/poster.png"> - <meta property="twitter:image" content="https://rsms.me/inter/res/poster.png"> - <meta property="fb:app_id" content="38027689216"> - <meta property="og:url" content="https://rsms.me/inter/"> - <meta property="og:site_name" content="rsms.me"> - <meta property="og:type" content="product"> - <meta property="og:locale" content="en_US" /> - <meta name="format-detection" content="telephone=no"> - <link rel="icon" type="image/png" href="../favicon.png" /> - <link href="../inter-ui.css?v=2.5" rel="stylesheet"> - <link href="../index.css?v=5" rel="stylesheet"> - <style type="text/css"> -body { - padding-bottom: 0; - background: white; -} - -.row.footer h2 { - margin:0; - text-align:center; -} - -/*.row.menu { - background: white; -}*/ - -livesample { - display: block; - color: #111; - outline: none; - padding-left: 20px; - border-left: 2px solid transparent; - margin-left:-22px; - margin-top: 1em; - margin-bottom: 1.6em; -} -livesample:hover { - /*color: rgb(3, 102, 214);*/ - border-left-color: rgb(3, 102, 214); -} -livesample:focus { - border-left-color: #eee; -} -livesample > p { - margin-top: 0; -} -livesample.s1 { - padding-left: 16px; - letter-spacing: -0.005em; - font-size: 5em; - font-weight: 600; - line-height: 1.1; - margin-top: 0; - margin-bottom: 0.3em; -} -livesample.s2 { - max-width: 400px; - font-size: 1em; -} -livesample.s3 { - font-size: 13px; - line-height: 18px; -} - livesample.s3 b, livesample.s3 strong { - font-weight:500; - color: black; - } - -livesample.col3 { - -moz-column-width: 20em; - -moz-columns: 20em; - -webkit-columns: 20em; - columns: 20em; - - -moz-column-gap: 2em; - -webkit-column-gap: 2em; - column-gap: 2em; -} -livesample.col2 { - -moz-column-count: 2; - -webkit-column-count: 2; - column-count: 2; -} - -.font-style-regular { font-weight:400 !important; font-style:normal !important; } -.font-style-italic { font-weight:400 !important; font-style:italic !important; } -.font-style-medium { font-weight:500 !important; font-style:normal !important; } -.font-style-medium-italic { font-weight:500 !important; font-style:italic !important; } -.font-style-bold { font-weight:700 !important; font-style:normal !important; } -.font-style-bold-italic { font-weight:700 !important; font-style:italic !important; } -.font-style-black { font-weight:900 !important; font-style:normal !important; } -.font-style-black-italic { font-weight:900 !important; font-style:italic !important; } - -div.live { - margin-top:1em; - margin-bottom:100px; - padding-bottom:100px; - border-bottom: 1px solid #ddd; -} - div.controls { - position: absolute; - right: 0; - top: 150px; - width: 220px; - padding: 10px 16px; - /*background:#eee;*/ - opacity:0.3; - border:1px solid #bbb; - border-top-left-radius: 5px; - border-bottom-left-radius: 5px; - border-right:none; - display: flex; - flex-direction: column; - overflow: hidden; - } - div.controls:hover { - opacity:1; - background:#f5f5f5; - border-color: transparent; - } - div.controls .control { - display: flex; - justify-content: space-between; - align-items: center; - overflow: hidden; - height:30px; - } - div.controls .control > * { - /*max-width: 50%;*/ - flex: 1 1 auto; - margin:0; - margin-right: 16px; - box-sizing: border-box; - } - div.controls .control > :last-child { - margin-right: 0; - } - div.controls .control > select { - min-width: 6em; - align-items: center; - justify-content: center; - } - div.controls .control > input, - div.controls .control > select { - width: 0; - outline: none; - } - div.controls .control > input[type="number"], - div.controls .control > input[type="text"] { - background: none; - border: none; - padding: 4px 0; - font-size: 13px; - /*border-radius: 2px;*/ - } - div.controls .control > input[type="number"] { - max-width: 60px; - text-align: right; - -moz-font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; - -ms-font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; - -o-font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; - -webkit-font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; - font-feature-settings: 'calt' 1, 'zero' 1, 'tnum' 1; - } - div.controls .control > input[type="range"] { - /*max-width: 80%;*/ - flex: 1 1 auto; - display: block; - } - div.controls .control > img.icon { - width: 16px; - height: 16px; - flex: 0 0 auto; - margin-right: 16px; - opacity: 0.8; - } - - /*div.controls .control > input.foo { - background-color: hotpink; - border:none; - border-radius: 90px; - }*/ - - -/* narrow windows */ -@media only screen and (max-width: 1200px) { - div.live div.controls { - width: 200px; - } -} -@media only screen and (max-width: 1024px) { - div.live div.controls { - width: 100px; - } - div.controls .control > input[type="range"] { - width: 0; - flex: 0 1 0%; - display: none; - } - div.controls .control > input[type="number"] { - max-width: 100%; - flex: 1 1 auto; - } -} -@media only screen and (max-width: 740px) { - livesample.s1 { - font-size:4.5em; - } - div.live div.controls { - display: none; - } -} -@media only screen and (max-width: 565px) { - livesample.s1 { - font-size:4em; - } -} -@media only screen and (max-width: 414px) { - livesample.s1 { - font-size:3.4em; - } -} - </style> - </head> - <body> - - <div class="row menu"> - <ul class="menu"> - <li class="home"><a href="../">Inter UI</a></li> - <li><a class="download-link" - href="https://github.com/rsms/inter/releases/latest/" - >Download</a></li> - <li><a href="/inter/samples/" class="active">Samples</a></li> - <li><a href="../lab/">Playground</a></li> - <li><a href="https://github.com/rsms/inter/">Source</a></li> - </ul> +--- +layout: default +title: Samples +--- +{% + +capture url_root + %}{% if site.safe == false %}/{% else %}/inter/{% endif +%}{% +endcapture %}{% + +for file in site.static_files %}{% + assign _path = file.path | remove_first: "/inter" %}{% + if _path == "/samples/index.css" %}{% + assign index_css_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% + elsif _path == "/res/bindings.js" %}{% + assign bindings_js_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% + elsif _path == "/res/graphplot.js" %}{% + assign graphplot_js_v = file.modified_time | date: "%Y%m%d%H%M%S" %}{% + endif %}{% +endfor + +%} +<link rel="stylesheet" href="index.css?v={{ index_css_v }}"> +<script src="{{url_root}}res/bindings.js?v={{ bindings_js_v }}"></script> +<script src="{{url_root}}res/graphplot.js?v={{ graphplot_js_v }}"></script> + +<div class="row"><div> + <div class="live"> + + <div class="controls"> + <div class="control"> + <img title="Style" class="icon" src="icons/style.svg"> + <select data-binding="style"> + <option value="regular" default>Regular</option> + <option value="italic">Italic</option> + <option value="medium" default>Medium</option> + <option value="medium-italic">Medium Italic</option> + <option value="bold" default>Bold</option> + <option value="bold-italic">Bold Italic</option> + <option value="black" default>Black</option> + <option value="black-italic">Black Italic</option> + </select> + </div> + <div class="control"> + <img title="Size" class="icon" src="icons/font-size.svg"> + <input type="range" min="8" max="100" step="1" data-binding="font-size"> + <input type="number" min="4" max="400" step="1" data-binding="font-size"> + </div> + <div class="control"> + <img title="Letter spacing in EM" class="icon" src="icons/letter-spacing.svg"> + <input type="range" min="-0.05" max="0.06" step="0.001" data-binding="letter-spacing"> + <input type="number" min="-0.15" max="1" step="0.001" data-binding="letter-spacing"> + </div> + <canvas class="graphplot">Canvas not Supported</canvas> + <div class="control info"> + <a href="{{url_root}}dynmetrics/">Learn about Dynamic Metrics</a> + </div> </div> - <div class="row white"><div> - <div class="live"> - - <div class="controls"> - <div class="control"> - <img title="Style" class="icon" src="icons/style.svg"> - <select data-binding="style"> - <option value="regular" default>Regular</option> - <option value="italic">Italic</option> - <option value="medium" default>Medium</option> - <option value="medium-italic">Medium Italic</option> - <option value="bold" default>Bold</option> - <option value="bold-italic">Bold Italic</option> - <option value="black" default>Black</option> - <option value="black-italic">Black Italic</option> - </select> - </div> - <div class="control"> - <img title="Size" class="icon" src="icons/font-size.svg"> - <input type="range" min="8" max="100" step="1" data-binding="font-size"> - <input type="number" min="4" max="400" step="1" data-binding="font-size"> - </div> - <div class="control"> - <img title="Letter spacing in EM" class="icon" src="icons/letter-spacing.svg"> - <input type="range" min="-0.05" max="0.06" step="0.001" data-binding="letter-spacing"> - <input type="number" min="-0.15" max="1" step="0.001" data-binding="letter-spacing"> - </div> - <!-- <div class="control"> - <img class="icon" src="icons/font-size.svg"> - <input type="text" class="foo" data-binding="foo"> - <input type="text" class="foo" data-binding="foo"> - </div> --> - </div> + <livesample contenteditable class="s1"> + Fabulous typography encountering spring + </livesample> - <livesample contenteditable class="s1"> - Fabulous typography encountering spring - </livesample> + <livesample contenteditable class="s2"> + The user interface (UI), in the industrial design field of human-computer + interaction, is the space where interactions between humans and machines occur. + </livesample> - <livesample contenteditable class="s2"> - The user interface (UI), in the industrial design field of human-computer - interaction, is the space where interactions between humans and machines occur. - </livesample> - - <livesample contenteditable class="s3 col3"> + <livesample contenteditable class="s3 col3"> <p><b>Fire Island Beach</b> is a barrier of sand, stretching for twenty miles along the south coast of Long Island, and separating the Great South Bay from the Atlantic ocean. @@ -350,89 +123,67 @@ When the tide is on the right moon and the wind has blown a gale from the southeast, the strand is entirely submerged, and people upon the main shore three miles away can see the surf breaking over the Beach hills. -</p><p> -Such a riot of sea and wind strews the whole extent of beach with -whatever has been lost or thrown overboard, or torn out of sunken ships. -Many a man has made a good week’s work in a single day by what he has -found while walking along the Beach when the surf was down. -</p><p> -“The Captain” knew all this and had patrolled that Beach scores of -times. -</p><p> -Ten years had passed since the first time which laid the habit of -wandering along the surf-shore apparently in search of whatever the sea -had cast up. Sometimes a spar, sometimes sheets of copper torn from a -wreck and carried by a high surf far along the strand, sometimes a -vessel’s gilded name, at other times only scattered drift-wood were the -rewards of these lonely walks. </p> - </livesample> - </div> - - <p class="sample-images"> - <img src="img/01.png" srcset="img/01@2x.png 2x" width="888"> - <img src="img/02.png" srcset="img/02@2x.png 2x" width="888"> - <!-- <img src="img/02.svg" width="888"> --> - <img src="img/03.png" srcset="img/03@2x.png 2x" width="888"> - <img src="img/04.png" srcset="img/04@2x.png 2x" width="888"> - <img src="img/05.png" srcset="img/05@2x.png 2x" width="888"> - <img src="img/dark-phone.jpg" srcset="img/dark-phone@2x.jpg 2x" width="888"> - <img src="img/06.png" srcset="img/06@2x.png 2x" width="888"> - <img src="img/07.png" srcset="img/07@2x.png 2x" width="888"> - <img src="img/08.png" srcset="img/08@2x.png 2x" width="888"> - <img src="img/09.png" srcset="img/09@2x.png 2x" width="888"> - <img src="img/10.png" srcset="img/10@2x.png 2x" width="888"> - <img src="img/11.png" srcset="img/11@2x.png 2x" width="888"> - <img src="img/12.png" srcset="img/12@2x.png 2x" width="888"> - <img src="img/13.png" srcset="img/13@2x.png 2x" width="888"> - <img src="img/14.png" srcset="img/14@2x.png 2x" width="888"> - <img src="img/15.png" srcset="img/15@2x.png 2x" width="888"> - </p> - <p style="text-align:center"> - <a href="https://www.figma.com/file/WmU5NWr52bnUcqv5os0V4sWi/" class="plain">Open these samples in Figma</a> - </p> - </div></div> - - <script src="../index.js?v=2"></script> - <script src="bindings.js"></script> - <script type="text/javascript">(function(){ - - - -// InterUIDynamicTracking takes the font size in points or pixels and returns -// the compensating tracking in EM. + </livesample> + <p class="learn-more"> + + <!-- <a href="{{url_root}}dynmetrics/">Learn about Dynamic Metrics</a> --> + </p> + </div> + + <p class="sample-images"> + <img src="img/01.png" srcset="img/01@2x.png 2x" width="888"> + <img src="img/02.png" srcset="img/02@2x.png 2x" width="888"> + <!-- <img src="img/02.svg" width="888"> --> + <img src="img/03.png" srcset="img/03@2x.png 2x" width="888"> + <img src="img/04.png" srcset="img/04@2x.png 2x" width="888"> + <img src="img/05.png" srcset="img/05@2x.png 2x" width="888"> + <img src="img/dark-phone.jpg" srcset="img/dark-phone@2x.jpg 2x" width="888"> + <img src="img/06.png" srcset="img/06@2x.png 2x" width="888"> + <img src="img/07.png" srcset="img/07@2x.png 2x" width="888"> + <img src="img/08.png" srcset="img/08@2x.png 2x" width="888"> + <img src="img/09.png" srcset="img/09@2x.png 2x" width="888"> + <img src="img/10.png" srcset="img/10@2x.png 2x" width="888"> + <img src="img/11.png" srcset="img/11@2x.png 2x" width="888"> + <img src="img/12.png" srcset="img/12@2x.png 2x" width="888"> + <img src="img/13.png" srcset="img/13@2x.png 2x" width="888"> + <img src="img/14.png" srcset="img/14@2x.png 2x" width="888"> + <img src="img/15.png" srcset="img/15@2x.png 2x" width="888"> + </p> + <p style="text-align:center"> + <a + href="https://www.figma.com/file/WmU5NWr52bnUcqv5os0V4sWi/" + class="plain">Open these samples in Figma</a> + </p> +</div></div> + +<script type="text/javascript">(function(){ + + + +// InterUIDynamicTracking produces tracking in EM for the given font size // function InterUIDynamicTracking(fontSize, weightClass) { // if (!weightClass) { -- currently unused // weightClass = 400 // } // - // y = -0.01021241 + 0.3720623 * e ^ (-0.2808687 * x) - // [6-35] 0.05877 .. -0.0101309 (13==0; stops growing around 30-35) - // See https://gist.github.com/rsms/8efdbca5f8145a584ed08a7c3d6e5788 - // - return -0.01021241 + 0.3720623 * Math.pow(Math.E, (-0.2808687 * fontSize)) - - // y = 0.025 - (ln(x) * 0.01) - // return 0.025 - Math.log(fontSize) * 0.01 + var a = -0.0149, b = 0.298, c = -0.23; + return a + b * Math.pow(Math.E, (c * fontSize)) } - -function InterUIDynamicLeading(fontSize, weightClass) { - var lineHeight = Math.round(fontSize * 1.4) - // - // TODO - // - // console.log( - // 'lineHeight:', lineHeight, - // `(${Math.round(fontSize * 1.45)})`, - // ) - - return lineHeight +// InterUIDynamicLineHeight produces the line height for the given font size +// +function InterUIDynamicLineHeight(fontSize, weightClass) { + var l = 1.4 + return Math.round(fontSize * l) } var bindings = new Bindings() +var graph = new GraphPlot($('canvas.graphplot')) +graph.setOrigin(-0.2, 0.8) +graph.setScale(0.049, 5) var s2 = $('livesample.s2') @@ -443,22 +194,39 @@ function updateWidth() { s2.style.maxWidth = Math.round(w) + 'px' } +function updateTracking() { + var fontSize = bindings.value('font-size', 0) + var letterSpacing = InterUIDynamicTracking(fontSize, 400) + bindings.setValue('letter-spacing', letterSpacing) +} + +function updateGraph() { + graph.clear() + var fontSize = bindings.value('font-size', 0) + var letterSpacing = bindings.value('letter-spacing') + graph.plotf(function(x) { + return InterUIDynamicTracking(x, 400) + }) + var graphedFontSize = Math.min(24, fontSize) // clamp to [-inf,24] + graph.plotPoints([[graphedFontSize, letterSpacing]], '#000') +} + bindings.configure('letter-spacing', 0, 'float', function (letterSpacing) { s2.style.letterSpacing = letterSpacing + 'em' updateWidth() + updateGraph() +}) +bindings.setFormatter('letter-spacing', function(v) { + return v.toFixed(3) }) -bindings.configure('font-size', 18, 'int', function(fontSize, prevval) { +bindings.configure('font-size', 16, 'float', function(fontSize, prevval) { s2.style.fontSize = fontSize + 'px' updateWidth() + updateTracking() - var letterSpacing = InterUIDynamicTracking(fontSize, 400) - letterSpacing = parseFloat(letterSpacing.toFixed(3)) // lower precision - - var lineHeight = InterUIDynamicLeading(fontSize, 400) + var lineHeight = InterUIDynamicLineHeight(fontSize, 400) s2.style.lineHeight = lineHeight + 'px' - - bindings.setValue('letter-spacing', letterSpacing) }) bindings.configure('style', null, null, function (style) { @@ -478,8 +246,14 @@ bindings.configure('style', null, null, function (style) { bindings.bindAllInputs('div.live .control input') bindings.bindAllInputs('div.live .control select') - - - })();</script> - </body> -</html> +// resize canvas when window resizes +var resizeDebounceTimer = null +window.addEventListener('resize', function(){ + clearTimeout(resizeDebounceTimer) + resizeDebounceTimer = setTimeout(function(){ + graph.autosize() + updateGraph() + }, 500) +}, {passive:true, capture:false}) + +})();</script> diff --git a/docs/serve.sh b/docs/serve.sh deleted file mode 100755 index b10c7649f..000000000 --- a/docs/serve.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -set -e -cd "$(dirname "$0")" - -if [ ! -s lab/fonts ]; then - ln -s ../../build/dist lab/fonts -fi - -if (which caddy >/dev/null); then - caddy_args=(\ - -host localhost \ - "bind localhost" \ - "mime .woff2 font/woff2" \ - "mime .woff application/font-woff" \ - ) - caddy "${caddy_args[@]}" -elif (which servedir >/dev/null); then - servedir -else - echo "Can not find 'caddy' nor 'servedir' in PATH." >&2 - echo "Install caddy from brew, apt or https://caddyserver.com/download" - echo "or install servedir with 'npm install -g secure-servedir'" - exit 1 -fi |