@dotcraft/avatar 0.7.1 → 0.7.3

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.
Files changed (122) hide show
  1. package/README.md +18 -20
  2. package/dist/AnimatedDecoration.d.ts +2 -2
  3. package/dist/AnimatedDecoration.d.ts.map +1 -1
  4. package/dist/AnimatedDecoration.js +2 -2
  5. package/dist/AnimatedDecoration.js.map +1 -1
  6. package/dist/AppearanceRig.d.ts +7 -1
  7. package/dist/AppearanceRig.d.ts.map +1 -1
  8. package/dist/AppearanceRig.js +2 -2
  9. package/dist/AppearanceRig.js.map +1 -1
  10. package/dist/Avatar.d.ts +2 -0
  11. package/dist/Avatar.d.ts.map +1 -1
  12. package/dist/Avatar.js +19 -7
  13. package/dist/Avatar.js.map +1 -1
  14. package/dist/BackDecorations.d.ts +9 -0
  15. package/dist/BackDecorations.d.ts.map +1 -0
  16. package/dist/BackDecorations.js +73 -0
  17. package/dist/BackDecorations.js.map +1 -0
  18. package/dist/DecorationShapes.d.ts +9 -2
  19. package/dist/DecorationShapes.d.ts.map +1 -1
  20. package/dist/DecorationShapes.js +8 -2
  21. package/dist/DecorationShapes.js.map +1 -1
  22. package/dist/Decorations.d.ts +6 -9
  23. package/dist/Decorations.d.ts.map +1 -1
  24. package/dist/Decorations.js +33 -16
  25. package/dist/Decorations.js.map +1 -1
  26. package/dist/FaceDecorations.d.ts +14 -0
  27. package/dist/FaceDecorations.d.ts.map +1 -0
  28. package/dist/FaceDecorations.js +69 -0
  29. package/dist/FaceDecorations.js.map +1 -0
  30. package/dist/HandDecorations.d.ts +5 -0
  31. package/dist/HandDecorations.d.ts.map +1 -0
  32. package/dist/HandDecorations.js +8 -0
  33. package/dist/HandDecorations.js.map +1 -0
  34. package/dist/HatDecorations.d.ts +2 -2
  35. package/dist/HatDecorations.d.ts.map +1 -1
  36. package/dist/HatDecorations.js +4 -0
  37. package/dist/HatDecorations.js.map +1 -1
  38. package/dist/MascotRig.d.ts +13 -1
  39. package/dist/MascotRig.d.ts.map +1 -1
  40. package/dist/MascotRig.js +6 -26
  41. package/dist/MascotRig.js.map +1 -1
  42. package/dist/ObjectDecorations.d.ts +2 -2
  43. package/dist/ObjectDecorations.d.ts.map +1 -1
  44. package/dist/ObjectDecorations.js +18 -2
  45. package/dist/ObjectDecorations.js.map +1 -1
  46. package/dist/RigMaterial.d.ts +18 -0
  47. package/dist/RigMaterial.d.ts.map +1 -0
  48. package/dist/RigMaterial.js +9 -0
  49. package/dist/RigMaterial.js.map +1 -0
  50. package/dist/SkinDecorations.d.ts +10 -0
  51. package/dist/SkinDecorations.d.ts.map +1 -0
  52. package/dist/SkinDecorations.js +28 -0
  53. package/dist/SkinDecorations.js.map +1 -0
  54. package/dist/accessories.css +1 -1
  55. package/dist/appearanceModel.d.ts +18 -14
  56. package/dist/appearanceModel.d.ts.map +1 -1
  57. package/dist/appearanceModel.js +62 -30
  58. package/dist/appearanceModel.js.map +1 -1
  59. package/dist/composer/styles/energy.css +34 -0
  60. package/dist/decorationCatalog.d.ts +17 -7
  61. package/dist/decorationCatalog.d.ts.map +1 -1
  62. package/dist/decorationCatalog.js +95 -36
  63. package/dist/decorationCatalog.js.map +1 -1
  64. package/dist/decorationMotion.d.ts +2 -2
  65. package/dist/decorationMotion.d.ts.map +1 -1
  66. package/dist/decorationMotion.js +4 -1
  67. package/dist/decorationMotion.js.map +1 -1
  68. package/dist/effects.css +86 -0
  69. package/dist/index.d.ts +2 -0
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +2 -0
  72. package/dist/index.js.map +1 -1
  73. package/dist/items.d.ts +460 -0
  74. package/dist/items.d.ts.map +1 -0
  75. package/dist/items.js +52 -0
  76. package/dist/items.js.map +1 -0
  77. package/dist/paintMaterials.d.ts +31 -0
  78. package/dist/paintMaterials.d.ts.map +1 -0
  79. package/dist/paintMaterials.js +10 -0
  80. package/dist/paintMaterials.js.map +1 -0
  81. package/dist/palette.d.ts +2 -0
  82. package/dist/palette.d.ts.map +1 -1
  83. package/dist/palette.js +4 -4
  84. package/dist/palette.js.map +1 -1
  85. package/dist/react.d.ts +2 -2
  86. package/dist/react.d.ts.map +1 -1
  87. package/dist/react.js +2 -2
  88. package/dist/react.js.map +1 -1
  89. package/dist/rig.css +6 -21
  90. package/dist/styles.css +1 -0
  91. package/package.json +1 -1
  92. package/src/AnimatedDecoration.tsx +4 -4
  93. package/src/AppearanceRig.tsx +5 -4
  94. package/src/Avatar.tsx +25 -11
  95. package/src/BackDecorations.tsx +134 -0
  96. package/src/DecorationShapes.tsx +11 -3
  97. package/src/Decorations.tsx +47 -22
  98. package/src/FaceDecorations.tsx +145 -0
  99. package/src/HandDecorations.tsx +113 -0
  100. package/src/HatDecorations.tsx +29 -2
  101. package/src/MascotRig.tsx +27 -44
  102. package/src/ObjectDecorations.tsx +69 -3
  103. package/src/RigMaterial.tsx +23 -0
  104. package/src/SkinDecorations.tsx +56 -0
  105. package/src/accessories.css +1 -1
  106. package/src/appearanceModel.ts +57 -37
  107. package/src/composer/styles/energy.css +34 -0
  108. package/src/decorationCatalog.ts +103 -38
  109. package/src/decorationMotion.ts +6 -3
  110. package/src/effects.css +86 -0
  111. package/src/index.ts +2 -0
  112. package/src/items.ts +86 -0
  113. package/src/paintMaterials.ts +18 -0
  114. package/src/palette.ts +7 -3
  115. package/src/react.ts +2 -2
  116. package/src/rig.css +6 -21
  117. package/src/styles.css +1 -0
  118. package/dist/HeldDecorations.d.ts +0 -5
  119. package/dist/HeldDecorations.d.ts.map +0 -1
  120. package/dist/HeldDecorations.js +0 -5
  121. package/dist/HeldDecorations.js.map +0 -1
  122. package/src/HeldDecorations.tsx +0 -48
@@ -1 +1 @@
1
- {"version":3,"file":"palette.js","sourceRoot":"","sources":["../src/palette.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"palette.js","sourceRoot":"","sources":["../src/palette.ts"],"names":[],"mappings":"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"}
package/dist/react.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { Avatar, AppearanceAvatar, type AvatarProps, type AppearanceAvatarProps } from './Avatar.js';
2
- export { DecorationSwatch, PrimaryDecoration, SecondaryDecoration } from './Decorations.js';
1
+ export { Avatar, AppearanceAvatar, sizeTier, type AvatarProps, type AppearanceAvatarProps, type SizeTier } from './Avatar.js';
2
+ export { DecorationSwatch, SlotDecoration, HeadDecoration } from './Decorations.js';
3
3
  export { ComposerMascot } from './composer/ComposerMascot.js';
4
4
  export type { ComposerMascotProps, ComposerMascotContext, MascotExpression, MascotLight } from './composer/types.js';
5
5
  export { ComposerMascotShadow } from './composer/ComposerMascotShadow.js';
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACpG,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAE3F,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACpH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAA;AACnF,OAAO,EAAE,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,KAAK,sBAAsB,EAAE,KAAK,uBAAuB,EAAE,MAAM,mCAAmC,CAAA;AACnK,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AAC/D,YAAY,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,KAAK,WAAW,EAAE,KAAK,qBAAqB,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC7H,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEnF,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACpH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAA;AACnF,OAAO,EAAE,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,KAAK,sBAAsB,EAAE,KAAK,uBAAuB,EAAE,MAAM,mCAAmC,CAAA;AACnK,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AAC/D,YAAY,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA"}
package/dist/react.js CHANGED
@@ -1,5 +1,5 @@
1
- export { Avatar, AppearanceAvatar } from './Avatar.js';
2
- export { DecorationSwatch, PrimaryDecoration, SecondaryDecoration } from './Decorations.js';
1
+ export { Avatar, AppearanceAvatar, sizeTier } from './Avatar.js';
2
+ export { DecorationSwatch, SlotDecoration, HeadDecoration } from './Decorations.js';
3
3
  export { ComposerMascot } from './composer/ComposerMascot.js';
4
4
  export { ComposerMascotShadow } from './composer/ComposerMascotShadow.js';
5
5
  export { useComposerAvatarBehavior } from './composer/useComposerAvatarBehavior.js';
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAgD,MAAM,aAAa,CAAA;AACpG,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAE3F,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAA;AACnF,OAAO,EAAE,mBAAmB,EAA8F,MAAM,mCAAmC,CAAA;AACnK,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA"}
1
+ {"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAA+D,MAAM,aAAa,CAAA;AAC7H,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEnF,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAA;AACnF,OAAO,EAAE,mBAAmB,EAA8F,MAAM,mCAAmC,CAAA;AACnK,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA"}
package/dist/rig.css CHANGED
@@ -1,6 +1,5 @@
1
- /* The robot's arm/antenna/face pieces carry stable dca-part-* classes (see
2
- MascotRig.tsx). Each arm's white and blue pieces are separate elements moving in
3
- lockstep, so transform-box: view-box resolves one shared origin for both. */
1
+ /* Arm outlines, material clips and held props move in lockstep.
2
+ transform-box: view-box resolves the same pivot for each layer. */
4
3
  .dca-part-eyes,
5
4
  .dca-part-glow,
6
5
  .dca-part-light,
@@ -40,6 +39,7 @@
40
39
  a prop is never left floating. Every rule that ENTERS a posed arm state overrides
41
40
  the delay back to 0 so raises stay immediate. */
42
41
  .dca-part-arm-l-w,
42
+ .dca-part-arm-l-b,
43
43
  .dca-part-arm-l {
44
44
  transform-box: view-box;
45
45
  transform-origin: 233px 514px;
@@ -103,9 +103,7 @@
103
103
  /* Props are always-mounted `dca-part-prop-*` groups inside MascotRobot at opacity 0,
104
104
  revealed by these composer root classes. */
105
105
 
106
- /* Mini terminal: the 1200ms transition delay keeps quick turns from flashing it. The
107
- arms only tuck inward by pure translate — a rotation would trigger the solid-colour
108
- swap and break the gradient's continuity with the torso. */
106
+ /* The 1200ms delay keeps quick turns from flashing the mini terminal. */
109
107
  .dca-part-prop-laptop {
110
108
  opacity: 0;
111
109
  transition: opacity 200ms ease;
@@ -117,6 +115,7 @@
117
115
  }
118
116
 
119
117
  .dca-action-prop-laptop .dca-part-arm-l-w,
118
+ .dca-action-prop-laptop .dca-part-arm-l-b,
120
119
  .dca-action-prop-laptop .dca-part-arm-l {
121
120
  transform: translate(18px, 0);
122
121
  transition: transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1) 1200ms;
@@ -166,10 +165,6 @@
166
165
  transition-delay: 0ms;
167
166
  }
168
167
 
169
- .dca-action-hold-sign .dca-part-arm-r-b {
170
- fill: var(--dca-part-raised-arm-right, #7a96fb);
171
- }
172
-
173
168
  .dca-part-prop-sign {
174
169
  opacity: 0;
175
170
  transition: opacity 140ms ease;
@@ -242,6 +237,7 @@
242
237
  /* The cheer reuses the wave's slide-then-rotate hinge grammar, so the outline wraps
243
238
  the band and the colour stays seam-continuous. */
244
239
  .dca-action-celebrate .dca-part-arm-l-w,
240
+ .dca-action-celebrate .dca-part-arm-l-b,
245
241
  .dca-action-celebrate .dca-part-arm-l {
246
242
  transform: translate(48px, 88px) rotate(135deg) scaleY(0.82);
247
243
  transition-delay: 0ms;
@@ -252,14 +248,3 @@
252
248
  transform: translate(-48px, 88px) rotate(-135deg) scaleY(0.82);
253
249
  transition-delay: 0ms;
254
250
  }
255
-
256
- /* Raised arms swap the body gradient for a solid hinge colour, so a rotated arm has
257
- no gradient to diverge from the torso's field. White halo capsules stay white. */
258
- .dca-action-wave .dca-part-arm-r-b,
259
- .dca-action-celebrate .dca-part-arm-r-b {
260
- fill: var(--dca-part-raised-arm-right, #7a96fb);
261
- }
262
-
263
- .dca-action-celebrate .dca-part-arm-l-b {
264
- fill: var(--dca-part-raised-arm-left, #3161f7);
265
- }
package/dist/styles.css CHANGED
@@ -1,6 +1,7 @@
1
1
  @import './rig.css';
2
2
  @import './avatar.css';
3
3
  @import './accessories.css';
4
+ @import './effects.css';
4
5
 
5
6
  @import "./composer/styles/foundation.css";
6
7
  @import "./composer/styles/overdrive.css";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotcraft/avatar",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "Name-derived DotCraft avatars and React SVG animation components",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,11 +1,11 @@
1
1
  import { useEffect, useRef } from 'react'
2
- import type { PrimaryId } from './appearanceModel.js'
2
+ import type { HeadId } from './items.js'
3
3
  import type { AvatarPose } from './characters.js'
4
- import { PrimaryDecoration } from './Decorations.js'
4
+ import { HeadDecoration } from './Decorations.js'
5
5
  import { advanceDecoration, decorationMotionProfiles, frameTransform, requestDecorationEvent, restFrame, type DecorationClock, type DecorationFrame } from './decorationMotion.js'
6
6
 
7
7
  export function AnimatedDecoration({ id, pose, sequence, enabled, paused }: {
8
- id: Exclude<PrimaryId, 'none'>; pose: AvatarPose; sequence: number; enabled: boolean; paused: boolean
8
+ id: HeadId; pose: AvatarPose; sequence: number; enabled: boolean; paused: boolean
9
9
  }) {
10
10
  const art = useRef<SVGGElement>(null)
11
11
  const shadow = useRef<SVGEllipseElement>(null)
@@ -38,6 +38,6 @@ export function AnimatedDecoration({ id, pose, sequence, enabled, paused }: {
38
38
  }, [id, pose, sequence, enabled, paused])
39
39
  return <g data-decoration-motion={profile.kind}>
40
40
  {profile.shadow > 0 && <ellipse ref={shadow} cx={profile.x} cy="404" rx={profile.shadow} ry="7" fill="#243344" opacity=".12" />}
41
- <g ref={art} transform={frameTransform(profile, restFrame)}><PrimaryDecoration id={id} /></g>
41
+ <g ref={art} transform={frameTransform(profile, restFrame)}><HeadDecoration id={id} /></g>
42
42
  </g>
43
43
  }
@@ -1,14 +1,15 @@
1
1
  import type { ReactNode } from 'react'
2
2
  import type { AvatarPose, AvatarExpression } from './characters.js'
3
3
  import type { Appearance } from './appearanceModel.js'
4
- import { MascotRig, type MascotExpression } from './MascotRig.js'
5
- export function AppearanceRig({ appearance, pose, expression: override, top, accessory, held }: {
6
- appearance: Appearance; pose: AvatarPose; expression?: AvatarExpression; top?: ReactNode; accessory?: ReactNode; held?: ReactNode
4
+ import { MascotRig, type BodyPaint, type Faceplate, type MascotExpression } from './MascotRig.js'
5
+ export function AppearanceRig({ appearance, pose, expression: override, top, accessory, faceplate, held, back, front, surface, paint }: {
6
+ appearance: Appearance; pose: AvatarPose; expression?: AvatarExpression
7
+ top?: ReactNode; accessory?: ReactNode; faceplate?: Faceplate; held?: ReactNode; back?: ReactNode; front?: ReactNode; surface?: ReactNode; paint?: BodyPaint
7
8
  }) {
8
9
  const derived: MascotExpression = pose === 'sleep' ? 'sleep' : ['done', 'greeting', 'acknowledge'].includes(pose) ? 'happy'
9
10
  : ['working', 'waiting', 'blocked'].includes(pose) ? 'operator' : 'neutral'
10
11
  const expression = override === 'base' ? 'neutral' : override ?? derived
11
- return <MascotRig size={1024} expression={expression} top={top} accessory={accessory} held={held}
12
+ return <MascotRig size={1024} expression={expression} top={top} accessory={accessory} faceplate={faceplate} held={held} back={back} front={front} surface={surface} paint={paint}
12
13
  baseFace={appearance.baseFace}
13
14
  light={pose === 'blocked' ? 'error' : pose === 'done' ? 'success' : 'default'}
14
15
  avatar={appearance.palette === -1 ? undefined : { palette: appearance.palette }} />
package/src/Avatar.tsx CHANGED
@@ -1,14 +1,18 @@
1
1
  import { useEffect, useRef, useState, type CSSProperties } from 'react'
2
2
  import { AppearanceRig } from './AppearanceRig.js'
3
3
  import type { AvatarPose, MotionMode, AvatarExpression, AvatarGesture } from './characters.js'
4
- import { deriveAppearance, isHeld, type Appearance } from './appearanceModel.js'
5
-
6
- import { SecondaryDecoration } from './Decorations.js'
4
+ import { deriveAppearance, type Appearance } from './appearanceModel.js'
7
5
  import { AnimatedDecoration } from './AnimatedDecoration.js'
6
+ import { FaceDecoration, faceplateOf } from './FaceDecorations.js'
7
+ import { HandDecoration } from './HandDecorations.js'
8
+ import { BackDecoration, BackFrontDecoration, hasFrontPart } from './BackDecorations.js'
9
+ import { SkinOverlay, SkinPaintSurface, skinPaint } from './SkinDecorations.js'
8
10
  import { useMotionEnvironment, useOnscreen, useTransitionPause } from './environment.js'
9
11
  import { useGesture } from './useGesture.js'
10
12
  import { useEventReplay } from './useEventReplay.js'
11
13
 
14
+ export type SizeTier = 'compact' | 'standard' | 'full'
15
+ export function sizeTier(size: number): SizeTier { return size <= 20 ? 'compact' : size < 44 ? 'standard' : 'full' }
12
16
 
13
17
  export interface AppearanceAvatarProps {
14
18
  appearance: Appearance
@@ -26,17 +30,18 @@ export interface AppearanceAvatarProps {
26
30
  }
27
31
  export function AppearanceAvatar({ appearance, state = 'idle', size = 44, motion = 'off', paused = false, label, eventSequence = 0, className, expression, gesture, gestureSequence = 0, onGestureComplete }: AppearanceAvatarProps) {
28
32
  const ref = useRef<HTMLSpanElement>(null)
29
- const visible = useOnscreen(ref, motion !== 'off' && size > 20)
30
- const environment = useMotionEnvironment(motion, size > 20)
33
+ const tier = sizeTier(size)
34
+ const compact = tier === 'compact'
35
+ const visible = useOnscreen(ref, motion !== 'off' && !compact)
36
+ const environment = useMotionEnvironment(motion, !compact)
31
37
  useTransitionPause(ref, paused || !visible)
32
38
  const [displayed, setDisplayed] = useState(state)
33
39
  const [displayedSequence, setDisplayedSequence] = useState(eventSequence)
34
40
  const [exiting, setExiting] = useState(false)
35
41
  const identity = JSON.stringify(appearance)
36
42
  const previousIdentity = useRef(identity)
37
- const compact = size <= 20
38
43
  const animated = environment && !compact
39
- const held = !compact && isHeld(appearance.secondary)
44
+ const held = !compact && appearance.hand !== 'none'
40
45
  const [shownExpression, setShownExpression] = useState(expression)
41
46
  useEffect(() => { if (!animated || (!paused && visible)) setShownExpression(expression) }, [expression, animated, paused, visible])
42
47
  useGesture(ref, gesture, gestureSequence, animated, paused || !visible, onGestureComplete)
@@ -58,6 +63,7 @@ export function AppearanceAvatar({ appearance, state = 'idle', size = 44, motion
58
63
  }, [state, displayed, animated, paused, visible, identity, eventSequence, displayedSequence])
59
64
 
60
65
  const pose = animated ? displayed : state
66
+ const effects = compact ? 'off' : tier === 'full' && animated ? 'live' : 'static'
61
67
  const classes = [
62
68
  'dca-rig',
63
69
  !compact && pose === 'waiting' ? 'dca-action-hold-sign' : '',
@@ -65,17 +71,25 @@ export function AppearanceAvatar({ appearance, state = 'idle', size = 44, motion
65
71
  !compact && pose === 'done' ? 'dca-action-celebrate' : '',
66
72
  !compact && pose === 'greeting' && !exiting ? 'dca-action-wave' : '',
67
73
  ].filter(Boolean).join(' ')
74
+ const paint = appearance.skin === 'none' ? undefined : skinPaint(appearance.skin)
75
+ const overlay = compact || appearance.skin === 'none' ? undefined
76
+ : paint ? <SkinPaintSurface id={appearance.skin} /> : <SkinOverlay id={appearance.skin} />
77
+ const faceplate = faceplateOf(appearance.face)
78
+ const back = appearance.back !== 'none' ? <g className="dca-part-back" data-back={appearance.back}><BackDecoration id={appearance.back} /></g> : undefined
79
+ const front = appearance.back !== 'none' && hasFrontPart(appearance.back) ? <g className="dca-part-front"><BackFrontDecoration id={appearance.back} /></g> : undefined
68
80
  return <span ref={ref} className={`dca-robot${className ? ` ${className}` : ''}`} style={{ width: size, height: size, '--dca-loop': '2.6s' } as CSSProperties}
69
81
  data-pose={pose} data-mode={motion} data-motion={animated ? 'on' : 'off'} data-paused={paused || !visible} data-exiting={exiting} data-compact={compact}
70
- data-primary={appearance.primary} data-secondary={appearance.secondary} data-base-face={appearance.baseFace}
82
+ data-size-tier={tier} data-effects={effects}
83
+ data-head={appearance.head} data-face={appearance.face} data-hand={appearance.hand} data-back={appearance.back} data-skin={appearance.skin} data-base-face={appearance.baseFace}
71
84
  data-gesture={animated ? gesture : undefined} data-held-state={held ? (pose === 'working' || pose === 'waiting' ? 'stowed' : 'holding') : undefined}>
72
85
  <svg className="dca-canvas" width={size} height={size} viewBox="0 0 1024 1024" fill="none" role={label ? 'img' : undefined} aria-hidden={label ? undefined : true}
73
86
  aria-label={label}>
74
87
  <g className="dca-body-motion"><g className={classes}>
75
88
  <AppearanceRig appearance={appearance} pose={pose} expression={animated ? shownExpression : expression}
76
- top={appearance.primary === 'none' ? undefined : <AnimatedDecoration id={appearance.primary} pose={state} sequence={eventSequence} enabled={animated} paused={paused || !visible} />}
77
- held={!compact && held ? <g data-accessory={appearance.secondary} className="dca-part-held"><SecondaryDecoration id={appearance.secondary} /></g> : undefined}
78
- accessory={!compact && !held ? <g data-accessory={appearance.secondary}><SecondaryDecoration id={appearance.secondary} /></g> : undefined} />
89
+ top={appearance.head === 'none' ? undefined : <AnimatedDecoration id={appearance.head} pose={state} sequence={eventSequence} enabled={animated} paused={paused || !visible} />}
90
+ held={held && appearance.hand !== 'none' ? <g data-accessory={appearance.hand} className="dca-part-held"><HandDecoration id={appearance.hand} /></g> : undefined}
91
+ accessory={!compact && appearance.face !== 'none' && !faceplate ? <g data-accessory={appearance.face}><FaceDecoration id={appearance.face} /></g> : undefined}
92
+ faceplate={faceplate} back={back} front={front} surface={overlay} paint={paint} />
79
93
  </g></g>
80
94
  </svg>
81
95
  </span>
@@ -0,0 +1,134 @@
1
+ import type { ReactNode } from 'react'
2
+ import type { BackId } from './items.js'
3
+ import { Glow } from './DecorationShapes.js'
4
+
5
+ function Wing({ outer, inner, fill, lining, outline = '#fff', flap = 'dca-fx-flap', children }: { outer: string; inner?: string; fill: string; lining?: string; outline?: string; flap?: string; children?: ReactNode }) {
6
+ return <g className={flap} style={{ transformOrigin: '272px 560px' }}>
7
+ <path d={outer} fill={fill} stroke={outline} strokeWidth="18" strokeLinejoin="round" paintOrder="stroke fill" />
8
+ {inner && <path d={inner} fill={lining} />}
9
+ {children}
10
+ </g>
11
+ }
12
+ function Wings(props: Parameters<typeof Wing>[0]) {
13
+ return <><Wing {...props} /><g transform="matrix(-1 0 0 1 1024 0)"><Wing {...props} /></g></>
14
+ }
15
+ const batWing = {
16
+ outer: 'M272 520C200 470 120 400 60 340c30 80 10 130-20 160 70 20 90 60 60 100 70 10 100 50 90 100h82Z',
17
+ inner: 'M262 540c-60-40-120-96-166-146 20 60 6 100-16 128 56 16 76 50 56 84 56 10 82 44 74 88h52Z',
18
+ }
19
+ const butterflyWing = {
20
+ outer: 'M272 540C190 380 60 340 20 420c-14 56 50 96 110 120-80 12-120 70-80 130 56 56 160 26 232-40Z',
21
+ inner: 'M262 560c-70-120-170-150-196-90-8 40 44 70 96 90-60 14-90 60-60 100 46 40 130 14 180-44Z',
22
+ }
23
+ const angelWing = {
24
+ outer: 'M272 520C180 440 80 420 40 470c20 50 70 70 120 80-60 20-90 60-70 100 50 20 110 0 160-40-30 40-30 80 0 100 40-10 80-60 100-120Z',
25
+ inner: 'M262 540C190 480 110 462 78 492c16 36 56 52 96 60-46 16-70 46-56 76 40 14 90-4 130-36-20 30-16 58 8 70 30-10 58-46 72-92Z',
26
+ }
27
+ const dragonWing = {
28
+ outer: 'M272 500C160 380 60 300 20 340c0 60 60 100 100 130-60 30-100 90-80 150 60 10 130-20 190-70-40 60-40 120 0 150 60-20 100-90 110-160Z',
29
+ inner: 'M262 530C170 430 90 370 60 396c4 44 50 76 84 100-50 24-84 74-70 122 50 4 110-24 160-66-30 48-30 96 0 122 44-18 78-76 86-134Z',
30
+ }
31
+
32
+ function SunRays() {
33
+ const rays = Array.from({ length: 12 }, (_, index) => {
34
+ const a = (index * 30 * Math.PI) / 180, w = (9 * Math.PI) / 180
35
+ const p = (r: number, t: number) => `${(512 + r * Math.cos(t)).toFixed(0)} ${(640 + r * Math.sin(t)).toFixed(0)}`
36
+ return <path key={index} d={`M${p(300, a - w)} L${p(560, a)} L${p(300, a + w)}Z`} fill={index % 2 ? '#ffcf11' : '#f6b500'} stroke="#fff" strokeWidth="14" strokeLinejoin="round" paintOrder="stroke fill" />
37
+ })
38
+ return <g className="dca-fx-rotate" style={{ transformOrigin: '512px 640px' }}>{rays}</g>
39
+ }
40
+ const balloon = (cx: number, cy: number, fill: string, delay?: string) => <g className="dca-fx-hover" style={{ transformOrigin: `${cx}px ${cy}px`, animationDelay: delay }}>
41
+ <path d={`M${cx} ${cy + 52}L${cx - 8} ${cy + 66}h16Z`} fill={fill} />
42
+ <ellipse cx={cx} cy={cy} rx="46" ry="54" fill={fill} stroke="#fff" strokeWidth="14" paintOrder="stroke fill" />
43
+ <ellipse cx={cx - 14} cy={cy - 18} rx="10" ry="16" fill="#fff" opacity=".6" />
44
+ </g>
45
+
46
+ const orbit = { transform: 'translate(512 760) rotate(-12)', rx: 450, ry: 104 }
47
+ const orbitBodies: { key: string; delay?: string; art: ReactNode }[] = [
48
+ { key: 'a', art: <><ellipse rx="64" ry="18" fill="none" stroke="#fff" strokeWidth="22" transform="rotate(-18)" /><ellipse rx="64" ry="18" fill="none" stroke="#ffe08a" strokeWidth="9" transform="rotate(-18)" /><circle r="44" fill="#fff" /><circle r="34" fill="#f6b500" /><path d="M-64 0a64 18 0 0 0 128 0" fill="none" stroke="#ffe08a" strokeWidth="9" transform="rotate(-18)" /></> },
49
+ { key: 'b', delay: '-2.67s', art: <><circle r="34" fill="#fff" /><circle r="25" fill="#c9d2ff" /></> },
50
+ { key: 'c', delay: '-5.33s', art: <><circle r="26" fill="#fff" /><circle r="17" fill="#ff9ad9" /></> },
51
+ ]
52
+ function OrbitBodies({ side }: { side: 'front' | 'back' }) {
53
+ return <>{orbitBodies.map(body => <g key={body.key} className={`dca-fx dca-fx-orbit dca-fx-orbit-${side} dca-fx-orbit-${body.key}`} style={body.delay ? { animationDelay: body.delay } : undefined}>{body.art}</g>)}</>
54
+ }
55
+ function OrbitArc({ side }: { side: 'front' | 'back' }) {
56
+ const sweep = side === 'back' ? 1 : 0
57
+ const outer = `M${-orbit.rx} 0A${orbit.rx} ${orbit.ry} 0 0 ${sweep} ${orbit.rx} 0`
58
+ return <>
59
+ <path d={outer} fill="none" stroke="#fff" strokeWidth="46" />
60
+ <path d={outer} fill="none" stroke="#b9c4ff" strokeWidth="30" />
61
+ </>
62
+ }
63
+
64
+ const halo = { cx: 512, cy: 229, r: 168 }
65
+
66
+ export function BackDecoration({ id }: { id: BackId }) {
67
+ switch (id) {
68
+ case 'cape': return <g className="dca-fx-sway" style={{ transformOrigin: '512px 452px' }}>
69
+ <path d="M262 452C190 600 130 780 104 930c80-26 160-26 240 0 56-20 112-30 168-30s112 10 168 30c80-26 160-26 240 0-26-150-86-330-158-478Z" fill="#b23a48" stroke="#fff" strokeWidth="18" strokeLinejoin="round" paintOrder="stroke fill" />
70
+ <path d="M296 470C236 600 190 760 176 896c56-16 108-22 168-16 56-14 112-22 168-22s112 8 168 22c60-6 112 0 168 16-14-136-60-296-120-426Z" fill="#d65a68" />
71
+ </g>
72
+ case 'jetpack': return <>
73
+ <g className="dca-fx dca-fx-flame" style={{ transformOrigin: '159px 800px' }}>
74
+ <path d="M159 892c-26-30-34-56-26-90h52c8 34 0 60-26 90Z" fill="#ffb347" />
75
+ <path d="M159 866c-12-18-16-34-10-52h20c6 18 2 34-10 52Z" fill="#ffe08a" />
76
+ </g>
77
+ <g className="dca-fx dca-fx-flame" style={{ transformOrigin: '865px 800px', animationDelay: '.35s' }}>
78
+ <path d="M865 892c-26-30-34-56-26-90h52c8 34 0 60-26 90Z" fill="#ffb347" />
79
+ <path d="M865 866c-12-18-16-34-10-52h20c6 18 2 34-10 52Z" fill="#ffe08a" />
80
+ </g>
81
+ <rect x="118" y="486" width="82" height="290" rx="40" fill="#8b95a5" stroke="#fff" strokeWidth="18" paintOrder="stroke fill" />
82
+ <rect x="824" y="486" width="82" height="290" rx="40" fill="#8b95a5" stroke="#fff" strokeWidth="18" paintOrder="stroke fill" />
83
+ <rect x="126" y="486" width="66" height="44" rx="20" fill="#e8654f" />
84
+ <rect x="832" y="486" width="66" height="44" rx="20" fill="#e8654f" />
85
+ <path d="M134 776h50l10 30h-70Z" fill="#3c4658" stroke="#fff" strokeWidth="12" strokeLinejoin="round" paintOrder="stroke fill" />
86
+ <path d="M840 776h50l10 30h-70Z" fill="#3c4658" stroke="#fff" strokeWidth="12" strokeLinejoin="round" paintOrder="stroke fill" />
87
+ </>
88
+ case 'bat-wings': return <Wings {...batWing} fill="#5b3a8c" lining="#3d2563" />
89
+ case 'butterfly-wings': return <Wings {...butterflyWing} fill="#f2a0b4" lining="#fff3c4" />
90
+ case 'angel-wings': return <>
91
+ <Glow blur={22} className="dca-fx-pulse"><path d={angelWing.outer} fill="#fff7dc" opacity=".6" /><path d={angelWing.outer} fill="#fff7dc" opacity=".6" transform="matrix(-1 0 0 1 1024 0)" /></Glow>
92
+ <Wings {...angelWing} fill="#fff" lining="#dfe4ff" outline="#b9c4ff" flap="dca-fx-flap-slow" />
93
+ </>
94
+ case 'dragon-wings': return <Wings {...dragonWing} fill="#b23a48" lining="#7f2634">
95
+ <g className="dca-fx dca-fx-pulse" fill="#ffb347"><circle cx="30" cy="350" r="14" /><circle cx="48" cy="618" r="12" /><circle cx="236" cy="704" r="12" /></g>
96
+ </Wings>
97
+ case 'crescent-moon': return <>
98
+ <path d="M330 130a190 190 0 1 0 176 254a150 150 0 0 1-176-254Z" fill="#f6d365" stroke="#fff" strokeWidth="18" strokeLinejoin="round" paintOrder="stroke fill" />
99
+ <path className="dca-fx dca-fx-sparkle-solo" d="M720 150l12 30 30 12-30 12-12 30-12-30-30-12 30-12Z" fill="#fff3c4" stroke="#fff" strokeWidth="10" strokeLinejoin="round" paintOrder="stroke fill" />
100
+ </>
101
+ case 'star-trail': return <g className="dca-fx-sparkle" fill="#f6b500" stroke="#fff" strokeWidth="14" strokeLinejoin="round" paintOrder="stroke fill">
102
+ <path d="M130 330l20 48 48 20-48 20-20 48-20-48-48-20 48-20Z" />
103
+ <path d="M900 250l16 38 38 16-38 16-16 38-16-38-38-16 38-16Z" style={{ animationDelay: '.6s' }} />
104
+ <path d="M920 690l12 30 30 12-30 12-12 30-12-30-30-12 30-12Z" style={{ animationDelay: '1.1s' }} />
105
+ </g>
106
+ case 'balloons': return <>
107
+ <path d="M150 384 262 560M206 306 262 560M112 484 262 560" stroke="#fff" strokeWidth="16" strokeLinecap="round" /><path d="M150 384 262 560M206 306 262 560M112 484 262 560" stroke="#8b95a5" strokeWidth="6" strokeLinecap="round" />
108
+ {balloon(150, 330, '#e8654f')}{balloon(206, 250, '#f6b500', '.5s')}{balloon(112, 430, '#4f7cf6', '1s')}
109
+ </>
110
+ case 'sun-rays': return <SunRays />
111
+ case 'halo': return <>
112
+ <Glow blur={24} className="dca-fx-pulse"><circle cx={halo.cx} cy={halo.cy} r={halo.r} fill="none" stroke="#ffe08a" strokeWidth="74" opacity=".65" /></Glow>
113
+ <circle cx={halo.cx} cy={halo.cy} r={halo.r} fill="none" stroke="#fff" strokeWidth="54" />
114
+ <circle cx={halo.cx} cy={halo.cy} r={halo.r} fill="none" stroke="#f6b500" strokeWidth="34" />
115
+ </>
116
+ case 'orbit-ring': return <g transform={orbit.transform}>
117
+ <Glow blur={22} className="dca-fx-pulse"><ellipse rx={orbit.rx} ry={orbit.ry} fill="none" stroke="#b9c4ff" strokeWidth="60" opacity=".55" /></Glow>
118
+ <OrbitArc side="back" />
119
+ <OrbitBodies side="back" />
120
+ </g>
121
+ default: return null
122
+ }
123
+ }
124
+
125
+ export function BackFrontDecoration({ id }: { id: BackId }) {
126
+ switch (id) {
127
+ case 'orbit-ring': return <g data-back-front={id} transform={orbit.transform}>
128
+ <OrbitArc side="front" />
129
+ <OrbitBodies side="front" />
130
+ </g>
131
+ default: return null
132
+ }
133
+ }
134
+ export function hasFrontPart(id: BackId): boolean { return id === 'orbit-ring' }
@@ -1,8 +1,16 @@
1
- import type { ReactNode } from 'react'
1
+ import { useId, type ReactNode } from 'react'
2
2
 
3
- export function Silhouette({ d, fill, children }: { d: string; fill: string; children?: ReactNode }) {
4
- return <><path d={d} fill={fill} stroke="#fff" strokeWidth="18" strokeLinejoin="round" paintOrder="stroke fill" />{children}</>
3
+ export function Silhouette({ d, fill, stroke = 18, children }: { d: string; fill: string; stroke?: number; children?: ReactNode }) {
4
+ return <><path d={d} fill={fill} stroke="#fff" strokeWidth={stroke} strokeLinejoin="round" paintOrder="stroke fill" />{children}</>
5
5
  }
6
6
  export function Detail({ children }: { children: ReactNode }) {
7
7
  return <g className="dca-decoration-detail">{children}</g>
8
8
  }
9
+ export function Glow({ children, blur = 18, className = '' }: { children: ReactNode; blur?: number; className?: string }) {
10
+ const id = `dca-fx-blur-${useId().replace(/:/g, '')}`
11
+ return <>
12
+ <defs><filter id={id} x="-40%" y="-40%" width="180%" height="180%"><feGaussianBlur stdDeviation={blur} /></filter></defs>
13
+ <g className={`dca-fx dca-fx-glow ${className}`.trim()} filter={`url(#${id})`}>{children}</g>
14
+ </>
15
+ }
16
+ export function useClipId() { return `dca-clip-${useId().replace(/:/g, '')}` }
@@ -1,31 +1,56 @@
1
- import type { PrimaryId, SecondaryId, DecorationId } from './appearanceModel.js'
2
- import { isHeld } from './appearanceModel.js'
3
- import { HeldDecoration } from './HeldDecorations.js'
1
+ import { useId } from 'react'
2
+ import type { ItemId, HeadId, SkinId } from './items.js'
3
+ import { itemOf } from './items.js'
4
4
  import { HatDecoration } from './HatDecorations.js'
5
5
  import { ObjectDecoration } from './ObjectDecorations.js'
6
+ import { FaceDecoration, FaceplateEyes, FaceplatePlate, isFaceplate } from './FaceDecorations.js'
7
+ import { HandDecoration } from './HandDecorations.js'
8
+ import { BackDecoration, BackFrontDecoration } from './BackDecorations.js'
9
+ import { SkinOverlay, SkinPaintSurface, skinPaint } from './SkinDecorations.js'
6
10
  import { decorationOf } from './decorationCatalog.js'
7
11
 
8
- export function SecondaryDecoration({ id }: { id: SecondaryId }) {
9
- if (isHeld(id)) return <HeldDecoration id={id} />
10
- switch (id) {
11
- case 'forehead-goggles': return <g strokeLinejoin="round">
12
- <path d="M374 419h109v46H374Zm167 0h109v46H541Z" fill="#a2c5d1" stroke="#8b7568" strokeWidth="14" />
13
- <path d="M483 442q29 20 58 0" stroke="#8b7568" strokeWidth="11" fill="none" />
14
- <path d="m389 429 18 21m149-21 18 21" stroke="#e0eff1" strokeWidth="8" />
15
- </g>
16
- default: return null
17
- }
18
- }
19
- export function PrimaryDecoration({ id }: { id: PrimaryId }) {
12
+ export function HeadDecoration({ id }: { id: HeadId }) {
20
13
  return <g data-decoration={id}><HatDecoration id={id} /><ObjectDecoration id={id} /></g>
21
14
  }
22
- export function DecoratedTop({ id }: { id: Exclude<PrimaryId, 'none'> }) {
23
- return <PrimaryDecoration id={id} />
15
+
16
+ function SkinSpecimen({ id }: { id: SkinId }) {
17
+ const uid = useId().replace(/:/g, '')
18
+ const paint = skinPaint(id)
19
+ return <g data-skin={id}>
20
+ <defs>
21
+ {paint?.render(`dca-swatch-paint-${uid}`)}
22
+ <clipPath id={`dca-swatch-clip-${uid}`}><rect x="243" y="408" width="538" height="426" rx="113" /></clipPath>
23
+ </defs>
24
+ <rect x="243" y="408" width="538" height="426" rx="113" fill={paint ? `url(#dca-swatch-paint-${uid})` : '#4f7cf6'} stroke="#fff" strokeWidth="18" paintOrder="stroke fill" />
25
+ <g clipPath={`url(#dca-swatch-clip-${uid})`}>{paint ? <SkinPaintSurface id={id} /> : <SkinOverlay id={id} />}</g>
26
+ </g>
27
+ }
28
+
29
+ export function SlotDecoration({ id }: { id: ItemId }) {
30
+ const item = itemOf(id)
31
+ switch (item.slot) {
32
+ case 'head': return <HeadDecoration id={item.id} />
33
+ case 'face': return isFaceplate(item.id)
34
+ ? <g data-accessory={item.id}><rect x="295" y="464" width="434" height="315" rx="78" fill="#fff" /><FaceplatePlate id={item.id} /><FaceplateEyes id={item.id} /></g>
35
+ : <g data-accessory={item.id}><FaceDecoration id={item.id} /></g>
36
+ case 'hand': return <g data-accessory={item.id}><HandDecoration id={item.id} /></g>
37
+ case 'back': return <g data-back={item.id}><BackDecoration id={item.id} /><BackFrontDecoration id={item.id} /></g>
38
+ case 'skin': return <SkinSpecimen id={item.id} />
39
+ }
40
+ }
41
+
42
+ const swatchViewBox: Record<ReturnType<typeof itemOf>['slot'], string> = {
43
+ head: '265 105 494 360',
44
+ face: '300 280 424 324',
45
+ hand: '40 330 400 400',
46
+ back: '20 120 984 800',
47
+ skin: '203 368 618 506',
24
48
  }
25
- export function DecorationSwatch({ id, size = 112 }: { id: DecorationId; size?: number }) {
26
- const secondary = decorationOf(id).category === 'Accessories'
27
- const forehead = id === 'forehead-goggles'
28
- return <svg width={size} height={size} viewBox={secondary ? forehead ? '300 280 424 324' : '65 435 315 360' : '265 105 494 360'} fill="none" role="img" aria-label={`${decorationOf(id).name} specimen`}>
29
- {secondary ? <SecondaryDecoration id={id as SecondaryId} /> : <PrimaryDecoration id={id as PrimaryId} />}
49
+ export function DecorationSwatch({ id, size = 112 }: { id: ItemId; size?: number }) {
50
+ const item = itemOf(id)
51
+ const viewBox = item.slot === 'face' && isFaceplate(item.id) ? '255 404 514 436' : swatchViewBox[item.slot]
52
+ return <svg width={size} height={size} viewBox={viewBox} fill="none" role="img" aria-label={`${decorationOf(id).name} specimen`}
53
+ className="dca-swatch dca-part-robot" data-expression="neutral" data-slot={item.slot} data-effects="static">
54
+ <SlotDecoration id={id} />
30
55
  </svg>
31
56
  }