README with screenshots, Crafting Apps table, community links; proofing ignores deletions/objects; comment shading; hhea line metrics; watermark tuning

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon ThomasandClaude Opus 5.5 committed 2026-10-06 00:18:42 -04:00
1 parent d95e09ba25
commit f3dbc31a57
15 files changed
+330 -162

No files matched your search

+6
View File
@@ -41,6 +41,12 @@ Generated-in-code art is original and has no file to list: the UI icon set (`cra
| `assets/fonts/SourceSerif4-It.ttf` | Paul D. Hunt / Frank Grießhammer, Adobe (released as open source) | https://github.com/adobe-fonts/source-sans · https://github.com/adobe-fonts/source-serif | OFL-1.1 (`assets/fonts/OFL-SourceSans3.txt`, `OFL-SourceSerif4.txt`) | Open-source typeface (Latin UI/document font, carried over from DesignCraft) |
| `assets/fonts/SourceSerif4-Regular.ttf` | Paul D. Hunt / Frank Grießhammer, Adobe (released as open source) | https://github.com/adobe-fonts/source-sans · https://github.com/adobe-fonts/source-serif | OFL-1.1 (`assets/fonts/OFL-SourceSans3.txt`, `OFL-SourceSerif4.txt`) | Open-source typeface (Latin UI/document font, carried over from DesignCraft) |
| `assets/fonts/SourceSerif4-Semibold.ttf` | Paul D. Hunt / Frank Grießhammer, Adobe (released as open source) | https://github.com/adobe-fonts/source-sans · https://github.com/adobe-fonts/source-serif | OFL-1.1 (`assets/fonts/OFL-SourceSans3.txt`, `OFL-SourceSerif4.txt`) | Open-source typeface (Latin UI/document font, carried over from DesignCraft) |
| `docs/images/review.png` | WordCraft contributors | screenshot of WordCraft itself (sample document written for WordCraft, rendered by `ui_shot`) | MIT OR Apache-2.0 | Original; no Microsoft UI or assets |
| `docs/images/references.png` | WordCraft contributors | screenshot of WordCraft itself (sample document written for WordCraft, rendered by `ui_shot`) | MIT OR Apache-2.0 | Original; no Microsoft UI or assets |
| `docs/images/hero.png` | WordCraft contributors | screenshot of WordCraft itself (sample document written for WordCraft, rendered by `ui_shot`) | MIT OR Apache-2.0 | Original; no Microsoft UI or assets |
| `docs/images/design.png` | WordCraft contributors | screenshot of WordCraft itself (sample document written for WordCraft, rendered by `ui_shot`) | MIT OR Apache-2.0 | Original; no Microsoft UI or assets |
| `docs/images/dark.png` | WordCraft contributors | screenshot of WordCraft itself (sample document written for WordCraft, rendered by `ui_shot`) | MIT OR Apache-2.0 | Original; no Microsoft UI or assets |
| `docs/images/backstage.png` | WordCraft contributors | screenshot of WordCraft itself (sample document written for WordCraft, rendered by `ui_shot`) | MIT OR Apache-2.0 | Original; no Microsoft UI or assets |
| `docs/brand/LICENSE-brand.txt` | ArtCraft Team | craftrules `assets/brand/` | ArtCraft trademark, `docs/brand/LICENSE-brand.txt` | Not open source; usable unmodified only |
| `docs/brand/artcraft-logo-white.png` | ArtCraft Team | craftrules `assets/brand/` | ArtCraft trademark, `docs/brand/LICENSE-brand.txt` | Not open source; usable unmodified only |
| `docs/brand/artcraft-logo-white.svg` | ArtCraft Team | craftrules `assets/brand/` | ArtCraft trademark, `docs/brand/LICENSE-brand.txt` | Not open source; usable unmodified only |
+243 -3
View File
@@ -1,4 +1,244 @@
WordCraft
==========
<p align="center">
<a href="https://getartcraft.com/">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/brand/artcraft-logo-white.svg">
<img alt="ArtCraft" src="docs/brand/artcraft-logo.svg" width="200">
</picture>
</a>
</p>
By ArtCraft
<h1 align="center">WordCraft</h1>
<p align="center">
<b>Writing and document design; an open-source, clean-room reimplementation of Microsoft Word, rebuilt in pure Rust.</b>
</p>
<p align="center">
A fast, open-source word processor with the Word workflow you already know: the ribbon, styles,
tables, track changes, references and mail merge. It reads and writes .docx, runs natively on
macOS, Windows, Linux and BSD, and in the browser via WebAssembly.<br>
<i>By the ArtCraft team.</i>
</p>
<p align="center">
<img alt="Written in Rust" src="https://img.shields.io/badge/written%20in-Rust-2b47b5?style=flat-square&logo=rust&logoColor=white">
<img alt="Runs on macOS, Windows, Linux, BSD and the web" src="https://img.shields.io/badge/runs%20on-macOS%20%C2%B7%20Windows%20%C2%B7%20Linux%20%C2%B7%20BSD%20%C2%B7%20Web-3b5bdb?style=flat-square">
<img alt="License: MIT OR Apache-2.0" src="https://img.shields.io/badge/license-MIT%20%2F%20Apache--2.0-2b47b5?style=flat-square">
<img alt="Agent-drivable over MCP" src="https://img.shields.io/badge/agents-MCP%20%C2%B7%20CLI-3b5bdb?style=flat-square">
</p>
<p align="center">
<a href="https://discord.gg/artcraft"><img alt="Join the ArtCraft community on Discord" src="https://img.shields.io/badge/Join%20us%20on%20Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" height="40"></a>
</p>
<p align="center">
<a href="https://getartcraft.com/apps/wordcraft"><b>WordCraft on getartcraft.com</b></a> ·
<a href="https://getartcraft.com/">ArtCraft</a> ·
<a href="https://getartcraft.com/apps">All Crafting Apps</a>
</p>
<br>
<p align="center">
<img src="docs/images/hero.png" alt="WordCraft with the Home tab of the ribbon open over a two-page document titled The Open Studio Handbook. The Navigation pane on the left lists the document's headings, the Styles gallery shows live previews of Normal, Heading 1, Title and Subtitle, and a word in the first paragraph is selected." width="100%">
<br><sub><b>The Open Studio Handbook</b>, WordCraft's built-in sample: the ribbon, live Styles gallery, rulers and the Navigation pane.</sub>
</p>
> [!NOTE]
> **ArtCraft is a community of artists from all walks of life.** Painters, photographers,
> filmmakers, illustrators, designers, animators, hobbyists, and people who picked up a pencil
> last week. If you make things, you're one of us. **[Come say hi on Discord](https://discord.gg/artcraft).**
<p align="center">
<a href="#a-tour">A tour</a> ·
<a href="#why-wordcraft">Why WordCraft</a> ·
<a href="#what-works-today">What works today</a> ·
<a href="#quick-start">Quick start</a> ·
<a href="#for-agents-cli-and-mcp">For agents</a> ·
<a href="#architecture">Architecture</a> ·
<a href="#roadmap">Roadmap</a> ·
<a href="#the-crafting-apps">The Crafting Apps</a> ·
<a href="#license-and-credits">License and credits</a>
</p>
## A tour
Every screenshot below is WordCraft itself, rendered offscreen by its own UI test harness
(`cargo run -p wordcraft-ui-egui --example ui_shot`).
<table>
<tr>
<td width="50%" valign="top"><img src="docs/images/review.png" alt="The Review tab with Track Changes on: the inserted words Cheaper rent is one reason and forty are underlined in magenta, the replaced words are struck through, two commented phrases are shaded and the Comments pane on the right shows both comments with Go to, Resolve and Delete buttons" width="100%"><p align="center"><sub><b>Review.</b> Track changes, comments, accept and reject, spelling and grammar as you type.</sub></p></td>
<td width="50%" valign="top"><img src="docs/images/references.png" alt="The References tab with two pages side by side: a table of contents with dotted leaders and page numbers on page one, and a styled table, numbered list and hyperlink on page two" width="100%"><p align="center"><sub><b>References.</b> Tables of contents, footnotes, citations in APA, MLA, Chicago or IEEE, index and captions.</sub></p></td>
</tr>
<tr>
<td width="50%" valign="top"><img src="docs/images/design.png" alt="The Design tab showing style-set previews; the document is set in a serif theme with plum headings underlined by thin rules and a pale diagonal DRAFT watermark behind the text" width="100%"><p align="center"><sub><b>Design.</b> Themes, style sets, paragraph spacing, watermarks, page colour and borders.</sub></p></td>
<td width="50%" valign="top"><img src="docs/images/dark.png" alt="WordCraft in dark mode with the Insert tab open and formatting marks shown: pilcrows at paragraph ends and dots for spaces" width="100%"><p align="center"><sub><b>Dark mode</b> with formatting marks, and the Insert tab: tables, pictures, shapes, links, headers, footers, fields and symbols.</sub></p></td>
</tr>
<tr>
<td colspan="2"><img src="docs/images/backstage.png" alt="The File tab start page with a Good morning greeting, thumbnails of the Blank document, Studio handbook, Letter, Résumé and Report templates, and a list of recent documents" width="100%"><p align="center"><sub><b>File.</b> Start from a template, open recent documents, edit properties, export to PDF and other formats.</sub></p></td>
</tr>
</table>
## Why WordCraft
- **Familiar.** Word's ribbon tabs, groups, shortcuts and behaviour: Enter continues a list,
Tab demotes it, Ctrl/⌘+B bolds the word under the caret, the Styles gallery previews styles live,
F4 repeats, F7 checks spelling, F8 extends the selection.
- **Your files.** Opens and saves .docx (OOXML), and also .odt, .rtf, .html, .md, .txt; exports PDF
with real, selectable text, links and bookmarks.
- **Fast.** Paragraph layout is cached, so typing in a 188-page document re-lays it out in about
1.4 ms; pages render on demand.
- **Everywhere.** One Rust codebase for macOS, Windows, Linux, BSD and the web. No Electron, no
Tauri: native [egui](https://github.com/emilk/egui) on the GPU.
- **Built for agents.** Every action is a command with an id. The same 389 commands drive the
ribbon, keyboard shortcuts, the command search, a command-line tool, a JSON control channel and
an MCP server.
- **Private.** Spelling, grammar and everything else work offline.
- **Open.** MIT OR Apache-2.0. Clean-room: built from public specifications and observation, with
every asset original or openly licensed.
## What works today
| Area | Highlights |
|---|---|
| **Writing** | Fast typing with IME, smart quotes, AutoCorrect, list autoformat (`* `, `1. `), dashes; word, sentence, paragraph selection; drag-select; clipboard with formatting; undo/redo; find and replace with regex |
| **Formatting** | Fonts, sizes, bold/italic/underline styles, strike, sub/superscript, caps, highlight, colours, character spacing, Format Painter, Change Case, Clear Formatting |
| **Paragraphs** | Alignment, indents (draggable on the ruler), spacing, line spacing, tabs with leaders, borders, shading, keep with next, widow/orphan control |
| **Styles** | Built-in style set, live gallery, Styles pane, create/modify/update styles, style sets, themes |
| **Lists** | Bullets, numbering, multilevel, restart, set value, custom formats |
| **Tables** | Insert by grid, merge/split, styles with banded rows, borders, shading, header rows repeated across pages, sort, formulas, text ↔ table |
| **Pages** | Margins, orientation, size, columns, page/column/section breaks, headers and footers (first page, odd/even), page numbers, watermark |
| **Objects** | Pictures (resize, crop, recolour, brightness/contrast, transparency, background removal, picture styles, rotate), shapes, text boxes, floating position |
| **References** | Table of contents, footnotes and endnotes, citations and bibliography (APA, MLA, Chicago, IEEE), captions, table of figures, cross-references, index, table of authorities |
| **Review** | Spelling and grammar with suggestions, thesaurus, word count, comments, track changes, accept/reject, compare documents, restrict editing, accessibility checker, document inspector |
| **Mailings** | Mail merge from CSV, merge fields, address block, greeting line, rules, preview, finish to a document; envelopes and labels |
| **View** | Print layout, web layout, draft, read mode, focus, zoom, one/multiple pages, page width, Navigation pane, rulers, gridlines, dark mode |
| **Files** | .docx read/write (opens in Word), PDF export, .odt, .rtf, .html, .md, .txt import/export, page images |
The honest picture, area by area, is in [ROADMAP.md](ROADMAP.md) and the generated
[feature parity report](docs/parity.md).
## Quick start
```sh
git clone https://github.com/storytold/wordcraft
cd wordcraft
cargo run --release -p wordcraft -- --sample # the desktop app with the sample document
cargo run --release -p wordcraft -- report.docx # open a document
```
Command line:
```sh
wordcraft-cli convert report.docx report.pdf # docx, pdf, odt, rtf, html, md, txt, png
wordcraft-cli text report.docx # plain text
wordcraft-cli inspect report.docx # structure as JSON
wordcraft-cli run --template sample \
--cmd 'select.text={"text":"Membership"}' --cmd format.bold --save out.docx
```
Web: `cd apps/wordcraft-web && trunk serve`, then open <http://127.0.0.1:8771/?sample>.
## For agents: CLI and MCP
WordCraft was designed to be driven by people *and* by AI agents.
```sh
claude mcp add wordcraft -- wordcraft-cli mcp # headless documents
wordcraft --control 7981 & # or drive the running app…
claude mcp add wordcraft-app -- wordcraft-cli mcp --connect 127.0.0.1:7981
```
Tools include `list_commands`, `execute`, `batch`, `type_text`, `select_text`, `inspect_document`,
`render_page`, `save_document`, and, with a running app, `screenshot`, `click` and `key`. Agents
can check their work through `inspect_document` without screenshots. See [docs/mcp.md](docs/mcp.md)
and the [control protocol](docs/control-protocol.md). Macros record any sequence of commands and
play it back (`tools.recordMacro`, `tools.macros`).
## Architecture
| Layer | Crate | Job |
|---|---|---|
| L0 | `wordcraft-geom` | units and measurements |
| L1 | `wordcraft-doc`, `wordcraft-fonts`, `wordcraft-proof` | document model and editing; fonts and shaping; spelling, grammar, hyphenation |
| L2 | `wordcraft-layout`, `wordcraft-docx`, `wordcraft-formats` | line breaking, pagination, tables, notes, hit testing; OOXML; ODT/RTF/HTML/Markdown/TXT |
| L3 | `wordcraft-render`, `wordcraft-pdf` | rasteriser (vello_cpu); PDF (krilla) |
| L4 | `wordcraft-engine` | session, undo, 389 commands, Word feature catalog |
| L5 | `wordcraft-mcp` | MCP server |
| L6 | `wordcraft-ui-egui` | the Word-style front end (swappable) |
| apps | `wordcraft`, `wordcraft-cli`, `wordcraft-web` | desktop, command line, browser |
`cargo xtask ci` runs formatting, clippy, ~250 tests, the asset-attribution check, the layering
check and the wasm build. Contributor and agent instructions: [AGENTS.md](AGENTS.md).
## Roadmap
WordCraft covers 87% of Word's ribbon features with commands today; we estimate about 58% of
real feature parity once depth is counted. Next: text wrap around floating pictures, margin
comment balloons, column balancing, charts, an equation editor and signed releases for every
platform. Details and estimates: [ROADMAP.md](ROADMAP.md).
## The Crafting Apps
WordCraft is one of the **Crafting Apps**: free, open-source creative tools from the
[ArtCraft](https://getartcraft.com/) team, each written from scratch in Rust and each able to
stand on its own.
| | App | What it's for | Code | Learn more |
|:-:|---|---|---|---|
| <img src="https://raw.githubusercontent.com/storytold/photocraft/main/assets/app-icon/hicolor/64x64/apps/ai.storyteller.photocraft.png" alt="" width="32" height="32"> | **PhotoCraft** | Image editing: layers, masks, type and real PSD files | [GitHub](https://github.com/storytold/photocraft) | [Website](https://getartcraft.com/apps/photocraft) |
| <img src="https://raw.githubusercontent.com/storytold/vectorcraft/main/assets/app-icon/hicolor/64x64/apps/ai.storyteller.vectorcraft.png" alt="" width="32" height="32"> | **VectorCraft** | Vector illustration | [GitHub](https://github.com/storytold/vectorcraft) | [Website](https://getartcraft.com/apps/vectorcraft) |
| <img src="https://raw.githubusercontent.com/storytold/filmcraft/main/assets/app-icon/hicolor/64x64/apps/ai.storyteller.filmcraft.png" alt="" width="32" height="32"> | **FilmCraft** | Video editing, color and sound | [GitHub](https://github.com/storytold/filmcraft) | [Website](https://getartcraft.com/apps/filmcraft) |
| <img src="https://raw.githubusercontent.com/storytold/lightcraft/main/assets/app-icon/hicolor/64x64/apps/ai.storyteller.lightcraft.png" alt="" width="32" height="32"> | **LightCraft** | Photo library and raw development | [GitHub](https://github.com/storytold/lightcraft) | [Website](https://getartcraft.com/apps/lightcraft) |
| <img src="https://raw.githubusercontent.com/storytold/printcraft/main/assets/app-icon/hicolor/64x64/apps/ai.storyteller.printcraft.png" alt="" width="32" height="32"> | **PrintCraft** | Reading, organizing and protecting PDFs | [GitHub](https://github.com/storytold/printcraft) | [Website](https://getartcraft.com/apps/printcraft) |
| <img src="https://raw.githubusercontent.com/storytold/effectcraft/main/assets/app-icon/hicolor/64x64/apps/ai.storyteller.effectcraft.png" alt="" width="32" height="32"> | **EffectCraft** | Motion graphics and visual effects | [GitHub](https://github.com/storytold/effectcraft) | [Website](https://getartcraft.com/apps/effectcraft) |
| <img src="https://raw.githubusercontent.com/storytold/designcraft/main/assets/app-icon/hicolor/64x64/apps/ai.storyteller.designcraft.png" alt="" width="32" height="32"> | **DesignCraft** | Page layout and publishing | [GitHub](https://github.com/storytold/designcraft) | [Website](https://getartcraft.com/apps/designcraft) |
| <img src="https://raw.githubusercontent.com/storytold/wordcraft/main/assets/app-icon/hicolor/64x64/apps/ai.storyteller.wordcraft.png" alt="" width="32" height="32"> | **WordCraft** | **Writing and document design · you are here** | [GitHub](https://github.com/storytold/wordcraft) | [Website](https://getartcraft.com/apps/wordcraft) |
And [**ArtCraft**](https://getartcraft.com/) itself, our AI image and video studio for artists who want real control.
<br>
<p align="center">
<a href="https://discord.gg/artcraft"><img alt="Join the ArtCraft community on Discord" src="https://img.shields.io/badge/Join%20us%20on%20Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white" height="40"></a>
</p>
<h3 align="center">Come make things with us</h3>
<p align="center">
Our Discord is where artists of every kind hang out: people who paint, shoot, draw, cut film,
set type, and people still figuring out what they like to make. Share what you're working on,
ask for help, tell us what's broken, or tell us what you wish these tools could do.
Whatever your medium and however long you've been at it, you're welcome here.
</p>
<p align="center">
<a href="https://discord.gg/artcraft"><b>discord.gg/artcraft</b></a> ·
<a href="https://getartcraft.com/">getartcraft.com</a> ·
<a href="https://getartcraft.com/apps">The Crafting Apps</a> ·
<a href="https://getartcraft.com/apps/wordcraft">WordCraft</a>
</p>
## License and credits
WordCraft is dual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE), at your option.
Copyright (c) 2026 ArtCraft Team and the WordCraft contributors. Required notices are in [NOTICE](NOTICE).
Bundled fonts, icons, images and other assets keep their own open licenses; each one is listed
with its author, source and license in [ATTRIBUTION.md](ATTRIBUTION.md).
The spelling dictionary and hyphenation come from Grady Ward's public-domain Moby Hyphenator II
word list. The sample documents and templates are original text written for WordCraft.
The ArtCraft name, wordmark and logos in [`docs/brand/`](docs/brand/) are trademarks of the
ArtCraft Team and are not covered by this license. They may be used only unmodified, and only as
part of this repository and WordCraft, under [`docs/brand/LICENSE-brand.txt`](docs/brand/LICENSE-brand.txt).
Forks and modified versions must remove them.
<sub>Microsoft and Microsoft Word are trademarks of the Microsoft group of companies. Adobe, Photoshop, Illustrator, Premiere Pro, Lightroom, Acrobat, After Effects and InDesign are trademarks or registered trademarks of Adobe Inc. in the United States and/or other countries. WordCraft is an independent, open-source project and is not affiliated with, sponsored by or endorsed by Microsoft Corporation or Adobe Inc.; these names are used only to describe the workflows it is compatible with.</sub>
<p align="center">
<a href="https://getartcraft.com/"><img alt="ArtCraft" src="docs/brand/artcraft-mark.svg" width="28"></a><br>
<sub>Made by the <a href="https://getartcraft.com/">ArtCraft</a> team and community.</sub>
</p>
+1 -1
View File
@@ -373,7 +373,7 @@ fn word_count(s: &mut Session, _: &Value) -> CmdResult {
/// Issues (spelling + grammar) in one paragraph as positions.
fn para_issues(s: &Session, story: StoryRef, path: &wordcraft_doc::Path) -> Vec<(Pos, Pos, wordcraft_proof::Issue)> {
let Some(p) = s.doc.para(story, path) else { return Vec::new() };
let text: String = p.text.chars().map(|c| if c == wordcraft_doc::para::OBJ { ' ' } else { c }).collect();
let text = wordcraft_layout::para::proof_text(p);
let mut v: Vec<wordcraft_proof::Issue> = wordcraft_proof::check_spelling(&text);
v.extend(wordcraft_proof::check_grammar(&text));
v.sort_by_key(|i| i.start);
+12 -8
View File
@@ -98,14 +98,18 @@ pub fn line_metrics(face: &crate::FontFace) -> (f64, f64) {
}
let mut v = (face.ascent.max(1.0), face.descent.abs());
if let Some(f) = face.skrifa() {
if let Ok(os2) = f.os2() {
let (a, d) = (os2.us_win_ascent() as f64, os2.us_win_descent() as f64);
if a > 0.0 && a + d < face.upem * 4.0 {
v = (a, d);
}
} else if let Ok(hhea) = f.hhea() {
let gap = hhea.line_gap().to_i16().max(0) as f64;
v = (hhea.ascender().to_i16() as f64 + gap, (hhea.descender().to_i16() as f64).abs());
// hhea ascender + descender + line gap (Word on macOS); OS/2 win metrics only when the
// hhea values are missing, and never more than twice the em.
let hhea = f.hhea().ok().map(|h| {
let gap = h.line_gap().to_i16().max(0) as f64;
(h.ascender().to_i16() as f64 + gap / 2.0, (h.descender().to_i16() as f64).abs() + gap / 2.0)
});
let win = f.os2().ok().map(|o| (o.us_win_ascent() as f64, o.us_win_descent() as f64));
let ok = |m: &(f64, f64)| m.0 > 0.0 && m.0 + m.1 <= face.upem * 2.0;
if let Some(m) = hhea.filter(ok) {
v = m;
} else if let Some(m) = win.filter(ok) {
v = m;
}
}
cache.lock().unwrap_or_else(|e| e.into_inner()).insert(face.id(), v);
+29
View File
@@ -173,6 +173,35 @@ fn lines(
let top = y + (line.top - first.top);
let base = top + (line.baseline - line.top);
let bottom = top + line.height;
// Commented text gets a soft shade (comment anchors are object markers).
if opts.markup
&& let Some(p) = para
{
let mut open: Option<usize> = None;
let mut ranges = Vec::new();
for off in p.object_offsets() {
match p.object_at(off) {
Some(InlineObject::CommentStart { .. }) => open = open.or(Some(off)),
Some(InlineObject::CommentEnd { .. }) => {
ranges.push((open.take().unwrap_or(0), off));
}
_ => {}
}
}
if let Some(o) = open {
ranges.push((o, p.len()));
}
for (a, b) in ranges {
if b <= line.start || a >= line.stop {
continue;
}
if let (Some(x0), Some(x1)) = (pl.x_of(li, a.max(line.start)), pl.x_of(li, b.min(line.stop)))
&& x1 > x0
{
out.push(Draw::Fill { rect: Rect::new(x + x0, top, x1 - x0, line.height), color: Rgb(0xEF, 0xE3, 0xF7), alpha });
}
}
}
// Backgrounds first: highlight and character shading.
for k in line.c0..line.c1 {
let (Some(c), Some(cx), Some(nx)) = (pl.clusters.get(k), line.xs.get(k - line.c0), line.xs.get(k + 1 - line.c0)) else { continue };
+18 -1
View File
@@ -932,7 +932,7 @@ fn proof_issues(p: &Paragraph) -> Vec<(usize, usize, bool)> {
if p.text.trim().is_empty() || p.text.len() > 100_000 {
return Vec::new();
}
let text: String = p.text.chars().map(|c| if c == OBJ { ' ' } else { c }).collect();
let text = proof_text(p);
let skip = |a: usize, b: usize| {
p.run_ranges().any(|(r, c)| r.start < b && a < r.end && (c.no_proof == Some(true) || c.hidden == Some(true) || c.link.is_some()))
};
@@ -941,3 +941,20 @@ fn proof_issues(p: &Paragraph) -> Vec<(usize, usize, bool)> {
v.extend(wordcraft_proof::check_grammar(&text).into_iter().filter(|i| !skip(i.start, i.end)).map(|i| (i.start, i.end, true)));
v
}
/// Text for proofing with the same byte offsets: inline objects and tracked deletions become
/// U+0001 bytes (neither words nor spaces).
pub fn proof_text(p: &wordcraft_doc::Paragraph) -> String {
let mut out = String::with_capacity(p.text.len());
for (i, c) in p.text.char_indices() {
let deleted = c == wordcraft_doc::para::OBJ || p.props_of_char(i).del.is_some();
if deleted {
for _ in 0..c.len_utf8() {
out.push('\u{1}');
}
} else {
out.push(c);
}
}
out
}
+2 -2
View File
@@ -192,13 +192,13 @@ fn draw_watermark(ctx: &mut RenderContext, view: Affine, page: &Page, wm: &wordc
return;
}
let diag = if wm.diagonal { ((page.w as f64).powi(2) + (page.h.min(2000.0) as f64).powi(2)).sqrt() } else { page.w as f64 };
let size = (diag * 0.7 / raw_w).min(300.0);
let size = (diag * 0.5 / raw_w).min(200.0);
let k = size / upem;
let angle = if wm.diagonal { -((page.h.min(2000.0) as f64) / page.w.max(1.0) as f64).atan() } else { 0.0 };
let base = Affine::translate((page.w as f64 / 2.0, page.h.min(2000.0) as f64 / 2.0))
* Affine::rotate(angle)
* Affine::translate((-raw_w * size / 2.0, size * 0.35));
ctx.set_paint(color(wm.color, if wm.semitransparent { 0.5 } else { 1.0 }));
ctx.set_paint(color(wm.color, if wm.semitransparent { 0.35 } else { 0.8 }));
let db = FontDb::global();
let mut x = 0.0;
for g in &glyphs {
+1 -1
View File
@@ -115,7 +115,7 @@ fn template_tile(ui: &mut Ui, app: &mut WordApp, label: &str, template: &str) {
let tex = ui.ctx().data(|d| d.get_temp::<egui::TextureHandle>(egui::Id::new(&key))).or_else(|| {
let mut s = wordcraft_engine::Session::new(wordcraft_doc::Document::new());
let _ = s.run("file.new", &json!({"template": template}));
let l = s.layout();
let l = s.export_layout();
let page = l.pages.first()?;
let img = wordcraft_render::render_page(&s.doc, page, 150.0 / page.w * ppp, &Default::default());
let px = img.to_straight();
Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 KiB

+18 -146
View File
@@ -2,48 +2,31 @@
Generated by `cargo xtask parity` (`wordcraft-cli parity --markdown`): the word-processor feature catalog (`crates/engine/src/catalog.rs`) compared with the live command registry.
**250 of 405 catalog features have commands (61.7%).**
**354 of 405 catalog features have commands (87.4%).**
| Tab | Live | Total |
|---|---|---|
| File | 11 | 20 |
| Quick Access | 2 | 4 |
| Home | 82 | 100 |
| Insert | 34 | 53 |
| File | 20 | 20 |
| Quick Access | 4 | 4 |
| Home | 89 | 100 |
| Insert | 42 | 53 |
| Draw | 0 | 11 |
| Design | 9 | 10 |
| Layout | 11 | 19 |
| References | 10 | 24 |
| Mailings | 0 | 17 |
| Review | 17 | 29 |
| View | 20 | 29 |
| Table Design | 4 | 5 |
| Table Layout | 26 | 30 |
| Picture Format | 0 | 13 |
| Shape Format | 0 | 6 |
| Header & Footer | 2 | 5 |
| Editing | 22 | 24 |
| Tools | 0 | 6 |
| Design | 10 | 10 |
| Layout | 18 | 19 |
| References | 24 | 24 |
| Mailings | 17 | 17 |
| Review | 26 | 29 |
| View | 25 | 29 |
| Table Design | 5 | 5 |
| Table Layout | 28 | 30 |
| Picture Format | 13 | 13 |
| Shape Format | 2 | 6 |
| Header & Footer | 5 | 5 |
| Editing | 23 | 24 |
| Tools | 3 | 6 |
## Missing
### File
- Backstage › Share (`file.share`)
- Backstage › Protect Document (`file.protect`)
- Backstage › Inspect Document (`file.inspect`)
- Backstage › Check Accessibility (`file.accessibility`)
- Backstage › Check Compatibility (`file.compatibility`)
- Backstage › Version History (`file.versions`)
- Backstage › Recover Unsaved (`file.recover`)
- Backstage › New from Template (`file.newFromTemplate`)
- Backstage › Save as Template (`file.saveTemplate`)
### Quick Access
- Toolbar › Repeat (`edit.repeat`)
- Toolbar › AutoSave (`file.autosave`)
### Home
- Clipboard › Paste Special (`edit.pasteSpecial`)
@@ -51,24 +34,16 @@ Generated by `cargo xtask parity` (`wordcraft-cli parity --markdown`): the word-
- Font › Character Border (`format.border`)
- Font › Phonetic Guide (`format.phonetic`)
- Font › Enclose Characters (`format.enclose`)
- Paragraph › Define New Bullet (`para.defineBullet`)
- Paragraph › Define New Number Format (`para.defineNumber`)
- Paragraph › Set Numbering Value (`para.setNumberingValue`)
- Paragraph › Text Direction RTL (`para.rtl`)
- Paragraph › Asian Typography (`para.asianTypography`)
- Styles › Style Inspector (`styles.inspector`)
- Styles › Manage Styles (`styles.manage`)
- Styles › Apply Styles (`styles.apply`)
- Editing › Advanced Find (`edit.advancedFind`)
- Editing › Select Objects (`select.objects`)
- Editing › Select Similar Formatting (`select.similar`)
- Voice › Dictate (`tools.dictate`)
- Editor › Editor (`review.editor`)
### Insert
- Tables › Draw Table (`table.draw`)
- Tables › Excel Spreadsheet (`insert.spreadsheet`)
- Illustrations › Online Pictures (`insert.onlinePicture`)
- Illustrations › Icons (`insert.icon`)
- Illustrations › 3D Models (`insert.model3d`)
@@ -78,13 +53,6 @@ Generated by `cargo xtask parity` (`wordcraft-cli parity --markdown`): the word-
- Illustrations › Drawing Canvas (`insert.canvas`)
- Add-ins › Get Add-ins (`addins.get`)
- Media › Online Video (`insert.video`)
- Links › Cross-reference (`insert.crossReference`)
- Header & Footer › Link to Previous (`layout.linkToPrevious`)
- Text › Quick Parts (`insert.quickParts`)
- Text › AutoText (`insert.autoText`)
- Text › Document Property (`insert.docProperty`)
- Text › Signature Line (`insert.signatureLine`)
- Text › Object (`insert.object`)
- Symbols › Ink Equation (`insert.inkEquation`)
### Draw
@@ -101,138 +69,42 @@ Generated by `cargo xtask parity` (`wordcraft-cli parity --markdown`): the word-
- Insert › Drawing Canvas (`insert.canvas`)
- Replay › Ink Replay (`draw.replay`)
### Design
- Document Formatting › Effects (`design.effects`)
### Layout
- Arrange › Position (`arrange.position`)
- Arrange › Wrap Text (`arrange.wrap`)
- Arrange › Bring Forward (`arrange.bringForward`)
- Arrange › Send Backward (`arrange.sendBackward`)
- Arrange › Selection Pane (`arrange.selectionPane`)
- Arrange › Align (`arrange.align`)
- Arrange › Group (`arrange.group`)
- Arrange › Rotate (`arrange.rotate`)
### References
- Footnotes › Footnote Options (`references.noteOptions`)
- Research › Researcher (`references.researcher`)
- Citations › Insert Citation (`references.citation`)
- Citations › Manage Sources (`references.sources`)
- Citations › Style (`references.citationStyle`)
- Citations › Bibliography (`references.bibliography`)
- Captions › Insert Table of Figures (`references.tableOfFigures`)
- Captions › Update Table of Figures (`references.updateFigures`)
- Captions › Cross-reference (`insert.crossReference`)
- Index › Mark Entry (`references.markEntry`)
- Index › Insert Index (`references.index`)
- Index › Update Index (`references.updateIndex`)
- Table of Authorities › Mark Citation (`references.markCitation`)
- Table of Authorities › Insert Table of Authorities (`references.tableOfAuthorities`)
### Mailings
- Create › Envelopes (`mailings.envelopes`)
- Create › Labels (`mailings.labels`)
- Start Mail Merge › Start Mail Merge (`mailings.start`)
- Start Mail Merge › Select Recipients (`mailings.recipients`)
- Start Mail Merge › Edit Recipient List (`mailings.editRecipients`)
- Write & Insert Fields › Highlight Merge Fields (`mailings.highlightFields`)
- Write & Insert Fields › Address Block (`mailings.addressBlock`)
- Write & Insert Fields › Greeting Line (`mailings.greetingLine`)
- Write & Insert Fields › Insert Merge Field (`mailings.insertField`)
- Write & Insert Fields › Rules (`mailings.rules`)
- Write & Insert Fields › Match Fields (`mailings.matchFields`)
- Preview Results › Preview Results (`mailings.preview`)
- Preview Results › Next Record (`mailings.next`)
- Preview Results › Previous Record (`mailings.previous`)
- Preview Results › Find Recipient (`mailings.findRecipient`)
- Preview Results › Check for Errors (`mailings.checkErrors`)
- Finish › Finish & Merge (`mailings.finish`)
### Review
- Proofing › Spelling & Grammar (`review.spelling`)
- Proofing › Thesaurus (`review.thesaurus`)
- Speech › Read Aloud (`review.readAloud`)
- Accessibility › Check Accessibility (`file.accessibility`)
- Language › Translate (`review.translate`)
- Language › Language (`review.language`)
- Tracking › Show Markup (`review.showMarkup`)
- Compare › Compare (`review.compare`)
- Compare › Combine (`review.combine`)
- Protect › Block Authors (`review.blockAuthors`)
- Protect › Restrict Editing (`review.restrict`)
- Ink › Hide Ink (`review.hideInk`)
### View
- Immersive › Immersive Reader (`view.immersive`)
- Page Movement › Vertical (`view.vertical`)
- Page Movement › Side to Side (`view.sideToSide`)
- Window › Arrange All (`view.arrangeAll`)
- Window › View Side by Side (`view.sideBySide`)
- Window › Synchronous Scrolling (`view.syncScroll`)
- Window › Switch Windows (`view.switchWindows`)
- Macros › Macros (`tools.macros`)
- Macros › Record Macro (`tools.recordMacro`)
### Table Design
- Borders › Border Painter (`table.borderPainter`)
### Table Layout
- Draw › Draw Table (`table.draw`)
- Draw › Eraser (`table.eraser`)
- Alignment › Text Direction (`table.textDirection`)
- Alignment › Cell Margins (`table.cellMargins`)
### Picture Format
- Adjust › Remove Background (`picture.removeBackground`)
- Adjust › Corrections (`picture.corrections`)
- Adjust › Color (`picture.color`)
- Adjust › Artistic Effects (`picture.effects`)
- Adjust › Transparency (`picture.transparency`)
- Adjust › Compress Pictures (`picture.compress`)
- Adjust › Change Picture (`picture.change`)
- Adjust › Reset Picture (`picture.reset`)
- Picture Styles › Picture Styles (`picture.style`)
- Picture Styles › Picture Border (`picture.border`)
- Accessibility › Alt Text (`picture.altText`)
- Size › Crop (`picture.crop`)
- Size › Size (`picture.size`)
### Shape Format
- Shape Styles › Shape Fill (`shape.fill`)
- Shape Styles › Shape Outline (`shape.outline`)
- Shape Styles › Shape Effects (`shape.effects`)
- Text › Text Direction (`shape.textDirection`)
- Text › Align Text (`shape.alignText`)
- Text › Create Link (`shape.link`)
### Header & Footer
- Navigation › Previous Section (`hf.previous`)
- Navigation › Next Section (`hf.next`)
- Position › Header from Top (`hf.position`)
### Editing
- Selection › Extend Selection (F8) (`select.extend`)
- Selection › Column Selection (`select.column`)
### Tools
- Proofing › AutoCorrect Options (`tools.autocorrect`)
- Proofing › Set Proofing Language (`review.language`)
- Customize › Customize Ribbon (`tools.customizeRibbon`)
- Customize › Customize Keyboard (`tools.customizeKeyboard`)
- Protection › Encrypt with Password (`file.encrypt`)
- Templates › Templates and Add-ins (`tools.templates`)