website: major update

This commit is contained in:
Rasmus Andersson 2018-02-20 01:38:51 -08:00
parent 761638ef42
commit 9f367901ef
22 changed files with 2139 additions and 1030 deletions

1
.gitignore vendored
View file

@ -17,6 +17,7 @@ nohup.out
build
/_*
/docs/lab/fonts
/docs/_site
src/FontInspector.html
src/svg

View file

@ -159,13 +159,13 @@ install_otf: all_otf
install: install_otf
geninfo: docs/info.json docs/lab/glyphinfo.json docs/glyphs/metrics.json
geninfo: docs/_data/fontinfo.json docs/lab/glyphinfo.json docs/glyphs/metrics.json
src/glyphorder.txt: src/Inter-UI-Regular.ufo/lib.plist src/Inter-UI-Black.ufo/lib.plist src/diacritics.txt misc/gen-glyphorder.py
misc/gen-glyphorder.py src/Inter-UI-*.ufo > src/glyphorder.txt
docs/info.json: misc/fontinfo.py docs/font-files/Inter-UI-*.otf
misc/fontinfo.py -pretty docs/font-files/Inter-UI-Regular.otf > docs/info.json
docs/_data/fontinfo.json: misc/fontinfo.py docs/font-files/Inter-UI-*.otf
misc/fontinfo.py -pretty docs/font-files/Inter-UI-Regular.otf > docs/_data/fontinfo.json
docs/lab/glyphinfo.json: _local/UnicodeData.txt src/glyphorder.txt src/fontbuild.cfg misc/gen-glyphinfo.py
misc/gen-glyphinfo.py -ucd _local/UnicodeData.txt \

10
docs/_config.yml Normal file
View file

@ -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

View file

@ -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"
}
}
}
]

View file

@ -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 %}

View file

@ -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>

View file

@ -1,6 +1,6 @@
#!/bin/sh
set -e
cd "$(dirname "$0")"
cd "$(dirname "$0")/.."
pushd res >/dev/null

9
docs/_scripts/serve.sh Executable file
View file

@ -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

262
docs/dynmetrics/index.css Normal file
View file

@ -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;
}
}

522
docs/dynmetrics/index.html Normal file
View file

@ -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 &nbsp; 0.0 &nbsp; ( 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 weeks 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>

View file

@ -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,9 +2210,8 @@
<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>
<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
@ -2232,9 +2219,9 @@
<kbd></kbd><kbd></kbd> on your keyboard.
Click on a glyph to see more details about it.
</p>
</div></div>
</div></div>
<div id="glyphs">
<div id="glyphs">
<div id="single-info" style="display:none">
<ul>
<li>Glyph name: <span class="name"></span></li>
@ -2246,13 +2233,11 @@
<li><a class="svgFile">&darr; Download SVG file</a></li>
</ul>
</div>
</div>
</div>
<div class="row kerning"><div>
<div class="row kerning"><div>
<h2 id="kerning"><a href="#kerning">Kerning</a></h2>
<div id="kerning-list"></div>
</div></div>
</div></div>
<script src="glyphs.js"></script>
</body>
</html>
<script src="glyphs.js?v={{ glyphs_js_v }}"></script>

View file

@ -1,45 +1,8 @@
<!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>
---
layout: default
---
<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>
<div class="row"><div>
<h1>The Inter UI font family</h1>
<p>
Inter UI is a typeface specially designed for user interfaces
@ -52,19 +15,19 @@
surrounding glyphs, slashed zero for when you need to disambiguate "0" from "o",
tabular numbers, etc.
</p>
</div></div>
</div></div>
<div class="row white" style="padding-bottom:0"><div>
<p id="samples" class="samples items">
<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></div>
<div class="row dark"><div>
<div class="row dark"><div>
<h2><a id="usage" href="#usage">How do I use it?</a></h2>
<p>
@ -82,15 +45,23 @@
<p>&nbsp;</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>&nbsp;</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></div>
<div class="row"><div>
<div class="row"><div>
<p>
There are currently four <a id="weights" href="#weights">weights</a>
</p>
@ -182,11 +153,11 @@
<p>&nbsp;</p>
<h2 class="banner"><a href="glyphs/">Browse all glyphs -></a></h2>
</div></div>
</div></div>
<div class="row-divider"></div>
<div class="row-divider"></div>
<div class="row"><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
@ -319,16 +290,14 @@
</ul>
</div></div>
</div></div>
<div class="row"><div>
<div class="row"><div>
<a href="https://twitter.com/rsms" class="plain">@rsms</a>
</div></div>
</div></div>
<script src="index.js?v=2"></script>
<script>
(function(){
<script>(function(){
// FAQ anchors
var av = document.querySelectorAll('ul.faq > li.q'), a, i, e, id, tn
@ -354,7 +323,4 @@
e.insertBefore(tn, e.firstChild)
}
})();
</script>
</body>
</html>
})();</script>

View file

@ -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');
})();

View file

@ -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;
@ -98,14 +98,20 @@ dem { /* de-emphasize */
opacity: 0.7;
}
num { /* number */
-moz-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 > * {
.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;
}*/
}

74
docs/res/base.js Normal file
View file

@ -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'])

View file

@ -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
}
}

View file

Before

Width:  |  Height:  |  Size: 700 B

After

Width:  |  Height:  |  Size: 700 B

Before After
Before After

239
docs/res/graphplot.js Normal file
View file

@ -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()
}

243
docs/samples/index.css Normal file
View file

@ -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;
}

View file

@ -1,257 +1,31 @@
<!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;
}
---
layout: default
title: Samples
---
{%
.row.footer h2 {
margin:0;
text-align:center;
}
capture url_root
%}{% if site.safe == false %}/{% else %}/inter/{% endif
%}{%
endcapture %}{%
/*.row.menu {
background: white;
}*/
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
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;
}
%}
<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>
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>
</div>
<div class="row white"><div>
<div class="row"><div>
<div class="live">
<div class="controls">
@ -278,11 +52,10 @@ div.live {
<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> -->
<canvas class="graphplot">Canvas not Supported</canvas>
<div class="control info">
<a href="{{url_root}}dynmetrics/">Learn about Dynamic Metrics</a>
</div>
</div>
<livesample contenteditable class="s1">
@ -350,23 +123,12 @@ 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 weeks 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
vessels gilded name, at other times only scattered drift-wood were the
rewards of these lonely walks.
</p>
</livesample>
<p class="learn-more">
&nbsp;
<!-- <a href="{{url_root}}dynmetrics/">Learn about Dynamic Metrics</a> -->
</p>
</div>
<p class="sample-images">
@ -389,50 +151,39 @@ rewards of these lonely walks.
<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>
<a
href="https://www.figma.com/file/WmU5NWr52bnUcqv5os0V4sWi/"
class="plain">Open these samples in Figma</a>
</p>
</div></div>
</div></div>
<script src="../index.js?v=2"></script>
<script src="bindings.js"></script>
<script type="text/javascript">(function(){
<script type="text/javascript">(function(){
// InterUIDynamicTracking takes the font size in points or pixels and returns
// the compensating tracking in EM.
// 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')
// 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>
</body>
</html>
})();</script>

View file

@ -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

View file

@ -7,6 +7,7 @@ import os
import sys
import argparse
import json
import re
from base64 import b64encode
from fontTools import ttLib
@ -288,6 +289,13 @@ def genFontInfo(fontpath, outputType, withGlyphs=True):
if 'subfamilyName' in nameDict:
info['name'] += '-' + nameDict['subfamilyName'].replace(' ', '')
if 'version' in nameDict:
version = nameDict['version']
v = re.split(r'[\s;]+', version)
if v and len(v) > 0:
version = v[0]
info['version'] = version
if outputType is not OUTPUT_TYPE_GLYPHLIST:
if len(nameDict):
info['names'] = nameDict
@ -425,7 +433,7 @@ def main():
args = argparser.parse_args()
fonts = {}
fonts = []
outputType = OUTPUT_TYPE_COMPLETE
if args.asGlyphList:
outputType = OUTPUT_TYPE_GLYPHLIST
@ -437,7 +445,7 @@ def main():
# internal cache that mixes up values for different fonts.
reload(sstruct)
font = genFontInfo(fontpath, outputType=outputType, withGlyphs=args.withGlyphs)
fonts[font['id']] = font
fonts.append(font)
n += 1
ostream = sys.stdout
@ -447,6 +455,7 @@ def main():
if args.prettyJson:
json.dump(fonts, ostream, sort_keys=True, indent=2, separators=(',', ': '))
sys.stdout.write('\n')
else:
json.dump(fonts, ostream, separators=(',', ':'))