textpour 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -96
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
# textpour
|
|
2
|
-
|
|
3
|
-
A render-agnostic **text-geometry kernel** on top of
|
|
4
|
-
[`@chenglou/pretext`](https://github.com/chenglou/pretext).
|
|
5
|
-
|
|
6
|
-
- **Shape-flow**: pour text into arbitrary 2D regions — circles, polygons, holes, boolean
|
|
7
|
-
combinations, SVG paths, glyph outlines, and raster alpha masks — by routing Pretext's
|
|
8
|
-
line-breaking through per-row spans. (CSS `shape-inside` never shipped; this does it.)
|
|
9
|
-
- **Typographic quality** (the moat): justification (`align: 'justify'`), soft-hyphenation,
|
|
10
|
-
balanced lines, auto-fit (binary-search font size), and conservative band sampling so glyphs
|
|
11
|
-
never poke outside tight curves.
|
|
12
|
-
- **Cursor ↔ point mapping**: map pixel positions to exact grapheme positions and back, for
|
|
13
|
-
caret/hit-testing in custom-rendered text.
|
|
14
|
-
- **Pluggable paint**: the kernel computes geometry; `Renderer`s paint it. Canvas2D works today;
|
|
15
|
-
an HTML-in-Canvas adapter (for high-fidelity, accessible, 3D-surface paint) is stubbed for later.
|
|
16
|
-
|
|
17
|
-
The design bet is the **plan/paint split**: Pretext plans cheaply every frame (no DOM reflow); an
|
|
18
|
-
expensive high-fidelity backend paints only when the plan changes.
|
|
19
|
-
|
|
20
|
-
## Demo
|
|
21
|
-
|
|
22
|
-
Text poured into a circle and a donut (multi-span), reflowing live as the region changes — the same
|
|
23
|
-
prepared pass reused on every frame:
|
|
24
|
-
|
|
25
|
-

|
|
26
|
-
|
|
27
|
-
## Why not just Pretext?
|
|
28
|
-
|
|
29
|
-
Pretext is the line-breaking and measurement engine — a very good one. It breaks lines at a width
|
|
30
|
-
*you give it*, measures without DOM reflow, and its fuller API even does Knuth–Plass justification,
|
|
31
|
-
syllable hyphenation, and "shrinkwrap" (`walkLineRanges`). It can already flow text past a floated
|
|
32
|
-
image, because that's still **one rectangular width that varies by `y`**.
|
|
33
|
-
|
|
34
|
-
What Pretext deliberately does **not** model is **2D geometry**. Its layout call is "one line, one
|
|
35
|
-
width." textpour adds exactly that missing layer:
|
|
36
|
-
|
|
37
|
-
- **Arbitrary regions, not a scalar width.** A `Region` turns any 2D shape — circles, ellipses,
|
|
38
|
-
polygons, boolean unions/intersections/**holes**, SVG paths, glyph outlines, raster alpha masks —
|
|
39
|
-
into the per-row spans Pretext consumes. Pretext has no notion of a shape, a hole, or an outline.
|
|
40
|
-
- **Multiple disjoint spans per line — the "cursor trick."** Pouring a single row across the left
|
|
41
|
-
*and* right of a hole (a donut), or into the prongs of a concave shape, in reading order on one
|
|
42
|
-
baseline. Pretext's one-line-one-width API can't natively continue a row across a gap; textpour
|
|
43
|
-
threads one cursor through every span on the row.
|
|
44
|
-
- **Auto-fit to a region** — binary-search the font size that exactly fills a shape. Pretext keys
|
|
45
|
-
layout on `(text, font)`; it doesn't size-to-fit a 2D area.
|
|
46
|
-
- **A render-agnostic plan/paint kernel** — geometry computed once, painted by pluggable
|
|
47
|
-
`Renderer`s (Canvas2D today, HTML-in-Canvas later).
|
|
48
|
-
- **Cursor ↔ point mapping** for hit-testing/caret in custom-rendered text.
|
|
49
|
-
|
|
50
|
-
Honest overlap: textpour targets the **published `@chenglou/pretext@0.0.1`**, whose API is just
|
|
51
|
-
`prepareWithSegments` + `layoutNextLine`. So textpour's own justification, soft-hyphenation, and
|
|
52
|
-
balanced-lines are pragmatic implementations over that minimal surface — when Pretext ships its
|
|
53
|
-
richer API (Knuth–Plass justify, real hyphenation, `walkLineRanges`), textpour will defer to those
|
|
54
|
-
and keep only the geometry it uniquely contributes.
|
|
55
|
-
|
|
56
|
-
In one line: **Pretext breaks the lines; textpour decides the shape those lines fill.**
|
|
57
|
-
|
|
58
|
-
## Quickstart
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
npm install
|
|
62
|
-
npm test # builds, runs the pure-logic test suite (56 specs)
|
|
63
|
-
npm run build # emits dist/
|
|
64
|
-
# demo (needs a browser + http):
|
|
65
|
-
npx http-server . # or any static server
|
|
66
|
-
# open /demo/index.html
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Status
|
|
70
|
-
|
|
71
|
-
**Phase 0** (kernel scaffold) and **Phase 1** (shape-flow quality — justification, soft-hyphenation,
|
|
72
|
-
balanced lines, auto-fit, region-from-outline, conservative band sampling) are complete and tested
|
|
73
|
-
(56 specs). See **ROADMAP.md** for what's next — the HTML-in-Canvas renderer (Phase 2), then the
|
|
74
|
-
flagship "shaped CSS text on a 3D surface" demo (Phase 3).
|
|
75
|
-
|
|
76
|
-
## Docs
|
|
77
|
-
|
|
78
|
-
- **EXPLAINER.md** — plain-words overview, ELI5, and the origin story (start here for the why).
|
|
79
|
-
- **CLAUDE.md** — how to work in this repo (conventions, commands, guardrails).
|
|
80
|
-
- **SPEC.md** — the full design, API reference, and the relationship to Pretext + HTML-in-Canvas.
|
|
81
|
-
- **ROADMAP.md** — phased tasks with acceptance + kill criteria.
|
|
82
|
-
|
|
83
|
-
## Example
|
|
84
|
-
|
|
85
|
-
```ts
|
|
86
|
-
import { shapeFlow, circle, subtract, Canvas2DRenderer, PretextLineSource } from 'textpour';
|
|
87
|
-
|
|
88
|
-
const source = new PretextLineSource(longText, '17px Georgia'); // one prepare pass
|
|
89
|
-
const region = subtract(circle(220, 220, 160), circle(220, 220, 67)); // a donut
|
|
90
|
-
const result = shapeFlow(source, region, { lineHeight: 24, ascent: 18 });
|
|
91
|
-
|
|
92
|
-
new Canvas2DRenderer('17px Georgia', { color: '#1a1a1a' }).render(result, ctx);
|
|
93
|
-
// result.overflow / result.endCursor drive auto-fit and multi-region pagination
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
MIT.
|
|
1
|
+
# textpour
|
|
2
|
+
|
|
3
|
+
A render-agnostic **text-geometry kernel** on top of
|
|
4
|
+
[`@chenglou/pretext`](https://github.com/chenglou/pretext).
|
|
5
|
+
|
|
6
|
+
- **Shape-flow**: pour text into arbitrary 2D regions — circles, polygons, holes, boolean
|
|
7
|
+
combinations, SVG paths, glyph outlines, and raster alpha masks — by routing Pretext's
|
|
8
|
+
line-breaking through per-row spans. (CSS `shape-inside` never shipped; this does it.)
|
|
9
|
+
- **Typographic quality** (the moat): justification (`align: 'justify'`), soft-hyphenation,
|
|
10
|
+
balanced lines, auto-fit (binary-search font size), and conservative band sampling so glyphs
|
|
11
|
+
never poke outside tight curves.
|
|
12
|
+
- **Cursor ↔ point mapping**: map pixel positions to exact grapheme positions and back, for
|
|
13
|
+
caret/hit-testing in custom-rendered text.
|
|
14
|
+
- **Pluggable paint**: the kernel computes geometry; `Renderer`s paint it. Canvas2D works today;
|
|
15
|
+
an HTML-in-Canvas adapter (for high-fidelity, accessible, 3D-surface paint) is stubbed for later.
|
|
16
|
+
|
|
17
|
+
The design bet is the **plan/paint split**: Pretext plans cheaply every frame (no DOM reflow); an
|
|
18
|
+
expensive high-fidelity backend paints only when the plan changes.
|
|
19
|
+
|
|
20
|
+
## Demo
|
|
21
|
+
|
|
22
|
+
Text poured into a circle and a donut (multi-span), reflowing live as the region changes — the same
|
|
23
|
+
prepared pass reused on every frame:
|
|
24
|
+
|
|
25
|
+

|
|
26
|
+
|
|
27
|
+
## Why not just Pretext?
|
|
28
|
+
|
|
29
|
+
Pretext is the line-breaking and measurement engine — a very good one. It breaks lines at a width
|
|
30
|
+
*you give it*, measures without DOM reflow, and its fuller API even does Knuth–Plass justification,
|
|
31
|
+
syllable hyphenation, and "shrinkwrap" (`walkLineRanges`). It can already flow text past a floated
|
|
32
|
+
image, because that's still **one rectangular width that varies by `y`**.
|
|
33
|
+
|
|
34
|
+
What Pretext deliberately does **not** model is **2D geometry**. Its layout call is "one line, one
|
|
35
|
+
width." textpour adds exactly that missing layer:
|
|
36
|
+
|
|
37
|
+
- **Arbitrary regions, not a scalar width.** A `Region` turns any 2D shape — circles, ellipses,
|
|
38
|
+
polygons, boolean unions/intersections/**holes**, SVG paths, glyph outlines, raster alpha masks —
|
|
39
|
+
into the per-row spans Pretext consumes. Pretext has no notion of a shape, a hole, or an outline.
|
|
40
|
+
- **Multiple disjoint spans per line — the "cursor trick."** Pouring a single row across the left
|
|
41
|
+
*and* right of a hole (a donut), or into the prongs of a concave shape, in reading order on one
|
|
42
|
+
baseline. Pretext's one-line-one-width API can't natively continue a row across a gap; textpour
|
|
43
|
+
threads one cursor through every span on the row.
|
|
44
|
+
- **Auto-fit to a region** — binary-search the font size that exactly fills a shape. Pretext keys
|
|
45
|
+
layout on `(text, font)`; it doesn't size-to-fit a 2D area.
|
|
46
|
+
- **A render-agnostic plan/paint kernel** — geometry computed once, painted by pluggable
|
|
47
|
+
`Renderer`s (Canvas2D today, HTML-in-Canvas later).
|
|
48
|
+
- **Cursor ↔ point mapping** for hit-testing/caret in custom-rendered text.
|
|
49
|
+
|
|
50
|
+
Honest overlap: textpour targets the **published `@chenglou/pretext@0.0.1`**, whose API is just
|
|
51
|
+
`prepareWithSegments` + `layoutNextLine`. So textpour's own justification, soft-hyphenation, and
|
|
52
|
+
balanced-lines are pragmatic implementations over that minimal surface — when Pretext ships its
|
|
53
|
+
richer API (Knuth–Plass justify, real hyphenation, `walkLineRanges`), textpour will defer to those
|
|
54
|
+
and keep only the geometry it uniquely contributes.
|
|
55
|
+
|
|
56
|
+
In one line: **Pretext breaks the lines; textpour decides the shape those lines fill.**
|
|
57
|
+
|
|
58
|
+
## Quickstart
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install
|
|
62
|
+
npm test # builds, runs the pure-logic test suite (56 specs)
|
|
63
|
+
npm run build # emits dist/
|
|
64
|
+
# demo (needs a browser + http):
|
|
65
|
+
npx http-server . # or any static server
|
|
66
|
+
# open /demo/index.html
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Status
|
|
70
|
+
|
|
71
|
+
**Phase 0** (kernel scaffold) and **Phase 1** (shape-flow quality — justification, soft-hyphenation,
|
|
72
|
+
balanced lines, auto-fit, region-from-outline, conservative band sampling) are complete and tested
|
|
73
|
+
(56 specs). See **ROADMAP.md** for what's next — the HTML-in-Canvas renderer (Phase 2), then the
|
|
74
|
+
flagship "shaped CSS text on a 3D surface" demo (Phase 3).
|
|
75
|
+
|
|
76
|
+
## Docs
|
|
77
|
+
|
|
78
|
+
- **EXPLAINER.md** — plain-words overview, ELI5, and the origin story (start here for the why).
|
|
79
|
+
- **CLAUDE.md** — how to work in this repo (conventions, commands, guardrails).
|
|
80
|
+
- **SPEC.md** — the full design, API reference, and the relationship to Pretext + HTML-in-Canvas.
|
|
81
|
+
- **ROADMAP.md** — phased tasks with acceptance + kill criteria.
|
|
82
|
+
|
|
83
|
+
## Example
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { shapeFlow, circle, subtract, Canvas2DRenderer, PretextLineSource } from 'textpour';
|
|
87
|
+
|
|
88
|
+
const source = new PretextLineSource(longText, '17px Georgia'); // one prepare pass
|
|
89
|
+
const region = subtract(circle(220, 220, 160), circle(220, 220, 67)); // a donut
|
|
90
|
+
const result = shapeFlow(source, region, { lineHeight: 24, ascent: 18 });
|
|
91
|
+
|
|
92
|
+
new Canvas2DRenderer('17px Georgia', { color: '#1a1a1a' }).render(result, ctx);
|
|
93
|
+
// result.overflow / result.endCursor drive auto-fit and multi-region pagination
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
MIT.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "textpour",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Pour text into arbitrary shapes — a render-agnostic text-geometry kernel on top of @chenglou/pretext (shape-flow + cursor<->point mapping, pluggable paint adapters).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|