@nanisoft/prism-llms 0.5.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,6 +6,17 @@
6
6
 
7
7
  # @nanisoft/prism-llms
8
8
 
9
+ ## 0.6.0
10
+
11
+ ### Minor Changes
12
+
13
+ - Regenerate the corpus for the third law of motion
14
+
15
+ The corpus picks up the `ParticleField`, `AuroraWash` and `Reveal` entries, the
16
+ `backdrop` slot on `Hero01`, the `aurora` field on `Backdrop01`, the
17
+ `scrollRail` prop on `SiteNavbar`, and the rewritten Motion documentation,
18
+ whose third law the new items document in their own JSDoc.
19
+
9
20
  ## 0.5.2
10
21
 
11
22
  ### Patch Changes
@@ -267,6 +278,13 @@ Changesets are appended above this entry for every published change.
267
278
 
268
279
  # @nanisoft/prism-mcp-server
269
280
 
281
+ ## 0.4.3
282
+
283
+ ### Patch Changes
284
+
285
+ - Updated dependencies
286
+ - @nanisoft/prism-llms@0.6.0
287
+
270
288
  ## 0.4.2
271
289
 
272
290
  ### Patch Changes
@@ -373,6 +391,16 @@ Changesets are appended above this entry for every published change.
373
391
 
374
392
  # @nanisoft/prism-tokens
375
393
 
394
+ ## 1.5.0
395
+
396
+ ### Minor Changes
397
+
398
+ - Add the `aurora` ambient cycle at 24000ms
399
+
400
+ The new member measures light crossing a ground: the washes a hero stands on.
401
+ It rides `ambient-ease-drift`, holds to the one-second floor with the rest of
402
+ the group, and is admitted into the closed set the emitted-contract gate holds.
403
+
376
404
  ## 1.2.0
377
405
 
378
406
  ### Minor Changes
@@ -914,6 +942,58 @@ Changesets are appended above this entry for every published change.
914
942
 
915
943
  # @nanisoft/prism-ui
916
944
 
945
+ ## 1.5.0
946
+
947
+ ### Minor Changes
948
+
949
+ - Add the third law of motion: arrivals, living fields, and the reading rail
950
+
951
+ Motion now has three laws. Feedback and the ambient cycles are unchanged; the
952
+ new law admits three authored mechanisms, each shipped as primitives rather
953
+ than opened as a licence:
954
+
955
+ - `Reveal` wraps a band in a scroll-driven arrival bound to the reader's own
956
+ scroll through `prism-reveal` utilities behind a view-timeline capability
957
+ check. No script arms it, a browser without the timeline ships no rule at
958
+ all, and the universal reduced-motion rule hands that reader the visible
959
+ page.
960
+ - `ParticleField` is the one script-driven figure: a linked, pointer-answering
961
+ medium whose complete still field renders on the server, whose loop stops off
962
+ screen, and whose palette is re-read when the document's pack or mode
963
+ changes. `AuroraWash` is the still counterpart: translucent planes in the
964
+ pack's own colours on the new `aurora` cycle, transform-only.
965
+ - `SiteNavbar` gains a reading rail on its sticky hairline, `scrollRail` on by
966
+ default: a spectrum line filling with the page's own scroll, drawing nothing
967
+ in a browser that cannot run the timeline. The current link's filled pill
968
+ becomes a persistent spectrum underline, and `Hero01` gains a `backdrop` slot
969
+ so a hero composes its own ground.
970
+
971
+ `Backdrop01` offers `field="aurora"`, and `prism-text-spectrum` is the one
972
+ admitted motion on text: display ink lit at the sweep tempo with foreground
973
+ ends, so it holds contrast in every pack and both modes.
974
+
975
+ `scripts/check-motion.mjs` holds the new layer: a reveal or rail selector
976
+ outside the `@supports` block naming its timeline fails the build, because an
977
+ animation whose timeline fails to resolve pauses at its invisible keyframe.
978
+
979
+ ### Patch Changes
980
+
981
+ - Updated dependencies
982
+ - @nanisoft/prism-tokens@1.5.0
983
+
984
+ ## 1.4.0
985
+
986
+ ### Minor Changes
987
+
988
+ - 3f9cc78: Add `MediaBand01`, an editorial band with a caller-owned media slot, and a `size`
989
+ prop on `Section` for compact, default and tall vertical rhythms.
990
+
991
+ The band owns the frame, the ratio, the surface and the order, and it never puts
992
+ the copy on top of an arbitrary photograph. The media is the caller's node, so an
993
+ image, a video poster or a composed figure can sit in the frame. The Section size
994
+ keeps the existing default byte-identical and gives a page three authored rhythms
995
+ instead of five site stylesheets inventing their own.
996
+
917
997
  ## 1.3.0
918
998
 
919
999
  ### Minor Changes
@@ -6126,10 +6206,10 @@ icon-only control carries an accessible name.
6126
6206
 
6127
6207
  # Motion
6128
6208
 
6129
- Two laws: feedback on a short scale, and a running figure on a cycle scale, both by token.
6209
+ Three laws: feedback on a short scale, a running figure on a cycle scale, and an arrival bound to the reader's own scroll, all by token.
6130
6210
 
6131
- Motion has two laws, and they are different laws rather than one law with an
6132
- exception. The distinction is falsifiable: stop the animation and ask whether
6211
+ Motion has three laws, and they are different laws rather than one law with
6212
+ exceptions. The distinction is falsifiable: stop the animation and ask whether
6133
6213
  the figure is still true and still legible.
6134
6214
 
6135
6215
  **Feedback is a response.** Something happened because the reader did it. They
@@ -6139,29 +6219,46 @@ overshoots. The scale is `fast` 80ms, `base` 160ms and `slow` 280ms, with
6139
6219
  token rather than a value, and it does not decide reduced motion for itself.
6140
6220
 
6141
6221
  **A cycle is a demonstration.** A marker crosses a rail, a reticle crosses a
6142
- series, a wavefront crosses a field. The reader did not cause it and is not
6143
- waiting for it: the figure is making a claim about a mechanism and the motion is
6144
- how the claim is made visible. If stopping the animation leaves nothing true and
6145
- nothing legible, the motion was the figure, and the right component is one that
6146
- says it is atmosphere.
6147
-
6148
- The cycle scale is separate because the two measure different things by a factor
6222
+ series, a wavefront crosses a field, light crosses a ground. The reader did not
6223
+ cause it and is not waiting for it: the figure is making a claim about a
6224
+ mechanism and the motion is how the claim is made visible. If stopping the
6225
+ animation leaves nothing true and nothing legible, the motion was the figure,
6226
+ and the right component is one that says it is atmosphere.
6227
+
6228
+ **An arrival is bound to the reader's own scroll.** A section a reader scrolls
6229
+ to may meet them, and the meeting is the third law rather than a loosened
6230
+ second: it runs on CSS scroll-driven animations, so no script decides when it
6231
+ plays and no timer can play it early; the content exists in the document from
6232
+ the first paint; a browser that does not ship the timeline declines the whole
6233
+ rule and shows the section simply there; and the universal reduced-motion rule
6234
+ hands that reader the same still page. The one script-driven figure in the
6235
+ system, `ParticleField`, follows the same test from the other side: it renders
6236
+ its complete still figure on the server and the script only adds the movement.
6237
+
6238
+ The cycle scale is separate because it measures a different thing by a factor
6149
6239
  of twenty-five, and one name cannot mean both. `ambient` is in seconds, and the
6150
- emitted contract measures it with a floor of one second: a cycle faster than that
6151
- is unreadable before it is understood.
6152
-
6153
- Three rules bound it, and none of them is a matter of taste.
6154
-
6155
- - **Nothing is hidden.** No ambient rule sets `opacity: 0`, and nothing waits
6156
- for a script, an intersection or a timer. Every figure is complete at first
6157
- paint, so a reader with scripting off, a print stylesheet or a crawler sees the
6158
- whole drawing.
6240
+ emitted contract measures it with a floor of one second: a cycle faster than
6241
+ that is unreadable before it is understood.
6242
+
6243
+ Three rules bound the ambient layer, and none of them is a matter of taste.
6244
+
6245
+ - **Nothing in the ambient layer is hidden.** No ambient rule sets `opacity: 0`
6246
+ and no ambient figure waits for a script or a timer. Every figure is complete
6247
+ at first paint, so a reader with scripting off, a print stylesheet or a
6248
+ crawler sees the whole drawing. The reveal layer is the one exception ever
6249
+ granted, and it is granted to the reader's own scroll position rather than to
6250
+ a script: it lives behind a capability check, and collapses to the fully
6251
+ visible form the moment anything, including reduced motion, declines to run
6252
+ it.
6159
6253
  - **Reduced motion removes the movement, not the figure.** The
6160
6254
  `prefers-reduced-motion` block is one unlayered rule setting `animation: none`
6161
6255
  and `transition: none` on the universal selector, and because every resting
6162
6256
  state is the full form, that reader gets the same figure, still.
6163
- - **Compositor properties only.** Every keyframe animates `transform` or
6164
- `opacity`. Nothing in the layer animates a layout or paint property.
6257
+ - **Compositor properties only.** Every ambient keyframe animates `transform`
6258
+ or `opacity`. Nothing in the layer animates a layout or paint property. The
6259
+ one named exception is the spectrum ink on display type, which animates a
6260
+ gradient position because text cannot be moved behind its own gradient, and
6261
+ the exception is a class in the stylesheet with a scope, not a licence.
6165
6262
 
6166
6263
  One rule covers the whole package rather than each component guarding itself, and
6167
6264
  that is a correction rather than a preference. A `motion-safe:` variant adds a
@@ -6176,8 +6273,8 @@ announcement, without the time.
6176
6273
  A keyframe is a mechanism and lives in the component package's stylesheet; a
6177
6274
  duration is a value and lives in the token source. They meet at exactly one
6178
6275
  place, an `animation` shorthand whose length is `var(--ambient-travel)`, so
6179
- neither can invent the other. The six `prism-ambient-*` classes exist so that a
6180
- component picks a cycle by naming a mechanism and never writes a timing.
6276
+ neither can invent the other. The eight `prism-ambient-*` classes exist so that
6277
+ a component picks a cycle by naming a mechanism and never writes a timing.
6181
6278
 
6182
6279
  <TokenTable group="motion" />
6183
6280
 
@@ -7800,6 +7897,99 @@ export default function AspectRatioDemo() {
7800
7897
  **`className`** `string` · optional · default: — — Layout only.
7801
7898
 
7802
7899
 
7900
+ ---
7901
+
7902
+ # AuroraWash
7903
+
7904
+ Light moving through a ground: translucent planes in the pack’s own colours, each on its own long orbit of the aurora cycle.
7905
+
7906
+ ```tsx
7907
+ import { AuroraWash } from '@nanisoft/prism-ui/components/aurora-wash'
7908
+ ```
7909
+
7910
+ ## Overview
7911
+
7912
+ AuroraWash is light moving through a ground: two or three large translucent
7913
+ planes in the pack's own colours, each on its own long orbit of the aurora
7914
+ cycle. It follows the wash law, so the stops are semantic, the element is
7915
+ `aria-hidden`, and it never touches text.
7916
+
7917
+ ## Guidelines
7918
+
7919
+ ### When to use
7920
+
7921
+ Use it where a hero's ground would otherwise be flat: a band whose claim is
7922
+ that a surface is alive reads differently with light crossing it, and the wash
7923
+ says that without drawing a single invented mark. It repaints with the pack,
7924
+ because the planes carry the pack's own primary and series colours, so a wash
7925
+ in one pack is a different wash in another.
7926
+
7927
+ Give it a clipped container. The wrapper clips, but the caller gives it the
7928
+ positioned ancestor to fill, and a wash that escapes its band is a page-wide
7929
+ stain.
7930
+
7931
+ ### When not to use
7932
+
7933
+ Do not put type on it without its own contrast. A wash is a ground, and the
7934
+ content over it owns the contrast the way content over `SignalField` does.
7935
+
7936
+ Do not use two on one page. Light moving through two grounds is two weathers,
7937
+ and the reader cannot be in both.
7938
+
7939
+ Do not reach for it when the claim is a mechanism rather than an atmosphere. A
7940
+ marker crossing a rail is `Backdrop01` with the travel cycle; the wash says a
7941
+ surface is lit, not that a system runs.
7942
+
7943
+ ### Best practices
7944
+
7945
+ - Let it be quiet. The intensity of a wash is the caller's, through opacity on
7946
+ the caller's own wrapper, and the restrained version is the one that reads
7947
+ as a place rather than as a poster.
7948
+ - Pair it with `ParticleField` only when the two claims belong together, and
7949
+ let the tempos differ, which the aurora and drift cycles already do.
7950
+ - Trust the still frame. The reduced-motion rule holds the planes at rest and
7951
+ the wash survives it, which is the test every ambient figure in this system
7952
+ passes.
7953
+
7954
+ **The wash as a ground, with type over it, and a pack boundary around the**
7955
+
7956
+ ```tsx
7957
+ import { AuroraWash } from '@nanisoft/prism-ui/components/aurora-wash'
7958
+
7959
+ /**
7960
+ * The wash as a ground, with type over it, and a pack boundary around the
7961
+ * second card so the demo shows the claim the component makes: the planes
7962
+ * carry the ground's own colours, and a wash in one pack is a different wash
7963
+ * in another.
7964
+ */
7965
+ export default function AuroraWashDemo() {
7966
+ return (
7967
+ <div className="flex flex-col gap-6">
7968
+ <div className="bg-card relative overflow-hidden rounded-xl border p-10">
7969
+ <AuroraWash className="absolute inset-0" />
7970
+ <div className="relative">
7971
+ <p className="text-muted-foreground text-sm font-medium tracking-wide uppercase">
7972
+ Preview
7973
+ </p>
7974
+ <h3 className="mt-3 text-3xl font-semibold tracking-tight text-balance">
7975
+ Light through the ground the page is wearing
7976
+ </h3>
7977
+ <p className="text-muted-foreground mt-4 max-w-168 text-lg text-pretty">
7978
+ Three planes on one long orbit, out of step with each other, each
7979
+ carrying a colour the page already resolved.
7980
+ </p>
7981
+ </div>
7982
+ </div>
7983
+ </div>
7984
+ )
7985
+ }
7986
+ ```
7987
+
7988
+ ## Props
7989
+
7990
+ **`className`** `string` · optional · default: — — Layout only, exactly as on every Component. The wash fills the nearest positioned ancestor, so the caller's job is to give it one and to keep the content above it; the wash never carries the content and never takes the pointer.
7991
+
7992
+
7803
7993
  ---
7804
7994
 
7805
7995
  # Avatar
@@ -22169,6 +22359,110 @@ export default function PaginationDemo() {
22169
22359
  > Extends: the native `<nav>` element. No additional Prism-specific props.
22170
22360
 
22171
22361
 
22362
+ ---
22363
+
22364
+ # ParticleField
22365
+
22366
+ A living field: points drifting on linked paths, answering the pointer, and standing still as a complete figure when the loop is stopped or declined.
22367
+
22368
+ ```tsx
22369
+ import { ParticleField } from '@nanisoft/prism-ui/components/particle-field'
22370
+ ```
22371
+
22372
+ ## Overview
22373
+
22374
+ ParticleField is a living field: points drifting on linked paths, the medium a
22375
+ page's largest statements stand in front of. It is the one script-driven figure
22376
+ in the system, and the static field it renders on the server is the contract
22377
+ that makes that safe: stop the loop, disarm the canvas, print the page, and the
22378
+ figure is still a field, still true, still legible.
22379
+
22380
+ ## Guidelines
22381
+
22382
+ ### When to use
22383
+
22384
+ Use it where a page claims there is a medium to move through: a hero that says
22385
+ traffic flows, a band that says an estate is observed, a ground that says the
22386
+ surface is live. The links are what make it a medium rather than dust, so size
22387
+ `linkDistance` to the band: a wide band carries longer lines than a panel.
22388
+
22389
+ Give it room behind content that has its own position and its own contrast. It
22390
+ is a ground, exactly as `SignalField` is, and it composes behind type rather
22391
+ than beside it.
22392
+
22393
+ ### When not to use
22394
+
22395
+ Do not use it behind a reading passage. A medium that moves while a reader
22396
+ reads is the first thing a reader with vestibular sensitivity will ask to have
22397
+ gone, and `SignalField` still, or nothing, is the ground a passage wants.
22398
+
22399
+ Do not use it to say something. It is `aria-hidden` by default because a medium
22400
+ is not information; a figure that carries a claim is `PulseGraph` or
22401
+ `PulseSeries`, both of which require a name.
22402
+
22403
+ Do not stack two of them. Two media on one page is a collision, and the reader
22404
+ cannot tell which one they are looking through.
22405
+
22406
+ ### Best practices
22407
+
22408
+ - Leave `interactive` on wherever a reader's hand can reach the ground, and
22409
+ turn it off under text a reader will select, because a surface that moves
22410
+ during a selection is a surface fighting the selection.
22411
+ - Keep the count in the dozens. A field with hundreds of points is a haze, and
22412
+ the clamp will not save a composition that wanted fog.
22413
+ - Pair it with `AuroraWash` when the claim is light moving through the medium
22414
+ as well as across it, and let the two differ in tempo, which they already do
22415
+ by an order of magnitude.
22416
+ - Trust the floor. The component that renders nothing until a script runs is
22417
+ the retired line's defect, and this one renders the whole figure before any
22418
+ script decides to help.
22419
+
22420
+ **The field as a ground, with type over it, which is the only honest way to**
22421
+
22422
+ ```tsx
22423
+ import { ParticleField } from '@nanisoft/prism-ui/components/particle-field'
22424
+
22425
+ /**
22426
+ * The field as a ground, with type over it, which is the only honest way to
22427
+ * preview a medium: a field on its own is a scatter and there is nothing to
22428
+ * judge.
22429
+ *
22430
+ * The demo is a server component. The field is a client component under it, so
22431
+ * the floor renders here and the loop arms in the reader's browser, which is
22432
+ * the arrangement a product composes.
22433
+ */
22434
+ export default function ParticleFieldDemo() {
22435
+ return (
22436
+ <div className="bg-card relative overflow-hidden rounded-xl border p-10">
22437
+ <ParticleField count={56} className="absolute inset-0" />
22438
+ <div className="relative">
22439
+ <p className="text-muted-foreground text-sm font-medium tracking-wide uppercase">
22440
+ Preview
22441
+ </p>
22442
+ <h3 className="mt-3 text-3xl font-semibold tracking-tight text-balance">
22443
+ A medium as a ground, with type over it
22444
+ </h3>
22445
+ <p className="text-muted-foreground mt-4 max-w-168 text-lg text-pretty">
22446
+ The points drift on linked paths and answer the pointer. Move the hand
22447
+ across this panel and the medium parts around it, and the field it
22448
+ falls back to when the loop is stopped is the same field at rest.
22449
+ </p>
22450
+ </div>
22451
+ </div>
22452
+ )
22453
+ }
22454
+ ```
22455
+
22456
+ ## Props
22457
+
22458
+ **`count`** `number` · optional · default: — — How many points the field drifts. Read as a suggestion and clamped, because a field behind a hero wants dozens and a field behind a panel wants a handful, and a count outside that range is either a haze or a chart.
22459
+ **`linkDistance`** `number` · optional · default: — — How far apart two points may sit and still be linked, in CSS pixels. The links are what make a field read as a medium rather than as dust, and the distance is a prop because a wide band carries longer lines than a panel.
22460
+ **`interactive`** `boolean` · optional · default: — — Whether the reader's pointer pushes the field. On by default, because a medium that answers the hand is the claim this figure makes; a caller placing the field under text a reader is selecting turns it off, because a surface that moves while a reader drags across it is a surface fighting the selection.
22461
+ **`label`** `string` · optional · default: — — The name of the figure, or `decorative`. See `SignalFieldProps`.
22462
+ **`decorative`** `boolean` · optional · default: —
22463
+ **`className`** `string` · optional · default: — — Layout only, exactly as on every Component.
22464
+
22465
+
22172
22466
  ---
22173
22467
 
22174
22468
  # PasswordField
@@ -25694,6 +25988,123 @@ export default function ResizableDemo() {
25694
25988
  **`size`** `Position` · optional · default: `50` — The pane's share of the group, as a percentage.
25695
25989
 
25696
25990
 
25991
+ ---
25992
+
25993
+ # Reveal
25994
+
25995
+ A section that meets the reader: the wrapper that binds an arrival to the reader’s own scroll position, with no script and no second introduction for the hero.
25996
+
25997
+ ```tsx
25998
+ import { Reveal } from '@nanisoft/prism-ui/components/reveal'
25999
+ ```
26000
+
26001
+ ## Overview
26002
+
26003
+ Reveal is a section that meets the reader: the wrapper that binds an arrival to
26004
+ the reader's own scroll position and to nothing else. It is a style the browser
26005
+ resolves rather than a state a script flips, so there is no observer, no
26006
+ listener and no client boundary, and the content exists from the first paint.
26007
+
26008
+ ## Guidelines
26009
+
26010
+ ### When to use
26011
+
26012
+ Use it on the bands a reader scrolls to. An arrival acknowledges the reader's
26013
+ own movement, which is the only input it answers to, and a band that enters
26014
+ the viewport as the reader arrives reads as a page composed for reading rather
26015
+ than as one long poster.
26016
+
26017
+ Stagger with `delay` when bands arrive in a rhythm, and keep the stagger to a
26018
+ page's own measure: three steps exist, and a cascade longer than the rhythm it
26019
+ sits in is a wait the reader did not cause.
26020
+
26021
+ ### When not to use
26022
+
26023
+ Do not wrap the hero. A section above the fold when the page loads has already
26024
+ finished entering, and the page does not introduce itself twice; the one
26025
+ authored moment a page carries belongs to its hero, not to every band under
26026
+ it.
26027
+
26028
+ Do not wrap everything. A reveal on every section is one identical entrance
26029
+ wearing four different clothes, and the second arrival a reader notices is the
26030
+ one where the device stops being about the content. Let the still bands
26031
+ between the arriving ones carry their own weight.
26032
+
26033
+ Do not use it for feedback or for state. A control answering a reader is the
26034
+ first law of motion and already has its scale; an arrival is the third law and
26035
+ holds exactly one job.
26036
+
26037
+ ### Best practices
26038
+
26039
+ - Compose it around a Block, not inside one. The wrapper is the whole of the
26040
+ component, every Block keeps its own surface, and no Block widens for a
26041
+ behaviour the whole page shares.
26042
+ - Remember the fallbacks are the design: a browser without scroll-driven
26043
+ animations shows the section simply there, a reader who asked for less
26044
+ motion gets the same still page, and neither of those outcomes is a failure
26045
+ to be worked around.
26046
+ - The `delay` steps are fractions of the entry rather than waits, so a reader
26047
+ who scrolls fast arrives fast. That is the property that separates this law
26048
+ from a timer, and it is worth keeping.
26049
+
26050
+ **Two cards arriving, the second a step behind the first. The demo is the**
26051
+
26052
+ ```tsx
26053
+ import { Reveal } from '@nanisoft/prism-ui/components/reveal'
26054
+
26055
+ /**
26056
+ * Two cards arriving, the second a step behind the first. The demo is the
26057
+ * device at its smallest: a staggered pair inside one panel, so the rhythm is
26058
+ * visible without a page to scroll.
26059
+ *
26060
+ * In this documentation frame the cards below the fold are the honest preview:
26061
+ * scroll to them and they arrive, arrive again on the way back up at no delay,
26062
+ * and a reader who has asked the platform for less motion finds them simply
26063
+ * there.
26064
+ */
26065
+ export default function RevealDemo() {
26066
+ return (
26067
+ <div className="flex flex-col gap-4">
26068
+ <Reveal>
26069
+ <div className="bg-card text-card-foreground rounded-xl border p-6 shadow-sm">
26070
+ <p className="text-muted-foreground text-sm font-medium tracking-wide uppercase">
26071
+ First band
26072
+ </p>
26073
+ <h3 className="mt-2 text-xl font-semibold tracking-tight">
26074
+ An arrival, bound to the scroll the reader owns
26075
+ </h3>
26076
+ <p className="text-muted-foreground mt-2 text-sm text-pretty">
26077
+ No script decides when this plays. The hand on the scroll does, and
26078
+ a browser that cannot run it shows the band simply there.
26079
+ </p>
26080
+ </div>
26081
+ </Reveal>
26082
+ <Reveal delay={1}>
26083
+ <div className="bg-card text-card-foreground rounded-xl border p-6 shadow-sm">
26084
+ <p className="text-muted-foreground text-sm font-medium tracking-wide uppercase">
26085
+ Second band
26086
+ </p>
26087
+ <h3 className="mt-2 text-xl font-semibold tracking-tight">
26088
+ The same arrival, a step behind
26089
+ </h3>
26090
+ <p className="text-muted-foreground mt-2 text-sm text-pretty">
26091
+ The step is a fraction of the entry rather than a wait, so a reader
26092
+ who scrolls fast arrives fast, and nothing here could delay them.
26093
+ </p>
26094
+ </div>
26095
+ </Reveal>
26096
+ </div>
26097
+ )
26098
+ }
26099
+ ```
26100
+
26101
+ ## Props
26102
+
26103
+ **`children`** `ReactNode` · required · default: — — The band, grid or figure that arrives.
26104
+ **`delay`** `1 | 2 | 3` · optional · default: — — How far into the page's rhythm this arrival sits behind the one before it, as a fraction of the entry rather than as a wait: the reader's scroll is the only clock, and a delay a reader could not hurry would be a delay the reader did not cause. Three steps, as on the ambient delays.
26105
+ **`className`** `string` · optional · default: — — Layout only, exactly as on every Component.
26106
+
26107
+
25697
26108
  ---
25698
26109
 
25699
26110
  # ScrollArea
@@ -33945,7 +34356,10 @@ Use `drift` and `pulse` for any figure. They are the two whose resting form is t
33945
34356
  figure's own full form, so nothing is lost when the cycle is at either end of its
33946
34357
  turn. Use `travel`, `sweep`, `scan` and `shimmer` when the figure is drawn wider
33947
34358
  than the band, because those four carry something across a field and the band
33948
- clips what leaves.
34359
+ clips what leaves. Use `aurora` when the claim is the ground rather than anything
34360
+ crossing it: the whole layer rides one slow orbit, so it suits a wash or a wide
34361
+ field and mismatches a drawing with a baseline, which would visibly leave the
34362
+ ground it was measured on.
33949
34363
 
33950
34364
  Use `pauseControl` on a page that gives a reader reason to want the page still.
33951
34365
 
@@ -33958,9 +34372,10 @@ Do not use it for a figure that belongs in the layout rather than behind the
33958
34372
  copy. That is `InstrumentPanel01`, and a panel beside the copy says the same thing
33959
34373
  with a border and a title bar instead of an opacity.
33960
34374
 
33961
- Do not reach for it to add movement to a page. There is no entrance animation,
33962
- no scroll effect and no motion on text in this system, and this Block is the one
33963
- place a cycle is allowed, which is exactly why it is not a decoration.
34375
+ Do not reach for it to add movement to a page. A cycle demonstrates a system
34376
+ that runs, and this Block is the one place in a band a cycle is allowed; an
34377
+ arrival is `Reveal`'s job and not a faster cycle's, and neither of them is a
34378
+ decoration, which is exactly why each has one place.
33964
34379
 
33965
34380
  ### Best practices
33966
34381
 
@@ -41673,10 +42088,10 @@ at the edge rather than pushing the field wider, and the table behind the figure
41673
42088
  carries its true dates.
41674
42089
 
41675
42090
  **There is no motion, so reduced motion costs the reader nothing.** No draw-in, no
41676
- bar that grows from nothing, no scroll effect, no entrance. DESIGN.md's Motion
41677
- section refuses entrance animation outright, and a schedule is the case where that
41678
- is most obviously right: a bar that arrives is a bar whose arrival a reader has to
41679
- wait for before they can read the relationship it has with the bar above it, and
42091
+ bar that grows from nothing, no entrance. DESIGN.md's Motion section lets a band
42092
+ arrive with the reader's own scroll, and a schedule is the case where arriving
42093
+ would misread: a bar that appears is a bar whose appearance a reader has to wait
42094
+ for before they can read the relationship it has with the bar above it, and
41680
42095
  the whole claim of a Gantt is that relationship.
41681
42096
 
41682
42097
  ## The hidden table, and its gaps
@@ -42508,6 +42923,11 @@ of those is a mechanism, and a mechanism reads better shown than described. The
42508
42923
  figure should be one that would still be true with every animation stopped, so
42509
42924
  what the reader gets from it is the claim and the motion is only the emphasis.
42510
42925
 
42926
+ Compose a ground with `backdrop` when the claim is the surface the hero stands
42927
+ on. An `AuroraWash` says the surface is lit, a `ParticleField` says there is a
42928
+ medium to move through, and the band clips and positions whatever it is given,
42929
+ so the caller composes a claim rather than a layout.
42930
+
42511
42931
  ### When not to use
42512
42932
 
42513
42933
  Do not use Hero01 inside an application screen. It is a marketing composition,
@@ -42521,7 +42941,9 @@ inside `Section` instead.
42521
42941
 
42522
42942
  Do not pass a figure that is only interesting while it moves. A slot that reads
42523
42943
  as empty in a still frame is a decoration with a slot, and this system does not
42524
- author those.
42944
+ author those. The same test holds for the ground: a `backdrop` that collapses
42945
+ into nothing when it is stopped was a video with extra steps, and the hero is a
42946
+ band making a claim, not a frame around one.
42525
42947
 
42526
42948
  ### Best practices
42527
42949
 
@@ -42658,6 +43080,7 @@ export default function Hero01Demo() {
42658
43080
  **`align`** `'center' | 'left'` · optional · default: `'center'` — Whether the copy is centered in the band or set flush to the left edge of the container. This is the hero's own alignment and not `SectionHeading`'s, because the two are not the same decision: a left-aligned hero is nearly always the left half of a two-column band with a panel or an instrument beside it, and that column is narrower than the container, so the alignment has to be the hero's before the container can be anything. It has no visual effect on its own, which is the point: it aligns the copy inside whatever width it is given.
42659
43081
  **`instrument`** `ReactNode` · optional · default: — — The figure beside the copy: a live view of the thing the copy is about. A slot, and the reason is the whole shape of this Block's second form. The hero that names what a product does and the hero that shows it running are the same section, and every one of the four NaniSoft product sites hand-wrote the two-column band that joins them, each with its own grid, its own gap and its own breakpoint. This is that band. What goes in it is the consumer's, and specifically it should be something that would still be true with every animation stopped: a `PulseGraph` of the pipeline the product runs, a `PulseSeries` of what it captures. A slot that only reads as motion is a decoration with a slot, and this system does not author those. The `instrumented` slot is marked as required when the hero is given one, so a figure cannot be half-wired.
42660
43082
  **`split`** `boolean` · optional · default: — — Puts the copy and the instrument side by side rather than stacked, and narrows the copy to the column it shares the band with. Implied by `instrument` and overridable: a consumer with a narrow instrument and a wide hero may want them stacked anyway.
43083
+ **`backdrop`** `ReactNode` · optional · default: — — The ground the hero stands on: a figure the whole band is drawn over. A slot, and for the same reason the instrument is one: the ground a hero wants is the product's own claim, and this Block cannot make it. An `AuroraWash` says the surface is lit, a `ParticleField` says there is a medium to move through, and a caller who wants both composes both, because the one decision a hero should not delegate is what its ground claims. The Block clips the ground to the band, takes the pointer away from it, and holds it behind the copy beside the hero's own faint wash, so a slot here never has to arrive pre-positioned. A ground that would not still be true with every animation stopped does not belong here, for the same reason an instrument that only reads as motion does not: this is a band making a claim, not a frame around a video.
42661
43084
  **`headingLevel`** `HeadingLevel` · optional · default: — — Heading level for the title. Defaults to `h2` because a block is composed, not a page: it installs into a consumer's layout and renders inside catalog previews, so the surrounding document already owns the `h1`. A page that uses this block as its top-level heading opts in with `headingLevel="h1"`; a document that already names this section in its own heading passes one level deeper. See `HeadingLevel`.
42662
43085
  **`className`** `string` · optional · default: — — Layout only, exactly as on every Component. Changing a Prism-owned visual property from here is prohibited.
42663
43086
 
@@ -46686,6 +47109,133 @@ export default function MagicLink01Demo() {
46686
47109
  **`dependencies`** `Button, Card, Field, Input, LiveRegion, Section` — the public Prism exports this item composes
46687
47110
 
46688
47111
 
47112
+ ---
47113
+
47114
+ # MediaBand01
47115
+
47116
+ An editorial band: one media slot held at a caller ratio beside one title, description and optional destination, with the copy always on a solid surface.
47117
+
47118
+ ```tsx
47119
+ import { MediaBand01 } from '@nanisoft/prism-ui/blocks/media-band-01'
47120
+ ```
47121
+
47122
+ ## Overview
47123
+
47124
+ MediaBand01 is an editorial band: one media frame beside one statement, with one
47125
+ action. It is the marketing surface the catalogue did not have. `Bento01` holds a
47126
+ media node in a cell, but a cell is one item of a set, and a set is the wrong shape
47127
+ for the one photograph a page stops on. `Gallery01` holds a set of images and opens
47128
+ one at full size, which is right for a portfolio and wrong for a statement.
47129
+
47130
+ The media is a slot, not a `src`. A caller can pass an image, a video poster, a
47131
+ rendered figure, or a composition of its own components. The Block owns the frame,
47132
+ the ratio, the surface and the order. The caller owns the node and its accessible
47133
+ name.
47134
+
47135
+ The copy is first in the document, and the media is first only in the visual order
47136
+ the caller asks for. A reader on a phone meets the title before the picture, and a
47137
+ reader at `lg` meets the arrangement the caller chose. That is one tree, so the
47138
+ heading is in the outline once.
47139
+
47140
+ The copy never sits on the picture. A title over an arbitrary photograph is a
47141
+ contrast failure nobody measured, and the solid column beside the image is both
47142
+ more legible and more editorial.
47143
+
47144
+ There is no animation. An editorial photograph is not feedback and it is not a
47145
+ figure showing a system running, so the band does not zoom, slide or reveal.
47146
+
47147
+ ## Guidelines
47148
+
47149
+ ### When to use
47150
+
47151
+ Use MediaBand01 when a page has one photograph or one composed figure that is a
47152
+ moment of its own, and one sentence that the picture makes. It is the band a page
47153
+ stops on between two sections of argument.
47154
+
47155
+ ### When not to use
47156
+
47157
+ Do not use it for a set of images. A set is `Gallery01` or a `Bento01` grid. Do not
47158
+ use it for a figure that carries a claim a screen reader must hear in full; that is
47159
+ `InstrumentPanel01` or one of the figure Components. Do not put the copy on top of
47160
+ the image; the solid column is the arrangement this Block exists to make easy.
47161
+
47162
+ ### Ratios and sides
47163
+
47164
+ `ratio` is `wide`, `square` or `portrait`. `align` is `media-left` or `media-right`,
47165
+ and it changes the visual order only. Below the breakpoint the copy always comes
47166
+ first.
47167
+
47168
+ ### Tone
47169
+
47170
+ `default` leaves the band on the page ground. `muted` puts it on the muted surface,
47171
+ which is for a band that is a chapter rather than a transition. The muted arm states
47172
+ its own ink as well as its own fill.
47173
+
47174
+ ### The media slot
47175
+
47176
+ The caller's node fills the frame. The Block does not style a node it did not
47177
+ render, so the image should set its own width, height and `object-fit`, and it
47178
+ should carry the alt text that names it. A composed figure should carry its own
47179
+ accessible name.
47180
+
47181
+ **The band with a placeholder in the media slot.**
47182
+
47183
+ ```tsx
47184
+ import { ImageIcon } from 'lucide-react'
47185
+
47186
+ import { MediaBand01 } from '@nanisoft/prism-ui/blocks/media-band-01'
47187
+
47188
+ /**
47189
+ * The band with a placeholder in the media slot.
47190
+ *
47191
+ * The slot is the point: a marketing band's picture is the consumer's asset, and
47192
+ * the demo shows the frame the Block owns rather than a photograph this package
47193
+ * would have to license. A real caller passes an image, a video poster or a
47194
+ * composed figure, and the frame holds it at the ratio the caller chose.
47195
+ */
47196
+ export default function MediaBand01Demo() {
47197
+ return (
47198
+ <MediaBand01
47199
+ headingLevel="h3"
47200
+ eyebrow="Preview"
47201
+ size="default"
47202
+ title="A photograph, a statement and one way forward"
47203
+ description="The copy is first in the document and the media is first only in the visual order the caller asks for. The frame holds a wide, square or portrait crop, and the copy never sits on the picture."
47204
+ media={
47205
+ <div className="bg-accent text-accent-foreground flex h-full w-full flex-col items-center justify-center gap-3">
47206
+ <ImageIcon className="size-8" aria-hidden />
47207
+ <span className="font-mono text-xs">media slot</span>
47208
+ </div>
47209
+ }
47210
+ caption="A placeholder in the slot. The caller supplies the image and its accessible name."
47211
+ action={{ label: 'Read the story', href: '#' }}
47212
+ />
47213
+ )
47214
+ }
47215
+ ```
47216
+
47217
+ ## Props
47218
+
47219
+ **`eyebrow`** `string` · optional · default: — — Optional label above the title. See the No-Default-Eyebrow Rule.
47220
+ **`title`** `ReactNode` · required · default: — — The band's one claim. Required: a band with no title is a picture.
47221
+ **`description`** `ReactNode` · optional · default: — — One or two sentences under the title.
47222
+ **`media`** `ReactNode` · required · default: — — The media, composed by the caller. A slot rather than a `src`, because the honest media here is not always an image: it is a photograph, a video poster, a rendered figure, or a composition of the consumer's own components. The Block owns the frame, the ratio and the surface, and the caller owns the node and its accessible name. **The node fills the frame.** The caller's image or figure should be sized to its container and should set its own `object-fit`; the Block does not style a node it did not render, which is the same rule every slot in this package follows.
47223
+ **`align`** `'media-left' | 'media-right'` · optional · default: `'media-right'` — Which side the media sits on at the wide breakpoint. Below the breakpoint the copy always comes first, because the title is the way into the picture and a reader on a phone should not have to scroll past a photograph to learn what it is for.
47224
+ **`ratio`** `MediaBand01Ratio` · optional · default: `'wide'` — The shape the media frame holds.
47225
+ **`tone`** `'default' | 'muted'` · optional · default: `'default'` — The surface the band is drawn on. `default` leaves it on the page ground, which is the quieter answer and the right one for a band that is one moment among several. `muted` puts it on the muted surface, for a band that is a chapter of its own. The muted arm states its own ink as well as its own fill, which is the `Stated Ink Rule` `Cta01` and `Bento01` both state: a surface that sets a fill and inherits its ink is correct wherever the design system happened to put it and wrong everywhere else.
47226
+ **`caption`** `ReactNode` · optional · default: — — One line under the media. Functional, not decorative: it says what a reader is looking at when the photograph is a placeholder or when the image is not the product itself. It is never a photo credit for a placeholder, and it is never a caption for a picture whose subject the title already names.
47227
+ **`action`** `MediaBand01Action` · optional · default: — — The band's one action. Omit it for a band that is a statement and not an ask.
47228
+ **`size`** `MediaBand01Size` · optional · default: `'tall'` — How tall the band is. See `MediaBand01Size`.
47229
+ **`headingLevel`** `HeadingLevel` · optional · default: `'h2'` — Heading level for the title. See `HeadingLevel`.
47230
+ **`className`** `string` · optional · default: — — Layout only, exactly as on every Block. Changing a Prism-owned visual property from here is prohibited.
47231
+
47232
+ ## Composition
47233
+
47234
+ **`exports`** `MediaBand01` — the public runtime names this Block promises
47235
+ **`source`** `packages/ui/src/blocks/media-band-01/index.tsx` — the file this Block is defined in
47236
+ **`dependencies`** `AspectRatio, CtaLink, Section` — the public Prism exports this item composes
47237
+
47238
+
46689
47239
  ---
46690
47240
 
46691
47241
  # MemberList01
@@ -56677,6 +57227,11 @@ none of the four and would rather compose its own.
56677
57227
  - Leave `sticky` on unless the page does not scroll. The bar is how a reader leaves
56678
57228
  the page they are on, and it takes that with them on exactly the long pages where
56679
57229
  it is needed. `sticky={false}` is honoured and puts the bar back in the flow.
57230
+ - Leave `scrollRail` on for pages a reader reads end to end. The rail fills with
57231
+ the reader's own progress, a browser that cannot run it draws no rail at all,
57232
+ and a reader who asked for less motion gets a still spectrum hairline. Turn
57233
+ it off on a short page, where a rail that is born nearly full misreads the
57234
+ page it is on.
56680
57235
 
56681
57236
  ### Content guidelines
56682
57237
 
@@ -56715,9 +57270,25 @@ Two things to know if you were styling against the old bar:
56715
57270
  - A rule that relied on the bar being translucent to hide a scrolling heading will
56716
57271
  no longer hide it, which is the point.
56717
57272
 
56718
- `will-change` is not on the bar and is not proposed for it. Nothing on the bar
56719
- animates, so a compositing hint applied at rest has no frame to be ready for and
56720
- nothing that would release it.
57273
+ `will-change` is not on the bar and is not proposed for it. Two things on the bar
57274
+ move, the current link's underline and the reading rail, and both are compositor
57275
+ transforms the browser promotes while they run, so a hint applied at rest has no
57276
+ frame to be ready for and nothing that would release it.
57277
+
57278
+ ### The reading rail, and the current link's underline
57279
+
57280
+ The sticky bar carries a two-pixel spectrum line on its bottom hairline, filled
57281
+ left to right by the page's own scroll. It is the travel figure at the scale of a
57282
+ page: one marker, one rail, the reader's hand providing the motion. The whole
57283
+ figure lives behind a capability check in the stylesheet, so a browser without
57284
+ scroll-driven animations draws no rail rather than an empty one, and the rail is
57285
+ `aria-hidden` because a reading position the scrollbar already shows is not
57286
+ information the bar needs to announce.
57287
+
57288
+ The current link is marked by a persistent underline in the same spectrum rather
57289
+ than by a filled pill, so the bar carries one indicator language on one edge. The
57290
+ underline is shape rather than colour, and `aria-current` still says the page to
57291
+ a reader who sees nothing at all.
56721
57292
 
56722
57293
  ### The one client boundary
56723
57294
 
@@ -56834,6 +57405,7 @@ export default function SiteNavbarDemo() {
56834
57405
  **`mobileLabels`** `SiteNavMobileLabels` · required · default: — — The two names of the mobile trigger, which is a round icon with no visible word. Required rather than defaulted, because a default would be a sentence this Block ships about a product that is not the caller's, and because a bar that renders an unlabelled round control below its own threshold has a keyboard reader reaching for something it cannot name.
56835
57406
  **`actions`** `ReactNode` · optional · default: — — A slot for controls the product owns, after the ones this bar composes. A slot rather than a prop, because an account menu and a sign-in link are application state and neither is a fact a bar can be told.
56836
57407
  **`sticky`** `boolean` · optional · default: — — Keeps the bar at the top of the viewport as the page scrolls. On by default, because the bar is how a reader leaves the page they are on, and a bar that scrolls away takes that with it on exactly the long pages a reader needs it. `false` is honoured: the bar is then part of the flow and scrolls away with the page. It was accepted and ignored until this release, so a site that passed it was given the sticky bar it had asked not to have, and `SiteHeader` has always applied it the other way round.
57408
+ **`scrollRail`** `boolean` · optional · default: `true` — Draws the reading rail: a two-pixel spectrum line on the bar's bottom hairline that fills with the reader's own progress through the page. On by default, because the rail is the one motion that costs a reader nothing: it is bound to the scroll position the reader already owns, it runs on a transform, and a browser that cannot run it draws no rail rather than an empty promise of one. A reader who asked the platform for less motion gets a still spectrum hairline, the same figure without the claim. `false` is for the pages the rail would misread: a short page whose scroll never gets going, or a composition where a second line under the bar is a line too many. The rail rides only a sticky bar, so `sticky={false}` takes it regardless.
56837
57409
  **`className`** `string` · optional · default: — — Layout only. Changing a Prism-owned visual property from here is prohibited.
56838
57410
 
56839
57411
  ## Composition