Repository navigation
v1.11.0
Added
m-keyboard(series music 音楽, purposemusic; not in the free pack for now): a piano keyboard for school music lessons. Child JSON{"range": "C4-C6", "names": "solfa" | "abc" | "iroha" | "none", "cumulative": bool, "dur": s, "steps": [{"keys": ["C4", "E4", "G4"], "label", "t": [s per key], "tone", "dur"}]}.rangecovers 1–3 octaves (12–36 semitones) and starts and ends on white keys; the part draws its own SVG keyboard: white keys as rectangles, black keys 0.58 wide and 0.62 long, on top, centred as on a real keyboard (the C–E group split into fifths and the F–B group into sevenths: C♯/D♯ and F♯/A♯ lean outwards, G♯ is centred). White-key names under the keyboard (ドレミファソラシ, CDEFGAB or ハニホヘトイロ); black-key names (ド♯ / C♯ / 嬰ハ, レ♭ / D♭ / 変ニ) only on lit keys, above the keyboard (a second row when two would touch). Each step lights its keys in--emph(or the step'stone) with a filled dot; a lit black key keeps its dark rim around the coloured inside;cumulative: truekeeps earlier steps' keys lit, faded, with a ring instead of the dot (never colour alone). Per-keytstaggers a scale or arpeggio, equaltis a chord.events(k)(spec §8.4 "Component sounds"): onenoteper key,pitchthe key name,vel0.7,durfromdur(step, then top level) or else to the next latert(0.8 s for the last);duration(k)reaches the end of the last note. Sound is never the only carrier: the lit keys show the same. Step labels 30 px above the keyboard. The lecture view (ctx.preview, orctx.mode === "lecture"from older players) shows later steps' keys faint without the dot, at the theme's--preview-opacityread with getComputedStyle (spec §8.4 "Answers under preview"; 0.45 only when the variable is missing). The part has no controls. Variantslight(0, the light fades in),press(the key dips 4 px and comes back),rise(the light fills the key from the bottom), all within 0.3 s and within the note. Range, key-name andt-length errors show the placeholder- Series
music(音楽, a subject series like kokugo) intools/lint.mjs(SERIES,SERIES_LABEL) and CONTRIBUTING; purposemusic(「音楽(音の高さ・和音・リズム)」 / "Music (pitch, chords, rhythm)",tile: "none"liketext-structure, icon keymusic) inpurposes.jsonand docs/conventions(.ja).md §4.tools/lint.mjsnow also fails when a series has no label tools/test-keyboard.mjs(intools/test-all.mjs): m-keyboard's key geometry without a browser (black-key centres 0.9, 2.1, 3+6/7, 5, 3+22/7 in white-key widths, width 0.58, over the line between their two white keys, the same offsets in every octave and from a range starting on D), key names (solfa, abc, iroha with 嬰・変, none, ♯ and ♭, E♯/B♯/F♭/C♭ refused), the events per step (a chord at one t, a scale with increasing t, pitches, dur to the next t or 0.8 s, step dur and top-level dur, the step length), the key state per step and time (current, cumulative, and the lecture preview: later steps faint, the current step's unlit keys and keys lit now not marked) and the range errors (one key, not key names, black ends, under 1 or over 3 octaves, backwards)tools/test-keyboard-preview.mjs(intools/test-all.mjs): m-keyboard's lecture preview in a browser: later steps' keys faint without the dot at the theme's--preview-opacity(0.45 when missing; 0.3 when set), also withctx.mode === "lecture", keys lit now unchanged, nothing without previewtools/test-shape.mjs: m-keyboard's wrong-shape case (notesinstead ofkeys)m-timeline: project-plan (Gantt) features, as an extension of the timeline (standards decision, owner-approved; not a new part). Nodeafter: ["id", …]draws a finish-to-start arrow (--muted, 3 px, right angles) from the end of each predecessor to the start of the dependent item, in the step where the dependent item appears, drawn while it appears; vertical runs are placed so as not to cross other bands or their names where that is possible; a dependent that starts on its predecessor's end day is entered from its edge near the start. With anyafter, each item of a lane gets its own row (author order). Nodeprogress(0–100) fills the band from its start in a stronger tone, with the % after the name when it fits (24 px). Attributetoday="2026-11-02"draws a vertical--accent2line with 今日 / Today (with periods only). Attributeunit="day" | "week" | "month"chooses the axis ticks: labels at the finest interval whose 24 px labels do not overlap, short unlabelled ticks between, weekends shaded lightly in day mode; withoutunitthe ticks are as before. A lesson that uses none of these renders as before (tools/test-seed0.mjs). The today line is drawn beneath the bars and their names, so it never strikes through bar text. Demo slide 「アプリ開発の工程表(架空)」. Pack-visible bytes (tools/pack-bytes.mjs) +278 form-timeline(README one bullet, theunit/todayprop docs,after?progress?in the shape summary; details in anllm: omitblock)tools/pack-bytes.mjs: the pack-visible bytes of each component (README outsidellm: omitwithout lines about demo.html, examples/, tools/ or the motion-components skill; frontmatter name, summary, steps; each prop's type, default and doc; the shape summary), at a git ref or the working tree, with--base <ref>for the difference to report in release notestools/test-timeline-gantt.mjs(intools/test-all.mjs): arrows start at the predecessor's end and end at the dependent's start with right angles and without crossing bands, the progress fill is progress % of the band, the today line sits at the date's position, and day / week / month tick labels do not overlap and stay at 24 px (the demo's plan and four made-up cases, includingorient="v")m-kakijun(series kokugo 国語, purposeprocess; not in the free pack for now): stroke order (書き順) of kana.text="あさ"(ひらがな・カタカナ, 濁音・半濁音, small kana, ー; 166 characters), one step per character with its strokes drawn one by one within the step (about 0.6 s a stroke, scaled by its inked length;per="stroke": one step per stroke; cues at each stroke start). The shapes are derived from strokesvg (Klee One), SIL OFL 1.1:data/kana/strokes.ofl.json, embedded verbatim (its_licensefirst) in index.js as the only thing between/* BEGIN OFL-1.1 data … */and/* END OFL-1.1 data */; the part's licence isMIT AND OFL-1.1(READMElicense:, manifestcomponents.kakijun.license), withOFL.txt,LICENSE-strokesvg.txtandstrokes-CHANGES.mdin the part's folder and aNOTICEentry (Studio inlines only a part's index.js, so a separate data file cannot ship yet). Each stroke is drawn as strokesvg does (data/kana/proto.html): a round brush along the centreline, clipped by the stroke's own outline, advanced by dash offset, no fleck behind the start; finished strokes in full, nothing of a later stroke early.grid="cross" | "none"(box with dashed 十字 guides),ghost(unwritten strokes faint),nums(circled stroke numbers at each start, 24 px, placed off each other, off the ink and without crossing leaders),ends="on"(とめ・はね・はらい at each end, 24 px, with a dotted leader when moved away),writing="tate"(top to bottom, columns right to left, boxes of a column touching; small kana in the upper-right quarter, lower-left in horizontal writing; a small kana's numbers and ending labels stay inside its own square on the empty side, and other characters' labels keep out of it; a warning when they cannot fit),size. A character without data warns and is drawn plainly in the theme font. The drawing is aria-hidden; accessible name 「あさ(書き順)」 and a readable layer (characters, stroke counts, endings) in real kana. Underctx.preview, later steps at the theme's--preview-opacity(0.45 without it). Variantsdraw(the default, first),pen(no fade: the order and direction are the content); the chooser is the seedless one. The part is about 210 KB (the shapes about 175 KB) Without numbers and ending labels (nums="off", noends), the margin around the boxes shrinks from 36 to 8 px.tools/kana-embed.mjs: writescomponents/kakijun/index.js's two data blocks (kakijun-data, MIT: count, ends, place and each stroke's inked length fromdata/kana/kana.json; the OFL-1.1 data between/* BEGIN OFL-1.1 data … */and/* END OFL-1.1 data */:data/kana/strokes.ofl.jsonverbatim) and copies the licence files into the part's folder;--checkcompares themtools/test-kakijun.mjs(intools/test-all.mjs): both embedded blocks equal the data files (the OFL block verbatim,_licensefirst) and the licence files are in place; for all 166 characters the final state covers 100 % of the outlines and nothing outside them, and in the middle of a stroke the ink stays inside the outlines drawn so far (no bleed); small kana inside their quarter in both writings, and their labels inside their own square on the empty side; the OFL-1.1 data markers and the manifest licence; steps, unknown characters, the accessible name and readable layer in real kanaNOTICE: lists the licence of m-kakijun's stroke shapes (SIL OFL 1.1) next to the repository's MIT licence; README.md / README.ja.md say thatcomponents/kakijun/index.jscontains an OFL-1.1 data block- README frontmatter
license:(optional SPDX expression,MIT AND <id>; checked bytools/lint.mjs, the licence text must be in the part's folder) goes into manifest.json ascomponents.<name>.license(tools/release.mjs)
Changed
- Visible change: preview views. In the lecture or preview view (
ctx.preview, orctx.mode === "lecture"from the current bundled player) every component exceptm-predict,m-hissanandm-timernow shows its later steps faintly, at the theme's--preview-opacity; 13 components do so for the first time and the others change how faint they are (details below). Talk, learn and video views are unchanged m-predict,m-hissan: visible change. Under preview they no longer show anything ahead: no later step is drawn faintly, so the answer (m-predict) and the digits still to be computed (m-hissan) appear only at their own step. Lessons pinned to v1.10.0 or earlier keep the faint later steps- Answers under preview (egatari-spec §8.4, Egatari Player P1): visible change, in the lecture or preview view only (
ctx.preview, orctx.mode === "lecture"from the current bundled player); normal rendering is byte-identical. Every component now draws the content its later steps would add, in its final state, at the theme's--preview-opacity(read with getComputedStyle on the element; 0.45 only when the variable is missing), with controls inert for that content; the current step renders as usual. Newly previewing:m-bars(later bars that fit the current axis),m-codetree(the later codewords' pixel cells and bit brackets; not the tree paths, whose window moves each step),m-collect(the summary boxes),m-curves,m-flow,m-gendai,m-kanbun(訓点, reading-order numbers and arcs, 書き下し文),m-kobun(slashes, part-of-speech labels and 現代語訳; the text keeps its colour until its step),m-kpi,m-market,m-quad,m-seq(the final curve and later dots),m-sweep(the curves for later values). Components that already previewed read--preview-opacityinstead of a fixed 0.45 (m-boxplotm-cyclem-fishbonem-histm-map-japanm-numberlinem-piem-scatterm-tapem-timelinem-tree),--lecture-dim(m-comparem-venn) or 0.28 (m-menu, whose faint cards are no longer clickable or focusable);m-numberlineandm-tapealso honourctx.preview. Exempt:m-predict(the answer),m-hissan(the digits are the computation) andm-timer(time ahead is not content) declarestatic preview = "none"and show nothing ahead (m-predictandm-hissanno longer show later steps faintly);tools/lint.mjschecks the flag andtools/release.mjswrites it to manifest.json ascomponents.<name>.preview: "none". Authors hide a particular answer withdata-preview="none", honoured by the player. Newtools/test-preview.mjs(intools/test-all.mjs); docs/conventions(.ja).md §1.2. Pack-visible README text:m-cyclem-fishbonem-piem-scatterm-timelinem-tree+5 bytes each (「薄く(0.45)」 became 「テーマの薄さで」); all other README notes, including the parts whose preview is partial (m-barsm-codetreem-kobunm-seqm-sweep), are inllm: omitblocks (pack-visible bytes unchanged) - No lesson seed (egatari-spec 28d8801, spec §8.4; Studio no longer writes
data-egatari-seed): a part's variant is itsvariant="<name>"attribute when it names one of its variants, otherwise the first name instatic variants.tools/variant.jsdrops the seed steps (the component'sseedattribute, the lesson'sdata-egatari-seed, the hashing and the seeded generator;VARIANTnow has onlyof), re-synced into every part with variants (17, andm-kakijun, merged after it). No visible change for lessons without a seed: seed 0 always gave the first variant, checked for every part (boxplot, compare, cycle, fishbone, hissan, hist, keyboard, kpi, map-japan, numberline, pie, predict, scatter, tape, timeline, tree, venn), and no part read the seed elsewhere. A lesson that carried a non-zero seed and pins v1.10.0 or earlier keeps its look; moved to this release, its parts withoutvariantshow their first variant.seedanddata-egatari-seedare ignored without a warning; an unknownvariantstill warns tools/test-seed0.mjsbecomestools/test-default-variant.mjs(same comparison: each part's demo, built with the last release's index.js and with the current one, must be pixel-identical; the default is now "the first variant" rather than "seed 0").tools/test-variant.mjschecks every part with variants: nothing written gives the first variant,seedanddata-egatari-seedare ignored, each name selects itself, an unknown name warns- READMEs of
m-comparem-cyclem-fishbonem-kpim-piem-scatterm-timelinem-treem-venn: 「書かなければ資料のシード値(data-egatari-seed)で選ばれる」 became 「書かなければ最初の見せ方」 (pack-visible bytes −43 each). The variants slides of 13 demos say 「→ 書かなければ最初の見せ方(fade)になる」 (m-kpi: count);m-hist's demo drops 「見せ方はシード値で選ばれる」. docs/conventions(.ja).md §1 (variants without a seed; §5 item 1 withdrawn), CONTRIBUTING(.ja), docs/input-components.ja.md
Fixed
.gitattributes:data/** -text, so a Windows checkout keepsdata/kana/byte-identical to the copies incomponents/kakijun/(tools/kana-embed.mjs --checkfailed there)m-tree,m-venn,m-numberline: the same step could come out with tens of different edge pixels (rounded box corners, circles, arcs) depending on how often it had been drawn before, so Egatari Studio's determinism check, its call-order check and test-step-reset failed now and then on CI's Linux and Windows (#1101). The DOM was always the same: Chrome draws an SVG shape that is rasterized again without being rebuilt (because something near it changed) with a different outline from its second raster on, on a software GPU, and how often that happened depended on the frames painted between calls.rendernow rebuilds the part's shapes at its end (the same attribute values; the DOM and a single render's pixels are unchanged). m-tree and m-venn had this since their first release (v1.9.1 behaves the same)tools/test-raster-history.mjs(intools/test-all.mjs): for each demo step of the three parts, the pixels after the step was drawn again several times and after a click with ctx.reset equal those of a fresh drawm-numberlinedemo: the 2本の数直線 slide overflowed the slide body by 47 px in Egatari Studio's checker (the part needed 478 px with arcs on both lines). It now shows the ×2/3 arc on the price line only, at 440 px; the part is unchanged- The same step left a different DOM depending on the calls before it (docs/contract.md §3; Egatari Studio's harness now compares the component DOM byte for byte between two renders of the same state). Drawing is unchanged.
m-cycle: a hidden arrowhead kept thetransformof an earlier render (demo slide 3, step 4); render now removes it.m-codetree: colours were written withstyle.fill = …(serialised asfill: var(--muted);) next toDECK.el'sfill:var(--muted);, so thestyletext depended on the history; render now writes thestyleattribute inDECK.el's form. A hidden run swatch is reset to itsx="0"instead of losingx, which had moved the attribute.m-seq,m-sweep: the faint curves'strokeis written the same way (samestyle.strokeissue).m-seq: the mark line and its label go back to x = 0 on steps without a mark instead of keeping the previous step's position.m-hist: the frequency polygon dropsstroke-dashoffsetwithstroke-dasharraywhen it is not being drawn in (grow).m-map-japan(variant="draw"): areas and lines not yet shown get the same outline, fill and dash attributes as at the start of their draw, instead of keeping an earlier render's.m-menu: each render writes the card'sstyleas one string after the author's own, andtabindex/aria-hiddenin a fixed order (withstyle.pointerEventsand toggled attributes, the attribute text and order depended on the steps shown before) tools/test-dom-order.mjs(intools/test-all.mjs): for every part's demo, every slide and every step k at its end, in the talk and lecture views, the components' DOM (outerHTML, byte for byte, no tolerance and no pixels) after seeking straight to k on a fresh deck equals the DOM after then seeking k+1, 0 and k. It caught the seven parts above
Pack-visible bytes (Egatari Studio's AI pack), change since v1.10.0
Counted with node tools/pack-bytes.mjs --base v1.10.0 (README outside llm: omit, frontmatter, props, shape summary).
- Free core:
m-bars+0,m-flow+0,m-menu+0,m-predict+0 - Free by subject:
m-curves+0,m-kpi−43,m-quad+0 - Kokugo:
m-gendai+0,m-kanbun+0,m-kobun+0 - Paid only:
m-timeline+240,m-compare−43,m-venn−43,m-cycle−38,m-fishbone−38,m-pie−38,m-scatter−38,m-tree−38; newm-kakijun1586,m-keyboard839; every other part +0
sha256 dd75a0e048e9de44865ad9ae8e0ddb0ae37cd13d2fb8b037d75c9e0d87238756 egatari-components-v1.11.0.tar.gz