Three independently ugly bugs that all fed the same log flood:
* Electron's `WebFrameMain.send` writes every "Render frame was disposed"
to stderr via `console.error`. When the worker fans a second
agent-event past a reloading renderer, we produced thousands of
identical lines and stalled the main loop on stderr I/O. Added a
`mainFrame.detached` guard so the send is short-circuited before
Electron's own catch block fires, and installed a targeted filter in
`suppress-warnings.ts` (now actually imported from the entry point)
so the specific `console.error("Error sending from webFrameMain:"…)`
noise never reaches the terminal. Any other payload still surfaces.
* `dispatchAgentMessage` accepted the human-reader sentinel as a wake
target when an agent replied to `__board__` — `wakeAgentIfPossible`
then called `db.getAgent("__board__")`, threw, and the dispatcher
kept repeating on every send. Strip `HUMAN_SENDER_ID` at
`resolveMessageWakeTargets`, and keep a defense-in-depth guard in the
heartbeat so a stray caller (future automation fan-out) cannot
reintroduce the crash.
* Pi's skills loader rejects any SKILL.md whose frontmatter `name`
diverges from its parent directory. The four bundled `my-writing-style`
copies declared `name: writing-style-skill`, so every install emitted
a warning and dropped the skill. They also lived as orphan gitlinks
(mode 160000 without .gitmodules), and the global `*.md` gitignore
hid every other SKILL.md from version control. Fixed the frontmatter
to match the dir, converted the dangling submodules to plain trees,
and allowlisted `builtin-skills/**/*.md` so a fresh clone carries the
catalogue instead of silently losing it.
141 lines
2.7 KiB
Markdown
141 lines
2.7 KiB
Markdown
---
|
|
name: measuring-text
|
|
description: Measuring text dimensions, fitting text to containers, and checking overflow
|
|
metadata:
|
|
tags: measure, text, layout, dimensions, fitText, fillTextBox
|
|
---
|
|
|
|
# Measuring text in Remotion
|
|
|
|
## Prerequisites
|
|
|
|
Install @remotion/layout-utils if it is not already installed:
|
|
|
|
```bash
|
|
npx remotion add @remotion/layout-utils
|
|
```
|
|
|
|
## Measuring text dimensions
|
|
|
|
Use `measureText()` to calculate the width and height of text:
|
|
|
|
```tsx
|
|
import { measureText } from "@remotion/layout-utils";
|
|
|
|
const { width, height } = measureText({
|
|
text: "Hello World",
|
|
fontFamily: "Arial",
|
|
fontSize: 32,
|
|
fontWeight: "bold",
|
|
});
|
|
```
|
|
|
|
Results are cached - duplicate calls return the cached result.
|
|
|
|
## Fitting text to a width
|
|
|
|
Use `fitText()` to find the optimal font size for a container:
|
|
|
|
```tsx
|
|
import { fitText } from "@remotion/layout-utils";
|
|
|
|
const { fontSize } = fitText({
|
|
text: "Hello World",
|
|
withinWidth: 600,
|
|
fontFamily: "Inter",
|
|
fontWeight: "bold",
|
|
});
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
fontSize: Math.min(fontSize, 80), // Cap at 80px
|
|
fontFamily: "Inter",
|
|
fontWeight: "bold",
|
|
}}
|
|
>
|
|
Hello World
|
|
</div>
|
|
);
|
|
```
|
|
|
|
## Checking text overflow
|
|
|
|
Use `fillTextBox()` to check if text exceeds a box:
|
|
|
|
```tsx
|
|
import { fillTextBox } from "@remotion/layout-utils";
|
|
|
|
const box = fillTextBox({ maxBoxWidth: 400, maxLines: 3 });
|
|
|
|
const words = ["Hello", "World", "This", "is", "a", "test"];
|
|
for (const word of words) {
|
|
const { exceedsBox } = box.add({
|
|
text: word + " ",
|
|
fontFamily: "Arial",
|
|
fontSize: 24,
|
|
});
|
|
if (exceedsBox) {
|
|
// Text would overflow, handle accordingly
|
|
break;
|
|
}
|
|
}
|
|
```
|
|
|
|
## Best practices
|
|
|
|
**Load fonts first:** Only call measurement functions after fonts are loaded.
|
|
|
|
```tsx
|
|
import { loadFont } from "@remotion/google-fonts/Inter";
|
|
|
|
const { fontFamily, waitUntilDone } = loadFont("normal", {
|
|
weights: ["400"],
|
|
subsets: ["latin"],
|
|
});
|
|
|
|
waitUntilDone().then(() => {
|
|
// Now safe to measure
|
|
const { width } = measureText({
|
|
text: "Hello",
|
|
fontFamily,
|
|
fontSize: 32,
|
|
});
|
|
});
|
|
```
|
|
|
|
**Use validateFontIsLoaded:** Catch font loading issues early:
|
|
|
|
```tsx
|
|
measureText({
|
|
text: "Hello",
|
|
fontFamily: "MyCustomFont",
|
|
fontSize: 32,
|
|
validateFontIsLoaded: true, // Throws if font not loaded
|
|
});
|
|
```
|
|
|
|
**Match font properties:** Use the same properties for measurement and rendering:
|
|
|
|
```tsx
|
|
const fontStyle = {
|
|
fontFamily: "Inter",
|
|
fontSize: 32,
|
|
fontWeight: "bold" as const,
|
|
letterSpacing: "0.5px",
|
|
};
|
|
|
|
const { width } = measureText({
|
|
text: "Hello",
|
|
...fontStyle,
|
|
});
|
|
|
|
return <div style={fontStyle}>Hello</div>;
|
|
```
|
|
|
|
**Avoid padding and border:** Use `outline` instead of `border` to prevent layout differences:
|
|
|
|
```tsx
|
|
<div style={{ outline: "2px solid red" }}>Text</div>
|
|
```
|