[{"data":1,"prerenderedAt":1502},["ShallowReactive",2],{"navigation":3,"\u002Fguides\u002Fsparkling":489,"\u002Fguides\u002Fsparkling-surround":1497},[4,34,51,317,343,348,353,431],{"title":5,"path":6,"stem":7,"children":8,"package":11,"category":11,"icon":33},"Getting Started","\u002Fgetting-started","1.getting-started\u002F1.index",[9,13,18,23,28],{"title":10,"path":6,"stem":7,"package":11,"category":11,"icon":12},"Introduction",null,"i-lucide-house",{"title":14,"path":15,"stem":16,"package":11,"category":11,"icon":17},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":19,"path":20,"stem":21,"package":11,"category":11,"icon":22},"Icons","\u002Fgetting-started\u002Ficons","1.getting-started\u002F3.icons","i-lucide-sparkles",{"title":24,"path":25,"stem":26,"package":11,"category":11,"icon":27},"CLI","\u002Fgetting-started\u002Fcli","1.getting-started\u002F4.cli","i-lucide-terminal",{"title":29,"path":30,"stem":31,"package":11,"category":11,"icon":32},"Roadmap","\u002Fgetting-started\u002Froadmap","1.getting-started\u002F5.roadmap","i-lucide-map","i-lucide-rocket",{"title":35,"package":11,"category":11,"icon":36,"path":37,"stem":38,"children":39,"page":50},"Packages","i-lucide-package","\u002Fpackages","2.packages",[40,45],{"title":41,"path":42,"stem":43,"package":11,"category":11,"icon":44},"@vyui\u002Fcore","\u002Fpackages\u002Fcore","2.packages\u002F1.core","i-lucide-box",{"title":46,"path":47,"stem":48,"package":11,"category":11,"icon":49},"@vyui\u002Fkit","\u002Fpackages\u002Fkit","2.packages\u002F2.kit","i-lucide-layers",false,{"title":52,"package":11,"category":11,"icon":53,"path":54,"stem":55,"children":56},"Components","i-lucide-layout-grid","\u002Fcomponents","3.components",[57,59,66,72,78,84,89,94,99,105,111,116,121,126,131,137,142,147,152,156,161,165,170,175,180,185,190,195,200,204,209,214,219,224,229,234,239,244,249,254,258,262,267,272,277,282,287,292,296,300,304,308,312],{"title":52,"path":54,"stem":58,"package":11,"category":11,"icon":53},"3.components\u002Findex",{"title":60,"path":61,"stem":62,"package":63,"category":64,"icon":65},"Accordion","\u002Fcomponents\u002Faccordion","3.components\u002Faccordion","kit","Navigation","i-lucide-list-collapse",{"title":67,"path":68,"stem":69,"package":63,"category":70,"icon":71},"Alert","\u002Fcomponents\u002Falert","3.components\u002Falert","Data Display","i-lucide-triangle-alert",{"title":73,"path":74,"stem":75,"package":76,"category":77,"icon":71},"Alert Dialog","\u002Fcomponents\u002Falert-dialog","3.components\u002Falert-dialog","core","Overlay",{"title":79,"path":80,"stem":81,"package":63,"category":82,"icon":83},"App","\u002Fcomponents\u002Fapp","3.components\u002Fapp","Layout","i-lucide-smartphone",{"title":85,"path":86,"stem":87,"package":63,"category":82,"icon":88},"Aspect Ratio","\u002Fcomponents\u002Faspect-ratio","3.components\u002Faspect-ratio","i-lucide-ratio",{"title":90,"path":91,"stem":92,"package":63,"category":70,"icon":93},"Avatar","\u002Fcomponents\u002Favatar","3.components\u002Favatar","i-lucide-circle-user-round",{"title":95,"path":96,"stem":97,"package":63,"category":70,"icon":98},"Avatar Group","\u002Fcomponents\u002Favatar-group","3.components\u002Favatar-group","i-lucide-users-round",{"title":100,"path":101,"stem":102,"package":63,"category":103,"icon":104},"Button","\u002Fcomponents\u002Fbutton","3.components\u002Fbutton","Buttons","i-lucide-square-mouse-pointer",{"title":106,"path":107,"stem":108,"package":63,"category":109,"icon":110},"Calendar","\u002Fcomponents\u002Fcalendar","3.components\u002Fcalendar","Form","i-lucide-calendar-days",{"title":112,"path":113,"stem":114,"package":63,"category":82,"icon":115},"Card","\u002Fcomponents\u002Fcard","3.components\u002Fcard","i-lucide-square",{"title":117,"path":118,"stem":119,"package":63,"category":109,"icon":120},"Checkbox","\u002Fcomponents\u002Fcheckbox","3.components\u002Fcheckbox","i-lucide-square-check",{"title":122,"path":123,"stem":124,"package":76,"category":64,"icon":125},"Collapsible","\u002Fcomponents\u002Fcollapsible","3.components\u002Fcollapsible","i-lucide-chevrons-down-up",{"title":127,"path":128,"stem":129,"package":76,"category":77,"icon":130},"Dialog","\u002Fcomponents\u002Fdialog","3.components\u002Fdialog","i-lucide-app-window",{"title":132,"path":133,"stem":134,"package":76,"category":135,"icon":136},"Draggable","\u002Fcomponents\u002Fdraggable","3.components\u002Fdraggable","Gestures & Lists","i-lucide-move",{"title":138,"path":139,"stem":140,"package":63,"category":77,"icon":141},"Drawer","\u002Fcomponents\u002Fdrawer","3.components\u002Fdrawer","i-lucide-panel-bottom",{"title":143,"path":144,"stem":145,"package":63,"category":77,"icon":146},"Dropdown Menu","\u002Fcomponents\u002Fdropdown-menu","3.components\u002Fdropdown-menu","i-lucide-menu",{"title":148,"path":149,"stem":150,"package":63,"category":135,"icon":151},"Feed List","\u002Fcomponents\u002Ffeed-list","3.components\u002Ffeed-list","i-lucide-list",{"title":109,"path":153,"stem":154,"package":63,"category":109,"icon":155},"\u002Fcomponents\u002Fform","3.components\u002Fform","i-lucide-clipboard-list",{"title":157,"path":158,"stem":159,"package":63,"category":109,"icon":160},"Form Field","\u002Fcomponents\u002Fform-field","3.components\u002Fform-field","i-lucide-form-input",{"title":162,"path":163,"stem":164,"package":76,"category":70,"icon":22},"Icon","\u002Fcomponents\u002Ficon","3.components\u002Ficon",{"title":166,"path":167,"stem":168,"package":63,"category":109,"icon":169},"Input","\u002Fcomponents\u002Finput","3.components\u002Finput","i-lucide-text-cursor-input",{"title":171,"path":172,"stem":173,"package":63,"category":174,"icon":141},"Island","\u002Fcomponents\u002Fisland","3.components\u002Fisland","Dynamic Island",{"title":176,"path":177,"stem":178,"package":63,"category":174,"icon":179},"Island Button","\u002Fcomponents\u002Fisland-button","3.components\u002Fisland-button","i-lucide-circle-ellipsis",{"title":181,"path":182,"stem":183,"package":63,"category":174,"icon":184},"Island Group","\u002Fcomponents\u002Fisland-group","3.components\u002Fisland-group","i-lucide-panels-top-left",{"title":186,"path":187,"stem":188,"package":63,"category":11,"icon":189},"KeyboardAware","\u002Fcomponents\u002Fkeyboard-aware","3.components\u002Fkeyboard-aware","i-lucide-keyboard",{"title":191,"path":192,"stem":193,"package":63,"category":109,"icon":194},"Label","\u002Fcomponents\u002Flabel","3.components\u002Flabel","i-lucide-tag",{"title":196,"path":197,"stem":198,"package":63,"category":77,"icon":199},"Modal","\u002Fcomponents\u002Fmodal","3.components\u002Fmodal","i-lucide-gallery-vertical-end",{"title":64,"path":201,"stem":202,"package":76,"category":64,"icon":203},"\u002Fcomponents\u002Fnavigation","3.components\u002Fnavigation","i-lucide-route",{"title":205,"path":206,"stem":207,"package":63,"category":109,"icon":208},"Number Field","\u002Fcomponents\u002Fnumber-field","3.components\u002Fnumber-field","i-lucide-list-plus",{"title":210,"path":211,"stem":212,"package":63,"category":109,"icon":213},"Pin Input","\u002Fcomponents\u002Fpin-input","3.components\u002Fpin-input","i-lucide-key-round",{"title":215,"path":216,"stem":217,"package":63,"category":82,"icon":218},"Placeholder","\u002Fcomponents\u002Fplaceholder","3.components\u002Fplaceholder","i-lucide-square-dashed",{"title":220,"path":221,"stem":222,"package":63,"category":77,"icon":223},"Popover","\u002Fcomponents\u002Fpopover","3.components\u002Fpopover","i-lucide-message-square-more",{"title":225,"path":226,"stem":227,"package":63,"category":70,"icon":228},"Progress","\u002Fcomponents\u002Fprogress","3.components\u002Fprogress","i-lucide-chart-no-axes-column-increasing",{"title":230,"path":231,"stem":232,"package":63,"category":109,"icon":233},"Radio Group","\u002Fcomponents\u002Fradio-group","3.components\u002Fradio-group","i-lucide-circle-dot",{"title":235,"path":236,"stem":237,"package":63,"category":109,"icon":238},"Rating","\u002Fcomponents\u002Frating","3.components\u002Frating","i-lucide-star",{"title":240,"path":241,"stem":242,"package":76,"category":82,"icon":243},"Scroll View","\u002Fcomponents\u002Fscroll-view","3.components\u002Fscroll-view","i-lucide-scroll",{"title":245,"path":246,"stem":247,"package":63,"category":109,"icon":248},"Select","\u002Fcomponents\u002Fselect","3.components\u002Fselect","i-lucide-list-check",{"title":250,"path":251,"stem":252,"package":63,"category":82,"icon":253},"Separator","\u002Fcomponents\u002Fseparator","3.components\u002Fseparator","i-lucide-separator-horizontal",{"title":255,"path":256,"stem":257,"package":76,"category":77,"icon":141},"Sheet","\u002Fcomponents\u002Fsheet","3.components\u002Fsheet",{"title":259,"path":260,"stem":261,"package":63,"category":82,"icon":184},"Skeleton","\u002Fcomponents\u002Fskeleton","3.components\u002Fskeleton",{"title":263,"path":264,"stem":265,"package":63,"category":109,"icon":266},"Slider","\u002Fcomponents\u002Fslider","3.components\u002Fslider","i-lucide-sliders-horizontal",{"title":268,"path":269,"stem":270,"package":63,"category":135,"icon":271},"Sortable","\u002Fcomponents\u002Fsortable","3.components\u002Fsortable","i-lucide-list-restart",{"title":273,"path":274,"stem":275,"package":63,"category":64,"icon":276},"Stepper","\u002Fcomponents\u002Fstepper","3.components\u002Fstepper","i-lucide-list-ordered",{"title":278,"path":279,"stem":280,"package":63,"category":135,"icon":281},"Swipe Action","\u002Fcomponents\u002Fswipe-action","3.components\u002Fswipe-action","i-lucide-move-horizontal",{"title":283,"path":284,"stem":285,"package":63,"category":135,"icon":286},"Swiper","\u002Fcomponents\u002Fswiper","3.components\u002Fswiper","i-lucide-gallery-horizontal-end",{"title":288,"path":289,"stem":290,"package":63,"category":109,"icon":291},"Switch","\u002Fcomponents\u002Fswitch","3.components\u002Fswitch","i-lucide-toggle-right",{"title":293,"path":294,"stem":295,"package":63,"category":64,"icon":184},"Tabs","\u002Fcomponents\u002Ftabs","3.components\u002Ftabs",{"title":297,"path":298,"stem":299,"package":63,"category":109,"icon":169},"Textarea","\u002Fcomponents\u002Ftextarea","3.components\u002Ftextarea",{"title":301,"path":302,"stem":303,"package":63,"category":77,"icon":223},"Toast","\u002Fcomponents\u002Ftoast","3.components\u002Ftoast",{"title":305,"path":306,"stem":307,"package":63,"category":109,"icon":291},"Toggle","\u002Fcomponents\u002Ftoggle","3.components\u002Ftoggle",{"title":309,"path":310,"stem":311,"package":63,"category":109,"icon":184},"Toggle Group","\u002Fcomponents\u002Ftoggle-group","3.components\u002Ftoggle-group",{"title":313,"path":314,"stem":315,"package":63,"category":77,"icon":316},"Tray","\u002Fcomponents\u002Ftray","3.components\u002Ftray","i-lucide-square-dashed-bottom",{"title":318,"path":319,"stem":320,"children":321,"package":11,"category":11,"icon":323},"Theming","\u002Ftheming","4.theming\u002F1.index",[322,324,328,333,338],{"title":318,"path":319,"stem":320,"package":11,"category":11,"icon":323},"i-lucide-palette",{"title":325,"path":326,"stem":327,"package":11,"category":11,"icon":266},"Overrides","\u002Ftheming\u002Foverrides","4.theming\u002F2.overrides",{"title":329,"path":330,"stem":331,"package":11,"category":11,"icon":332},"Colors","\u002Ftheming\u002Fcolors","4.theming\u002F3.colors","i-lucide-swatch-book",{"title":334,"path":335,"stem":336,"package":11,"category":11,"icon":337},"Dark Mode","\u002Ftheming\u002Fdark-mode","4.theming\u002F4.dark-mode","i-lucide-moon",{"title":339,"path":340,"stem":341,"package":11,"category":11,"icon":342},"Fonts","\u002Ftheming\u002Ffonts","4.theming\u002F5.fonts","i-lucide-type",{"title":344,"path":345,"stem":346,"package":11,"category":11,"icon":347},"Accessibility","\u002Faccessibility","5.accessibility","i-lucide-accessibility",{"title":349,"path":350,"stem":351,"package":11,"category":11,"icon":352},"i18n","\u002Fi18n","6.i18n","i-lucide-languages",{"title":354,"path":355,"stem":356,"children":357,"package":11,"category":11,"icon":359},"Composables","\u002Fcomposables","7.composables\u002F1.index",[358,360,365,370,375,380,384,389,394,399,403,408,412,416,421,426],{"title":354,"path":355,"stem":356,"package":11,"category":11,"icon":359},"i-lucide-square-function",{"title":361,"path":362,"stem":363,"package":11,"category":11,"icon":364},"useEmitAsProps","\u002Fcomposables\u002Fuse-emit-as-props","7.composables\u002F10.use-emit-as-props","i-lucide-zap",{"title":366,"path":367,"stem":368,"package":11,"category":11,"icon":369},"useForwardPropsEmits","\u002Fcomposables\u002Fuse-forward-props-emits","7.composables\u002F11.use-forward-props-emits","i-lucide-merge",{"title":371,"path":372,"stem":373,"package":11,"category":11,"icon":374},"useForwardExpose","\u002Fcomposables\u002Fuse-forward-expose","7.composables\u002F12.use-forward-expose","i-lucide-share-2",{"title":376,"path":377,"stem":378,"package":11,"category":11,"icon":379},"usePrimitiveElement","\u002Fcomposables\u002Fuse-primitive-element","7.composables\u002F14.use-primitive-element","i-lucide-crosshair",{"title":381,"path":382,"stem":383,"package":11,"category":11,"icon":83},"useSafeArea","\u002Fcomposables\u002Fuse-safe-area","7.composables\u002F15.use-safe-area",{"title":385,"path":386,"stem":387,"package":11,"category":11,"icon":388},"useGlobalEvent","\u002Fcomposables\u002Fuse-global-event","7.composables\u002F16.use-global-event","i-lucide-radio",{"title":390,"path":391,"stem":392,"package":11,"category":11,"icon":393},"getViewportSize","\u002Fcomposables\u002Fget-viewport-size","7.composables\u002F17.get-viewport-size","i-lucide-scaling",{"title":395,"path":396,"stem":397,"package":11,"category":11,"icon":398},"useAppConfig","\u002Fcomposables\u002Fuse-app-config","7.composables\u002F2.use-app-config","i-lucide-settings",{"title":400,"path":401,"stem":402,"package":11,"category":11,"icon":337},"useColorMode","\u002Fcomposables\u002Fuse-color-mode","7.composables\u002F3.use-color-mode",{"title":404,"path":405,"stem":406,"package":11,"category":11,"icon":407},"useComponentIcons","\u002Fcomposables\u002Fuse-component-icons","7.composables\u002F4.use-component-icons","i-lucide-shapes",{"title":409,"path":410,"stem":411,"package":11,"category":11,"icon":141},"useTray","\u002Fcomposables\u002Fuse-tray","7.composables\u002F5.use-tray",{"title":413,"path":414,"stem":415,"package":11,"category":11,"icon":352},"i18n composables","\u002Fcomposables\u002Fi18n-composables","7.composables\u002F6.i18n-composables",{"title":417,"path":418,"stem":419,"package":11,"category":11,"icon":420},"useId","\u002Fcomposables\u002Fuse-id","7.composables\u002F7.use-id","i-lucide-hash",{"title":422,"path":423,"stem":424,"package":11,"category":11,"icon":425},"useFilter","\u002Fcomposables\u002Fuse-filter","7.composables\u002F8.use-filter","i-lucide-filter",{"title":427,"path":428,"stem":429,"package":11,"category":11,"icon":430},"useForwardProps","\u002Fcomposables\u002Fuse-forward-props","7.composables\u002F9.use-forward-props","i-lucide-arrow-right-left",{"title":432,"path":433,"stem":434,"children":435,"package":11,"category":11,"icon":437},"Guides","\u002Fguides","8.guides\u002F1.index",[436,438,442,447,451,456,461,466,470,475,479,484],{"title":432,"path":433,"stem":434,"package":11,"category":11,"icon":437},"i-lucide-book-open",{"title":439,"path":440,"stem":441,"package":11,"category":11,"icon":364},"Instant first frame","\u002Fguides\u002Finstant-first-frame-rendering","8.guides\u002F10.instant-first-frame-rendering",{"title":443,"path":444,"stem":445,"package":11,"category":11,"icon":446},"Why Vy UI","\u002Fguides\u002Fwhy-vy-ui","8.guides\u002F11.why-vy-ui","i-lucide-help-circle",{"title":448,"path":449,"stem":450,"package":11,"category":11,"icon":22},"Sparkling","\u002Fguides\u002Fsparkling","8.guides\u002F12.sparkling",{"title":452,"path":453,"stem":454,"package":11,"category":11,"icon":455},"Lynx UI frameworks","\u002Fguides\u002Flynx-ui-frameworks","8.guides\u002F2.lynx-ui-frameworks","i-lucide-library",{"title":457,"path":458,"stem":459,"package":11,"category":11,"icon":460},"Vue Lynx","\u002Fguides\u002Fvue-lynx","8.guides\u002F3.vue-lynx","i-lucide-component",{"title":462,"path":463,"stem":464,"package":11,"category":11,"icon":465},"Lynx vs React Native","\u002Fguides\u002Flynx-vs-react-native","8.guides\u002F4.lynx-vs-react-native","i-lucide-git-compare",{"title":467,"path":468,"stem":469,"package":11,"category":11,"icon":83},"Testing on device","\u002Fguides\u002Ftesting-on-device","8.guides\u002F5.testing-on-device",{"title":471,"path":472,"stem":473,"package":11,"category":11,"icon":474},"Testing with Xcode","\u002Fguides\u002Ftesting-with-xcode","8.guides\u002F6.testing-with-xcode","i-lucide-apple",{"title":476,"path":477,"stem":478,"package":11,"category":11,"icon":27},"rspeedy dev server","\u002Fguides\u002Frspeedy-dev-server","8.guides\u002F7.rspeedy-dev-server",{"title":480,"path":481,"stem":482,"package":11,"category":11,"icon":483},"Tailwind on Lynx","\u002Fguides\u002Ftailwind-on-lynx","8.guides\u002F8.tailwind-on-lynx","i-lucide-wind",{"title":485,"path":486,"stem":487,"package":11,"category":11,"icon":488},"Theming on Lynx","\u002Fguides\u002Ftheming-on-lynx","8.guides\u002F9.theming-on-lynx","i-lucide-paintbrush",{"id":490,"title":448,"body":491,"category":11,"description":1489,"extension":1490,"links":11,"meta":1491,"navigation":1492,"package":11,"path":449,"seo":1493,"stem":450,"__hash__":1496},"docs\u002F8.guides\u002F12.sparkling.md",{"type":492,"value":493,"toc":1478},"minimark",[494,511,514,519,522,541,552,600,625,629,632,640,694,705,709,716,899,902,1091,1094,1098,1101,1224,1238,1241,1245,1262,1279,1283,1305,1344,1348,1356,1359,1369,1373,1411,1426,1441,1447,1451,1474],[495,496,497,498,502,503,506,507,510],"p",{},"Lynx is built to be embedded, so it ships the renderer and the bundler and leaves the application shell to whatever hosts it. ",[499,500,501],"code",{},"rspeedy build"," produces a ",[499,504,505],{},"main.lynx.bundle",", Lynx Go loads it from a QR code, and the rest is the host's job: the Activity or view controller that holds a ",[499,508,509],{},"LynxView",", the mechanism that opens a second page, and every call that crosses from JavaScript into native code. Sparkling is TikTok's shell for that, open-sourced in November 2025 under Apache-2.0 and described in its own documentation as unlocking \"Lynx at TikTok scale\".",[495,512,513],{},"What it actually gives you is the part of a Lynx app that is not the UI. Native SDKs for iOS and Android host the runtime, a scheme URL format identifies pages, a code generator produces the JavaScript-to-native bridge from a TypeScript declaration, and a CLI wraps the build, the dev server, and the simulator launch. The published modules cover routing, key-value storage, and media picking, which are the three things every app needs and nobody enjoys writing twice.",[515,516,518],"h2",{"id":517},"containers-hold-the-runtime","Containers hold the runtime",[495,520,521],{},"Sparkling content always runs inside a native container, and there are two kinds because there are two ways to adopt Lynx.",[495,523,524,525,528,529,532,533,536,537,540],{},"A full-page container is a screen the platform owns: ",[499,526,527],{},"SPKViewController"," on iOS, ",[499,530,531],{},"SparklingActivity"," on Android. The native layer manages the navigation bar, the status bar, orientation, and the loading and error views, and it forwards ",[499,534,535],{},"viewDidAppear"," and ",[499,538,539],{},"onResume"," into the Lynx runtime for you.",[495,542,543,544,547,548,551],{},"An embedded container is a plain view you place yourself, ",[499,545,546],{},"SPKContainerView"," or ",[499,549,550],{},"SparklingView",", sized and positioned by the surrounding native layout. That is the one that makes brownfield adoption real, because a card, a banner, or one panel of an otherwise native screen can come from a Lynx bundle without the host app surrendering navigation:",[553,554,560],"pre",{"className":555,"code":556,"filename":557,"language":558,"meta":559,"style":559},"language-kotlin shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","val ctx = SparklingContext().apply {\n  scheme = \"hybrid:\u002F\u002Flynxview?bundle=card.lynx.bundle\"\n}\nval spkView = Sparkling.build(this, ctx).createView()\ncontainer.addView(spkView)\nspkView?.loadUrl()\n","MainActivity.kt","kotlin","",[499,561,562,570,576,582,588,594],{"__ignoreMap":559},[563,564,567],"span",{"class":565,"line":566},"line",1,[563,568,569],{},"val ctx = SparklingContext().apply {\n",[563,571,573],{"class":565,"line":572},2,[563,574,575],{},"  scheme = \"hybrid:\u002F\u002Flynxview?bundle=card.lynx.bundle\"\n",[563,577,579],{"class":565,"line":578},3,[563,580,581],{},"}\n",[563,583,585],{"class":565,"line":584},4,[563,586,587],{},"val spkView = Sparkling.build(this, ctx).createView()\n",[563,589,591],{"class":565,"line":590},5,[563,592,593],{},"container.addView(spkView)\n",[563,595,597],{"class":565,"line":596},6,[563,598,599],{},"spkView?.loadUrl()\n",[495,601,602,603,536,606,609,610,613,614,617,618,621,622,624],{},"The trade is that the SDK does not own your view controller, so visibility has to be forwarded by hand through ",[499,604,605],{},"handleViewDidAppear",[499,607,608],{},"handleViewDidDisappear"," on iOS, or ",[499,611,612],{},"onShowEvent()",", ",[499,615,616],{},"onHideEvent()",", and ",[499,619,620],{},"release()"," on Android. Forgetting ",[499,623,620],{}," leaves a runtime alive behind a screen the user has already left.",[515,626,628],{"id":627},"schemes-are-the-contract","Schemes are the contract",[495,630,631],{},"Both container types are opened by a URL rather than by an API call, which is what lets JavaScript open a native screen without knowing anything about native code:",[553,633,638],{"className":634,"code":636,"language":637},[635],"language-text","hybrid:\u002F\u002Flynxview_page?bundle=detail.lynx.bundle&title=Detail&hide_nav_bar=1\n","text",[499,639,636],{"__ignoreMap":559},[495,641,642,643,646,647,650,651,654,655,658,659,613,662,613,665,613,668,613,671,613,674,613,677,613,680,613,683,617,686,689,690,693],{},"The host selects the container (",[499,644,645],{},"lynxview_page"," for a standard Lynx page, ",[499,648,649],{},"lynxview_card"," for an Android card, ",[499,652,653],{},"webview"," for a WebView), and the query string configures it. ",[499,656,657],{},"bundle"," is the only required parameter; the rest are chrome, including ",[499,660,661],{},"title",[499,663,664],{},"title_color",[499,666,667],{},"nav_bar_color",[499,669,670],{},"container_bg_color",[499,672,673],{},"hide_nav_bar",[499,675,676],{},"hide_status_bar",[499,678,679],{},"trans_status_bar",[499,681,682],{},"force_theme_style",[499,684,685],{},"hide_loading",[499,687,688],{},"hide_error",". Anything Sparkling does not recognise is passed through to the page in ",[499,691,692],{},"lynx.__globalProps.queryItems",", so custom parameters cost nothing.",[495,695,696,697,700,701,704],{},"Colors must be six-digit hex, because the two platforms disagree about how to read the eight-digit form, and a literal ",[499,698,699],{},"#"," in a value has to be encoded as ",[499,702,703],{},"%23",".",[515,706,708],{"id":707},"pages-are-build-entries-not-registered-routes","Pages are build entries, not registered routes",[495,710,711,712,715],{},"Every entry in ",[499,713,714],{},"source.entry"," becomes a bundle, and every bundle is navigable the moment it exists. There is no route table to keep in sync, which for a multi-page app is a genuine simplification:",[553,717,722],{"className":718,"code":719,"filename":720,"language":721,"meta":559,"style":559},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const config = {\n  lynxConfig,\n  appName: 'MyApp',\n  router: {\n    main: { path: '.\u002Fsrc\u002Fpages\u002Fmain' },\n    detail: { path: '.\u002Fsrc\u002Fpages\u002Fdetail' },\n  },\n  platform: {\n    android: { packageName: 'com.example.myapp' },\n    ios: { bundleIdentifier: 'com.example.myapp' },\n  },\n}\n","app.config.ts","ts",[499,723,724,741,749,770,779,804,826,832,842,866,889,894],{"__ignoreMap":559},[563,725,726,730,734,738],{"class":565,"line":566},[563,727,729],{"class":728},"spNyl","const",[563,731,733],{"class":732},"sTEyZ"," config ",[563,735,737],{"class":736},"sMK4o","=",[563,739,740],{"class":736}," {\n",[563,742,743,746],{"class":565,"line":572},[563,744,745],{"class":732},"  lynxConfig",[563,747,748],{"class":736},",\n",[563,750,751,755,758,761,765,768],{"class":565,"line":578},[563,752,754],{"class":753},"swJcz","  appName",[563,756,757],{"class":736},":",[563,759,760],{"class":736}," '",[563,762,764],{"class":763},"sfazB","MyApp",[563,766,767],{"class":736},"'",[563,769,748],{"class":736},[563,771,772,775,777],{"class":565,"line":584},[563,773,774],{"class":753},"  router",[563,776,757],{"class":736},[563,778,740],{"class":736},[563,780,781,784,786,789,792,794,796,799,801],{"class":565,"line":590},[563,782,783],{"class":753},"    main",[563,785,757],{"class":736},[563,787,788],{"class":736}," {",[563,790,791],{"class":753}," path",[563,793,757],{"class":736},[563,795,760],{"class":736},[563,797,798],{"class":763},".\u002Fsrc\u002Fpages\u002Fmain",[563,800,767],{"class":736},[563,802,803],{"class":736}," },\n",[563,805,806,809,811,813,815,817,819,822,824],{"class":565,"line":596},[563,807,808],{"class":753},"    detail",[563,810,757],{"class":736},[563,812,788],{"class":736},[563,814,791],{"class":753},[563,816,757],{"class":736},[563,818,760],{"class":736},[563,820,821],{"class":763},".\u002Fsrc\u002Fpages\u002Fdetail",[563,823,767],{"class":736},[563,825,803],{"class":736},[563,827,829],{"class":565,"line":828},7,[563,830,831],{"class":736},"  },\n",[563,833,835,838,840],{"class":565,"line":834},8,[563,836,837],{"class":753},"  platform",[563,839,757],{"class":736},[563,841,740],{"class":736},[563,843,845,848,850,852,855,857,859,862,864],{"class":565,"line":844},9,[563,846,847],{"class":753},"    android",[563,849,757],{"class":736},[563,851,788],{"class":736},[563,853,854],{"class":753}," packageName",[563,856,757],{"class":736},[563,858,760],{"class":736},[563,860,861],{"class":763},"com.example.myapp",[563,863,767],{"class":736},[563,865,803],{"class":736},[563,867,869,872,874,876,879,881,883,885,887],{"class":565,"line":868},10,[563,870,871],{"class":753},"    ios",[563,873,757],{"class":736},[563,875,788],{"class":736},[563,877,878],{"class":753}," bundleIdentifier",[563,880,757],{"class":736},[563,882,760],{"class":736},[563,884,861],{"class":763},[563,886,767],{"class":736},[563,888,803],{"class":736},[563,890,892],{"class":565,"line":891},11,[563,893,831],{"class":736},[563,895,897],{"class":565,"line":896},12,[563,898,581],{"class":736},[495,900,901],{},"Navigation from JavaScript then names a bundle and passes parameters, and the destination reads them back off global props:",[553,903,905],{"className":718,"code":904,"language":721,"meta":559,"style":559},"import { navigate } from 'sparkling-navigation'\n\nnavigate(\n  { path: 'pages\u002Fdetail.lynx.bundle', options: { params: { title: 'Detail', itemId: '123' } } },\n  res => console.log(res.code, res.msg),\n)\n\n\u002F\u002F on the detail page\nconst { itemId } = lynx.__globalProps.queryItems\n",[499,906,907,932,938,947,1012,1048,1053,1057,1063],{"__ignoreMap":559},[563,908,909,913,915,918,921,924,926,929],{"class":565,"line":566},[563,910,912],{"class":911},"s7zQu","import",[563,914,788],{"class":736},[563,916,917],{"class":732}," navigate",[563,919,920],{"class":736}," }",[563,922,923],{"class":911}," from",[563,925,760],{"class":736},[563,927,928],{"class":763},"sparkling-navigation",[563,930,931],{"class":736},"'\n",[563,933,934],{"class":565,"line":572},[563,935,937],{"emptyLinePlaceholder":936},true,"\n",[563,939,940,944],{"class":565,"line":578},[563,941,943],{"class":942},"s2Zo4","navigate",[563,945,946],{"class":732},"(\n",[563,948,949,952,954,956,958,961,963,966,969,971,973,976,978,980,983,985,987,990,992,994,997,999,1001,1004,1006,1008,1010],{"class":565,"line":584},[563,950,951],{"class":736},"  {",[563,953,791],{"class":753},[563,955,757],{"class":736},[563,957,760],{"class":736},[563,959,960],{"class":763},"pages\u002Fdetail.lynx.bundle",[563,962,767],{"class":736},[563,964,965],{"class":736},",",[563,967,968],{"class":753}," options",[563,970,757],{"class":736},[563,972,788],{"class":736},[563,974,975],{"class":753}," params",[563,977,757],{"class":736},[563,979,788],{"class":736},[563,981,982],{"class":753}," title",[563,984,757],{"class":736},[563,986,760],{"class":736},[563,988,989],{"class":763},"Detail",[563,991,767],{"class":736},[563,993,965],{"class":736},[563,995,996],{"class":753}," itemId",[563,998,757],{"class":736},[563,1000,760],{"class":736},[563,1002,1003],{"class":763},"123",[563,1005,767],{"class":736},[563,1007,920],{"class":736},[563,1009,920],{"class":736},[563,1011,803],{"class":736},[563,1013,1014,1018,1021,1024,1026,1029,1032,1034,1036,1038,1041,1043,1046],{"class":565,"line":590},[563,1015,1017],{"class":1016},"sHdIc","  res",[563,1019,1020],{"class":728}," =>",[563,1022,1023],{"class":732}," console",[563,1025,704],{"class":736},[563,1027,1028],{"class":942},"log",[563,1030,1031],{"class":732},"(res",[563,1033,704],{"class":736},[563,1035,499],{"class":732},[563,1037,965],{"class":736},[563,1039,1040],{"class":732}," res",[563,1042,704],{"class":736},[563,1044,1045],{"class":732},"msg)",[563,1047,748],{"class":736},[563,1049,1050],{"class":565,"line":596},[563,1051,1052],{"class":732},")\n",[563,1054,1055],{"class":565,"line":828},[563,1056,937],{"emptyLinePlaceholder":936},[563,1058,1059],{"class":565,"line":834},[563,1060,1062],{"class":1061},"sHwdD","\u002F\u002F on the detail page\n",[563,1064,1065,1067,1069,1072,1075,1078,1081,1083,1086,1088],{"class":565,"line":844},[563,1066,729],{"class":728},[563,1068,788],{"class":736},[563,1070,1071],{"class":732}," itemId ",[563,1073,1074],{"class":736},"}",[563,1076,1077],{"class":736}," =",[563,1079,1080],{"class":732}," lynx",[563,1082,704],{"class":736},[563,1084,1085],{"class":732},"__globalProps",[563,1087,704],{"class":736},[563,1089,1090],{"class":732},"queryItems\n",[495,1092,1093],{},"Each page is its own container with its own LynxView, so state does not survive a navigation the way it would in a single-page router, and a shared store has to live in storage or in global props rather than in memory.",[515,1095,1097],{"id":1096},"the-method-bridge-is-generated","The method bridge is generated",[495,1099,1100],{},"Custom native calls start as a TypeScript declaration file with no implementation, which is the single source of truth:",[553,1102,1105],{"className":718,"code":1103,"filename":1104,"language":721,"meta":559,"style":559},"export interface HelloRequest {\n  name: string\n  style?: 'formal' | 'casual'\n}\n\ndeclare function hello(\n  params: HelloRequest,\n  callback: (result: HelloResponse) => void,\n): void\n","src\u002Fmy-greeting\u002Fmy-greeting.d.ts",[499,1106,1107,1121,1131,1156,1160,1164,1177,1188,1216],{"__ignoreMap":559},[563,1108,1109,1112,1115,1119],{"class":565,"line":566},[563,1110,1111],{"class":911},"export",[563,1113,1114],{"class":728}," interface",[563,1116,1118],{"class":1117},"sBMFI"," HelloRequest",[563,1120,740],{"class":736},[563,1122,1123,1126,1128],{"class":565,"line":572},[563,1124,1125],{"class":753},"  name",[563,1127,757],{"class":736},[563,1129,1130],{"class":1117}," string\n",[563,1132,1133,1136,1139,1141,1144,1146,1149,1151,1154],{"class":565,"line":578},[563,1134,1135],{"class":753},"  style",[563,1137,1138],{"class":736},"?:",[563,1140,760],{"class":736},[563,1142,1143],{"class":763},"formal",[563,1145,767],{"class":736},[563,1147,1148],{"class":736}," |",[563,1150,760],{"class":736},[563,1152,1153],{"class":763},"casual",[563,1155,931],{"class":736},[563,1157,1158],{"class":565,"line":584},[563,1159,581],{"class":736},[563,1161,1162],{"class":565,"line":590},[563,1163,937],{"emptyLinePlaceholder":936},[563,1165,1166,1169,1172,1175],{"class":565,"line":596},[563,1167,1168],{"class":728},"declare",[563,1170,1171],{"class":728}," function",[563,1173,1174],{"class":942}," hello",[563,1176,946],{"class":736},[563,1178,1179,1182,1184,1186],{"class":565,"line":828},[563,1180,1181],{"class":1016},"  params",[563,1183,757],{"class":736},[563,1185,1118],{"class":1117},[563,1187,748],{"class":736},[563,1189,1190,1193,1195,1198,1201,1203,1206,1209,1211,1214],{"class":565,"line":834},[563,1191,1192],{"class":942},"  callback",[563,1194,757],{"class":736},[563,1196,1197],{"class":736}," (",[563,1199,1200],{"class":1016},"result",[563,1202,757],{"class":736},[563,1204,1205],{"class":1117}," HelloResponse",[563,1207,1208],{"class":736},")",[563,1210,1020],{"class":728},[563,1212,1213],{"class":1117}," void",[563,1215,748],{"class":736},[563,1217,1218,1221],{"class":565,"line":844},[563,1219,1220],{"class":736},"):",[563,1222,1223],{"class":1117}," void\n",[495,1225,1226,1229,1230,1233,1234,1237],{},[499,1227,1228],{},"npx sparkling-method-cli codegen"," turns that into an abstract Kotlin class, a Swift class, a typed TypeScript wrapper, and a metadata file, leaving you to implement ",[499,1231,1232],{},"execute"," on each platform. Interfaces become model classes and union types become enums, so a parameter renamed in the ",[499,1235,1236],{},".d.ts"," breaks both native builds rather than failing silently at runtime, which is the main thing this design buys.",[495,1239,1240],{},"It does not make the native work disappear. Every custom method is still Kotlin plus Swift plus a review of both, so the ceiling on how much of your app can be pure TypeScript is set by how many native capabilities you need.",[515,1242,1244],{"id":1243},"the-development-loop","The development loop",[495,1246,1247,1250,1251,536,1254,1257,1258,1261],{},[499,1248,1249],{},"npx sparkling dev"," starts an Rspeedy dev server on port 5969, chosen because it spells LYNX on a phone keypad, serves one endpoint per entry, and prints a QR code that Sparkling Go or LynxExplorer can scan. ",[499,1252,1253],{},"npx sparkling run:ios",[499,1255,1256],{},"run:android"," build the native shell in debug, which loads bundles over HTTP rather than from assets, and saves push hot updates into the running app. ",[499,1259,1260],{},"npx sparkling doctor"," checks Node, the JDK, the Android SDK, Ruby, Xcode, CocoaPods, and the simulator before you waste twenty minutes on a toolchain problem, and it is the first command worth running.",[495,1263,1264,1265,536,1268,1271,1272,536,1275,1278],{},"Release builds go through ",[499,1266,1267],{},"npx sparkling build",[499,1269,1270],{},"copy-assets",", which drops the bundles into ",[499,1273,1274],{},"android\u002Fapp\u002Fsrc\u002Fmain\u002Fassets",[499,1276,1277],{},"ios\u002FLynxResources"," for the shell to load locally.",[515,1280,1282],{"id":1281},"what-it-means-for-a-vue-lynx-app","What it means for a Vue Lynx app",[495,1284,1285,1286,1288,1289,1292,1293,1296,1297,1300,1301,1304],{},"Sparkling's scaffolder and templates are ReactLynx, and the documentation is written against React throughout. The seam is lower than that, though: ",[499,1287,720],{}," wraps an ordinary Rspeedy config under ",[499,1290,1291],{},"lynxConfig",", the container loads a compiled ",[499,1294,1295],{},".lynx.bundle",", and vue-lynx emits exactly that artifact, so in principle ",[499,1298,1299],{},"pluginVueLynx"," goes where ",[499,1302,1303],{},"pluginReactLynx"," goes and the native side never knows the difference. I have not shipped a Vue app inside a Sparkling shell, so treat that as the mechanically obvious path rather than a verified one.",[495,1306,1307,1308,1310,1311,536,1314,1317,1318,1321,1322,536,1325,1328,1329,1332,1333,536,1336,1339,1340,1343],{},"Two pieces of Vy UI already assume Sparkling exists. ",[499,1309,381],{}," reads ",[499,1312,1313],{},"topHeight",[499,1315,1316],{},"bottomHeight"," from ",[499,1319,1320],{},"lynx.__globalProps",", which are Sparkling's names for the iOS safe-area insets, and normalizes them against Lynx Explorer's ",[499,1323,1324],{},"safeAreaTop",[499,1326,1327],{},"safeAreaBottom"," with the ",[499,1330,1331],{},"os"," field deciding whether the container has already inset the view natively. The same global props object carries ",[499,1334,1335],{},"theme",[499,1337,1338],{},"preferredTheme"," for color mode, and ",[499,1341,1342],{},"accessibleMode",", a bitmask whose low bit means VoiceOver or TalkBack is running.",[515,1345,1347],{"id":1346},"whether-to-use-it","Whether to use it",[495,1349,1350,1351,1355],{},"Sparkling is the easiest path for most Vue Lynx apps. If you need full control or a smaller shell, building your own native host (see our ",[1352,1353,1354],"a",{"href":472},"Xcode guide",") is equally valid. For most apps, Sparkling's containers, routing, bridge, and dev workflow cover what you need.",[495,1357,1358],{},"The one case where a custom host still wins is a single-screen app with no native bridge methods, where the Sparkling SDK is more weight than the app needs. Past that threshold — multiple pages, embedded containers, or any native calls — Sparkling pays for itself immediately.",[495,1360,1361,1362,1368],{},"The repository has been public since late November 2025 and is under active development, so expect the surface to keep settling. Nothing in the design is React-specific past the templates, and the rough edges a Vue project meets are the same ones a React project meets. The ",[1352,1363,1367],{"href":1364,"rel":1365},"https:\u002F\u002Ftiktok.github.io\u002Fsparkling\u002F",[1366],"nofollow","Sparkling documentation"," covers the full API surface, and is the reference for anything beyond this overview.",[515,1370,1372],{"id":1371},"getting-started","Getting started",[553,1374,1378],{"className":1375,"code":1376,"language":1377,"meta":559,"style":559},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","npm create sparkling-app@latest my-app\ncd my-app\nnpm run run:ios\n","sh",[499,1379,1380,1394,1401],{"__ignoreMap":559},[563,1381,1382,1385,1388,1391],{"class":565,"line":566},[563,1383,1384],{"class":1117},"npm",[563,1386,1387],{"class":763}," create",[563,1389,1390],{"class":763}," sparkling-app@latest",[563,1392,1393],{"class":763}," my-app\n",[563,1395,1396,1399],{"class":565,"line":572},[563,1397,1398],{"class":942},"cd",[563,1400,1393],{"class":763},[563,1402,1403,1405,1408],{"class":565,"line":578},[563,1404,1384],{"class":1117},[563,1406,1407],{"class":763}," run",[563,1409,1410],{"class":763}," run:ios\n",[495,1412,1413,1414,613,1417,613,1420,613,1422,1425],{},"The scaffolder produces a Lynx app project with Android and iOS native shells already wired for Sparkling, a working JS-to-native method example, and developer workflow commands (",[499,1415,1416],{},"dev",[499,1418,1419],{},"build",[499,1421,1256],{},[499,1423,1424],{},"run:ios","). Add Sparkling's published modules as needed:",[553,1427,1429],{"className":1375,"code":1428,"language":1377,"meta":559,"style":559},"npm install sparkling-storage\n",[499,1430,1431],{"__ignoreMap":559},[563,1432,1433,1435,1438],{"class":565,"line":566},[563,1434,1384],{"class":1117},[563,1436,1437],{"class":763}," install",[563,1439,1440],{"class":763}," sparkling-storage\n",[495,1442,1443,1444,1446],{},"Node.js 22 or 24 is required. For native targets you need Android Studio \u002F JDK 11 for Android and Xcode 16+ for iOS, plus Ruby (>=3.2.6, \u003C3.4) for the iOS build. ",[499,1445,1260],{}," checks all of this before you waste time on a toolchain problem.",[515,1448,1450],{"id":1449},"related","Related",[1452,1453,1454,1460,1465],"card-group",{},[1455,1456,1457],"card",{"icon":83,"title":467,"to":468},[495,1458,1459],{},"The QR-code loop with Lynx Go, and the config that has to be right first.",[1455,1461,1462],{"icon":474,"title":471,"to":472},[495,1463,1464],{},"Building a custom iOS host — for apps needing more control or minimal footprint.",[1455,1466,1467],{"icon":27,"title":476,"to":477},[495,1468,1469,1470,1473],{},"The dev URLs underneath ",[499,1471,1472],{},"sparkling dev",", and cycling the QR code.",[1475,1476,1477],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":559,"searchDepth":566,"depth":572,"links":1479},[1480,1481,1482,1483,1484,1485,1486,1487,1488],{"id":517,"depth":572,"text":518},{"id":627,"depth":572,"text":628},{"id":707,"depth":572,"text":708},{"id":1096,"depth":572,"text":1097},{"id":1243,"depth":572,"text":1244},{"id":1281,"depth":572,"text":1282},{"id":1346,"depth":572,"text":1347},{"id":1371,"depth":572,"text":1372},{"id":1449,"depth":572,"text":1450},"TikTok's open-source native shell for Lynx, covering containers, scheme routing, the typed native bridge, and where a Vue Lynx app fits into it.","md",{},{"icon":22},{"title":1494,"description":1495},"Sparkling: TikTok's native app shell for Lynx","What Sparkling is, how its containers, hybrid:\u002F\u002F schemes, and typed method bridge work, and how a Vue Lynx app fits inside a Sparkling shell.","lKjTzXHCktpmdIM1tDq9adhNGJwFRMuJs1kde7pAmx8",[1498,1500],{"title":443,"path":444,"stem":445,"description":1499,"icon":-1,"children":-1,"navigation":-1},"What a component library is actually worth on Lynx, how the headless and styled layers differ, and when copying the source with the CLI beats depending on the package.",{"title":452,"path":453,"stem":454,"description":1501,"icon":-1,"children":-1,"navigation":-1},"A comparison of the UI component libraries available for Lynx today, covering what each one ships, which framework it targets, and how mature it is.",1789821814771]