designmd-forge 1.2.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.
Files changed (907) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +119 -0
  3. package/dist/__tests__/designStore.test.js +41 -0
  4. package/dist/__tests__/linter.test.js +23 -0
  5. package/dist/__tests__/sectionParser.test.js +60 -0
  6. package/dist/__tests__/server.test.js +129 -0
  7. package/dist/constants.js +12 -0
  8. package/dist/data/authoring-guide.md +113 -0
  9. package/dist/data/designs/airbnb.md +545 -0
  10. package/dist/data/designs/airtable.md +554 -0
  11. package/dist/data/designs/apple.md +562 -0
  12. package/dist/data/designs/binance.md +634 -0
  13. package/dist/data/designs/bmw-m.md +503 -0
  14. package/dist/data/designs/bmw.md +544 -0
  15. package/dist/data/designs/bugatti.md +454 -0
  16. package/dist/data/designs/cal.md +542 -0
  17. package/dist/data/designs/card-heavy.md +250 -0
  18. package/dist/data/designs/claude.md +589 -0
  19. package/dist/data/designs/clay.md +541 -0
  20. package/dist/data/designs/clickhouse.md +544 -0
  21. package/dist/data/designs/cohere.md +451 -0
  22. package/dist/data/designs/coinbase.md +570 -0
  23. package/dist/data/designs/composio.md +506 -0
  24. package/dist/data/designs/content-first.md +236 -0
  25. package/dist/data/designs/cursor.md +537 -0
  26. package/dist/data/designs/data-dashboard.md +300 -0
  27. package/dist/data/designs/dell-1996.md +632 -0
  28. package/dist/data/designs/elevenlabs.md +504 -0
  29. package/dist/data/designs/enterprise-neutral.md +252 -0
  30. package/dist/data/designs/expo.md +526 -0
  31. package/dist/data/designs/ferrari.md +531 -0
  32. package/dist/data/designs/figma.md +578 -0
  33. package/dist/data/designs/framer.md +544 -0
  34. package/dist/data/designs/hashicorp.md +575 -0
  35. package/dist/data/designs/hp.md +670 -0
  36. package/dist/data/designs/ibm.md +550 -0
  37. package/dist/data/designs/intercom.md +546 -0
  38. package/dist/data/designs/ios-acorns-android.md +430 -0
  39. package/dist/data/designs/ios-acorns-expo.md +381 -0
  40. package/dist/data/designs/ios-acorns-swiftui.md +378 -0
  41. package/dist/data/designs/ios-acorns.md +384 -0
  42. package/dist/data/designs/ios-airbnb-android.md +658 -0
  43. package/dist/data/designs/ios-airbnb-expo.md +457 -0
  44. package/dist/data/designs/ios-airbnb-swiftui.md +464 -0
  45. package/dist/data/designs/ios-airbnb.md +410 -0
  46. package/dist/data/designs/ios-alltrails-android.md +451 -0
  47. package/dist/data/designs/ios-alltrails-expo.md +400 -0
  48. package/dist/data/designs/ios-alltrails-swiftui.md +343 -0
  49. package/dist/data/designs/ios-alltrails.md +344 -0
  50. package/dist/data/designs/ios-amazon-android.md +686 -0
  51. package/dist/data/designs/ios-amazon-expo.md +433 -0
  52. package/dist/data/designs/ios-amazon-music-android.md +416 -0
  53. package/dist/data/designs/ios-amazon-music-expo.md +368 -0
  54. package/dist/data/designs/ios-amazon-music-swiftui.md +436 -0
  55. package/dist/data/designs/ios-amazon-music.md +389 -0
  56. package/dist/data/designs/ios-amazon-swiftui.md +460 -0
  57. package/dist/data/designs/ios-amazon.md +440 -0
  58. package/dist/data/designs/ios-apple-fitness-android.md +462 -0
  59. package/dist/data/designs/ios-apple-fitness-expo.md +373 -0
  60. package/dist/data/designs/ios-apple-fitness-swiftui.md +373 -0
  61. package/dist/data/designs/ios-apple-fitness.md +399 -0
  62. package/dist/data/designs/ios-apple-maps-android.md +646 -0
  63. package/dist/data/designs/ios-apple-maps-expo.md +557 -0
  64. package/dist/data/designs/ios-apple-maps-swiftui.md +588 -0
  65. package/dist/data/designs/ios-apple-maps.md +447 -0
  66. package/dist/data/designs/ios-apple-music-android.md +737 -0
  67. package/dist/data/designs/ios-apple-music-expo.md +596 -0
  68. package/dist/data/designs/ios-apple-music-swiftui.md +578 -0
  69. package/dist/data/designs/ios-apple-music.md +494 -0
  70. package/dist/data/designs/ios-apple-notes-android.md +675 -0
  71. package/dist/data/designs/ios-apple-notes-expo.md +468 -0
  72. package/dist/data/designs/ios-apple-notes-swiftui.md +489 -0
  73. package/dist/data/designs/ios-apple-notes.md +413 -0
  74. package/dist/data/designs/ios-apple-tv-android.md +405 -0
  75. package/dist/data/designs/ios-apple-tv-expo.md +341 -0
  76. package/dist/data/designs/ios-apple-tv-swiftui.md +348 -0
  77. package/dist/data/designs/ios-apple-tv.md +390 -0
  78. package/dist/data/designs/ios-apple-wallet-android.md +617 -0
  79. package/dist/data/designs/ios-apple-wallet-expo.md +487 -0
  80. package/dist/data/designs/ios-apple-wallet-swiftui.md +425 -0
  81. package/dist/data/designs/ios-apple-wallet.md +360 -0
  82. package/dist/data/designs/ios-asana-android.md +435 -0
  83. package/dist/data/designs/ios-asana-expo.md +411 -0
  84. package/dist/data/designs/ios-asana-swiftui.md +416 -0
  85. package/dist/data/designs/ios-asana.md +433 -0
  86. package/dist/data/designs/ios-audible-android.md +450 -0
  87. package/dist/data/designs/ios-audible-expo.md +328 -0
  88. package/dist/data/designs/ios-audible-swiftui.md +418 -0
  89. package/dist/data/designs/ios-audible.md +364 -0
  90. package/dist/data/designs/ios-bandcamp-android.md +471 -0
  91. package/dist/data/designs/ios-bandcamp-expo.md +378 -0
  92. package/dist/data/designs/ios-bandcamp-swiftui.md +374 -0
  93. package/dist/data/designs/ios-bandcamp.md +372 -0
  94. package/dist/data/designs/ios-bear-android.md +496 -0
  95. package/dist/data/designs/ios-bear-expo.md +449 -0
  96. package/dist/data/designs/ios-bear-swiftui.md +479 -0
  97. package/dist/data/designs/ios-bear.md +412 -0
  98. package/dist/data/designs/ios-bereal-android.md +392 -0
  99. package/dist/data/designs/ios-bereal-expo.md +299 -0
  100. package/dist/data/designs/ios-bereal-swiftui.md +319 -0
  101. package/dist/data/designs/ios-bereal.md +336 -0
  102. package/dist/data/designs/ios-binance-android.md +481 -0
  103. package/dist/data/designs/ios-binance-expo.md +404 -0
  104. package/dist/data/designs/ios-binance-swiftui.md +418 -0
  105. package/dist/data/designs/ios-binance.md +410 -0
  106. package/dist/data/designs/ios-bluesky-android.md +442 -0
  107. package/dist/data/designs/ios-bluesky-expo.md +362 -0
  108. package/dist/data/designs/ios-bluesky-swiftui.md +328 -0
  109. package/dist/data/designs/ios-bluesky.md +338 -0
  110. package/dist/data/designs/ios-booking-android.md +471 -0
  111. package/dist/data/designs/ios-booking-expo.md +364 -0
  112. package/dist/data/designs/ios-booking-swiftui.md +377 -0
  113. package/dist/data/designs/ios-booking.md +346 -0
  114. package/dist/data/designs/ios-bumble-android.md +756 -0
  115. package/dist/data/designs/ios-bumble-expo.md +629 -0
  116. package/dist/data/designs/ios-bumble-swiftui.md +546 -0
  117. package/dist/data/designs/ios-bumble.md +424 -0
  118. package/dist/data/designs/ios-cal-ai-android.md +664 -0
  119. package/dist/data/designs/ios-cal-ai-expo.md +415 -0
  120. package/dist/data/designs/ios-cal-ai-swiftui.md +486 -0
  121. package/dist/data/designs/ios-cal-ai.md +387 -0
  122. package/dist/data/designs/ios-calm-android.md +431 -0
  123. package/dist/data/designs/ios-calm-expo.md +384 -0
  124. package/dist/data/designs/ios-calm-swiftui.md +327 -0
  125. package/dist/data/designs/ios-calm.md +356 -0
  126. package/dist/data/designs/ios-canva-android.md +469 -0
  127. package/dist/data/designs/ios-canva-expo.md +374 -0
  128. package/dist/data/designs/ios-canva-swiftui.md +422 -0
  129. package/dist/data/designs/ios-canva.md +395 -0
  130. package/dist/data/designs/ios-cash-app-android.md +601 -0
  131. package/dist/data/designs/ios-cash-app-expo.md +453 -0
  132. package/dist/data/designs/ios-cash-app-swiftui.md +463 -0
  133. package/dist/data/designs/ios-cash-app.md +365 -0
  134. package/dist/data/designs/ios-character-ai-android.md +489 -0
  135. package/dist/data/designs/ios-character-ai-expo.md +420 -0
  136. package/dist/data/designs/ios-character-ai-swiftui.md +417 -0
  137. package/dist/data/designs/ios-character-ai.md +392 -0
  138. package/dist/data/designs/ios-charles-schwab-android.md +454 -0
  139. package/dist/data/designs/ios-charles-schwab-expo.md +388 -0
  140. package/dist/data/designs/ios-charles-schwab-swiftui.md +394 -0
  141. package/dist/data/designs/ios-charles-schwab.md +380 -0
  142. package/dist/data/designs/ios-chatgpt-android.md +753 -0
  143. package/dist/data/designs/ios-chatgpt-expo.md +644 -0
  144. package/dist/data/designs/ios-chatgpt-swiftui.md +653 -0
  145. package/dist/data/designs/ios-chatgpt.md +466 -0
  146. package/dist/data/designs/ios-chime-android.md +438 -0
  147. package/dist/data/designs/ios-chime-expo.md +419 -0
  148. package/dist/data/designs/ios-chime-swiftui.md +383 -0
  149. package/dist/data/designs/ios-chime.md +389 -0
  150. package/dist/data/designs/ios-chipotle-android.md +397 -0
  151. package/dist/data/designs/ios-chipotle-expo.md +301 -0
  152. package/dist/data/designs/ios-chipotle-swiftui.md +345 -0
  153. package/dist/data/designs/ios-chipotle.md +340 -0
  154. package/dist/data/designs/ios-citymapper-android.md +466 -0
  155. package/dist/data/designs/ios-citymapper-expo.md +420 -0
  156. package/dist/data/designs/ios-citymapper-swiftui.md +424 -0
  157. package/dist/data/designs/ios-citymapper.md +394 -0
  158. package/dist/data/designs/ios-claude-android.md +625 -0
  159. package/dist/data/designs/ios-claude-expo.md +671 -0
  160. package/dist/data/designs/ios-claude-swiftui.md +649 -0
  161. package/dist/data/designs/ios-claude.md +447 -0
  162. package/dist/data/designs/ios-clickup-android.md +484 -0
  163. package/dist/data/designs/ios-clickup-expo.md +423 -0
  164. package/dist/data/designs/ios-clickup-swiftui.md +416 -0
  165. package/dist/data/designs/ios-clickup.md +431 -0
  166. package/dist/data/designs/ios-clubhouse-android.md +524 -0
  167. package/dist/data/designs/ios-clubhouse-expo.md +425 -0
  168. package/dist/data/designs/ios-clubhouse-swiftui.md +447 -0
  169. package/dist/data/designs/ios-clubhouse.md +406 -0
  170. package/dist/data/designs/ios-coffee-meets-bagel-android.md +461 -0
  171. package/dist/data/designs/ios-coffee-meets-bagel-expo.md +372 -0
  172. package/dist/data/designs/ios-coffee-meets-bagel-swiftui.md +368 -0
  173. package/dist/data/designs/ios-coffee-meets-bagel.md +376 -0
  174. package/dist/data/designs/ios-coinbase-android.md +611 -0
  175. package/dist/data/designs/ios-coinbase-expo.md +500 -0
  176. package/dist/data/designs/ios-coinbase-swiftui.md +490 -0
  177. package/dist/data/designs/ios-coinbase.md +409 -0
  178. package/dist/data/designs/ios-copilot-android.md +625 -0
  179. package/dist/data/designs/ios-copilot-expo.md +423 -0
  180. package/dist/data/designs/ios-copilot-swiftui.md +471 -0
  181. package/dist/data/designs/ios-copilot.md +367 -0
  182. package/dist/data/designs/ios-craft-android.md +459 -0
  183. package/dist/data/designs/ios-craft-expo.md +417 -0
  184. package/dist/data/designs/ios-craft-swiftui.md +449 -0
  185. package/dist/data/designs/ios-craft.md +449 -0
  186. package/dist/data/designs/ios-crunchyroll-android.md +432 -0
  187. package/dist/data/designs/ios-crunchyroll-expo.md +388 -0
  188. package/dist/data/designs/ios-crunchyroll-swiftui.md +417 -0
  189. package/dist/data/designs/ios-crunchyroll.md +388 -0
  190. package/dist/data/designs/ios-crypto-com-android.md +461 -0
  191. package/dist/data/designs/ios-crypto-com-expo.md +404 -0
  192. package/dist/data/designs/ios-crypto-com-swiftui.md +419 -0
  193. package/dist/data/designs/ios-crypto-com.md +410 -0
  194. package/dist/data/designs/ios-deepseek-android.md +471 -0
  195. package/dist/data/designs/ios-deepseek-expo.md +391 -0
  196. package/dist/data/designs/ios-deepseek-swiftui.md +354 -0
  197. package/dist/data/designs/ios-deepseek.md +393 -0
  198. package/dist/data/designs/ios-deezer-android.md +475 -0
  199. package/dist/data/designs/ios-deezer-expo.md +400 -0
  200. package/dist/data/designs/ios-deezer-swiftui.md +430 -0
  201. package/dist/data/designs/ios-deezer.md +388 -0
  202. package/dist/data/designs/ios-deliveroo-android.md +493 -0
  203. package/dist/data/designs/ios-deliveroo-expo.md +424 -0
  204. package/dist/data/designs/ios-deliveroo-swiftui.md +398 -0
  205. package/dist/data/designs/ios-deliveroo.md +420 -0
  206. package/dist/data/designs/ios-delta-android.md +439 -0
  207. package/dist/data/designs/ios-delta-expo.md +381 -0
  208. package/dist/data/designs/ios-delta-swiftui.md +400 -0
  209. package/dist/data/designs/ios-delta.md +397 -0
  210. package/dist/data/designs/ios-discord-android.md +611 -0
  211. package/dist/data/designs/ios-discord-expo.md +618 -0
  212. package/dist/data/designs/ios-discord-swiftui.md +630 -0
  213. package/dist/data/designs/ios-discord.md +451 -0
  214. package/dist/data/designs/ios-disney-plus-android.md +464 -0
  215. package/dist/data/designs/ios-disney-plus-expo.md +358 -0
  216. package/dist/data/designs/ios-disney-plus-swiftui.md +412 -0
  217. package/dist/data/designs/ios-disney-plus.md +355 -0
  218. package/dist/data/designs/ios-dominos-android.md +417 -0
  219. package/dist/data/designs/ios-dominos-expo.md +316 -0
  220. package/dist/data/designs/ios-dominos-swiftui.md +340 -0
  221. package/dist/data/designs/ios-dominos.md +347 -0
  222. package/dist/data/designs/ios-doordash-android.md +527 -0
  223. package/dist/data/designs/ios-doordash-expo.md +323 -0
  224. package/dist/data/designs/ios-doordash-swiftui.md +301 -0
  225. package/dist/data/designs/ios-doordash.md +393 -0
  226. package/dist/data/designs/ios-dropbox-android.md +522 -0
  227. package/dist/data/designs/ios-dropbox-expo.md +393 -0
  228. package/dist/data/designs/ios-dropbox-swiftui.md +400 -0
  229. package/dist/data/designs/ios-dropbox.md +374 -0
  230. package/dist/data/designs/ios-duolingo-android.md +641 -0
  231. package/dist/data/designs/ios-duolingo-expo.md +597 -0
  232. package/dist/data/designs/ios-duolingo-swiftui.md +539 -0
  233. package/dist/data/designs/ios-duolingo.md +409 -0
  234. package/dist/data/designs/ios-ebay-android.md +436 -0
  235. package/dist/data/designs/ios-ebay-expo.md +344 -0
  236. package/dist/data/designs/ios-ebay-swiftui.md +308 -0
  237. package/dist/data/designs/ios-ebay.md +355 -0
  238. package/dist/data/designs/ios-espn-android.md +468 -0
  239. package/dist/data/designs/ios-espn-expo.md +387 -0
  240. package/dist/data/designs/ios-espn-swiftui.md +410 -0
  241. package/dist/data/designs/ios-espn.md +384 -0
  242. package/dist/data/designs/ios-etsy-android.md +439 -0
  243. package/dist/data/designs/ios-etsy-expo.md +351 -0
  244. package/dist/data/designs/ios-etsy-swiftui.md +296 -0
  245. package/dist/data/designs/ios-etsy.md +355 -0
  246. package/dist/data/designs/ios-evernote-android.md +419 -0
  247. package/dist/data/designs/ios-evernote-expo.md +379 -0
  248. package/dist/data/designs/ios-evernote-swiftui.md +380 -0
  249. package/dist/data/designs/ios-evernote.md +416 -0
  250. package/dist/data/designs/ios-expedia-android.md +451 -0
  251. package/dist/data/designs/ios-expedia-expo.md +433 -0
  252. package/dist/data/designs/ios-expedia-swiftui.md +399 -0
  253. package/dist/data/designs/ios-expedia.md +431 -0
  254. package/dist/data/designs/ios-facebook-android.md +628 -0
  255. package/dist/data/designs/ios-facebook-expo.md +471 -0
  256. package/dist/data/designs/ios-facebook-swiftui.md +459 -0
  257. package/dist/data/designs/ios-facebook.md +452 -0
  258. package/dist/data/designs/ios-feeld-android.md +431 -0
  259. package/dist/data/designs/ios-feeld-expo.md +379 -0
  260. package/dist/data/designs/ios-feeld-swiftui.md +401 -0
  261. package/dist/data/designs/ios-feeld.md +378 -0
  262. package/dist/data/designs/ios-fidelity-android.md +426 -0
  263. package/dist/data/designs/ios-fidelity-expo.md +396 -0
  264. package/dist/data/designs/ios-fidelity-swiftui.md +398 -0
  265. package/dist/data/designs/ios-fidelity.md +387 -0
  266. package/dist/data/designs/ios-figma-android.md +578 -0
  267. package/dist/data/designs/ios-figma-expo.md +504 -0
  268. package/dist/data/designs/ios-figma-swiftui.md +542 -0
  269. package/dist/data/designs/ios-figma.md +404 -0
  270. package/dist/data/designs/ios-fitbit-android.md +439 -0
  271. package/dist/data/designs/ios-fitbit-expo.md +389 -0
  272. package/dist/data/designs/ios-fitbit-swiftui.md +380 -0
  273. package/dist/data/designs/ios-fitbit.md +396 -0
  274. package/dist/data/designs/ios-flickr-android.md +506 -0
  275. package/dist/data/designs/ios-flickr-expo.md +434 -0
  276. package/dist/data/designs/ios-flickr-swiftui.md +421 -0
  277. package/dist/data/designs/ios-flickr.md +394 -0
  278. package/dist/data/designs/ios-flighty-android.md +418 -0
  279. package/dist/data/designs/ios-flighty-expo.md +353 -0
  280. package/dist/data/designs/ios-flighty-swiftui.md +337 -0
  281. package/dist/data/designs/ios-flighty.md +357 -0
  282. package/dist/data/designs/ios-flo-android.md +447 -0
  283. package/dist/data/designs/ios-flo-expo.md +363 -0
  284. package/dist/data/designs/ios-flo-swiftui.md +355 -0
  285. package/dist/data/designs/ios-flo.md +351 -0
  286. package/dist/data/designs/ios-garmin-connect-android.md +531 -0
  287. package/dist/data/designs/ios-garmin-connect-expo.md +429 -0
  288. package/dist/data/designs/ios-garmin-connect-swiftui.md +459 -0
  289. package/dist/data/designs/ios-garmin-connect.md +419 -0
  290. package/dist/data/designs/ios-gas-android.md +438 -0
  291. package/dist/data/designs/ios-gas-expo.md +350 -0
  292. package/dist/data/designs/ios-gas-swiftui.md +329 -0
  293. package/dist/data/designs/ios-gas.md +387 -0
  294. package/dist/data/designs/ios-gemini-android.md +568 -0
  295. package/dist/data/designs/ios-gemini-expo.md +416 -0
  296. package/dist/data/designs/ios-gemini-swiftui.md +424 -0
  297. package/dist/data/designs/ios-gemini.md +351 -0
  298. package/dist/data/designs/ios-github-android.md +507 -0
  299. package/dist/data/designs/ios-github-expo.md +486 -0
  300. package/dist/data/designs/ios-github-swiftui.md +459 -0
  301. package/dist/data/designs/ios-github.md +394 -0
  302. package/dist/data/designs/ios-gmail-android.md +548 -0
  303. package/dist/data/designs/ios-gmail-expo.md +457 -0
  304. package/dist/data/designs/ios-gmail-swiftui.md +470 -0
  305. package/dist/data/designs/ios-gmail.md +441 -0
  306. package/dist/data/designs/ios-goodreads-android.md +436 -0
  307. package/dist/data/designs/ios-goodreads-expo.md +407 -0
  308. package/dist/data/designs/ios-goodreads-swiftui.md +378 -0
  309. package/dist/data/designs/ios-goodreads.md +385 -0
  310. package/dist/data/designs/ios-google-calendar-android.md +565 -0
  311. package/dist/data/designs/ios-google-calendar-expo.md +616 -0
  312. package/dist/data/designs/ios-google-calendar-swiftui.md +585 -0
  313. package/dist/data/designs/ios-google-calendar.md +431 -0
  314. package/dist/data/designs/ios-google-maps-android.md +614 -0
  315. package/dist/data/designs/ios-google-maps-expo.md +515 -0
  316. package/dist/data/designs/ios-google-maps-swiftui.md +484 -0
  317. package/dist/data/designs/ios-google-maps.md +451 -0
  318. package/dist/data/designs/ios-grammarly-android.md +449 -0
  319. package/dist/data/designs/ios-grammarly-expo.md +383 -0
  320. package/dist/data/designs/ios-grammarly-swiftui.md +381 -0
  321. package/dist/data/designs/ios-grammarly.md +392 -0
  322. package/dist/data/designs/ios-grindr-android.md +494 -0
  323. package/dist/data/designs/ios-grindr-expo.md +358 -0
  324. package/dist/data/designs/ios-grindr-swiftui.md +357 -0
  325. package/dist/data/designs/ios-grindr.md +356 -0
  326. package/dist/data/designs/ios-grok-android.md +471 -0
  327. package/dist/data/designs/ios-grok-expo.md +388 -0
  328. package/dist/data/designs/ios-grok-swiftui.md +397 -0
  329. package/dist/data/designs/ios-grok.md +357 -0
  330. package/dist/data/designs/ios-groupme-android.md +551 -0
  331. package/dist/data/designs/ios-groupme-expo.md +442 -0
  332. package/dist/data/designs/ios-groupme-swiftui.md +439 -0
  333. package/dist/data/designs/ios-groupme.md +424 -0
  334. package/dist/data/designs/ios-grubhub-android.md +506 -0
  335. package/dist/data/designs/ios-grubhub-expo.md +428 -0
  336. package/dist/data/designs/ios-grubhub-swiftui.md +408 -0
  337. package/dist/data/designs/ios-grubhub.md +427 -0
  338. package/dist/data/designs/ios-happn-android.md +464 -0
  339. package/dist/data/designs/ios-happn-expo.md +411 -0
  340. package/dist/data/designs/ios-happn-swiftui.md +401 -0
  341. package/dist/data/designs/ios-happn.md +400 -0
  342. package/dist/data/designs/ios-headspace-android.md +688 -0
  343. package/dist/data/designs/ios-headspace-expo.md +574 -0
  344. package/dist/data/designs/ios-headspace-swiftui.md +498 -0
  345. package/dist/data/designs/ios-headspace.md +430 -0
  346. package/dist/data/designs/ios-hevy-android.md +473 -0
  347. package/dist/data/designs/ios-hevy-expo.md +405 -0
  348. package/dist/data/designs/ios-hevy-swiftui.md +367 -0
  349. package/dist/data/designs/ios-hevy.md +410 -0
  350. package/dist/data/designs/ios-hinge-android.md +743 -0
  351. package/dist/data/designs/ios-hinge-expo.md +580 -0
  352. package/dist/data/designs/ios-hinge-swiftui.md +512 -0
  353. package/dist/data/designs/ios-hinge.md +405 -0
  354. package/dist/data/designs/ios-hopper-android.md +440 -0
  355. package/dist/data/designs/ios-hopper-expo.md +353 -0
  356. package/dist/data/designs/ios-hopper-swiftui.md +340 -0
  357. package/dist/data/designs/ios-hopper.md +354 -0
  358. package/dist/data/designs/ios-hulu-android.md +435 -0
  359. package/dist/data/designs/ios-hulu-expo.md +331 -0
  360. package/dist/data/designs/ios-hulu-swiftui.md +374 -0
  361. package/dist/data/designs/ios-hulu.md +353 -0
  362. package/dist/data/designs/ios-iheartradio-android.md +481 -0
  363. package/dist/data/designs/ios-iheartradio-expo.md +417 -0
  364. package/dist/data/designs/ios-iheartradio-swiftui.md +423 -0
  365. package/dist/data/designs/ios-iheartradio.md +381 -0
  366. package/dist/data/designs/ios-imessage-android.md +426 -0
  367. package/dist/data/designs/ios-imessage-expo.md +384 -0
  368. package/dist/data/designs/ios-imessage-swiftui.md +378 -0
  369. package/dist/data/designs/ios-imessage.md +394 -0
  370. package/dist/data/designs/ios-instacart-android.md +471 -0
  371. package/dist/data/designs/ios-instacart-expo.md +349 -0
  372. package/dist/data/designs/ios-instacart-swiftui.md +378 -0
  373. package/dist/data/designs/ios-instacart.md +360 -0
  374. package/dist/data/designs/ios-instagram-android.md +646 -0
  375. package/dist/data/designs/ios-instagram-expo.md +310 -0
  376. package/dist/data/designs/ios-instagram-swiftui.md +333 -0
  377. package/dist/data/designs/ios-instagram.md +376 -0
  378. package/dist/data/designs/ios-jira-android.md +432 -0
  379. package/dist/data/designs/ios-jira-expo.md +375 -0
  380. package/dist/data/designs/ios-jira-swiftui.md +433 -0
  381. package/dist/data/designs/ios-jira.md +424 -0
  382. package/dist/data/designs/ios-kakaotalk-android.md +491 -0
  383. package/dist/data/designs/ios-kakaotalk-expo.md +418 -0
  384. package/dist/data/designs/ios-kakaotalk-swiftui.md +406 -0
  385. package/dist/data/designs/ios-kakaotalk.md +414 -0
  386. package/dist/data/designs/ios-kayak-android.md +466 -0
  387. package/dist/data/designs/ios-kayak-expo.md +407 -0
  388. package/dist/data/designs/ios-kayak-swiftui.md +426 -0
  389. package/dist/data/designs/ios-kayak.md +392 -0
  390. package/dist/data/designs/ios-kick-android.md +487 -0
  391. package/dist/data/designs/ios-kick-expo.md +434 -0
  392. package/dist/data/designs/ios-kick-swiftui.md +429 -0
  393. package/dist/data/designs/ios-kick.md +389 -0
  394. package/dist/data/designs/ios-kik-android.md +433 -0
  395. package/dist/data/designs/ios-kik-expo.md +363 -0
  396. package/dist/data/designs/ios-kik-swiftui.md +363 -0
  397. package/dist/data/designs/ios-kik.md +392 -0
  398. package/dist/data/designs/ios-kindle-android.md +439 -0
  399. package/dist/data/designs/ios-kindle-expo.md +356 -0
  400. package/dist/data/designs/ios-kindle-swiftui.md +372 -0
  401. package/dist/data/designs/ios-kindle.md +369 -0
  402. package/dist/data/designs/ios-klarna-android.md +420 -0
  403. package/dist/data/designs/ios-klarna-expo.md +349 -0
  404. package/dist/data/designs/ios-klarna-swiftui.md +360 -0
  405. package/dist/data/designs/ios-klarna.md +356 -0
  406. package/dist/data/designs/ios-lemon8-android.md +492 -0
  407. package/dist/data/designs/ios-lemon8-expo.md +413 -0
  408. package/dist/data/designs/ios-lemon8-swiftui.md +428 -0
  409. package/dist/data/designs/ios-lemon8.md +378 -0
  410. package/dist/data/designs/ios-life360-android.md +474 -0
  411. package/dist/data/designs/ios-life360-expo.md +375 -0
  412. package/dist/data/designs/ios-life360-swiftui.md +390 -0
  413. package/dist/data/designs/ios-life360.md +402 -0
  414. package/dist/data/designs/ios-line-android.md +517 -0
  415. package/dist/data/designs/ios-line-expo.md +402 -0
  416. package/dist/data/designs/ios-line-swiftui.md +361 -0
  417. package/dist/data/designs/ios-line.md +362 -0
  418. package/dist/data/designs/ios-linear-android.md +457 -0
  419. package/dist/data/designs/ios-linear-expo.md +367 -0
  420. package/dist/data/designs/ios-linear-swiftui.md +401 -0
  421. package/dist/data/designs/ios-linear.md +368 -0
  422. package/dist/data/designs/ios-linkedin-android.md +620 -0
  423. package/dist/data/designs/ios-linkedin-expo.md +469 -0
  424. package/dist/data/designs/ios-linkedin-swiftui.md +472 -0
  425. package/dist/data/designs/ios-linkedin.md +444 -0
  426. package/dist/data/designs/ios-locket-android.md +500 -0
  427. package/dist/data/designs/ios-locket-expo.md +375 -0
  428. package/dist/data/designs/ios-locket-swiftui.md +375 -0
  429. package/dist/data/designs/ios-locket.md +381 -0
  430. package/dist/data/designs/ios-lyft-android.md +406 -0
  431. package/dist/data/designs/ios-lyft-expo.md +333 -0
  432. package/dist/data/designs/ios-lyft-swiftui.md +315 -0
  433. package/dist/data/designs/ios-lyft.md +337 -0
  434. package/dist/data/designs/ios-marriott-bonvoy-android.md +488 -0
  435. package/dist/data/designs/ios-marriott-bonvoy-expo.md +412 -0
  436. package/dist/data/designs/ios-marriott-bonvoy-swiftui.md +461 -0
  437. package/dist/data/designs/ios-marriott-bonvoy.md +379 -0
  438. package/dist/data/designs/ios-mastodon-android.md +476 -0
  439. package/dist/data/designs/ios-mastodon-expo.md +379 -0
  440. package/dist/data/designs/ios-mastodon-swiftui.md +349 -0
  441. package/dist/data/designs/ios-mastodon.md +337 -0
  442. package/dist/data/designs/ios-match-android.md +496 -0
  443. package/dist/data/designs/ios-match-expo.md +393 -0
  444. package/dist/data/designs/ios-match-swiftui.md +450 -0
  445. package/dist/data/designs/ios-match.md +382 -0
  446. package/dist/data/designs/ios-max-android.md +454 -0
  447. package/dist/data/designs/ios-max-expo.md +342 -0
  448. package/dist/data/designs/ios-max-swiftui.md +332 -0
  449. package/dist/data/designs/ios-max.md +352 -0
  450. package/dist/data/designs/ios-mcdonalds-android.md +497 -0
  451. package/dist/data/designs/ios-mcdonalds-expo.md +382 -0
  452. package/dist/data/designs/ios-mcdonalds-swiftui.md +394 -0
  453. package/dist/data/designs/ios-mcdonalds.md +410 -0
  454. package/dist/data/designs/ios-messenger-android.md +523 -0
  455. package/dist/data/designs/ios-messenger-expo.md +379 -0
  456. package/dist/data/designs/ios-messenger-swiftui.md +369 -0
  457. package/dist/data/designs/ios-messenger.md +361 -0
  458. package/dist/data/designs/ios-microsoft-teams-android.md +446 -0
  459. package/dist/data/designs/ios-microsoft-teams-expo.md +362 -0
  460. package/dist/data/designs/ios-microsoft-teams-swiftui.md +384 -0
  461. package/dist/data/designs/ios-microsoft-teams.md +359 -0
  462. package/dist/data/designs/ios-midjourney-android.md +503 -0
  463. package/dist/data/designs/ios-midjourney-expo.md +406 -0
  464. package/dist/data/designs/ios-midjourney-swiftui.md +376 -0
  465. package/dist/data/designs/ios-midjourney.md +407 -0
  466. package/dist/data/designs/ios-miro-android.md +475 -0
  467. package/dist/data/designs/ios-miro-expo.md +421 -0
  468. package/dist/data/designs/ios-miro-swiftui.md +407 -0
  469. package/dist/data/designs/ios-miro.md +424 -0
  470. package/dist/data/designs/ios-monday-android.md +426 -0
  471. package/dist/data/designs/ios-monday-expo.md +382 -0
  472. package/dist/data/designs/ios-monday-swiftui.md +386 -0
  473. package/dist/data/designs/ios-monday.md +415 -0
  474. package/dist/data/designs/ios-monzo-android.md +423 -0
  475. package/dist/data/designs/ios-monzo-expo.md +391 -0
  476. package/dist/data/designs/ios-monzo-swiftui.md +371 -0
  477. package/dist/data/designs/ios-monzo.md +382 -0
  478. package/dist/data/designs/ios-myfitnesspal-android.md +631 -0
  479. package/dist/data/designs/ios-myfitnesspal-expo.md +489 -0
  480. package/dist/data/designs/ios-myfitnesspal-swiftui.md +500 -0
  481. package/dist/data/designs/ios-myfitnesspal.md +408 -0
  482. package/dist/data/designs/ios-netflix-android.md +570 -0
  483. package/dist/data/designs/ios-netflix-expo.md +528 -0
  484. package/dist/data/designs/ios-netflix-swiftui.md +543 -0
  485. package/dist/data/designs/ios-netflix.md +476 -0
  486. package/dist/data/designs/ios-nextdoor-android.md +399 -0
  487. package/dist/data/designs/ios-nextdoor-expo.md +317 -0
  488. package/dist/data/designs/ios-nextdoor-swiftui.md +343 -0
  489. package/dist/data/designs/ios-nextdoor.md +332 -0
  490. package/dist/data/designs/ios-nike-run-club-android.md +598 -0
  491. package/dist/data/designs/ios-nike-run-club-expo.md +459 -0
  492. package/dist/data/designs/ios-nike-run-club-swiftui.md +474 -0
  493. package/dist/data/designs/ios-nike-run-club.md +400 -0
  494. package/dist/data/designs/ios-noom-android.md +455 -0
  495. package/dist/data/designs/ios-noom-expo.md +362 -0
  496. package/dist/data/designs/ios-noom-swiftui.md +369 -0
  497. package/dist/data/designs/ios-noom.md +404 -0
  498. package/dist/data/designs/ios-notion-android.md +575 -0
  499. package/dist/data/designs/ios-notion-expo.md +543 -0
  500. package/dist/data/designs/ios-notion-swiftui.md +562 -0
  501. package/dist/data/designs/ios-notion.md +506 -0
  502. package/dist/data/designs/ios-nubank-android.md +447 -0
  503. package/dist/data/designs/ios-nubank-expo.md +391 -0
  504. package/dist/data/designs/ios-nubank-swiftui.md +391 -0
  505. package/dist/data/designs/ios-nubank.md +388 -0
  506. package/dist/data/designs/ios-obsidian-android.md +456 -0
  507. package/dist/data/designs/ios-obsidian-expo.md +401 -0
  508. package/dist/data/designs/ios-obsidian-swiftui.md +412 -0
  509. package/dist/data/designs/ios-obsidian.md +363 -0
  510. package/dist/data/designs/ios-okcupid-android.md +496 -0
  511. package/dist/data/designs/ios-okcupid-expo.md +378 -0
  512. package/dist/data/designs/ios-okcupid-swiftui.md +343 -0
  513. package/dist/data/designs/ios-okcupid.md +364 -0
  514. package/dist/data/designs/ios-opentable-android.md +426 -0
  515. package/dist/data/designs/ios-opentable-expo.md +350 -0
  516. package/dist/data/designs/ios-opentable-swiftui.md +328 -0
  517. package/dist/data/designs/ios-opentable.md +411 -0
  518. package/dist/data/designs/ios-oura-android.md +426 -0
  519. package/dist/data/designs/ios-oura-expo.md +353 -0
  520. package/dist/data/designs/ios-oura-swiftui.md +327 -0
  521. package/dist/data/designs/ios-oura.md +356 -0
  522. package/dist/data/designs/ios-overcast-android.md +508 -0
  523. package/dist/data/designs/ios-overcast-expo.md +420 -0
  524. package/dist/data/designs/ios-overcast-swiftui.md +427 -0
  525. package/dist/data/designs/ios-overcast.md +414 -0
  526. package/dist/data/designs/ios-pandora-android.md +477 -0
  527. package/dist/data/designs/ios-pandora-expo.md +406 -0
  528. package/dist/data/designs/ios-pandora-swiftui.md +413 -0
  529. package/dist/data/designs/ios-pandora.md +366 -0
  530. package/dist/data/designs/ios-panera-android.md +414 -0
  531. package/dist/data/designs/ios-panera-expo.md +352 -0
  532. package/dist/data/designs/ios-panera-swiftui.md +369 -0
  533. package/dist/data/designs/ios-panera.md +412 -0
  534. package/dist/data/designs/ios-paramount-plus-android.md +415 -0
  535. package/dist/data/designs/ios-paramount-plus-expo.md +363 -0
  536. package/dist/data/designs/ios-paramount-plus-swiftui.md +372 -0
  537. package/dist/data/designs/ios-paramount-plus.md +400 -0
  538. package/dist/data/designs/ios-paypal-android.md +535 -0
  539. package/dist/data/designs/ios-paypal-expo.md +429 -0
  540. package/dist/data/designs/ios-paypal-swiftui.md +466 -0
  541. package/dist/data/designs/ios-paypal.md +393 -0
  542. package/dist/data/designs/ios-peacock-android.md +453 -0
  543. package/dist/data/designs/ios-peacock-expo.md +393 -0
  544. package/dist/data/designs/ios-peacock-swiftui.md +420 -0
  545. package/dist/data/designs/ios-peacock.md +411 -0
  546. package/dist/data/designs/ios-peloton-android.md +470 -0
  547. package/dist/data/designs/ios-peloton-expo.md +401 -0
  548. package/dist/data/designs/ios-peloton-swiftui.md +409 -0
  549. package/dist/data/designs/ios-peloton.md +415 -0
  550. package/dist/data/designs/ios-perplexity-android.md +553 -0
  551. package/dist/data/designs/ios-perplexity-expo.md +703 -0
  552. package/dist/data/designs/ios-perplexity-swiftui.md +602 -0
  553. package/dist/data/designs/ios-perplexity.md +453 -0
  554. package/dist/data/designs/ios-pinterest-android.md +551 -0
  555. package/dist/data/designs/ios-pinterest-expo.md +466 -0
  556. package/dist/data/designs/ios-pinterest-swiftui.md +464 -0
  557. package/dist/data/designs/ios-pinterest.md +427 -0
  558. package/dist/data/designs/ios-plenty-of-fish-android.md +462 -0
  559. package/dist/data/designs/ios-plenty-of-fish-expo.md +380 -0
  560. package/dist/data/designs/ios-plenty-of-fish-swiftui.md +429 -0
  561. package/dist/data/designs/ios-plenty-of-fish.md +387 -0
  562. package/dist/data/designs/ios-plex-android.md +403 -0
  563. package/dist/data/designs/ios-plex-expo.md +333 -0
  564. package/dist/data/designs/ios-plex-swiftui.md +349 -0
  565. package/dist/data/designs/ios-plex.md +379 -0
  566. package/dist/data/designs/ios-pluto-tv-android.md +413 -0
  567. package/dist/data/designs/ios-pluto-tv-expo.md +379 -0
  568. package/dist/data/designs/ios-pluto-tv-swiftui.md +411 -0
  569. package/dist/data/designs/ios-pluto-tv.md +362 -0
  570. package/dist/data/designs/ios-pocket-casts-android.md +492 -0
  571. package/dist/data/designs/ios-pocket-casts-expo.md +430 -0
  572. package/dist/data/designs/ios-pocket-casts-swiftui.md +479 -0
  573. package/dist/data/designs/ios-pocket-casts.md +427 -0
  574. package/dist/data/designs/ios-postman-android.md +472 -0
  575. package/dist/data/designs/ios-postman-expo.md +372 -0
  576. package/dist/data/designs/ios-postman-swiftui.md +377 -0
  577. package/dist/data/designs/ios-postman.md +405 -0
  578. package/dist/data/designs/ios-prime-video-android.md +447 -0
  579. package/dist/data/designs/ios-prime-video-expo.md +365 -0
  580. package/dist/data/designs/ios-prime-video-swiftui.md +333 -0
  581. package/dist/data/designs/ios-prime-video.md +351 -0
  582. package/dist/data/designs/ios-quora-android.md +513 -0
  583. package/dist/data/designs/ios-quora-expo.md +362 -0
  584. package/dist/data/designs/ios-quora-swiftui.md +375 -0
  585. package/dist/data/designs/ios-quora.md +359 -0
  586. package/dist/data/designs/ios-raya-android.md +401 -0
  587. package/dist/data/designs/ios-raya-expo.md +366 -0
  588. package/dist/data/designs/ios-raya-swiftui.md +393 -0
  589. package/dist/data/designs/ios-raya.md +366 -0
  590. package/dist/data/designs/ios-reddit-android.md +605 -0
  591. package/dist/data/designs/ios-reddit-expo.md +553 -0
  592. package/dist/data/designs/ios-reddit-swiftui.md +514 -0
  593. package/dist/data/designs/ios-reddit.md +460 -0
  594. package/dist/data/designs/ios-resy-android.md +430 -0
  595. package/dist/data/designs/ios-resy-expo.md +344 -0
  596. package/dist/data/designs/ios-resy-swiftui.md +330 -0
  597. package/dist/data/designs/ios-resy.md +412 -0
  598. package/dist/data/designs/ios-revolut-android.md +433 -0
  599. package/dist/data/designs/ios-revolut-expo.md +379 -0
  600. package/dist/data/designs/ios-revolut-swiftui.md +372 -0
  601. package/dist/data/designs/ios-revolut.md +353 -0
  602. package/dist/data/designs/ios-robinhood-android.md +587 -0
  603. package/dist/data/designs/ios-robinhood-expo.md +416 -0
  604. package/dist/data/designs/ios-robinhood-swiftui.md +431 -0
  605. package/dist/data/designs/ios-robinhood.md +380 -0
  606. package/dist/data/designs/ios-runna-android.md +485 -0
  607. package/dist/data/designs/ios-runna-expo.md +388 -0
  608. package/dist/data/designs/ios-runna-swiftui.md +413 -0
  609. package/dist/data/designs/ios-runna.md +390 -0
  610. package/dist/data/designs/ios-shazam-android.md +436 -0
  611. package/dist/data/designs/ios-shazam-expo.md +348 -0
  612. package/dist/data/designs/ios-shazam-swiftui.md +394 -0
  613. package/dist/data/designs/ios-shazam.md +338 -0
  614. package/dist/data/designs/ios-signal-android.md +462 -0
  615. package/dist/data/designs/ios-signal-expo.md +361 -0
  616. package/dist/data/designs/ios-signal-swiftui.md +350 -0
  617. package/dist/data/designs/ios-signal.md +357 -0
  618. package/dist/data/designs/ios-skype-android.md +398 -0
  619. package/dist/data/designs/ios-skype-expo.md +368 -0
  620. package/dist/data/designs/ios-skype-swiftui.md +369 -0
  621. package/dist/data/designs/ios-skype.md +406 -0
  622. package/dist/data/designs/ios-skyscanner-android.md +451 -0
  623. package/dist/data/designs/ios-skyscanner-expo.md +423 -0
  624. package/dist/data/designs/ios-skyscanner-swiftui.md +419 -0
  625. package/dist/data/designs/ios-skyscanner.md +421 -0
  626. package/dist/data/designs/ios-slack-android.md +695 -0
  627. package/dist/data/designs/ios-slack-expo.md +601 -0
  628. package/dist/data/designs/ios-slack-swiftui.md +594 -0
  629. package/dist/data/designs/ios-slack.md +474 -0
  630. package/dist/data/designs/ios-sleep-cycle-android.md +436 -0
  631. package/dist/data/designs/ios-sleep-cycle-expo.md +380 -0
  632. package/dist/data/designs/ios-sleep-cycle-swiftui.md +409 -0
  633. package/dist/data/designs/ios-sleep-cycle.md +386 -0
  634. package/dist/data/designs/ios-snapchat-android.md +671 -0
  635. package/dist/data/designs/ios-snapchat-expo.md +528 -0
  636. package/dist/data/designs/ios-snapchat-swiftui.md +557 -0
  637. package/dist/data/designs/ios-snapchat.md +478 -0
  638. package/dist/data/designs/ios-sofi-android.md +446 -0
  639. package/dist/data/designs/ios-sofi-expo.md +387 -0
  640. package/dist/data/designs/ios-sofi-swiftui.md +379 -0
  641. package/dist/data/designs/ios-sofi.md +385 -0
  642. package/dist/data/designs/ios-soundcloud-android.md +488 -0
  643. package/dist/data/designs/ios-soundcloud-expo.md +364 -0
  644. package/dist/data/designs/ios-soundcloud-swiftui.md +399 -0
  645. package/dist/data/designs/ios-soundcloud.md +359 -0
  646. package/dist/data/designs/ios-southwest-android.md +446 -0
  647. package/dist/data/designs/ios-southwest-expo.md +389 -0
  648. package/dist/data/designs/ios-southwest-swiftui.md +405 -0
  649. package/dist/data/designs/ios-southwest.md +405 -0
  650. package/dist/data/designs/ios-spotify-android.md +427 -0
  651. package/dist/data/designs/ios-spotify-expo.md +321 -0
  652. package/dist/data/designs/ios-spotify-swiftui.md +312 -0
  653. package/dist/data/designs/ios-spotify.md +366 -0
  654. package/dist/data/designs/ios-starbucks-android.md +622 -0
  655. package/dist/data/designs/ios-starbucks-expo.md +497 -0
  656. package/dist/data/designs/ios-starbucks-swiftui.md +500 -0
  657. package/dist/data/designs/ios-starbucks.md +440 -0
  658. package/dist/data/designs/ios-strava-android.md +656 -0
  659. package/dist/data/designs/ios-strava-expo.md +501 -0
  660. package/dist/data/designs/ios-strava-swiftui.md +465 -0
  661. package/dist/data/designs/ios-strava.md +433 -0
  662. package/dist/data/designs/ios-strong-android.md +479 -0
  663. package/dist/data/designs/ios-strong-expo.md +396 -0
  664. package/dist/data/designs/ios-strong-swiftui.md +363 -0
  665. package/dist/data/designs/ios-strong.md +415 -0
  666. package/dist/data/designs/ios-substack-android.md +440 -0
  667. package/dist/data/designs/ios-substack-expo.md +395 -0
  668. package/dist/data/designs/ios-substack-swiftui.md +371 -0
  669. package/dist/data/designs/ios-substack.md +372 -0
  670. package/dist/data/designs/ios-swiggy-android.md +549 -0
  671. package/dist/data/designs/ios-swiggy-expo.md +443 -0
  672. package/dist/data/designs/ios-swiggy-swiftui.md +471 -0
  673. package/dist/data/designs/ios-swiggy.md +432 -0
  674. package/dist/data/designs/ios-taco-bell-android.md +529 -0
  675. package/dist/data/designs/ios-taco-bell-expo.md +407 -0
  676. package/dist/data/designs/ios-taco-bell-swiftui.md +419 -0
  677. package/dist/data/designs/ios-taco-bell.md +430 -0
  678. package/dist/data/designs/ios-telegram-android.md +676 -0
  679. package/dist/data/designs/ios-telegram-expo.md +594 -0
  680. package/dist/data/designs/ios-telegram-swiftui.md +518 -0
  681. package/dist/data/designs/ios-telegram.md +458 -0
  682. package/dist/data/designs/ios-the-league-android.md +454 -0
  683. package/dist/data/designs/ios-the-league-expo.md +391 -0
  684. package/dist/data/designs/ios-the-league-swiftui.md +409 -0
  685. package/dist/data/designs/ios-the-league.md +368 -0
  686. package/dist/data/designs/ios-things-3-android.md +421 -0
  687. package/dist/data/designs/ios-things-3-expo.md +351 -0
  688. package/dist/data/designs/ios-things-3-swiftui.md +359 -0
  689. package/dist/data/designs/ios-things-3.md +339 -0
  690. package/dist/data/designs/ios-threads-android.md +588 -0
  691. package/dist/data/designs/ios-threads-expo.md +468 -0
  692. package/dist/data/designs/ios-threads-swiftui.md +452 -0
  693. package/dist/data/designs/ios-threads.md +424 -0
  694. package/dist/data/designs/ios-threema-android.md +496 -0
  695. package/dist/data/designs/ios-threema-expo.md +415 -0
  696. package/dist/data/designs/ios-threema-swiftui.md +446 -0
  697. package/dist/data/designs/ios-threema.md +397 -0
  698. package/dist/data/designs/ios-tidal-android.md +398 -0
  699. package/dist/data/designs/ios-tidal-expo.md +323 -0
  700. package/dist/data/designs/ios-tidal-swiftui.md +340 -0
  701. package/dist/data/designs/ios-tidal.md +351 -0
  702. package/dist/data/designs/ios-tiktok-android.md +654 -0
  703. package/dist/data/designs/ios-tiktok-expo.md +578 -0
  704. package/dist/data/designs/ios-tiktok-swiftui.md +595 -0
  705. package/dist/data/designs/ios-tiktok.md +387 -0
  706. package/dist/data/designs/ios-tinder-android.md +681 -0
  707. package/dist/data/designs/ios-tinder-expo.md +512 -0
  708. package/dist/data/designs/ios-tinder-swiftui.md +497 -0
  709. package/dist/data/designs/ios-tinder.md +415 -0
  710. package/dist/data/designs/ios-todoist-android.md +711 -0
  711. package/dist/data/designs/ios-todoist-expo.md +607 -0
  712. package/dist/data/designs/ios-todoist-swiftui.md +573 -0
  713. package/dist/data/designs/ios-todoist.md +418 -0
  714. package/dist/data/designs/ios-trello-android.md +412 -0
  715. package/dist/data/designs/ios-trello-expo.md +332 -0
  716. package/dist/data/designs/ios-trello-swiftui.md +359 -0
  717. package/dist/data/designs/ios-trello.md +344 -0
  718. package/dist/data/designs/ios-tripadvisor-android.md +450 -0
  719. package/dist/data/designs/ios-tripadvisor-expo.md +322 -0
  720. package/dist/data/designs/ios-tripadvisor-swiftui.md +326 -0
  721. package/dist/data/designs/ios-tripadvisor.md +356 -0
  722. package/dist/data/designs/ios-tubi-android.md +453 -0
  723. package/dist/data/designs/ios-tubi-expo.md +419 -0
  724. package/dist/data/designs/ios-tubi-swiftui.md +463 -0
  725. package/dist/data/designs/ios-tubi.md +383 -0
  726. package/dist/data/designs/ios-tumblr-android.md +462 -0
  727. package/dist/data/designs/ios-tumblr-expo.md +374 -0
  728. package/dist/data/designs/ios-tumblr-swiftui.md +380 -0
  729. package/dist/data/designs/ios-tumblr.md +337 -0
  730. package/dist/data/designs/ios-turo-android.md +500 -0
  731. package/dist/data/designs/ios-turo-expo.md +454 -0
  732. package/dist/data/designs/ios-turo-swiftui.md +447 -0
  733. package/dist/data/designs/ios-turo.md +392 -0
  734. package/dist/data/designs/ios-twitch-android.md +412 -0
  735. package/dist/data/designs/ios-twitch-expo.md +342 -0
  736. package/dist/data/designs/ios-twitch-swiftui.md +328 -0
  737. package/dist/data/designs/ios-twitch.md +354 -0
  738. package/dist/data/designs/ios-uber-android.md +637 -0
  739. package/dist/data/designs/ios-uber-eats-android.md +502 -0
  740. package/dist/data/designs/ios-uber-eats-expo.md +407 -0
  741. package/dist/data/designs/ios-uber-eats-swiftui.md +393 -0
  742. package/dist/data/designs/ios-uber-eats.md +353 -0
  743. package/dist/data/designs/ios-uber-expo.md +512 -0
  744. package/dist/data/designs/ios-uber-swiftui.md +483 -0
  745. package/dist/data/designs/ios-uber.md +395 -0
  746. package/dist/data/designs/ios-united-airlines-android.md +494 -0
  747. package/dist/data/designs/ios-united-airlines-expo.md +408 -0
  748. package/dist/data/designs/ios-united-airlines-swiftui.md +453 -0
  749. package/dist/data/designs/ios-united-airlines.md +388 -0
  750. package/dist/data/designs/ios-venmo-android.md +654 -0
  751. package/dist/data/designs/ios-venmo-expo.md +458 -0
  752. package/dist/data/designs/ios-venmo-swiftui.md +469 -0
  753. package/dist/data/designs/ios-venmo.md +436 -0
  754. package/dist/data/designs/ios-vercel-android.md +454 -0
  755. package/dist/data/designs/ios-vercel-expo.md +387 -0
  756. package/dist/data/designs/ios-vercel-swiftui.md +374 -0
  757. package/dist/data/designs/ios-vercel.md +399 -0
  758. package/dist/data/designs/ios-vero-android.md +498 -0
  759. package/dist/data/designs/ios-vero-expo.md +376 -0
  760. package/dist/data/designs/ios-vero-swiftui.md +374 -0
  761. package/dist/data/designs/ios-vero.md +394 -0
  762. package/dist/data/designs/ios-viber-android.md +377 -0
  763. package/dist/data/designs/ios-viber-expo.md +375 -0
  764. package/dist/data/designs/ios-viber-swiftui.md +378 -0
  765. package/dist/data/designs/ios-viber.md +403 -0
  766. package/dist/data/designs/ios-vimeo-android.md +465 -0
  767. package/dist/data/designs/ios-vimeo-expo.md +347 -0
  768. package/dist/data/designs/ios-vimeo-swiftui.md +383 -0
  769. package/dist/data/designs/ios-vimeo.md +403 -0
  770. package/dist/data/designs/ios-vrbo-android.md +488 -0
  771. package/dist/data/designs/ios-vrbo-expo.md +395 -0
  772. package/dist/data/designs/ios-vrbo-swiftui.md +421 -0
  773. package/dist/data/designs/ios-vrbo.md +383 -0
  774. package/dist/data/designs/ios-vsco-android.md +490 -0
  775. package/dist/data/designs/ios-vsco-expo.md +413 -0
  776. package/dist/data/designs/ios-vsco-swiftui.md +449 -0
  777. package/dist/data/designs/ios-vsco.md +412 -0
  778. package/dist/data/designs/ios-walmart-android.md +479 -0
  779. package/dist/data/designs/ios-walmart-expo.md +370 -0
  780. package/dist/data/designs/ios-walmart-swiftui.md +387 -0
  781. package/dist/data/designs/ios-walmart.md +366 -0
  782. package/dist/data/designs/ios-waze-android.md +695 -0
  783. package/dist/data/designs/ios-waze-expo.md +587 -0
  784. package/dist/data/designs/ios-waze-swiftui.md +601 -0
  785. package/dist/data/designs/ios-waze.md +453 -0
  786. package/dist/data/designs/ios-webull-android.md +429 -0
  787. package/dist/data/designs/ios-webull-expo.md +384 -0
  788. package/dist/data/designs/ios-webull-swiftui.md +406 -0
  789. package/dist/data/designs/ios-webull.md +375 -0
  790. package/dist/data/designs/ios-wechat-android.md +545 -0
  791. package/dist/data/designs/ios-wechat-expo.md +398 -0
  792. package/dist/data/designs/ios-wechat-swiftui.md +394 -0
  793. package/dist/data/designs/ios-wechat.md +363 -0
  794. package/dist/data/designs/ios-whatsapp-android.md +568 -0
  795. package/dist/data/designs/ios-whatsapp-expo.md +502 -0
  796. package/dist/data/designs/ios-whatsapp-swiftui.md +483 -0
  797. package/dist/data/designs/ios-whatsapp.md +425 -0
  798. package/dist/data/designs/ios-whoop-android.md +635 -0
  799. package/dist/data/designs/ios-whoop-expo.md +562 -0
  800. package/dist/data/designs/ios-whoop-swiftui.md +553 -0
  801. package/dist/data/designs/ios-whoop.md +419 -0
  802. package/dist/data/designs/ios-wise-android.md +428 -0
  803. package/dist/data/designs/ios-wise-expo.md +357 -0
  804. package/dist/data/designs/ios-wise-swiftui.md +356 -0
  805. package/dist/data/designs/ios-wise.md +361 -0
  806. package/dist/data/designs/ios-x-twitter-android.md +618 -0
  807. package/dist/data/designs/ios-x-twitter-expo.md +442 -0
  808. package/dist/data/designs/ios-x-twitter-swiftui.md +429 -0
  809. package/dist/data/designs/ios-x-twitter.md +432 -0
  810. package/dist/data/designs/ios-yelp-android.md +455 -0
  811. package/dist/data/designs/ios-yelp-expo.md +397 -0
  812. package/dist/data/designs/ios-yelp-swiftui.md +369 -0
  813. package/dist/data/designs/ios-yelp.md +398 -0
  814. package/dist/data/designs/ios-youtube-android.md +668 -0
  815. package/dist/data/designs/ios-youtube-expo.md +435 -0
  816. package/dist/data/designs/ios-youtube-music-android.md +450 -0
  817. package/dist/data/designs/ios-youtube-music-expo.md +404 -0
  818. package/dist/data/designs/ios-youtube-music-swiftui.md +434 -0
  819. package/dist/data/designs/ios-youtube-music.md +381 -0
  820. package/dist/data/designs/ios-youtube-swiftui.md +496 -0
  821. package/dist/data/designs/ios-youtube.md +466 -0
  822. package/dist/data/designs/ios-zalo-android.md +510 -0
  823. package/dist/data/designs/ios-zalo-expo.md +389 -0
  824. package/dist/data/designs/ios-zalo-swiftui.md +431 -0
  825. package/dist/data/designs/ios-zalo.md +388 -0
  826. package/dist/data/designs/ios-zomato-android.md +527 -0
  827. package/dist/data/designs/ios-zomato-expo.md +437 -0
  828. package/dist/data/designs/ios-zomato-swiftui.md +433 -0
  829. package/dist/data/designs/ios-zomato.md +439 -0
  830. package/dist/data/designs/ios-zoom-android.md +423 -0
  831. package/dist/data/designs/ios-zoom-expo.md +355 -0
  832. package/dist/data/designs/ios-zoom-swiftui.md +379 -0
  833. package/dist/data/designs/ios-zoom.md +357 -0
  834. package/dist/data/designs/ios-zwift-android.md +402 -0
  835. package/dist/data/designs/ios-zwift-expo.md +402 -0
  836. package/dist/data/designs/ios-zwift-swiftui.md +378 -0
  837. package/dist/data/designs/ios-zwift.md +411 -0
  838. package/dist/data/designs/kraken.md +125 -0
  839. package/dist/data/designs/lamborghini.md +288 -0
  840. package/dist/data/designs/linear.app.md +548 -0
  841. package/dist/data/designs/lovable.md +298 -0
  842. package/dist/data/designs/mastercard.md +365 -0
  843. package/dist/data/designs/material-clean.md +289 -0
  844. package/dist/data/designs/meta.md +683 -0
  845. package/dist/data/designs/midnight-pro.md +256 -0
  846. package/dist/data/designs/minimal-brutalist.md +245 -0
  847. package/dist/data/designs/minimax.md +746 -0
  848. package/dist/data/designs/mintlify.md +852 -0
  849. package/dist/data/designs/miro.md +825 -0
  850. package/dist/data/designs/mistral.ai.md +773 -0
  851. package/dist/data/designs/mongodb.md +767 -0
  852. package/dist/data/designs/nike.md +575 -0
  853. package/dist/data/designs/nintendo-2001.md +649 -0
  854. package/dist/data/designs/notion.md +821 -0
  855. package/dist/data/designs/nova-mobile-design-md.md +235 -0
  856. package/dist/data/designs/nvidia.md +640 -0
  857. package/dist/data/designs/ollama.md +539 -0
  858. package/dist/data/designs/opencode.ai.md +521 -0
  859. package/dist/data/designs/pinterest.md +597 -0
  860. package/dist/data/designs/playful-color.md +253 -0
  861. package/dist/data/designs/playstation.md +661 -0
  862. package/dist/data/designs/posthog.md +690 -0
  863. package/dist/data/designs/raycast.md +669 -0
  864. package/dist/data/designs/renault.md +589 -0
  865. package/dist/data/designs/replicate.md +616 -0
  866. package/dist/data/designs/resend.md +585 -0
  867. package/dist/data/designs/revolut.md +636 -0
  868. package/dist/data/designs/runwayml.md +244 -0
  869. package/dist/data/designs/sanity.md +357 -0
  870. package/dist/data/designs/sentry.md +551 -0
  871. package/dist/data/designs/shopify.md +516 -0
  872. package/dist/data/designs/slack.md +482 -0
  873. package/dist/data/designs/soft-glass.md +258 -0
  874. package/dist/data/designs/spacex.md +363 -0
  875. package/dist/data/designs/spotify.md +246 -0
  876. package/dist/data/designs/starbucks.md +580 -0
  877. package/dist/data/designs/stripe.md +487 -0
  878. package/dist/data/designs/supabase.md +462 -0
  879. package/dist/data/designs/superhuman.md +448 -0
  880. package/dist/data/designs/tesla.md +286 -0
  881. package/dist/data/designs/theverge.md +339 -0
  882. package/dist/data/designs/together.ai.md +633 -0
  883. package/dist/data/designs/uber.md +636 -0
  884. package/dist/data/designs/vercel.md +736 -0
  885. package/dist/data/designs/vodafone.md +538 -0
  886. package/dist/data/designs/voltagent.md +521 -0
  887. package/dist/data/designs/warp.md +526 -0
  888. package/dist/data/designs/webflow.md +588 -0
  889. package/dist/data/designs/wired.md +497 -0
  890. package/dist/data/designs/wise.md +544 -0
  891. package/dist/data/designs/x.ai.md +465 -0
  892. package/dist/data/designs/zapier.md +537 -0
  893. package/dist/data/index.json +2600 -0
  894. package/dist/httpServer.js +83 -0
  895. package/dist/index.js +13 -0
  896. package/dist/server.js +32 -0
  897. package/dist/services/designStore.js +59 -0
  898. package/dist/services/linter.js +87 -0
  899. package/dist/services/sectionParser.js +154 -0
  900. package/dist/tools/authoring.js +131 -0
  901. package/dist/tools/browse.js +232 -0
  902. package/dist/tools/diff.js +88 -0
  903. package/dist/tools/getDesign.js +216 -0
  904. package/dist/tools/guardrails.js +87 -0
  905. package/dist/tools/lint.js +104 -0
  906. package/dist/types.js +1 -0
  907. package/package.json +65 -0
@@ -0,0 +1,654 @@
1
+ # TikTok (iOS) — Jetpack Compose Implementation Guide
2
+
3
+ Companion to [DESIGN.md](DESIGN.md) — the framework-neutral spec. This file ports TikTok's visual language to **Android with Jetpack Compose (Material 3)**: a color token object, a `Typography` set, paste-ready `@Composable`s, `Modifier`s, motion, and haptics.
4
+
5
+ > Why a Compose guide for an iOS-referenced app? The DESIGN.md tokens are platform-neutral. This file keeps the *visual* identity (the true-black canvas, chromatic-aberration logo/Create button, rose-as-the-verb, the full-bleed 9:16 feed with a floating right-side action rail) while making everything idiomatic Android — a custom bottom bar instead of a UITabBar, an `AccelerateDecelerate` `VerticalPager` instead of a paged `TabView`, `sp`/`dp` instead of `pt`.
6
+
7
+ Assumes Compose BOM `2024.09+`, Kotlin `2.0+`, `minSdk 24`, Material 3, [Coil](https://coil-kt.github.io/coil/) `2.6+` for avatars/artwork, and `androidx.media3:media3-exoplayer` for the video feed (wrap a `PlayerView` in `AndroidView`). No color extraction — TikTok is monochromatically cyan + rose on black, so `androidx.palette` is not required.
8
+
9
+ ## 1. Color Tokens
10
+
11
+ ```kotlin
12
+ // ui/theme/TikTokColors.kt
13
+ import androidx.compose.ui.graphics.Color
14
+
15
+ object TikTokColors {
16
+ // Canvas & Surfaces
17
+ val Canvas = Color(0xFF010101) // true black — a hair warmer than #000000
18
+ val Surface = Color(0xFF161823) // DMs, sheets
19
+ val InputField = Color(0xFF2F2F2F) // comment compose, search
20
+
21
+ // Brand
22
+ val Rose = Color(0xFFFE2C55) // the verb — Like, Follow, scrubber fill
23
+ val Cyan = Color(0xFF25F4EE) // the accent — Create button, chromatic aberration
24
+
25
+ // Text
26
+ val TextPrimary = Color(0xFFFFFFFF)
27
+ val TextSecondary = Color(0xFFE5E5E5) // hashtag counts
28
+ val TextTertiary = Color(0xFFFFFFFF).copy(alpha = 0.6f) // placeholder, meta
29
+ val TextDisabled = Color(0xFFFFFFFF).copy(alpha = 0.3f)
30
+
31
+ // Overlays
32
+ val FollowerGray = Color(0xFFFFFFFF).copy(alpha = 0.15f) // "Following" pill bg
33
+ val ScrimLight = Color(0xFF000000).copy(alpha = 0.25f) // icon shadow
34
+ val ScrimMedium = Color(0xFF000000).copy(alpha = 0.4f) // text-on-video shadow
35
+ val ScrimHeavy = Color(0xFF000000).copy(alpha = 0.6f) // sheet dim
36
+ val ScrubberTrack = Color(0xFFFFFFFF).copy(alpha = 0.3f)
37
+ }
38
+ ```
39
+
40
+ TikTok has **no light mode** — every screen is dark. Supply only a Material 3 `darkColorScheme`. `primary` is rose (the verb); `secondary` is cyan (the Create accent).
41
+
42
+ ```kotlin
43
+ // ui/theme/Theme.kt
44
+ import androidx.compose.material3.darkColorScheme
45
+ import androidx.compose.material3.MaterialTheme
46
+ import androidx.compose.runtime.Composable
47
+
48
+ private val TikTokScheme = darkColorScheme(
49
+ primary = TikTokColors.Rose,
50
+ onPrimary = TikTokColors.TextPrimary,
51
+ secondary = TikTokColors.Cyan,
52
+ background = TikTokColors.Canvas,
53
+ onBackground = TikTokColors.TextPrimary,
54
+ surface = TikTokColors.Surface,
55
+ onSurface = TikTokColors.TextPrimary,
56
+ surfaceVariant = TikTokColors.InputField,
57
+ error = TikTokColors.Rose, // TikTok reuses rose for error
58
+ )
59
+
60
+ @Composable
61
+ fun TikTokTheme(content: @Composable () -> Unit) =
62
+ MaterialTheme(colorScheme = TikTokScheme, typography = TikTokTypography, content = content)
63
+ // Dark-only — never provide a lightColorScheme.
64
+ ```
65
+
66
+ ## 2. Typography
67
+
68
+ Proxima Nova is a licensed third-party face (Mark Simonson). Drop the TTF/OTF files in `res/font/` (lowercase, snake_case). Fall back to the system font (Roboto) — its geometric-humanist tone is the closest free substitute on Android.
69
+
70
+ ```kotlin
71
+ // ui/theme/TikTokType.kt
72
+ import androidx.compose.material3.Typography
73
+ import androidx.compose.ui.text.TextStyle
74
+ import androidx.compose.ui.text.font.Font
75
+ import androidx.compose.ui.text.font.FontFamily
76
+ import androidx.compose.ui.text.font.FontWeight
77
+ import androidx.compose.ui.unit.sp
78
+
79
+ val ProximaNova = FontFamily(
80
+ Font(R.font.proximanova_regular, FontWeight.Normal), // 400
81
+ Font(R.font.proximanova_medium, FontWeight.Medium), // 500
82
+ Font(R.font.proximanova_semibold, FontWeight.SemiBold), // 600
83
+ Font(R.font.proximanova_bold, FontWeight.Bold), // 700
84
+ )
85
+
86
+ // Named ramp — mirrors DESIGN.md §3 exactly (pt → sp 1:1, weights preserved)
87
+ object TikTokText {
88
+ val DisplayName = TextStyle(ProximaNova, fontWeight = FontWeight.Bold, fontSize = 24.sp, lineHeight = 29.sp, letterSpacing = (-0.2).sp)
89
+ val SheetTitle = TextStyle(ProximaNova, fontWeight = FontWeight.SemiBold, fontSize = 17.sp, lineHeight = 21.sp, letterSpacing = (-0.1).sp)
90
+ val Username = TextStyle(ProximaNova, fontWeight = FontWeight.Bold, fontSize = 16.sp, lineHeight = 19.sp)
91
+ val Caption = TextStyle(ProximaNova, fontWeight = FontWeight.Normal, fontSize = 15.sp, lineHeight = 20.sp)
92
+ val CaptionHashtag = TextStyle(ProximaNova, fontWeight = FontWeight.Bold, fontSize = 15.sp, lineHeight = 20.sp)
93
+ val UsernameList = TextStyle(ProximaNova, fontWeight = FontWeight.SemiBold, fontSize = 15.sp, lineHeight = 19.sp)
94
+ val ActionCount = TextStyle(ProximaNova, fontWeight = FontWeight.Bold, fontSize = 13.sp, lineHeight = 16.sp)
95
+ val Music = TextStyle(ProximaNova, fontWeight = FontWeight.Medium, fontSize = 13.sp, lineHeight = 16.sp)
96
+ val Body = TextStyle(ProximaNova, fontWeight = FontWeight.Normal, fontSize = 14.sp, lineHeight = 20.sp)
97
+ val Meta = TextStyle(ProximaNova, fontWeight = FontWeight.Normal, fontSize = 12.sp, lineHeight = 16.sp)
98
+ val Tab = TextStyle(ProximaNova, fontWeight = FontWeight.SemiBold, fontSize = 10.sp, lineHeight = 10.sp, letterSpacing = 0.1.sp)
99
+ val ButtonPrimary = TextStyle(ProximaNova, fontWeight = FontWeight.Bold, fontSize = 16.sp, lineHeight = 16.sp)
100
+ val ButtonSecondary = TextStyle(ProximaNova, fontWeight = FontWeight.SemiBold, fontSize = 14.sp, lineHeight = 14.sp)
101
+ val Follow = TextStyle(ProximaNova, fontWeight = FontWeight.Bold, fontSize = 14.sp, lineHeight = 14.sp)
102
+ val Chip = TextStyle(ProximaNova, fontWeight = FontWeight.SemiBold, fontSize = 13.sp, lineHeight = 13.sp)
103
+ }
104
+
105
+ // Map onto Material 3 slots so stock components inherit the brand
106
+ val TikTokTypography = Typography(
107
+ headlineMedium = TikTokText.DisplayName,
108
+ titleMedium = TikTokText.SheetTitle,
109
+ bodyMedium = TikTokText.Body,
110
+ labelLarge = TikTokText.ButtonPrimary,
111
+ labelSmall = TikTokText.Tab,
112
+ )
113
+ ```
114
+
115
+ ### Text-on-Video Shadow Modifier
116
+
117
+ Every label overlaid on a video needs this — it is non-negotiable for legibility over bright frames.
118
+
119
+ ```kotlin
120
+ import androidx.compose.ui.Modifier
121
+ import androidx.compose.ui.draw.shadow
122
+ import androidx.compose.ui.geometry.Offset
123
+ import androidx.compose.ui.graphics.Shadow
124
+ import androidx.compose.ui.text.TextStyle
125
+
126
+ // For Text, fold the shadow into the TextStyle so it renders per-glyph
127
+ fun TextStyle.onVideo(): TextStyle = copy(
128
+ shadow = Shadow(color = TikTokColors.ScrimMedium, offset = Offset(0f, 1f), blurRadius = 4f),
129
+ )
130
+
131
+ // For icons / Boxes, use a drop shadow modifier
132
+ fun Modifier.tiktokIconShadow(): Modifier =
133
+ this.shadow(elevation = 3.dp, clip = false, ambientColor = TikTokColors.ScrimLight, spotColor = TikTokColors.ScrimLight)
134
+ ```
135
+
136
+ ## 3. Signature Components
137
+
138
+ ### Follow Button (the iconic rose pill — 4dp corner, not full pill)
139
+
140
+ ```kotlin
141
+ import androidx.compose.animation.core.animateFloatAsState
142
+ import androidx.compose.animation.core.spring
143
+ import androidx.compose.foundation.background
144
+ import androidx.compose.foundation.clickable
145
+ import androidx.compose.foundation.interaction.MutableInteractionSource
146
+ import androidx.compose.foundation.interaction.collectIsPressedAsState
147
+ import androidx.compose.foundation.layout.*
148
+ import androidx.compose.foundation.shape.RoundedCornerShape
149
+ import androidx.compose.material3.Text
150
+ import androidx.compose.runtime.*
151
+ import androidx.compose.ui.Alignment
152
+ import androidx.compose.ui.draw.clip
153
+ import androidx.compose.ui.draw.scale
154
+ import androidx.compose.ui.hapticfeedback.HapticFeedbackType
155
+ import androidx.compose.ui.platform.LocalHapticFeedback
156
+ import androidx.compose.ui.unit.dp
157
+
158
+ @Composable
159
+ fun TikTokFollowButton(
160
+ isFollowing: Boolean,
161
+ onToggle: () -> Unit,
162
+ modifier: Modifier = Modifier,
163
+ ) {
164
+ val interaction = remember { MutableInteractionSource() }
165
+ val pressed by interaction.collectIsPressedAsState()
166
+ val scale by animateFloatAsState(if (pressed) 0.95f else 1f, spring(dampingRatio = 0.7f), label = "followScale")
167
+ val haptics = LocalHapticFeedback.current
168
+
169
+ Box(
170
+ modifier = modifier
171
+ .heightIn(min = 28.dp)
172
+ .scale(scale)
173
+ .clip(RoundedCornerShape(4.dp)) // TikTok-signature "almost-square", NOT a full pill
174
+ .background(if (isFollowing) TikTokColors.FollowerGray else TikTokColors.Rose)
175
+ .clickable(interaction, indication = null) {
176
+ // success haptic on follow, soft on unfollow
177
+ haptics.performHapticFeedback(
178
+ if (!isFollowing) HapticFeedbackType.LongPress else HapticFeedbackType.TextHandleMove
179
+ )
180
+ onToggle()
181
+ }
182
+ .padding(horizontal = 16.dp, vertical = 6.dp),
183
+ contentAlignment = Alignment.Center,
184
+ ) {
185
+ Text(
186
+ if (isFollowing) "Following" else "Follow",
187
+ style = if (isFollowing) TikTokText.ButtonSecondary else TikTokText.Follow,
188
+ color = TikTokColors.TextPrimary,
189
+ )
190
+ }
191
+ }
192
+ ```
193
+
194
+ ### Chromatic Aberration Modifier (the brand thesis)
195
+
196
+ iOS stacks three offset copies. Compose: render the same content three times — cyan offset -x, rose offset +x, white core on top — in a `Box`.
197
+
198
+ ```kotlin
199
+ import androidx.compose.ui.graphics.graphicsLayer
200
+
201
+ @Composable
202
+ fun ChromaticAberration(
203
+ offsetDp: Float = 3f, // scales with size: 1 @16sp, 3 @44dp, 6 @96dp
204
+ content: @Composable (color: androidx.compose.ui.graphics.Color) -> Unit,
205
+ ) {
206
+ Box {
207
+ Box(Modifier.graphicsLayer { translationX = -offsetDp * density }) { content(TikTokColors.Cyan) }
208
+ Box(Modifier.graphicsLayer { translationX = offsetDp * density }) { content(TikTokColors.Rose) }
209
+ content(TikTokColors.TextPrimary) // white core on top
210
+ }
211
+ }
212
+
213
+ // Usage — the glitch wordmark:
214
+ // ChromaticAberration(offsetDp = 6f) { c ->
215
+ // Text("d", style = TextStyle(fontSize = 96.sp, fontWeight = FontWeight.Bold), color = c)
216
+ // }
217
+ ```
218
+
219
+ ### Create Tab Button (chromatic, the centered anchor)
220
+
221
+ ```kotlin
222
+ import androidx.compose.foundation.layout.size
223
+ import androidx.compose.material.icons.Icons
224
+ import androidx.compose.material.icons.filled.Add
225
+ import androidx.compose.material3.Icon
226
+
227
+ @Composable
228
+ fun TikTokCreateButton(
229
+ onClick: () -> Unit,
230
+ modifier: Modifier = Modifier,
231
+ ) {
232
+ val interaction = remember { MutableInteractionSource() }
233
+ val pressed by interaction.collectIsPressedAsState()
234
+ val scale by animateFloatAsState(if (pressed) 0.94f else 1f, label = "createScale")
235
+ val haptics = LocalHapticFeedback.current
236
+
237
+ Box(
238
+ modifier = modifier
239
+ .size(width = 44.dp, height = 30.dp)
240
+ .scale(scale)
241
+ .clip(RoundedCornerShape(8.dp))
242
+ .clickable(interaction, indication = null) {
243
+ haptics.performHapticFeedback(HapticFeedbackType.LongPress) // heavy
244
+ onClick()
245
+ },
246
+ contentAlignment = Alignment.Center,
247
+ ) {
248
+ // cyan left edge, rose right edge, white through the middle
249
+ Box(Modifier.matchParentSize().graphicsLayer { translationX = -3 * density }.background(TikTokColors.Cyan))
250
+ Box(Modifier.matchParentSize().graphicsLayer { translationX = 3 * density }.background(TikTokColors.Rose))
251
+ Box(Modifier.matchParentSize().background(TikTokColors.TextPrimary))
252
+ Icon(Icons.Filled.Add, "Create", tint = TikTokColors.Canvas, modifier = Modifier.size(18.dp))
253
+ }
254
+ }
255
+ ```
256
+
257
+ ### Right-Side Action Rail (the load-bearing feed UX)
258
+
259
+ ```kotlin
260
+ import androidx.compose.animation.core.LinearEasing
261
+ import androidx.compose.animation.core.RepeatMode
262
+ import androidx.compose.animation.core.infiniteRepeatable
263
+ import androidx.compose.animation.core.rememberInfiniteTransition
264
+ import androidx.compose.animation.core.tween
265
+ import androidx.compose.foundation.border
266
+ import androidx.compose.foundation.shape.CircleShape
267
+ import androidx.compose.material.icons.filled.*
268
+ import androidx.compose.ui.draw.rotate
269
+ import androidx.compose.ui.graphics.Color
270
+ import androidx.compose.ui.graphics.vector.ImageVector
271
+ import androidx.compose.ui.layout.ContentScale
272
+ import coil.compose.AsyncImage
273
+
274
+ @Composable
275
+ fun ActionRail(
276
+ avatarUrl: String,
277
+ isFollowed: Boolean,
278
+ onFollow: () -> Unit,
279
+ likeCount: Int,
280
+ isLiked: Boolean,
281
+ onLike: () -> Unit,
282
+ commentCount: Int,
283
+ bookmarkCount: Int,
284
+ shareCount: Int,
285
+ musicArtworkUrl: String,
286
+ modifier: Modifier = Modifier,
287
+ ) {
288
+ Column(
289
+ modifier = modifier.padding(end = 12.dp),
290
+ horizontalAlignment = Alignment.CenterHorizontally,
291
+ verticalArrangement = Arrangement.spacedBy(24.dp),
292
+ ) {
293
+ // Avatar + follow badge
294
+ Box(contentAlignment = Alignment.BottomCenter) {
295
+ AsyncImage(
296
+ model = avatarUrl, contentDescription = null,
297
+ modifier = Modifier.size(48.dp).clip(CircleShape).border(2.dp, TikTokColors.TextPrimary, CircleShape),
298
+ contentScale = ContentScale.Crop,
299
+ )
300
+ if (!isFollowed) {
301
+ Box(
302
+ Modifier
303
+ .offset(y = 9.dp)
304
+ .size(18.dp)
305
+ .clip(CircleShape)
306
+ .background(TikTokColors.Rose)
307
+ .clickable(onClick = onFollow),
308
+ contentAlignment = Alignment.Center,
309
+ ) { Icon(Icons.Filled.Add, "Follow", tint = TikTokColors.TextPrimary, modifier = Modifier.size(10.dp)) }
310
+ }
311
+ }
312
+ RailIcon(if (isLiked) Icons.Filled.Favorite else Icons.Filled.FavoriteBorder, likeCount, if (isLiked) TikTokColors.Rose else TikTokColors.TextPrimary, onLike)
313
+ RailIcon(Icons.Filled.Comment, commentCount, TikTokColors.TextPrimary) {}
314
+ RailIcon(Icons.Filled.Bookmark, bookmarkCount, TikTokColors.TextPrimary) {}
315
+ RailIcon(Icons.Filled.Reply, shareCount, TikTokColors.TextPrimary) {}
316
+ SpinningMusicDisc(musicArtworkUrl)
317
+ }
318
+ }
319
+
320
+ @Composable
321
+ private fun RailIcon(icon: ImageVector, count: Int, tint: Color, onClick: () -> Unit) {
322
+ Column(
323
+ horizontalAlignment = Alignment.CenterHorizontally,
324
+ verticalArrangement = Arrangement.spacedBy(4.dp),
325
+ modifier = Modifier.defaultMinSize(minWidth = 48.dp, minHeight = 48.dp).clickable(onClick = onClick),
326
+ ) {
327
+ Icon(icon, null, tint = tint, modifier = Modifier.size(30.dp).tiktokIconShadow())
328
+ Text(formatCount(count), style = TikTokText.ActionCount.onVideo(), color = TikTokColors.TextPrimary)
329
+ }
330
+ }
331
+
332
+ // Counts abbreviate — never raw integers above 1,000
333
+ fun formatCount(n: Int): String = when {
334
+ n < 1_000 -> "$n"
335
+ n < 1_000_000 -> "%.1fK".format(n / 1_000.0).removeSuffix(".0K").let { if (it.endsWith("K")) it else it + "K" }
336
+ else -> "%.1fM".format(n / 1_000_000.0).removeSuffix(".0M").let { if (it.endsWith("M")) it else it + "M" }
337
+ }
338
+
339
+ @Composable
340
+ private fun SpinningMusicDisc(artworkUrl: String) {
341
+ val t = rememberInfiniteTransition(label = "disc")
342
+ val angle by t.animateFloat(
343
+ 0f, 360f,
344
+ infiniteRepeatable(tween(6000, easing = LinearEasing), RepeatMode.Restart), // 360° / 6s
345
+ label = "discAngle",
346
+ )
347
+ Box(
348
+ Modifier.size(44.dp).rotate(angle).clip(CircleShape).background(TikTokColors.Canvas),
349
+ contentAlignment = Alignment.Center,
350
+ ) {
351
+ AsyncImage(
352
+ model = artworkUrl, contentDescription = null,
353
+ modifier = Modifier.size(28.dp).clip(CircleShape),
354
+ contentScale = ContentScale.Crop,
355
+ )
356
+ }
357
+ }
358
+ ```
359
+
360
+ ### Feed Caption Overlay (bold hashtags inline)
361
+
362
+ ```kotlin
363
+ import androidx.compose.ui.text.buildAnnotatedString
364
+ import androidx.compose.ui.text.SpanStyle
365
+ import androidx.compose.ui.text.withStyle
366
+ import androidx.compose.ui.text.style.TextOverflow
367
+
368
+ @Composable
369
+ fun CaptionOverlay(
370
+ username: String,
371
+ caption: String, // "sunset loop #fyp #bayarea"
372
+ musicTitle: String,
373
+ modifier: Modifier = Modifier,
374
+ ) {
375
+ Column(
376
+ modifier = modifier.padding(start = 16.dp, end = 80.dp), // leave room for the action rail
377
+ verticalArrangement = Arrangement.spacedBy(8.dp),
378
+ ) {
379
+ Text("@$username", style = TikTokText.Username.onVideo(), color = TikTokColors.TextPrimary)
380
+ Text(
381
+ buildAnnotatedString {
382
+ caption.split(" ").forEachIndexed { i, token ->
383
+ if (i > 0) append(" ")
384
+ if (token.startsWith("#")) {
385
+ withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append(token) } // hashtags bold inline
386
+ } else append(token)
387
+ }
388
+ },
389
+ style = TikTokText.Caption.onVideo(),
390
+ color = TikTokColors.TextPrimary,
391
+ maxLines = 2,
392
+ overflow = TextOverflow.Ellipsis,
393
+ )
394
+ Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(6.dp)) {
395
+ Icon(Icons.Filled.MusicNote, null, tint = TikTokColors.TextPrimary, modifier = Modifier.size(12.dp))
396
+ Text(musicTitle, style = TikTokText.Music.onVideo(), color = TikTokColors.TextPrimary, maxLines = 1)
397
+ }
398
+ }
399
+ }
400
+ ```
401
+
402
+ ### Video Progress Scrubber
403
+
404
+ ```kotlin
405
+ @Composable
406
+ fun VideoScrubber(progress: Float, isScrubbing: Boolean, modifier: Modifier = Modifier) {
407
+ val height by animateFloatAsState(if (isScrubbing) 4f else 2f, label = "scrubH")
408
+ Box(
409
+ modifier
410
+ .fillMaxWidth()
411
+ .height(height.dp)
412
+ .background(TikTokColors.ScrubberTrack),
413
+ ) {
414
+ Box(Modifier.fillMaxWidth(progress).height(height.dp).background(TikTokColors.Rose))
415
+ }
416
+ }
417
+ ```
418
+
419
+ ## 4. Full-Bleed Vertical Feed + Double-Tap Burst (the signature system)
420
+
421
+ TikTok's thesis: a 9:16 video fills the screen edge-to-edge (ignoring safe areas for *content*), UI floats on top, and a double-tap anywhere spawns a 120dp rose heart. iOS uses a rotated paged `TabView` + a tap overlay; Compose uses a vertical `Pager` with the video drawn behind the overlays, plus `detectTapGestures(onDoubleTap)`.
422
+
423
+ ```kotlin
424
+ import androidx.compose.foundation.gestures.detectTapGestures
425
+ import androidx.compose.foundation.pager.VerticalPager
426
+ import androidx.compose.foundation.pager.rememberPagerState
427
+ import androidx.compose.ui.input.pointer.pointerInput
428
+ import androidx.compose.ui.geometry.Offset
429
+ import androidx.compose.ui.unit.IntOffset
430
+ import kotlinx.coroutines.delay
431
+ import kotlin.math.roundToInt
432
+
433
+ @Composable
434
+ fun TikTokFeed(
435
+ pageCount: Int,
436
+ videoContent: @Composable (page: Int) -> Unit, // wrap ExoPlayer PlayerView in AndroidView
437
+ overlayContent: @Composable (page: Int) -> Unit,
438
+ ) {
439
+ val pagerState = rememberPagerState(pageCount = { pageCount })
440
+ VerticalPager(
441
+ state = pagerState,
442
+ modifier = Modifier.fillMaxSize().background(TikTokColors.Canvas),
443
+ ) { page ->
444
+ Box(Modifier.fillMaxSize()) {
445
+ // video ignores safe areas and fills edge-to-edge
446
+ Box(Modifier.fillMaxSize()) { videoContent(page) }
447
+ DoubleTapLikeLayer { /* register like */ }
448
+ overlayContent(page)
449
+ }
450
+ }
451
+ }
452
+
453
+ @Composable
454
+ fun DoubleTapLikeLayer(onLike: () -> Unit) {
455
+ val hearts = remember { mutableStateListOf<HeartBurst>() }
456
+ val haptics = LocalHapticFeedback.current
457
+
458
+ Box(
459
+ Modifier
460
+ .fillMaxSize()
461
+ .pointerInput(Unit) {
462
+ detectTapGestures(
463
+ onDoubleTap = { pos ->
464
+ val id = System.nanoTime()
465
+ hearts.add(HeartBurst(id, pos))
466
+ haptics.performHapticFeedback(HapticFeedbackType.LongPress) // heavy on first tap
467
+ onLike()
468
+ },
469
+ )
470
+ },
471
+ ) {
472
+ hearts.forEach { h -> key(h.id) { HeartBurstView(h) { hearts.remove(h) } } }
473
+ }
474
+ }
475
+
476
+ data class HeartBurst(val id: Long, val pos: Offset)
477
+
478
+ @Composable
479
+ private fun HeartBurstView(burst: HeartBurst, onDone: () -> Unit) {
480
+ val scale = remember { androidx.compose.animation.core.Animatable(0f) }
481
+ val alpha = remember { androidx.compose.animation.core.Animatable(1f) }
482
+ LaunchedEffect(burst.id) {
483
+ // 0 → 1.4 → 1.0 over 400ms spring, then fade 1 → 0 over 200ms
484
+ scale.animateTo(1.4f, spring(dampingRatio = 0.55f, stiffness = 500f))
485
+ scale.animateTo(1.0f, spring(dampingRatio = 0.7f))
486
+ alpha.animateTo(0f, tween(200))
487
+ onDone()
488
+ }
489
+ Icon(
490
+ Icons.Filled.Favorite, null,
491
+ tint = TikTokColors.Rose,
492
+ modifier = Modifier
493
+ .offset { IntOffset((burst.pos.x - 60.dp.toPx()).roundToInt(), (burst.pos.y - 60.dp.toPx()).roundToInt()) }
494
+ .size(120.dp)
495
+ .scale(scale.value)
496
+ .androidx.compose.ui.draw.alpha(alpha.value),
497
+ )
498
+ }
499
+ ```
500
+
501
+ ### Chromatic Loading Spinner
502
+
503
+ ```kotlin
504
+ import androidx.compose.foundation.Canvas
505
+ import androidx.compose.ui.graphics.drawscope.Stroke
506
+ import androidx.compose.ui.geometry.Offset as GOffset
507
+
508
+ @Composable
509
+ fun TikTokLoadingSpinner(modifier: Modifier = Modifier) {
510
+ val t = rememberInfiniteTransition(label = "spinner")
511
+ val angle by t.animateFloat(0f, 360f, infiniteRepeatable(tween(1000, easing = LinearEasing)), label = "spin")
512
+ Canvas(modifier.size(32.dp).rotate(angle)) {
513
+ val sw = 3.dp.toPx()
514
+ fun arc(color: androidx.compose.ui.graphics.Color, dx: Float) = drawArc(
515
+ color = color, startAngle = 0f, sweepAngle = 270f, useCenter = false,
516
+ topLeft = GOffset(dx, 0f), size = androidx.compose.ui.geometry.Size(size.width, size.height),
517
+ style = Stroke(width = sw),
518
+ )
519
+ arc(TikTokColors.Cyan, -3.dp.toPx())
520
+ arc(TikTokColors.Rose, 3.dp.toPx())
521
+ arc(TikTokColors.TextPrimary, 0f)
522
+ }
523
+ }
524
+ ```
525
+
526
+ ## 5. Navigation (Tab Bar)
527
+
528
+ TikTok's iOS tab bar is **transparent over the feed** (only text-shadowed glyphs) and a `.regularMaterial` blur over `rgba(1,1,1,0.92)` on every other screen, with the centered chromatic Create button. Android has no first-class live blur — use a translucent `Surface` (`Canvas` at ~92% alpha) on non-feed screens and full transparency on the feed. Build a custom row (not `NavigationBar`) so you can swap materials and embed the Create button.
529
+
530
+ ```kotlin
531
+ import androidx.compose.foundation.layout.Spacer
532
+ import androidx.compose.material3.HorizontalDivider
533
+
534
+ enum class TikTokTab { Home, Discover, Inbox, Profile }
535
+
536
+ @Composable
537
+ fun TikTokBottomBar(
538
+ selected: TikTokTab,
539
+ onSelect: (TikTokTab) -> Unit,
540
+ onCreate: () -> Unit,
541
+ isOnFeed: Boolean,
542
+ modifier: Modifier = Modifier,
543
+ ) {
544
+ Box(modifier.fillMaxWidth()) {
545
+ Column {
546
+ if (!isOnFeed) HorizontalDivider(color = TikTokColors.TextPrimary.copy(alpha = 0.08f), thickness = 0.5.dp)
547
+ Row(
548
+ Modifier
549
+ .fillMaxWidth()
550
+ .height(48.dp)
551
+ .background(if (isOnFeed) Color.Transparent else TikTokColors.Canvas.copy(alpha = 0.92f))
552
+ .padding(horizontal = 8.dp),
553
+ verticalAlignment = Alignment.CenterVertically,
554
+ ) {
555
+ Tab(TikTokTab.Home, Icons.Filled.Home, "Home", selected, isOnFeed, onSelect, Modifier.weight(1f))
556
+ Tab(TikTokTab.Discover, Icons.Filled.Search, "Discover", selected, isOnFeed, onSelect, Modifier.weight(1f))
557
+ Spacer(Modifier.width(56.dp)) // room for Create
558
+ Tab(TikTokTab.Inbox, Icons.Filled.Inbox, "Inbox", selected, isOnFeed, onSelect, Modifier.weight(1f))
559
+ Tab(TikTokTab.Profile, Icons.Filled.Person, "Profile", selected, isOnFeed, onSelect, Modifier.weight(1f))
560
+ }
561
+ }
562
+ TikTokCreateButton(onClick = onCreate, modifier = Modifier.align(Alignment.Center))
563
+ }
564
+ }
565
+
566
+ @Composable
567
+ private fun Tab(
568
+ tab: TikTokTab, icon: ImageVector, label: String,
569
+ selected: TikTokTab, isOnFeed: Boolean, onSelect: (TikTokTab) -> Unit, modifier: Modifier,
570
+ ) {
571
+ Column(
572
+ modifier = modifier.clickable { onSelect(tab) },
573
+ horizontalAlignment = Alignment.CenterHorizontally,
574
+ verticalArrangement = Arrangement.spacedBy(3.dp),
575
+ ) {
576
+ val tint = if (selected == tab) TikTokColors.TextPrimary else TikTokColors.TextPrimary.copy(alpha = 0.5f)
577
+ Icon(icon, label, tint = tint, modifier = Modifier.size(24.dp).then(if (isOnFeed) Modifier.tiktokIconShadow() else Modifier))
578
+ Text(label, style = if (isOnFeed) TikTokText.Tab.onVideo() else TikTokText.Tab, color = tint)
579
+ }
580
+ }
581
+ ```
582
+
583
+ The top feed tabs ("Following" / "For You") are just two text labels floating on the video with a 2dp animated underline — no container; render them in a `Row` above the feed with `Modifier.windowInsetsPadding(WindowInsets.statusBars)`.
584
+
585
+ ## 6. Motion & Haptics
586
+
587
+ | Moment | Compose recipe |
588
+ |--------|----------------|
589
+ | Swipe up for next video | `VerticalPager`, ~300ms `spring(dampingRatio = 0.85f)` paging |
590
+ | Swipe right/left (profile / For You) | horizontal `Pager` with destination parallax (`graphicsLayer`) |
591
+ | Double-tap like | heart `Animatable` 0 → 1.4 → 1.0 over 400ms `spring`, fade 1 → 0 `tween(200)`; `HapticFeedbackType.LongPress` (heavy) |
592
+ | Heart icon tap | `Animatable` 1 → 1.3 → 1.0 `spring`, rose fill swap, heavy haptic |
593
+ | Follow button | pill recolors rose → translucent over ~200ms, scale 0.95 → 1.0; success haptic on follow |
594
+ | Spinning music disc | `rememberInfiniteTransition` 360° / 6s `LinearEasing`, pauses with video |
595
+ | Comment sheet | `ModalBottomSheet` slide-up ~350ms `spring(dampingRatio = 0.85f)` |
596
+ | Create tap | tab bar dims ~0.8s, camera UI fades in `tween(400)` |
597
+
598
+ ```kotlin
599
+ // Heart single-tap — 1.0 → 1.3 → 1.0 bounce + heavy haptic + rose swap
600
+ @Composable
601
+ fun TikTokHeart(isLiked: Boolean, onToggle: () -> Unit) {
602
+ val scale = remember { androidx.compose.animation.core.Animatable(1f) }
603
+ val haptics = LocalHapticFeedback.current
604
+ LaunchedEffect(isLiked) {
605
+ if (isLiked) {
606
+ haptics.performHapticFeedback(HapticFeedbackType.LongPress) // heavy
607
+ scale.animateTo(1.3f, spring(dampingRatio = 0.5f, stiffness = 600f))
608
+ scale.animateTo(1.0f, spring(dampingRatio = 0.7f))
609
+ }
610
+ }
611
+ Icon(
612
+ if (isLiked) Icons.Filled.Favorite else Icons.Filled.FavoriteBorder,
613
+ contentDescription = if (isLiked) "Unlike" else "Like",
614
+ tint = if (isLiked) TikTokColors.Rose else TikTokColors.TextPrimary,
615
+ modifier = Modifier.size(30.dp).scale(scale.value).tiktokIconShadow().clickable(onClick = onToggle),
616
+ )
617
+ }
618
+ ```
619
+
620
+ Haptics: `LocalHapticFeedback` `LongPress` approximates iOS heavy/success; `TextHandleMove` approximates soft. For a true graded *heavy* cue on double-tap-like, use `LocalView.current.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)` or a `Vibrator` `VibrationEffect.createOneShot(18, 255)`.
621
+
622
+ ## 7. Icons
623
+
624
+ TikTok uses custom glyphs (the chromatic wordmark especially). The closest first-party set is `androidx.compose.material:material-icons-extended`; ship the chromatic wordmark and any brand-exact glyphs as vector drawables loaded via `ImageVector.vectorResource(R.drawable.…)`.
625
+
626
+ | Component | SF Symbol (iOS) | Material Icon (Compose) |
627
+ |-----------|-----------------|--------------------------|
628
+ | Heart (idle / active) | `heart` / `heart.fill` | `Icons.Filled.FavoriteBorder` / `Icons.Filled.Favorite` |
629
+ | Comment | `ellipsis.bubble.fill` | `Icons.Filled.Comment` |
630
+ | Bookmark | `bookmark.fill` | `Icons.Filled.Bookmark` |
631
+ | Share | `arrowshape.turn.up.right.fill` | `Icons.Filled.Reply` |
632
+ | Music note | `music.note` | `Icons.Filled.MusicNote` |
633
+ | Create plus | `plus` | `Icons.Filled.Add` |
634
+ | Home tab | `house.fill` | `Icons.Filled.Home` |
635
+ | Discover tab | `magnifyingglass` | `Icons.Filled.Search` |
636
+ | Inbox tab | `tray.fill` | `Icons.Filled.Inbox` |
637
+ | Profile tab | `person.fill` | `Icons.Filled.Person` |
638
+ | Back | `chevron.backward` | `Icons.Filled.ArrowBackIosNew` |
639
+ | More | `ellipsis` | `Icons.Filled.MoreHoriz` |
640
+ | Send | `paperplane.fill` | `Icons.Filled.Send` |
641
+ | Live | `dot.radiowaves.left.and.right` | `Icons.Filled.SensorsOff` (or custom live drawable) |
642
+ | Wordmark "d" | custom chromatic glyph | vector drawable via `ChromaticAberration` |
643
+
644
+ ## 8. Minimum SDK & Accessibility Notes
645
+
646
+ - **minSdk 24** (Compose floor is 21; `VerticalPager`, ExoPlayer, and the chromatic motion are comfortable at 24). `compileSdk 34+`, Compose BOM `2024.09+`, Kotlin `2.0+`.
647
+ - **Edge-to-edge**: call `enableEdgeToEdge()` in the `Activity`. The **video content draws under the system bars** (the 9:16 frame fills edge-to-edge, including under the camera cutout); only the *UI overlays* respect insets via `Modifier.windowInsetsPadding(WindowInsets.safeDrawing)`. Force a light status bar (white over video) since there is no light mode.
648
+ - **Font scaling**: `sp` honors the user's font scale — sheet content (comments, inbox, settings) scales fully. **Pin** the feed overlays (caption, username, action counts) and the 10sp tab labels via `CompositionLocalProvider(LocalDensity provides Density(density, fontScale = 1f))` — the 9:16 layout is tight and scaling breaks it.
649
+ - **TalkBack**: label the heart "Like video by @username, 24.5K likes" and the Follow button "Follow @username" via `Modifier.semantics`. Mark the spinning music disc decorative unless it opens the audio page (then expose it as a button). The double-tap layer should also expose a single-tap accessible "Like" action.
650
+ - **Touch targets**: Material guidance is 48.dp. The right-rail glyphs are 30dp on a 48dp `defaultMinSize` target; the Create button is 44×30dp with a ~56dp effective hit area — verify with `Modifier.minimumInteractiveComponentSize()`.
651
+ - **Contrast**: white text on video is reinforced by the `rgba(0,0,0,0.4)` shadow folded into `TextStyle.onVideo()` — validate on bright-frame samples; never render white text on a gray surface without it.
652
+ - **Reduce motion**: detect `Settings.Global.ANIMATOR_DURATION_SCALE == 0f` (or a stored pref) — freeze the spinning music disc and skip the double-tap burst spring (fall back to an instant heart fade), but keep the heavy haptic.
653
+ - **Orientation**: lock the feed to portrait (`android:screenOrientation="portrait"` on the feed Activity, or `requestedOrientation`) — the 9:16 video is the entire thesis. The video-player modal from the profile grid may rotate to landscape.
654
+ - **Dynamic color**: do **not** enable Material You `dynamicColorScheme()` — TikTok's brand is the fixed rose/cyan-on-`#010101` chromatic identity; a wallpaper-derived palette would destroy the aberration treatment and the verb/accent split.