summaryrefslogtreecommitdiff
path: root/docs/dynmetrics/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'docs/dynmetrics/index.html')
-rw-r--r--docs/dynmetrics/index.html684
1 files changed, 9 insertions, 675 deletions
diff --git a/docs/dynmetrics/index.html b/docs/dynmetrics/index.html
index 07cf908c9..2c9cc54cd 100644
--- a/docs/dynmetrics/index.html
+++ b/docs/dynmetrics/index.html
@@ -1,683 +1,17 @@
---
layout: default
-title: Dynamic Metrics
+title: 404 not found
+custom_html_header: |
+ <link rel="canonical" href="https://d.rsms.me/inter-website/v3/dynmetrics/">
+ <meta name="robots" content="noindex">
---
-{%
-
-if site.safe == false %}{%
-assign url_root = "/" %}{% else %}{%
-assign url_root = "/inter/" %}{% endif %}{%
-
-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>
+<div class="row"><div>
+ <h1>404 not found</h1>
<p>
- There's of course no absolute right or wrong when it comes to expressing
- yourself with typography, but Inter Dynamic Metrics provides guidelines
- for how to best use Inter.
- You simply provide the optical font size,
- and the tracking and line height is calculated for you through the following
- formula:
+ This page used to exist, but is no longer.<br>
</p>
<p>
- <formula>
- tracking =
- <const>a</const> + <const>b</const> ×
- <const title="Base of natural logarithm; ≈2.718">e</const><sup>(<const>c</const> × <const>z</const>)</sup>
- </formula>
- <!--formula>
- line height = <num data-binding="var-l">1.4</num> × <const>z</const>
- </formula-->
- <formula title="Values for Inter">
- <g><const title="Constant a">a</const> = <num data-binding="var-a">-0.0223</num></g> &nbsp;&nbsp;
- <g><const title="Constant b">b</const> = <num data-binding="var-b">0.185</num></g> &nbsp;&nbsp;
- <g><const title="Constant c">c</const> = <num data-binding="var-c">-0.1745</num></g> &nbsp;&nbsp;
- <g><const>z</const> = font size</g>
- </formula>
- </p>
- <p class="wide-window">
- The controls below can be used to play around with the
- <const>a</const>, <const>b</const> and <const>c</const> constants to discover
- how they affect tracking.
- </p>
- <p class="narrow-window">
- <small>View this on a larger screen to enable interactive control.</small>
+ You can visit an archived version of the old website:
+ <a href="https://d.rsms.me/inter-website/v3/dynmetrics/">https://d.rsms.me/inter-website/v3/dynmetrics/</a>
</p>
</div></div>
-
-<div class="white full-width row with-sidebar">
-
- <div class="samples">
- <p 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>
- <span contenteditable spellcheck="false" class="content">
- 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.
- </span>
- </p>
- </div>
-
- <div class="sidebar controls">
-
- <div class="control">
- <img title="Style" class="icon" src="icons/style.svg">
- <select data-binding="style">
- <option value="thin">Thin</option>
- <option value="extra-light">Extra Light</option>
- <option value="light">Light</option>
- <option value="regular" default selected>Regular</option>
- <option value="medium">Medium</option>
- <option value="semi-bold">Semi Bold</option>
- <option value="bold">Bold</option>
- <option value="extra-bold">Extra Bold</option>
- <option value="black">Black</option>
- <option disabled>————————————</option>
- <option value="thin-italic">Thin Italic</option>
- <option value="extra-light-italic">Extra Light Italic</option>
- <option value="light-italic">Light Italic</option>
- <option value="italic">Italic</option>
- <option value="medium-italic">Medium Italic</option>
- <option value="semi-bold-italic">Semi Bold Italic</option>
- <option value="bold-italic">Bold Italic</option>
- <option value="extra-bold-italic">Extra Bold Italic</option>
- <option value="black-italic">Black Italic</option>
- </select>
- </div>
- <div class="control">
- <img title="Base tracking" class="icon" src="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>
- <div class="control">
- <img title="Line height" class="icon" src="icons/line-height.svg">
- <input type="range" min="1" max="2" step="0.01" data-binding="var-l">
- <input type="number" min="1" max="2" step="0.01" data-binding="var-l">
- </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="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>
-
- <hr class="without-bottom-margin">
-
- <canvas class="graphplot">Canvas not Supported</canvas>
-
- <hr class="when-selection without-top-margin">
- <h3 class="when-selection">CSS</h3>
- <textarea class="when-selection" readonly id="code-output"></textarea>
-
- <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
-
-function round(num, prec) {
- return parseFloat(num.toFixed(prec))
-}
-
-// 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({
- // // 2018
- // 6: 0.021,
- // 7: 0.017,
- // 8: 0.013,
- // 9: 0.01,
- // 10: 0.007,
- // 11: 0.005,
- // 12: 0.002,
- // 13: 0,
- // 14: -0.002,
- // 15: -0.004,
- // 16: -0.005,
- // 17: -0.007,
- // 18: -0.008,
- // 20: -0.01,
- // 24: -0.013,
- // 30: -0.016,
- // 40: -0.02,
- // 80: -0.02,
-
- // 2019-02-02
- // 6: 0.066,
- // 7: 0.05,
- // 8: 0.036,
- // 9: 0.025,
- // 10: 0.015,
- // 11: 0.007,
- // 12: 0,
- // 13: -0.005,
- // 14: -0.01,
- // 15: -0.014,
- // 16: -0.017,
- // 17: -0.02,
- // 18: -0.022,
- // 20: -0.026,
- // 24: -0.03,
- // 30: -0.033,
- // 40: -0.034,
- // 80: -0.034,
-
- // // 2019-02-06
- // 6: 0.04,
- // 7: 0.032,
- // 8: 0.024,
- // 9: 0.017,
- // 10: 0.01,
- // 11: 0.005,
- // 12: 0,
- // 13: -0.004,
- // 14: -0.008,
- // 15: -0.011,
- // 16: -0.014,
- // 17: -0.017,
- // 18: -0.019,
- // 20: -0.023,
- // 24: -0.029,
- // 30: -0.034,
- // 40: -0.037,
- // 80: -0.038,
-
- // 2019-02-07
- 6: 0.043,
- 7: 0.032,
- 8: 0.024,
- 9: 0.016,
- 10: 0.01,
- 11: 0.005,
- 12: 0,
- 13: -0.0025,
- 14: -0.006,
- 15: -0.009,
- 16: -0.011,
- 17: -0.013,
- 18: -0.014,
- 20: -0.017,
- 24: -0.019,
- 30: -0.021,
- 40: -0.022,
- 80: -0.022,
-})
-
-
-// Variables for constants involved in Dynamic Metrics
-
-// var a = -0.012, b = 0.23, c = -0.21; // di=0.002514 on set-2018-02-18
-// var a = -0.013, b = 0.251, c = -0.222 // di=0.001742 on set-2018-02-18
-// var a = -0.015, b = 0.283, c = -0.23; // di=0.00221 on set-2018-02-18
-// var a = -0.0149, b = 0.298, c = -0.23; // di=0.000484 on set-2018-02-19
-// var a = -0.018, b = 0.21, c = -0.18; // di=0.000532 on set-2018-02-20
-// var a = -0.017, b = 0.202, c = -0.175; // 2018-09-28
-// var a = -0.02, b = 0.0755, c = -0.102 // 2019-02-02
-// var a = -0.038, b = 0.161, c = -0.12 // 2019-02-06
-var a = -0.0223, b = 0.185, c = -0.1745 // 2019-02-07
-
-
-var l = 1.4
-
-
-// _InterDynamicTracking is a version of InterDynamicTracking that
-// uses some global variables that are adjustable.
-//
-function _InterDynamicTracking(fontSize, weightClass) {
- // Note: weightClass is currently unused
- //
- // 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)
-}
-
-
-function InterDynamicLineHeight(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.contentEl = $('.content', 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()
-
- // listen for focus events on the editable content
- var s = this
- this.contentEl.addEventListener(
- 'focus',
- function(){ s.onReceivedFocus() },
- {passive:true, capture:false}
- )
- this.contentEl.addEventListener(
- 'blur',
- function(){ s.onLostFocus() },
- {passive:true, capture:false}
- )
-}
-
-Sample.prototype.onReceivedFocus = function() {}
-Sample.prototype.onLostFocus = function() {}
-
-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 + _InterDynamicTracking(fontSize, weightClass)
- this.lineHeight = InterDynamicLineHeight(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.cssProperties = function() {
- return [
- ['font-size', round(this.fontSize, 3) + 'px'],
- ['letter-spacing', round(this.tracking, 3) + 'em'],
- ['line-height', round(this.lineHeight, 3) + 'px'],
- ]
-}
-
-Sample.prototype.setText = function(text) {
- this.contentEl.innerText = text
- this.render()
-}
-
-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 samplesEl = $('.samples')
-var sampleTemplate
-var samples = [] // Sample[]
-var focusedSample = null // Sample | null
-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() {
- 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))
- samples.push(new Sample(80))
-
- // connect focus events
- var onSampleReceivedFocus = function() { setSelectedSample(this) }
- samples.forEach(function(s) {
- s.onReceivedFocus = onSampleReceivedFocus
- })
-
- // add to dom in one go
- addChildren(samplesEl, samples.map(function(s) { return s.rootEl }))
-}
-
-function setSelectedSample(sample) {
- if (focusedSample !== sample) {
- if (focusedSample) {
- focusedSample.rootEl.classList.remove('selected')
- }
- if (sample) {
- sample.rootEl.classList.add('selected')
- }
- focusedSample = sample
- updateSelection()
- }
-}
-
-function updateSample(sample) {
- sample.setFontSize(sample.fontSize) // updates derived values
- sample.render()
-}
-
-function updateSamples() {
- samples.forEach(updateSample)
- updateIdealMatches()
- updateGraphPlot()
- updateCodeView()
-}
-
-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(
- x => _InterDynamicTracking(x, weightClass),
- 'rgba(0, 0, 0, 0.5)'
- )
- if (focusedSample) {
- var graphedFontSize = Math.min(24, focusedSample.fontSize) // clamp to [-inf,24]
- graph.plotPoints([
- [graphedFontSize, focusedSample.tracking]
- ], 'rgb(45, 143, 255)')
- }
-}
-
-var codeOutput = $('#code-output')
-codeOutput.addEventListener('focus', function(ev) {
- ev.preventDefault()
- ev.stopPropagation()
- codeOutput.select()
-}, {passive:false,capture:true})
-
-codeOutput.addEventListener('pointerdown', function(ev) {
- // TODO: don't do this if codeOutput is focused
- ev.preventDefault()
- ev.stopPropagation()
- codeOutput.select()
- document.execCommand("copy")
- HUDNotification.show('Copied to clipboard')
-}, {passive:false,capture:true})
-
-function updateCodeView() {
- var s = ''
- if (focusedSample) {
- var props = focusedSample.cssProperties()
- props.forEach(function(prop, i) {
- var name = prop[0], value = prop[1]
- s += name + ': ' + value + ';'
- if (i != props.length-1) {
- s += '\n'
- }
- })
- }
- codeOutput.value = s
-}
-
-function updateSelection() {
- var controlsEl = $('.controls')
- if (focusedSample) {
- controlsEl.classList.add('has-selected-sample')
- } else {
- controlsEl.classList.remove('has-selected-sample')
- }
-
- updateGraphPlot()
- updateCodeView()
-}
-
-
-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 = samplesEl.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-semi-bold')
- cl.remove('font-style-semi-bold-italic')
- cl.remove('font-style-bold')
- cl.remove('font-style-bold-italic')
- cl.remove('font-style-extra-bold')
- cl.remove('font-style-extra-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('[data-binding]')
-
-// double-click base tracking to reset
-$('input[type="range"][data-binding="base-tracking"]').addEventListener(
- 'dblclick',
- function(ev) { bindings.setValue('base-tracking', 0) }
-)
-
-;[
- ['var-a',a],
- ['var-b',b],
- ['var-c',c],
- ['var-l',l],
- ['base-tracking', 0]
-].forEach(p => {
- let bindname = p[0], defval = p[1]
- $$('input[type="range"][data-binding="'+bindname+'"]').forEach(e => {
- e.addEventListener('dblclick', ev =>
- bindings.setValue(bindname, defval))
- })
-})
-
-// allow editing of ideal values
-idealValuesTextArea.addEventListener('input', function(ev) {
- setIdealValues(parseValues(idealValuesTextArea.value))
- updateSamples()
-})
-
-// listen for clicks onto "background", to deselect any selected sample
-document.body.addEventListener('pointerdown', function(ev){
- if (
- ev.target === document.body ||
- ev.target === samplesEl ||
- ev.target.classList && ev.target.classList.contains('row')
- ) {
- setSelectedSample(null)
- }
-})
-
-
-// start
-initSamples()
-updateSamples()
-
-})();</script>