{"id":13720674,"url":"https://github.com/Experience-Monks/opentype-layout","last_synced_at":"2025-05-07T12:33:04.208Z","repository":{"id":57156406,"uuid":"61648316","full_name":"Experience-Monks/opentype-layout","owner":"Experience-Monks","description":"word wraps and lays out Opentype.js glyphs","archived":false,"fork":false,"pushed_at":"2016-06-21T19:08:33.000Z","size":416,"stargazers_count":89,"open_issues_count":2,"forks_count":11,"subscribers_count":15,"default_branch":"master","last_synced_at":"2024-11-14T09:19:11.383Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://jam3.github.io/opentype-layout/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Experience-Monks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-06-21T16:09:52.000Z","updated_at":"2024-06-27T07:02:46.000Z","dependencies_parsed_at":"2022-09-05T01:01:02.382Z","dependency_job_id":null,"html_url":"https://github.com/Experience-Monks/opentype-layout","commit_stats":null,"previous_names":["experience-monks/opentype-layout","jam3/opentype-layout"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Experience-Monks%2Fopentype-layout","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Experience-Monks%2Fopentype-layout/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Experience-Monks%2Fopentype-layout/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Experience-Monks%2Fopentype-layout/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Experience-Monks","download_url":"https://codeload.github.com/Experience-Monks/opentype-layout/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224604525,"owners_count":17339152,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T01:01:06.737Z","updated_at":"2024-11-14T10:30:26.898Z","avatar_url":"https://github.com/Experience-Monks.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# opentype-layout\n\n[![experimental](http://badges.github.io/stability-badges/dist/experimental.svg)](http://github.com/badges/stability-badges)\n\nExperimental word-wrapping and layout for [Opentype.js](https://github.com/nodebox/opentype.js).\n\n\u003cimg src=\"http://i.imgur.com/Sq3WFJX.png\" width=\"50%\" /\u003e\n\n## Install\n\nBest used with npm and browserify. This should also work in Node.js and other environments.\n\n```sh\nnpm install opentype-layout --save\n```\n\n## Demo\n\n[Live Demo](https://jam3.github.io/opentype-layout/)\n\nThe demo shows Canvas2D vector text (red stroke) rendered on top of DOM/CSS (black fill). The demo reads the computed CSS style and converts units into the proper EM font units. Some lines also visualize some of the available metrics.\n\n[\u003cimg src=\"http://i.imgur.com/ThVDUtX.png\" width=\"50%\" /\u003e](https://jam3.github.io/opentype-layout/)\n\n## Example\n\nSee the [demo](./demo) folder for a complete example.\n\n```js\nvar opentype = require('opentype.js');\nvar computeLayout = require('opentype-layout');\n\nopentype.load('Font.ttf', function (err, font) {\n  if (err) throw err;\n\n  var fontSizePx = 72;\n  var text = 'Hello\\nWorld! This box should start word-wrapping!'\n  var scale = 1 / font.unitsPerEm * fontSizePx;\n\n  // Layout some text - notice everything is in em units!\n  var result = computeLayout(font, text, {\n    lineHeight: 2.5 * font.unitsPerEm, // '2.5em' in font units\n    width: 500 / scale // '500px' in font units\n  });\n\n  // Array of characters after layout\n  console.log(result.glyphs);\n\n  // Computed height after word-wrap\n  console.log(result.height);\n});\n```\n\n## Usage\n\n#### `layout = computeLayout(font, text, [opt])`\n\nComputes a new layout from the given Opentype.js `Font` interface and a `text` string.\n\nAll units should be in raw font units in the EM square, assuming a lower-left origin. For example, a `lineHeight` of `'2em'` should be passed as `2 * font.unitsPerEm`. It is up to the user to scale the results to a pixel/point size after the fact.\n\nOptions:\n\n- `width` the width of the box in font units, will cause word-wrapping (default `Infinity`)\n- `align` string alignment of the text within its `width` (default `'left'`)\n- `letterSpacing` the additional letter spacing in font units (default 0)\n- `lineHeight` the line height in font units as per CSS spec, default `1.175 * font.unitsPerEm` to match browsers\n- `start` the starting character index into `text` to layout, default 0\n- `end` the ending index into `text` to layout (exclusive), default `text.length`\n- `mode` can be 'pre' (maintain spacing), or 'nowrap' (collapse whitespace but only break on newline characters), otherwise defaults to normal word-wrap behaviour\n\nSee [word-wrapper](https://www.npmjs.com/package/word-wrapper) for details on how word wrapping is computed.\n\n## Metrics\n\nThe returned object has the following metrics.\n\n#### `layout.glyphs`\n\nThis provides an array of characters after layout, useful for rendering. Each element in the array has the following properties:\n\n```js\n{\n  position: [ x, y ],\n  data: { ... Opentype.js Glyph object ... },\n  index: charIndex,\n  row: lineIndex,\n  column: columnInLineIndex\n}\n```\n\nThe position is in raw font units.\n\n#### `layout.baseline`\n\nThis is the value from pen origin to the baseline of the last line of text in the layout.\n\n#### `layout.leading`\n\nThis is the `L` value in the [CSS line-height spec](https://www.w3.org/TR/CSS2/visudet.html#line-height). Divide this by two for the \"half-leading\", which tells you how far above the first ascender and below the last descender the text box extends to. \n\n#### `layout.lines`\n\nThis is an array of line objects with the following properties:\n\n```js\n{\n  start: startCharIndex, // inclusive\n  end: endCharIndex, // exclusive\n  width: lineWidth // in font units\n}\n```\n\n#### `layout.lineHeight`\n\nThis is the computed `lineHeight` in font units. If no `lineHeight` is specified in options, it will be equivalent to `1.175 * font.unitsPerEm`.\n\n#### `layout.left`\n\nThis is the distance from the left of the text box to the widest line of text in the box. This is zero when `align` is left, but changes with other alignments.\n\n#### `layout.right`\n\nThis is the distance from the right of the box to the widest line of text in the box. This is zero when `align` is right, but changes with other alignments.\n\n#### `layout.width`\n\nThe width of the text box. If no `opt.width` is passed, this will equal `layout.maxLineWidth` (i.e. length of a single line of text). If `opt.width` is passed, this value should equal it.\n\n#### `layout.height`\n\nThe height of the text box, including the half leadings above the first ascender and below the last descender.\n\n#### `layout.maxLineWidth`\n\nThis is the maximum line width in all lines. This can be used to determine the \"real\" width of the text box after word wrap, instead of the `layout.width` which may be larger.\n\n## TODOs\n\nThis module is not yet finished — below are some areas that need improvement. PRs welcome.\n\n- `'center'` and `'right'` alignment do not match exactly with DOM/CSS\n- Tab characters are not yet handled\n- Undefined characters are not yet handled gracefully\n- Word wrap algorithm is naïve and does not always match DOM/CSS\n- Mainly suited for Latin left-to-right text, does not handle CTL\n\n## License\n\nMIT, see [LICENSE.md](http://github.com/Jam3/opentype-layout/blob/master/LICENSE.md) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FExperience-Monks%2Fopentype-layout","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FExperience-Monks%2Fopentype-layout","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FExperience-Monks%2Fopentype-layout/lists"}