01 / apply it
yardr pack apply ./visuals --depot <depot>From a clone of yardr-packs: the pack's directory. yardr pack check ./visuals --depot <depot> shows what it would change first.
yardr pack apply https://yardr.dev/packs/visuals/ --depot <depot>From this site, as the files below: from yardr v0.8.0 on.
02 / the flows
One flow.
flow visualbacklog → picked · 4 stages
03 / the files
Every file, as it ships.
# Visuals pack for yardr: the lane a composed visual takes before anyone
# holds the file. A bead of type visual carries a brief that names a format
# (a poster, a social card, a cover, a slide) and its size. A visual designer
# composes three directions at that exact size on the bead's branch and shoots
# each one, and a person looks at the shots, names the direction to hold, and
# holds its file with a PNG at the exact size (and a PDF where the brief is
# for print). Nothing lands.
# Like the starter pack it names no agent product, model, depot, person or
# secret: the import asks, and they stay in the yard. The format is the
# starter's (packs/starter/pack.yaml, docs/packs.md in the yardr repository).
name: visuals
# The kind of depot the pack is for: the directions are committed on the bead's
# branch.
kind: git
# The setup notes, for the operator: the import, the agent it asks for and the
# programs the shots need. pack check and pack apply print them.
setup: SETUP.md
# One flow, for beads of type visual, beside the flow the depot follows for its
# own work (the starter's, say): this pack has none without a type. The type is
# the pack's own because a type follows one flow. The webdesign pack's flow is
# for type mockup, so a pack that reused that type would have its import
# re-point every depot already on the mockup flow.
#
# There is no assembly stage. The directions stay on the bead's branch and the
# shots on its note, and the words of the person's pick name the direction to
# hold: landing all three files would put throwaways on the base, and landing
# one would need another agent to take the other two out. A bead ends at
# picked, where the person holds the picked file with its PNG (and its PDF for
# print) from the branch.
#
# Rounds are not limited. The only way back is a person's move from pick, with
# a note that says what to change, so a person decides each round.
flows:
visual:
type: visual
stages:
backlog: { group: backlog, file: flows/visual/backlog.md, manual: [directions] }
directions: { group: visual-designers, file: flows/visual/directions.md, outcomes: { done: pick, question: pick }, manual: [backlog] }
pick: { group: decisions, file: flows/visual/pick.md, manual: [picked, directions, backlog] }
picked: { end: true }
# The visual designers are a group of this pack's own. The webdesign pack takes
# a group of its own for the same reason: a pack names a group together with
# its role, so naming builders here would aim the depot's code builders at a
# designer's prompt, and naming webdesign's designers would aim this pack's
# role at mockup beads. The import makes <depot>-visual-designers and asks
# which agent runs it. One bead at a time: each serves its worktree and runs
# headless Chrome three times. A yard that wants more raises the limit of the
# group it has (yardr group set). backlog and decisions are the yard's two
# people groups, which the import reuses.
groups:
visual-designers: { agent: roles/visual-designer.md, limit: 1 }
backlog: { people: true }
decisions: { people: true }
# The designer's role tells it to mail {{yardmaster}}, so the pack names the
# crew member, as the starter does. It hears a bead enter pick, a bead close,
# and the events that need someone. The pack carries no role for it: the
# yardmaster keeps the prompt it has.
crew:
yardmaster:
hears:
events: [attention]
stages: [pick]
done: true
summary: a visual bead waits here until its brief names the format, the size and what to say A visual bead asks for three directions to pick from and hold, not for a page to ship. Before it is sent to `directions` its body says: - the format: what the visual is (a poster, a social card, a cover, a slide) and where it will be seen; - the size: for screen, the exact pixels, width by height (1080x1350, say); for print, the trim size and which it is (A4, A5, US Letter, say); - the subject: what the product, place or person is, in one concrete sentence; - the audience: who sees the visual; - the job: the one thing the visual gets its viewer to do or feel; - the words: the copy that must appear, or that the designer writes it; - what the brief fixes: brand colours, typefaces, a logo, pictures that must appear, or that nothing is fixed; - reference work: pictures or addresses of work the person likes or dislikes, each with what to take from it or leave; - what is not wanted: looks already tried and turned down. Send it with `yardr bead advance <id> --to directions`.
summary: you compose three directions at the brief's exact size and put their shots on one note You make directions here, not a finished file. You work on branch `yard/<bead>` in the bead's own worktree. The bead's body is the brief, and your role says how to work. Before the bead leaves as `done`: - three files `directions/<n>-<name>.svg` or `directions/<n>-<name>.html` are committed on the branch, each composed at the brief's exact size and opening on its own with no build step; - beside each, its finished PNG at the exact size is committed (`directions/<n>-<name>.png`), and for a print brief its PDF (`directions/<n>-<name>.pdf`), taken at the last commit; - one note on the bead carries the three shots at the exact size, taken at the last commit, and says that commit's short SHA; - the same note gives each file's address on the watch (the address `yardr preview watch` printed, then the file name), or what the command printed when it gave none; the watch ends when the bead leaves `directions`, so the shots are the record; - the same note names each direction's idea, type pairing and palette, and your role's distinctness rule holds for the three. Outcomes: - `done`: all of that holds. The bead goes to `pick`, where a person looks at the shots. - `question`: no direction can start without an answer, a size the brief never names, say. Note exactly what you need first. The bead goes to `pick`, where a person answers and sends it back to `directions`.
summary: a person looks at the shots, names the direction to hold, or sends the bead back For a person. What to read: the designer's note on the bead, which carries the three shots at the brief's exact size and names each direction (`yardr prime --bead <id>` prints the bead with every note in full). The directions are files that open on their own, on the bead's branch `yard/<bead>` under `directions/`; the shots are what to judge them by. A bead leaves `pick` when a person moves it, with words: - to `picked` when a direction is taken: the bead closes, and nothing lands on the base. Name the direction in your words, by its number and name, and say what to keep from the others. What you hold is the picked file with its PNG at the exact size (and its PDF where the brief is for print), on the branch under `directions/`; - to `directions` with a note when none is there yet: say what to change, and the designer composes three again; - to `backlog` to park it or have the brief reshaped. A bead also comes here when the designer could not start without an answer: the note says what it needs. Answer in a note and send it back to `directions`. When a bead arrives the yard puts a card for these moves on it, and picking one moves the bead: your words with the pick stay on the bead for whoever works it next. A bead with an ask already open gets no card, and a card gives way to an ask put after it: that question is what you answer, and the bead is moved by hand once it is. ## Ask kind: moves question: Which direction do you hold, or where should this bead go next? context: - The designer's note holds the three shots at the brief's exact size and names each direction. The directions are on the bead's branch under directions/. - To hold one, move the bead to picked and name it in your words. To ask for another round, move it back to directions and say what to change. - Your words with the pick stay on the bead for whoever works it next.
# Visuals A pack for a yard that wants finished visuals from agents: posters, social cards, covers, slides. A brief goes in, three directions come out, each composed at the brief's exact size with a picture of it, and a person picks one and holds the finished file. Nothing lands. Nothing here is compiled into yardr; apply it with: ```sh yardr pack apply /path/to/yardr-packs/visuals --depot <depot> ``` `yardr pack check /path/to/yardr-packs/visuals --depot <depot>` shows what the import would do first, and writes nothing. SETUP.md is the operator's steps. The pack adds the bead type `visual` beside the flows a depot already follows. A depot on the webdesign pack's mockup flow keeps it. One type follows one flow, and the webdesign pack's flow is for the type `mockup`, so a pack that reused that type would have its import re-point every depot on the mockup flow. The type `visual` is this pack's own, and an import leaves every other type's flow, routes and groups as they are. ## How it hangs together ``` backlog -> directions directions -> pick on done | pick on question | backlog pick -> picked | directions | backlog picked terminal ``` | stage | worked by | what happens | |---|---|---| | `backlog` | `backlog`, people | the bead waits until its brief says the format, the size, the subject, the audience, the job, the words, what is fixed, reference work and what is not wanted | | `directions` | `visual-designers` | an agent commits three direction files, `directions/<n>-<name>.svg` or `.html`, each composed at the brief's exact size, starts a watch on the folder so the person can open the files while they are built, shoots each at that size (and prints a PDF where the brief is for print), and puts the shots on one note that names each direction's idea, type pairing and palette and each file's address on the watch | | `pick` | `decisions`, people | a person reads the shots and moves the bead to `picked`, back to `directions` with a note, or to `backlog`; the yard puts a card on the bead offering these moves, and the person's words with the pick name the direction | | `picked` | | the end: the bead closes, and the person holds the picked file with its PNG (and its PDF for print) from the branch | `question` also leads to `pick`. A designer that cannot start without an answer (a brief that names no size) says what it needs on a note, and the person answers there and sends the bead back to `directions`. There is no assembly stage. The directions stay on the bead's branch `yard/<bead>` and the shots on its note, and the words of the pick name the direction to hold. Landing all three files would put throwaways on the base, and landing one would need another agent to take the other two out. What the person holds is the picked file with its finished PNG at the exact size (and its PDF where the brief is for print), on the branch under `directions/`. **Three directions that differ in idea.** The designer's role asks for three ideas, each a composition built around something that only this subject has, and for each a type pairing and a palette. The rule is that no two directions share the same idea, and a palette alone never carries the difference: one layout in three tints fails it. A brief that fixes the brand's colours or typefaces keeps them in all three, and the ideas carry the difference. **The exact size.** The designer shoots each file with headless Chrome run directly, at the brief's exact pixels (`--window-size`, `--screenshot`), and checks each PNG with `file`. The shot script yardr carries (`contrib/shot`) takes a width only and keeps the height at 800, which is why the role runs Chrome itself. For a print brief the PNG is the trim size at 96 CSS pixels to the inch (A4 is 794x1123), and the PDF, printed with `--print-to-pdf` from a page that carries the trim size, is the print master. A file narrower than 500 pixels is shot through a frame of its exact size, since Chrome on macOS lays narrower windows out 500 wide. **The watch.** Once the first file exists the designer starts `yardr preview watch $YARDR_BEAD directions`. The yard serves the folder's files read-only through its preview endpoint, and a file reloads in the browser whenever it changes, so the person sees the three directions take shape. The command prints the address they open at on its `opens at` line: the host the yard's edge gave the watch, or the path `/preview/<app>/` on the yard where the edge gives none. `directions/` holds no `index.html`, so the folder's own address answers 404, and so does the Open button of the watch's card on the Previews page. The designer therefore names each file's address, the printed address followed by the file name, and puts the three on a note as soon as the watch is up, so the person has them while the designer builds. The note with the shots gives them again. The watch ends by itself when the bead leaves `directions`, so the shots are the record of what the person picks from. ## What it needs - **An agent for `<depot>-visual-designers`.** The import asks for its kind, model and permission arguments, as it does for any agent group it makes. The group is the pack's own and not the depot's `builders`: a pack names a group together with its role, so naming `builders` would aim the depot's code builders at a designer's prompt. One designer works at a time, and `yardr group set <depot>-visual-designers --limit 2` allows more. - **The yard's two people groups**, `backlog` and `decisions`, which the import reuses when the yard has them and asks for the members when it does not. - **A crew member called `yardmaster`**, or another that takes the name (`--crew yardmaster=<name>`). It hears a bead enter `pick`, a bead close, and the events that need someone. The pack carries no role for it, so the yardmaster keeps its prompt. - **On the yard's machine**, for the shots: headless Chrome (Google Chrome in `/Applications`, `google-chrome` or `chromium` on the PATH, or a path in `SHOT_CHROME`), `python3` and a yardr checkout to read. The directions load their typefaces from CDNs, so the machine needs the network while a designer works. - **A yardr with `yardr preview watch`**, for the watch (yardr 26b2a52, 4 November 2026, and after). `yardr docs watch` prints its page on a yardr that has the command and names the pages it has on one that does not. On an older yardr `yardr preview watch` prints the help of `preview` and ends 0, so the designer goes by the `opens at` line: with none, it puts what the command printed on its note and goes on, and the shots are as before. The address is the path on the yard until the yard is linked to an edge that gives the watch a host (yardr ec29917, 4 November 2026, and after). Where the yard is linked and the edge refuses, the command prints the edge's words under the path. ## What the import asks Beside a yard that has `backlog`, `decisions` and a `yardmaster`: the agent of `<depot>-visual-designers` (`--bind visual-designers=<kind>[:<model>]`), or the group of the yard that takes it (`--group visual-designers=<group>`). Otherwise also the members of `backlog` and `decisions` (`--members decisions=<a>,<b>`) and which crew member takes `yardmaster` (`--crew yardmaster=<name>`). ## Files - `pack.yaml`: the flow, the groups that work it and the crew member its role names. - `flows/visual/`: a stage file for each stage a bead waits or is worked in. What a stage needs to be true is here, and how a designer works is in the role. - `roles/visual-designer.md`: the designer's role. It holds the work in five steps, the house style for composed stills, and the exact-size mechanics. - `SETUP.md`: the operator's cards. - `test`: the pack's tests. Files of a pack that `pack.yaml` does not name are not installed. The role and the stage files point at none of them, because the yard that imports the pack never has them. ## Runtimes The pack has no program of its own beyond `test`, which needs `sh` and `grep`. The designer's steps use `git`, `file` and headless Chrome run directly. ## Testing `sh .yardr/test` at the root of the repository runs `yardr pack check` and then `visuals/test`. The test needs no network and no secret and takes well under a second. It is text, so it pins what a later edit could lose without a sound: - the role carries the distinctness rule, the exact-size mechanics (Chrome run directly, the PNG shot and its check, the print PDF and its check, the frame under 500 wide) and the watch (the command with the bead's id, how a file's address is made, and the two notes that carry the addresses); - each stage file has its exit line, `directions.md` names the finished PNG and PDF, the role's distinctness rule and the address of each file on the watch, `backlog.md` names the size, and `pick.md` has the card of its moves; - the decisions of `pack.yaml`: the pack's own type and group, no script group, the yardmaster hearing `pick` and carrying no role; - no role or stage file points at a file the import does not install. ## What was checked, and what was not Checked, in a scratch yard under a short temp directory, with an environment of nothing but `HOME` and `PATH`, hand-walked throughout so that no agent started (the trial played designer and person by hand): - `yardr pack check` and `yardr pack apply` of this directory into a depot, with the answers on the command line as SETUP.md gives them. The flow prints as the four stages above, the installed role has no placeholder left, and the yard reads all three stage files and the card without a warning. - Checked against a depot that already follows the webdesign pack, the plan shows the mockup pointer, its routes and its groups as `not in the pack (would be left alone)`, and `backlog` and `decisions` as `unchanged`. Against a fresh yard the plan instead creates `backlog` and `decisions` and asks for their members, and creates the yardmaster's two subscriptions with the `yardmaster` itself `unchanged`. - Two beads of type `visual` walked from a brief to three direction files with shots on a note to picked: one for screen (1080x1350) and one for print (A4). Each held PNG is byte-exact to the brief's size (`file` names its pixels), with a PDF at the trim size for the print one. A third bead walked the `question` outcome to `pick` and back to `directions` with words, and the pick card rendered on it with its question and moves. - The role's exact-size mechanics, step by step as separate commands: the PNG of an HTML file and of an SVG file at 1080x1350, `file` naming `PNG image data, 1080 x 1350`; the PDF of a print page, `file` naming one page and `MediaBox` the trim size; a width under 500 shot through a frame at its exact width; a note with three `--file`; and the temp directory removed. - The test breaks on each of 26 changes made to a copy, one at a time: the distinctness rule, each mechanics flag and check, the watch command and its address rules, the type, the group, the limit, an added script group, a crew role, an exit line, the pick card, and a link to a file the import leaves behind. Not checked: - No designer agent has run this role or started its watch. Whether one follows it to three directions that differ in idea, and how good they are, is not known. The first real bead is that test. The watch command was read and not run against a bead, so what a person sees in a browser, and whether the addresses reach the person in time, is as the docs describe. - Shots on a machine other than a Mac with Google Chrome. The role looks for Chrome and Chromium elsewhere, and has not been run there. ## Left out - **Generated images and any image model.** A picture the machine dreams up is a source pack of its own, later, added on without changing this one. This pack composes: type, layout, shapes, charts. - **A dir depot version**, for people with no repository. - **Brand kits kept between beads.** Each bead carries what its brief fixes. - **Video and motion.** A still is what this pack holds. - **Landing anything on a base.** There is no assembly by design. - **A printer's bleed past trim.** The file is the trim size exactly; full-bleed art runs to its edge. - **The type `mockup`.** One type follows one flow, so it stays webdesign's.
# Visual designer
You make visual directions for one bead, in its own worktree on branch
`yard/<bead>`. A bead of type visual carries a brief that names a format (a
poster, a social card, a cover, a slide) and its size, and asks for three
directions that a person looks at and picks one to hold. Your product is three
direction files, each composed at the brief's exact size, a finished PNG of
each at that size (and a PDF where the brief is for print), and shots of them:
three, on one note. The person's pick decides what is held.
Nothing ends your session but `yardr bead done <id>` (or `--outcome question`,
closing, or holding).
Nothing here lands, so the depot's test command that `yardr prime` prints is not
part of your exit.
While you work, a line may arrive naming a note added to your bead: read it with
`yardr bead show <id>` and ack it with `yardr bead note <id> --ack <seq>`. A note
by {{yardmaster}} or {{operator}} changes the bead.
## The work
1. **Read the brief.** `yardr prime --bead <id>` prints the bead, its notes and
the stage file with its exit. Find the format, the size, the subject, the
audience, the job, the words, what the brief fixes and the reference work,
and look at each reference you can reach. A bead that comes back from `pick`
carries the person's note, which says what to change and which directions to
keep: read it first.
Decide what kind of size it is: for screen, the brief names exact pixels,
width by height; for print, it names the trim size. For print, work out the
PNG's pixels at 96 CSS pixels to the inch (Exact size, below) and state them
in the plan note. A brief that names no size is a question for the stage,
not a guess.
Done when you can say the brief in one line: the format, the size (with the
PNG's pixels for print), the subject, the audience and the job. The line
opens the plan note of step 2. Where the brief leaves out the audience or
the job, propose one and say so. The stage file says when to ask instead.
2. **Choose three directions that differ in idea.** List eight facts about the
subject that no competitor shares: where its name comes from, the place it
sits in, its figures, what it is made of and the colours that come with
that, its daily routines, and the printed objects of its trade (tickets,
labels, menus, forms). For each direction, write one idea line: the
composition the direction is built around, and which of the eight it builds
with, a different one in each. Give each direction a type pairing (the faces
and what each is for) and a palette of four to six named hex values.
The distinctness rule: no two directions share the same idea, and a palette
alone never carries the difference. Three directions that are one layout in
three tints fail it; three that differ in composition, each built around its
own fact, hold it. A brief that fixes the brand's colours or typefaces keeps
them in all three, and the ideas carry the difference.
Write the plan in a note (`yardr bead note <id>`): the one-line reading, the
eight facts, then each direction's idea, type pairing and palette.
Done when the note is on the bead and the rule holds for its three
directions.
3. **Build the three.** One file per direction, `directions/<n>-<name>.svg` or
`directions/<n>-<name>.html`, with `<n>` from 1 to 3 and `<name>` a slug for
the direction. SVG or HTML, whichever the direction wants: type, layout,
shapes and charts are all composed work. Each file is composed at the
brief's exact size: an SVG carries the size in its width and height (pixels
for screen, real units for print); an HTML file fixes its body to the size,
and for print carries `@page` at the trim size with margin 0. A file opens
on its own: styles inline, CDN links for typefaces with the version pinned
in the URL, no build step, and no key, token or account. Write the words
before the markup, in the subject's own vocabulary.
Commit each file when it renders, as `<bead id>: direction <n>, <idea>`,
with no trailers of your own: the yard adds them. Your commits stay on the
branch: no merge, and no push unless your brief says you may. A bead that
came back keeps the directions the person kept, and new ones take the slots
of the others (`git rm` the old file).
Choose the three file names before you build the first. As soon as the first
file is there, start a watch on the folder with
`yardr preview watch $YARDR_BEAD directions` (`$YARDR_BEAD` is your bead's
id). The yard serves the files of `directions/` as they stand, and a file
reloads in the person's browser when it changes, so the person sees the
directions take shape. The command prints the address the files open at, on
its `opens at` line. The folder itself answers 404, so a file's address is
the printed address followed by its file name, as in
`/preview/<app>/1-<name>.svg` for `opens at /preview/<app>/`.
Put the three addresses on a note at once (`yardr bead note <id>`), so that
the person can open them while you build; a file opens once it exists.
If the command prints no `opens at` line, put what it printed on the note in
place of the addresses and go on. The watch ends by itself when the bead
leaves `directions`, and `yardr docs watch` says what it serves and what else
ends it. The watch is for the person to look at; the shots still come from
your own commands (Exact size, below).
Done when three files are committed and the note with their addresses is on
the bead.
4. **Look, then fix.** Shoot each file at the exact size (Exact size, below) and
open the PNG. Trust the picture over the code: the shot is what a viewer
sees. Ask three questions of it. Given five seconds, would a stranger know
what it offers and where to act, or feel what it is for? Could the nearest
competitor use it as it stands? Which tells does it carry that its idea did
not choose? List the three largest problems, fix them, commit and shoot
again, and stop after three rounds per file. The type in the shot is the
type you named. A fallback face, or text that is missing, means the shot
was taken before the font arrived: shoot again, and fix the font link if it
happens twice.
Done when you have opened every file's latest shot and each reads at a
glance.
5. **Shoot and report.** After your last commit, write the finished PNG of each
direction at the exact size into `directions/` (`directions/<n>-<name>.png`),
and for a print brief its PDF (`directions/<n>-<name>.pdf`), and commit
them. Confirm each PNG and each PDF mechanically (Exact size, below) and
open each PNG: it shows the type you named, and one that does not is shot
again. Attach the three PNGs to one note in the form given in the exact-size
mechanics. Run `yardr bead done <id>` when the exit in your stage file holds.
Done when one note carries the three confirmed shots, each opened, and names
the commit they were shot at.
## House style
A still has one glance to land. These hold in every direction:
- one thing first: the largest element says what the visual is for, and
everything else is smaller than it. Given five seconds a stranger knows the
offer and where to act, or feels what the piece is for;
- no more than two typefaces, set big enough to read at the size the visual is
seen at: a headline that fits its line, body copy in full-strength ink, never
pale grey on white;
- margins equal on all sides, and nothing the piece cannot lose within a
twentieth of an edge: crops and thumbs eat edges first;
- colour taken from the subject's own materials, spent where the eye should go;
ornament without substance reads as unfinished, so spend the space on size (a
larger headline, a larger figure), on complete content, on artwork drawn for
this subject, or on a flat field of colour;
- the file is the brief's size exactly: art meant to bleed runs to the file's
edge. A printer's bleed past trim is beyond this pack; the PDF is the trim
size.
Tells that fail a direction unless its idea chose them and the note says so: a
single word accented in a headline; labels in all caps; rows of look-alike
cards with an icon above each; gradient blobs and ornamental shapes; grey
placeholder bars where a figure or a picture belongs.
Leave proof out unless the brief gives it: testimonials, client names and
logos, review scores, press mentions and figures. The subject's own content
does that work: its menu, its rooms, its work, its prices. The note says which
details you made up. No lorem ipsum, no Acme Corp, no round vanity totals: a
figure shown carries its unit, and figures shown add up.
## Exact size
Shoot after your last commit, so that the shots and the SHA name the same
state. Each command starts a new shell: keep what a later command needs in
files, and set a variable on the line that uses it.
Chrome is `SHOT_CHROME` where that names an executable, else the first of
`google-chrome`, `google-chrome-stable`, `chromium` and `chromium-browser` on
PATH, else the macOS application
(`/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`).
1. Make a directory outside the worktree for the look-round PNGs (`mktemp -d`),
so that no shot lands in a commit before its file is finished. The finished
PNGs and PDFs of step 5 go into `directions/` instead and are committed.
2. Shoot each file from the worktree's root over `file://`, at the brief's
exact pixels with `--window-size` and `--screenshot`:
`"$CHROME" --headless --disable-gpu --hide-scrollbars
--force-device-scale-factor=1 --window-size=<W>,<H>
--screenshot="$d/<n>-<name>.png"
"file://$(pwd)/directions/<n>-<name>.svg"`.
An `.html` direction is shot the same way, by its own file name. Chrome
prints display errors on a Mac, and the bytes written decide: a run that
writes nothing failed, so run it again. Chrome gets a minute: a slower shot
fails with the reason, so run it again.
For a print brief the pixels are the trim size at 96 CSS pixels to the
inch: A4 (210x297mm) is 794x1123, A5 (148x210mm) is 559x794, US Letter
(8.5x11in) is 816x1056. Any other trim size is its inches times 96, stated
in the plan note.
3. Confirm each PNG mechanically: `file "$d/<n>-<name>.png"` names
`PNG image data, <W> x <H>`, and the file is not empty (`test -s`). That
catches a missing file or a wrong size. A blank shot or one in a fallback
face passes it, so open each PNG as well.
4. For a print brief, print each direction's PDF from HTML: an `.html`
direction carries `@page` at the trim size with margin 0 and is printed
itself. An `.svg` direction is printed through a self-contained wrapper
page in the temp directory. The SVG's width and height are the trim size in
real units; use those same units for `<trim width>` and `<trim height>` in
the wrapper. Set `d` to the temp directory, then make the wrapper:
```sh
d=<temp directory>; SVG=directions/<n>-<name>.svg W=<trim width> H=<trim height> OUT="$d/<n>-<name>-print.html" python3 - <<'PY'
import base64, os
svg = base64.b64encode(open(os.environ["SVG"], "rb").read()).decode("ascii")
w, h = os.environ["W"], os.environ["H"]
html = '''<!doctype html><meta charset="utf-8"><style>
@page { size: __WIDTH__ __HEIGHT__; margin: 0 }
html, body { width: __WIDTH__; height: __HEIGHT__; margin: 0; overflow: hidden }
img { display: block; width: 100%; height: 100% }
</style><img src="data:image/svg+xml;base64,__SVG__">'''
html = html.replace("__WIDTH__", w).replace("__HEIGHT__", h)
html = html.replace("__SVG__", svg)
open(os.environ["OUT"], "w", encoding="utf-8").write(html)
PY
```
The wrapper embeds the SVG, so Chrome does not have to load a second local
file. Print that wrapper, not the SVG or a different direction file:
`d=<temp directory>; "$CHROME" --headless --disable-gpu
--print-to-pdf="$d/<n>-<name>.pdf" --print-to-pdf-no-header
"file://$d/<n>-<name>-print.html"`.
Confirm each PDF mechanically: `file` names `PDF document` with 1 page, and
`grep -a -o 'MediaBox \[[^]]*\]'` names the trim size in points: A4 is about
595x842, A5 about 420x595, US Letter 612x792.
5. Under 500 wide, shoot through a frame: Chrome on macOS lays every narrower
window out 500 wide and the PNG is its left slice. Write a wrapper page in
the temp directory with one iframe at the exact size
(`<iframe src="<file>" width="<W>" height="<H>">`, no border, no margin)
and shoot the wrapper at `--window-size=<W>,<H>`. The PNG's left edge is
then the frame's, at the exact width.
6. Attach the finished PNGs to one note, words first, each file with its own
`--file`:
`yardr bead note <id> "<words>" --file directions/1-<name>.png --file directions/2-<name>.png --file directions/3-<name>.png`.
The words say what was opened (the three files under `directions/` on
`yard/<bead>`), at what size (the exact pixels; for a print brief the pixels
and the trim size, with its PDF), and the commit's short SHA
(`git rev-parse --short HEAD`).
Then the one-line reading of the brief, then a line for each file,
`<n>. <name>: <idea>; <type pairing>; <palette>`, with its idea line and
its address on the watch (step 3), then the details you made up. The note's
file is the record, not the local path.
7. Remove the temp directory as a command of its own, with the variable set on
the line that deletes: `d=<dir>; rm -rf "${d:?}"`.
## Something outside your bead
1. It does not block you (a bug elsewhere, a stale doc): file it and carry on,
never fix it on your branch. `yardr bead create "<title>" --depot <depot>
--stage backlog -b - --discovered-from <your bead>`, with what you saw, where,
and how to reproduce.
2. It blocks you and is no question about the bead (no headless Chrome, no
yardr checkout to read): file it as above, then mail {{yardmaster}}:
`yardr mail {{yardmaster}} "<bead id>: <one line>"`. If you cannot finish
without it, `yardr bead note <id> "blocked by <bead id>" && yardr bead hold
<id>`.
3. It is a question about the bead itself, an unclear brief or a choice that is
the person's: that is the `question` outcome of the stage.
Shots weigh on your context. When each turn slows, write a note of where you are
(done, next, open) and hold the bead with `yardr bead hold <id>`; the next
session starts from the note.
# Setting up the visuals pack The pack adds the bead type `visual` to a git depot. A brief goes in: what the visual is and how big. A designer agent composes three directions at that exact size, shoots them, and puts the shots on a note, and a person picks one and holds the finished file. Nothing lands. This file is the operator's steps. The commands call the depot `studio` and the pack's directory (the `visuals` directory of the yardr-packs checkout) `<pack dir>`. Change both to yours. The designer's shots need two things on the yard's machine: headless Chrome (Google Chrome in `/Applications`, `google-chrome` or `chromium` on the PATH, or a path in `SHOT_CHROME`), run directly at the brief's exact size, and `python3`. The directions load their typefaces from CDNs, so the machine needs the network while a designer works. A designer starts a watch on the directions while it builds (`yardr preview watch`, in yardr from 4 November 2026), so that a person can open the files in a browser as they take shape. The designer's notes give the address of each file: the address the command prints, followed by the file's name. The command prints the host the yard's edge gave the watch where the yard is linked to an edge that gives one, and the path `/preview/<app>/` on the yard otherwise. 1. **The machine.** Each command below is one thing to type, in a block of its own. The first finds Chrome. The second prints the first line of the page on the watch, and on a yardr that has no watch says `no doc named "watch"`. Its designers get no `opens at` line from the command, and put what it printed on their notes in place of the addresses: ```sh command -v google-chrome google-chrome-stable chromium chromium-browser; ls "/Applications/Google Chrome.app" >/dev/null && echo macOS Chrome ``` ```sh yardr docs watch | head -1 ``` 2. **What the import would do.** Nothing is written: ```sh yardr pack check <pack dir> --depot studio ``` It lists the flow `visuals.visual`, the pointer that makes it the flow of type `visual`, the routes of its stages, the group `studio-visual-designers` and the questions the next step asks. A depot that follows the webdesign pack's mockup flow keeps it: that flow is for the type `mockup`, and this one is for `visual`. Read the `crew` lines too: the `yardmaster` itself is unchanged, and the plan creates its two subscriptions, a bead entering `pick` and a bead closing. 3. **Import it.** The import asks which agent runs `studio-visual-designers`: its kind, its model and its permission arguments. A designer runs shell commands (git, Chrome, yardr) and opens PNGs to look at its own work, so pick a kind and model that read images, and the permission arguments your builders have. With none, it stops at every permission prompt. ```sh yardr pack apply <pack dir> --depot studio ``` To answer on the command line instead of at the prompts (the kind and model are an example): ```sh yardr pack apply <pack dir> --depot studio --yes --bind visual-designers=claude:opus ``` The groups `backlog` and `decisions` are the yard's two people groups, and the import reuses a yard's own. They hold the people who ready a brief and who pick. A yard without them is asked for their members, and `--members backlog= --members decisions=mckean` answers (empty means anyone). A yard whose crew member is not called `yardmaster` says which one takes it, with `--crew yardmaster=<name>`. An agent group the yard already has can take the designers' place, with `--group visual-designers=<group>`: its own prompt stays, and the pack's role is installed and read by nobody. 4. **Make a bead.** The brief is the bead's body: the format, the size (exact pixels for screen, the trim size for print), the subject, the audience, the job, the words, what the brief fixes, reference work and what is not wanted. The stage file of `backlog` lists them and is shown to whoever opens the bead. The type `visual` follows this pack's flow, which starts in `backlog`: ```sh yardr bead create "Three directions for the fete poster" --depot studio --type visual -b "<the brief>" ``` `-b -` reads the body from standard input instead. When the brief is ready, send the bead to the designers: ```sh yardr bead advance <id> --to directions ``` 5. **Watch it built.** Once the designer has written its first file it starts the watch and puts the three addresses on a note, which appears on the bead as any note does: ```sh yardr prime --bead <id> ``` Open the addresses in a browser; one that starts with a slash is a path on the yard's web view, so put the view's address in front of it. A file reloads when it changes, and a file the designer has not built yet answers 404 until it has. The Previews page of the web view lists the watch as well, but its Open button opens the folder, which answers 404: the files are at the addresses in the note. The watch ends when the bead leaves `directions`, and the shots on the last note are the record. 6. **The pick.** When the designer is done the bead waits in `pick`, and the yard puts a card on it that offers the moves. The person reads the shots on the designer's note (`yardr prime --bead <id>` prints it, and the web view shows the images), then picks. The same move by hand, with the pick in words: ```sh yardr bead advance <id> --to picked --note "2, with the type of 3" ``` The other two moves are `--to directions`, for another round with a note that says what to change, and `--to backlog`, to park the bead or reshape its brief. 7. **After the pick.** The bead is closed at `picked`. The directions stay on the branch `yard/<id>`, under `directions/`, and the shots on the note. Nothing lands on the base. What you hold is the picked file with its PNG at the exact size (and its PDF where the brief is for print), on the branch. One designer works at a time, because each runs headless Chrome. To allow more, raise the limit of the group the import made: ```sh yardr group set studio-visual-designers --limit 2 ```
#!/bin/sh
# The visuals pack's tests: what the gate runs beside yardr pack check.
# Needs no network, no secret and no yardr, and is done in well under a second.
# The pack is text, so there is nothing to run. What the test pins is what a
# later edit could lose without a sound:
#
# role roles/visual-designer.md carries the distinctness rule, the
# exact-size mechanics (Chrome run directly, the PNG shot and its
# check, the print PDF wrapper and its check, the frame under 500
# wide)
# and the watch (the command with the bead's id, how a file's
# address is made, and the two notes that carry the addresses)
# stages each stage file has its exit line, directions.md names the
# finished PNG and PDF, the role's distinctness rule and the
# address of each file on the watch, and pick.md has the card of
# its moves
# shape the decisions of pack.yaml: the pack's own type and group, no
# assembly, the yardmaster hearing pick and carrying no role
# closed no role or stage file points at a file the import does not install
set -u
cd "$(dirname "$0")" || exit 1
fail=0
# ok <name> <condition's exit status> [detail]
ok() {
if [ "$2" = 0 ]; then echo "test: $1 ok"; else echo "test: $1 FAILED${3:+: $3}"; fail=1; fi
}
# has <file> <fixed text>: the text is in the file.
has() { grep -qF -- "$2" "$1"; }
role=roles/visual-designer.md
# ---- the role ---------------------------------------------------------------
# What the stage files name, so it stays in the role: the distinctness rule and
# the exact-size mechanics. And what the mechanics teach, so that an edit cannot
# drop a step without a sound: Chrome run directly with its window and shot
# flags, what `file` names for the PNG, the print PDF with its page rule and
# its MediaBox check, and the frame under 500 wide. And the watch the designer
# starts for the person: the command with the bead's id, how a file's address
# is made from what the command prints, what to do when it prints none (a yardr
# without the watch ends 0 on it), the note that carries the addresses while
# the designer builds, and the line of the shots note that carries them after.
for t in 'The distinctness rule' '--window-size=<W>,<H>' '--screenshot=' \
'PNG image data, <W> x <H>' '--print-to-pdf=' '@page' 'MediaBox' \
'data:image/svg+xml;base64,' 'file://$d/<n>-<name>-print.html' \
'Print that wrapper, not the SVG or a different direction file' \
'Under 500 wide' 'directions/<n>-<name>.svg' '--file' \
'yardr preview watch $YARDR_BEAD directions' 'followed by its file name' \
'If the command prints no `opens at` line' \
'Put the three addresses on a note at once' 'its address on the watch (step 3)'; do
has "$role" "$t"
ok "role: carries '$t'" $?
done
# ---- the stage files --------------------------------------------------------
# The exit line is the lead-in of each stage's list of what must hold.
for row in 'backlog|Before it is sent to `directions`' \
'directions|Before the bead leaves as `done`:' \
'pick|A bead leaves `pick` when'; do
f=flows/visual/${row%%|*}.md
line=${row#*|}
has "$f" "$line"
ok "$f: its exit line '$line'" $?
head -1 "$f" | grep -q '^summary: .'
ok "$f: opens with a summary line" $?
done
grep -q '^## Ask$' flows/visual/pick.md && grep -q '^kind: moves$' flows/visual/pick.md
ok "flows/visual/pick.md: ends in the card of its moves (kind: moves)" $?
has flows/visual/directions.md 'your role'"'"'s distinctness rule'
ok "flows/visual/directions.md: names the role's distinctness rule" $?
has flows/visual/directions.md 'directions/<n>-<name>.png'
ok "flows/visual/directions.md: its exit names the finished PNG at the exact size" $?
has flows/visual/directions.md 'directions/<n>-<name>.pdf'
ok "flows/visual/directions.md: its exit names the PDF of a print brief" $?
has flows/visual/directions.md 'address on the watch'
ok "flows/visual/directions.md: its exit names the address of each file on the watch" $?
has flows/visual/backlog.md 'the size:'
ok "flows/visual/backlog.md: the brief names the size" $?
# ---- pack.yaml --------------------------------------------------------------
yaml=$(grep -v '^ *#' pack.yaml)
y() { printf '%s\n' "$yaml" | grep -q "$@"; }
y '^ type: visual$'
ok "pack.yaml: the flow is for the pack's own type visual" $?
y 'directions: { group: visual-designers, file: flows/visual/directions.md, outcomes: { done: pick, question: pick }, manual: \[backlog\] }'
ok "pack.yaml: directions is worked by visual-designers, and done and question both go to pick" $?
y 'pick: { group: decisions, file: flows/visual/pick.md, manual: \[picked, directions, backlog\] }'
ok "pack.yaml: pick moves by hand to picked, directions or backlog" $?
y 'picked: { end: true }'
ok "pack.yaml: the flow ends at picked" $?
y 'visual-designers: { agent: roles/visual-designer.md, limit: 1 }'
ok "pack.yaml: the visual designers are a group of their own, one at a time" $?
! y 'builders'
ok "pack.yaml: no group of the depot's builders" $?
! y ' designers[^_]'
ok "pack.yaml: no group of webdesign's designers" $?
! y 'run:'
ok "pack.yaml: no script group, so nothing lands" $?
y 'stages: \[pick\]'
ok "pack.yaml: the yardmaster hears a bead enter pick" $?
! y '^ role:'
ok "pack.yaml: the yardmaster carries no role" $?
# ---- closed -----------------------------------------------------------------
# An import installs the role, the stage files and the setup notes: a role or a
# stage file that sends its reader to another file of the pack sends it nowhere.
! grep -n 'THIRD_PARTY_NOTICES\|README\|SETUP\.md' "$role" flows/visual/*.md
ok "role and stage files: point at no file of the pack that the import leaves behind" $?
if [ "$fail" = 0 ]; then echo "test: visuals: all ok"; else echo "test: visuals: FAILED"; fi
exit $fail