wai-vector: a title card and credit roll in the vector corpus #249

Merged
dcharlot merged 4 commits from wai/d7-titles-slice into main 2026-10-14 11:08:13 -04:00
8 changed files with 649 additions and 6 deletions

View file

@ -6,6 +6,15 @@ wire format may change and such changes are recorded here.
## v0.4.0 — current
### Vector graphics (Draft): a title card and credit roll in the corpus
`wai/vector-conformance/` gains `motion/stroke-titles`: a 1280 × 720 document at 25 fps
in the default stroke set, a lower third that slides in, holds and fades as a group, and
a credit roll that rises three design pixels a frame. Each line's window is cut to the
frames at which it meets the canvas (graphics-vector §5.4, *Where a block is*). Every
frame's digest is in its expected file, so the native, WASI, Node and three-engine
browser legs and the independent checker each check all of them.
### `wai.neural.int_synth` through the integer operator set
The first capability whose reference decoder decodes through `wai-ops/1`.

View file

@ -11,7 +11,7 @@ repertoire; and the text layer (§5): the transcript and every frame's projectio
each payload's text record. The capability is a Draft and is not registered; this
corpus precedes its registration.
**Provenance.** Generated here by `wai-vector vectors gen` from formulas and from centre lines drawn in this repository: every payload, outline set, stroke source and arithmetic input is integers and text written here, with no media and no third-party font. The synthetic outline sets are drawn from formulas in `wai-vector/src/vectors/sets.rs` and `raster.rs`. The two in-house sets are drawn here as integer centre lines, the ASCII stroke set in `wai-vector/src/vectors/stroke.rs` and the Arabic, Hebrew and Devanagari test repertoire in `wai-vector/src/vectors/repertoire.rs`; the generator writes them as `WSF1` sources under `sources/` and expands each by Annex A into `sets/stroke-ascii.wos1` and `sets/test-repertoire.wos1`. No outline is traced from any font. Every set's notes state where it comes from and that it is licensed Apache-2.0, and the two in-house sets' notes carry the licence text. All text in the blocks is written here; the `a11y` payloads' blocks, windows and strings are written in `wai-vector/src/vectors/a11y.rs`, and each text record is computed from its payload by `wai-vector/src/text.rs`.
**Provenance.** Generated here by `wai-vector vectors gen` from formulas and from centre lines drawn in this repository: every payload, outline set, stroke source and arithmetic input is integers and text written here, with no media and no third-party font. The synthetic outline sets are drawn from formulas in `wai-vector/src/vectors/sets.rs` and `raster.rs`. The two in-house sets are drawn here as integer centre lines, the ASCII stroke set in `wai-vector/src/vectors/stroke.rs` and the Arabic, Hebrew and Devanagari test repertoire in `wai-vector/src/vectors/repertoire.rs`; the generator writes them as `WSF1` sources under `sources/` and expands each by Annex A into `sets/stroke-ascii.wos1` and `sets/test-repertoire.wos1`. No outline is traced from any font. Every set's notes state where it comes from and that it is licensed Apache-2.0, and the two in-house sets' notes carry the licence text. All text in the blocks is written here; the `a11y` payloads' blocks, windows and strings are written in `wai-vector/src/vectors/a11y.rs`, the words of the title card and credit roll in `wai-vector/src/vectors/text.rs`, and each text record is computed from its payload by `wai-vector/src/text.rs`.
**Equivalence.** A sink conforms on this corpus when, for every payload, it reports the
expected file's `code`: the first refusal §2.7 gives, or `accepted`; and for every
@ -108,7 +108,11 @@ outline-set parser conforms when it reports §2.1's first code for every `.wos1`
pop, and pixels on which the two candidate fill orders differ (§3.9).
- `motion` — a credit roll at an integer speed (frame `k` is frame 0 moved, P2) and at
a fractional one, a lower third that slides, holds and fades as a group, and each
easing mode; and a lower third and a short credit roll set in the stroke set.
easing mode; a lower third and a short credit roll set in the stroke set; and a title
card and a credit roll in the stroke set at 1280 × 720 and 25 fps, seven seconds: a
lower third that slides in, holds and fades out as a group, then a heading and five
credits, each a role and what filled it, that rise three design pixels a frame and
fade out, each line's window cut to the frames at which it meets the canvas.
- `clock` — one document at 1280 × 720, 1920 × 1080 and 3840 × 2160, and at 25,
30000/1001 and 60 fps.
- `slicing` — a document and three pieces cut from it; each piece's frames equal the

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -3,5 +3,6 @@
"lower-third":"a lower third that slides in on an easing table, holds and fades out, as one group: accepted",
"roll-fractional":"the same roll at 1.5 design pixels per frame: no whole-pixel shift between frames: accepted",
"roll-integer":"a credit roll at 2 design pixels per frame, keys on frame ticks: frame k is frame 0 moved 2k pixels at the design size, 4k at twice it (P2): accepted",
"stroke-slice":"a lower third in the stroke set (a bar and two lines that slide in on an easing table, hold and fade out as one group) and a short credit roll moving up three design pixels a frame: accepted"
"stroke-slice":"a lower third in the stroke set (a bar and two lines that slide in on an easing table, hold and fade out as one group) and a short credit roll moving up three design pixels a frame: accepted",
"stroke-titles":"a title card and a credit roll in the stroke set at 1280x720 and 25 fps, seven seconds: a lower third (a bar and two lines that slide in on an easing table, hold and fade out as one group), then a roll of a heading and five credits, each a role and what filled it, moving up three design pixels a frame and fading out; each line's window cut to the frames at which it meets the canvas: accepted"
}

View file

@ -0,0 +1,452 @@
{
"header":{"magic":"WVG1","format":1,"tb":120000,"t0":0,"dur":840000,"design_w":1280,"design_h":720,"n_sizes":1,"n_rates":1,"n_sets":1,"n_tables":1,"n_paints":4,"n_texts":13,"n_tracks":4,"n_paths":1,"n_items":18,"n_keys":10,"n_glyphs":181,"n_clusters":181,"path_contours":1,"path_points":4,"strings_len":207,"inline_len":0,"held_len":105523,"zero@72":[0,0,0,0,0,0,0,0]},
"sizes":[
{"w":1280,"h":720,"cost":32796279}
],
"rates":[
{"num":25,"den":1}
],
"sets":[
{"carriage":0,"zero@1":[0,0,0],"length":105523,"sha256":"05476c4658ef7366c7700736487eac4c3c1b7d21264978c7d05bd4c7427736c9"}
],
"tables":[
[0,9000,17000,24000,30500,36000,41000,45500,49500,53000,56000,58500,60700,62500,64000,65000,65536]
],
"paints":[
[16,36,96,224],
[255,255,255,255],
[200,210,225,255],
[160,170,185,255]
],
"tracks":[
{"kind":2,"zero@1":0,"zero@2":0,"n_keys":2},
{"kind":1,"zero@1":0,"zero@2":0,"n_keys":3},
{"kind":2,"zero@1":0,"zero@2":0,"n_keys":2},
{"kind":1,"zero@1":0,"zero@2":0,"n_keys":3}
],
"keys":[
[0,-182272,2,[0,0,0]],
[57600,0,0,[0,0,0]],
[0,255,0,[0,0,0]],
[278400,255,1,[0,0,0]],
[336000,0,0,[0,0,0]],
[297600,0,1,[0,0,0]],
[840000,-86784,0,[0,0,0]],
[0,255,0,[0,0,0]],
[768000,255,1,[0,0,0]],
[840000,0,0,[0,0,0]]
],
"paths":[
{"n_contours":1,"n_points":4,"zero@4":0,"xmin":80,"ymin":552,"xmax":672,"ymax":668}
],
"path_ends":[3],
"path_points":[
[80,552,0],
[672,552,0],
[672,668,0],
[80,668,0]
],
"texts":[
{"purpose":3,"dir":0,"lang_len":2,"mode":0,"group":1,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":31},
{"purpose":3,"dir":0,"lang_len":2,"mode":0,"group":1,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":35},
{"purpose":1,"dir":0,"lang_len":2,"mode":0,"group":0,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":7},
{"purpose":2,"dir":0,"lang_len":2,"mode":0,"group":2,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":9},
{"purpose":2,"dir":0,"lang_len":2,"mode":0,"group":2,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":14},
{"purpose":2,"dir":0,"lang_len":2,"mode":0,"group":3,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":6},
{"purpose":2,"dir":0,"lang_len":2,"mode":0,"group":3,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":14},
{"purpose":2,"dir":0,"lang_len":2,"mode":0,"group":4,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":7},
{"purpose":2,"dir":0,"lang_len":2,"mode":0,"group":4,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":18},
{"purpose":2,"dir":0,"lang_len":2,"mode":0,"group":5,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":5},
{"purpose":2,"dir":0,"lang_len":2,"mode":0,"group":5,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":14},
{"purpose":2,"dir":0,"lang_len":2,"mode":0,"group":6,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":8},
{"purpose":2,"dir":0,"lang_len":2,"mode":0,"group":6,"ruby":0,"ruby_start":0,"ruby_len":0,"str_len":13}
],
"items":[
{"kind":0,"rule":0,"zero@2":0,"ref":65535,"paint":65535,"text":65535,"zero@10":0,"n_glyphs":0,"n_clusters":0,"t_on":0,"t_off":336000,"unit_scale":0,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":0,"ty":65535,"op":1,"zero@42":[0,0,0,0,0,0]},
{"kind":2,"rule":0,"zero@2":0,"ref":0,"paint":0,"text":65535,"zero@10":0,"n_glyphs":0,"n_clusters":0,"t_on":0,"t_off":336000,"unit_scale":16777216,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":1,"text":0,"zero@10":0,"n_glyphs":31,"n_clusters":31,"t_on":4800,"t_off":336000,"unit_scale":327680,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":2,"text":1,"zero@10":0,"n_glyphs":35,"n_clusters":35,"t_on":4800,"t_off":336000,"unit_scale":262144,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":1,"rule":0,"zero@2":0,"ref":0,"paint":0,"text":0,"zero@10":0,"n_glyphs":0,"n_clusters":0,"t_on":0,"t_off":0,"unit_scale":0,"m00":0,"m01":0,"m10":0,"m11":0,"tx":0,"ty":0,"op":0,"zero@42":[0,0,0,0,0,0]},
{"kind":0,"rule":0,"zero@2":0,"ref":65535,"paint":65535,"text":65535,"zero@10":0,"n_glyphs":0,"n_clusters":0,"t_on":297600,"t_off":840000,"unit_scale":0,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":2,"op":3,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":1,"text":2,"zero@10":0,"n_glyphs":7,"n_clusters":7,"t_on":316800,"t_off":840000,"unit_scale":327680,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":3,"text":3,"zero@10":0,"n_glyphs":9,"n_clusters":9,"t_on":403200,"t_off":840000,"unit_scale":262144,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":1,"text":4,"zero@10":0,"n_glyphs":14,"n_clusters":14,"t_on":403200,"t_off":840000,"unit_scale":262144,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":3,"text":5,"zero@10":0,"n_glyphs":6,"n_clusters":6,"t_on":460800,"t_off":840000,"unit_scale":262144,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":1,"text":6,"zero@10":0,"n_glyphs":14,"n_clusters":14,"t_on":460800,"t_off":840000,"unit_scale":262144,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":3,"text":7,"zero@10":0,"n_glyphs":7,"n_clusters":7,"t_on":523200,"t_off":840000,"unit_scale":262144,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":1,"text":8,"zero@10":0,"n_glyphs":18,"n_clusters":18,"t_on":523200,"t_off":840000,"unit_scale":262144,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":3,"text":9,"zero@10":0,"n_glyphs":5,"n_clusters":5,"t_on":580800,"t_off":840000,"unit_scale":262144,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":1,"text":10,"zero@10":0,"n_glyphs":14,"n_clusters":14,"t_on":580800,"t_off":840000,"unit_scale":262144,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":3,"text":11,"zero@10":0,"n_glyphs":8,"n_clusters":8,"t_on":643200,"t_off":840000,"unit_scale":262144,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":3,"rule":0,"zero@2":0,"ref":0,"paint":1,"text":12,"zero@10":0,"n_glyphs":13,"n_clusters":13,"t_on":643200,"t_off":840000,"unit_scale":262144,"m00":65535,"m01":65535,"m10":65535,"m11":65535,"tx":65535,"ty":65535,"op":65535,"zero@42":[0,0,0,0,0,0]},
{"kind":1,"rule":0,"zero@2":0,"ref":0,"paint":0,"text":0,"zero@10":0,"n_glyphs":0,"n_clusters":0,"t_on":0,"t_off":0,"unit_scale":0,"m00":0,"m01":0,"m10":0,"m11":0,"tx":0,"ty":0,"op":0,"zero@42":[0,0,0,0,0,0]}
],
"glyphs":[
[84,0,28672,153600],
[105,0,34422,153600],
[116,0,36822,153600],
[108,0,40422,153600],
[101,0,42822,153600],
[115,0,48222,153600],
[44,0,52922,153600],
[32,0,55122,153600],
[99,0,58122,153600],
[97,0,63122,153600],
[114,0,68522,153600],
[114,0,72322,153600],
[105,0,76122,153600],
[101,0,78522,153600],
[100,0,83922,153600],
[32,0,89522,153600],
[97,0,92522,153600],
[115,0,97922,153600],
[32,0,102622,153600],
[105,0,105622,153600],
[110,0,108022,153600],
[115,0,113622,153600],
[116,0,118322,153600],
[114,0,121922,153600],
[117,0,125722,153600],
[99,0,131322,153600],
[116,0,136322,153600],
[105,0,139922,153600],
[111,0,142322,153600],
[110,0,147922,153600],
[115,0,153522,153600],
[100,0,28672,163840],
[114,0,33152,163840],
[97,0,36192,163840],
[119,0,40512,163840],
[110,0,46512,163840],
[32,0,50992,163840],
[111,0,53392,163840],
[110,0,57872,163840],
[32,0,62352,163840],
[116,0,64752,163840],
[104,0,67632,163840],
[101,0,72112,163840],
[32,0,76432,163840],
[100,0,78832,163840],
[101,0,83312,163840],
[118,0,87632,163840],
[105,0,91792,163840],
[99,0,93712,163840],
[101,0,97712,163840],
[32,0,102032,163840],
[116,0,104432,163840],
[104,0,107312,163840],
[97,0,111792,163840],
[116,0,116112,163840],
[32,0,118992,163840],
[115,0,121392,163840],
[104,0,125152,163840],
[111,0,129632,163840],
[119,0,134112,163840],
[115,0,140112,163840],
[32,0,143872,163840],
[116,0,146272,163840],
[104,0,149152,163840],
[101,0,153632,163840],
[109,0,157952,163840],
[67,0,147840,194560],
[114,0,154340,194560],
[101,0,158140,194560],
[100,0,163540,194560],
[105,0,169140,194560],
[116,0,171540,194560],
[115,0,175140,194560],
[76,0,126280,206336],
[101,0,130480,206336],
[116,0,134800,206336],
[116,0,137680,206336],
[101,0,140560,206336],
[114,0,144880,206336],
[105,0,147920,206336],
[110,0,149840,206336],
[103,0,154320,206336],
[116,0,168960,206336],
[104,0,171840,206336],
[101,0,176320,206336],
[32,0,180640,206336],
[115,0,183040,206336],
[116,0,186800,206336],
[114,0,189680,206336],
[111,0,192720,206336],
[107,0,197200,206336],
[101,0,201200,206336],
[32,0,205520,206336],
[115,0,207920,206336],
[101,0,211680,206336],
[116,0,216000,206336],
[84,0,135720,216064],
[105,0,140320,216064],
[109,0,142240,216064],
[105,0,147920,216064],
[110,0,149840,216064],
[103,0,154320,216064],
[116,0,168960,216064],
[104,0,171840,216064],
[101,0,176320,216064],
[32,0,180640,216064],
[116,0,183040,216064],
[105,0,185920,216064],
[99,0,187840,216064],
[107,0,191840,216064],
[32,0,195840,216064],
[99,0,198240,216064],
[108,0,202240,216064],
[111,0,204160,216064],
[99,0,208640,216064],
[107,0,212640,216064],
[68,0,129360,225792],
[114,0,134560,225792],
[97,0,137600,225792],
[119,0,141920,225792],
[105,0,147920,225792],
[110,0,149840,225792],
[103,0,154320,225792],
[105,0,168960,225792],
[110,0,170880,225792],
[116,0,175360,225792],
[101,0,178240,225792],
[103,0,182560,225792],
[101,0,186960,225792],
[114,0,191280,225792],
[32,0,194320,225792],
[97,0,196720,225792],
[114,0,201040,225792],
[105,0,204080,225792],
[116,0,206000,225792],
[104,0,208880,225792],
[109,0,213360,225792],
[101,0,219040,225792],
[116,0,223360,225792],
[105,0,226240,225792],
[99,0,228160,225792],
[87,0,136160,235520],
[111,0,142960,235520],
[114,0,147440,235520],
[100,0,150480,235520],
[115,0,154960,235520],
[116,0,168960,235520],
[104,0,171840,235520],
[101,0,176320,235520],
[32,0,180640,235520],
[116,0,183040,235520],
[101,0,185920,235520],
[120,0,190240,235520],
[116,0,194240,235520],
[32,0,197120,235520],
[108,0,199520,235520],
[97,0,201440,235520],
[121,0,205760,235520],
[101,0,209920,235520],
[114,0,214240,235520],
[67,0,125920,245248],
[104,0,131120,245248],
[101,0,135600,245248],
[99,0,139920,245248],
[107,0,143920,245248],
[105,0,147920,245248],
[110,0,149840,245248],
[103,0,154320,245248],
[102,0,168960,245248],
[114,0,171760,245248],
[97,0,174800,245248],
[109,0,179120,245248],
[101,0,184800,245248],
[32,0,189120,245248],
[100,0,191520,245248],
[105,0,196000,245248],
[103,0,197920,245248],
[101,0,202320,245248],
[115,0,206640,245248],
[116,0,210400,245248],
[115,0,213280,245248]
],
"clusters":[
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,5,1],
[1,0,6,1],
[1,0,7,1],
[1,0,8,1],
[1,0,9,1],
[1,0,10,1],
[1,0,11,1],
[1,0,12,1],
[1,0,13,1],
[1,0,14,1],
[1,0,15,1],
[1,0,16,1],
[1,0,17,1],
[1,0,18,1],
[1,0,19,1],
[1,0,20,1],
[1,0,21,1],
[1,0,22,1],
[1,0,23,1],
[1,0,24,1],
[1,0,25,1],
[1,0,26,1],
[1,0,27,1],
[1,0,28,1],
[1,0,29,1],
[1,0,30,1],
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,5,1],
[1,0,6,1],
[1,0,7,1],
[1,0,8,1],
[1,0,9,1],
[1,0,10,1],
[1,0,11,1],
[1,0,12,1],
[1,0,13,1],
[1,0,14,1],
[1,0,15,1],
[1,0,16,1],
[1,0,17,1],
[1,0,18,1],
[1,0,19,1],
[1,0,20,1],
[1,0,21,1],
[1,0,22,1],
[1,0,23,1],
[1,0,24,1],
[1,0,25,1],
[1,0,26,1],
[1,0,27,1],
[1,0,28,1],
[1,0,29,1],
[1,0,30,1],
[1,0,31,1],
[1,0,32,1],
[1,0,33,1],
[1,0,34,1],
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,5,1],
[1,0,6,1],
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,5,1],
[1,0,6,1],
[1,0,7,1],
[1,0,8,1],
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,5,1],
[1,0,6,1],
[1,0,7,1],
[1,0,8,1],
[1,0,9,1],
[1,0,10,1],
[1,0,11,1],
[1,0,12,1],
[1,0,13,1],
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,5,1],
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,5,1],
[1,0,6,1],
[1,0,7,1],
[1,0,8,1],
[1,0,9,1],
[1,0,10,1],
[1,0,11,1],
[1,0,12,1],
[1,0,13,1],
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,5,1],
[1,0,6,1],
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,5,1],
[1,0,6,1],
[1,0,7,1],
[1,0,8,1],
[1,0,9,1],
[1,0,10,1],
[1,0,11,1],
[1,0,12,1],
[1,0,13,1],
[1,0,14,1],
[1,0,15,1],
[1,0,16,1],
[1,0,17,1],
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,5,1],
[1,0,6,1],
[1,0,7,1],
[1,0,8,1],
[1,0,9,1],
[1,0,10,1],
[1,0,11,1],
[1,0,12,1],
[1,0,13,1],
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,5,1],
[1,0,6,1],
[1,0,7,1],
[1,0,0,1],
[1,0,1,1],
[1,0,2,1],
[1,0,3,1],
[1,0,4,1],
[1,0,5,1],
[1,0,6,1],
[1,0,7,1],
[1,0,8,1],
[1,0,9,1],
[1,0,10,1],
[1,0,11,1],
[1,0,12,1]
],
"strings":"enTitles, carried as instructionsendrawn on the device that shows themenCreditsenLetteringenthe stroke setenTimingenthe tick clockenDrawingeninteger arithmeticenWordsenthe text layerenCheckingenframe digests",
"inline":""
}

View file

@ -1,5 +1,7 @@
//! Vectors drawn from the in-house sets (`graphics-vector.md` §4): the `text` group,
//! and the stroke-glyph members of `runs` and `motion`.
//! and the stroke-glyph members of `runs` and `motion`, among them `motion/stroke-titles`,
//! a title card and a credit roll at 1280 × 720 and 25 fps, whose words are written here
//! ([`TITLES_LOWER_THIRD`], [`TITLES_ROLL_HEADING`] and [`TITLES_ROLL`]).
//!
//! `text` renders text runs from the ASCII stroke set and the test repertoire at two
//! listed sizes each: Latin; Arabic and Hebrew right to left; Devanagari with a
@ -21,9 +23,11 @@ use super::canonical::{TB, held};
use super::raster::{BLUE, ONE, RED, WHITE, frame_doc};
use super::repertoire::{self, FACE, lay_out, repertoire_source, shape_arabic, shape_devanagari, shape_hebrew};
use super::stroke::ascii_source;
use crate::arith::r_rat;
use crate::arith::{floor_div, r_rat};
use crate::scene::*;
use crate::wos1::{self, Wos1};
use crate::wsf1::Wsf1;
use crate::wvg1::{Key, Table};
/// Q16 design subpixels per outline unit: `n` subpixels per unit.
pub(super) const fn us(n: u32) -> u32 {
@ -305,9 +309,180 @@ pub fn vectors() -> Vec<Vector> {
}
add("motion", "stroke-slice", &s, "a lower third in the stroke set (a bar and two lines that slide in on an easing table, hold and fade out as one group) and a short credit roll moving up three design pixels a frame: accepted");
}
// ---- motion/stroke-titles: a title card and a credit roll at 1280 x 720, 25 fps.
add(
"motion",
"stroke-titles",
&stroke_titles(&latin_set, &stroke),
"a title card and a credit roll in the stroke set at 1280x720 and 25 fps, seven seconds: a lower third (a bar and two lines that slide in on an easing table, hold and fade out as one group), then a roll of a heading and five credits, each a role and what filled it, moving up three design pixels a frame and fading out; each line's window cut to the frames at which it meets the canvas: accepted",
);
v
}
/// The lower third of `motion/stroke-titles`: two lines, read as one group.
pub const TITLES_LOWER_THIRD: [&str; 2] = ["Titles, carried as instructions", "drawn on the device that shows them"];
/// The heading of its credit roll.
pub const TITLES_ROLL_HEADING: &str = "Credits";
/// Its credits: each a role, and the part of the system that filled it, read as one group.
pub const TITLES_ROLL: [(&str, &str); 5] = [
("Lettering", "the stroke set"),
("Timing", "the tick clock"),
("Drawing", "integer arithmetic"),
("Words", "the text layer"),
("Checking", "frame digests"),
];
/// A track's value at tick `tau`, by the sink's own evaluation (§3.2).
fn track_at(t: &TrackDef, tau: i64) -> i64 {
let mut tables: Vec<Table> = Vec::new();
let keys: Vec<Key> = t
.keys
.iter()
.map(|k| {
let interp = match &k.ease {
Ease::Hold => 0,
Ease::Linear => 1,
Ease::Table(e) => {
tables.push(Table { e: *e });
(tables.len() + 1) as u8
}
};
Key { t: k.t, value: k.value, interp, zero: [0; 3] }
})
.collect();
crate::track::eval(&keys, &tables, tau)
}
/// Whether a run, moved by `d` design subpixels, meets a `w` × `h` canvas (§5.4, *Where
/// a block is*): the exact box of one of its glyphs, at the design size, overlaps the
/// canvas. Asked here with a margin of one design pixel on every side, so placement's
/// rounding cannot put a frame the encoder counts as meeting the canvas outside it.
fn meets(set: &Wos1, glyphs: &[(u16, i32, i32)], unit_scale: u32, d: (i64, i64), w: u16, h: u16) -> bool {
let s = i64::from(unit_scale);
let lo = |v: i16| floor_div(i64::from(v) * s, 65_536);
let hi = |v: i16| -floor_div(-i64::from(v) * s, 65_536);
let (cw, ch) = (i64::from(PX) * i64::from(w), i64::from(PX) * i64::from(h));
let m = i64::from(PX);
glyphs.iter().any(|&(gid, x, y)| {
let Some(g) = set.glyph(gid) else { return false };
if g.n_points == 0 {
return false;
}
let (x, y) = (d.0 + i64::from(x), d.1 + i64::from(y));
x + hi(g.xmax) > m && x + lo(g.xmin) < cw - m && y + hi(g.ymax) > m && y + lo(g.ymin) < ch - m
})
}
/// A run of a line: its block, its glyphs placed, its clusters, its unit scale and
/// its paint.
type LineRun = (u16, Vec<(u16, i32, i32)>, Vec<(u16, u32, u32)>, u32, [u8; 4]);
/// The runs of one line read together, pushed with one window inside `[from, to)`
/// frames: from the first frame at which every run, moved by `shift(frame)`, meets a
/// `w` × `h` canvas, to `to`. Every run must meet the canvas at every frame of that
/// window, so a line is never projected while it is off the canvas.
#[allow(clippy::too_many_arguments)]
fn push_line(s: &mut SceneDef, set: &Wos1, runs: Vec<LineRun>, from: u32, to: u32, w: u16, h: u16, shift: impl Fn(u32) -> (i64, i64)) {
let on = runs
.iter()
.map(|(_, g, _, u, _)| (from..to).find(|&f| meets(set, g, *u, shift(f), w, h)).expect("the run meets the canvas"))
.max()
.expect("a line has a run");
for (text, g, c, u, paint) in runs {
assert!((on..to).all(|f| meets(set, &g, u, shift(f), w, h)), "a run leaves the canvas inside its window");
s.items.push(run(0, text, g, c, u, paint, (on * ONE, to * ONE), NO_SLOTS));
}
}
/// `motion/stroke-titles`: a title card and a credit roll in the stroke set, on a
/// 1280 × 720 design canvas listed at that size and 25 fps, seven seconds long.
///
/// - Frames 0–70, the lower third: a bar and two lines that slide in from the left on
/// an easing table over 12 frames, hold, and fade out over frames 58–70, as one
/// group.
/// - Frames 62–175, the credit roll: a heading and five credits, each a role
/// right-aligned to the gutter and what filled it left-aligned after it, moving up
/// three design pixels a frame (keys on frame ticks, so frame `k` of the roll is its
/// first frame moved `3k` pixels), entering from below the canvas and fading out over
/// frames 160–175.
///
/// Each line's window is cut to the frames at which every run of it meets the canvas.
fn stroke_titles(latin_set: &Wsf1, stroke: &SetDef) -> SceneDef {
const W: u16 = 1280;
const H: u16 = 720;
const FRAMES: u32 = 175;
// The lower third's window, the end of its slide and the start of its fade; the
// roll's window start and the start of its fade, in frames.
const LT_END: u32 = 70;
const SLIDE: u32 = 12;
const LT_FADE: u32 = 58;
const ROLL: u32 = 62;
const ROLL_FADE: u32 = 160;
const BAR: [u8; 4] = [16, 36, 96, 224];
const SOFT: [u8; 4] = [200, 210, 225, 255];
const ROLE: [u8; 4] = [160, 170, 185, 255];
let end = FRAMES * ONE;
let set = wos1::parse(&stroke.bytes).expect("the stroke set parses");
let px = |n: i32| n * PX;
// A run's width in whole design pixels, rounded up.
let width = |l: &Latin, u: u32| (r_rat(i64::from(l.2) * i64::from(u), 65_536) as i32 + PX - 1) / PX;
let mut s = SceneDef::new(TB, 0, end, W, H);
s.sizes = vec![(W, H)];
s.rates = vec![(25, 1)];
s.sets = vec![stroke.clone()];
let grouped = |purpose: u8, text: &str, group: u16| {
let mut t = block(purpose, "en", 0, text);
t.group = group;
t
};
s.texts = vec![grouped(3, TITLES_LOWER_THIRD[0], 1), grouped(3, TITLES_LOWER_THIRD[1], 1), block(1, "en", 0, TITLES_ROLL_HEADING)];
for (i, (role, part)) in TITLES_ROLL.iter().enumerate() {
s.texts.push(grouped(2, role, 2 + i as u16));
s.texts.push(grouped(2, part, 2 + i as u16));
}
// The lower third. The bar, in path units of one design pixel (unit_scale 2^24),
// ends 32 pixels past the longer line.
let (u1, u2) = (us(5), us(4));
let lines = [latin(latin_set, TITLES_LOWER_THIRD[0], 0), latin(latin_set, TITLES_LOWER_THIRD[1], 0)];
let text_x = 112;
let bar_right = text_x + width(&lines[0], u1).max(width(&lines[1], u2)) + 32;
let ease_out = Ease::Table([0, 9_000, 17_000, 24_000, 30_500, 36_000, 41_000, 45_500, 49_500, 53_000, 56_000, 58_500, 60_700, 62_500, 64_000, 65_000, 65_536]);
let slide = TrackDef { kind: 2, keys: vec![KeyDef { t: 0, value: -px(bar_right + 40), ease: ease_out }, KeyDef { t: SLIDE * ONE, value: 0, ease: Ease::Hold }] };
let fade = TrackDef {
kind: 1,
keys: vec![KeyDef { t: 0, value: 255, ease: Ease::Hold }, KeyDef { t: LT_FADE * ONE, value: 255, ease: Ease::Linear }, KeyDef { t: LT_END * ONE, value: 0, ease: Ease::Hold }],
};
s.items.push(ItemDef::Begin { clip: None, t_on: 0, t_off: LT_END * ONE, tx: Some(slide.clone()), ty: None, op: Some(fade) });
s.items.push(ItemDef::Path { path: PathDef::rect(80, 552, bar_right as i16, 668), rule: 0, paint: BAR, text: None, t_on: 0, t_off: LT_END * ONE, unit_scale: 1 << 24, slots: NO_SLOTS });
let runs = lines.into_iter().zip([(u1, 600, WHITE), (u2, 640, SOFT)]).enumerate().map(|(k, ((g, c, _), (u, y, paint)))| (k as u16, place(&g, (px(text_x), px(y)), u), c, u, paint)).collect();
push_line(&mut s, &set, runs, 0, LT_END, W, H, |f| (track_at(&slide, i64::from(f * ONE)), 0));
s.items.push(ItemDef::End);
// The roll: rises three design pixels a frame from its first frame to the end.
let rise = TrackDef::linear(2, ROLL * ONE, 0, end, -3 * PX * (FRAMES - ROLL) as i32);
let roll_op = TrackDef {
kind: 1,
keys: vec![KeyDef { t: 0, value: 255, ease: Ease::Hold }, KeyDef { t: ROLL_FADE * ONE, value: 255, ease: Ease::Linear }, KeyDef { t: end, value: 0, ease: Ease::Hold }],
};
s.items.push(ItemDef::Begin { clip: None, t_on: ROLL * ONE, t_off: end, tx: None, ty: Some(rise.clone()), op: Some(roll_op) });
let rose = |f: u32| (0, track_at(&rise, i64::from(f * ONE)));
let head = latin(latin_set, TITLES_ROLL_HEADING, 0);
let head_x = px(640) - r_rat(i64::from(head.2) * i64::from(u1), 2 * 65_536) as i32;
push_line(&mut s, &set, vec![(2, place(&head.0, (head_x, px(760)), u1), head.1, u1, WHITE)], ROLL, FRAMES, W, H, rose);
for (i, (role, part)) in TITLES_ROLL.iter().enumerate() {
let y = px(806 + 38 * i as i32);
let (r, p) = (latin(latin_set, role, 0), latin(latin_set, part, 0));
let rx = px(620) - r_rat(i64::from(r.2) * i64::from(u2), 65_536) as i32;
let runs = vec![(3 + 2 * i as u16, place(&r.0, (rx, y), u2), r.1, u2, ROLE), (4 + 2 * i as u16, place(&p.0, (px(660), y), u2), p.1, u2, WHITE)];
push_line(&mut s, &set, runs, ROLL, FRAMES, W, H, rose);
}
s.items.push(ItemDef::End);
s
}
/// The test words' shaping, checked by the joining-table test: `(text, gids in logical
/// order)`. The expected glyph IDs are written as the code points Unicode assigns to
/// each contextual form, never through the table's own constants, so a table that