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