@domandigital/craft 0.12.0 → 0.14.0
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/CHANGELOG.md +26 -0
- package/CHARACTER.md +140 -1
- package/COPY.md +5 -0
- package/dist/{audit-5QWFLZ6L.js → audit-6WHR7ZTV.js} +7 -3
- package/dist/audit.cjs +1267 -165
- package/dist/audit.d.cts +95 -1
- package/dist/audit.d.ts +95 -1
- package/dist/audit.js +1265 -165
- package/dist/{chunk-J3QUROJ5.js → chunk-3OTKMKJQ.js} +66 -91
- package/dist/{chunk-PU5G5DUC.js → chunk-7T5WR74C.js} +27 -14
- package/dist/{chunk-AL6MRG6V.js → chunk-GQVEYTBY.js} +3592 -2173
- package/dist/{chunk-S3NZAVU6.js → chunk-OOZOEWGD.js} +1 -1
- package/dist/{chunk-CDAJUS5U.js → chunk-PBK6SYH5.js} +51 -16
- package/dist/{chunk-ULPI335S.js → chunk-Q7ILL2HV.js} +211 -10
- package/dist/chunk-QYBAVU3P.js +6 -0
- package/dist/{chunk-ZKVJ7K6X.js → chunk-WUACK2HX.js} +2 -1
- package/dist/chunk-XVBR2UPH.js +217 -0
- package/dist/cli-3CGUKXY4.js +19 -0
- package/dist/{cli-ZPJIWVEP.js → cli-O3CDSONO.js} +7 -8
- package/dist/{cli-ZB2VJ7CY.js → cli-WG3UJNUF.js} +15 -16
- package/dist/cli-WSHPSWVU.js +21 -0
- package/dist/{cli-C3JLFXMG.js → cli-Z2IQG3LC.js} +5 -5
- package/dist/cli.js +3 -2
- package/dist/index.cjs +1719 -636
- package/dist/index.d.cts +570 -196
- package/dist/index.d.ts +570 -196
- package/dist/index.js +1684 -636
- package/dist/migrate-VIFAYIBM.js +9 -0
- package/package.json +1 -1
- package/word-lists.json +1 -1
- package/dist/chunk-LHGY43LL.js +0 -462
- package/dist/chunk-PZ4MF2VV.js +0 -117
- package/dist/cli-2DY3V3SF.js +0 -17
- package/dist/cli-QM2AQQMF.js +0 -19
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# @domandigital/craft
|
|
2
2
|
|
|
3
|
+
## 0.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8686cf1: Phase N, specificity. `specificity(text, brief?)` counts what only this business could have written: names, places, numbers, prices, dates, contact details and trade nouns, with Title Case and shouted lines read without their capitals and stock figures ("24/7", "100%", "5-star") masked. A brief's own terms are recognised wherever they appear. Snapshots now record each section's `text` and the `firstScreenText` a visitor reads before scrolling, leaving out navigation, buttons, links and footers. Two new tells, both `warn`: `generic-hero-claim` (copy and rendered, home page only: the headline and the line under it name nothing particular) and `unproven-claim` (rendered: a claim of standing such as "trusted" or "fully qualified" with no review, rating, registration number or accreditation in its section or the one either side). `craft copy compare <ours> --competitor <theirs>` lists the hero and service sentences on each page that hold no specific the other page lacks. The catalogue table no longer prints "rendered + rendered" for rendered-only tells.
|
|
8
|
+
|
|
9
|
+
## 0.13.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 72527d6: Phase L: component-level sameness.
|
|
14
|
+
|
|
15
|
+
- Six rendered tells, all `warn`, read from snapshot version 2: `cta-band-stock` (a centred band on its own colour with one or two buttons), `pricing-trio-popular` (three price cards, one badged "Most popular"), `testimonial-avatar-carousel`, `faq-accordion-closer` (the page ends on a question list), `stats-row` (a row of three to six big figures) and `centred-everything`. A version 1 snapshot never trips them. `CATALOGUE_VERSION` is `2026.09.10`.
|
|
16
|
+
- Tells can now have `surface: "rendered"`: they exist only on a rendered page, so they carry snapshot fixtures and no source fixtures. `runTell` refuses them; use `auditSnapshot`.
|
|
17
|
+
- Snapshot sections gain `badges`, `avatars`, `carousel` and `figures`; fingerprint sections gain `symmetry`, `controls`, `cards`, `background`, `badges`, `avatars`, `carousel` and `figures`.
|
|
18
|
+
- `craft estate compare --component <role>` ranks pairs of sites by how alike one component is and names what they share. `craft estate compare <site> --component <role>` compares one site against the rest. There is no sibling line for components yet, so it ranks and judges nothing.
|
|
19
|
+
- `craft audit --null` scores each component against the same role in the null model (`components` in the JSON).
|
|
20
|
+
- New exports: `RENDERED_TELLS`, `COMPONENT_ROLES`, `PROMO_BADGE`, `componentsOf`, `componentDistance`, `componentShared`, `closestComponents`, `estateComponentPairs`, `componentTypicality`, `componentTypicalities`, and the types `RenderedTell`, `ComponentPair`, `ComponentTypicality`.
|
|
21
|
+
|
|
22
|
+
- 8f5dbf6: Phase M: imagery and provenance.
|
|
23
|
+
|
|
24
|
+
- Snapshots record every picture on the page as `images`: each `img` and each CSS background large enough to be one, with its source (unwrapped from `/_next/image?url=`, `/_vercel/image` and Cloudflare's `/cdn-cgi/image/`), size, position, section, alt text and a role (`photo`, `illustration`, `icon`, `avatar`, `logo`). At most 60, largest first. Older snapshots have no `images` and are never judged on them.
|
|
25
|
+
- `craft audit` reads the first 256 KB of up to 24 of the larger pictures (20 seconds at most per page) and records `provenance`: the IPTC digital source type when an XMP packet or a C2PA manifest says a trained model made the picture. Only a positive is evidence; a picture with no marker is unknown. `snapshotUrl(url, { provenance: false })` skips the reads.
|
|
26
|
+
- Four rendered tells, all `warn`: `stock-photo` (a stock library or placeholder service, by host or by the library's own file name), `stock-avatar` (placeholder-face services), `ai-image` (the picture's own metadata says a model made it) and `no-real-imagery` (a page of four or more sections with no photograph). `CATALOGUE_VERSION` is `2026.09.11`.
|
|
27
|
+
- New exports: `IMAGERY_TELLS`, `STOCK_PHOTO_HOSTS`, `STOCK_AVATAR_HOSTS`, `stockSource`, `stockAvatarSource`, `scanProvenance`, `PROVENANCE_SCAN_BYTES`, `AI_SOURCE_TYPES`, and the types `SnapshotImage`, `ImageRole`, `ImageProvenance`. From `@domandigital/craft/audit`: `PROVENANCE_MAX_IMAGES`, `PROVENANCE_BUDGET_MS`.
|
|
28
|
+
|
|
3
29
|
## 0.12.0
|
|
4
30
|
|
|
5
31
|
### Minor Changes
|
package/CHARACTER.md
CHANGED
|
@@ -192,6 +192,110 @@ against different sets.
|
|
|
192
192
|
Known limit: a computed font family is the family the stylesheet asked for.
|
|
193
193
|
A face that failed to load is still reported under its name.
|
|
194
194
|
|
|
195
|
+
### Stock components (snapshot v2)
|
|
196
|
+
|
|
197
|
+
A version 2 snapshot names what each section is for (`role`: a CTA band,
|
|
198
|
+
pricing, testimonials, an FAQ, a process, features, a team, a contact form)
|
|
199
|
+
and how it is laid out (`geometry`: centring, width, balance, its own ground,
|
|
200
|
+
its buttons), with the parts that make a component a stock one: badge texts,
|
|
201
|
+
round portraits, a carousel, a row of big figures. Six tells read them, and
|
|
202
|
+
only them, so a version 1 snapshot never trips one:
|
|
203
|
+
|
|
204
|
+
- `cta-band-stock`: a centred band on its own colour with one or two buttons.
|
|
205
|
+
- `pricing-trio-popular`: three price cards, one badged "Most popular".
|
|
206
|
+
- `testimonial-avatar-carousel`: round headshots in a sliding carousel.
|
|
207
|
+
- `faq-accordion-closer`: the page ends on a question-and-answer list.
|
|
208
|
+
- `stats-row`: three to six big figures in a row (not straight after the
|
|
209
|
+
hero, which is `hero-then-proof`'s finding).
|
|
210
|
+
- `centred-everything`: 80% or more of the sections centre their text.
|
|
211
|
+
|
|
212
|
+
Each fix keeps the component's job (the ask, the prices, the proof, the
|
|
213
|
+
answers) and changes how it looks. None removes a section, because the
|
|
214
|
+
page's order is the client's, not ours.
|
|
215
|
+
|
|
216
|
+
These six have rendered paths only (surface `rendered`): no source file shows
|
|
217
|
+
a pricing trio reliably. They ship as warnings like every tell, and have not
|
|
218
|
+
yet been read against the estate. Snapshot the estate with this build before
|
|
219
|
+
any is considered for `block`.
|
|
220
|
+
|
|
221
|
+
### Imagery and provenance
|
|
222
|
+
|
|
223
|
+
A snapshot records every picture on the page (`images`): each `img` and
|
|
224
|
+
each CSS background large enough to be one, with its source (unwrapped from
|
|
225
|
+
an image optimiser such as `/_next/image?url=`), size, position, section and
|
|
226
|
+
a role: photo, illustration, icon, avatar or logo. `craft audit` also reads
|
|
227
|
+
the first 256 KB of up to 24 of the larger pictures and looks for the IPTC
|
|
228
|
+
digital source type that says a trained model made them
|
|
229
|
+
(`trainedAlgorithmicMedia` or `compositeWithTrainedAlgorithmicMedia`), in an
|
|
230
|
+
XMP packet or a C2PA manifest (Content Credentials). Four tells read them:
|
|
231
|
+
|
|
232
|
+
- `stock-photo`: a picture from a stock library or placeholder service, by
|
|
233
|
+
its host (Unsplash, Pexels, iStock, Adobe Stock and others) or, when it was
|
|
234
|
+
downloaded and self-hosted, by the library's own file name
|
|
235
|
+
(`shutterstock_1234567890.jpg`, `…-unsplash.jpg`).
|
|
236
|
+
- `stock-avatar`: round portraits from a placeholder-face service
|
|
237
|
+
(randomuser.me, Pravatar, DiceBear, generated-face sites) or a stock library.
|
|
238
|
+
- `ai-image`: a picture whose own metadata says a model made it.
|
|
239
|
+
- `no-real-imagery`: a page of four or more sections with no photograph at
|
|
240
|
+
all, only icons and illustrations.
|
|
241
|
+
|
|
242
|
+
Provenance only ever counts for. Most pictures carry no metadata, anything
|
|
243
|
+
that re-encodes them (a CMS, an image optimiser) strips it, and a PNG can
|
|
244
|
+
keep it after the pixels, beyond the bytes read. A picture with no marker is
|
|
245
|
+
unknown, not real. `snapshotUrl(url, { provenance: false })` skips the reads.
|
|
246
|
+
|
|
247
|
+
Snapshots taken before craft recorded images have no `images`, and none of
|
|
248
|
+
these tells judges them. There is no `blob-illustration` tell: telling an
|
|
249
|
+
abstract blob from a diagram needs an SVG's path data or its pixels, which a
|
|
250
|
+
cross-origin picture does not give the page, and no flag case has been proved
|
|
251
|
+
reliable. It stays on the list until one is.
|
|
252
|
+
|
|
253
|
+
### Specificity
|
|
254
|
+
|
|
255
|
+
A page built from no brief could belong to anyone, because the model had
|
|
256
|
+
nothing particular to say. Specificity counts what only this business could
|
|
257
|
+
have written: names, places, numbers, prices, dates, contact details, and
|
|
258
|
+
the nouns of the trade (`TRADE_NOUNS`, a seed list). Two rules keep the
|
|
259
|
+
count honest. A Title Case or shouted line's capitals are not read as names
|
|
260
|
+
("Quality You Can Trust" is not a proper noun), and the figures every site
|
|
261
|
+
uses ("24/7", "100%", "5-star", "No. 1") are masked before counting. A text
|
|
262
|
+
is generic when it has no specific other than trade nouns and fewer than two
|
|
263
|
+
of those: one trade noun ("quality plumbing you can trust") is what every
|
|
264
|
+
competitor also says.
|
|
265
|
+
|
|
266
|
+
A snapshot now records the page's text: each section's headings,
|
|
267
|
+
paragraphs, list items and quotes (`text`), and what a visitor reads before
|
|
268
|
+
scrolling (`firstScreenText`), leaving out navigation, a header without the
|
|
269
|
+
headline, footers and the words on buttons and links. Two tells read it:
|
|
270
|
+
|
|
271
|
+
- `generic-hero-claim`: the home page's first screen names nothing
|
|
272
|
+
particular. Also a copy tell, on a literal `<h1>` and the paragraph under
|
|
273
|
+
it in the home page's source (a root route file such as `app/page.tsx`, a
|
|
274
|
+
top-level `index.html`, or a hero or home component). Every other page's
|
|
275
|
+
headline is a label ("Privacy policy", "Boiler repairs"), not a claim, and
|
|
276
|
+
is not judged.
|
|
277
|
+
- `unproven-claim`: a claim of standing ("trusted", "fully qualified",
|
|
278
|
+
"award-winning", "5-star service") with no review, rating, quoted
|
|
279
|
+
testimonial, registration number or accreditation (by name, or as a logo
|
|
280
|
+
whose alt text or file name names it) in its section or the one either
|
|
281
|
+
side.
|
|
282
|
+
|
|
283
|
+
A brief sharpens the count: its own terms (the business's name, its town,
|
|
284
|
+
its trade) are recognised wherever they appear, even opening a sentence or
|
|
285
|
+
in a shouted heading. The tells run without one. `craft copy compare <ours>
|
|
286
|
+
--competitor <theirs>` uses one, from `--brief`, `art-direction.json` or a
|
|
287
|
+
null model's `null.json`, and lists the hero and service sentences on each
|
|
288
|
+
page that hold no specific the other page lacks: a town both name, or a
|
|
289
|
+
trade noun both use, is shared; the business's name, its prices and its
|
|
290
|
+
jobs are its own. It is a measure for a person to read and always exits 0.
|
|
291
|
+
|
|
292
|
+
The limits, stated so nobody reads more into a pass than is there: a place
|
|
293
|
+
in a Title Case heading ("Boiler Repairs In Brackley") is not recognised
|
|
294
|
+
without a brief, a headline whose words come from data (`{site.headline}`)
|
|
295
|
+
is not read in source, and "specific" means particular, not true. `craft
|
|
296
|
+
copy claims` is where a figure gets checked. Snapshots taken before craft
|
|
297
|
+
recorded text have none, and neither tell judges them.
|
|
298
|
+
|
|
195
299
|
## The counterfactual
|
|
196
300
|
|
|
197
301
|
A list of tells goes stale; the model does not. So signal 2 asks the model
|
|
@@ -257,6 +361,29 @@ pipeline that has decided to hold the line.
|
|
|
257
361
|
`craft direction propose --estate estate.json` reads the register too, so a
|
|
258
362
|
proposed accent steers away from one a sibling already uses.
|
|
259
363
|
|
|
364
|
+
Sites that share one component are rarer than siblings and easier to fix:
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
craft estate compare --component cta-band # every pair's closest CTA bands
|
|
368
|
+
craft estate compare --component pricing --json
|
|
369
|
+
craft estate compare rmp --component cta-band # one site against the rest
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Each pair lists what its two components share ("centred", "1 button", "same
|
|
373
|
+
coloured band"), closest first. There is no sibling line for components yet:
|
|
374
|
+
it needs a calibration set of real components (see the CTA collection in
|
|
375
|
+
`calibration/idiom/cta/` once it exists), so this ranks and names, and judges
|
|
376
|
+
nothing. Only sites added with snapshot v2 have components to compare, and
|
|
377
|
+
the command says so when fewer than two have the role. `--component` takes
|
|
378
|
+
one of `cta-band`, `footer-cta`, `pricing`, `testimonials`, `faq`, `process`,
|
|
379
|
+
`features`, `team`, `contact` or `stats`.
|
|
380
|
+
|
|
381
|
+
With `--null`, `craft audit` also places each of the page's components
|
|
382
|
+
against the same role in the null model, the way it places the whole page
|
|
383
|
+
(`components` in the JSON). A role needs at least five null pages that have
|
|
384
|
+
it. Null models built before snapshot v2 have no components, and the report
|
|
385
|
+
says so rather than printing nothing.
|
|
386
|
+
|
|
260
387
|
## The character report
|
|
261
388
|
|
|
262
389
|
`craft report` reads one site against everything above and gives a verdict:
|
|
@@ -541,7 +668,7 @@ Generated from the package. Run `pnpm --filter @domandigital/craft run docs`
|
|
|
541
668
|
after changing an entry; a test fails until you do.
|
|
542
669
|
|
|
543
670
|
<!-- craft:catalogue:start -->
|
|
544
|
-
Catalogue version `2026.09.
|
|
671
|
+
Catalogue version `2026.09.12`, 68 tells.
|
|
545
672
|
|
|
546
673
|
| Id | Gen | Surface | Severity | Tell | Why it is a default |
|
|
547
674
|
| --- | --- | --- | --- | --- | --- |
|
|
@@ -601,4 +728,16 @@ Catalogue version `2026.09.9`, 56 tells.
|
|
|
601
728
|
| `repeated-sentence` | 1 | copy | warn | Repeated sentence | The same sentence on two pages, or the same nine words lightly edited, is one of the strongest signs a document was assembled rather than written. |
|
|
602
729
|
| `heading-shape` | 2 | copy | warn | One heading shape | Headings that all share one shape ('X, and Y', 'X, because Y', 'Keep, rewrite, consolidate, retire') read as a template filled in section by section. |
|
|
603
730
|
| `heading-echo` | 2 | copy | warn | Heading echoed | A heading repeated word for word as the first line under it spends the reader's attention twice on the same words. |
|
|
731
|
+
| `generic-hero-claim` | 1 | copy + rendered | warn | Headline that fits any business | The first thing a visitor reads on the home page names no place, no person, no price and no job, so it would fit every competitor's site unchanged. A model writes it when it has nothing particular to say. |
|
|
732
|
+
| `cta-band-stock` | 1 | rendered | warn | Stock call-to-action band | A full-width coloured band with a centred heading, one line and one or two buttons is what a model closes every section run with. It asks for the booking the same way on every site. |
|
|
733
|
+
| `pricing-trio-popular` | 1 | rendered | warn | Three-tier pricing with a popular badge | Three price cards with the middle one badged 'Most popular' is the SaaS pricing page, applied to a plumber or a salon whether or not anyone chose the middle option. |
|
|
734
|
+
| `testimonial-avatar-carousel` | 1 | rendered | warn | Avatar testimonial carousel | Round headshots over quotes in a sliding carousel is the stock testimonial block. Most visitors see the first slide only, and stock or AI faces make every quote read as invented. |
|
|
735
|
+
| `faq-accordion-closer` | 2 | rendered | warn | FAQ accordion as the closer | Ending the page on a collapsed FAQ, often followed only by a band, is the model's default page ending. The answers a buyer needs are hidden behind clicks at the point they decide. |
|
|
736
|
+
| `stats-row` | 1 | rendered | warn | Row of big numbers | Three or four large figures in a row (500+ clients, 98% satisfaction, 10 years) is the stock proof block, and the numbers are often round, unsourced or invented. |
|
|
737
|
+
| `centred-everything` | 2 | rendered | warn | Every section centred | When almost every section stacks a centred heading over centred text, the page has no reading line and every block looks like the one before. It is the layout nothing was decided for. |
|
|
738
|
+
| `stock-photo` | 1 | rendered | warn | Stock photography | A picture from a stock library is the picture every other site in the trade can use. It shows a job the client did not do, in a kitchen that is not theirs, and a visitor who has seen it before stops believing the rest. |
|
|
739
|
+
| `stock-avatar` | 1 | rendered | warn | Stock or placeholder faces | Round portraits from a placeholder-face service or a stock library next to reviews make every quote read as invented, and some of those faces are generated people who do not exist. |
|
|
740
|
+
| `ai-image` | 2 | rendered | warn | Generated image | The file itself says a model made it (its XMP or Content Credentials name a trained-model source). A generated picture stands in for work the client did not photograph, and anyone can read the label. |
|
|
741
|
+
| `no-real-imagery` | 1 | rendered | warn | No photograph on the page | A page with no photograph at all, only icons and illustrations, is the page a model builds when it has no assets. Icon tiles stand in for the evidence a buyer looks for: the work, the premises, the people. |
|
|
742
|
+
| `unproven-claim` | 1 | rendered | warn | Claim with no proof next to it | "Trusted", "fully qualified" and "award-winning" ask the visitor to take the business's word for it. A page built with no reviews and no registration number makes the claim anyway, with nothing beside it. |
|
|
604
743
|
<!-- craft:catalogue:end -->
|
package/COPY.md
CHANGED
|
@@ -102,6 +102,7 @@ person reading decides which instance earns its place.
|
|
|
102
102
|
| `inline-label-list` | three or more bullets in a row opening "**Label:**", where the label repeats the line |
|
|
103
103
|
| `prompt-context` | "This article uses the attached Perplexity research file as the primary source", "the attached research is right to say", "the attached brief asks": the model naming what it was given. A web page has no attachment. **Zero in anything published** |
|
|
104
104
|
| `placeholder` | "[Insert client name]", lorem ipsum, `TODO_PLACEHOLDER`. Fine in a draft commit; **zero in anything delivered** |
|
|
105
|
+
| `generic-hero-claim` | on the home page (a root route file, a top-level `index.html`, or a hero or home component), a literal `<h1>` and the paragraph under it that name no place, person, number, price or job: "Quality you can trust", "Your vision, our expertise". One trade noun is not enough ("quality plumbing"); two are ("boiler and radiator repairs"). Also read on the rendered first screen by `craft audit` |
|
|
105
106
|
|
|
106
107
|
### Style is not evidence
|
|
107
108
|
|
|
@@ -218,6 +219,10 @@ Hyphenated compounds count as one word. Not automated.
|
|
|
218
219
|
sourced or UNSOURCED. A claim is sourced, corrected or cut, never re-cited
|
|
219
220
|
from memory. The copy check cannot do this part: a false figure in clean
|
|
220
221
|
prose passes every tell.
|
|
222
|
+
- **Proof sits next to the claim it backs.** "Trusted", "fully qualified",
|
|
223
|
+
"award-winning" and "5-star service" need a review, a rating or an
|
|
224
|
+
accreditation in the same section or the one either side of it. `craft
|
|
225
|
+
audit` reports each one that has none (`unproven-claim`, a warning).
|
|
221
226
|
|
|
222
227
|
## CTA rule
|
|
223
228
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
+
PROVENANCE_BUDGET_MS,
|
|
3
|
+
PROVENANCE_MAX_IMAGES,
|
|
2
4
|
VISUAL_MAX_HEIGHT,
|
|
3
5
|
audit,
|
|
4
6
|
collectInPage,
|
|
@@ -7,11 +9,13 @@ import {
|
|
|
7
9
|
snapshotPage,
|
|
8
10
|
snapshotUrl,
|
|
9
11
|
snapshotUrls
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-Q7ILL2HV.js";
|
|
11
13
|
import "./chunk-JYNXGCYZ.js";
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-GQVEYTBY.js";
|
|
15
|
+
import "./chunk-QYBAVU3P.js";
|
|
14
16
|
export {
|
|
17
|
+
PROVENANCE_BUDGET_MS,
|
|
18
|
+
PROVENANCE_MAX_IMAGES,
|
|
15
19
|
VISUAL_MAX_HEIGHT,
|
|
16
20
|
audit,
|
|
17
21
|
collectInPage,
|