mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-12 19:44:48 +01:00
design-html: match Pretext docs to the vendored bundle; fix cross-block server state (s08 H1, H2, H3, H4, H7, M6)
- H1-H3: walkLineRanges, layoutNextLine and layoutWithLines signatures and return shapes now match design-html/vendor/pretext.js; patterns 2-4 rewritten. - H4: inline the ES-module bundle in <script type="module"> with page code in the same module; no window.Pretext global exists. - H7: remember the printed server URL and PID; later blocks restate them. - M6: drop the 2-3 line cap on the refinement summary. Template-only commit: generated SKILL.md is expected red until the regeneration commit.
This commit is contained in:
1 parent
0d9f77bd08
commit
2941980083
2 files changed
+36
-42
No files matched your search
@@ -231,8 +231,9 @@ _ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
|
||||
[ -n "$_PRETEXT_VENDOR" ] && echo "VENDOR: $_PRETEXT_VENDOR" || echo "VENDOR_MISSING"
|
||||
```
|
||||
|
||||
- If `VENDOR` found: read the file and inline it in a `<script>` tag. The HTML file
|
||||
is fully self-contained with zero network dependencies.
|
||||
- If `VENDOR` found: inline the file in a `<script type="module">` and put the page's
|
||||
Pretext code after it in that same script; the bundle ends in `export {...}` and sets
|
||||
no global. The HTML file is fully self-contained with zero network dependencies.
|
||||
- If `VENDOR_MISSING`: use CDN import as fallback:
|
||||
`<script type="module">import { prepare, layout, prepareWithSegments, walkLineRanges, layoutNextLine, layoutWithLines } from 'https://esm.sh/@chenglou/pretext'</script>`
|
||||
Add a comment: `<!-- FALLBACK: vendor/pretext.js missing, using CDN -->`
|
||||
@@ -306,17 +307,20 @@ echo "SERVER: http://localhost:$_PORT/finalized.html"
|
||||
echo "PID: $_SERVER_PID"
|
||||
```
|
||||
|
||||
Remember the printed `SERVER:` URL and `PID:` value; each bash block is a fresh
|
||||
shell, so later blocks restate them literally.
|
||||
|
||||
If python3 is not available, fall back to:
|
||||
```bash
|
||||
open <path-to-finalized.html>
|
||||
```
|
||||
|
||||
Tell the user: "Live preview running at http://localhost:$_PORT/finalized.html.
|
||||
Tell the user: "Live preview running at <SERVER URL>.
|
||||
After each edit, just refresh the browser (Cmd+R) to see changes."
|
||||
|
||||
When the refinement loop ends (Step 4 exits), kill the server:
|
||||
```bash
|
||||
kill $_SERVER_PID 2>/dev/null || true
|
||||
kill <PID> 2>/dev/null || true
|
||||
```
|
||||
|
||||
---
|
||||
@@ -377,7 +381,7 @@ LOOP:
|
||||
5. Apply feedback using targeted Edit tool changes on the HTML file
|
||||
(do NOT regenerate the entire file — surgical edits only)
|
||||
|
||||
6. Brief summary of what changed (2-3 lines max)
|
||||
6. Briefly say what changed
|
||||
|
||||
7. If verification screenshots are available, re-take them to confirm the fix
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ Pretext API usage patterns. Follow them exactly.
|
||||
|
||||
**Pattern 1: Basic height computation (Simple layout, Card/grid)**
|
||||
```js
|
||||
import { prepare, layout } from './pretext-inline.js'
|
||||
// Or if inlined: const { prepare, layout } = window.Pretext
|
||||
import { prepare, layout } from '@chenglou/pretext'
|
||||
// Vanilla HTML: omit the import; this code follows the inlined bundle in the same <script type="module">
|
||||
|
||||
// 1. PREPARE — one-time, after fonts load
|
||||
await document.fonts.ready
|
||||
@@ -45,37 +45,26 @@ for (const el of elements) {
|
||||
|
||||
**Pattern 2: Shrinkwrap / tight-fit containers (Chat bubbles)**
|
||||
```js
|
||||
import { prepareWithSegments, walkLineRanges } from './pretext-inline.js'
|
||||
import { prepareWithSegments, walkLineRanges } from '@chenglou/pretext'
|
||||
|
||||
// Find the tightest width that produces the same line count
|
||||
function shrinkwrap(text, font, maxWidth, lineHeight) {
|
||||
// Tight-fit width: lay out at maxWidth, then shrink the bubble to its widest line
|
||||
function shrinkwrap(text, font, maxWidth) {
|
||||
const segs = prepareWithSegments(text, font)
|
||||
let bestWidth = maxWidth
|
||||
walkLineRanges(segs, maxWidth, (lineCount, startIdx, endIdx) => {
|
||||
// walkLineRanges calls back with progressively narrower widths
|
||||
// The first call gives us the line count at maxWidth
|
||||
// We want the narrowest width that still produces this line count
|
||||
let widest = 0
|
||||
const lineCount = walkLineRanges(segs, maxWidth, (line) => {
|
||||
widest = Math.max(widest, line.width)
|
||||
})
|
||||
// Binary search for tightest width with same line count
|
||||
const { lineCount: targetLines } = layout(prepare(text, font), maxWidth, lineHeight)
|
||||
let lo = 0, hi = maxWidth
|
||||
while (hi - lo > 1) {
|
||||
const mid = (lo + hi) / 2
|
||||
const { lineCount } = layout(prepare(text, font), mid, lineHeight)
|
||||
if (lineCount === targetLines) hi = mid
|
||||
else lo = mid
|
||||
}
|
||||
return hi
|
||||
return { width: Math.ceil(widest), lineCount }
|
||||
}
|
||||
```
|
||||
|
||||
**Pattern 3: Text around obstacles (Editorial layout)**
|
||||
```js
|
||||
import { prepareWithSegments, layoutNextLine } from './pretext-inline.js'
|
||||
import { prepareWithSegments, layoutNextLine } from '@chenglou/pretext'
|
||||
|
||||
function layoutAroundObstacles(text, font, containerWidth, lineHeight, obstacles) {
|
||||
const segs = prepareWithSegments(text, font)
|
||||
let state = null
|
||||
let cursor = { segmentIndex: 0, graphemeIndex: 0 }
|
||||
let y = 0
|
||||
const lines = []
|
||||
|
||||
@@ -88,11 +77,11 @@ function layoutAroundObstacles(text, font, containerWidth, lineHeight, obstacles
|
||||
}
|
||||
}
|
||||
|
||||
const result = layoutNextLine(segs, state, availWidth, lineHeight)
|
||||
const result = layoutNextLine(segs, cursor, availWidth)
|
||||
if (!result) break
|
||||
|
||||
lines.push({ text: result.text, width: result.width, x: 0, y })
|
||||
state = result.state
|
||||
cursor = result.end
|
||||
y += lineHeight
|
||||
}
|
||||
|
||||
@@ -102,21 +91,21 @@ function layoutAroundObstacles(text, font, containerWidth, lineHeight, obstacles
|
||||
|
||||
**Pattern 4: Full line-by-line rendering (Complex editorial)**
|
||||
```js
|
||||
import { prepareWithSegments, layoutWithLines } from './pretext-inline.js'
|
||||
import { prepareWithSegments, layoutWithLines } from '@chenglou/pretext'
|
||||
|
||||
const segs = prepareWithSegments(text, font)
|
||||
const { lines, height } = layoutWithLines(segs, containerWidth, lineHeight)
|
||||
|
||||
// lines = [{ text, width, x, y }, ...]
|
||||
// lines = [{ text, width, start, end }, ...] (no x/y: line i sits at y = i * lineHeight)
|
||||
// Use for Canvas/SVG rendering or custom DOM positioning
|
||||
for (const line of lines) {
|
||||
lines.forEach((line, i) => {
|
||||
const span = document.createElement('span')
|
||||
span.textContent = line.text
|
||||
span.style.position = 'absolute'
|
||||
span.style.left = `${line.x}px`
|
||||
span.style.top = `${line.y}px`
|
||||
span.style.left = '0px'
|
||||
span.style.top = `${i * lineHeight}px`
|
||||
container.appendChild(span)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Pretext API Reference
|
||||
@@ -134,16 +123,17 @@ layout(prepared, maxWidth, lineHeight) → { height, lineCount }
|
||||
prepareWithSegments(text, font) → handle
|
||||
Like prepare() but enables line-level APIs below.
|
||||
|
||||
layoutWithLines(segs, maxWidth, lineHeight) → { lines: [{text, width, x, y}...], height }
|
||||
Full line-by-line breakdown. For Canvas/SVG rendering.
|
||||
layoutWithLines(segs, maxWidth, lineHeight) → { lineCount, height, lines: [{text, width, start, end}...] }
|
||||
Full line-by-line breakdown (no x/y: line i is at y = i * lineHeight). For Canvas/SVG rendering.
|
||||
|
||||
walkLineRanges(segs, maxWidth, onLine) → void
|
||||
Calls onLine(lineCount, startIdx, endIdx) for each possible layout.
|
||||
Find minimum width for N lines. For tight-fit containers.
|
||||
walkLineRanges(segs, maxWidth, onLine) → lineCount
|
||||
Calls onLine({ width, start, end }) once per line at maxWidth (no text built).
|
||||
The widest line's width is the tight-fit container width. For chat bubbles.
|
||||
|
||||
layoutNextLine(segs, state, maxWidth, lineHeight) → { text, width, state } | null
|
||||
layoutNextLine(segs, cursor, maxWidth) → { text, width, start, end } | null
|
||||
Iterator. Different maxWidth per line = text around obstacles.
|
||||
Pass null as initial state. Returns null when text is exhausted.
|
||||
Start with cursor { segmentIndex: 0, graphemeIndex: 0 }; pass result.end next.
|
||||
Returns null when text is exhausted. Takes no lineHeight: advance y yourself.
|
||||
|
||||
clearCache() → void
|
||||
Clears internal measurement caches. Use when cycling many fonts.
|
||||
|
||||
Reference in new issue
Block a user