@nadicodeai/design-system 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -21,6 +21,7 @@ Handoff gate: `npm run lint:design && npm run lint && npm run build && npm run t
21
21
  | Shared design-language terms | `CONTEXT.md` |
22
22
  | Colors, tokens, typography, layout doctrine, seam ownership, component semantics | `DESIGN.md` (read it before stating any of these) |
23
23
  | CSS layers, token pipeline, dark remaps, generated outputs, their guards | `DESIGN.md` "CSS Architecture & Token Pipeline"; decision history in `../docs/adr/` |
24
+ | Motion direction and runtime | `DESIGN.md` "Motion", `src/css/motion.css`, then `../skills/nadicodeai-product-design/references/motion-craft.md` for agent procedure |
24
25
  | Package exports | `package.json` (guard: `tests/guards/build-produces-exports.test.ts`) |
25
26
  | Static or non-React consumption | `README.md` |
26
27
  | React consumption | `../@nadicodeai/ui/docs/consuming-cross-repo.md` |
@@ -40,4 +41,4 @@ Handoff gate: `npm run lint:design && npm run lint && npm run build && npm run t
40
41
  - External references are source-first: read live DOM/CSSOM rules before authoring; screenshots verify, they never author. Map every imported behavior to `DESIGN.md` or an explicit user approval, ask when the contract leaves a decision open, and never import reference mood, polarity, decoration, or animation uninvited. Stop and re-read source before a second visual patch to the same component.
41
42
  - Name everything as NadicodeAI-owned primitives; source brands (Vercel, Attio) appear only in reference notes, never in names, comments, or contracts.
42
43
  - Any change to package-consumed output ends with an explicit release decision, a version bump or a `[no-publish]` commit marker (enforced by the pre-push release gate; procedure: `../docs/internal/npm-publishing.md`).
43
- - The deleted `design-canvas/` prototypes live only in git history. `src/css/motion.css` preserves current runtime transitions and animations, while `src/js/chat-autoplay.js` is the single allowed runtime JS enhancer; never reconstruct the prototypes or add a second runtime JS surface.
44
+ - The deleted `design-canvas/` prototypes live only in git history. `src/css/motion.css` owns shared runtime motion primitives, while `src/js/chat-autoplay.js` is the single allowed runtime JS enhancer; never reconstruct the prototypes or add a second runtime JS surface.
package/DESIGN.md CHANGED
@@ -566,6 +566,10 @@ Corners are restrained and assigned by material role.
566
566
 
567
567
  Public page-grammar cells are not cards and remain square because their parent frame supplies the visual system. Product cards are resting content surfaces and use the 6 px role above; they do not gain thicker borders, nested frames, or a shadow merely because they contain grouped settings.
568
568
 
569
+ ## Motion
570
+
571
+ Motion clarifies state, feedback, hierarchy, or continuity; it does not decorate routine work. Repeated interactions stay fast and quiet, while rare explanatory moments may be more expressive. Motion preserves meaning when movement is reduced.
572
+
569
573
  ## Components
570
574
 
571
575
  This section is the semantic catalog for framework-agnostic components. Exact reusable values stay in the token maps above; CSS owns component composition. Page grammar and composition semantics live in `## Layout`, while React components and reusable sections live in `@nadicodeai/ui`.
@@ -398,8 +398,8 @@
398
398
  if (thread.__ncAutoplayPlayer) return thread.__ncAutoplayPlayer;
399
399
  var player = new ChatThreadPlayer(thread);
400
400
  // Read the stagger token off the live thread (parity with motion.css);
401
- // fallback equals the motion.css default (160ms) if the bundle is absent.
402
- player.staggerMs = durationToken(thread, "--nc-duration-stagger", 160);
401
+ // fallback equals the motion.css default (60ms) if the bundle is absent.
402
+ player.staggerMs = durationToken(thread, "--nc-duration-stagger", 60);
403
403
  thread.__ncAutoplayPlayer = player;
404
404
  players.push(player);
405
405
  // Inject the pause/resume button unless reduced-motion is on (that path
@@ -728,18 +728,25 @@
728
728
  /* src/css/motion.css */
729
729
  @layer motion {
730
730
  :root {
731
- --nc-duration-stagger: 160ms;
732
- --nc-duration-msg-in: 360ms;
733
- --nc-duration-transition: 360ms;
731
+ --nc-duration-stagger: 60ms;
732
+ --nc-duration-msg-in: 240ms;
733
+ --nc-duration-transition: 240ms;
734
734
  --nc-duration-typing: 1s;
735
735
  --nc-duration-pulse: 1.6s;
736
+ --nc-duration-shimmer: 2s;
736
737
  --nc-duration-confirm: 180ms;
737
738
  --nc-duration-open: 220ms;
738
739
  --nc-duration-close: 140ms;
740
+ --nc-duration-drawer: 450ms;
741
+ --nc-duration-drawer-swipe: 400ms;
739
742
  --nc-ease-emphasized: cubic-bezier(0.3, 0.7, 0.2, 1);
740
- --nc-ease-bounce: ease-in-out;
741
- --nc-ease-out: ease-out;
742
743
  --nc-ease-out-strong: cubic-bezier(0.23, 1, 0.32, 1);
744
+ --nc-ease-in-out-strong: cubic-bezier(0.77, 0, 0.175, 1);
745
+ --nc-ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
746
+ --nc-ease-bounce: var(--nc-ease-in-out-strong);
747
+ --nc-ease-out: var(--nc-ease-out-strong);
748
+ --default-transition-duration: var(--nc-duration-confirm);
749
+ --default-transition-timing-function: var(--nc-ease-out-strong);
743
750
  }
744
751
  @keyframes nc-msg-in {
745
752
  from {
@@ -763,13 +770,20 @@
763
770
  }
764
771
  @keyframes nc-pulse {
765
772
  0% {
766
- box-shadow: 0 0 0 0 currentColor;
773
+ opacity: 0.45;
774
+ transform: scale(0.7);
767
775
  }
768
- 70% {
769
- box-shadow: 0 0 0 6px transparent;
776
+ 70%, 100% {
777
+ opacity: 0;
778
+ transform: scale(1.9);
770
779
  }
771
- 100% {
772
- box-shadow: 0 0 0 0 transparent;
780
+ }
781
+ @keyframes nc-shimmer {
782
+ from {
783
+ background-position: 100% center;
784
+ }
785
+ to {
786
+ background-position: 0% center;
773
787
  }
774
788
  }
775
789
  .nc-anim-msg-in {
@@ -781,9 +795,59 @@
781
795
  animation-delay: var(--nc-anim-delay, 0ms);
782
796
  }
783
797
  .nc-anim-pulse {
798
+ position: relative;
799
+ }
800
+ .nc-anim-pulse::after {
801
+ content: "";
802
+ position: absolute;
803
+ inset: -2px;
804
+ border: var(--nc-guide) solid currentColor;
805
+ border-radius: inherit;
806
+ pointer-events: none;
784
807
  animation: nc-pulse var(--nc-duration-pulse) var(--nc-ease-out) infinite;
785
808
  animation-delay: var(--nc-anim-delay, 0ms);
786
809
  }
810
+ .nc-anim-shimmer {
811
+ --nc-shimmer-spread: 1em;
812
+ position: relative;
813
+ }
814
+ .nc-anim-shimmer::after {
815
+ content: attr(data-nc-shimmer);
816
+ content: attr(data-nc-shimmer) / "";
817
+ position: absolute;
818
+ inset: 0;
819
+ color: transparent;
820
+ background-image:
821
+ linear-gradient(
822
+ 90deg,
823
+ transparent calc(50% - var(--nc-shimmer-spread)),
824
+ var(--background) 50%,
825
+ transparent calc(50% + var(--nc-shimmer-spread)));
826
+ background-size: 250% 100%;
827
+ background-repeat: no-repeat;
828
+ background-clip: text;
829
+ pointer-events: none;
830
+ animation: nc-shimmer var(--nc-duration-shimmer) linear infinite;
831
+ }
832
+ .nc-transition-paint {
833
+ transition-property:
834
+ background-color,
835
+ border-color,
836
+ color,
837
+ opacity;
838
+ transition-duration: var(--nc-duration-confirm);
839
+ transition-timing-function: var(--nc-ease-out-strong);
840
+ }
841
+ .nc-transition-opacity {
842
+ transition-property: opacity;
843
+ transition-duration: var(--nc-duration-confirm);
844
+ transition-timing-function: var(--nc-ease-out-strong);
845
+ }
846
+ .nc-transition-transform {
847
+ transition-property: transform;
848
+ transition-duration: var(--nc-duration-confirm);
849
+ transition-timing-function: var(--nc-ease-out-strong);
850
+ }
787
851
  @media (prefers-reduced-motion: no-preference) {
788
852
  [data-nc-settle=armed] {
789
853
  opacity: 0;
@@ -794,12 +858,21 @@
794
858
  }
795
859
  @media (prefers-reduced-motion: reduce) {
796
860
  .nc-anim-msg-in,
797
- .nc-anim-typing,
798
- .nc-anim-pulse {
861
+ .nc-anim-typing {
799
862
  animation: none;
800
863
  opacity: 1;
801
864
  transform: none;
802
- box-shadow: none;
865
+ }
866
+ .nc-anim-shimmer::after,
867
+ .nc-anim-pulse::after {
868
+ animation: none;
869
+ opacity: 0;
870
+ transform: none;
871
+ }
872
+ .nc-transition-paint,
873
+ .nc-transition-opacity,
874
+ .nc-transition-transform {
875
+ transition: none;
803
876
  }
804
877
  }
805
878
  }
@@ -1524,10 +1597,10 @@
1524
1597
  text-underline-offset: 2px;
1525
1598
  text-decoration-thickness: var(--nc-guide);
1526
1599
  transition:
1527
- background-color var(--nc-duration-stagger) var(--nc-ease-out-strong),
1528
- border-color var(--nc-duration-stagger) var(--nc-ease-out-strong),
1529
- color var(--nc-duration-stagger) var(--nc-ease-out-strong),
1530
- opacity var(--nc-duration-stagger) var(--nc-ease-out-strong);
1600
+ background-color var(--nc-duration-confirm) var(--nc-ease-out-strong),
1601
+ border-color var(--nc-duration-confirm) var(--nc-ease-out-strong),
1602
+ color var(--nc-duration-confirm) var(--nc-ease-out-strong),
1603
+ opacity var(--nc-duration-confirm) var(--nc-ease-out-strong);
1531
1604
  }
1532
1605
  @media (hover: hover) and (pointer: fine) {
1533
1606
  .nc-link-inline:hover {
@@ -1751,10 +1824,10 @@
1751
1824
  letter-spacing: var(--nc-type-caption-mono-letter-spacing);
1752
1825
  cursor: pointer;
1753
1826
  transition:
1754
- background-color var(--nc-duration-stagger) var(--nc-ease-out-strong),
1755
- border-color var(--nc-duration-stagger) var(--nc-ease-out-strong),
1756
- color var(--nc-duration-stagger) var(--nc-ease-out-strong),
1757
- opacity var(--nc-duration-stagger) var(--nc-ease-out-strong);
1827
+ background-color var(--nc-duration-confirm) var(--nc-ease-out-strong),
1828
+ border-color var(--nc-duration-confirm) var(--nc-ease-out-strong),
1829
+ color var(--nc-duration-confirm) var(--nc-ease-out-strong),
1830
+ opacity var(--nc-duration-confirm) var(--nc-ease-out-strong);
1758
1831
  }
1759
1832
  @media (hover: hover) and (pointer: fine) {
1760
1833
  .nc-chat-pause:hover {
@@ -1767,13 +1840,7 @@
1767
1840
  border-color: var(--nc-body);
1768
1841
  }
1769
1842
  .nc-chat-pause:active {
1770
- transform: scale(0.97);
1771
- transition: transform var(--nc-duration-stagger) var(--nc-ease-out-strong);
1772
- }
1773
- @media (prefers-reduced-motion: reduce) {
1774
- .nc-chat-pause:active {
1775
- transform: none;
1776
- }
1843
+ opacity: 0.9;
1777
1844
  }
1778
1845
  .nc-chat-thread-footer {
1779
1846
  display: flex;
@@ -2368,10 +2435,14 @@
2368
2435
  .nc-usage-meter-fill {
2369
2436
  position: absolute;
2370
2437
  inset: 0;
2371
- right: auto;
2372
- width: var(--nc-usage, 0%);
2438
+ width: 100%;
2439
+ scale: var(--nc-usage, 0%) 1;
2440
+ transform-origin: left center;
2373
2441
  background: var(--nc-ink);
2374
- transition: width var(--nc-duration-transition) var(--nc-ease-emphasized);
2442
+ transition: scale var(--nc-duration-transition) var(--nc-ease-emphasized);
2443
+ }
2444
+ .nc-usage-meter-fill:dir(rtl) {
2445
+ transform-origin: right center;
2375
2446
  }
2376
2447
  @media (prefers-reduced-motion: reduce) {
2377
2448
  .nc-usage-meter-fill {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nadicodeai/design-system",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"