tfrere HF Staff Cursor commited on
Commit
1e9f6d1
·
1 Parent(s): 4348e2e

feat: modal logo artwork + sync colour variants from pollen site

Browse files

- welcome modal now uses the Microduck sticker + wordmark press assets
(LFS-tracked PNGs, signed like every other private-Space subresource)
- variants.js replaced with the site's 3d-module version: dedicated
tongue/hips/sideShells slots, black leg motors, uniform yellow/orange
shoe, and orange lower beak on the blue scheme
- swatches honour the per-variant swatch override (purple dot is purple)
- duck.js/variants.js dynamic imports reuse rl.js's ?v= cache-buster

Co-authored-by: Cursor <cursoragent@cursor.com>

Files changed (6) hide show
  1. .gitattributes +1 -0
  2. assets/logo-duck.png +3 -0
  3. assets/logo-wordmark.png +3 -0
  4. index.html +29 -23
  5. rl.js +11 -8
  6. variants.js +57 -33
.gitattributes CHANGED
@@ -35,4 +35,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  *.stl filter=lfs diff=lfs merge=lfs -text
37
  *.wav filter=lfs diff=lfs merge=lfs -text
 
38
  *.jpg filter=lfs diff=lfs merge=lfs -text
 
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  *.stl filter=lfs diff=lfs merge=lfs -text
37
  *.wav filter=lfs diff=lfs merge=lfs -text
38
+ *.png filter=lfs diff=lfs merge=lfs -text
39
  *.jpg filter=lfs diff=lfs merge=lfs -text
assets/logo-duck.png ADDED

Git LFS Details

  • SHA256: 976af27e4c25e1b8b7afb6e30aa4bde33752d9ea451a0a1f39e8c13c4a98cf1a
  • Pointer size: 131 Bytes
  • Size of remote file: 165 kB
assets/logo-wordmark.png ADDED

Git LFS Details

  • SHA256: 9f091b8cc94594d422755963c581984c515d5aab05444c3b9a2b2c4056038d47
  • Pointer size: 131 Bytes
  • Size of remote file: 246 kB
index.html CHANGED
@@ -281,31 +281,30 @@
281
  from { transform: translateY(18px) scale(0.94); opacity: 0; }
282
  to { transform: none; opacity: 1; }
283
  }
284
- #welcome .badge {
285
- width: 4rem;
286
- height: 4rem;
287
- margin: 0 auto 1.1rem;
288
- display: flex;
289
- align-items: center;
290
- justify-content: center;
291
- font-size: 2rem;
292
- border-radius: 50%;
293
- background: rgba(255, 210, 63, 0.12);
294
- border: 1px solid rgba(255, 210, 63, 0.35);
295
- animation: badge-bob 3s ease-in-out infinite;
296
  }
297
  @keyframes badge-bob {
298
- 0%, 100% { transform: translateY(0) rotate(-3deg); }
299
- 50% { transform: translateY(-6px) rotate(3deg); }
 
 
 
 
 
300
  }
301
- #welcome h1 {
302
- font-size: 1.05rem;
 
303
  font-weight: 700;
304
- letter-spacing: 0.18em;
305
  text-transform: uppercase;
306
- color: #fff;
307
  }
308
- #welcome h1 b { color: var(--yellow); font-weight: 700; }
309
  #welcome .tagline {
310
  margin-top: 0.5rem;
311
  font-size: 0.8rem;
@@ -410,9 +409,10 @@
410
  <div id="loading">Compiling physics&hellip;</div>
411
 
412
  <div id="welcome" hidden>
413
- <div class="card" role="dialog" aria-modal="true" aria-labelledby="welcome-title">
414
- <div class="badge">🐤</div>
415
- <h1 id="welcome-title"><b>Microduck</b> playground</h1>
 
416
  <p class="tagline">
417
  A real robot brain in your browser: MuJoCo physics compiled to
418
  WebAssembly, driven by the duck's actual trained neural policies
@@ -434,6 +434,12 @@
434
  // or clicking the blurred backdrop. The top-left brand reopens it.
435
  (() => {
436
  const modal = document.getElementById("welcome");
 
 
 
 
 
 
437
  const open = () => {
438
  modal.hidden = false;
439
  modal.classList.remove("closing");
@@ -464,7 +470,7 @@
464
  appended: a plain src attribute can 401 when the browser blocks the
465
  *.static.hf.space auth cookie inside the hub iframe. -->
466
  <script type="module">
467
- const V = "20"; // bump on rl.js changes to defeat heuristic caching
468
  const sign = new URLSearchParams(location.search).get("__sign");
469
  const suffix = sign ? `&__sign=${encodeURIComponent(sign)}` : "";
470
  import(`./rl.js?v=${V}${suffix}`);
 
281
  from { transform: translateY(18px) scale(0.94); opacity: 0; }
282
  to { transform: none; opacity: 1; }
283
  }
284
+ #welcome .logo-duck {
285
+ display: block;
286
+ height: 7.5rem;
287
+ margin: 0 auto 0.4rem;
288
+ filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.45));
289
+ animation: badge-bob 3.2s ease-in-out infinite;
 
 
 
 
 
 
290
  }
291
  @keyframes badge-bob {
292
+ 0%, 100% { transform: translateY(0) rotate(-2deg); }
293
+ 50% { transform: translateY(-6px) rotate(2deg); }
294
+ }
295
+ #welcome .logo-wordmark {
296
+ display: block;
297
+ width: min(78%, 300px);
298
+ margin: 0 auto;
299
  }
300
+ #welcome .subtitle {
301
+ margin-top: 0.55rem;
302
+ font-size: 0.62rem;
303
  font-weight: 700;
304
+ letter-spacing: 0.32em;
305
  text-transform: uppercase;
306
+ color: rgba(255, 210, 63, 0.75);
307
  }
 
308
  #welcome .tagline {
309
  margin-top: 0.5rem;
310
  font-size: 0.8rem;
 
409
  <div id="loading">Compiling physics&hellip;</div>
410
 
411
  <div id="welcome" hidden>
412
+ <div class="card" role="dialog" aria-modal="true" aria-label="Microduck playground">
413
+ <img class="logo-duck" id="logo-duck" alt="" />
414
+ <img class="logo-wordmark" id="logo-wordmark" alt="Microduck" />
415
+ <div class="subtitle">RL playground</div>
416
  <p class="tagline">
417
  A real robot brain in your browser: MuJoCo physics compiled to
418
  WebAssembly, driven by the duck's actual trained neural policies
 
434
  // or clicking the blurred backdrop. The top-left brand reopens it.
435
  (() => {
436
  const modal = document.getElementById("welcome");
437
+ // Logo images need the same ?__sign JWT as every other subresource
438
+ // on the private Space (rl.js hasn't installed its signer yet).
439
+ const sign = new URLSearchParams(location.search).get("__sign");
440
+ const signedUrl = (u) => (sign ? `${u}?__sign=${encodeURIComponent(sign)}` : u);
441
+ document.getElementById("logo-duck").src = signedUrl("./assets/logo-duck.png");
442
+ document.getElementById("logo-wordmark").src = signedUrl("./assets/logo-wordmark.png");
443
  const open = () => {
444
  modal.hidden = false;
445
  modal.classList.remove("closing");
 
470
  appended: a plain src attribute can 401 when the browser blocks the
471
  *.static.hf.space auth cookie inside the hub iframe. -->
472
  <script type="module">
473
+ const V = "21"; // bump on rl.js changes to defeat heuristic caching
474
  const sign = new URLSearchParams(location.search).get("__sign");
475
  const suffix = sign ? `&__sign=${encodeURIComponent(sign)}` : "";
476
  import(`./rl.js?v=${V}${suffix}`);
rl.js CHANGED
@@ -32,10 +32,14 @@ window.__hfSigned = signed; // duck.js uses it for kinematics + STL requests
32
 
33
  // Local modules are imported dynamically through signed() for the same
34
  // reason: a static import of ./duck.js would 401 without the cookie.
 
 
 
 
35
  const { buildRig, cloneRig, loadKinematics, setJoint, setJawOpen, MODEL_DIR, MESH_VERSION } =
36
- await import(signed("./duck.js"));
37
  const { VARIANTS, VARIANT_NAMES, materialHookFor, randomVariantName, applyVariant, specToHex } =
38
- await import(signed("./variants.js"));
39
 
40
  ort.env.wasm.wasmPaths = "https://cdn.jsdelivr.net/npm/onnxruntime-web@1.27.0/dist/";
41
  ort.env.wasm.numThreads = 1; // static hosting sends no COOP/COEP headers
@@ -700,14 +704,16 @@ function syncButtons() {
700
  }
701
 
702
  // ── Colour swatches: re-skin the rig live, with a quack ─────────────────
703
- // One representative colour per variant so the dots read at a glance.
 
 
704
  const SWATCH_SLOT = { classic: "feet", charcoal: "headDome", purple: "feet", blue: "facePlate" };
705
  const swatchesEl = document.getElementById("swatches");
706
  const swatchBtns = new Map();
707
  for (const name of VARIANT_NAMES) {
708
  const v = VARIANTS[name];
709
  const b = document.createElement("button");
710
- b.style.background = specToHex(v[SWATCH_SLOT[name] ?? "bodyShell"]);
711
  b.setAttribute("aria-label", `${name} colours`);
712
  b.addEventListener("click", () => {
713
  if (name === currentVariant) return;
@@ -744,10 +750,7 @@ window.rl = {
744
  // translucent ducks. Fire-and-forget: any failure just means no ghosts.
745
  const r3 = (x) => Math.round(x * 1000) / 1000;
746
  try {
747
- // Same heuristic-cache pitfall as everything else served without
748
- // Cache-Control: reuse rl.js's own ?v= so ghosts.js updates ship together.
749
- const selfV = new URL(import.meta.url).searchParams.get("v") ?? "0";
750
- const { initGhosts } = await import(signed(`./ghosts.js?v=${selfV}`));
751
  ghosts = await initGhosts({
752
  scene, rig, cloneRig, setJoint, setJawOpen, applyVariant,
753
  jointNames: JOINT_NAMES,
 
32
 
33
  // Local modules are imported dynamically through signed() for the same
34
  // reason: a static import of ./duck.js would 401 without the cookie.
35
+ // They also reuse rl.js's own ?v= cache-buster: python http.server (and
36
+ // some CDN edges) send no Cache-Control, so without it browsers can keep
37
+ // serving stale module bytes after a deploy.
38
+ const SELF_V = new URL(import.meta.url).searchParams.get("v") ?? "0";
39
  const { buildRig, cloneRig, loadKinematics, setJoint, setJawOpen, MODEL_DIR, MESH_VERSION } =
40
+ await import(signed(`./duck.js?v=${SELF_V}`));
41
  const { VARIANTS, VARIANT_NAMES, materialHookFor, randomVariantName, applyVariant, specToHex } =
42
+ await import(signed(`./variants.js?v=${SELF_V}`));
43
 
44
  ort.env.wasm.wasmPaths = "https://cdn.jsdelivr.net/npm/onnxruntime-web@1.27.0/dist/";
45
  ort.env.wasm.numThreads = 1; // static hosting sends no COOP/COEP headers
 
704
  }
705
 
706
  // ── Colour swatches: re-skin the rig live, with a quack ─────────────────
707
+ // One representative colour per variant so the dots read at a glance.
708
+ // Variants can force theirs with a `swatch` spec (purple does: its head
709
+ // is warm gray but its identity is the purple accents).
710
  const SWATCH_SLOT = { classic: "feet", charcoal: "headDome", purple: "feet", blue: "facePlate" };
711
  const swatchesEl = document.getElementById("swatches");
712
  const swatchBtns = new Map();
713
  for (const name of VARIANT_NAMES) {
714
  const v = VARIANTS[name];
715
  const b = document.createElement("button");
716
+ b.style.background = specToHex(v.swatch ?? v[SWATCH_SLOT[name] ?? "bodyShell"]);
717
  b.setAttribute("aria-label", `${name} colours`);
718
  b.addEventListener("click", () => {
719
  if (name === currentVariant) return;
 
750
  // translucent ducks. Fire-and-forget: any failure just means no ghosts.
751
  const r3 = (x) => Math.round(x * 1000) / 1000;
752
  try {
753
+ const { initGhosts } = await import(signed(`./ghosts.js?v=${SELF_V}`));
 
 
 
754
  ghosts = await initGhosts({
755
  scene, rig, cloneRig, setJoint, setJawOpen, applyVariant,
756
  jointNames: JOINT_NAMES,
variants.js CHANGED
@@ -37,76 +37,94 @@ const FEET_YELLOW = { color: [0.784, 0.455, 0.023], roughness: 0.5, metalness: 0
37
 
38
  // Slots (validated against the four-robot reference photo): headDome
39
  // (top shell), facePlate (around the eye), trim (band under the shell +
40
- // upper beak base), beakUpper (mouth-roof plate), beakLower (jaw plates),
41
- // eyeRing, lens, bodyShell (trunk shells), legShells (upper-leg shells),
42
- // feet (foot blocks + ankle brackets), soles, mechDark, mechGray.
 
 
 
 
43
  export const VARIANTS = {
44
  // Front-center robot: warm gray head, cream body, amber eye, orange
45
- // trim/upper beak over a lighter amber lower beak, amber-orange feet.
46
  classic: {
47
- headDome: WARM_GRAY,
48
  facePlate: WARM_GRAY,
49
  trim: BRIGHT_ORANGE,
50
  beakUpper: BRIGHT_ORANGE,
51
- beakLower: AMBER,
 
52
  eyeRing: AMBER_YELLOW,
53
  lens: LENS,
54
  bodyShell: CREAM,
 
55
  legShells: CREAM,
56
- feet: AMBER_ORANGE,
57
  soles: AMBER_ORANGE,
 
58
  mechDark: DARK,
59
  mechGray: GRAY,
60
  },
61
  // Front-left robot: charcoal shells, slightly lighter face plate,
62
- // amber eye, orange/amber beak, yellow soles peeking under black feet.
63
  charcoal: {
64
  headDome: CHARCOAL,
65
  facePlate: CHARCOAL_FACE,
66
  trim: BRIGHT_ORANGE,
67
  beakUpper: BRIGHT_ORANGE,
68
- beakLower: AMBER,
 
69
  eyeRing: AMBER_YELLOW,
70
  lens: LENS,
71
  bodyShell: CHARCOAL_BODY,
 
72
  legShells: CHARCOAL_BODY,
73
- feet: CHARCOAL_BODY,
74
- soles: CLEAN_YELLOW,
 
75
  mechDark: DARK,
76
  mechGray: GRAY,
77
  },
78
  // Back-center robot: light warm gray head, purple eye, YELLOW trim and
79
- // beak (both plates), cream body, purple feet.
80
  purple: {
81
  headDome: LIGHT_WARM_GRAY,
82
- facePlate: LIGHT_WARM_GRAY,
83
  trim: CLEAN_YELLOW,
84
  beakUpper: CLEAN_YELLOW,
85
  beakLower: CLEAN_YELLOW,
 
86
  eyeRing: PURPLE_RING,
87
  lens: LENS,
88
  bodyShell: CREAM,
 
89
  legShells: CREAM,
90
- feet: PURPLE_FEET,
91
- soles: PURPLE_FEET,
 
92
  mechDark: DARK,
93
  mechGray: GRAY,
 
 
 
94
  },
95
  // Right robot: pale blue dome over a medium blue face plate (two
96
- // different blues), amber eye, orange/amber beak, blue-gray body,
97
- // clean yellow feet.
98
  blue: {
99
  headDome: PALE_BLUE,
100
  facePlate: MEDIUM_BLUE,
101
  trim: BRIGHT_ORANGE,
102
  beakUpper: BRIGHT_ORANGE,
103
- beakLower: AMBER,
 
104
  eyeRing: AMBER_YELLOW,
105
  lens: LENS,
106
- bodyShell: BLUE_GRAY,
107
- legShells: BLUE_GRAY,
108
- feet: FEET_YELLOW,
109
- soles: FEET_YELLOW,
 
 
110
  mechDark: DARK,
111
  mechGray: GRAY,
112
  },
@@ -131,17 +149,18 @@ export function meshMaterialsFor(v) {
131
  "noenoeil.stl": v.eyeRing,
132
  "lens.stl": v.lens,
133
  "m12_lens_holder.stl": v.mechDark,
134
- // Beak: mouth-roof plate on top, rigid jaw + soft pad below.
 
135
  "soft_mouth_top.stl": v.beakUpper,
136
  "jaw.stl": v.beakLower,
137
- "jaw_soft.stl": v.beakLower,
138
- // Body shells
139
  "trunk_base.stl": v.bodyShell,
140
- "left_shell.stl": v.bodyShell,
141
- "right_shell.stl": v.bodyShell,
142
  "upper_leg_left.stl": v.legShells,
143
  "upper_leg_right.stl": v.legShells,
144
- "hip_l.stl": v.trim,
145
  // Feet: foot block + ankle bracket, soft sole pad below.
146
  "foot_left.stl": v.feet,
147
  "foot_right.stl": v.feet,
@@ -149,8 +168,17 @@ export function meshMaterialsFor(v) {
149
  "ankle_right.stl": v.feet,
150
  "sole_left.stl": v.soles,
151
  "sole_right.stl": v.soles,
152
- // Dark mechanics
 
 
153
  "xl330.stl": v.mechDark,
 
 
 
 
 
 
 
154
  "neck.stl": v.mechDark,
155
  "np_f970.stl": v.mechDark,
156
  "pcb__raspberry_pi_zero_2_w.stl": v.mechDark,
@@ -159,15 +187,11 @@ export function meshMaterialsFor(v) {
159
  "speaker.stl": v.mechDark,
160
  // Gray mechanics
161
  "upper_leg_rigidity_plate.stl": v.mechGray,
162
- "leg.stl": v.mechGray,
163
- "yaw2roll.stl": v.mechGray,
164
  "yaw_roll_motion.stl": v.mechGray,
165
  "neck_pitch.stl": v.mechGray,
166
- "bearing_roll.stl": v.mechGray,
167
  "motor_support.stl": v.mechGray,
168
  "power_support.stl": v.mechGray,
169
  "seeed_bearing__configuration__22x16x4.stl": v.mechGray,
170
- "seeed_bearing__configuration_default.stl": v.mechGray,
171
  };
172
  }
173
 
 
37
 
38
  // Slots (validated against the four-robot reference photo): headDome
39
  // (top shell), facePlate (around the eye), trim (band under the shell +
40
+ // upper beak base), beakUpper (mouth-roof plate), beakLower (rigid jaw),
41
+ // tongue (soft pad inside the beak), eyeRing, lens, bodyShell (trunk
42
+ // base), sideShells (left + right trunk shells), legShells (upper-leg
43
+ // shells), feet (shoe upper: foot blocks + ankle brackets), soles (shoe
44
+ // lower: sole pads), hips (hip covers), mechDark, mechGray.
45
+ // The shoe is deliberately identical on all variants: yellow upper
46
+ // (feet), orange lower (soles).
47
  export const VARIANTS = {
48
  // Front-center robot: warm gray head, cream body, amber eye, orange
49
+ // trim and beak.
50
  classic: {
51
+ headDome: CREAM,
52
  facePlate: WARM_GRAY,
53
  trim: BRIGHT_ORANGE,
54
  beakUpper: BRIGHT_ORANGE,
55
+ beakLower: BRIGHT_ORANGE,
56
+ tongue: AMBER_YELLOW,
57
  eyeRing: AMBER_YELLOW,
58
  lens: LENS,
59
  bodyShell: CREAM,
60
+ sideShells: CREAM,
61
  legShells: CREAM,
62
+ feet: BRIGHT_ORANGE,
63
  soles: AMBER_ORANGE,
64
+ hips: GRAY,
65
  mechDark: DARK,
66
  mechGray: GRAY,
67
  },
68
  // Front-left robot: charcoal shells, slightly lighter face plate,
69
+ // amber eye, orange/amber beak.
70
  charcoal: {
71
  headDome: CHARCOAL,
72
  facePlate: CHARCOAL_FACE,
73
  trim: BRIGHT_ORANGE,
74
  beakUpper: BRIGHT_ORANGE,
75
+ beakLower: BRIGHT_ORANGE,
76
+ tongue: AMBER_YELLOW,
77
  eyeRing: AMBER_YELLOW,
78
  lens: LENS,
79
  bodyShell: CHARCOAL_BODY,
80
+ sideShells: CHARCOAL_BODY,
81
  legShells: CHARCOAL_BODY,
82
+ feet: BRIGHT_ORANGE,
83
+ soles: AMBER_ORANGE,
84
+ hips: GRAY,
85
  mechDark: DARK,
86
  mechGray: GRAY,
87
  },
88
  // Back-center robot: light warm gray head, purple eye, YELLOW trim and
89
+ // beak (both plates), cream body.
90
  purple: {
91
  headDome: LIGHT_WARM_GRAY,
92
+ facePlate: WARM_GRAY,
93
  trim: CLEAN_YELLOW,
94
  beakUpper: CLEAN_YELLOW,
95
  beakLower: CLEAN_YELLOW,
96
+ tongue: AMBER_YELLOW,
97
  eyeRing: PURPLE_RING,
98
  lens: LENS,
99
  bodyShell: CREAM,
100
+ sideShells: CREAM,
101
  legShells: CREAM,
102
+ feet: CLEAN_YELLOW,
103
+ soles: PURPLE_RING,
104
+ hips: GRAY,
105
  mechDark: DARK,
106
  mechGray: GRAY,
107
+ // UI swatch override: the head is warm gray, but this colourway's
108
+ // identity is its purple accents - the picker dot shows that.
109
+ swatch: PURPLE_FEET,
110
  },
111
  // Right robot: pale blue dome over a medium blue face plate (two
112
+ // different blues), amber eye, orange/amber beak, blue-gray body.
 
113
  blue: {
114
  headDome: PALE_BLUE,
115
  facePlate: MEDIUM_BLUE,
116
  trim: BRIGHT_ORANGE,
117
  beakUpper: BRIGHT_ORANGE,
118
+ beakLower: BRIGHT_ORANGE,
119
+ tongue: AMBER_YELLOW,
120
  eyeRing: AMBER_YELLOW,
121
  lens: LENS,
122
+ bodyShell: PALE_BLUE,
123
+ sideShells: PALE_BLUE,
124
+ legShells: PALE_BLUE,
125
+ feet: BRIGHT_ORANGE,
126
+ soles: AMBER_ORANGE,
127
+ hips: MEDIUM_BLUE,
128
  mechDark: DARK,
129
  mechGray: GRAY,
130
  },
 
149
  "noenoeil.stl": v.eyeRing,
150
  "lens.stl": v.lens,
151
  "m12_lens_holder.stl": v.mechDark,
152
+ // Beak: mouth-roof plate on top, rigid jaw below, soft pad (the
153
+ // tongue) riding on the jaw.
154
  "soft_mouth_top.stl": v.beakUpper,
155
  "jaw.stl": v.beakLower,
156
+ "jaw_soft.stl": v.tongue,
157
+ // Body: trunk base + the two side shells (shared slot).
158
  "trunk_base.stl": v.bodyShell,
159
+ "left_shell.stl": v.sideShells,
160
+ "right_shell.stl": v.sideShells,
161
  "upper_leg_left.stl": v.legShells,
162
  "upper_leg_right.stl": v.legShells,
163
+ "hip_l.stl": v.hips,
164
  // Feet: foot block + ankle bracket, soft sole pad below.
165
  "foot_left.stl": v.feet,
166
  "foot_right.stl": v.feet,
 
168
  "ankle_right.stl": v.feet,
169
  "sole_left.stl": v.soles,
170
  "sole_right.stl": v.soles,
171
+ // Dark mechanics. leg.stl is the printed shin that wraps the ankle
172
+ // motor and its bearing ring: in gray they read as two gray motors,
173
+ // so both go dark with the motor they hold.
174
  "xl330.stl": v.mechDark,
175
+ "leg.stl": v.mechDark,
176
+ "seeed_bearing__configuration_default.stl": v.mechDark,
177
+ // Hip yaw mechanism (ribbed ring + 4-screw plate): reads as the hip
178
+ // motor, so it goes dark too. The printed hip cover (hip_l.stl)
179
+ // keeps the dedicated `hips` slot.
180
+ "yaw2roll.stl": v.mechDark,
181
+ "bearing_roll.stl": v.mechDark,
182
  "neck.stl": v.mechDark,
183
  "np_f970.stl": v.mechDark,
184
  "pcb__raspberry_pi_zero_2_w.stl": v.mechDark,
 
187
  "speaker.stl": v.mechDark,
188
  // Gray mechanics
189
  "upper_leg_rigidity_plate.stl": v.mechGray,
 
 
190
  "yaw_roll_motion.stl": v.mechGray,
191
  "neck_pitch.stl": v.mechGray,
 
192
  "motor_support.stl": v.mechGray,
193
  "power_support.stl": v.mechGray,
194
  "seeed_bearing__configuration__22x16x4.stl": v.mechGray,
 
195
  };
196
  }
197