[{"data":1,"prerenderedAt":7116},["ShallowReactive",2],{"all-pages":3,"content-query-tXwpPNMR5n":5514},[4,219,744,1374,2048,4062,4687,5132,5146,5187,5239,5294,5352,5414,5479,5488],{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":6,"title":8,"description":9,"keywords":10,"slug":11,"pagetitle":12,"date":6,"tags":13,"canonicalUrl":14,"body":15,"_type":213,"_id":214,"_source":215,"_file":216,"_stem":217,"_extension":218},"/about","",false,"About UX/UI designer and developer - eveatwork.studio","Web product design and development portfolio of Eve S. Blakcori, United Kingdom.","product designer, UI developer, web designer, front-end developer, UX/UI designer","about","About",null,"https://www.eveatwork.studio/about/",{"type":16,"children":17,"toc":208},"root",[18,26,31,58,65,196],{"type":19,"tag":20,"props":21,"children":22},"element","p",{},[23],{"type":24,"value":25},"text","Hi, I’m Eve – UI development lead, and design systems innovator.",{"type":19,"tag":20,"props":27,"children":28},{},[29],{"type":24,"value":30},"I help teams scale UI development, improve efficiency, and create pixel-perfect, consistent and accessible digital experiences.",{"type":19,"tag":20,"props":32,"children":33},{},[34,36,42,44,49,51,56],{"type":24,"value":35},"Currently, I work as a UI development team lead at Domino’s UK, where I lead ",{"type":19,"tag":37,"props":38,"children":39},"strong",{},[40],{"type":24,"value":41},"UI development strategy",{"type":24,"value":43},", drive ",{"type":19,"tag":37,"props":45,"children":46},{},[47],{"type":24,"value":48},"design system innovation",{"type":24,"value":50}," and manage a ",{"type":19,"tag":37,"props":52,"children":53},{},[54],{"type":24,"value":55},"scalable, high-performance",{"type":24,"value":57}," UI components library.",{"type":19,"tag":59,"props":60,"children":62},"h3",{"id":61},"what-i-do-best",[63],{"type":24,"value":64},"What I Do Best",{"type":19,"tag":66,"props":67,"children":68},"ul",{},[69,80,126,150,173],{"type":19,"tag":70,"props":71,"children":72},"li",{},[73,78],{"type":19,"tag":37,"props":74,"children":75},{},[76],{"type":24,"value":77},"UI Team Leadership",{"type":24,"value":79}," – Mentoring, setting goals, and ensuring smooth collaboration between design, product, and development teams.",{"type":19,"tag":70,"props":81,"children":82},{},[83,88,90,95,97,103,105,110,112,117,119,124],{"type":19,"tag":37,"props":84,"children":85},{},[86],{"type":24,"value":87},"Scalable UI Systems",{"type":24,"value":89}," – Managing ",{"type":19,"tag":37,"props":91,"children":92},{},[93],{"type":24,"value":94},"two 150+ component UI libraries",{"type":24,"value":96},", one for ",{"type":19,"tag":98,"props":99,"children":100},"em",{},[101],{"type":24,"value":102},"Vue 2",{"type":24,"value":104}," and one for ",{"type":19,"tag":98,"props":106,"children":107},{},[108],{"type":24,"value":109},"Vue 3",{"type":24,"value":111},", introducing ",{"type":19,"tag":37,"props":113,"children":114},{},[115],{"type":24,"value":116},"design tokens",{"type":24,"value":118},", and ",{"type":19,"tag":37,"props":120,"children":121},{},[122],{"type":24,"value":123},"improving developer experience",{"type":24,"value":125},".",{"type":19,"tag":70,"props":127,"children":128},{},[129,134,136,141,143,148],{"type":19,"tag":37,"props":130,"children":131},{},[132],{"type":24,"value":133},"Workflow Optimisation",{"type":24,"value":135}," – Implementing ",{"type":19,"tag":37,"props":137,"children":138},{},[139],{"type":24,"value":140},"Chromatic for visual testing",{"type":24,"value":142}," (saving 40+ hours/month) and ",{"type":19,"tag":37,"props":144,"children":145},{},[146],{"type":24,"value":147},"streamlining UI processes",{"type":24,"value":149}," with Notion and Azure DevOps dashboards.",{"type":19,"tag":70,"props":151,"children":152},{},[153,158,160,165,167,172],{"type":19,"tag":37,"props":154,"children":155},{},[156],{"type":24,"value":157},"Project Delivery & Management",{"type":24,"value":159}," – Leading ",{"type":19,"tag":37,"props":161,"children":162},{},[163],{"type":24,"value":164},"UI projects from planning to execution",{"type":24,"value":166},", ensuring on-time delivery while maintaining high-quality standards. Managing priorities and improving ",{"type":19,"tag":37,"props":168,"children":169},{},[170],{"type":24,"value":171},"cross-functional collaboration",{"type":24,"value":125},{"type":19,"tag":70,"props":174,"children":175},{},[176,181,183,188,190,195],{"type":19,"tag":37,"props":177,"children":178},{},[179],{"type":24,"value":180},"UI Consistency & Maintainability",{"type":24,"value":182}," – Establishing ",{"type":19,"tag":37,"props":184,"children":185},{},[186],{"type":24,"value":187},"design systems and shared UI libraries",{"type":24,"value":189}," to maintain consistency across multiple projects while ",{"type":19,"tag":37,"props":191,"children":192},{},[193],{"type":24,"value":194},"reducing technical debt and third-party dependencies",{"type":24,"value":125},{"type":19,"tag":20,"props":197,"children":198},{},[199,201,206],{"type":24,"value":200},"At the core of my work is a simple goal: I want to help teams ",{"type":19,"tag":37,"props":202,"children":203},{},[204],{"type":24,"value":205},"build better UIs",{"type":24,"value":207}," - faster, smarter, and more efficiently.",{"title":6,"searchDepth":209,"depth":209,"links":210},2,[211],{"id":61,"depth":212,"text":64},3,"markdown","content:about:index.md","content","about/index.md","about/index","md",{"_path":220,"_dir":221,"_draft":7,"_partial":7,"_locale":6,"title":222,"description":223,"keywords":224,"slug":225,"pagetitle":222,"longPageTitle":222,"date":226,"longDate":227,"serpDate":228,"tags":229,"category":233,"featured":234,"canonicalUrl":235,"projectCompany":236,"projectLink":13,"projectThumbnail":237,"projectMedia":238,"pageClassName":13,"nextProjectSlug":240,"schemaImage1x1":241,"schemaImage4x3":242,"schemaImage16x9":243,"ctaTitle":13,"ctaSubtitle":13,"ctaButtonText":13,"body":244,"_type":213,"_id":741,"_source":215,"_file":742,"_stem":743,"_extension":218},"/articles/10-things-business-leaders-need-to-know-about-website-reskinning","articles","10 Things Business Leaders Need to Know About Website Reskinning\n","Learn what website reskinning is, the benefits for your business, and how it compares to a full redesign. Discover the process, timeline, and tips for refreshing your website’s design without altering its core functionality.","Website reskinning, reskin website, website redesign vs reskin, business website reskin, website reskin benefits, reskin website process, refresh website design, website reskin guide, reskin website timeline, update website look, website design update, website reskin cost, improve website appearance, website reskin SEO impact, website reskin for small business, reskin vs redesign website, modernise website design, website UI reskin, website reskin planning, website reskin best practices","10-things-business-leaders-need-to-know-about-website-reskinning","2024-10-14","October 14th, 2024","14 Oct 2024",[230,231,232],"front-end","reskin","UI development","Questions & Answers",true,"https://www.eveatwork.studio/articles/10-things-business-leaders-need-to-know-about-website-reskinning/","Eve At Work","/articles/website-reskin-101/website-reskin-101-for-business-leaders--thumbnail.png",[239],"/articles/website-reskin-101/website-reskin-101-for-business-leaders--page-hero.png","how-we-utilised-figma-variables-api-for-creating-design-tokens","/articles/website-reskin-101/website-reskin-101-for-business-leaders__1x1.png","/articles/website-reskin-101/website-reskin-101-for-business-leaders__4x3.png","/articles/website-reskin-101/website-reskin-101-for-business-leaders__16x9.png",{"type":16,"children":245,"toc":727},[246,258,263,268,275,280,303,309,314,337,343,348,354,359,412,418,423,456,461,467,472,495,501,506,512,517,550,556,568,574,579,602,608,613,618,624],{"type":19,"tag":20,"props":247,"children":248},{},[249,251,256],{"type":24,"value":250},"In today’s fast-paced digital landscape, keeping your website up-to-date is essential for maintaining a solid online presence. While a complete website redesign may seem like the go-to solution, it’s often time-consuming and costly. This is where ",{"type":19,"tag":37,"props":252,"children":253},{},[254],{"type":24,"value":255},"website reskinning",{"type":24,"value":257}," comes in—a quicker, more cost-effective way to refresh the look of your site without changing its core structure or functionality.",{"type":19,"tag":20,"props":259,"children":260},{},[261],{"type":24,"value":262},"A reskin involves updating the visual elements of your website, such as colours, fonts, and imagery, to give it a modern appearance and align it with current branding. A well-timed reskin can be a game-changer for businesses looking to enhance user experience and stay competitive.",{"type":19,"tag":20,"props":264,"children":265},{},[266],{"type":24,"value":267},"In this Q&A style post, I will answer the most commonly asked questions about website reskinning - what it is, what benefits it can provide to the business, and why it might be the perfect alternative to a complete redesign.",{"type":19,"tag":269,"props":270,"children":272},"h2",{"id":271},"_1-what-is-website-reskinning-and-how-is-it-different-from-a-redesign",[273],{"type":24,"value":274},"1. What is website reskinning, and how is it different from a redesign?",{"type":19,"tag":20,"props":276,"children":277},{},[278],{"type":24,"value":279},"Website reskinning focuses on changing a site’s appearance without altering its core structure or functionality. It’s a visual overhaul, often involving updates to colours, fonts, images, and layouts, while the site’s back-end code and content typically stay the same.",{"type":19,"tag":66,"props":281,"children":282},{},[283,293],{"type":19,"tag":70,"props":284,"children":285},{},[286,291],{"type":19,"tag":37,"props":287,"children":288},{},[289],{"type":24,"value":290},"Reskinning:",{"type":24,"value":292}," Involves aesthetic changes to give the site a fresh look.",{"type":19,"tag":70,"props":294,"children":295},{},[296,301],{"type":19,"tag":37,"props":297,"children":298},{},[299],{"type":24,"value":300},"Redesign:",{"type":24,"value":302}," Involves more profound changes to both the design and functionality, often requiring back-end adjustments, navigation reworks, and structural updates.",{"type":19,"tag":269,"props":304,"children":306},{"id":305},"_2-why-should-a-business-reskin-its-website-instead-of-redesigning-it",[307],{"type":24,"value":308},"2. Why should a business reskin its website instead of redesigning it?",{"type":19,"tag":20,"props":310,"children":311},{},[312],{"type":24,"value":313},"A website reskin is ideal when:",{"type":19,"tag":66,"props":315,"children":316},{},[317,322,327,332],{"type":19,"tag":70,"props":318,"children":319},{},[320],{"type":24,"value":321},"The site’s structure, functionality, and performance still meet business needs.",{"type":19,"tag":70,"props":323,"children":324},{},[325],{"type":24,"value":326},"The goal is to refresh the website’s appearance quickly and affordably without significant disruption.",{"type":19,"tag":70,"props":328,"children":329},{},[330],{"type":24,"value":331},"There’s a need to modernise the UI of a website while avoiding the costs and time investment of a full redesign.",{"type":19,"tag":70,"props":333,"children":334},{},[335],{"type":24,"value":336},"The focus is on improving user experience and aesthetics without rebuilding the core systems. A redesign, however, may be necessary if the site’s usability, content structure, or technology stack is outdated.",{"type":19,"tag":269,"props":338,"children":340},{"id":339},"_3-how-often-should-a-website-be-reskinned",[341],{"type":24,"value":342},"3. How often should a website be reskinned?",{"type":19,"tag":20,"props":344,"children":345},{},[346],{"type":24,"value":347},"Typically, a website should be reskinned every 3-4 years to stay current with design trends, align with evolving brand guidelines, and maintain a fresh user experience. Market changes, user feedback, and competition may also drive the need for a faster refresh.",{"type":19,"tag":269,"props":349,"children":351},{"id":350},"_4-what-elements-of-a-website-change-during-a-reskin",[352],{"type":24,"value":353},"4. What elements of a website change during a reskin?",{"type":19,"tag":20,"props":355,"children":356},{},[357],{"type":24,"value":358},"The following elements are usually updated during a reskin:",{"type":19,"tag":66,"props":360,"children":361},{},[362,372,382,392,402],{"type":19,"tag":70,"props":363,"children":364},{},[365,370],{"type":19,"tag":37,"props":366,"children":367},{},[368],{"type":24,"value":369},"Colours:",{"type":24,"value":371}," To reflect current branding or design trends.",{"type":19,"tag":70,"props":373,"children":374},{},[375,380],{"type":19,"tag":37,"props":376,"children":377},{},[378],{"type":24,"value":379},"Typography:",{"type":24,"value":381}," To improve readability or align with branding.",{"type":19,"tag":70,"props":383,"children":384},{},[385,390],{"type":19,"tag":37,"props":386,"children":387},{},[388],{"type":24,"value":389},"Images and Graphics:",{"type":24,"value":391}," Replaced or updated to match a new visual theme or style.",{"type":19,"tag":70,"props":393,"children":394},{},[395,400],{"type":19,"tag":37,"props":396,"children":397},{},[398],{"type":24,"value":399},"Website responsiveness:",{"type":24,"value":401}," To improve the usability of the website on smaller devices.",{"type":19,"tag":70,"props":403,"children":404},{},[405,410],{"type":19,"tag":37,"props":406,"children":407},{},[408],{"type":24,"value":409},"Layout:",{"type":24,"value":411}," To improve spacing, button styles, hover effects, and overall visual aesthetics without changing the website’s structure. Core elements like the content, navigation, and functionality usually remain the same.",{"type":19,"tag":269,"props":413,"children":415},{"id":414},"_5-how-long-does-a-website-reskin-typically-take",[416],{"type":24,"value":417},"5. How long does a website reskin typically take?",{"type":19,"tag":20,"props":419,"children":420},{},[421],{"type":24,"value":422},"The timeline for a website reskin depends a lot on its complexity and the project’s scope:",{"type":19,"tag":66,"props":424,"children":425},{},[426,436,446],{"type":19,"tag":70,"props":427,"children":428},{},[429,434],{"type":19,"tag":37,"props":430,"children":431},{},[432],{"type":24,"value":433},"Design Phase:",{"type":24,"value":435}," Creating and refining new visual designs typically takes 2-4 weeks, depending on the complexity of the website and the amount of stakeholder feedback required.",{"type":19,"tag":70,"props":437,"children":438},{},[439,444],{"type":19,"tag":37,"props":440,"children":441},{},[442],{"type":24,"value":443},"Development Phase:",{"type":24,"value":445}," Implementing the design changes highly depends not only on the website’s size but also on the state of the code (i.e. an existing technical debt). On average, the reskin’s development phase can take 4 to 8 weeks.",{"type":19,"tag":70,"props":447,"children":448},{},[449,454],{"type":19,"tag":37,"props":450,"children":451},{},[452],{"type":24,"value":453},"Testing Phase:",{"type":24,"value":455}," Allow 1-2 weeks for thorough testing across different browsers and devices. Larger sites or more complex branding changes will extend the timeline, while smaller sites can be tested more quickly.",{"type":19,"tag":20,"props":457,"children":458},{},[459],{"type":24,"value":460},"All of the above also depend on the overall reskin release plan. If you want to release all changes to production in one go, the timeline for the project will be shorter. However, if you want to introduce the changes gradually, this will take more time.",{"type":19,"tag":269,"props":462,"children":464},{"id":463},"_6-will-a-website-reskin-affect-seo",[465],{"type":24,"value":466},"6. Will a website reskin affect SEO?",{"type":19,"tag":20,"props":468,"children":469},{},[470],{"type":24,"value":471},"A reskin can impact SEO, both positively and negatively:",{"type":19,"tag":66,"props":473,"children":474},{},[475,485],{"type":19,"tag":70,"props":476,"children":477},{},[478,483],{"type":19,"tag":37,"props":479,"children":480},{},[481],{"type":24,"value":482},"Positive Impact:",{"type":24,"value":484}," A reskin that improves mobile responsiveness, page speed, or user experience can positively affect SEO rankings.",{"type":19,"tag":70,"props":486,"children":487},{},[488,493],{"type":19,"tag":37,"props":489,"children":490},{},[491],{"type":24,"value":492},"Negative Impact:",{"type":24,"value":494}," Any unintentional HTML structure, metadata, or site speed changes could harm rankings. SEO best practices should be followed throughout the reskinning process to mitigate the risks, and performance should be monitored post-launch.",{"type":19,"tag":269,"props":496,"children":498},{"id":497},"_7-can-a-website-reskin-be-done-without-changing-the-existing-back-end-or-cms",[499],{"type":24,"value":500},"7. Can a website reskin be done without changing the existing back-end or CMS?",{"type":19,"tag":20,"props":502,"children":503},{},[504],{"type":24,"value":505},"A reskin focuses on the front end (visual elements), leaving the back end and CMS functionality unchanged. This makes reskinning an efficient option for businesses that want to refresh their design while keeping their content management process intact.",{"type":19,"tag":269,"props":507,"children":509},{"id":508},"_8-what-are-the-costs-involved-in-reskinning-a-website",[510],{"type":24,"value":511},"8. What are the costs involved in reskinning a website?",{"type":19,"tag":20,"props":513,"children":514},{},[515],{"type":24,"value":516},"The cost of reskinning a website varies depending on factors like:",{"type":19,"tag":66,"props":518,"children":519},{},[520,530,540],{"type":19,"tag":70,"props":521,"children":522},{},[523,528],{"type":19,"tag":37,"props":524,"children":525},{},[526],{"type":24,"value":527},"Website Size:",{"type":24,"value":529}," Larger sites with more pages require more design and development work.",{"type":19,"tag":70,"props":531,"children":532},{},[533,538],{"type":19,"tag":37,"props":534,"children":535},{},[536],{"type":24,"value":537},"Custom Design Work:",{"type":24,"value":539}," Custom designs tailored to a company’s needs will be more expensive than off-the-shelf templates.",{"type":19,"tag":70,"props":541,"children":542},{},[543,548],{"type":19,"tag":37,"props":544,"children":545},{},[546],{"type":24,"value":547},"Hiring Professional Designers or Agencies:",{"type":24,"value":549}," Outsourcing the reskin to a professional team will incur higher costs but may result in better quality. On average, reskinning costs can range from a few thousand pounds for a small site to higher amounts for more complex projects with larger codebases and custom designs.",{"type":19,"tag":269,"props":551,"children":553},{"id":552},"_9-will-a-website-be-down-during-the-reskinning-deployment-process",[554],{"type":24,"value":555},"9. Will a website be down during the reskinning deployment process?",{"type":19,"tag":20,"props":557,"children":558},{},[559,561,566],{"type":24,"value":560},"In most cases, downtime can be minimised or even avoided during a reskin deployment to production. A ",{"type":19,"tag":37,"props":562,"children":563},{},[564],{"type":24,"value":565},"staging environment",{"type":24,"value":567}," allows the new design to be tested and refined without affecting the live site. Once the reskin is ready, the new design can be deployed with minimal disruption. Deploying changes during off-peak hours or using strategies like blue-green deployment can minimise downtime.",{"type":19,"tag":269,"props":569,"children":571},{"id":570},"_10-how-will-users-be-affected-by-a-website-reskin",[572],{"type":24,"value":573},"10. How will users be affected by a website reskin?",{"type":19,"tag":20,"props":575,"children":576},{},[577],{"type":24,"value":578},"A well-executed reskin should enhance the user experience by delivering a more visually appealing and modern interface without disrupting users’ interaction with the site. However, sudden or drastic design changes may confuse regular users, so it’s important to:",{"type":19,"tag":66,"props":580,"children":581},{},[582,587,592,597],{"type":19,"tag":70,"props":583,"children":584},{},[585],{"type":24,"value":586},"Introduce changes gradually, especially on sites with a larger number of visitors.",{"type":19,"tag":70,"props":588,"children":589},{},[590],{"type":24,"value":591},"Maintain consistency in key UI elements.",{"type":19,"tag":70,"props":593,"children":594},{},[595],{"type":24,"value":596},"Ensure usability testing is conducted to confirm that users can easily navigate the refreshed design.",{"type":19,"tag":70,"props":598,"children":599},{},[600],{"type":24,"value":601},"Communicate the changes to users beforehand to reduce confusion or resistance to the new look.",{"type":19,"tag":269,"props":603,"children":605},{"id":604},"summary",[606],{"type":24,"value":607},"Summary",{"type":19,"tag":20,"props":609,"children":610},{},[611],{"type":24,"value":612},"In this post, I answered business leaders’ or owners’ most commonly asked questions about website reskinning. To summarise, reskinning offers businesses a practical and efficient way to modernise their online presence without a complete redesign. By focusing on visual updates, reskinning can help improve user experience, align your site with current branding, and boost engagement while maintaining your website’s core structure and functionality.",{"type":19,"tag":20,"props":614,"children":615},{},[616],{"type":24,"value":617},"Whether you want to refresh your website’s look, improve performance, or stay competitive in a fast-evolving digital world, I hope this post helps you make informed decisions for your business.",{"type":19,"tag":269,"props":619,"children":621},{"id":620},"glossary-of-terms",[622],{"type":24,"value":623},"Glossary of Terms",{"type":19,"tag":66,"props":625,"children":626},{},[627,637,647,657,667,677,687,697,707,717],{"type":19,"tag":70,"props":628,"children":629},{},[630,635],{"type":19,"tag":37,"props":631,"children":632},{},[633],{"type":24,"value":634},"Website Reskinning:",{"type":24,"value":636}," The process of updating the visual design of a website, such as colours, fonts, images, and layout, without changing its core functionality or structure.",{"type":19,"tag":70,"props":638,"children":639},{},[640,645],{"type":19,"tag":37,"props":641,"children":642},{},[643],{"type":24,"value":644},"Website Redesign:",{"type":24,"value":646}," A comprehensive overhaul of a website’s design and functionality, often involving changes to the back end, structure, navigation, and user experience.",{"type":19,"tag":70,"props":648,"children":649},{},[650,655],{"type":19,"tag":37,"props":651,"children":652},{},[653],{"type":24,"value":654},"CMS (Content Management System):",{"type":24,"value":656}," A software platform used to manage, create, and modify digital content on a website without needing to write code. Examples include WordPress, Joomla, and Drupal.",{"type":19,"tag":70,"props":658,"children":659},{},[660,665],{"type":19,"tag":37,"props":661,"children":662},{},[663],{"type":24,"value":664},"User Experience (UX):",{"type":24,"value":666}," Refers to the overall experience a person has when interacting with a website or digital product, including ease of use, accessibility, and how intuitive the design is.",{"type":19,"tag":70,"props":668,"children":669},{},[670,675],{"type":19,"tag":37,"props":671,"children":672},{},[673],{"type":24,"value":674},"Visual Elements:",{"type":24,"value":676}," The components of a website’s design that are visible to users, such as colours, typography, images, buttons, and layout.",{"type":19,"tag":70,"props":678,"children":679},{},[680,685],{"type":19,"tag":37,"props":681,"children":682},{},[683],{"type":24,"value":684},"Responsive Design:",{"type":24,"value":686}," A design approach that ensures a website’s layout and content adapts to different screen sizes and devices, such as smartphones, tablets, and desktop computers.",{"type":19,"tag":70,"props":688,"children":689},{},[690,695],{"type":19,"tag":37,"props":691,"children":692},{},[693],{"type":24,"value":694},"Staging Environment:",{"type":24,"value":696}," A testing version of a website where changes can be made and reviewed before they go live. It mirrors the live website but is not publicly accessible.",{"type":19,"tag":70,"props":698,"children":699},{},[700,705],{"type":19,"tag":37,"props":701,"children":702},{},[703],{"type":24,"value":704},"Blue-Green Deployment:",{"type":24,"value":706}," A deployment strategy that maintains two identical environments (blue and green). The live site runs in one environment while changes are made in another. When the changes are ready, traffic is switched to the updated environment.",{"type":19,"tag":70,"props":708,"children":709},{},[710,715],{"type":19,"tag":37,"props":711,"children":712},{},[713],{"type":24,"value":714},"SEO (Search Engine Optimisation):",{"type":24,"value":716}," Improving a website’s visibility on search engines like Google. This involves optimising elements such as keywords, content, metadata, and website structure to improve search rankings.",{"type":19,"tag":70,"props":718,"children":719},{},[720,725],{"type":19,"tag":37,"props":721,"children":722},{},[723],{"type":24,"value":724},"Technical Debt:",{"type":24,"value":726}," Refers to the concept of taking shortcuts in the development process that may lead to future complications. It often results from outdated code or systems that require extra time and resources to address in future updates.",{"title":6,"searchDepth":209,"depth":209,"links":728},[729,730,731,732,733,734,735,736,737,738,739,740],{"id":271,"depth":209,"text":274},{"id":305,"depth":209,"text":308},{"id":339,"depth":209,"text":342},{"id":350,"depth":209,"text":353},{"id":414,"depth":209,"text":417},{"id":463,"depth":209,"text":466},{"id":497,"depth":209,"text":500},{"id":508,"depth":209,"text":511},{"id":552,"depth":209,"text":555},{"id":570,"depth":209,"text":573},{"id":604,"depth":209,"text":607},{"id":620,"depth":209,"text":623},"content:articles:10-things-business-leaders-need-to-know-about-website-reskinning:index.md","articles/10-things-business-leaders-need-to-know-about-website-reskinning/index.md","articles/10-things-business-leaders-need-to-know-about-website-reskinning/index",{"_path":745,"_dir":221,"_draft":7,"_partial":7,"_locale":6,"title":746,"description":747,"keywords":748,"slug":749,"pagetitle":746,"longPageTitle":746,"date":750,"longDate":751,"serpDate":752,"tags":753,"category":756,"featured":234,"canonicalUrl":757,"projectCompany":758,"projectLink":13,"projectThumbnail":759,"projectMedia":760,"pageClassName":13,"nextProjectSlug":225,"schemaImage1x1":762,"schemaImage4x3":763,"schemaImage16x9":764,"ctaTitle":13,"ctaSubtitle":13,"ctaButtonText":13,"ctaButtonURL":13,"body":765,"_type":213,"_id":1371,"_source":215,"_file":1372,"_stem":1373,"_extension":218},"/articles/building-ui-foundations-across-multiple-products","Building UI Foundations Across Multiple Products: Lessons from Leading a Shared Component Library\n","What I've learned from supporting shared UI libraries, design systems, accessibility, and frontend quality across several web applications.","product design case study, UI development case study, web design case study, front end development case study","building-ui-foundations-across-multiple-products","2026-05-01","May 1st, 2026","1 May 2026",[232,754,755],"design system","UI foundations","Case study","https://www.eveatwork.studio/articles/building-ui-foundations-across-multiple-products/","Domino's","/articles/building-ui-foundations/building-ui-foundations--thumbnail.png",[761],"/articles/building-ui-foundations/building-ui-foundations--page-hero.png","/articles/building-ui-foundations/building-ui-foundations__1x1.png","/articles/building-ui-foundations/building-ui-foundations__4x3.png","/articles/building-ui-foundations/building-ui-foundations__16x9.png",{"type":16,"children":766,"toc":1360},[767,772,777,782,787,792,797,803,808,813,818,823,828,833,838,843,848,854,859,864,869,874,879,884,889,894,900,905,910,968,973,978,983,988,994,999,1004,1009,1014,1047,1052,1057,1062,1067,1073,1078,1083,1088,1093,1098,1103,1108,1113,1118,1123,1129,1134,1139,1144,1149,1154,1159,1164,1169,1174,1207,1212,1217,1223,1228,1233,1238,1243,1248,1253,1258,1263,1269,1274,1279,1284,1289,1294,1299,1304,1309,1314,1319,1325,1330,1335,1340,1345,1350,1355],{"type":19,"tag":20,"props":768,"children":769},{},[770],{"type":24,"value":771},"When you work on one product, UI decisions can feel very local. A component is changed, a page is updated, a pattern is adjusted in a single repository, and the impact is mostly contained.",{"type":19,"tag":20,"props":773,"children":774},{},[775],{"type":24,"value":776},"When you work across multiple products that share the same UI, the same decision becomes part of the system.",{"type":19,"tag":20,"props":778,"children":779},{},[780],{"type":24,"value":781},"A small change to a shared component can affect several applications. A CSS decision can impact experimentation. A missing accessibility expectation can be repeated across multiple journeys. A design token can become the difference between consistent theming and dozens of slightly different colours living across different codebases.",{"type":19,"tag":20,"props":783,"children":784},{},[785],{"type":24,"value":786},"That is the part of UI work I have become increasingly interested in: not just building individual interfaces, but building the foundations that help many teams create better interfaces with more consistency and confidence.",{"type":19,"tag":20,"props":788,"children":789},{},[790],{"type":24,"value":791},"In my current role as a UI Development Team Lead at Domino's UK & Ireland, I work across shared UI libraries, design systems, accessibility, Storybook documentation, visual regression testing, design tokens, and frontend delivery processes. Over time, I have realised that the most valuable UI work is often not the most visible work. It is the work that quietly improves how other teams build.",{"type":19,"tag":20,"props":793,"children":794},{},[795],{"type":24,"value":796},"This article is a reflection on what I have learned from building and supporting UI foundations across multiple web applications at Domino's.",{"type":19,"tag":269,"props":798,"children":800},{"id":799},"when-ui-decisions-stop-being-local",[801],{"type":24,"value":802},"When UI Decisions Stop Being Local",{"type":19,"tag":20,"props":804,"children":805},{},[806],{"type":24,"value":807},"In a single product team, a UI decision usually belongs to that product. I should know that, since I have worked on many individual products during my career.",{"type":19,"tag":20,"props":809,"children":810},{},[811],{"type":24,"value":812},"In a multi-product environment, those decisions quickly become bigger than one team.",{"type":19,"tag":20,"props":814,"children":815},{},[816],{"type":24,"value":817},"If five applications use the same shared UI library, then every component has to support more than one immediate use case. It needs to be flexible enough to work across different journeys, but not so flexible that it becomes inconsistent or difficult to maintain.",{"type":19,"tag":20,"props":819,"children":820},{},[821],{"type":24,"value":822},"I have seen this most clearly with components like product cards and buttons, where a small implementation detail in one variant can affect layout, accessibility, and even A/B tests of others.",{"type":19,"tag":20,"props":824,"children":825},{},[826],{"type":24,"value":827},"That balance is difficult.",{"type":19,"tag":20,"props":829,"children":830},{},[831],{"type":24,"value":832},"Too much control, and teams feel blocked by the system. Too much flexibility, and the system stops being a system. Components become configurable to the point where every product can make them behave differently, and consistency slowly disappears.",{"type":19,"tag":20,"props":834,"children":835},{},[836],{"type":24,"value":837},"This is where UI foundation work goes beyond frontend implementation. It becomes product and design thinking, engineering judgement, and communication all at once.",{"type":19,"tag":20,"props":839,"children":840},{},[841],{"type":24,"value":842},"A shared component is not just a piece of code. It is a decision that other teams inherit.",{"type":19,"tag":20,"props":844,"children":845},{},[846],{"type":24,"value":847},"That means every API, prop, slot, class name, token, accessibility behaviour, and documentation example matters more than it might seem at first.",{"type":19,"tag":269,"props":849,"children":851},{"id":850},"the-quiet-cost-of-inconsistency",[852],{"type":24,"value":853},"The Quiet Cost of Inconsistency",{"type":19,"tag":20,"props":855,"children":856},{},[857],{"type":24,"value":858},"Inconsistency rarely appears all at once. It usually grows quietly.",{"type":19,"tag":20,"props":860,"children":861},{},[862],{"type":24,"value":863},"One team adds a slightly different spacing rule. Another team creates a one-off variation of a component because the shared version does not quite support their use case. A designer introduces a new pattern in Figma, but there is no clear path for turning it into a reusable component. A developer fixes an accessibility issue locally, but the learning never makes it back into the shared library.",{"type":19,"tag":20,"props":865,"children":866},{},[867],{"type":24,"value":868},"None of these things feels dramatic in isolation. In fact, they are often reasonable decisions in the moment. Teams are just trying to deliver on time. They have deadlines. They need to solve the problem in front of them.",{"type":19,"tag":20,"props":870,"children":871},{},[872],{"type":24,"value":873},"But over time, the cost becomes visible.",{"type":19,"tag":20,"props":875,"children":876},{},[877],{"type":24,"value":878},"The same UI problem gets solved multiple times. Design and code drift apart. QA has to learn different behaviours for similar patterns. Accessibility becomes inconsistent, and product teams lose confidence in the shared library. Designers are not always sure which patterns are available, just like developers are not always sure which components are safe to use.",{"type":19,"tag":20,"props":880,"children":881},{},[882],{"type":24,"value":883},"This is one of the biggest reasons UI foundations matter.",{"type":19,"tag":20,"props":885,"children":886},{},[887],{"type":24,"value":888},"Good UI foundations do not remove all complexity, but they reduce unnecessary complexity. They give teams a shared starting point and make the right thing easier to do. They help teams spend less time recreating basic patterns and more time solving the specific problems that matter to users.",{"type":19,"tag":20,"props":890,"children":891},{},[892],{"type":24,"value":893},"For me, this is where design systems become truly valuable, not as a polished collection of components, but as a way of reducing repeated decision-making across teams.",{"type":19,"tag":269,"props":895,"children":897},{"id":896},"what-i-mean-by-ui-foundations",[898],{"type":24,"value":899},"What I Mean by UI Foundations",{"type":19,"tag":20,"props":901,"children":902},{},[903],{"type":24,"value":904},"When people hear “shared UI”, they often think about component libraries first. That is understandable. Components are the most visible part of the system.",{"type":19,"tag":20,"props":906,"children":907},{},[908],{"type":24,"value":909},"But UI foundations are much more than that. To me, they include:",{"type":19,"tag":66,"props":911,"children":912},{},[913,918,923,928,933,938,943,948,953,958,963],{"type":19,"tag":70,"props":914,"children":915},{},[916],{"type":24,"value":917},"Reusable components and patterns",{"type":19,"tag":70,"props":919,"children":920},{},[921],{"type":24,"value":922},"Design tokens",{"type":19,"tag":70,"props":924,"children":925},{},[926],{"type":24,"value":927},"CSS architecture",{"type":19,"tag":70,"props":929,"children":930},{},[931],{"type":24,"value":932},"Accessibility standards",{"type":19,"tag":70,"props":934,"children":935},{},[936],{"type":24,"value":937},"Documentation",{"type":19,"tag":70,"props":939,"children":940},{},[941],{"type":24,"value":942},"Visual regression testing",{"type":19,"tag":70,"props":944,"children":945},{},[946],{"type":24,"value":947},"Release notes and migration guidance",{"type":19,"tag":70,"props":949,"children":950},{},[951],{"type":24,"value":952},"Package publishing processes",{"type":19,"tag":70,"props":954,"children":955},{},[956],{"type":24,"value":957},"Setting consumer responsibilities",{"type":19,"tag":70,"props":959,"children":960},{},[961],{"type":24,"value":962},"Cross-product validation",{"type":19,"tag":70,"props":964,"children":965},{},[966],{"type":24,"value":967},"And in general, the relationship between design, engineering, QA, and product teams",{"type":19,"tag":20,"props":969,"children":970},{},[971],{"type":24,"value":972},"A component library is the code, and UI foundations are the system around it.",{"type":19,"tag":20,"props":974,"children":975},{},[976],{"type":24,"value":977},"For example, a button component is very useful. But a button component with clear usage guidance, accessible focus states, design token support, visual regression coverage, documented variants, and a reliable release process is much more valuable.",{"type":19,"tag":20,"props":979,"children":980},{},[981],{"type":24,"value":982},"The same applies to larger patterns. A modal is not just a container that opens and closes. It needs to handle focus management, keyboard behaviour, scroll and close behaviour, content structure, accessibility announcements, and various edge cases. If those expectations are not defined, each consumer of this component has to interpret them on their own. And this is where inconsistency comes back in.",{"type":19,"tag":20,"props":984,"children":985},{},[986],{"type":24,"value":987},"Let's put it this way - good UI foundations create shared expectations. They answer questions before every team has to ask them.",{"type":19,"tag":269,"props":989,"children":991},{"id":990},"a-component-library-is-only-one-part-of-the-system",[992],{"type":24,"value":993},"A Component Library Is Only One Part of the System",{"type":19,"tag":20,"props":995,"children":996},{},[997],{"type":24,"value":998},"One of the biggest lessons I have learned is that having a component library does not automatically mean you have a strong UI platform.",{"type":19,"tag":20,"props":1000,"children":1001},{},[1002],{"type":24,"value":1003},"A component library can exist and still be difficult to use.",{"type":19,"tag":20,"props":1005,"children":1006},{},[1007],{"type":24,"value":1008},"It can have components that are technically reusable, but poorly documented. It can also have components that have too many props because they have absorbed years of one-off requirements. Components in the library can look visually correct, but not clearly define keyboard or screen reader behaviour. The new versions of the library can be published regularly, but without enough guidance for consuming teams to understand what changed or what they need to test.",{"type":19,"tag":20,"props":1010,"children":1011},{},[1012],{"type":24,"value":1013},"This is why I think the work around the component is just as important as the component itself.",{"type":19,"tag":66,"props":1015,"children":1016},{},[1017,1022,1027,1032,1037,1042],{"type":19,"tag":70,"props":1018,"children":1019},{},[1020],{"type":24,"value":1021},"Can teams find the component and understand when to use it?",{"type":19,"tag":70,"props":1023,"children":1024},{},[1025],{"type":24,"value":1026},"Can they see examples that match real product use cases?",{"type":19,"tag":70,"props":1028,"children":1029},{},[1030],{"type":24,"value":1031},"Can QA understand the expected behaviour?",{"type":19,"tag":70,"props":1033,"children":1034},{},[1035],{"type":24,"value":1036},"Can designers see whether the implementation matches the intended pattern?",{"type":19,"tag":70,"props":1038,"children":1039},{},[1040],{"type":24,"value":1041},"Can accessibility expectations be tested?",{"type":19,"tag":70,"props":1043,"children":1044},{},[1045],{"type":24,"value":1046},"Can teams upgrade safely?",{"type":19,"tag":20,"props":1048,"children":1049},{},[1050],{"type":24,"value":1051},"If the answers to those questions are unclear, the component library will struggle to scale.",{"type":19,"tag":20,"props":1053,"children":1054},{},[1055],{"type":24,"value":1056},"We use Storybook to develop components in isolation at Domino's, and I have found it useful to think about Storybook as a platform to serve several audiences at once: developers need implementation details, QA needs expected behaviours, UX needs confidence that the component reflects the design intent, and product teams need to understand the impact of changes. And when it comes to release notes, they became a way to communicate impact.",{"type":19,"tag":20,"props":1058,"children":1059},{},[1060],{"type":24,"value":1061},"This means Storybook becomes more than just a development tool. It becomes a shared space for documentation, review, and quality.",{"type":19,"tag":20,"props":1063,"children":1064},{},[1065],{"type":24,"value":1066},"This is the difference between building components and building a UI platform.",{"type":19,"tag":269,"props":1068,"children":1070},{"id":1069},"building-for-adoption-not-just-reuse",[1071],{"type":24,"value":1072},"Building for Adoption, Not Just Reuse",{"type":19,"tag":20,"props":1074,"children":1075},{},[1076],{"type":24,"value":1077},"It is easy to say that shared components or design tokens should be reused. It is much harder to make reuse feel natural.",{"type":19,"tag":20,"props":1079,"children":1080},{},[1081],{"type":24,"value":1082},"Adoption does not happen just because a component exists. Teams adopt shared UI when it solves their problem, is easy to understand, and does not create more friction than it removes.",{"type":19,"tag":20,"props":1084,"children":1085},{},[1086],{"type":24,"value":1087},"That means a lot of UI platform work is really about reducing friction.",{"type":19,"tag":20,"props":1089,"children":1090},{},[1091],{"type":24,"value":1092},"Clear examples matter. Naming matters. So do defaults, documentation, migration notes and release processes. The ability to listen when consuming teams struggle with a pattern could make or break the adoption of the UI library.",{"type":19,"tag":20,"props":1094,"children":1095},{},[1096],{"type":24,"value":1097},"A technically good component can still fail if teams do not trust it, understand it, or know how to integrate it.",{"type":19,"tag":20,"props":1099,"children":1100},{},[1101],{"type":24,"value":1102},"This is especially true when a shared library is used across multiple applications. A change cannot only be tested in isolation. It needs to be validated in the places where it is actually consumed. A component might look perfect in Storybook but behave differently inside a real product layout, with real content, data, and real edge cases.",{"type":19,"tag":20,"props":1104,"children":1105},{},[1106],{"type":24,"value":1107},"This is why I care about the full path from component to production.",{"type":19,"tag":20,"props":1109,"children":1110},{},[1111],{"type":24,"value":1112},"Often, our acceptance criteria explicitly includes updating consuming applications with the new shared package version and validating the change across products, because the shared library work is not truly complete until it has been tested, where users would experience it.",{"type":19,"tag":20,"props":1114,"children":1115},{},[1116],{"type":24,"value":1117},"For shared UI work to succeed, teams need more than a package version. They need context. They need to know what changed, why it changed, whether it affects them, and what they need to check.",{"type":19,"tag":20,"props":1119,"children":1120},{},[1121],{"type":24,"value":1122},"That is not admin. That is part of the product experience of the design system itself.",{"type":19,"tag":269,"props":1124,"children":1126},{"id":1125},"accessibility-has-to-be-part-of-the-foundation",[1127],{"type":24,"value":1128},"Accessibility Has to Be Part of the Foundation",{"type":19,"tag":20,"props":1130,"children":1131},{},[1132],{"type":24,"value":1133},"Accessibility is often treated as something that happens at the end of a piece of work. A final check. A QA task. A list of issues to fix before release.",{"type":19,"tag":20,"props":1135,"children":1136},{},[1137],{"type":24,"value":1138},"In shared UI work, that approach does not go far enough.",{"type":19,"tag":20,"props":1140,"children":1141},{},[1142],{"type":24,"value":1143},"If a component is used across several products, its accessibility behaviour is reused. That can be a very good thing if the component is built well. It can also be a risk if the pattern is unclear, incomplete, or easy to misuse.",{"type":19,"tag":20,"props":1145,"children":1146},{},[1147],{"type":24,"value":1148},"Accessibility has to be part of the foundation.",{"type":19,"tag":20,"props":1150,"children":1151},{},[1152],{"type":24,"value":1153},"That means defining keyboard behaviour. It means thinking about focus management when a component opens, closes, updates, or disappears. It means making sure hidden content is actually hidden from keyboard users and assistive technologies. It means documenting what screen readers should announce and what should stay silent. It also means being clear about what the consuming team is responsible for.",{"type":19,"tag":20,"props":1155,"children":1156},{},[1157],{"type":24,"value":1158},"A shared component can provide accessible defaults, but it cannot always guarantee an accessible page.",{"type":19,"tag":20,"props":1160,"children":1161},{},[1162],{"type":24,"value":1163},"For example, an accordion component can manage expanded and collapsed states correctly, but the consuming team still needs to provide meaningful content and use it in the right context. A modal can manage focus, but the journey around it still needs to make sense. A skip link can exist in the header, but the page still needs a valid target.",{"type":19,"tag":20,"props":1165,"children":1166},{},[1167],{"type":24,"value":1168},"This is why accessibility documentation matters so much.",{"type":19,"tag":20,"props":1170,"children":1171},{},[1172],{"type":24,"value":1173},"For each important component, I like to think about accessibility in practical terms:",{"type":19,"tag":66,"props":1175,"children":1176},{},[1177,1182,1187,1192,1197,1202],{"type":19,"tag":70,"props":1178,"children":1179},{},[1180],{"type":24,"value":1181},"What is the purpose of this component?",{"type":19,"tag":70,"props":1183,"children":1184},{},[1185],{"type":24,"value":1186},"How should keyboard users interact with it?",{"type":19,"tag":70,"props":1188,"children":1189},{},[1190],{"type":24,"value":1191},"Where should the focus move?",{"type":19,"tag":70,"props":1193,"children":1194},{},[1195],{"type":24,"value":1196},"What should a screen reader announce?",{"type":19,"tag":70,"props":1198,"children":1199},{},[1200],{"type":24,"value":1201},"What should remain hidden?",{"type":19,"tag":70,"props":1203,"children":1204},{},[1205],{"type":24,"value":1206},"What must consuming teams do correctly?",{"type":19,"tag":20,"props":1208,"children":1209},{},[1210],{"type":24,"value":1211},"When these expectations are written down, accessibility becomes less subjective. It becomes easier for developers to build, for QA to test, and for designers to consider earlier in the process.",{"type":19,"tag":20,"props":1213,"children":1214},{},[1215],{"type":24,"value":1216},"A simple example is an accordion. Visually, collapsed content may look hidden, but if interactive elements inside it can still receive keyboard focus, the experience becomes confusing and inaccessible. That kind of issue needs to be solved at the component level, then documented so teams know what behaviour to expect.",{"type":19,"tag":269,"props":1218,"children":1220},{"id":1219},"the-invisible-work-that-keeps-ui-systems-healthy",[1221],{"type":24,"value":1222},"The Invisible Work That Keeps UI Systems Healthy",{"type":19,"tag":20,"props":1224,"children":1225},{},[1226],{"type":24,"value":1227},"Some of the most important UI platform work is work that most people never see.",{"type":19,"tag":20,"props":1229,"children":1230},{},[1231],{"type":24,"value":1232},"Cleaning up package publishing. Removing files that should never have been shipped to consumers. Aligning dependency versions. Maintaining Storybook. Reviewing visual regression snapshots. Improving CSS architecture. Writing migration notes. Removing unused props. Creating release templates. Checking that external tools and third-party integrations are not broken by internal implementation details.",{"type":19,"tag":20,"props":1234,"children":1235},{},[1236],{"type":24,"value":1237},"This work is not always glamorous, but it is what keeps a UI system healthy.",{"type":19,"tag":20,"props":1239,"children":1240},{},[1241],{"type":24,"value":1242},"One example from my own work was improving the way our shared UI package was published. Over time, the package had started to include files that consumers did not need, such as stories, tests, documentation, and internal assets. Cleaning that up significantly reduced the package size (from roughly 20MB to 2MB) and made the library more focused for consuming applications. It was not a flashy UI change, but it made the package cleaner, lighter, and more appropriate for production consumers.",{"type":19,"tag":20,"props":1244,"children":1245},{},[1246],{"type":24,"value":1247},"That kind of work does not change the visual design of a page, but it improves the foundation that every consuming application relies on.",{"type":19,"tag":20,"props":1249,"children":1250},{},[1251],{"type":24,"value":1252},"Another example is CSS architecture. In one area, we had to think carefully about scoped styles and dynamic selectors. Scoped styles can be useful, but in our context, dynamically generated attributes created problems for external experimentation tools that relied on stable selectors. The solution was not just a technical preference. It was a platform decision: stable, predictable class names mattered because other teams and tools depended on them.",{"type":19,"tag":20,"props":1254,"children":1255},{},[1256],{"type":24,"value":1257},"These are the kinds of details that often sit below the surface of UI work. They are easy to miss until something breaks.",{"type":19,"tag":20,"props":1259,"children":1260},{},[1261],{"type":24,"value":1262},"A healthy UI system needs people who care about those details before they become production issues.",{"type":19,"tag":269,"props":1264,"children":1266},{"id":1265},"what-ive-learned",[1267],{"type":24,"value":1268},"What I've Learned",{"type":19,"tag":20,"props":1270,"children":1271},{},[1272],{"type":24,"value":1273},"The more I work in this space, the more I believe that shared UI work needs clear ownership.",{"type":19,"tag":20,"props":1275,"children":1276},{},[1277],{"type":24,"value":1278},"Not ownership in the sense of controlling everything, but ownership in the sense of caring for the system as a whole. Someone needs to think about how the component library evolves, how design decisions become code, how accessibility is documented, how teams consume releases, how visual quality is protected, and how technical debt is managed before it slows everyone down.",{"type":19,"tag":20,"props":1280,"children":1281},{},[1282],{"type":24,"value":1283},"A few lessons stand out.",{"type":19,"tag":20,"props":1285,"children":1286},{},[1287],{"type":24,"value":1288},"First, consistency does not happen by accident. It needs shared patterns, clear documentation, and regular maintenance.",{"type":19,"tag":20,"props":1290,"children":1291},{},[1292],{"type":24,"value":1293},"Second, documentation is part of the product. If teams cannot understand how to use a component, the component is not finished.",{"type":19,"tag":20,"props":1295,"children":1296},{},[1297],{"type":24,"value":1298},"Third, accessibility needs to be designed into the system, not added as a final layer.",{"type":19,"tag":20,"props":1300,"children":1301},{},[1302],{"type":24,"value":1303},"Fourth, adoption matters as much as implementation. The best component is not the one with the most options. It is the one that helps teams do the right thing with the least confusion.",{"type":19,"tag":20,"props":1305,"children":1306},{},[1307],{"type":24,"value":1308},"Fifth, UI foundations are never really done. Products change. Design language evolves. Frameworks move on. Accessibility expectations mature. What matters is having a system that can evolve without becoming chaotic.",{"type":19,"tag":20,"props":1310,"children":1311},{},[1312],{"type":24,"value":1313},"And finally, the invisible work matters. The package cleanup, the release notes, the testing setup, the design token naming, the migration guidance, the small fixes to focus states and CSS selectors — all of it contributes to the quality of the user experience, even when users never see the work directly.",{"type":19,"tag":20,"props":1315,"children":1316},{},[1317],{"type":24,"value":1318},"Over time, my role has moved from simply building UI to thinking about the conditions that help other teams build good UI. That shift has changed the way I see frontend work. The craft is still important, but so is the system that enables it to scale.",{"type":19,"tag":269,"props":1320,"children":1322},{"id":1321},"why-this-work-matters",[1323],{"type":24,"value":1324},"Why This Work Matters",{"type":19,"tag":20,"props":1326,"children":1327},{},[1328],{"type":24,"value":1329},"The goal of UI foundations is not to make every product look identical.",{"type":19,"tag":20,"props":1331,"children":1332},{},[1333],{"type":24,"value":1334},"The goal is to give teams a stronger starting point.",{"type":19,"tag":20,"props":1336,"children":1337},{},[1338],{"type":24,"value":1339},"Good UI foundations help teams move faster without creating unnecessary inconsistency. They make it easier to carry design intent into production. They reduce repeated work. They make accessibility easier to implement correctly and give QA clearer expectations. They help developers focus on product problems instead of rebuilding the same patterns again and again.",{"type":19,"tag":20,"props":1341,"children":1342},{},[1343],{"type":24,"value":1344},"Most importantly, they create a better user experience.",{"type":19,"tag":20,"props":1346,"children":1347},{},[1348],{"type":24,"value":1349},"Users do not see the component library. They do not see the design tokens, Storybook pages, release notes, visual regression tests, or packaging improvements. But they feel the result when journeys are more consistent, interactions behave as expected, pages are easier to navigate, and products feel more considered.",{"type":19,"tag":20,"props":1351,"children":1352},{},[1353],{"type":24,"value":1354},"That is why I care about this work.",{"type":19,"tag":20,"props":1356,"children":1357},{},[1358],{"type":24,"value":1359},"For me, building UI foundations across multiple products is about more than maintaining components.  It is about creating the conditions for consistently better digital experiences at scale, with less friction for everyone involved.",{"title":6,"searchDepth":209,"depth":209,"links":1361},[1362,1363,1364,1365,1366,1367,1368,1369,1370],{"id":799,"depth":209,"text":802},{"id":850,"depth":209,"text":853},{"id":896,"depth":209,"text":899},{"id":990,"depth":209,"text":993},{"id":1069,"depth":209,"text":1072},{"id":1125,"depth":209,"text":1128},{"id":1219,"depth":209,"text":1222},{"id":1265,"depth":209,"text":1268},{"id":1321,"depth":209,"text":1324},"content:articles:building-ui-foundations-across-multiple-products:index.md","articles/building-ui-foundations-across-multiple-products/index.md","articles/building-ui-foundations-across-multiple-products/index",{"_path":1375,"_dir":221,"_draft":7,"_partial":7,"_locale":6,"title":1376,"description":1377,"keywords":748,"slug":1378,"pagetitle":1376,"longPageTitle":1376,"date":1379,"longDate":1380,"serpDate":1381,"tags":1382,"category":756,"featured":234,"canonicalUrl":1383,"projectCompany":758,"projectLink":13,"projectThumbnail":1384,"projectMedia":1385,"pageClassName":13,"nextProjectSlug":1387,"schemaImage1x1":1386,"schemaImage4x3":1386,"schemaImage16x9":1386,"ctaTitle":1388,"ctaSubtitle":1389,"ctaButtonText":1390,"ctaButtonURL":220,"body":1391,"_type":213,"_id":2045,"_source":215,"_file":2046,"_stem":2047,"_extension":218},"/articles/how-do-you-reskin-a-website","From Outdated to Modern UI: How We Reskinned a Legacy Domino's Website\n","How do you reskin a website? A closer look at Domino's legacy website reskin project - the process, ups, downs and overall result","how-do-you-reskin-a-website","2022-04-20","April 20th, 2022","20 Apr 2022",[230,231,232],"https://www.eveatwork.studio/articles/how-do-you-reskin-a-website/","/articles/dominos-reskin.mp4",[1386],"/articles/side-by-side.png","hult-international-svg-animations","Related article","10 Things Business Leaders Need to Know About Website Reskinning","Read the article",{"type":16,"children":1392,"toc":2028},[1393,1398,1409,1414,1432,1437,1442,1448,1453,1476,1488,1494,1499,1511,1529,1535,1541,1546,1551,1564,1570,1575,1580,1603,1608,1620,1626,1631,1636,1641,1653,1659,1664,1669,1682,1687,1699,1705,1710,1738,1743,1755,1761,1767,1772,1777,1782,1792,1798,1803,1808,1827,1832,1837,1847,1857,1861,1866,1871,1876,1881,1885],{"type":19,"tag":20,"props":1394,"children":1395},{},[1396],{"type":24,"value":1397},"Just before the pandemic shifted us all into remote work, our team began planning a reskin project for Domino’s UK website.",{"type":19,"tag":20,"props":1399,"children":1400},{},[1401,1403,1407],{"type":24,"value":1402},"A ",{"type":19,"tag":37,"props":1404,"children":1405},{},[1406],{"type":24,"value":231},{"type":24,"value":1408}," is essentially a user interface (UI) refresh of the customer-facing side of a website.",{"type":19,"tag":20,"props":1410,"children":1411},{},[1412],{"type":24,"value":1413},"The process looks something like this:",{"type":19,"tag":66,"props":1415,"children":1416},{},[1417,1422,1427],{"type":19,"tag":70,"props":1418,"children":1419},{},[1420],{"type":24,"value":1421},"Start with an existing, well-established website (in our case, about 8 years old).",{"type":19,"tag":70,"props":1423,"children":1424},{},[1425],{"type":24,"value":1426},"Work from a polished design vision provided by the creative team.",{"type":19,"tag":70,"props":1428,"children":1429},{},[1430],{"type":24,"value":1431},"Transition from the current look to the new one as smoothly as possible, without disrupting the customer experience or business performance.",{"type":19,"tag":20,"props":1433,"children":1434},{},[1435],{"type":24,"value":1436},"This last point was especially important. Domino’s is one of the most popular pizza brands in the UK, and even subtle changes in the UI can influence customer behaviour. For example, something as simple as adjusting the style of a call-to-action button could reduce clicks. That’s why careful planning and incremental updates were crucial.",{"type":19,"tag":20,"props":1438,"children":1439},{},[1440],{"type":24,"value":1441},"Having spent months in both planning and implementation, I can say with confidence that reskinning a legacy website is a complex undertaking.",{"type":19,"tag":269,"props":1443,"children":1445},{"id":1444},"key-considerations",[1446],{"type":24,"value":1447},"Key Considerations",{"type":19,"tag":20,"props":1449,"children":1450},{},[1451],{"type":24,"value":1452},"Several challenges shaped our approach:",{"type":19,"tag":66,"props":1454,"children":1455},{},[1456,1461,1466,1471],{"type":19,"tag":70,"props":1457,"children":1458},{},[1459],{"type":24,"value":1460},"The project was a live system, with multiple development teams continuously adding features, backend logic, and UI updates.",{"type":19,"tag":70,"props":1462,"children":1463},{},[1464],{"type":24,"value":1465},"Some of the new designs required significant structural HTML changes.",{"type":19,"tag":70,"props":1467,"children":1468},{},[1469],{"type":24,"value":1470},"The codebase was based on older technologies and practices - layouts built with CSS tables, floats, and absolute positioning, with many fixed-width elements. Even small updates could cascade into widespread adjustments.",{"type":19,"tag":70,"props":1472,"children":1473},{},[1474],{"type":24,"value":1475},"UI components weren’t standardised, so the same element often appeared hundreds of times across the codebase. This meant even small changes could turn into time-consuming tasks.",{"type":19,"tag":20,"props":1477,"children":1478},{},[1479,1481,1486],{"type":24,"value":1480},"One might ask: why not rebuild from scratch with modern technologies and practices? The answer lies in customer trust. For a brand with such a loyal customer base, dramatic visual changes can disrupt the user experience and even affect trust in the platform. The reskin served as a ",{"type":19,"tag":37,"props":1482,"children":1483},{},[1484],{"type":24,"value":1485},"bridge",{"type":24,"value":1487}," between the old and the upcoming fully re-platformed website.",{"type":19,"tag":269,"props":1489,"children":1491},{"id":1490},"our-approach",[1492],{"type":24,"value":1493},"Our Approach",{"type":19,"tag":20,"props":1495,"children":1496},{},[1497],{"type":24,"value":1498},"This was the first reskin of this scale for most of the team. Domino’s receives a very high volume of daily visitors, which made the work both challenging and rewarding.",{"type":19,"tag":20,"props":1500,"children":1501},{},[1502,1504,1509],{"type":24,"value":1503},"We adopted a ",{"type":19,"tag":37,"props":1505,"children":1506},{},[1507],{"type":24,"value":1508},"phased, incremental approach",{"type":24,"value":1510},":",{"type":19,"tag":66,"props":1512,"children":1513},{},[1514,1519,1524],{"type":19,"tag":70,"props":1515,"children":1516},{},[1517],{"type":24,"value":1518},"A small team of one product owner, one designer, and two developers started the project, with QA joining later.",{"type":19,"tag":70,"props":1520,"children":1521},{},[1522],{"type":24,"value":1523},"The work was divided into five phases, each focusing on specific UI updates - such as colours, spacing, icons, or button styles.",{"type":19,"tag":70,"props":1525,"children":1526},{},[1527],{"type":24,"value":1528},"Incremental releases allowed us to gradually introduce changes, minimising disruption for customers.",{"type":19,"tag":269,"props":1530,"children":1532},{"id":1531},"project-phases",[1533],{"type":24,"value":1534},"Project Phases",{"type":19,"tag":59,"props":1536,"children":1538},{"id":1537},"phase-1-testing-the-ground",[1539],{"type":24,"value":1540},"Phase 1 – Testing the Ground",{"type":19,"tag":20,"props":1542,"children":1543},{},[1544],{"type":24,"value":1545},"This phase focused on preparation and exploration. We checked the codebase, updated outdated NPM packages, and created a file structure for all upcoming phases.",{"type":19,"tag":20,"props":1547,"children":1548},{},[1549],{"type":24,"value":1550},"For the customer-facing side, we introduced one small change: updating the primary and secondary colours. The change was intentionally minimal and went completely unnoticed by most visitors. That was fine - the main objective was to understand the legacy system and identify what to look out for in future stages.",{"type":19,"tag":20,"props":1552,"children":1553},{},[1554],{"type":19,"tag":98,"props":1555,"children":1556},{},[1557,1562],{"type":19,"tag":37,"props":1558,"children":1559},{},[1560],{"type":24,"value":1561},"Release date",{"type":24,"value":1563}," – 10/2020",{"type":19,"tag":59,"props":1565,"children":1567},{"id":1566},"phase-2-brightening-the-experience",[1568],{"type":24,"value":1569},"Phase 2 – Brightening the Experience",{"type":19,"tag":20,"props":1571,"children":1572},{},[1573],{"type":24,"value":1574},"Before this release, the website relied heavily on dark tones - grey navigation, black menu cards, and navy backgrounds.",{"type":19,"tag":20,"props":1576,"children":1577},{},[1578],{"type":24,"value":1579},"In this phase, we significantly brightened the site:",{"type":19,"tag":66,"props":1581,"children":1582},{},[1583,1588,1593,1598],{"type":19,"tag":70,"props":1584,"children":1585},{},[1586],{"type":24,"value":1587},"Navigation, cards, and backgrounds were lightened.",{"type":19,"tag":70,"props":1589,"children":1590},{},[1591],{"type":24,"value":1592},"Shadows were introduced for cards, helping them stand out from the background.",{"type":19,"tag":70,"props":1594,"children":1595},{},[1596],{"type":24,"value":1597},"Alignment and spacing issues were addressed across the site, giving elements more breathing space.",{"type":19,"tag":70,"props":1599,"children":1600},{},[1601],{"type":24,"value":1602},"Several PNG icons were replaced with vectors for sharper visuals.",{"type":19,"tag":20,"props":1604,"children":1605},{},[1606],{"type":24,"value":1607},"From a user perspective, the change felt subtle, but on closer inspection, pages were noticeably cleaner, brighter, and more consistent. For the team, this was a big milestone - our first visible transformation of the site.",{"type":19,"tag":20,"props":1609,"children":1610},{},[1611],{"type":19,"tag":98,"props":1612,"children":1613},{},[1614,1618],{"type":19,"tag":37,"props":1615,"children":1616},{},[1617],{"type":24,"value":1561},{"type":24,"value":1619}," – 02/2021",{"type":19,"tag":59,"props":1621,"children":1623},{"id":1622},"phase-3-icon-overhaul",[1624],{"type":24,"value":1625},"Phase 3 – Icon Overhaul",{"type":19,"tag":20,"props":1627,"children":1628},{},[1629],{"type":24,"value":1630},"After Phase 2, we realised our planned phases were quite large. We discussed breaking them into smaller increments, but because many design elements were interdependent, it wasn’t practical.",{"type":19,"tag":20,"props":1632,"children":1633},{},[1634],{"type":24,"value":1635},"Phase 3 focused on icons. Previously, the site used a mix of PNG sprites and Font Awesome. We consolidated these into a modern SVG system, which allowed for scalability and consistent quality.",{"type":19,"tag":20,"props":1637,"children":1638},{},[1639],{"type":24,"value":1640},"We also introduced ribbon titles to certain pages, adding a touch of playfulness that tied nicely with printed marketing materials.",{"type":19,"tag":20,"props":1642,"children":1643},{},[1644],{"type":19,"tag":98,"props":1645,"children":1646},{},[1647,1651],{"type":19,"tag":37,"props":1648,"children":1649},{},[1650],{"type":24,"value":1561},{"type":24,"value":1652}," – 03/2021",{"type":19,"tag":59,"props":1654,"children":1656},{"id":1655},"phase-4-completing-the-icon-work",[1657],{"type":24,"value":1658},"Phase 4 – Completing the Icon Work",{"type":19,"tag":20,"props":1660,"children":1661},{},[1662],{"type":24,"value":1663},"This phase turned out to be the most difficult. We continued migrating icons to the new SVG system but also updated several global elements.",{"type":19,"tag":20,"props":1665,"children":1666},{},[1667],{"type":24,"value":1668},"Key changes included:",{"type":19,"tag":66,"props":1670,"children":1671},{},[1672,1677],{"type":19,"tag":70,"props":1673,"children":1674},{},[1675],{"type":24,"value":1676},"Sub-navigation updates on the menu and checkout pages.",{"type":19,"tag":70,"props":1678,"children":1679},{},[1680],{"type":24,"value":1681},"A new, darker header style.",{"type":19,"tag":20,"props":1683,"children":1684},{},[1685],{"type":24,"value":1686},"Because these updates touched so many areas of the site, we encountered numerous unexpected issues. Still, the team stayed motivated, keeping spirits up with humour even as we worked through setbacks.",{"type":19,"tag":20,"props":1688,"children":1689},{},[1690],{"type":19,"tag":98,"props":1691,"children":1692},{},[1693,1697],{"type":19,"tag":37,"props":1694,"children":1695},{},[1696],{"type":24,"value":1561},{"type":24,"value":1698}," – 04/2021",{"type":19,"tag":59,"props":1700,"children":1702},{"id":1701},"phase-5-final-refinements",[1703],{"type":24,"value":1704},"Phase 5 – Final Refinements",{"type":19,"tag":20,"props":1706,"children":1707},{},[1708],{"type":24,"value":1709},"The last phase was all about polishing and consistency:",{"type":19,"tag":66,"props":1711,"children":1712},{},[1713,1718,1723,1728,1733],{"type":19,"tag":70,"props":1714,"children":1715},{},[1716],{"type":24,"value":1717},"Rounded buttons for a modern look.",{"type":19,"tag":70,"props":1719,"children":1720},{},[1721],{"type":24,"value":1722},"Cleaned-up dialogues and modals.",{"type":19,"tag":70,"props":1724,"children":1725},{},[1726],{"type":24,"value":1727},"Layout refinements across pages.",{"type":19,"tag":70,"props":1729,"children":1730},{},[1731],{"type":24,"value":1732},"Final designs for promotional cards.",{"type":19,"tag":70,"props":1734,"children":1735},{},[1736],{"type":24,"value":1737},"Navigation updates with a white background and clearer fulfilment and cart CTAs.",{"type":19,"tag":20,"props":1739,"children":1740},{},[1741],{"type":24,"value":1742},"The knowledge that this was the final phase kept the team energised. That said, every time we spotted a missed UI element, we joked about an imaginary “Phase 6.”",{"type":19,"tag":20,"props":1744,"children":1745},{},[1746],{"type":19,"tag":98,"props":1747,"children":1748},{},[1749,1753],{"type":19,"tag":37,"props":1750,"children":1751},{},[1752],{"type":24,"value":1561},{"type":24,"value":1754}," – 06/2021",{"type":19,"tag":269,"props":1756,"children":1758},{"id":1757},"challenges-and-lessons-learned",[1759],{"type":24,"value":1760},"Challenges and Lessons Learned",{"type":19,"tag":59,"props":1762,"children":1764},{"id":1763},"legacy-code-and-structure",[1765],{"type":24,"value":1766},"Legacy Code and Structure",{"type":19,"tag":20,"props":1768,"children":1769},{},[1770],{"type":24,"value":1771},"The CSS and HTML were organised in a way that made incremental updates more complex. For example, the same styles were sometimes applied to unrelated components, and we often found duplicate templates with only minor variations.",{"type":19,"tag":20,"props":1773,"children":1774},{},[1775],{"type":24,"value":1776},"To improve maintainability, we reorganised CSS using the BEM methodology, grouping component styles more logically. The project was already using SCSS, which made this transition smoother.",{"type":19,"tag":20,"props":1778,"children":1779},{},[1780],{"type":24,"value":1781},"Still, due to the scope and timeline, we couldn’t fully refactor the HTML. Updating the same copy-pasted code across different areas became repetitive and time-consuming.",{"type":19,"tag":20,"props":1783,"children":1784},{},[1785,1790],{"type":19,"tag":37,"props":1786,"children":1787},{},[1788],{"type":24,"value":1789},"Lesson:",{"type":24,"value":1791}," Code organisation is best addressed early in a project. Following best practices from the start ensures scalability and reduces technical debt.",{"type":19,"tag":59,"props":1793,"children":1795},{"id":1794},"source-control-and-qa-process",[1796],{"type":24,"value":1797},"Source Control and QA Process",{"type":19,"tag":20,"props":1799,"children":1800},{},[1801],{"type":24,"value":1802},"Initially, only two developers worked on the reskin, with QA joining later. By then, several phases were already underway, creating challenges with bug fixes overlapping active development.",{"type":19,"tag":20,"props":1804,"children":1805},{},[1806],{"type":24,"value":1807},"The process looked like this:",{"type":19,"tag":1809,"props":1810,"children":1811},"ol",{},[1812,1817,1822],{"type":19,"tag":70,"props":1813,"children":1814},{},[1815],{"type":24,"value":1816},"QA found a bug in Phase 2.",{"type":19,"tag":70,"props":1818,"children":1819},{},[1820],{"type":24,"value":1821},"We fixed it in Phase 2, then merged it into Phase 3 and Phase 4.",{"type":19,"tag":70,"props":1823,"children":1824},{},[1825],{"type":24,"value":1826},"Another bug was found, and the cycle repeated.",{"type":19,"tag":20,"props":1828,"children":1829},{},[1830],{"type":24,"value":1831},"Because fixes overlapped with in-progress work, regressions often crept in. We frequently found ourselves redoing work we thought was complete. Phase 4, in particular, was challenging due to regressions and rework.",{"type":19,"tag":20,"props":1833,"children":1834},{},[1835],{"type":24,"value":1836},"By contrast, Phase 5 - larger in scope - went much more smoothly, because QA was fully engaged alongside development. Bugs were caught early and resolved before becoming regressions.",{"type":19,"tag":20,"props":1838,"children":1839},{},[1840,1845],{"type":19,"tag":37,"props":1841,"children":1842},{},[1843],{"type":24,"value":1844},"Lesson 1:",{"type":24,"value":1846}," Engage the whole team - including QA - from day one. Parallel testing prevents regressions and saves significant time later.",{"type":19,"tag":20,"props":1848,"children":1849},{},[1850,1855],{"type":19,"tag":37,"props":1851,"children":1852},{},[1853],{"type":24,"value":1854},"Lesson 2:",{"type":24,"value":1856}," If resources are limited, structuring work into isolated sets of files or branches for each phase can help reduce conflicts.",{"type":19,"tag":269,"props":1858,"children":1859},{"id":604},[1860],{"type":24,"value":607},{"type":19,"tag":20,"props":1862,"children":1863},{},[1864],{"type":24,"value":1865},"Despite the challenges, the reskin project achieved its goal: creating a smoother bridge between the legacy Domino’s website and the upcoming re-platform.",{"type":19,"tag":20,"props":1867,"children":1868},{},[1869],{"type":24,"value":1870},"The updated UI aligned more closely with modern design expectations while maintaining customer trust and engagement. The project also gave the team valuable experience in phased rollouts, legacy code management, and collaboration under constraints.",{"type":19,"tag":20,"props":1872,"children":1873},{},[1874],{"type":24,"value":1875},"Most importantly, it set the stage for the next chapter: introducing Vue.js, Storybook, headless CMS, and microservices into the Domino’s platform.",{"type":19,"tag":20,"props":1877,"children":1878},{},[1879],{"type":24,"value":1880},"Thank you for reading, and I look forward to sharing more insights in future articles.",{"type":19,"tag":269,"props":1882,"children":1883},{"id":620},[1884],{"type":24,"value":623},{"type":19,"tag":66,"props":1886,"children":1887},{},[1888,1898,1908,1918,1928,1938,1948,1958,1968,1978,1988,1998,2008,2018],{"type":19,"tag":70,"props":1889,"children":1890},{},[1891,1896],{"type":19,"tag":37,"props":1892,"children":1893},{},[1894],{"type":24,"value":1895},"UI (User Interface):",{"type":24,"value":1897}," The visual and interactive elements of a website or application that users engage with.",{"type":19,"tag":70,"props":1899,"children":1900},{},[1901,1906],{"type":19,"tag":37,"props":1902,"children":1903},{},[1904],{"type":24,"value":1905},"CTA (Call-to-Action):",{"type":24,"value":1907}," A button or link designed to encourage a specific user action (e.g., “Order Now”).",{"type":19,"tag":70,"props":1909,"children":1910},{},[1911,1916],{"type":19,"tag":37,"props":1912,"children":1913},{},[1914],{"type":24,"value":1915},"HTML (Hypertext Markup Language):",{"type":24,"value":1917}," The standard language used to structure content on the web.",{"type":19,"tag":70,"props":1919,"children":1920},{},[1921,1926],{"type":19,"tag":37,"props":1922,"children":1923},{},[1924],{"type":24,"value":1925},"CSS (Cascading Style Sheets):",{"type":24,"value":1927}," A stylesheet language used to control the design, layout, and presentation of HTML elements.",{"type":19,"tag":70,"props":1929,"children":1930},{},[1931,1936],{"type":19,"tag":37,"props":1932,"children":1933},{},[1934],{"type":24,"value":1935},"SCSS (Sassy CSS):",{"type":24,"value":1937}," A CSS preprocessor that adds features like variables and nesting for easier stylesheet management.",{"type":19,"tag":70,"props":1939,"children":1940},{},[1941,1946],{"type":19,"tag":37,"props":1942,"children":1943},{},[1944],{"type":24,"value":1945},"BEM (Block, Element, Modifier):",{"type":24,"value":1947}," A methodology for naming and organising CSS classes in a consistent and scalable way.",{"type":19,"tag":70,"props":1949,"children":1950},{},[1951,1956],{"type":19,"tag":37,"props":1952,"children":1953},{},[1954],{"type":24,"value":1955},"NPM (Node Package Manager):",{"type":24,"value":1957}," A tool used to manage JavaScript libraries and dependencies in a project.",{"type":19,"tag":70,"props":1959,"children":1960},{},[1961,1966],{"type":19,"tag":37,"props":1962,"children":1963},{},[1964],{"type":24,"value":1965},"SVG (Scalable Vector Graphics):",{"type":24,"value":1967}," A file format for vector images that can scale to any size without losing quality.",{"type":19,"tag":70,"props":1969,"children":1970},{},[1971,1976],{"type":19,"tag":37,"props":1972,"children":1973},{},[1974],{"type":24,"value":1975},"PNG (Portable Network Graphics):",{"type":24,"value":1977}," A raster image format commonly used for web graphics.",{"type":19,"tag":70,"props":1979,"children":1980},{},[1981,1986],{"type":19,"tag":37,"props":1982,"children":1983},{},[1984],{"type":24,"value":1985},"Font Awesome:",{"type":24,"value":1987}," A popular library of pre-built icons.",{"type":19,"tag":70,"props":1989,"children":1990},{},[1991,1996],{"type":19,"tag":37,"props":1992,"children":1993},{},[1994],{"type":24,"value":1995},"QA (Quality Assurance):",{"type":24,"value":1997}," The process of testing software to ensure it works correctly and meets requirements.",{"type":19,"tag":70,"props":1999,"children":2000},{},[2001,2006],{"type":19,"tag":37,"props":2002,"children":2003},{},[2004],{"type":24,"value":2005},"Regression:",{"type":24,"value":2007}," A bug that reappears after previously being fixed, often caused by later changes in the codebase.",{"type":19,"tag":70,"props":2009,"children":2010},{},[2011,2016],{"type":19,"tag":37,"props":2012,"children":2013},{},[2014],{"type":24,"value":2015},"Source Control:",{"type":24,"value":2017}," A system for managing changes to code (e.g., Git).",{"type":19,"tag":70,"props":2019,"children":2020},{},[2021,2026],{"type":19,"tag":37,"props":2022,"children":2023},{},[2024],{"type":24,"value":2025},"Re-platforming:",{"type":24,"value":2027}," Rebuilding or migrating a website onto a modern technology stack while maintaining its functionality.",{"title":6,"searchDepth":209,"depth":209,"links":2029},[2030,2031,2032,2039,2043,2044],{"id":1444,"depth":209,"text":1447},{"id":1490,"depth":209,"text":1493},{"id":1531,"depth":209,"text":1534,"children":2033},[2034,2035,2036,2037,2038],{"id":1537,"depth":212,"text":1540},{"id":1566,"depth":212,"text":1569},{"id":1622,"depth":212,"text":1625},{"id":1655,"depth":212,"text":1658},{"id":1701,"depth":212,"text":1704},{"id":1757,"depth":209,"text":1760,"children":2040},[2041,2042],{"id":1763,"depth":212,"text":1766},{"id":1794,"depth":212,"text":1797},{"id":604,"depth":209,"text":607},{"id":620,"depth":209,"text":623},"content:articles:how-do-you-reskin-a-website:index.md","articles/how-do-you-reskin-a-website/index.md","articles/how-do-you-reskin-a-website/index",{"_path":2049,"_dir":221,"_draft":7,"_partial":7,"_locale":6,"title":2050,"description":2051,"keywords":2052,"slug":2053,"pagetitle":2050,"longPageTitle":2050,"date":2054,"longDate":2055,"serpDate":2056,"tags":2057,"category":2060,"featured":234,"canonicalUrl":2061,"projectCompany":758,"projectLink":13,"projectThumbnail":2062,"projectMedia":2063,"pageClassName":13,"nextProjectSlug":749,"schemaImage1x1":2065,"schemaImage4x3":2066,"schemaImage16x9":2067,"ctaTitle":13,"ctaSubtitle":13,"ctaButtonText":13,"body":2068,"_type":213,"_id":4059,"_source":215,"_file":4060,"_stem":4061,"_extension":218},"/articles/how-to-build-your-own-design-tokens-package-using-figma-variables-api","How to Build Your Own Design Tokens Package Using Figma Variables API","Discover how Domino's streamlined UI consistency and design token generation by leveraging the Figma Variables API. Learn about automating theme support, integrating design tokens across projects, and simplifying light and dark mode implementation.","Figma Variables API, Design tokens, Figma API design tokens, UI consistency, Design token automation, Light and dark mode implementation, Figma theming, Scalable design systems, Domino's UI development, Figma for enterprise","how-to-build-your-own-design-tokens-package-using-figma-variables-api","2026-11-05","November 5th, 2026","05 Nov 2026",[232,754,116,230,2058,2059],"process improvements","technical guide","How-to guide","https://www.eveatwork.studio/articles/how-to-build-your-own-design-tokens-package-using-figma-variables-api","/articles/build-your-own-design-tokens/build-your-own-design-tokens-package--thumbnail.png",[2064],"/articles/build-your-own-design-tokens/build-your-own-design-tokens-package--page-hero.png","/articles/build-your-own-design-tokens/build-your-own-design-tokens-package__1x1.png","/articles/build-your-own-design-tokens/build-your-own-design-tokens-package__4x3.png","/articles/build-your-own-design-tokens/build-your-own-design-tokens-package__16x9.png",{"type":16,"children":2069,"toc":4017},[2070,2086,2091,2096,2101,2114,2120,2126,2131,2136,2141,2146,2213,2218,2224,2229,2235,2240,2273,2278,2354,2359,2364,2372,2377,2383,2388,2394,2399,2417,2422,2438,2444,2449,2454,2459,2471,2491,2497,2502,2512,2517,2540,2545,2556,2562,2568,2581,2592,2612,2617,2626,2632,2637,2646,2655,2684,2689,2714,2735,2741,2746,2757,2762,2775,2794,2803,2822,2831,2872,2878,2883,2892,2901,2906,2912,2917,2923,2928,2937,3025,3038,3057,3077,3083,3129,3134,3160,3169,3209,3216,3228,3241,3247,3282,3291,3316,3348,3358,3363,3369,3382,3395,3404,3409,3492,3498,3503,3512,3517,3544,3550,3555,3566,3571,3580,3618,3623,3629,3634,3645,3651,3656,3662,3671,3684,3690,3695,3704,3709,3718,3723,3736,3742,3754,3759,3768,3781,3787,3792,3801,3826,3839,3860,3871,3877,3882,3891,3896,3901,3907,3912,3918,3923,3928,3933,3938,3944,3949,3954,3960,3965,3991,3997,4002,4007,4012],{"type":19,"tag":20,"props":2071,"children":2072},{},[2073,2075,2084],{"type":24,"value":2074},"In my ",{"type":19,"tag":2076,"props":2077,"children":2081},"a",{"href":2078,"rel":2079},"https://www.eveatwork.studio/articles/how-we-utilised-figma-variables-api-for-creating-design-tokens/",[2080],"nofollow",[2082],{"type":24,"value":2083},"previous article",{"type":24,"value":2085},", I explained how we started using Figma's Variables API to improve UI consistency at Domino's.",{"type":19,"tag":20,"props":2087,"children":2088},{},[2089],{"type":24,"value":2090},"A key part of that solution was a custom design tokens package that I designed and developed to connect our Figma variables with our front-end applications. The package has since evolved, with further contributions from my team.",{"type":19,"tag":20,"props":2092,"children":2093},{},[2094],{"type":24,"value":2095},"That article received a lot of interest, so in this tutorial, I'll show you how to build something similar yourself.",{"type":19,"tag":20,"props":2097,"children":2098},{},[2099],{"type":24,"value":2100},"We'll fetch variables using Figma's REST API, resolve aliases, generate SCSS files supporting light and dark themes, and prepare the results for distribution as an npm package.",{"type":19,"tag":20,"props":2102,"children":2103},{},[2104,2106,2112],{"type":24,"value":2105},"One caveat before we start: the Variables REST API currently requires a Figma Enterprise plan. If you don't have one, see ",{"type":19,"tag":2076,"props":2107,"children":2109},{"href":2108},"#what-youll-need",[2110],{"type":24,"value":2111},"What you'll need",{"type":24,"value":2113}," for alternatives.",{"type":19,"tag":269,"props":2115,"children":2117},{"id":2116},"before-we-start",[2118],{"type":24,"value":2119},"Before we start",{"type":19,"tag":59,"props":2121,"children":2123},{"id":2122},"why-build-your-own-design-tokens-package",[2124],{"type":24,"value":2125},"Why build your own design tokens package?",{"type":19,"tag":20,"props":2127,"children":2128},{},[2129],{"type":24,"value":2130},"Plenty of tools already manage design tokens, and for many teams an existing solution is the right choice.",{"type":19,"tag":20,"props":2132,"children":2133},{},[2134],{"type":24,"value":2135},"The main reason to build your own is control. You decide how variables are named, processed and organised, and which output formats you generate. That helps when you're working with existing applications that have specific requirements, and it gives you a clear understanding of how design decisions travel from Figma into production code.",{"type":19,"tag":20,"props":2137,"children":2138},{},[2139],{"type":24,"value":2140},"The trade-off is maintenance: you'll need to keep the package compatible with changes to Figma's API and make sure the generated output stays reliable. If your requirements are fairly straightforward, a small Node.js application is often all you need.",{"type":19,"tag":59,"props":2142,"children":2144},{"id":2143},"what-youll-need",[2145],{"type":24,"value":2111},{"type":19,"tag":66,"props":2147,"children":2148},{},[2149,2168,2187,2205],{"type":19,"tag":70,"props":2150,"children":2151},{},[2152,2157,2159,2166],{"type":19,"tag":37,"props":2153,"children":2154},{},[2155],{"type":24,"value":2156},"Figma Enterprise access.",{"type":24,"value":2158}," The Variables REST API requires an eligible Enterprise account, appropriate seat permissions and access to the relevant file. Check ",{"type":19,"tag":2076,"props":2160,"children":2163},{"href":2161,"rel":2162},"https://developers.figma.com/docs/rest-api/variables/",[2080],[2164],{"type":24,"value":2165},"Figma's documentation",{"type":24,"value":2167}," for the latest requirements.",{"type":19,"tag":70,"props":2169,"children":2170},{},[2171,2176,2178,2185],{"type":19,"tag":37,"props":2172,"children":2173},{},[2174],{"type":24,"value":2175},"Figma's personal access token",{"type":24,"value":2177}," with the ",{"type":19,"tag":2179,"props":2180,"children":2182},"code",{"className":2181},[],[2183],{"type":24,"value":2184},"file_variables:read",{"type":24,"value":2186}," scope.",{"type":19,"tag":70,"props":2188,"children":2189},{},[2190,2195,2197,2203],{"type":19,"tag":37,"props":2191,"children":2192},{},[2193],{"type":24,"value":2194},"Node.js 24 or 26 LTS and npm.",{"type":24,"value":2196}," We'll use Node's built-in ",{"type":19,"tag":2179,"props":2198,"children":2200},{"className":2199},[],[2201],{"type":24,"value":2202},"fetch",{"type":24,"value":2204}," API, so there's no need for an additional HTTP client.",{"type":19,"tag":70,"props":2206,"children":2207},{},[2208],{"type":19,"tag":37,"props":2209,"children":2210},{},[2211],{"type":24,"value":2212},"Basic JavaScript and SCSS knowledge.",{"type":19,"tag":20,"props":2214,"children":2215},{},[2216],{"type":24,"value":2217},"If you're not on an Enterprise plan, Figma's Plugin API can read variables from inside Figma, although that needs a different implementation from the one in this article. Existing plugins and tools, such as Tokens Studio, may also cover your needs without any custom code.",{"type":19,"tag":269,"props":2219,"children":2221},{"id":2220},"_1-prepare-your-variables-in-figma",[2222],{"type":24,"value":2223},"1. Prepare your variables in Figma",{"type":19,"tag":20,"props":2225,"children":2226},{},[2227],{"type":24,"value":2228},"Before writing any code, we need variables to work with.",{"type":19,"tag":59,"props":2230,"children":2232},{"id":2231},"collections-modes-and-aliases",[2233],{"type":24,"value":2234},"Collections, modes and aliases",{"type":19,"tag":20,"props":2236,"children":2237},{},[2238],{"type":24,"value":2239},"Figma organises variables using three concepts:",{"type":19,"tag":66,"props":2241,"children":2242},{},[2243,2253,2263],{"type":19,"tag":70,"props":2244,"children":2245},{},[2246,2251],{"type":19,"tag":37,"props":2247,"children":2248},{},[2249],{"type":24,"value":2250},"Collections",{"type":24,"value":2252}," group related variables, such as colours or spacing.",{"type":19,"tag":70,"props":2254,"children":2255},{},[2256,2261],{"type":19,"tag":37,"props":2257,"children":2258},{},[2259],{"type":24,"value":2260},"Modes",{"type":24,"value":2262}," let the same variable hold different values, such as Light and Dark.",{"type":19,"tag":70,"props":2264,"children":2265},{},[2266,2271],{"type":19,"tag":37,"props":2267,"children":2268},{},[2269],{"type":24,"value":2270},"Aliases",{"type":24,"value":2272}," let one variable reference another instead of duplicating its value.",{"type":19,"tag":20,"props":2274,"children":2275},{},[2276],{"type":24,"value":2277},"Our example uses two collections:",{"type":19,"tag":66,"props":2279,"children":2280},{},[2281,2316],{"type":19,"tag":70,"props":2282,"children":2283},{},[2284,2290,2292,2298,2300,2306,2308,2314],{"type":19,"tag":2179,"props":2285,"children":2287},{"className":2286},[],[2288],{"type":24,"value":2289},"Palette",{"type":24,"value":2291}," holds three base colours: ",{"type":19,"tag":2179,"props":2293,"children":2295},{"className":2294},[],[2296],{"type":24,"value":2297},"Neutral/dark",{"type":24,"value":2299},", ",{"type":19,"tag":2179,"props":2301,"children":2303},{"className":2302},[],[2304],{"type":24,"value":2305},"Neutral/white",{"type":24,"value":2307}," and ",{"type":19,"tag":2179,"props":2309,"children":2311},{"className":2310},[],[2312],{"type":24,"value":2313},"Neutral/grey",{"type":24,"value":2315},". It has a single mode.",{"type":19,"tag":70,"props":2317,"children":2318},{},[2319,2324,2326,2332,2333,2339,2340,2346,2348,2353],{"type":19,"tag":2179,"props":2320,"children":2322},{"className":2321},[],[2323],{"type":24,"value":2260},{"type":24,"value":2325}," holds four semantic colours, including ",{"type":19,"tag":2179,"props":2327,"children":2329},{"className":2328},[],[2330],{"type":24,"value":2331},"Surface/primary",{"type":24,"value":2299},{"type":19,"tag":2179,"props":2334,"children":2336},{"className":2335},[],[2337],{"type":24,"value":2338},"Text/primary",{"type":24,"value":2307},{"type":19,"tag":2179,"props":2341,"children":2343},{"className":2342},[],[2344],{"type":24,"value":2345},"Border/default",{"type":24,"value":2347},". It has two modes, Light and Dark, and each value is an alias pointing to a colour in ",{"type":19,"tag":2179,"props":2349,"children":2351},{"className":2350},[],[2352],{"type":24,"value":2289},{"type":24,"value":125},{"type":19,"tag":20,"props":2355,"children":2356},{},[2357],{"type":24,"value":2358},"Both collections are included in the generated output in this sample project. You can also hide a palette collection from publishing if you only want semantic tokens in your package.",{"type":19,"tag":20,"props":2360,"children":2361},{},[2362],{"type":24,"value":2363},"Palette:",{"type":19,"tag":2365,"props":2366,"children":2371},"img",{"src":2367,"className":2368,"alt":2370},"v1793872801/figma-design-tokens--palette_uehmay.png",[2369],"no-padding","Figma's variables panel showing a Palette collection with a single mode, where each palette colour is a variable.",[],{"type":19,"tag":20,"props":2373,"children":2374},{},[2375],{"type":24,"value":2376},"Modes:",{"type":19,"tag":2365,"props":2378,"children":2382},{"src":2379,"className":2380,"alt":2381},"v1793872801/figma-design-tokens--modes_umwhcs.png",[2369],"Figma's variables panel showing a Modes collection with Light and Dark modes, where each semantic variable references a palette colour.",[],{"type":19,"tag":20,"props":2384,"children":2385},{},[2386],{"type":24,"value":2387},"Aliases let designers maintain a colour palette separately from the semantic variables used throughout the interface. They also mean we can't copy values from the API response straight into CSS. We have to resolve those references first.",{"type":19,"tag":59,"props":2389,"children":2391},{"id":2390},"choose-meaningful-variable-names",[2392],{"type":24,"value":2393},"Choose meaningful variable names",{"type":19,"tag":20,"props":2395,"children":2396},{},[2397],{"type":24,"value":2398},"Agree on a naming convention before you create your variables.",{"type":19,"tag":20,"props":2400,"children":2401},{},[2402,2407,2409,2415],{"type":19,"tag":2179,"props":2403,"children":2405},{"className":2404},[],[2406],{"type":24,"value":2338},{"type":24,"value":2408}," describes how a colour is used, whereas ",{"type":19,"tag":2179,"props":2410,"children":2412},{"className":2411},[],[2413],{"type":24,"value":2414},"Dark Grey",{"type":24,"value":2416}," describes how it looks. Semantic names are more flexible because their purpose stays the same even when the underlying values change.",{"type":19,"tag":20,"props":2418,"children":2419},{},[2420],{"type":24,"value":2421},"Figma lets you use forward slashes to build hierarchies, and we'll use those names to generate CSS custom properties later:",{"type":19,"tag":20,"props":2423,"children":2424},{},[2425,2430,2432],{"type":19,"tag":2179,"props":2426,"children":2428},{"className":2427},[],[2429],{"type":24,"value":2338},{"type":24,"value":2431}," → ",{"type":19,"tag":2179,"props":2433,"children":2435},{"className":2434},[],[2436],{"type":24,"value":2437},"--text-primary",{"type":19,"tag":269,"props":2439,"children":2441},{"id":2440},"_2-set-up-the-nodejs-application",[2442],{"type":24,"value":2443},"2. Set up the Node.js application",{"type":19,"tag":20,"props":2445,"children":2446},{},[2447],{"type":24,"value":2448},"The code in this tutorial is based on the package I originally developed for Domino's, with some refactoring and simplification to make the individual steps easier to understand.",{"type":19,"tag":20,"props":2450,"children":2451},{},[2452],{"type":24,"value":2453},"We'll use Node.js to fetch the data, process the values and generate the output files.",{"type":19,"tag":20,"props":2455,"children":2456},{},[2457],{"type":24,"value":2458},"Create a directory and initialise an npm package:",{"type":19,"tag":2460,"props":2461,"children":2466},"pre",{"className":2462,"code":2464,"language":2465,"meta":6},[2463],"language-bash","mkdir figma-design-tokens\ncd figma-design-tokens\nnpm init -y\nnpm pkg set type=module\nnpm install --save-dev dotenv\n","bash",[2467],{"type":19,"tag":2179,"props":2468,"children":2469},{"__ignoreMap":6},[2470],{"type":24,"value":2464},{"type":19,"tag":20,"props":2472,"children":2473},{},[2474,2476,2481,2483,2489],{"type":24,"value":2475},"We'll use JavaScript modules and Node's built-in ",{"type":19,"tag":2179,"props":2477,"children":2479},{"className":2478},[],[2480],{"type":24,"value":2202},{"type":24,"value":2482},", so there's no need for an HTTP client. ",{"type":19,"tag":2179,"props":2484,"children":2486},{"className":2485},[],[2487],{"type":24,"value":2488},"dotenv",{"type":24,"value":2490}," is a dev dependency because only the generation script needs it, not the consumers of your package.",{"type":19,"tag":59,"props":2492,"children":2494},{"id":2493},"organise-the-application",[2495],{"type":24,"value":2496},"Organise the application",{"type":19,"tag":20,"props":2498,"children":2499},{},[2500],{"type":24,"value":2501},"You could write the whole process in one file, but smaller functions are easier to read and test. Here's the structure we'll build:",{"type":19,"tag":2460,"props":2503,"children":2507},{"className":2504,"code":2506,"language":24,"meta":6},[2505],"language-text","figma-design-tokens/\n├── index.js\n├── _config.js\n├── _steps/\n│   ├── _fetch-figma.js\n│   ├── _write-json.js\n│   ├── _alias-resolver.js\n│   ├── _build-token-sets.js\n│   └── _write-token-files.js\n├── _utils/\n│   ├── _files.js\n│   ├── _names.js\n│   └── _values.js\n├── compiled/            # generated output\n└── package.json\n",[2508],{"type":19,"tag":2179,"props":2509,"children":2510},{"__ignoreMap":6},[2511],{"type":24,"value":2506},{"type":19,"tag":20,"props":2513,"children":2514},{},[2515],{"type":24,"value":2516},"The process has four steps:",{"type":19,"tag":1809,"props":2518,"children":2519},{},[2520,2525,2530,2535],{"type":19,"tag":70,"props":2521,"children":2522},{},[2523],{"type":24,"value":2524},"Fetch variables from Figma.",{"type":19,"tag":70,"props":2526,"children":2527},{},[2528],{"type":24,"value":2529},"Save the response as JSON.",{"type":19,"tag":70,"props":2531,"children":2532},{},[2533],{"type":24,"value":2534},"Transform the variables into token sets: resolve aliases, convert values and sort.",{"type":19,"tag":70,"props":2536,"children":2537},{},[2538],{"type":24,"value":2539},"Write the SCSS and TypeScript files.",{"type":19,"tag":20,"props":2541,"children":2542},{},[2543],{"type":24,"value":2544},"The application builds and validates the token sets before writing the generated SCSS and TypeScript files. This means errors during token transformation won't leave partially generated styles behind. We'll then write each completed token set to its corresponding output files.",{"type":19,"tag":2460,"props":2546,"children":2551},{"className":2547,"code":2549,"language":2550,"meta":6},[2548],"language-js","// index.js\nimport { CONFIG } from \"./_config.js\";\nimport { fetchFigmaVariables } from \"./_steps/_fetch-figma.js\";\nimport { writeInitialJson } from \"./_steps/_write-json.js\";\nimport { buildTokenSets } from \"./_steps/_build-token-sets.js\";\nimport { writeTokenFiles } from \"./_steps/_write-token-files.js\";\ntry {\n  const { FIGMA_FILE_KEY, OUTPUT_PATHS } = CONFIG;\n  const data = await fetchFigmaVariables(FIGMA_FILE_KEY);\n  writeInitialJson(data, OUTPUT_PATHS.JSON);\n  const tokenSets = buildTokenSets(data);\n  writeTokenFiles(tokenSets, OUTPUT_PATHS);\n  console.log(\"Token compilation complete!\");\n} catch (error) {\n  console.error(\"Token compilation failed:\", error);\n  process.exitCode = 1;\n}\n","js",[2552],{"type":19,"tag":2179,"props":2553,"children":2554},{"__ignoreMap":6},[2555],{"type":24,"value":2549},{"type":19,"tag":269,"props":2557,"children":2559},{"id":2558},"_3-fetch-variables-from-figma",[2560],{"type":24,"value":2561},"3. Fetch variables from Figma",{"type":19,"tag":59,"props":2563,"children":2565},{"id":2564},"configure-authentication",[2566],{"type":24,"value":2567},"Configure authentication",{"type":19,"tag":20,"props":2569,"children":2570},{},[2571,2573,2579],{"type":24,"value":2572},"Store your token and file key in a ",{"type":19,"tag":2179,"props":2574,"children":2576},{"className":2575},[],[2577],{"type":24,"value":2578},".env",{"type":24,"value":2580}," file rather than hardcoding them:",{"type":19,"tag":2460,"props":2582,"children":2587},{"className":2583,"code":2585,"language":2586,"meta":6},[2584],"language-env","FIGMA_API_TOKEN=your_access_token\nFIGMA_FILE_KEY=your_figma_file_key\n","env",[2588],{"type":19,"tag":2179,"props":2589,"children":2590},{"__ignoreMap":6},[2591],{"type":24,"value":2585},{"type":19,"tag":20,"props":2593,"children":2594},{},[2595,2597,2602,2604,2610],{"type":24,"value":2596},"You can find the file key in the URL of the Figma file containing your variables. Add ",{"type":19,"tag":2179,"props":2598,"children":2600},{"className":2599},[],[2601],{"type":24,"value":2578},{"type":24,"value":2603}," to ",{"type":19,"tag":2179,"props":2605,"children":2607},{"className":2606},[],[2608],{"type":24,"value":2609},".gitignore",{"type":24,"value":2611}," so your credentials aren't committed.",{"type":19,"tag":20,"props":2613,"children":2614},{},[2615],{"type":24,"value":2616},"Then read the values and define your output paths in one place:",{"type":19,"tag":2460,"props":2618,"children":2621},{"className":2619,"code":2620,"language":2550,"meta":6},[2548],"// _config.js\nimport \"dotenv/config\";\nexport const CONFIG = {\n  FIGMA_FILE_KEY: process.env.FIGMA_FILE_KEY,\n  OUTPUT_PATHS: {\n    JSON: \"./compiled/json/\",\n    SCSS: \"./compiled/design-tokens/scss/\",\n    DOCS: \"./compiled/helpers/doc-helpers/\",\n  },\n};\n",[2622],{"type":19,"tag":2179,"props":2623,"children":2624},{"__ignoreMap":6},[2625],{"type":24,"value":2620},{"type":19,"tag":59,"props":2627,"children":2629},{"id":2628},"fetch-the-variables",[2630],{"type":24,"value":2631},"Fetch the variables",{"type":19,"tag":20,"props":2633,"children":2634},{},[2635],{"type":24,"value":2636},"Figma provides an endpoint for retrieving a file's variables:",{"type":19,"tag":20,"props":2638,"children":2639},{},[2640],{"type":19,"tag":2179,"props":2641,"children":2643},{"className":2642},[],[2644],{"type":24,"value":2645},"GET /v1/files/:file_key/variables/local",{"type":19,"tag":2460,"props":2647,"children":2650},{"className":2648,"code":2649,"language":2550,"meta":6},[2548],"// _steps/_fetch-figma.js\nimport \"dotenv/config\";\nexport async function fetchFigmaVariables(fileKey) {\n  const token = process.env.FIGMA_API_TOKEN;\n  if (!token || !fileKey) {\n    throw new Error(\n      \"Set FIGMA_API_TOKEN and FIGMA_FILE_KEY in your .env file.\"\n    );\n  }\n  const res = await fetch(\n    `https://api.figma.com/v1/files/${fileKey}/variables/local`,\n    { headers: { \"X-FIGMA-TOKEN\": token } }\n  );\n  if (!res.ok) {\n    const body = await res.text();\n    throw new Error(\n      `Figma API request failed (${res.status}): ${body}`\n    );\n  }\n  const { meta } = await res.json();\n  return {\n    collections: meta.variableCollections,\n    variables: meta.variables,\n  };\n}\n",[2651],{"type":19,"tag":2179,"props":2652,"children":2653},{"__ignoreMap":6},[2654],{"type":24,"value":2649},{"type":19,"tag":20,"props":2656,"children":2657},{},[2658,2660,2666,2668,2674,2676,2682],{"type":24,"value":2659},"We include the status code and response body in the error because ",{"type":19,"tag":2179,"props":2661,"children":2663},{"className":2662},[],[2664],{"type":24,"value":2665},"statusText",{"type":24,"value":2667}," is often empty. A ",{"type":19,"tag":2179,"props":2669,"children":2671},{"className":2670},[],[2672],{"type":24,"value":2673},"403",{"type":24,"value":2675}," usually points to a missing token scope or insufficient plan or file access, and a ",{"type":19,"tag":2179,"props":2677,"children":2679},{"className":2678},[],[2680],{"type":24,"value":2681},"429",{"type":24,"value":2683}," means you're being rate limited.",{"type":19,"tag":20,"props":2685,"children":2686},{},[2687],{"type":24,"value":2688},"We only need two parts of the response:",{"type":19,"tag":66,"props":2690,"children":2691},{},[2692,2703],{"type":19,"tag":70,"props":2693,"children":2694},{},[2695,2701],{"type":19,"tag":2179,"props":2696,"children":2698},{"className":2697},[],[2699],{"type":24,"value":2700},"variableCollections",{"type":24,"value":2702},", which describes how variables are organised.",{"type":19,"tag":70,"props":2704,"children":2705},{},[2706,2712],{"type":19,"tag":2179,"props":2707,"children":2709},{"className":2708},[],[2710],{"type":24,"value":2711},"variables",{"type":24,"value":2713},", which contains the individual variable definitions and values.",{"type":19,"tag":20,"props":2715,"children":2716},{},[2717,2719,2725,2727,2733],{"type":24,"value":2718},"Use the ",{"type":19,"tag":2179,"props":2720,"children":2722},{"className":2721},[],[2723],{"type":24,"value":2724},"/local",{"type":24,"value":2726}," endpoint, because it provides the values for each collection mode. The ",{"type":19,"tag":2179,"props":2728,"children":2730},{"className":2729},[],[2731],{"type":24,"value":2732},"/published",{"type":24,"value":2734}," endpoint serves a different purpose and doesn't provide the same per-mode values.",{"type":19,"tag":59,"props":2736,"children":2738},{"id":2737},"understanding-the-api-response",[2739],{"type":24,"value":2740},"Understanding the API response",{"type":19,"tag":20,"props":2742,"children":2743},{},[2744],{"type":24,"value":2745},"Here are shortened extracts from the two collections in my sample Figma project. I've omitted API metadata that isn't needed for this tutorial, but kept the actual IDs and mode names:",{"type":19,"tag":2460,"props":2747,"children":2752},{"className":2748,"code":2750,"language":2751,"meta":6},[2749],"language-json","{\n  \"VariableCollectionId:1:2\": {\n    \"id\": \"VariableCollectionId:1:2\",\n    \"name\": \"Palette\",\n    \"defaultModeId\": \"1:0\",\n    \"hiddenFromPublishing\": false,\n    \"modes\": [{ \"modeId\": \"1:0\", \"name\": \"Mode 1\" }],\n    \"variableIds\": [\"VariableID:1:4\", \"VariableID:1:3\", \"VariableID:1:5\"]\n  },\n  \"VariableCollectionId:1:6\": {\n    \"id\": \"VariableCollectionId:1:6\",\n    \"name\": \"Modes\",\n    \"defaultModeId\": \"1:1\",\n    \"hiddenFromPublishing\": false,\n    \"modes\": [\n      { \"modeId\": \"1:1\", \"name\": \"Light\" },\n      { \"modeId\": \"1:2\", \"name\": \"Dark\" }\n    ],\n    \"variableIds\": [\n      \"VariableID:1:9\", \"VariableID:1:8\",\n      \"VariableID:1:7\", \"VariableID:3:2\"\n    ]\n  }\n}\n","json",[2753],{"type":19,"tag":2179,"props":2754,"children":2755},{"__ignoreMap":6},[2756],{"type":24,"value":2750},{"type":19,"tag":20,"props":2758,"children":2759},{},[2760],{"type":24,"value":2761},"Each collection has a name, its modes, a default mode and the IDs of its variables. Each mode has an ID that we'll use when processing values.",{"type":19,"tag":20,"props":2763,"children":2764},{},[2765,2767,2773],{"type":24,"value":2766},"In this sample, both collections have ",{"type":19,"tag":2179,"props":2768,"children":2770},{"className":2769},[],[2771],{"type":24,"value":2772},"hiddenFromPublishing: false",{"type":24,"value":2774},", so the generator will export files for both. If you hide a collection in Figma, the generator skips its output but can still use its variables to resolve aliases.",{"type":19,"tag":20,"props":2776,"children":2777},{},[2778,2780,2785,2787,2792],{"type":24,"value":2779},"Now let's look at ",{"type":19,"tag":2179,"props":2781,"children":2783},{"className":2782},[],[2784],{"type":24,"value":2331},{"type":24,"value":2786},", a semantic variable in the ",{"type":19,"tag":2179,"props":2788,"children":2790},{"className":2789},[],[2791],{"type":24,"value":2260},{"type":24,"value":2793}," collection:",{"type":19,"tag":2460,"props":2795,"children":2798},{"className":2796,"code":2797,"language":2751,"meta":6},[2749],"{\n  \"VariableID:1:8\": {\n    \"id\": \"VariableID:1:8\",\n    \"name\": \"Surface/primary\",\n    \"variableCollectionId\": \"VariableCollectionId:1:6\",\n    \"resolvedType\": \"COLOR\",\n    \"valuesByMode\": {\n      \"1:1\": { \"type\": \"VARIABLE_ALIAS\", \"id\": \"VariableID:1:3\" },\n      \"1:2\": { \"type\": \"VARIABLE_ALIAS\", \"id\": \"VariableID:1:4\" }\n    }\n  }\n}\n",[2799],{"type":19,"tag":2179,"props":2800,"children":2801},{"__ignoreMap":6},[2802],{"type":24,"value":2797},{"type":19,"tag":20,"props":2804,"children":2805},{},[2806,2808,2813,2815,2820],{"type":24,"value":2807},"This variable doesn't contain actual colour values. Instead, Light mode references ",{"type":19,"tag":2179,"props":2809,"children":2811},{"className":2810},[],[2812],{"type":24,"value":2305},{"type":24,"value":2814},", while Dark mode references ",{"type":19,"tag":2179,"props":2816,"children":2818},{"className":2817},[],[2819],{"type":24,"value":2297},{"type":24,"value":2821},". Those palette variables hold direct colours:",{"type":19,"tag":2460,"props":2823,"children":2826},{"className":2824,"code":2825,"language":2751,"meta":6},[2749],"{\n  \"VariableID:1:3\": {\n    \"id\": \"VariableID:1:3\",\n    \"name\": \"Neutral/white\",\n    \"variableCollectionId\": \"VariableCollectionId:1:2\",\n    \"resolvedType\": \"COLOR\",\n    \"valuesByMode\": {\n      \"1:0\": { \"r\": 1, \"g\": 1, \"b\": 1, \"a\": 1 }\n    }\n  },\n  \"VariableID:1:4\": {\n    \"id\": \"VariableID:1:4\",\n    \"name\": \"Neutral/dark\",\n    \"variableCollectionId\": \"VariableCollectionId:1:2\",\n    \"resolvedType\": \"COLOR\",\n    \"valuesByMode\": {\n      \"1:0\": { \"r\": 0.26340895891189575, \"g\": 0.26340895891189575, \"b\": 0.26340895891189575, \"a\": 1 }\n    }\n  }\n}\n",[2827],{"type":19,"tag":2179,"props":2828,"children":2829},{"__ignoreMap":6},[2830],{"type":24,"value":2825},{"type":19,"tag":20,"props":2832,"children":2833},{},[2834,2836,2841,2843,2849,2850,2856,2858,2863,2864,2870],{"type":24,"value":2835},"These are concrete colours, but their channels still need to be converted to CSS values. Notice that mode IDs belong to their collections: ",{"type":19,"tag":2179,"props":2837,"children":2839},{"className":2838},[],[2840],{"type":24,"value":2260},{"type":24,"value":2842}," uses ",{"type":19,"tag":2179,"props":2844,"children":2846},{"className":2845},[],[2847],{"type":24,"value":2848},"1:1",{"type":24,"value":2307},{"type":19,"tag":2179,"props":2851,"children":2853},{"className":2852},[],[2854],{"type":24,"value":2855},"1:2",{"type":24,"value":2857},", while ",{"type":19,"tag":2179,"props":2859,"children":2861},{"className":2860},[],[2862],{"type":24,"value":2289},{"type":24,"value":2842},{"type":19,"tag":2179,"props":2865,"children":2867},{"className":2866},[],[2868],{"type":24,"value":2869},"1:0",{"type":24,"value":2871},". We'll handle those differences when resolving aliases.",{"type":19,"tag":59,"props":2873,"children":2875},{"id":2874},"save-the-retrieved-data",[2876],{"type":24,"value":2877},"Save the retrieved data",{"type":19,"tag":20,"props":2879,"children":2880},{},[2881],{"type":24,"value":2882},"Before transforming anything, save the response as JSON:",{"type":19,"tag":2460,"props":2884,"children":2887},{"className":2885,"code":2886,"language":2550,"meta":6},[2548],"// _steps/_write-json.js\nimport { writeFile } from \"../_utils/_files.js\";\nexport function writeInitialJson({ collections, variables }, jsonPath) {\n  writeFile(\n    `${jsonPath}collections.json`,\n    JSON.stringify(collections, null, 2)\n  );\n  writeFile(\n    `${jsonPath}variables.json`,\n    JSON.stringify(variables, null, 2)\n  );\n}\n",[2888],{"type":19,"tag":2179,"props":2889,"children":2890},{"__ignoreMap":6},[2891],{"type":24,"value":2886},{"type":19,"tag":2460,"props":2893,"children":2896},{"className":2894,"code":2895,"language":2550,"meta":6},[2548],"// _utils/_files.js\nimport fs from \"fs\";\nimport path from \"path\";\nexport function writeFile(filePath, contents) {\n  fs.mkdirSync(path.dirname(filePath), { recursive: true });\n  fs.writeFileSync(filePath, contents);\n}\n",[2897],{"type":19,"tag":2179,"props":2898,"children":2899},{"__ignoreMap":6},[2900],{"type":24,"value":2895},{"type":19,"tag":20,"props":2902,"children":2903},{},[2904],{"type":24,"value":2905},"This snapshot lets you debug the generation process without repeatedly calling Figma, and it's still there if a later step fails. These JSON files are intermediate build files and aren't published with the package.",{"type":19,"tag":269,"props":2907,"children":2909},{"id":2908},"_4-transform-figma-variables-into-design-tokens",[2910],{"type":24,"value":2911},"4. Transform Figma variables into design tokens",{"type":19,"tag":20,"props":2913,"children":2914},{},[2915],{"type":24,"value":2916},"This is the core of our application. Figma gives us structured design data, but our applications need usable CSS values. We'll convert variable names, resolve aliases, match modes and generate two types of output: SCSS mixins containing CSS custom properties, and TypeScript files containing token metadata for documentation.",{"type":19,"tag":59,"props":2918,"children":2920},{"id":2919},"convert-figma-names-into-css-names",[2921],{"type":24,"value":2922},"Convert Figma names into CSS names",{"type":19,"tag":20,"props":2924,"children":2925},{},[2926],{"type":24,"value":2927},"Figma variable names can contain slashes, spaces and other characters, so we need a consistent way to turn them into CSS-safe names:",{"type":19,"tag":2460,"props":2929,"children":2932},{"className":2930,"code":2931,"language":2550,"meta":6},[2548],"// _utils/_names.js\nexport function buildName(value) {\n  if (!value) return;\n  return String(value)\n    .toLowerCase()\n    .replace(/[^a-z0-9]+/g, \"-\")\n    .replace(/^-+|-+$/g, \"\");\n}\n",[2933],{"type":19,"tag":2179,"props":2934,"children":2935},{"__ignoreMap":6},[2936],{"type":24,"value":2931},{"type":19,"tag":2938,"props":2939,"children":2940},"table",{},[2941,2960],{"type":19,"tag":2942,"props":2943,"children":2944},"thead",{},[2945],{"type":19,"tag":2946,"props":2947,"children":2948},"tr",{},[2949,2955],{"type":19,"tag":2950,"props":2951,"children":2952},"th",{},[2953],{"type":24,"value":2954},"Figma name",{"type":19,"tag":2950,"props":2956,"children":2957},{},[2958],{"type":24,"value":2959},"CSS property",{"type":19,"tag":2961,"props":2962,"children":2963},"tbody",{},[2964,2984,3004],{"type":19,"tag":2946,"props":2965,"children":2966},{},[2967,2976],{"type":19,"tag":2968,"props":2969,"children":2970},"td",{},[2971],{"type":19,"tag":2179,"props":2972,"children":2974},{"className":2973},[],[2975],{"type":24,"value":2338},{"type":19,"tag":2968,"props":2977,"children":2978},{},[2979],{"type":19,"tag":2179,"props":2980,"children":2982},{"className":2981},[],[2983],{"type":24,"value":2437},{"type":19,"tag":2946,"props":2985,"children":2986},{},[2987,2995],{"type":19,"tag":2968,"props":2988,"children":2989},{},[2990],{"type":19,"tag":2179,"props":2991,"children":2993},{"className":2992},[],[2994],{"type":24,"value":2345},{"type":19,"tag":2968,"props":2996,"children":2997},{},[2998],{"type":19,"tag":2179,"props":2999,"children":3001},{"className":3000},[],[3002],{"type":24,"value":3003},"--border-default",{"type":19,"tag":2946,"props":3005,"children":3006},{},[3007,3016],{"type":19,"tag":2968,"props":3008,"children":3009},{},[3010],{"type":19,"tag":2179,"props":3011,"children":3013},{"className":3012},[],[3014],{"type":24,"value":3015},"Surface/secondary",{"type":19,"tag":2968,"props":3017,"children":3018},{},[3019],{"type":19,"tag":2179,"props":3020,"children":3022},{"className":3021},[],[3023],{"type":24,"value":3024},"--surface-secondary",{"type":19,"tag":20,"props":3026,"children":3027},{},[3028,3030,3036],{"type":24,"value":3029},"The helper returns the lowercase, hyphenated name, and we add the ",{"type":19,"tag":2179,"props":3031,"children":3033},{"className":3032},[],[3034],{"type":24,"value":3035},"--",{"type":24,"value":3037}," prefix when we write the declaration. We also use it for collection filenames and mode suffixes.",{"type":19,"tag":20,"props":3039,"children":3040},{},[3041,3043,3049,3050,3055],{"type":24,"value":3042},"Because the helper lowercases everything, two different Figma names such as ",{"type":19,"tag":2179,"props":3044,"children":3046},{"className":3045},[],[3047],{"type":24,"value":3048},"Text/Primary",{"type":24,"value":2307},{"type":19,"tag":2179,"props":3051,"children":3053},{"className":3052},[],[3054],{"type":24,"value":2338},{"type":24,"value":3056}," would produce the same property. We'll check for that when we build the token sets.",{"type":19,"tag":20,"props":3058,"children":3059},{},[3060,3062,3068,3070,3076],{"type":24,"value":3061},"If your team already maintains a web code syntax on each variable in Figma, you can read ",{"type":19,"tag":2179,"props":3063,"children":3065},{"className":3064},[],[3066],{"type":24,"value":3067},"variable.codeSyntax.WEB",{"type":24,"value":3069}," instead of generating names. You'll just need to parse it if it contains ",{"type":19,"tag":2179,"props":3071,"children":3073},{"className":3072},[],[3074],{"type":24,"value":3075},"var(...)",{"type":24,"value":125},{"type":19,"tag":59,"props":3078,"children":3080},{"id":3079},"resolve-variable-aliases",[3081],{"type":24,"value":3082},"Resolve variable aliases",{"type":19,"tag":20,"props":3084,"children":3085},{},[3086,3088,3093,3095,3100,3102,3107,3109,3114,3115,3120,3122,3127],{"type":24,"value":3087},"Remember ",{"type":19,"tag":2179,"props":3089,"children":3091},{"className":3090},[],[3092],{"type":24,"value":2331},{"type":24,"value":3094},"? Its values are references to other variables, not colours. In Light mode (",{"type":19,"tag":2179,"props":3096,"children":3098},{"className":3097},[],[3099],{"type":24,"value":2848},{"type":24,"value":3101},"), it points to ",{"type":19,"tag":2179,"props":3103,"children":3105},{"className":3104},[],[3106],{"type":24,"value":2305},{"type":24,"value":3108},"; in Dark mode (",{"type":19,"tag":2179,"props":3110,"children":3112},{"className":3111},[],[3113],{"type":24,"value":2855},{"type":24,"value":3101},{"type":19,"tag":2179,"props":3116,"children":3118},{"className":3117},[],[3119],{"type":24,"value":2297},{"type":24,"value":3121},". Both palette variables belong to a collection with just one mode (",{"type":19,"tag":2179,"props":3123,"children":3125},{"className":3124},[],[3126],{"type":24,"value":2869},{"type":24,"value":3128},"). When an alias crosses collections, we have to select the right mode in the target collection.",{"type":19,"tag":20,"props":3130,"children":3131},{},[3132],{"type":24,"value":3133},"The resolver below tries these options in order:",{"type":19,"tag":1809,"props":3135,"children":3136},{},[3137,3142,3147],{"type":19,"tag":70,"props":3138,"children":3139},{},[3140],{"type":24,"value":3141},"The same mode ID, which works for aliases within a collection.",{"type":19,"tag":70,"props":3143,"children":3144},{},[3145],{"type":24,"value":3146},"A mode with the same name, such as Light to Light.",{"type":19,"tag":70,"props":3148,"children":3149},{},[3150,3152,3158],{"type":24,"value":3151},"The target collection's ",{"type":19,"tag":2179,"props":3153,"children":3155},{"className":3154},[],[3156],{"type":24,"value":3157},"defaultModeId",{"type":24,"value":3159},", which suits single-mode collections like our palette.",{"type":19,"tag":2460,"props":3161,"children":3164},{"className":3162,"code":3163,"language":2550,"meta":6},[2548],"// _steps/_alias-resolver.js\nexport class AliasResolver {\n  constructor(variables, collections) {\n    // Include every variable, even those in hidden collections\n    this.variables = new Map(\n      Object.values(variables).map(v => [v.id, v])\n    );\n    this.collections = collections;\n  }\n\n  resolve(variable, modeId) {\n    const collection = this.collections[variable.variableCollectionId];\n    const modeName = collection.modes.find(\n      m => m.modeId === modeId\n    )?.name;\n    return this.#follow(\n      variable.valuesByMode[modeId],\n      modeId,\n      modeName,\n      new Set([variable.id])\n    );\n  }\n\n  #follow(value, modeId, modeName, seen) {\n    if (value?.type !== \"VARIABLE_ALIAS\") return value;\n    if (seen.has(value.id)) {\n      throw new Error(`Circular alias: ${value.id}`);\n    }\n    seen.add(value.id);\n    const target = this.variables.get(value.id);\n    if (!target) {\n      throw new Error(`Unresolved alias: ${value.id}`);\n    }\n    const targetModeId = this.#matchMode(target, modeId, modeName);\n    return this.#follow(\n      target.valuesByMode[targetModeId],\n      targetModeId,\n      modeName,\n      seen\n    );\n  }\n\n  #matchMode(variable, modeId, modeName) {\n    if (modeId in variable.valuesByMode) return modeId;\n    const collection = this.collections[variable.variableCollectionId];\n    const sameName = collection.modes.find(m => m.name === modeName);\n    return sameName?.modeId ?? collection.defaultModeId;\n  }\n}\n",[3165],{"type":19,"tag":2179,"props":3166,"children":3167},{"__ignoreMap":6},[3168],{"type":24,"value":3163},{"type":19,"tag":20,"props":3170,"children":3171},{},[3172,3174,3179,3181,3186,3188,3193,3195,3200,3202,3207],{"type":24,"value":3173},"In our sample, the resolver follows ",{"type":19,"tag":2179,"props":3175,"children":3177},{"className":3176},[],[3178],{"type":24,"value":2331},{"type":24,"value":3180}," in Light mode (",{"type":19,"tag":2179,"props":3182,"children":3184},{"className":3183},[],[3185],{"type":24,"value":2848},{"type":24,"value":3187},") to ",{"type":19,"tag":2179,"props":3189,"children":3191},{"className":3190},[],[3192],{"type":24,"value":2305},{"type":24,"value":3194},", then uses the palette collection’s default mode (",{"type":19,"tag":2179,"props":3196,"children":3198},{"className":3197},[],[3199],{"type":24,"value":2869},{"type":24,"value":3201},") to obtain the actual colour. Dark mode follows the same process to ",{"type":19,"tag":2179,"props":3203,"children":3205},{"className":3204},[],[3206],{"type":24,"value":2297},{"type":24,"value":3208},". The resolver also throws on missing or circular alias references, so those errors fail the run rather than producing bad tokens.",{"type":19,"tag":3210,"props":3211,"children":3213},"h4",{"id":3212},"why-flatten-aliases",[3214],{"type":24,"value":3215},"Why flatten aliases?",{"type":19,"tag":20,"props":3217,"children":3218},{},[3219,3221,3226],{"type":24,"value":3220},"We resolve aliases all the way down to concrete values, so the generated Light and Dark mixins are self-contained. The sample also exports the ",{"type":19,"tag":2179,"props":3222,"children":3224},{"className":3223},[],[3225],{"type":24,"value":2289},{"type":24,"value":3227}," collection, but the semantic tokens don't depend on its generated CSS because their aliases have already been flattened.",{"type":19,"tag":20,"props":3229,"children":3230},{},[3231,3233,3239],{"type":24,"value":3232},"An alternative is to preserve the alias relationships in the generated CSS, for example by emitting ",{"type":19,"tag":2179,"props":3234,"children":3236},{"className":3235},[],[3237],{"type":24,"value":3238},"var(--neutral-white)",{"type":24,"value":3240}," instead of its resolved colour. That approach requires applications to include the palette declarations as well as the semantic ones. Choose whichever suits your design system.",{"type":19,"tag":59,"props":3242,"children":3244},{"id":3243},"convert-values-into-css",[3245],{"type":24,"value":3246},"Convert values into CSS",{"type":19,"tag":20,"props":3248,"children":3249},{},[3250,3252,3258,3259,3265,3266,3272,3274,3280],{"type":24,"value":3251},"Once aliases are resolved, we convert the underlying values into CSS. Our implementation handles three variable types: ",{"type":19,"tag":2179,"props":3253,"children":3255},{"className":3254},[],[3256],{"type":24,"value":3257},"COLOR",{"type":24,"value":2299},{"type":19,"tag":2179,"props":3260,"children":3262},{"className":3261},[],[3263],{"type":24,"value":3264},"FLOAT",{"type":24,"value":2307},{"type":19,"tag":2179,"props":3267,"children":3269},{"className":3268},[],[3270],{"type":24,"value":3271},"STRING",{"type":24,"value":3273},". Any other type, such as ",{"type":19,"tag":2179,"props":3275,"children":3277},{"className":3276},[],[3278],{"type":24,"value":3279},"BOOLEAN",{"type":24,"value":3281},", is skipped with a warning so it never disappears silently.",{"type":19,"tag":2460,"props":3283,"children":3286},{"className":3284,"code":3285,"language":2550,"meta":6},[2548],"// _utils/_values.js\nexport function buildToken(type, value) {\n  if (value === undefined || value === null || value === \"\") return;\n\n  switch (type) {\n    case \"COLOR\":\n      return buildRgba(value);\n    case \"FLOAT\":\n      return buildSizeUnit(value);\n    case \"STRING\":\n      return String(value);\n    default:\n      console.warn(`Skipping unsupported variable type: ${type}`);\n  }\n}\n\nfunction buildRgba({ r, g, b, a }) {\n  const alpha = Math.round((a + Number.EPSILON) * 100) / 100;\n  return `rgba(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(b * 255)}, ${alpha})`;\n}\n\nfunction buildSizeUnit(value) {\n  return `${value}px`;\n}\n",[3287],{"type":19,"tag":2179,"props":3288,"children":3289},{"__ignoreMap":6},[3290],{"type":24,"value":3285},{"type":19,"tag":20,"props":3292,"children":3293},{},[3294,3299,3301,3307,3309,3315],{"type":19,"tag":37,"props":3295,"children":3296},{},[3297],{"type":24,"value":3298},"Colours.",{"type":24,"value":3300}," Figma returns channels as numbers between 0 and 1, so we multiply red, green and blue by 255. Our white ",{"type":19,"tag":2179,"props":3302,"children":3304},{"className":3303},[],[3305],{"type":24,"value":3306},"{ r: 1, g: 1, b: 1, a: 1 }",{"type":24,"value":3308}," becomes ",{"type":19,"tag":2179,"props":3310,"children":3312},{"className":3311},[],[3313],{"type":24,"value":3314},"rgba(255, 255, 255, 1)",{"type":24,"value":125},{"type":19,"tag":20,"props":3317,"children":3318},{},[3319,3324,3326,3331,3333,3339,3340,3346],{"type":19,"tag":37,"props":3320,"children":3321},{},[3322],{"type":24,"value":3323},"Numbers.",{"type":24,"value":3325}," ",{"type":19,"tag":2179,"props":3327,"children":3329},{"className":3328},[],[3330],{"type":24,"value":3264},{"type":24,"value":3332}," values become pixel values, so ",{"type":19,"tag":2179,"props":3334,"children":3336},{"className":3335},[],[3337],{"type":24,"value":3338},"16",{"type":24,"value":3308},{"type":19,"tag":2179,"props":3341,"children":3343},{"className":3342},[],[3344],{"type":24,"value":3345},"16px",{"type":24,"value":3347},". That suits spacing, but not every number should have a unit. If you use numeric variables for opacity, line height or other unitless properties, extend this converter.",{"type":19,"tag":20,"props":3349,"children":3350},{},[3351,3356],{"type":19,"tag":37,"props":3352,"children":3353},{},[3354],{"type":24,"value":3355},"Strings.",{"type":24,"value":3357}," Strings are returned as they are, which works when the string is already a valid CSS value. Values that need specific syntax or quoting need extra formatting.",{"type":19,"tag":20,"props":3359,"children":3360},{},[3361],{"type":24,"value":3362},"Each variable type has its own converter, so the application is easy to extend.",{"type":19,"tag":59,"props":3364,"children":3366},{"id":3365},"build-the-token-sets",[3367],{"type":24,"value":3368},"Build the token sets",{"type":19,"tag":20,"props":3370,"children":3371},{},[3372,3374,3380],{"type":24,"value":3373},"Now we combine everything. For each collection, we create one token set per mode, or a single set if the collection has only one mode. The generator skips collections marked ",{"type":19,"tag":2179,"props":3375,"children":3377},{"className":3376},[],[3378],{"type":24,"value":3379},"hiddenFromPublishing",{"type":24,"value":3381},"; in our sample, both collections are included.",{"type":19,"tag":20,"props":3383,"children":3384},{},[3385,3387,3393],{"type":24,"value":3386},"Each variable's collection is available as ",{"type":19,"tag":2179,"props":3388,"children":3390},{"className":3389},[],[3391],{"type":24,"value":3392},"variable.variableCollectionId",{"type":24,"value":3394},", and the loop already knows the collection and mode it's working on, so there's no need to search for the right mode.",{"type":19,"tag":2460,"props":3396,"children":3399},{"className":3397,"code":3398,"language":2550,"meta":6},[2548],"// _steps/_build-token-sets.js\nimport { AliasResolver } from \"./_alias-resolver.js\";\nimport { buildName } from \"../_utils/_names.js\";\nimport { buildToken } from \"../_utils/_values.js\";\n\nexport function buildTokenSets({ collections, variables }) {\n  const resolver = new AliasResolver(variables, collections);\n  const tokenSets = new Map();\n  for (const collection of Object.values(collections)) {\n    if (collection.hiddenFromPublishing) continue;\n    const hasMultipleModes = collection.modes.length > 1;\n    for (const mode of collection.modes) {\n      const collectionName = buildName(collection.name);\n      const key = hasMultipleModes\n        ? `${collectionName}--${buildName(mode.name)}`\n        : collectionName;\n      const tokens = new Map();\n      for (const id of collection.variableIds) {\n        const variable = variables[id];\n        const resolved = resolver.resolve(variable, mode.modeId);\n        const value = buildToken(variable.resolvedType, resolved);\n        if (value === undefined) continue;\n        const name = `--${buildName(variable.name)}`;\n        if (tokens.has(name)) {\n          throw new Error(\n            `Name collision in \"${collection.name}\": ${name}`\n          );\n        }\n        tokens.set(name, value);\n      }\n      tokenSets.set(key, {\n        title: hasMultipleModes ? mode.name : collection.name,\n        tokens: sortTokens(tokens),\n      });\n    }\n  }\n  return tokenSets;\n}\n\nfunction sortTokens(tokens) {\n  const entries = [...tokens];\n  const allPixels = entries.every(([, value]) =>\n    /^-?\\d+(\\.\\d+)?px$/.test(value)\n  );\n  return entries.sort(([nameA, valueA], [nameB, valueB]) =>\n    allPixels\n      ? parseFloat(valueA) - parseFloat(valueB)\n      : nameA.localeCompare(nameB)\n  );\n}\n",[3400],{"type":19,"tag":2179,"props":3401,"children":3402},{"__ignoreMap":6},[3403],{"type":24,"value":3398},{"type":19,"tag":20,"props":3405,"children":3406},{},[3407],{"type":24,"value":3408},"A few things are worth noting:",{"type":19,"tag":66,"props":3410,"children":3411},{},[3412,3454,3487],{"type":19,"tag":70,"props":3413,"children":3414},{},[3415,3417,3422,3424,3430,3431,3437,3439,3445,3447,3453],{"type":24,"value":3416},"The key for each set doubles as the filename and mixin name. A collection called ",{"type":19,"tag":2179,"props":3418,"children":3420},{"className":3419},[],[3421],{"type":24,"value":2260},{"type":24,"value":3423}," with Light and Dark modes produces ",{"type":19,"tag":2179,"props":3425,"children":3427},{"className":3426},[],[3428],{"type":24,"value":3429},"modes--light",{"type":24,"value":2307},{"type":19,"tag":2179,"props":3432,"children":3434},{"className":3433},[],[3435],{"type":24,"value":3436},"modes--dark",{"type":24,"value":3438},", while a single-mode collection called ",{"type":19,"tag":2179,"props":3440,"children":3442},{"className":3441},[],[3443],{"type":24,"value":3444},"Spacing",{"type":24,"value":3446}," produces ",{"type":19,"tag":2179,"props":3448,"children":3450},{"className":3449},[],[3451],{"type":24,"value":3452},"spacing",{"type":24,"value":125},{"type":19,"tag":70,"props":3455,"children":3456},{},[3457,3459,3465,3466,3472,3473,3479,3480,3485],{"type":24,"value":3458},"Tokens are sorted alphabetically to keep the output predictable and easy to review. When every value in a set is a pixel value, they're sorted numerically instead, so ",{"type":19,"tag":2179,"props":3460,"children":3462},{"className":3461},[],[3463],{"type":24,"value":3464},"4px",{"type":24,"value":2299},{"type":19,"tag":2179,"props":3467,"children":3469},{"className":3468},[],[3470],{"type":24,"value":3471},"8px",{"type":24,"value":2299},{"type":19,"tag":2179,"props":3474,"children":3476},{"className":3475},[],[3477],{"type":24,"value":3478},"12px",{"type":24,"value":2307},{"type":19,"tag":2179,"props":3481,"children":3483},{"className":3482},[],[3484],{"type":24,"value":3345},{"type":24,"value":3486}," read in order.",{"type":19,"tag":70,"props":3488,"children":3489},{},[3490],{"type":24,"value":3491},"The name collision check throws an error rather than letting one token silently overwrite another.",{"type":19,"tag":59,"props":3493,"children":3495},{"id":3494},"write-the-files",[3496],{"type":24,"value":3497},"Write the files",{"type":19,"tag":20,"props":3499,"children":3500},{},[3501],{"type":24,"value":3502},"Finally, we render each token set as an SCSS mixin and a TypeScript file:",{"type":19,"tag":2460,"props":3504,"children":3507},{"className":3505,"code":3506,"language":2550,"meta":6},[2548],"// _steps/_write-token-files.js\nimport fs from \"fs\";\nimport { writeFile } from \"../_utils/_files.js\";\n\nexport function writeTokenFiles(tokenSets, paths) {\n  // Remove stale files from renamed or deleted collections\n  fs.rmSync(paths.SCSS, { recursive: true, force: true });\n  fs.rmSync(paths.DOCS, { recursive: true, force: true });\n  for (const [key, { title, tokens }] of tokenSets) {\n    const declarations = tokens\n      .map(([name, value]) => `  ${name}: ${value};`)\n      .join(\"\\n\");\n    writeFile(\n      `${paths.SCSS}collection-${key}--css-vars.scss`,\n      `@mixin ${key}--css-vars {\\n${declarations}\\n}\\n`\n    );\n    const variables = tokens.map(([name, value]) => ({ name, value }));\n    writeFile(\n      `${paths.DOCS}${key}.ts`,\n      `export default [{\\n  title: ${JSON.stringify(title)},\\n  variables: ${JSON.stringify(variables, null, 2)}\\n}];\\n`\n    );\n  }\n}\n",[3508],{"type":19,"tag":2179,"props":3509,"children":3510},{"__ignoreMap":6},[3511],{"type":24,"value":3506},{"type":19,"tag":20,"props":3513,"children":3514},{},[3515],{"type":24,"value":3516},"Each token set is rendered into a complete file rather than assembled through multiple append operations. This keeps the generation process straightforward and makes the resulting files easier to inspect and review.",{"type":19,"tag":20,"props":3518,"children":3519},{},[3520,3522,3528,3529,3535,3536,3542],{"type":24,"value":3521},"For our sample, the generator produces three SCSS files: ",{"type":19,"tag":2179,"props":3523,"children":3525},{"className":3524},[],[3526],{"type":24,"value":3527},"collection-palette--css-vars.scss",{"type":24,"value":2299},{"type":19,"tag":2179,"props":3530,"children":3532},{"className":3531},[],[3533],{"type":24,"value":3534},"collection-modes--light--css-vars.scss",{"type":24,"value":2307},{"type":19,"tag":2179,"props":3537,"children":3539},{"className":3538},[],[3540],{"type":24,"value":3541},"collection-modes--dark--css-vars.scss",{"type":24,"value":3543},". It also creates a corresponding TypeScript documentation file for each token set.",{"type":19,"tag":59,"props":3545,"children":3547},{"id":3546},"the-generated-scss",[3548],{"type":24,"value":3549},"The generated SCSS",{"type":19,"tag":20,"props":3551,"children":3552},{},[3553],{"type":24,"value":3554},"Here's the Light mode file generated from the sample variables:",{"type":19,"tag":2460,"props":3556,"children":3561},{"className":3557,"code":3559,"language":3560,"meta":6},[3558],"language-scss","@mixin modes--light--css-vars {\n  --border-default: rgba(201, 201, 201, 1);\n  --surface-primary: rgba(255, 255, 255, 1);\n  --surface-secondary: rgba(67, 67, 67, 1);\n  --text-primary: rgba(67, 67, 67, 1);\n}\n","scss",[3562],{"type":19,"tag":2179,"props":3563,"children":3564},{"__ignoreMap":6},[3565],{"type":24,"value":3559},{"type":19,"tag":20,"props":3567,"children":3568},{},[3569],{"type":24,"value":3570},"And the Dark mode file:",{"type":19,"tag":2460,"props":3572,"children":3575},{"className":3573,"code":3574,"language":3560,"meta":6},[3558],"@mixin modes--dark--css-vars {\n  --border-default: rgba(201, 201, 201, 1);\n  --surface-primary: rgba(67, 67, 67, 1);\n  --surface-secondary: rgba(255, 255, 255, 1);\n  --text-primary: rgba(255, 255, 255, 1);\n}\n",[3576],{"type":19,"tag":2179,"props":3577,"children":3578},{"__ignoreMap":6},[3579],{"type":24,"value":3574},{"type":19,"tag":20,"props":3581,"children":3582},{},[3583,3585,3590,3591,3596,3597,3602,3604,3609,3611,3616],{"type":24,"value":3584},"The property names are identical in both modes, while the values can differ. Here, ",{"type":19,"tag":2179,"props":3586,"children":3588},{"className":3587},[],[3589],{"type":24,"value":2331},{"type":24,"value":2299},{"type":19,"tag":2179,"props":3592,"children":3594},{"className":3593},[],[3595],{"type":24,"value":3015},{"type":24,"value":2307},{"type":19,"tag":2179,"props":3598,"children":3600},{"className":3599},[],[3601],{"type":24,"value":2338},{"type":24,"value":3603}," change between themes, but ",{"type":19,"tag":2179,"props":3605,"children":3607},{"className":3606},[],[3608],{"type":24,"value":2345},{"type":24,"value":3610}," remains the same because both modes reference ",{"type":19,"tag":2179,"props":3612,"children":3614},{"className":3613},[],[3615],{"type":24,"value":2313},{"type":24,"value":3617},". UI components can use the same custom properties regardless of the active theme.",{"type":19,"tag":20,"props":3619,"children":3620},{},[3621],{"type":24,"value":3622},"The generator also creates a single-mode palette mixin. Our component examples use the semantic mixins, so they don't need to include the palette mixin separately.",{"type":19,"tag":59,"props":3624,"children":3626},{"id":3625},"the-generated-typescript",[3627],{"type":24,"value":3628},"The generated TypeScript",{"type":19,"tag":20,"props":3630,"children":3631},{},[3632],{"type":24,"value":3633},"The TypeScript files aren't needed for styling. They provide a structured list of tokens and values that documentation tools can consume, so you get two outputs from the same Figma data without maintaining them separately:",{"type":19,"tag":2460,"props":3635,"children":3640},{"className":3636,"code":3638,"language":3639,"meta":6},[3637],"language-ts","export default [{\n  title: \"Light\",\n  variables: [\n    { name: \"--border-default\", value: \"rgba(201, 201, 201, 1)\" },\n    { name: \"--surface-primary\", value: \"rgba(255, 255, 255, 1)\" },\n    { name: \"--surface-secondary\", value: \"rgba(67, 67, 67, 1)\" },\n    { name: \"--text-primary\", value: \"rgba(67, 67, 67, 1)\" }\n  ]\n}];\n","ts",[3641],{"type":19,"tag":2179,"props":3642,"children":3643},{"__ignoreMap":6},[3644],{"type":24,"value":3638},{"type":19,"tag":269,"props":3646,"children":3648},{"id":3647},"_5-package-and-distribute-the-design-tokens",[3649],{"type":24,"value":3650},"5. Package and distribute the design tokens",{"type":19,"tag":20,"props":3652,"children":3653},{},[3654],{"type":24,"value":3655},"To make the tokens available to multiple applications without copying files between codebases, publish them as an npm package.",{"type":19,"tag":59,"props":3657,"children":3659},{"id":3658},"configure-packagejson",[3660],{"type":24,"value":3661},"Configure package.json",{"type":19,"tag":2460,"props":3663,"children":3666},{"className":3664,"code":3665,"language":2751,"meta":6},[2749],"{\n  \"name\": \"@your-scope/design-tokens\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"fetch:design-tokens\": \"node ./index.js\"\n  },\n  \"files\": [\n    \"./compiled/design-tokens/\",\n    \"./compiled/helpers/doc-helpers/\"\n  ]\n}\n",[3667],{"type":19,"tag":2179,"props":3668,"children":3669},{"__ignoreMap":6},[3670],{"type":24,"value":3665},{"type":19,"tag":20,"props":3672,"children":3673},{},[3674,3676,3682],{"type":24,"value":3675},"The ",{"type":19,"tag":2179,"props":3677,"children":3679},{"className":3678},[],[3680],{"type":24,"value":3681},"files",{"type":24,"value":3683}," array determines which directories are included in the published package: the generated SCSS files and the TypeScript documentation helpers. The intermediate JSON files are left out because consumers don't need them.",{"type":19,"tag":59,"props":3685,"children":3687},{"id":3686},"generate-and-verify-the-package",[3688],{"type":24,"value":3689},"Generate and verify the package",{"type":19,"tag":20,"props":3691,"children":3692},{},[3693],{"type":24,"value":3694},"Run the token generation process:",{"type":19,"tag":2460,"props":3696,"children":3699},{"className":3697,"code":3698,"language":2465,"meta":6},[2463],"npm run fetch:design-tokens\n",[3700],{"type":19,"tag":2179,"props":3701,"children":3702},{"__ignoreMap":6},[3703],{"type":24,"value":3698},{"type":19,"tag":20,"props":3705,"children":3706},{},[3707],{"type":24,"value":3708},"Then check what would be included in the published package:",{"type":19,"tag":2460,"props":3710,"children":3713},{"className":3711,"code":3712,"language":2465,"meta":6},[2463],"npm pack --dry-run\n",[3714],{"type":19,"tag":2179,"props":3715,"children":3716},{"__ignoreMap":6},[3717],{"type":24,"value":3712},{"type":19,"tag":20,"props":3719,"children":3720},{},[3721],{"type":24,"value":3722},"This catches missing files and unexpected contents before you publish.",{"type":19,"tag":20,"props":3724,"children":3725},{},[3726,3728,3734],{"type":24,"value":3727},"Once you've verified the package contents, it's ready to publish to your chosen npm registry. For a public scoped package, you can use ",{"type":19,"tag":2179,"props":3729,"children":3731},{"className":3730},[],[3732],{"type":24,"value":3733},"npm publish --access public",{"type":24,"value":3735},", provided you've configured the package name and npm authentication. For private registries, follow your organisation's publishing process.",{"type":19,"tag":269,"props":3737,"children":3739},{"id":3738},"_6-use-the-design-tokens-in-a-front-end-application",[3740],{"type":24,"value":3741},"6. Use the design tokens in a front-end application",{"type":19,"tag":20,"props":3743,"children":3744},{},[3745,3747,3753],{"type":24,"value":3746},"Once the package is published, install it in your front-end project using ",{"type":19,"tag":2179,"props":3748,"children":3750},{"className":3749},[],[3751],{"type":24,"value":3752},"npm install @your-scope/design-tokens",{"type":24,"value":125},{"type":19,"tag":20,"props":3755,"children":3756},{},[3757],{"type":24,"value":3758},"Then import the SCSS files in your main stylesheet:",{"type":19,"tag":2460,"props":3760,"children":3763},{"className":3761,"code":3762,"language":3560,"meta":6},[3558],"@use \"@your-scope/design-tokens/compiled/design-tokens/scss/collection-modes--light--css-vars.scss\" as *;\n@use \"@your-scope/design-tokens/compiled/design-tokens/scss/collection-modes--dark--css-vars.scss\" as *;\n",[3764],{"type":19,"tag":2179,"props":3765,"children":3766},{"__ignoreMap":6},[3767],{"type":24,"value":3762},{"type":19,"tag":20,"props":3769,"children":3770},{},[3771,3773,3779],{"type":24,"value":3772},"Depending on your bundler, you may need to add ",{"type":19,"tag":2179,"props":3774,"children":3776},{"className":3775},[],[3777],{"type":24,"value":3778},"node_modules",{"type":24,"value":3780}," to Sass's load path for these imports to resolve.",{"type":19,"tag":59,"props":3782,"children":3784},{"id":3783},"apply-light-and-dark-themes",[3785],{"type":24,"value":3786},"Apply light and dark themes",{"type":19,"tag":20,"props":3788,"children":3789},{},[3790],{"type":24,"value":3791},"The generated files contain SCSS mixins, so importing them doesn't output any CSS. We need to include the mixins in the right selectors:",{"type":19,"tag":2460,"props":3793,"children":3796},{"className":3794,"code":3795,"language":3560,"meta":6},[3558],":root {\n  color-scheme: light;\n  @include modes--light--css-vars;\n}\n// Respect the system setting unless the user has chosen light\n@media (prefers-color-scheme: dark) {\n  :root:not([data-theme=\"light\"]) {\n    color-scheme: dark;\n    @include modes--dark--css-vars;\n  }\n}\n// An explicit choice always wins\nhtml[data-theme=\"dark\"] {\n  color-scheme: dark;\n  @include modes--dark--css-vars;\n}\n",[3797],{"type":19,"tag":2179,"props":3798,"children":3799},{"__ignoreMap":6},[3800],{"type":24,"value":3795},{"type":19,"tag":20,"props":3802,"children":3803},{},[3804,3810,3812,3818,3820,3825],{"type":19,"tag":2179,"props":3805,"children":3807},{"className":3806},[],[3808],{"type":24,"value":3809},":root",{"type":24,"value":3811}," sets the default Light values. When the user's system prefers a dark theme, and they haven't explicitly chosen Light, the first dark rule overrides them. The ",{"type":19,"tag":2179,"props":3813,"children":3815},{"className":3814},[],[3816],{"type":24,"value":3817},"data-theme=\"dark\"",{"type":24,"value":3819}," attribute lets an application force dark mode regardless of the system setting, and it works because that selector has higher specificity than ",{"type":19,"tag":2179,"props":3821,"children":3823},{"className":3822},[],[3824],{"type":24,"value":3809},{"type":24,"value":125},{"type":19,"tag":20,"props":3827,"children":3828},{},[3829,3831,3837],{"type":24,"value":3830},"Setting ",{"type":19,"tag":2179,"props":3832,"children":3834},{"className":3833},[],[3835],{"type":24,"value":3836},"color-scheme",{"type":24,"value":3838}," is a small but valuable detail, because it makes native controls and scrollbars follow the theme.",{"type":19,"tag":20,"props":3840,"children":3841},{},[3842,3844,3850,3852,3858],{"type":24,"value":3843},"The application only needs to set the ",{"type":19,"tag":2179,"props":3845,"children":3847},{"className":3846},[],[3848],{"type":24,"value":3849},"data-theme",{"type":24,"value":3851}," attribute on the HTML element. To avoid a flash of the wrong theme, set it in an inline script in the ",{"type":19,"tag":2179,"props":3853,"children":3855},{"className":3854},[],[3856],{"type":24,"value":3857},"\u003Chead>",{"type":24,"value":3859},", before the page renders:",{"type":19,"tag":2460,"props":3861,"children":3866},{"className":3862,"code":3864,"language":3865,"meta":6},[3863],"language-html","\u003Cscript>\n  const saved = localStorage.getItem(\"theme\");\n  if (saved) document.documentElement.dataset.theme = saved;\n\u003C/script>\n","html",[3867],{"type":19,"tag":2179,"props":3868,"children":3869},{"__ignoreMap":6},[3870],{"type":24,"value":3864},{"type":19,"tag":59,"props":3872,"children":3874},{"id":3873},"use-tokens-in-components",[3875],{"type":24,"value":3876},"Use tokens in components",{"type":19,"tag":20,"props":3878,"children":3879},{},[3880],{"type":24,"value":3881},"Components can then reference the custom properties directly:",{"type":19,"tag":2460,"props":3883,"children":3886},{"className":3884,"code":3885,"language":3560,"meta":6},[3558],".card {\n  background-color: var(--surface-primary);\n  color: var(--text-primary);\n  border: 1px solid var(--border-default);\n}\n",[3887],{"type":19,"tag":2179,"props":3888,"children":3889},{"__ignoreMap":6},[3890],{"type":24,"value":3885},{"type":19,"tag":20,"props":3892,"children":3893},{},[3894],{"type":24,"value":3895},"The component doesn't need separate rules for each theme. It uses the same semantic variables every time, and the active theme determines their values.",{"type":19,"tag":20,"props":3897,"children":3898},{},[3899],{"type":24,"value":3900},"That separation is especially useful in a shared component library, where components are consumed by multiple applications. They don't need to know where the values came from or how the theme was selected.",{"type":19,"tag":269,"props":3902,"children":3904},{"id":3903},"_7-keep-your-design-tokens-up-to-date",[3905],{"type":24,"value":3906},"7. Keep your design tokens up to date",{"type":19,"tag":20,"props":3908,"children":3909},{},[3910],{"type":24,"value":3911},"When variables change in Figma, rerun the compilation process to regenerate the token files. Before publishing an updated package, put a few safeguards in place.",{"type":19,"tag":59,"props":3913,"children":3915},{"id":3914},"review-generated-changes",[3916],{"type":24,"value":3917},"Review generated changes",{"type":19,"tag":20,"props":3919,"children":3920},{},[3921],{"type":24,"value":3922},"Changing a colour updates its generated CSS value, but that change can affect many components. Renaming or removing a variable is more disruptive because it can break applications that depend on it.",{"type":19,"tag":20,"props":3924,"children":3925},{},[3926],{"type":24,"value":3927},"The generator already fails on API errors, missing or circular aliases and name collisions, and it warns about unsupported variable types. These checks help catch technical errors, but they can't tell you whether a token's value is visually appropriate. So I recommend committing the generated files and reviewing the changes in a pull request, paying particular attention to removed or renamed custom properties.",{"type":19,"tag":20,"props":3929,"children":3930},{},[3931],{"type":24,"value":3932},"At Domino's, we have hundreds of tokens, so checking the visual impact of every change by hand isn't realistic. We use Chromatic as a visual regression gate for our Shared UI component library. When we update the tokens package in Shared UI, Chromatic compares the rendered component snapshots against their previous versions and highlights differences for review. This helps us catch unexpected visual changes before releasing the updated component library to consuming applications.",{"type":19,"tag":20,"props":3934,"children":3935},{},[3936],{"type":24,"value":3937},"Chromatic's coverage is limited to the components and states represented in our Storybook stories, so it complements reviewing generated files and testing in real applications rather than replacing them.",{"type":19,"tag":59,"props":3939,"children":3941},{"id":3940},"version-your-package",[3942],{"type":24,"value":3943},"Version your package",{"type":19,"tag":20,"props":3945,"children":3946},{},[3947],{"type":24,"value":3948},"Use semantic versioning to communicate the impact of changes. Updates to existing token values may be suitable for patch or minor releases, depending on their impact. Removing or renaming a token is a breaking change. Renaming a collection or mode in Figma can also be breaking, as it changes the generated filenames and mixin names.",{"type":19,"tag":20,"props":3950,"children":3951},{},[3952],{"type":24,"value":3953},"Document each release so consumers know what to expect.",{"type":19,"tag":59,"props":3955,"children":3957},{"id":3956},"consider-automation",[3958],{"type":24,"value":3959},"Consider automation",{"type":19,"tag":20,"props":3961,"children":3962},{},[3963],{"type":24,"value":3964},"The next step is running the process in CI/CD so that generation, checks and publishing follow a repeatable path. A few practical points:",{"type":19,"tag":66,"props":3966,"children":3967},{},[3968,3973,3986],{"type":19,"tag":70,"props":3969,"children":3970},{},[3971],{"type":24,"value":3972},"Store the Figma token as a CI secret. Personal access tokens can expire, so plan how you'll rotate it.",{"type":19,"tag":70,"props":3974,"children":3975},{},[3976,3978,3984],{"type":24,"value":3977},"Figma's ",{"type":19,"tag":2179,"props":3979,"children":3981},{"className":3980},[],[3982],{"type":24,"value":3983},"LIBRARY_PUBLISH",{"type":24,"value":3985}," webhook can notify you when a library is published, potentially triggering token generation. If you automate this, account for the possibility of receiving multiple events for a single publication.",{"type":19,"tag":70,"props":3987,"children":3988},{},[3989],{"type":24,"value":3990},"Decide whether to publish automatically or after an approval step. The review described above is a natural place for one.",{"type":19,"tag":269,"props":3992,"children":3994},{"id":3993},"conclusion",[3995],{"type":24,"value":3996},"Conclusion",{"type":19,"tag":20,"props":3998,"children":3999},{},[4000],{"type":24,"value":4001},"We've built a reusable design tokens package using Figma's Variables API and Node.js. It retrieves variables, organises them by collection and mode, resolves aliases, converts values into CSS custom properties, generates documentation data and prepares the resulting files for distribution through npm.",{"type":19,"tag":20,"props":4003,"children":4004},{},[4005],{"type":24,"value":4006},"When I originally built this package for Domino's, my goal was to remove the inconsistencies between design decisions and the values used in our applications. It has since become a reusable part of our UI development infrastructure, and it continues to evolve with contributions from my team.",{"type":19,"tag":20,"props":4008,"children":4009},{},[4010],{"type":24,"value":4011},"The biggest benefit isn't just avoiding manual copying and pasting. It's having a repeatable way to keep design values and front-end implementations aligned.",{"type":19,"tag":20,"props":4013,"children":4014},{},[4015],{"type":24,"value":4016},"Start with a few variables, get the process working from Figma to CSS, and expand it as your requirements grow.",{"title":6,"searchDepth":209,"depth":209,"links":4018},[4019,4023,4027,4030,4036,4045,4049,4053,4058],{"id":2116,"depth":209,"text":2119,"children":4020},[4021,4022],{"id":2122,"depth":212,"text":2125},{"id":2143,"depth":212,"text":2111},{"id":2220,"depth":209,"text":2223,"children":4024},[4025,4026],{"id":2231,"depth":212,"text":2234},{"id":2390,"depth":212,"text":2393},{"id":2440,"depth":209,"text":2443,"children":4028},[4029],{"id":2493,"depth":212,"text":2496},{"id":2558,"depth":209,"text":2561,"children":4031},[4032,4033,4034,4035],{"id":2564,"depth":212,"text":2567},{"id":2628,"depth":212,"text":2631},{"id":2737,"depth":212,"text":2740},{"id":2874,"depth":212,"text":2877},{"id":2908,"depth":209,"text":2911,"children":4037},[4038,4039,4040,4041,4042,4043,4044],{"id":2919,"depth":212,"text":2922},{"id":3079,"depth":212,"text":3082},{"id":3243,"depth":212,"text":3246},{"id":3365,"depth":212,"text":3368},{"id":3494,"depth":212,"text":3497},{"id":3546,"depth":212,"text":3549},{"id":3625,"depth":212,"text":3628},{"id":3647,"depth":209,"text":3650,"children":4046},[4047,4048],{"id":3658,"depth":212,"text":3661},{"id":3686,"depth":212,"text":3689},{"id":3738,"depth":209,"text":3741,"children":4050},[4051,4052],{"id":3783,"depth":212,"text":3786},{"id":3873,"depth":212,"text":3876},{"id":3903,"depth":209,"text":3906,"children":4054},[4055,4056,4057],{"id":3914,"depth":212,"text":3917},{"id":3940,"depth":212,"text":3943},{"id":3956,"depth":212,"text":3959},{"id":3993,"depth":209,"text":3996},"content:articles:how-to-build-your-own-design-tokens-package-using-figma-variables-api:index.md","articles/how-to-build-your-own-design-tokens-package-using-figma-variables-api/index.md","articles/how-to-build-your-own-design-tokens-package-using-figma-variables-api/index",{"_path":4063,"_dir":221,"_draft":7,"_partial":7,"_locale":6,"title":4064,"description":2051,"keywords":2052,"slug":240,"pagetitle":4065,"longPageTitle":4065,"date":4066,"longDate":4067,"serpDate":4068,"tags":4069,"category":756,"featured":234,"canonicalUrl":2078,"projectCompany":758,"projectLink":13,"projectThumbnail":4070,"projectMedia":4071,"pageClassName":13,"nextProjectSlug":1378,"schemaImage1x1":4073,"schemaImage4x3":4074,"schemaImage16x9":4075,"ctaTitle":13,"ctaSubtitle":13,"ctaButtonText":13,"body":4076,"_type":213,"_id":4684,"_source":215,"_file":4685,"_stem":4686,"_extension":218},"/articles/how-we-utilised-figma-variables-api-for-creating-design-tokens","How We Utilised Figma Variables API for UI Development at Domino's\n","How We Utilised Figma Variables API for Standardised UI Development at Domino's\n","2024-09-18","September 18th, 2024","18 Sep 2024",[232,754,116,230,2058],"/articles/design-tokens/how-we-utilised-figma-variables-api-for-creating-design-tokens--thumbnail.png",[4072],"/articles/design-tokens/how-we-utilised-figma-variables-api-for-creating-design-tokens--page-hero.png","/articles/design-tokens/how-we-utilised-figma-variables-api-for-creating-design-tokens__1x1.png","/articles/design-tokens/how-we-utilised-figma-variables-api-for-creating-design-tokens__4x3.png","/articles/design-tokens/how-we-utilised-figma-variables-api-for-creating-design-tokens__16x9.png",{"type":16,"children":4077,"toc":4673},[4078,4106,4111,4117,4122,4127,4132,4137,4142,4147,4165,4171,4176,4181,4186,4191,4196,4201,4206,4212,4217,4222,4227,4232,4237,4243,4248,4252,4257,4262,4287,4292,4328,4341,4352,4358,4363,4368,4381,4386,4429,4440,4453,4462,4467,4473,4478,4483,4488,4494,4507,4512,4517,4523,4528,4533,4539,4544,4553,4558,4564,4569,4575,4580,4585,4590,4596,4601,4606,4610],{"type":19,"tag":20,"props":4079,"children":4080},{},[4081,4083,4088,4090,4095,4097,4104],{"type":24,"value":4082},"At Domino's, we ",{"type":19,"tag":98,"props":4084,"children":4085},{},[4086],{"type":24,"value":4087},"strive",{"type":24,"value":4089}," for consistency and scalability when building UIs across web and mobile platforms. While we have always aimed for a unified design and development process, maintaining ",{"type":19,"tag":98,"props":4091,"children":4092},{},[4093],{"type":24,"value":4094},"consistency",{"type":24,"value":4096}," in design variable names across projects has always been challenging. With the introduction of ",{"type":19,"tag":2076,"props":4098,"children":4101},{"href":4099,"rel":4100},"https://www.figma.com/developers/api#variables",[2080],[4102],{"type":24,"value":4103},"Figma's Variables API",{"type":24,"value":4105},", we have addressed this issue by automating the fetching of Figma variables directly into our codebase, which enabled us to maintain consistency between design and UI implementation and, as a very nice bonus, support both light and dark modes seamlessly.",{"type":19,"tag":20,"props":4107,"children":4108},{},[4109],{"type":24,"value":4110},"In this post, I will walk you through how we used Figma's API to automatically generate design tokens, improving our workflow by aligning design and development more closely.",{"type":19,"tag":269,"props":4112,"children":4114},{"id":4113},"the-problem-we-had-to-solve",[4115],{"type":24,"value":4116},"The Problem We Had To Solve",{"type":19,"tag":20,"props":4118,"children":4119},{},[4120],{"type":24,"value":4121},"The engineering goals at Domino's are ambitious, and we often partner with other companies to reach them. Which means things are always very dynamic. Developers change, different teams build different parts of the website, email templates, mobile apps and so on.",{"type":19,"tag":20,"props":4123,"children":4124},{},[4125],{"type":24,"value":4126},"When developing UI, devs always ensure that no raw design values (like the HEX values of colours) are used across the code, following the “DRY” (Don't Repeat Yourself) principles to maintain clean code across all projects.",{"type":19,"tag":20,"props":4128,"children":4129},{},[4130],{"type":24,"value":4131},"Developers achieve this by converting reusable design values into variables. Then, those variables can be used anywhere in the code, ensuring consistency in the codebase and produced UI.",{"type":19,"tag":20,"props":4133,"children":4134},{},[4135],{"type":24,"value":4136},"Maintaining consistency between the naming conventions of those variables has been quite a challenge, though.",{"type":19,"tag":20,"props":4138,"children":4139},{},[4140],{"type":24,"value":4141},"For instance, here is an example of one colour which is named differently across different projects:",{"type":19,"tag":2365,"props":4143,"children":4146},{"src":4144,"alt":4145},"/v1726146403/one-colour-many-names_yzruwc.png","Example of a single color variable named differently across multiple projects",[],{"type":19,"tag":20,"props":4148,"children":4149},{},[4150,4152,4157,4159,4163],{"type":24,"value":4151},"As I am sure you can already see, this is quite inefficient. This scenario becomes particularly problematic when scaling up and adding new projects. Adding ",{"type":19,"tag":98,"props":4153,"children":4154},{},[4155],{"type":24,"value":4156},"new",{"type":24,"value":4158}," sets of design variables to ",{"type":19,"tag":98,"props":4160,"children":4161},{},[4162],{"type":24,"value":4156},{"type":24,"value":4164}," projects is neither ideal nor scalable.",{"type":19,"tag":269,"props":4166,"children":4168},{"id":4167},"introducing-design-tokens",[4169],{"type":24,"value":4170},"Introducing Design Tokens",{"type":19,"tag":20,"props":4172,"children":4173},{},[4174],{"type":24,"value":4175},"To address this issue, we decided to add Design Tokens as a Service to Domino's tech stack.",{"type":19,"tag":20,"props":4177,"children":4178},{},[4179],{"type":24,"value":4180},"Design tokens are a centralised set of design values like colours, fonts, and shadows that are common across all projects. These values can be packaged into a single resource and shared across the organisation.",{"type":19,"tag":20,"props":4182,"children":4183},{},[4184],{"type":24,"value":4185},"Essentially, design tokens allow you to go from this setup for multiple projects:",{"type":19,"tag":2365,"props":4187,"children":4190},{"src":4188,"alt":4189},"/v1726145744/projects-setup-before_qnsmhd.png","Before adopting design tokens: multiple inconsistent design setups for colors, fonts, and shadows across various projects.",[],{"type":19,"tag":20,"props":4192,"children":4193},{},[4194],{"type":24,"value":4195},"To this:",{"type":19,"tag":2365,"props":4197,"children":4200},{"src":4198,"alt":4199},"/v1726145808/projects-setup-after_h9nhbs.png","After adopting design tokens: centralized and consistent design system with shared values for colors, fonts, and shadows across all projects.",[],{"type":19,"tag":20,"props":4202,"children":4203},{},[4204],{"type":24,"value":4205},"With design tokens, we can ensure consistency across all projects and simplify the process of maintaining design values. Any updates made in the design tokens package can be instantly reflected in the individual projects, ensuring that design and development stay in sync.",{"type":19,"tag":269,"props":4207,"children":4209},{"id":4208},"leveraging-figmas-variables-api",[4210],{"type":24,"value":4211},"Leveraging Figma's Variables API",{"type":19,"tag":20,"props":4213,"children":4214},{},[4215],{"type":24,"value":4216},"Design tokens can be achieved in a couple of ways. For example, some teams maintain files containing all design tokens in an easy-to-access location, and then these files are used as a single source of truth by everyone - devs and designers.",{"type":19,"tag":20,"props":4218,"children":4219},{},[4220],{"type":24,"value":4221},"This approach is better than maintaining multiple sets of design values. However, it is still very manual - someone must update the files whenever changes are introduced.",{"type":19,"tag":20,"props":4223,"children":4224},{},[4225],{"type":24,"value":4226},"To support scalability, we created an automated process that generates design tokens by pulling variables directly from Figma using the new Variables REST API.",{"type":19,"tag":20,"props":4228,"children":4229},{},[4230],{"type":24,"value":4231},"Figma's Variables API provides direct access to the variables our designers create in Figma files, allowing us to automate the design token generation process.",{"type":19,"tag":20,"props":4233,"children":4234},{},[4235],{"type":24,"value":4236},"Once the design tokens are generated, we publish them as an installable npm package, which we then use across multiple projects, ensuring consistency in the developed UI and naming conventions.",{"type":19,"tag":269,"props":4238,"children":4240},{"id":4239},"how-figmas-variables-simplify-theme-support",[4241],{"type":24,"value":4242},"How Figma's Variables Simplify Theme Support",{"type":19,"tag":20,"props":4244,"children":4245},{},[4246],{"type":24,"value":4247},"One of the most powerful features of Figma variables is their ability to support multiple modes, such as light and dark themes. In Figma, you can define a single variable, such as background-color, and assign it multiple values depending on the mode. For example:",{"type":19,"tag":2365,"props":4249,"children":4251},{"src":4250,"alt":6},"/v1745472332/Screenshot_2025-04-24_at_06.22.56_yxe8pq.png",[],{"type":19,"tag":20,"props":4253,"children":4254},{},[4255],{"type":24,"value":4256},"This view in Figma allows you to manage all variables in one location, ensuring that mode/theme-specific styles are consistent and easy to update.",{"type":19,"tag":20,"props":4258,"children":4259},{},[4260],{"type":24,"value":4261},"A setup like this also simplifies the front-end implementation of themes. When Figma variables are fetched and converted into CSS variables, switching between light and dark modes becomes as simple as toggling between different sets of predefined tokens:",{"type":19,"tag":66,"props":4263,"children":4264},{},[4265,4276],{"type":19,"tag":70,"props":4266,"children":4267},{},[4268,4274],{"type":19,"tag":2179,"props":4269,"children":4271},{"className":4270},[],[4272],{"type":24,"value":4273},"--background-colour: #ffffff",{"type":24,"value":4275}," - for light theme",{"type":19,"tag":70,"props":4277,"children":4278},{},[4279,4285],{"type":19,"tag":2179,"props":4280,"children":4282},{"className":4281},[],[4283],{"type":24,"value":4284},"--background-colour: #000000",{"type":24,"value":4286}," - for dark theme",{"type":19,"tag":20,"props":4288,"children":4289},{},[4290],{"type":24,"value":4291},"Figma's modes magic does not end with colour themes. You can apply similar principles to the sizing units, like container paddings, for example, which are often different for different screen sizes:",{"type":19,"tag":66,"props":4293,"children":4294},{},[4295,4306,4317],{"type":19,"tag":70,"props":4296,"children":4297},{},[4298,4304],{"type":19,"tag":2179,"props":4299,"children":4301},{"className":4300},[],[4302],{"type":24,"value":4303},"--container-padding: 12px",{"type":24,"value":4305}," - for mobiles",{"type":19,"tag":70,"props":4307,"children":4308},{},[4309,4315],{"type":19,"tag":2179,"props":4310,"children":4312},{"className":4311},[],[4313],{"type":24,"value":4314},"--container-padding: 16px",{"type":24,"value":4316}," - for tablets",{"type":19,"tag":70,"props":4318,"children":4319},{},[4320,4326],{"type":19,"tag":2179,"props":4321,"children":4323},{"className":4322},[],[4324],{"type":24,"value":4325},"--container-padding: 24px",{"type":24,"value":4327}," - for desktops",{"type":19,"tag":20,"props":4329,"children":4330},{},[4331,4333,4339],{"type":24,"value":4332},"And instead of writing multiple media queries to apply different padding values to all affected elements, you can switch between CSS variables at the ",{"type":19,"tag":2179,"props":4334,"children":4336},{"className":4335},[],[4337],{"type":24,"value":4338},":root{}",{"type":24,"value":4340}," level:",{"type":19,"tag":2460,"props":4342,"children":4347},{"className":4343,"code":4345,"language":4346,"meta":6},[4344],"language-CSS",":root {\n  @media (max-width: 520px) {\n    --container-padding: 12px;\n  }\n\n  @media (max-width: 768px) {\n    --container-padding: 16px;\n  }\n\n  @media (min-width: 769px) {\n    --container-padding: 24px;\n  }\n}\n\n.container {\n  padding: var(--container-padding);\n}\n","CSS",[4348],{"type":19,"tag":2179,"props":4349,"children":4350},{"__ignoreMap":6},[4351],{"type":24,"value":4345},{"type":19,"tag":269,"props":4353,"children":4355},{"id":4354},"automating-the-fetching-of-design-tokens",[4356],{"type":24,"value":4357},"Automating the Fetching of Design Tokens",{"type":19,"tag":20,"props":4359,"children":4360},{},[4361],{"type":24,"value":4362},"Considering all the benefits this system could provide us with, convincing people to work on adopting the Design Tokens approach was not a difficult sell. All we needed was to actually do the work.",{"type":19,"tag":20,"props":4364,"children":4365},{},[4366],{"type":24,"value":4367},"The approach we took consisted of two parts:",{"type":19,"tag":66,"props":4369,"children":4370},{},[4371,4376],{"type":19,"tag":70,"props":4372,"children":4373},{},[4374],{"type":24,"value":4375},"Part 1 - UX designers had to create variables in Figma.",{"type":19,"tag":70,"props":4377,"children":4378},{},[4379],{"type":24,"value":4380},"Part 2 - The UI team had to find a way to fetch those variables from Figma and convert them to design tokens in the format needed.",{"type":19,"tag":20,"props":4382,"children":4383},{},[4384],{"type":24,"value":4385},"For the UI part, we built a Node.js application. I'm not going to get into specific details of this application here (there will be a follow-up article with code examples), but here's how it works:",{"type":19,"tag":1809,"props":4387,"children":4388},{},[4389,4399,4409,4419],{"type":19,"tag":70,"props":4390,"children":4391},{},[4392,4397],{"type":19,"tag":37,"props":4393,"children":4394},{},[4395],{"type":24,"value":4396},"Authentication and Setup",{"type":24,"value":4398},": First, we set up Figma API access by generating a personal access token and obtaining the ID of the Figma file containing all variables.",{"type":19,"tag":70,"props":4400,"children":4401},{},[4402,4407],{"type":19,"tag":37,"props":4403,"children":4404},{},[4405],{"type":24,"value":4406},"Fetching Data",{"type":24,"value":4408},": Once authenticated, our Node.js script fetches the published variables data from Figma.",{"type":19,"tag":70,"props":4410,"children":4411},{},[4412,4417],{"type":19,"tag":37,"props":4413,"children":4414},{},[4415],{"type":24,"value":4416},"Processing Data",{"type":24,"value":4418},": The data is then processed, and we generate separate files for different token collections (e.g., Core colour tokens and Light/Dark mode tokens).",{"type":19,"tag":70,"props":4420,"children":4421},{},[4422,4427],{"type":19,"tag":37,"props":4423,"children":4424},{},[4425],{"type":24,"value":4426},"Generating CSS Variables",{"type":24,"value":4428},": Finally, we generate design tokens as CSS variables for our web projects and group them into SCSS mixins for easier imports. For example, we might generate tokens like this:",{"type":19,"tag":2460,"props":4430,"children":4435},{"className":4431,"code":4433,"language":4434,"meta":6},[4432],"language-SCSS","/* Tokens for light mode - CSS variables */\n@mixin modes--light--css-vars {\n  --text-primary: rgba(57, 51, 54, 1); \n  --text-secondary: rgba(84, 84, 84, 1); \n  --text-black: rgba(57, 51, 54, 1); \n  --text-brand-blue-default: rgba(0, 100, 145, 1); \n  --text-brand-blue-bold: rgba(0, 100, 145, 1); \n  --text-brand-blue-bolder: rgba(0, 100, 145, 1); \n  --text-white: rgba(255, 255, 255, 1); \n  ...\n}\n\n/* Tokens for dark mode - CSS variables */\n@mixin modes--dark--css-vars {\n  --text-primary: rgba(245, 245, 245, 1); \n  --text-secondary: rgba(245, 245, 245, 1); \n  --text-black: rgba(57, 51, 54, 1); \n  --text-brand-blue-default: rgba(0, 100, 145, 1); \n  --text-brand-blue-bold: rgba(24, 147, 204, 1); \n  --text-brand-blue-bolder: rgba(245, 245, 245, 1); \n  --text-white: rgba(255, 255, 255, 1); \n  ...\n}\n","SCSS",[4436],{"type":19,"tag":2179,"props":4437,"children":4438},{"__ignoreMap":6},[4439],{"type":24,"value":4433},{"type":19,"tag":20,"props":4441,"children":4442},{},[4443,4445,4451],{"type":24,"value":4444},"And add them to the ",{"type":19,"tag":2179,"props":4446,"children":4448},{"className":4447},[],[4449],{"type":24,"value":4450},":root {}",{"type":24,"value":4452}," like this:",{"type":19,"tag":2460,"props":4454,"children":4457},{"className":4455,"code":4456,"language":4434,"meta":6},[4432],"@import \"design-tokens/collection-modes--light--css-vars.scss\";\n@import \"design-tokens/collection-modes--dark--css-vars.scss\";\n\n:root {\n  @include modes--light--css-vars;\n\n  @media (prefers-color-scheme: dark) {\n    @include modes--dark--css-vars;\n  }\n}\n",[4458],{"type":19,"tag":2179,"props":4459,"children":4460},{"__ignoreMap":6},[4461],{"type":24,"value":4456},{"type":19,"tag":20,"props":4463,"children":4464},{},[4465],{"type":24,"value":4466},"This makes the CSS variables accessible across all pages of our application. They can be easily integrated into the front-end code, enabling smooth toggling between light and dark modes based on user preferences.",{"type":19,"tag":269,"props":4468,"children":4470},{"id":4469},"showcase-adding-light-and-dark-themes-to-our-button-component",[4471],{"type":24,"value":4472},"Showcase: Adding Light and Dark Themes To Our Button Component",{"type":19,"tag":20,"props":4474,"children":4475},{},[4476],{"type":24,"value":4477},"To illustrate the impact of our new system, let's look at how it improved our button component.",{"type":19,"tag":20,"props":4479,"children":4480},{},[4481],{"type":24,"value":4482},"Before implementing design tokens, our UI library only supported the light theme, and adding a dark one was going to be a time-consuming process, mainly because of how our variables were named.",{"type":19,"tag":20,"props":4484,"children":4485},{},[4486],{"type":24,"value":4487},"For all the colour variables in our system, we used generic naming conventions which were not specific enough to allow for easy theme switching.",{"type":19,"tag":2365,"props":4489,"children":4493},{"src":4490,"className":4491,"alt":4492},"/v1726677034/button-variables-before_my06jl.png",[2369],"UI library before design tokens: limited to a light theme, with generic color variable names like $base-utility-primary, making theme switching and dark theme integration difficult.",[],{"type":19,"tag":20,"props":4495,"children":4496},{},[4497,4499,4505],{"type":24,"value":4498},"For example, ",{"type":19,"tag":2179,"props":4500,"children":4502},{"className":4501},[],[4503],{"type":24,"value":4504},"$base-utility-primary",{"type":24,"value":4506}," was used in all the components that needed that shade of green colour, and changing the value of this variable would have affected many elements in our UI library.",{"type":19,"tag":20,"props":4508,"children":4509},{},[4510],{"type":24,"value":4511},"This was neither right nor wrong; it was just the way things were done when designs were initially created for our UI components library.",{"type":19,"tag":20,"props":4513,"children":4514},{},[4515],{"type":24,"value":4516},"With Figma variables in place, UX designers are much more specific when defining colour names. Here, you can see variables created specifically for the button component:",{"type":19,"tag":2365,"props":4518,"children":4522},{"src":4519,"className":4520,"alt":4521},"/v1726677064/figma-variables-for-button_mwr8ct.png",[2369],"Figma variables for the button component, showing specific color names defined for light and dark themes to enable easier theme management.",[],{"type":19,"tag":20,"props":4524,"children":4525},{},[4526],{"type":24,"value":4527},"These variable names are much easier to read and understand, and the use intent is very obvious to anyone.",{"type":19,"tag":20,"props":4529,"children":4530},{},[4531],{"type":24,"value":4532},"When we fetch these same variables from Figma into our Design Tokens system, they look like this:",{"type":19,"tag":2365,"props":4534,"children":4538},{"src":4535,"className":4536,"alt":4537},"/v1726677089/design-tokens-for-button_tjeq38.png",[2369],"CSS variables automatically generated from Figma design tokens, streamlining the process of converting design values into code for consistent UI implementation.",[],{"type":19,"tag":20,"props":4540,"children":4541},{},[4542],{"type":24,"value":4543},"As you can see, the variables are grouped into light and dark mode SCSS mixins, which, when imported gloablly, really simplifies the CSS code for the actual buttons:",{"type":19,"tag":2460,"props":4545,"children":4548},{"className":4546,"code":4547,"language":4434,"meta":6},[4432],".button-primary {\n  background-color: var(--button-surface-primary);\n\n  &:hover {\n    background-color: var(--button-surface-primary-hover);\n  }\n\n  &:active {\n    background-color: var(--button-surface-primary-active);\n  }\n}\n",[4549],{"type":19,"tag":2179,"props":4550,"children":4551},{"__ignoreMap":6},[4552],{"type":24,"value":4547},{"type":19,"tag":20,"props":4554,"children":4555},{},[4556],{"type":24,"value":4557},"And this way we can easily support light and dark themes in our UI components:",{"type":19,"tag":2365,"props":4559,"children":4563},{"src":4560,"className":4561,"alt":4562},"/v1726677111/light-and-dark-teme-of-button_fuj0lm.png",[2369],"Button component design tokens in action, showcasing neatly styled buttons that support both light and dark modes for a consistent UI experience.",[],{"type":19,"tag":20,"props":4565,"children":4566},{},[4567],{"type":24,"value":4568},"When the design team updates the button colours in Figma, the changes are reflected in our UI library by just simply running the Node.js script. And once design tokens have been added to the remaining projects, this process will significantly reduce development time and ensure consistency.",{"type":19,"tag":269,"props":4570,"children":4572},{"id":4571},"the-road-ahead-for-design-tokens-at-dominos",[4573],{"type":24,"value":4574},"The Road Ahead for Design Tokens at Domino's",{"type":19,"tag":20,"props":4576,"children":4577},{},[4578],{"type":24,"value":4579},"We have made significant progress in integrating Figma's Variables into our development workflow; however, the project is still in progress.",{"type":19,"tag":20,"props":4581,"children":4582},{},[4583],{"type":24,"value":4584},"Our goal is to fully implement design tokens across all projects, ensuring a unified, scalable approach to UI development. As we continue to refine our implementation, I am excited to see how this approach evolves and how it will shape the future of UI development at Domino's.",{"type":19,"tag":20,"props":4586,"children":4587},{},[4588],{"type":24,"value":4589},"By staying focused on this ongoing work, I am confident our efforts will result in a more cohesive, efficient, and scalable design system for all of Domino's digital experiences.",{"type":19,"tag":269,"props":4591,"children":4593},{"id":4592},"update-august-2026",[4594],{"type":24,"value":4595},"Update, August 2026",{"type":19,"tag":20,"props":4597,"children":4598},{},[4599],{"type":24,"value":4600},"Since this article was first published, the design tokens pipeline has become the standard foundation for theming across Domino's UI estate. Beyond our two shared component libraries – where it now powers light and dark mode support for 150+ components consumed by four Nuxt applications – the same tokens package is also consumed by three further repositories: our static HTML pages generator, Customer flow pages, and an internal tool used by Domino's engineers.",{"type":19,"tag":20,"props":4602,"children":4603},{},[4604],{"type":24,"value":4605},"What started as a fix for inconsistent variable naming has become shared infrastructure across nine repositories and counting – the foundation the rest of our UI platform work has been built on since.",{"type":19,"tag":269,"props":4607,"children":4608},{"id":620},[4609],{"type":24,"value":623},{"type":19,"tag":66,"props":4611,"children":4612},{},[4613,4623,4633,4643,4653,4663],{"type":19,"tag":70,"props":4614,"children":4615},{},[4616,4621],{"type":19,"tag":37,"props":4617,"children":4618},{},[4619],{"type":24,"value":4620},"Design Tokens:",{"type":24,"value":4622}," Centralised design values (like colours, fonts, sizes) that can be shared across projects.",{"type":19,"tag":70,"props":4624,"children":4625},{},[4626,4631],{"type":19,"tag":37,"props":4627,"children":4628},{},[4629],{"type":24,"value":4630},"Figma:",{"type":24,"value":4632}," A collaborative interface design tool.",{"type":19,"tag":70,"props":4634,"children":4635},{},[4636,4641],{"type":19,"tag":37,"props":4637,"children":4638},{},[4639],{"type":24,"value":4640},"Variables API:",{"type":24,"value":4642}," An API provided by Figma that allows access to design variables defined in Figma files.",{"type":19,"tag":70,"props":4644,"children":4645},{},[4646,4651],{"type":19,"tag":37,"props":4647,"children":4648},{},[4649],{"type":24,"value":4650},"CSS Variables:",{"type":24,"value":4652}," Also known as CSS custom properties, these entities contain specific values to be reused throughout a document.",{"type":19,"tag":70,"props":4654,"children":4655},{},[4656,4661],{"type":19,"tag":37,"props":4657,"children":4658},{},[4659],{"type":24,"value":4660},"SCSS:",{"type":24,"value":4662}," A preprocessor scripting language interpreted or compiled into Cascading Style Sheets (CSS).",{"type":19,"tag":70,"props":4664,"children":4665},{},[4666,4671],{"type":19,"tag":37,"props":4667,"children":4668},{},[4669],{"type":24,"value":4670},"Node.js:",{"type":24,"value":4672}," An open-source, cross-platform JavaScript runtime environment.",{"title":6,"searchDepth":209,"depth":209,"links":4674},[4675,4676,4677,4678,4679,4680,4681,4682,4683],{"id":4113,"depth":209,"text":4116},{"id":4167,"depth":209,"text":4170},{"id":4208,"depth":209,"text":4211},{"id":4239,"depth":209,"text":4242},{"id":4354,"depth":209,"text":4357},{"id":4469,"depth":209,"text":4472},{"id":4571,"depth":209,"text":4574},{"id":4592,"depth":209,"text":4595},{"id":620,"depth":209,"text":623},"content:articles:how-we-utilised-figma-variables-api-for-creating-design-tokens:index.md","articles/how-we-utilised-figma-variables-api-for-creating-design-tokens/index.md","articles/how-we-utilised-figma-variables-api-for-creating-design-tokens/index",{"_path":4688,"_dir":221,"_draft":7,"_partial":7,"_locale":6,"title":4689,"description":4690,"keywords":748,"slug":1387,"pagetitle":4689,"longPageTitle":4691,"date":4692,"longDate":4693,"serpDate":4694,"tags":4695,"category":756,"featured":234,"canonicalUrl":4698,"projectCompany":4699,"projectLink":13,"projectThumbnail":4700,"projectMedia":4701,"pageClassName":13,"nextProjectSlug":749,"schemaImage1x1":13,"schemaImage4x3":13,"schemaImage16x9":13,"ctaTitle":13,"ctaSubtitle":13,"ctaButtonText":13,"body":4707,"_type":213,"_id":5129,"_source":215,"_file":5130,"_stem":5131,"_extension":218},"/articles/hult-international-svg-animations","SVG Animations for HULT International","UI/UX case study for SVG Animations for HULT International.","How do you animate 78 SVG shapes in less than 10 days?","2019-12-30","December 30th, 2019","30 Dec 2019",[4696,230,4697],"CSS3 Animations","SVG Animations","https://www.eveatwork.studio/articles/hult-international-svg-animations/","HULT International","/articles/MBA-hero-min.mp4",[4702,4700,4703,4704,4705,4706],"/articles/UNDERGRADUATE-hero-min.mp4","/articles/MASTERS-hero-min.mp4","/articles/EMBA-hero-min.mp4","/articles/EMBA_v2-hero-min.mp4","/articles/ASHRIDGE-hero-min.mp4",{"type":16,"children":4708,"toc":5119},[4709,4715,4727,4770,4781,4830,4856,4861,4867,4878,4884,4926,4932,4984,4990,5003,5009,5070,5082,5088,5106],{"type":19,"tag":269,"props":4710,"children":4712},{"id":4711},"the-client-the-challenge",[4713],{"type":24,"value":4714},"The Client & The Challenge",{"type":19,"tag":20,"props":4716,"children":4717},{},[4718,4720,4725],{"type":24,"value":4719},"HULT International Business School, with branches across North America, Europe, and Asia, approached me during their website redesign. They needed ",{"type":19,"tag":37,"props":4721,"children":4722},{},[4723],{"type":24,"value":4724},"five custom SVG animations",{"type":24,"value":4726}," that would be:",{"type":19,"tag":66,"props":4728,"children":4729},{},[4730,4740,4750,4760],{"type":19,"tag":70,"props":4731,"children":4732},{},[4733,4738],{"type":19,"tag":37,"props":4734,"children":4735},{},[4736],{"type":24,"value":4737},"Lightweight",{"type":24,"value":4739}," – Minimal file size to maintain fast page loads.",{"type":19,"tag":70,"props":4741,"children":4742},{},[4743,4748],{"type":19,"tag":37,"props":4744,"children":4745},{},[4746],{"type":24,"value":4747},"Reusable",{"type":24,"value":4749}," – One animation framework supporting multiple use cases.",{"type":19,"tag":70,"props":4751,"children":4752},{},[4753,4758],{"type":19,"tag":37,"props":4754,"children":4755},{},[4756],{"type":24,"value":4757},"CSS-Only",{"type":24,"value":4759}," – No JavaScript libraries allowed.",{"type":19,"tag":70,"props":4761,"children":4762},{},[4763,4768],{"type":19,"tag":37,"props":4764,"children":4765},{},[4766],{"type":24,"value":4767},"Time-Sensitive",{"type":24,"value":4769}," – Completed within 10 days.",{"type":19,"tag":20,"props":4771,"children":4772},{},[4773,4775,4780],{"type":24,"value":4774},"The animations had to work in ",{"type":19,"tag":37,"props":4776,"children":4777},{},[4778],{"type":24,"value":4779},"two scenarios",{"type":24,"value":1510},{"type":19,"tag":1809,"props":4782,"children":4783},{},[4784,4807],{"type":19,"tag":70,"props":4785,"children":4786},{},[4787,4792,4794,4799,4800,4805],{"type":19,"tag":37,"props":4788,"children":4789},{},[4790],{"type":24,"value":4791},"On Page Load (Hero Section)",{"type":24,"value":4793}," – Shapes should ",{"type":19,"tag":37,"props":4795,"children":4796},{},[4797],{"type":24,"value":4798},"fade in",{"type":24,"value":2299},{"type":19,"tag":37,"props":4801,"children":4802},{},[4803],{"type":24,"value":4804},"transform naturally",{"type":24,"value":4806},", and settle into a final position.",{"type":19,"tag":70,"props":4808,"children":4809},{},[4810,4815,4816,4821,4823,4828],{"type":19,"tag":37,"props":4811,"children":4812},{},[4813],{"type":24,"value":4814},"On Hover (Programme Cards)",{"type":24,"value":4793},{"type":19,"tag":37,"props":4817,"children":4818},{},[4819],{"type":24,"value":4820},"animate continuously",{"type":24,"value":4822}," while hovered and",{"type":19,"tag":37,"props":4824,"children":4825},{},[4826],{"type":24,"value":4827},"return to their original state",{"type":24,"value":4829}," when the mouse leaves.",{"type":19,"tag":20,"props":4831,"children":4832},{},[4833,4835,4840,4842,4847,4849,4854],{"type":24,"value":4834},"With ",{"type":19,"tag":37,"props":4836,"children":4837},{},[4838],{"type":24,"value":4839},"78 shapes",{"type":24,"value":4841}," across five illustrations and each requiring ",{"type":19,"tag":37,"props":4843,"children":4844},{},[4845],{"type":24,"value":4846},"two animation variations",{"type":24,"value":4848},", I was effectively building ",{"type":19,"tag":37,"props":4850,"children":4851},{},[4852],{"type":24,"value":4853},"10 separate animations",{"type":24,"value":4855}," under a tight deadline.",{"type":19,"tag":20,"props":4857,"children":4858},{},[4859],{"type":24,"value":4860},"I loved the challenge!",{"type":19,"tag":269,"props":4862,"children":4864},{"id":4863},"my-approach-precision-scalability",[4865],{"type":24,"value":4866},"My Approach: Precision & Scalability",{"type":19,"tag":20,"props":4868,"children":4869},{},[4870,4872,4877],{"type":24,"value":4871},"To meet the requirements efficiently, I structured the project into ",{"type":19,"tag":37,"props":4873,"children":4874},{},[4875],{"type":24,"value":4876},"three key phases",{"type":24,"value":1510},{"type":19,"tag":59,"props":4879,"children":4881},{"id":4880},"_1-restructuring-preparation",[4882],{"type":24,"value":4883},"1. Restructuring & Preparation",{"type":19,"tag":66,"props":4885,"children":4886},{},[4887,4898,4908],{"type":19,"tag":70,"props":4888,"children":4889},{},[4890,4892,4897],{"type":24,"value":4891},"I cleaned and restructured each SVG to ensure ",{"type":19,"tag":37,"props":4893,"children":4894},{},[4895],{"type":24,"value":4896},"scalability",{"type":24,"value":125},{"type":19,"tag":70,"props":4899,"children":4900},{},[4901,4906],{"type":19,"tag":37,"props":4902,"children":4903},{},[4904],{"type":24,"value":4905},"Class names",{"type":24,"value":4907}," were assigned to all shapes for easy targeting.",{"type":19,"tag":70,"props":4909,"children":4910},{},[4911,4913,4918,4919,4924],{"type":24,"value":4912},"I wrote ",{"type":19,"tag":37,"props":4914,"children":4915},{},[4916],{"type":24,"value":4917},"SCSS mixins",{"type":24,"value":2307},{"type":19,"tag":37,"props":4920,"children":4921},{},[4922],{"type":24,"value":4923},"functions",{"type":24,"value":4925}," to keep animations modular and reusable.",{"type":19,"tag":59,"props":4927,"children":4929},{"id":4928},"_2-developing-optimised-animations",[4930],{"type":24,"value":4931},"2. Developing Optimised Animations",{"type":19,"tag":66,"props":4933,"children":4934},{},[4935,4960,4972],{"type":19,"tag":70,"props":4936,"children":4937},{},[4938,4940,4945,4947,4952,4953,4958],{"type":24,"value":4939},"Using ",{"type":19,"tag":37,"props":4941,"children":4942},{},[4943],{"type":24,"value":4944},"CSS3 animations",{"type":24,"value":4946},", I kept files ",{"type":19,"tag":37,"props":4948,"children":4949},{},[4950],{"type":24,"value":4951},"lightweight",{"type":24,"value":2307},{"type":19,"tag":37,"props":4954,"children":4955},{},[4956],{"type":24,"value":4957},"self-contained",{"type":24,"value":4959},", eliminating the need for external scripts.",{"type":19,"tag":70,"props":4961,"children":4962},{},[4963,4965,4970],{"type":24,"value":4964},"Shared ",{"type":19,"tag":37,"props":4966,"children":4967},{},[4968],{"type":24,"value":4969},"timing and transformation rules",{"type":24,"value":4971}," ensured natural movement while keeping the code manageable.",{"type":19,"tag":70,"props":4973,"children":4974},{},[4975,4977,4982],{"type":24,"value":4976},"SCSS and node.js were leveraged to output ",{"type":19,"tag":37,"props":4978,"children":4979},{},[4980],{"type":24,"value":4981},"two sets of CSS",{"type":24,"value":4983}," - one for hero animations and another for card hover animations.",{"type":19,"tag":59,"props":4985,"children":4987},{"id":4986},"_3-testing-fine-tuning",[4988],{"type":24,"value":4989},"3. Testing & Fine-Tuning",{"type":19,"tag":66,"props":4991,"children":4992},{},[4993,4998],{"type":19,"tag":70,"props":4994,"children":4995},{},[4996],{"type":24,"value":4997},"I rigorously tested each animation to ensure smooth performance across devices.",{"type":19,"tag":70,"props":4999,"children":5000},{},[5001],{"type":24,"value":5002},"Adjustments were made to individual animations while maintaining a consistent, high-quality motion experience.",{"type":19,"tag":269,"props":5004,"children":5006},{"id":5005},"the-outcome-lightweight-scalable-cost-effective",[5007],{"type":24,"value":5008},"The Outcome: Lightweight, Scalable, & Cost-Effective",{"type":19,"tag":66,"props":5010,"children":5011},{},[5012,5021,5032,5044],{"type":19,"tag":70,"props":5013,"children":5014},{},[5015,5020],{"type":19,"tag":37,"props":5016,"children":5017},{},[5018],{"type":24,"value":5019},"All SVG animations were delivered within the 10-day deadline",{"type":24,"value":125},{"type":19,"tag":70,"props":5022,"children":5023},{},[5024,5026,5031],{"type":24,"value":5025},"File sizes remained tiny, with the largest animation at just ",{"type":19,"tag":37,"props":5027,"children":5028},{},[5029],{"type":24,"value":5030},"68 KB",{"type":24,"value":125},{"type":19,"tag":70,"props":5033,"children":5034},{},[5035,5037,5042],{"type":24,"value":5036},"Animations were ",{"type":19,"tag":37,"props":5038,"children":5039},{},[5040],{"type":24,"value":5041},"fully scalable",{"type":24,"value":5043}," without loss of quality.",{"type":19,"tag":70,"props":5045,"children":5046},{},[5047,5049,5054,5056,5061,5063,5068],{"type":24,"value":5048},"The project’s ",{"type":19,"tag":37,"props":5050,"children":5051},{},[5052],{"type":24,"value":5053},"structured setup",{"type":24,"value":5055}," allowed me to create ",{"type":19,"tag":37,"props":5057,"children":5058},{},[5059],{"type":24,"value":5060},"another set of animations",{"type":24,"value":5062}," a month later in ",{"type":19,"tag":37,"props":5064,"children":5065},{},[5066],{"type":24,"value":5067},"half the time",{"type":24,"value":5069},", reducing costs for HULT.",{"type":19,"tag":20,"props":5071,"children":5072},{},[5073,5075,5080],{"type":24,"value":5074},"By prioritising ",{"type":19,"tag":37,"props":5076,"children":5077},{},[5078],{"type":24,"value":5079},"organisation, efficiency, and scalability",{"type":24,"value":5081},", I ensured that HULT’s animations not only enhanced their website but also provided long-term value.",{"type":19,"tag":269,"props":5083,"children":5085},{"id":5084},"key-takeaways",[5086],{"type":24,"value":5087},"Key Takeaways",{"type":19,"tag":66,"props":5089,"children":5090},{},[5091,5096,5101],{"type":19,"tag":70,"props":5092,"children":5093},{},[5094],{"type":24,"value":5095},"Well-structured code save time & cost.",{"type":19,"tag":70,"props":5097,"children":5098},{},[5099],{"type":24,"value":5100},"CSS-only solutions keep animations lightweight & performant.",{"type":19,"tag":70,"props":5102,"children":5103},{},[5104],{"type":24,"value":5105},"Reusable frameworks allow easy expansion for future needs.",{"type":19,"tag":20,"props":5107,"children":5108},{},[5109,5111,5117],{"type":24,"value":5110},"Need custom SVG animations for your project? ",{"type":19,"tag":2076,"props":5112,"children":5114},{"href":5113},"mailto:eve@eveatwork.studio",[5115],{"type":24,"value":5116},"Let’s talk!",{"type":24,"value":5118}," 🚀",{"title":6,"searchDepth":209,"depth":209,"links":5120},[5121,5122,5127,5128],{"id":4711,"depth":209,"text":4714},{"id":4863,"depth":209,"text":4866,"children":5123},[5124,5125,5126],{"id":4880,"depth":212,"text":4883},{"id":4928,"depth":212,"text":4931},{"id":4986,"depth":212,"text":4989},{"id":5005,"depth":209,"text":5008},{"id":5084,"depth":209,"text":5087},"content:articles:hult-international-svg-animations:index.md","articles/hult-international-svg-animations/index.md","articles/hult-international-svg-animations/index",{"_path":5133,"_dir":6,"_draft":7,"_partial":7,"_locale":6,"title":5134,"description":5135,"keywords":5136,"slug":221,"pagetitle":5137,"date":6,"tags":13,"canonicalUrl":5138,"exclude":234,"body":5139,"_type":213,"_id":5143,"_source":215,"_file":5144,"_stem":5145,"_extension":218},"/articles","UI/UX design and development articles - eveatwork.studio","Articles of eveatwork.studio - web product design and development portfolio of Eve S. Blakcori, United Kingdom.","product designer, UI developer, web designer, front end developer, UX/UI designer, UI developer","Articles","https://www.eveatwork.studio/articles/",{"type":16,"children":5140,"toc":5141},[],{"title":6,"searchDepth":209,"depth":209,"links":5142},[],"content:articles:index.md","articles/index.md","articles/index",{"_path":5147,"_dir":6,"_draft":7,"_partial":7,"_locale":6,"title":5148,"description":5149,"keywords":5150,"slug":5151,"pagetitle":5152,"date":6,"tags":13,"canonicalUrl":5153,"body":5154,"_type":213,"_id":5184,"_source":215,"_file":5185,"_stem":5186,"_extension":218},"/contact","Contact UX/UI designer and developer - eveatwork.studio","Contact details of eveatwork.studio - web product designer and front end developer Eve S. Blakcori.","product designer, UI developer, web designer, front end developer, UX/UI designer from United Kingdom, UI developer from United Kingdom","contact","Contact","https://www.eveatwork.studio/contact/",{"type":16,"children":5155,"toc":5182},[5156,5161,5166,5171],{"type":19,"tag":20,"props":5157,"children":5158},{},[5159],{"type":24,"value":5160},"Hi there, and thank you for your interest in working together.",{"type":19,"tag":20,"props":5162,"children":5163},{},[5164],{"type":24,"value":5165},"I help teams and businesses create clearer, more consistent digital experiences through UI design, front-end development, design systems, and accessibility.",{"type":19,"tag":20,"props":5167,"children":5168},{},[5169],{"type":24,"value":5170},"Whether you need support with a website, product interface, shared UI library, or accessibility improvements, I'd love to hear what you're working on.",{"type":19,"tag":20,"props":5172,"children":5173},{},[5174,5176,5181],{"type":24,"value":5175},"If there is any other reason you want to speak to me, drop me a line at ",{"type":19,"tag":2076,"props":5177,"children":5178},{"href":5113},[5179],{"type":24,"value":5180},"eve@eveatwork.studio",{"type":24,"value":125},{"title":6,"searchDepth":209,"depth":209,"links":5183},[],"content:contact:index.md","contact/index.md","contact/index",{"_path":5188,"_dir":5189,"_draft":7,"_partial":7,"_locale":6,"title":5190,"description":6,"sort":5191,"date":5192,"position":5193,"company":5194,"techStack":5195,"body":5196,"_type":213,"_id":5236,"_source":215,"_file":5237,"_stem":5238,"_extension":218},"/experience/2014-icentric","experience","2014 Icentric","e","July 2014 - September 2016","Front-end developer","iCentric Agency","LESS, CSS, JS & HTML",{"type":16,"children":5197,"toc":5234},[5198,5211,5221],{"type":19,"tag":66,"props":5199,"children":5200},{},[5201,5206],{"type":19,"tag":70,"props":5202,"children":5203},{},[5204],{"type":24,"value":5205},"Converting designs to code using LESS, CSS, HTML & JS",{"type":19,"tag":70,"props":5207,"children":5208},{},[5209],{"type":24,"value":5210},"Integrating CMS to the front-end",{"type":19,"tag":5212,"props":5213,"children":5215},"h5",{"id":5214},"featured-projects",[5216],{"type":19,"tag":37,"props":5217,"children":5218},{},[5219],{"type":24,"value":5220},"Featured projects:",{"type":19,"tag":66,"props":5222,"children":5223},{},[5224,5229],{"type":19,"tag":70,"props":5225,"children":5226},{},[5227],{"type":24,"value":5228},"Mottmac website - UI & front-end development, CMS integration",{"type":19,"tag":70,"props":5230,"children":5231},{},[5232],{"type":24,"value":5233},"iCentric website - UI & creative development, CMS integration",{"title":6,"searchDepth":209,"depth":209,"links":5235},[],"content:experience:2014-icentric.md","experience/2014-icentric.md","experience/2014-icentric",{"_path":5240,"_dir":5189,"_draft":7,"_partial":7,"_locale":6,"title":5241,"description":6,"sort":5242,"date":5243,"position":5244,"company":5245,"techStack":5246,"body":5247,"_type":213,"_id":5291,"_source":215,"_file":5292,"_stem":5293,"_extension":218},"/experience/2016-connells","2016 Connells","d","October 2016 - April 2017","Senior front-end developer","Connells Group","HTML5, CSS3, SASS, JS",{"type":16,"children":5248,"toc":5289},[5249,5272,5281],{"type":19,"tag":66,"props":5250,"children":5251},{},[5252,5257,5262,5267],{"type":19,"tag":70,"props":5253,"children":5254},{},[5255],{"type":24,"value":5256},"UX/UI design - I created user-centred designs for various Connells Group websites and portals using Figma and Adobe XD.",{"type":19,"tag":70,"props":5258,"children":5259},{},[5260],{"type":24,"value":5261},"Front-end and UI development - I wrote semantic, modular front end code using HTML5, CSS3, W3C coding practices, SASS, JS, Vue.js and other technologies.",{"type":19,"tag":70,"props":5263,"children":5264},{},[5265],{"type":24,"value":5266},"Creating prototypes for various POCs.",{"type":19,"tag":70,"props":5268,"children":5269},{},[5270],{"type":24,"value":5271},"Also, I created and maintained UI libraries for various projects.",{"type":19,"tag":5212,"props":5273,"children":5274},{"id":5214},[5275,5279],{"type":19,"tag":37,"props":5276,"children":5277},{},[5278],{"type":24,"value":5220},{"type":24,"value":5280}," ",{"type":19,"tag":66,"props":5282,"children":5283},{},[5284],{"type":19,"tag":70,"props":5285,"children":5286},{},[5287],{"type":24,"value":5288},"Sequence Home website - UI development, CMS integration",{"title":6,"searchDepth":209,"depth":209,"links":5290},[],"content:experience:2016-connells.md","experience/2016-connells.md","experience/2016-connells",{"_path":5295,"_dir":5189,"_draft":7,"_partial":7,"_locale":6,"title":5296,"description":6,"sort":5297,"date":5298,"position":5299,"company":5245,"techStack":5300,"body":5301,"_type":213,"_id":5349,"_source":215,"_file":5350,"_stem":5351,"_extension":218},"/experience/2017-connells","2017 Connells","c","April 2017 - August 2019","Lead front-end developer","Figma, Vue.js, CSS3, SCSS, HTML5, Umbraco, BEM",{"type":16,"children":5302,"toc":5347},[5303,5321,5329],{"type":19,"tag":66,"props":5304,"children":5305},{},[5306,5311,5316],{"type":19,"tag":70,"props":5307,"children":5308},{},[5309],{"type":24,"value":5310},"When I was promoted to the front-end lead position at Connells, I was made in charge of all front-end projects, which meant I set standards in front-end code and tool choices and took responsibility for the visual appearances of our web projects. Also, I helped less experienced colleagues with their day-to-day tasks.",{"type":19,"tag":70,"props":5312,"children":5313},{},[5314],{"type":24,"value":5315},"Another part of my job was maintaining a high awareness of industry issues and trends, particularly regarding accessibility, usability, and emerging technologies.",{"type":19,"tag":70,"props":5317,"children":5318},{},[5319],{"type":24,"value":5320},"On top of that, I kept all responsibilities from my previous role at Connells.",{"type":19,"tag":5212,"props":5322,"children":5323},{"id":5214},[5324,5328],{"type":19,"tag":37,"props":5325,"children":5326},{},[5327],{"type":24,"value":5220},{"type":24,"value":5280},{"type":19,"tag":66,"props":5330,"children":5331},{},[5332,5337,5342],{"type":19,"tag":70,"props":5333,"children":5334},{},[5335],{"type":24,"value":5336},"Connells Group corporate website design and build - Last project done at Connells (95% completion). UI design and implementation, CMS integration",{"type":19,"tag":70,"props":5338,"children":5339},{},[5340],{"type":24,"value":5341},"Connells Surveyors website design and build - UI design and implementation, CMS integration",{"type":19,"tag":70,"props":5343,"children":5344},{},[5345],{"type":24,"value":5346},"Figma API design tokens system - Figma API, NPM, JavaScript, Node.js",{"title":6,"searchDepth":209,"depth":209,"links":5348},[],"content:experience:2017-connells.md","experience/2017-connells.md","experience/2017-connells",{"_path":5353,"_dir":5189,"_draft":7,"_partial":7,"_locale":6,"title":5354,"description":6,"sort":5355,"date":5356,"position":5357,"company":5358,"techStack":5359,"body":5360,"_type":213,"_id":5411,"_source":215,"_file":5412,"_stem":5413,"_extension":218},"/experience/2019-dominos","2019 Dominos","b","September 2019 - May 2021","Senior front-end developer / UI library","Domino’s Pizza UK & Ireland Ltd","Vue.js, Nuxt, TypeScript, SCSS, HTML5, Storybook, Mocha & Chai",{"type":16,"children":5361,"toc":5409},[5362,5390,5397],{"type":19,"tag":66,"props":5363,"children":5364},{},[5365,5370,5375,5380,5385],{"type":19,"tag":70,"props":5366,"children":5367},{},[5368],{"type":24,"value":5369},"At Domino's, I am responsible for the UI side of the front-end projects. ",{"type":19,"tag":70,"props":5371,"children":5372},{},[5373],{"type":24,"value":5374},"I mainly work on Domino's design system / UI library. I build reusable components in Storybook and help less experienced developers produce high-quality results.",{"type":19,"tag":70,"props":5376,"children":5377},{},[5378],{"type":24,"value":5379},"I write unit tests and documentation for the code and make sure our code supports various browsers. ",{"type":19,"tag":70,"props":5381,"children":5382},{},[5383],{"type":24,"value":5384},"Besides writing code, I organise and prioritise the work for our team and set the standards in the tools and methods we choose.",{"type":19,"tag":70,"props":5386,"children":5387},{},[5388],{"type":24,"value":5389},"Also, I take accountability for the quality of the visual appearance and make sure the state of code is up to the standards.",{"type":19,"tag":5212,"props":5391,"children":5392},{"id":5214},[5393],{"type":19,"tag":37,"props":5394,"children":5395},{},[5396],{"type":24,"value":5220},{"type":19,"tag":20,"props":5398,"children":5399},{},[5400,5407],{"type":19,"tag":2076,"props":5401,"children":5404},{"href":5402,"rel":5403},"https://www.dominos.co.uk/",[2080],[5405],{"type":24,"value":5406},"Domino's website re-skin",{"type":24,"value":5408}," - I recently lead a successful Domino's UK eCommerce website re-skin in preparation for the new platform and design.",{"title":6,"searchDepth":209,"depth":209,"links":5410},[],"content:experience:2019-dominos.md","experience/2019-dominos.md","experience/2019-dominos",{"_path":5415,"_dir":5189,"_draft":7,"_partial":7,"_locale":6,"title":5416,"description":6,"sort":2076,"date":5417,"position":5418,"company":5358,"techStack":5359,"body":5419,"_type":213,"_id":5476,"_source":215,"_file":5477,"_stem":5478,"_extension":218},"/experience/2021-dominos","2021 Dominos","May 2021 - present","Development team lead / UI library",{"type":16,"children":5420,"toc":5474},[5421,5449,5456],{"type":19,"tag":66,"props":5422,"children":5423},{},[5424,5429,5434,5439,5444],{"type":19,"tag":70,"props":5425,"children":5426},{},[5427],{"type":24,"value":5428},"All of the responsibilities from the previous role at Domino’s.",{"type":19,"tag":70,"props":5430,"children":5431},{},[5432],{"type":24,"value":5433},"Also, as a Development team lead, I am now responsible for leading and managing the team of developers. This involves providing feedback, addressing any issues, having regular 1 to 1s, half-year and yearly performance reviews.",{"type":19,"tag":70,"props":5435,"children":5436},{},[5437],{"type":24,"value":5438},"I recruit and onboard new colleagues, lead daily standups and any other planned or ad-hoc meetings.",{"type":19,"tag":70,"props":5440,"children":5441},{},[5442],{"type":24,"value":5443},"I work closely with UX/UI designers, Product Owners and other dev teams.",{"type":19,"tag":70,"props":5445,"children":5446},{},[5447],{"type":24,"value":5448},"At Domino's, I am the main point of contact for UI & the front end. ",{"type":19,"tag":5212,"props":5450,"children":5451},{"id":5214},[5452],{"type":19,"tag":37,"props":5453,"children":5454},{},[5455],{"type":24,"value":5220},{"type":19,"tag":66,"props":5457,"children":5458},{},[5459,5464,5469],{"type":19,"tag":70,"props":5460,"children":5461},{},[5462],{"type":24,"value":5463},"Domino's design system/UI library - UI development, unit testing, documentation",{"type":19,"tag":70,"props":5465,"children":5466},{},[5467],{"type":24,"value":5468},"Azure B2C templates development - UI development, team lead",{"type":19,"tag":70,"props":5470,"children":5471},{},[5472],{"type":24,"value":5473},"Fesign Tokens system - Development",{"title":6,"searchDepth":209,"depth":209,"links":5475},[],"content:experience:2021-dominos.md","experience/2021-dominos.md","experience/2021-dominos",{"_path":5480,"_dir":6,"_draft":7,"_partial":7,"_locale":6,"title":6,"description":6,"body":5481,"_type":213,"_id":5485,"_source":215,"_file":5486,"_stem":5487,"_extension":218},"/",{"type":16,"children":5482,"toc":5483},[],{"title":6,"searchDepth":209,"depth":209,"links":5484},[],"content:index.md","index.md","index",{"_path":5489,"_dir":6,"_draft":7,"_partial":7,"_locale":6,"title":5490,"description":5491,"keywords":10,"slug":5492,"pagetitle":5490,"date":6,"tags":13,"canonicalUrl":5493,"body":5494,"_type":213,"_id":5511,"_source":215,"_file":5512,"_stem":5513,"_extension":218},"/thank-you","Thank you","Thank you for getting in touch","thank-you","https://www.eveatwork.studio/thank-you/",{"type":16,"children":5495,"toc":5509},[5496,5501],{"type":19,"tag":20,"props":5497,"children":5498},{},[5499],{"type":24,"value":5500},"Your message was sent! You are about to be taken back to the homepage. If that does not happen, please click the link below.",{"type":19,"tag":20,"props":5502,"children":5503},{},[5504],{"type":19,"tag":2076,"props":5505,"children":5506},{"href":5480},[5507],{"type":24,"value":5508},"back to the website",{"title":6,"searchDepth":209,"depth":209,"links":5510},[],"content:thank-you:index.md","thank-you/index.md","thank-you/index",{"_path":2049,"_dir":221,"_draft":7,"_partial":7,"_locale":6,"title":2050,"description":2051,"keywords":2052,"slug":2053,"pagetitle":2050,"longPageTitle":2050,"date":2054,"longDate":2055,"serpDate":2056,"tags":5515,"category":2060,"featured":234,"canonicalUrl":2061,"projectCompany":758,"projectLink":13,"projectThumbnail":2062,"projectMedia":5516,"pageClassName":13,"nextProjectSlug":749,"schemaImage1x1":2065,"schemaImage4x3":2066,"schemaImage16x9":2067,"ctaTitle":13,"ctaSubtitle":13,"ctaButtonText":13,"body":5517,"_type":213,"_id":4059,"_source":215,"_file":4060,"_stem":4061,"_extension":218},[232,754,116,230,2058,2059],[2064],{"type":16,"children":5518,"toc":7074},[5519,5529,5533,5537,5541,5550,5554,5558,5562,5566,5570,5574,5626,5630,5634,5638,5642,5646,5673,5677,5740,5744,5748,5752,5756,5760,5764,5768,5772,5787,5791,5805,5809,5813,5817,5821,5829,5845,5849,5853,5861,5865,5884,5888,5896,5900,5904,5914,5922,5938,5942,5950,5954,5958,5966,5974,5996,6000,6021,6037,6041,6045,6053,6057,6067,6083,6091,6107,6115,6149,6153,6157,6165,6173,6177,6181,6185,6189,6193,6201,6278,6288,6304,6320,6324,6364,6368,6389,6397,6431,6435,6445,6455,6459,6487,6495,6515,6541,6549,6553,6557,6567,6577,6585,6589,6658,6662,6666,6674,6678,6700,6704,6708,6716,6720,6728,6762,6766,6770,6774,6782,6786,6790,6794,6802,6812,6816,6820,6828,6832,6840,6844,6854,6858,6868,6872,6880,6890,6894,6898,6906,6927,6937,6953,6961,6965,6969,6977,6981,6985,6989,6993,6997,7001,7005,7009,7013,7017,7021,7025,7029,7033,7054,7058,7062,7066,7070],{"type":19,"tag":20,"props":5520,"children":5521},{},[5522,5523,5528],{"type":24,"value":2074},{"type":19,"tag":2076,"props":5524,"children":5526},{"href":2078,"rel":5525},[2080],[5527],{"type":24,"value":2083},{"type":24,"value":2085},{"type":19,"tag":20,"props":5530,"children":5531},{},[5532],{"type":24,"value":2090},{"type":19,"tag":20,"props":5534,"children":5535},{},[5536],{"type":24,"value":2095},{"type":19,"tag":20,"props":5538,"children":5539},{},[5540],{"type":24,"value":2100},{"type":19,"tag":20,"props":5542,"children":5543},{},[5544,5545,5549],{"type":24,"value":2105},{"type":19,"tag":2076,"props":5546,"children":5547},{"href":2108},[5548],{"type":24,"value":2111},{"type":24,"value":2113},{"type":19,"tag":269,"props":5551,"children":5552},{"id":2116},[5553],{"type":24,"value":2119},{"type":19,"tag":59,"props":5555,"children":5556},{"id":2122},[5557],{"type":24,"value":2125},{"type":19,"tag":20,"props":5559,"children":5560},{},[5561],{"type":24,"value":2130},{"type":19,"tag":20,"props":5563,"children":5564},{},[5565],{"type":24,"value":2135},{"type":19,"tag":20,"props":5567,"children":5568},{},[5569],{"type":24,"value":2140},{"type":19,"tag":59,"props":5571,"children":5572},{"id":2143},[5573],{"type":24,"value":2111},{"type":19,"tag":66,"props":5575,"children":5576},{},[5577,5591,5605,5619],{"type":19,"tag":70,"props":5578,"children":5579},{},[5580,5584,5585,5590],{"type":19,"tag":37,"props":5581,"children":5582},{},[5583],{"type":24,"value":2156},{"type":24,"value":2158},{"type":19,"tag":2076,"props":5586,"children":5588},{"href":2161,"rel":5587},[2080],[5589],{"type":24,"value":2165},{"type":24,"value":2167},{"type":19,"tag":70,"props":5592,"children":5593},{},[5594,5598,5599,5604],{"type":19,"tag":37,"props":5595,"children":5596},{},[5597],{"type":24,"value":2175},{"type":24,"value":2177},{"type":19,"tag":2179,"props":5600,"children":5602},{"className":5601},[],[5603],{"type":24,"value":2184},{"type":24,"value":2186},{"type":19,"tag":70,"props":5606,"children":5607},{},[5608,5612,5613,5618],{"type":19,"tag":37,"props":5609,"children":5610},{},[5611],{"type":24,"value":2194},{"type":24,"value":2196},{"type":19,"tag":2179,"props":5614,"children":5616},{"className":5615},[],[5617],{"type":24,"value":2202},{"type":24,"value":2204},{"type":19,"tag":70,"props":5620,"children":5621},{},[5622],{"type":19,"tag":37,"props":5623,"children":5624},{},[5625],{"type":24,"value":2212},{"type":19,"tag":20,"props":5627,"children":5628},{},[5629],{"type":24,"value":2217},{"type":19,"tag":269,"props":5631,"children":5632},{"id":2220},[5633],{"type":24,"value":2223},{"type":19,"tag":20,"props":5635,"children":5636},{},[5637],{"type":24,"value":2228},{"type":19,"tag":59,"props":5639,"children":5640},{"id":2231},[5641],{"type":24,"value":2234},{"type":19,"tag":20,"props":5643,"children":5644},{},[5645],{"type":24,"value":2239},{"type":19,"tag":66,"props":5647,"children":5648},{},[5649,5657,5665],{"type":19,"tag":70,"props":5650,"children":5651},{},[5652,5656],{"type":19,"tag":37,"props":5653,"children":5654},{},[5655],{"type":24,"value":2250},{"type":24,"value":2252},{"type":19,"tag":70,"props":5658,"children":5659},{},[5660,5664],{"type":19,"tag":37,"props":5661,"children":5662},{},[5663],{"type":24,"value":2260},{"type":24,"value":2262},{"type":19,"tag":70,"props":5666,"children":5667},{},[5668,5672],{"type":19,"tag":37,"props":5669,"children":5670},{},[5671],{"type":24,"value":2270},{"type":24,"value":2272},{"type":19,"tag":20,"props":5674,"children":5675},{},[5676],{"type":24,"value":2277},{"type":19,"tag":66,"props":5678,"children":5679},{},[5680,5707],{"type":19,"tag":70,"props":5681,"children":5682},{},[5683,5688,5689,5694,5695,5700,5701,5706],{"type":19,"tag":2179,"props":5684,"children":5686},{"className":5685},[],[5687],{"type":24,"value":2289},{"type":24,"value":2291},{"type":19,"tag":2179,"props":5690,"children":5692},{"className":5691},[],[5693],{"type":24,"value":2297},{"type":24,"value":2299},{"type":19,"tag":2179,"props":5696,"children":5698},{"className":5697},[],[5699],{"type":24,"value":2305},{"type":24,"value":2307},{"type":19,"tag":2179,"props":5702,"children":5704},{"className":5703},[],[5705],{"type":24,"value":2313},{"type":24,"value":2315},{"type":19,"tag":70,"props":5708,"children":5709},{},[5710,5715,5716,5721,5722,5727,5728,5733,5734,5739],{"type":19,"tag":2179,"props":5711,"children":5713},{"className":5712},[],[5714],{"type":24,"value":2260},{"type":24,"value":2325},{"type":19,"tag":2179,"props":5717,"children":5719},{"className":5718},[],[5720],{"type":24,"value":2331},{"type":24,"value":2299},{"type":19,"tag":2179,"props":5723,"children":5725},{"className":5724},[],[5726],{"type":24,"value":2338},{"type":24,"value":2307},{"type":19,"tag":2179,"props":5729,"children":5731},{"className":5730},[],[5732],{"type":24,"value":2345},{"type":24,"value":2347},{"type":19,"tag":2179,"props":5735,"children":5737},{"className":5736},[],[5738],{"type":24,"value":2289},{"type":24,"value":125},{"type":19,"tag":20,"props":5741,"children":5742},{},[5743],{"type":24,"value":2358},{"type":19,"tag":20,"props":5745,"children":5746},{},[5747],{"type":24,"value":2363},{"type":19,"tag":2365,"props":5749,"children":5751},{"src":2367,"className":5750,"alt":2370},[2369],[],{"type":19,"tag":20,"props":5753,"children":5754},{},[5755],{"type":24,"value":2376},{"type":19,"tag":2365,"props":5757,"children":5759},{"src":2379,"className":5758,"alt":2381},[2369],[],{"type":19,"tag":20,"props":5761,"children":5762},{},[5763],{"type":24,"value":2387},{"type":19,"tag":59,"props":5765,"children":5766},{"id":2390},[5767],{"type":24,"value":2393},{"type":19,"tag":20,"props":5769,"children":5770},{},[5771],{"type":24,"value":2398},{"type":19,"tag":20,"props":5773,"children":5774},{},[5775,5780,5781,5786],{"type":19,"tag":2179,"props":5776,"children":5778},{"className":5777},[],[5779],{"type":24,"value":2338},{"type":24,"value":2408},{"type":19,"tag":2179,"props":5782,"children":5784},{"className":5783},[],[5785],{"type":24,"value":2414},{"type":24,"value":2416},{"type":19,"tag":20,"props":5788,"children":5789},{},[5790],{"type":24,"value":2421},{"type":19,"tag":20,"props":5792,"children":5793},{},[5794,5799,5800],{"type":19,"tag":2179,"props":5795,"children":5797},{"className":5796},[],[5798],{"type":24,"value":2338},{"type":24,"value":2431},{"type":19,"tag":2179,"props":5801,"children":5803},{"className":5802},[],[5804],{"type":24,"value":2437},{"type":19,"tag":269,"props":5806,"children":5807},{"id":2440},[5808],{"type":24,"value":2443},{"type":19,"tag":20,"props":5810,"children":5811},{},[5812],{"type":24,"value":2448},{"type":19,"tag":20,"props":5814,"children":5815},{},[5816],{"type":24,"value":2453},{"type":19,"tag":20,"props":5818,"children":5819},{},[5820],{"type":24,"value":2458},{"type":19,"tag":2460,"props":5822,"children":5824},{"className":5823,"code":2464,"language":2465,"meta":6},[2463],[5825],{"type":19,"tag":2179,"props":5826,"children":5827},{"__ignoreMap":6},[5828],{"type":24,"value":2464},{"type":19,"tag":20,"props":5830,"children":5831},{},[5832,5833,5838,5839,5844],{"type":24,"value":2475},{"type":19,"tag":2179,"props":5834,"children":5836},{"className":5835},[],[5837],{"type":24,"value":2202},{"type":24,"value":2482},{"type":19,"tag":2179,"props":5840,"children":5842},{"className":5841},[],[5843],{"type":24,"value":2488},{"type":24,"value":2490},{"type":19,"tag":59,"props":5846,"children":5847},{"id":2493},[5848],{"type":24,"value":2496},{"type":19,"tag":20,"props":5850,"children":5851},{},[5852],{"type":24,"value":2501},{"type":19,"tag":2460,"props":5854,"children":5856},{"className":5855,"code":2506,"language":24,"meta":6},[2505],[5857],{"type":19,"tag":2179,"props":5858,"children":5859},{"__ignoreMap":6},[5860],{"type":24,"value":2506},{"type":19,"tag":20,"props":5862,"children":5863},{},[5864],{"type":24,"value":2516},{"type":19,"tag":1809,"props":5866,"children":5867},{},[5868,5872,5876,5880],{"type":19,"tag":70,"props":5869,"children":5870},{},[5871],{"type":24,"value":2524},{"type":19,"tag":70,"props":5873,"children":5874},{},[5875],{"type":24,"value":2529},{"type":19,"tag":70,"props":5877,"children":5878},{},[5879],{"type":24,"value":2534},{"type":19,"tag":70,"props":5881,"children":5882},{},[5883],{"type":24,"value":2539},{"type":19,"tag":20,"props":5885,"children":5886},{},[5887],{"type":24,"value":2544},{"type":19,"tag":2460,"props":5889,"children":5891},{"className":5890,"code":2549,"language":2550,"meta":6},[2548],[5892],{"type":19,"tag":2179,"props":5893,"children":5894},{"__ignoreMap":6},[5895],{"type":24,"value":2549},{"type":19,"tag":269,"props":5897,"children":5898},{"id":2558},[5899],{"type":24,"value":2561},{"type":19,"tag":59,"props":5901,"children":5902},{"id":2564},[5903],{"type":24,"value":2567},{"type":19,"tag":20,"props":5905,"children":5906},{},[5907,5908,5913],{"type":24,"value":2572},{"type":19,"tag":2179,"props":5909,"children":5911},{"className":5910},[],[5912],{"type":24,"value":2578},{"type":24,"value":2580},{"type":19,"tag":2460,"props":5915,"children":5917},{"className":5916,"code":2585,"language":2586,"meta":6},[2584],[5918],{"type":19,"tag":2179,"props":5919,"children":5920},{"__ignoreMap":6},[5921],{"type":24,"value":2585},{"type":19,"tag":20,"props":5923,"children":5924},{},[5925,5926,5931,5932,5937],{"type":24,"value":2596},{"type":19,"tag":2179,"props":5927,"children":5929},{"className":5928},[],[5930],{"type":24,"value":2578},{"type":24,"value":2603},{"type":19,"tag":2179,"props":5933,"children":5935},{"className":5934},[],[5936],{"type":24,"value":2609},{"type":24,"value":2611},{"type":19,"tag":20,"props":5939,"children":5940},{},[5941],{"type":24,"value":2616},{"type":19,"tag":2460,"props":5943,"children":5945},{"className":5944,"code":2620,"language":2550,"meta":6},[2548],[5946],{"type":19,"tag":2179,"props":5947,"children":5948},{"__ignoreMap":6},[5949],{"type":24,"value":2620},{"type":19,"tag":59,"props":5951,"children":5952},{"id":2628},[5953],{"type":24,"value":2631},{"type":19,"tag":20,"props":5955,"children":5956},{},[5957],{"type":24,"value":2636},{"type":19,"tag":20,"props":5959,"children":5960},{},[5961],{"type":19,"tag":2179,"props":5962,"children":5964},{"className":5963},[],[5965],{"type":24,"value":2645},{"type":19,"tag":2460,"props":5967,"children":5969},{"className":5968,"code":2649,"language":2550,"meta":6},[2548],[5970],{"type":19,"tag":2179,"props":5971,"children":5972},{"__ignoreMap":6},[5973],{"type":24,"value":2649},{"type":19,"tag":20,"props":5975,"children":5976},{},[5977,5978,5983,5984,5989,5990,5995],{"type":24,"value":2659},{"type":19,"tag":2179,"props":5979,"children":5981},{"className":5980},[],[5982],{"type":24,"value":2665},{"type":24,"value":2667},{"type":19,"tag":2179,"props":5985,"children":5987},{"className":5986},[],[5988],{"type":24,"value":2673},{"type":24,"value":2675},{"type":19,"tag":2179,"props":5991,"children":5993},{"className":5992},[],[5994],{"type":24,"value":2681},{"type":24,"value":2683},{"type":19,"tag":20,"props":5997,"children":5998},{},[5999],{"type":24,"value":2688},{"type":19,"tag":66,"props":6001,"children":6002},{},[6003,6012],{"type":19,"tag":70,"props":6004,"children":6005},{},[6006,6011],{"type":19,"tag":2179,"props":6007,"children":6009},{"className":6008},[],[6010],{"type":24,"value":2700},{"type":24,"value":2702},{"type":19,"tag":70,"props":6013,"children":6014},{},[6015,6020],{"type":19,"tag":2179,"props":6016,"children":6018},{"className":6017},[],[6019],{"type":24,"value":2711},{"type":24,"value":2713},{"type":19,"tag":20,"props":6022,"children":6023},{},[6024,6025,6030,6031,6036],{"type":24,"value":2718},{"type":19,"tag":2179,"props":6026,"children":6028},{"className":6027},[],[6029],{"type":24,"value":2724},{"type":24,"value":2726},{"type":19,"tag":2179,"props":6032,"children":6034},{"className":6033},[],[6035],{"type":24,"value":2732},{"type":24,"value":2734},{"type":19,"tag":59,"props":6038,"children":6039},{"id":2737},[6040],{"type":24,"value":2740},{"type":19,"tag":20,"props":6042,"children":6043},{},[6044],{"type":24,"value":2745},{"type":19,"tag":2460,"props":6046,"children":6048},{"className":6047,"code":2750,"language":2751,"meta":6},[2749],[6049],{"type":19,"tag":2179,"props":6050,"children":6051},{"__ignoreMap":6},[6052],{"type":24,"value":2750},{"type":19,"tag":20,"props":6054,"children":6055},{},[6056],{"type":24,"value":2761},{"type":19,"tag":20,"props":6058,"children":6059},{},[6060,6061,6066],{"type":24,"value":2766},{"type":19,"tag":2179,"props":6062,"children":6064},{"className":6063},[],[6065],{"type":24,"value":2772},{"type":24,"value":2774},{"type":19,"tag":20,"props":6068,"children":6069},{},[6070,6071,6076,6077,6082],{"type":24,"value":2779},{"type":19,"tag":2179,"props":6072,"children":6074},{"className":6073},[],[6075],{"type":24,"value":2331},{"type":24,"value":2786},{"type":19,"tag":2179,"props":6078,"children":6080},{"className":6079},[],[6081],{"type":24,"value":2260},{"type":24,"value":2793},{"type":19,"tag":2460,"props":6084,"children":6086},{"className":6085,"code":2797,"language":2751,"meta":6},[2749],[6087],{"type":19,"tag":2179,"props":6088,"children":6089},{"__ignoreMap":6},[6090],{"type":24,"value":2797},{"type":19,"tag":20,"props":6092,"children":6093},{},[6094,6095,6100,6101,6106],{"type":24,"value":2807},{"type":19,"tag":2179,"props":6096,"children":6098},{"className":6097},[],[6099],{"type":24,"value":2305},{"type":24,"value":2814},{"type":19,"tag":2179,"props":6102,"children":6104},{"className":6103},[],[6105],{"type":24,"value":2297},{"type":24,"value":2821},{"type":19,"tag":2460,"props":6108,"children":6110},{"className":6109,"code":2825,"language":2751,"meta":6},[2749],[6111],{"type":19,"tag":2179,"props":6112,"children":6113},{"__ignoreMap":6},[6114],{"type":24,"value":2825},{"type":19,"tag":20,"props":6116,"children":6117},{},[6118,6119,6124,6125,6130,6131,6136,6137,6142,6143,6148],{"type":24,"value":2835},{"type":19,"tag":2179,"props":6120,"children":6122},{"className":6121},[],[6123],{"type":24,"value":2260},{"type":24,"value":2842},{"type":19,"tag":2179,"props":6126,"children":6128},{"className":6127},[],[6129],{"type":24,"value":2848},{"type":24,"value":2307},{"type":19,"tag":2179,"props":6132,"children":6134},{"className":6133},[],[6135],{"type":24,"value":2855},{"type":24,"value":2857},{"type":19,"tag":2179,"props":6138,"children":6140},{"className":6139},[],[6141],{"type":24,"value":2289},{"type":24,"value":2842},{"type":19,"tag":2179,"props":6144,"children":6146},{"className":6145},[],[6147],{"type":24,"value":2869},{"type":24,"value":2871},{"type":19,"tag":59,"props":6150,"children":6151},{"id":2874},[6152],{"type":24,"value":2877},{"type":19,"tag":20,"props":6154,"children":6155},{},[6156],{"type":24,"value":2882},{"type":19,"tag":2460,"props":6158,"children":6160},{"className":6159,"code":2886,"language":2550,"meta":6},[2548],[6161],{"type":19,"tag":2179,"props":6162,"children":6163},{"__ignoreMap":6},[6164],{"type":24,"value":2886},{"type":19,"tag":2460,"props":6166,"children":6168},{"className":6167,"code":2895,"language":2550,"meta":6},[2548],[6169],{"type":19,"tag":2179,"props":6170,"children":6171},{"__ignoreMap":6},[6172],{"type":24,"value":2895},{"type":19,"tag":20,"props":6174,"children":6175},{},[6176],{"type":24,"value":2905},{"type":19,"tag":269,"props":6178,"children":6179},{"id":2908},[6180],{"type":24,"value":2911},{"type":19,"tag":20,"props":6182,"children":6183},{},[6184],{"type":24,"value":2916},{"type":19,"tag":59,"props":6186,"children":6187},{"id":2919},[6188],{"type":24,"value":2922},{"type":19,"tag":20,"props":6190,"children":6191},{},[6192],{"type":24,"value":2927},{"type":19,"tag":2460,"props":6194,"children":6196},{"className":6195,"code":2931,"language":2550,"meta":6},[2548],[6197],{"type":19,"tag":2179,"props":6198,"children":6199},{"__ignoreMap":6},[6200],{"type":24,"value":2931},{"type":19,"tag":2938,"props":6202,"children":6203},{},[6204,6218],{"type":19,"tag":2942,"props":6205,"children":6206},{},[6207],{"type":19,"tag":2946,"props":6208,"children":6209},{},[6210,6214],{"type":19,"tag":2950,"props":6211,"children":6212},{},[6213],{"type":24,"value":2954},{"type":19,"tag":2950,"props":6215,"children":6216},{},[6217],{"type":24,"value":2959},{"type":19,"tag":2961,"props":6219,"children":6220},{},[6221,6240,6259],{"type":19,"tag":2946,"props":6222,"children":6223},{},[6224,6232],{"type":19,"tag":2968,"props":6225,"children":6226},{},[6227],{"type":19,"tag":2179,"props":6228,"children":6230},{"className":6229},[],[6231],{"type":24,"value":2338},{"type":19,"tag":2968,"props":6233,"children":6234},{},[6235],{"type":19,"tag":2179,"props":6236,"children":6238},{"className":6237},[],[6239],{"type":24,"value":2437},{"type":19,"tag":2946,"props":6241,"children":6242},{},[6243,6251],{"type":19,"tag":2968,"props":6244,"children":6245},{},[6246],{"type":19,"tag":2179,"props":6247,"children":6249},{"className":6248},[],[6250],{"type":24,"value":2345},{"type":19,"tag":2968,"props":6252,"children":6253},{},[6254],{"type":19,"tag":2179,"props":6255,"children":6257},{"className":6256},[],[6258],{"type":24,"value":3003},{"type":19,"tag":2946,"props":6260,"children":6261},{},[6262,6270],{"type":19,"tag":2968,"props":6263,"children":6264},{},[6265],{"type":19,"tag":2179,"props":6266,"children":6268},{"className":6267},[],[6269],{"type":24,"value":3015},{"type":19,"tag":2968,"props":6271,"children":6272},{},[6273],{"type":19,"tag":2179,"props":6274,"children":6276},{"className":6275},[],[6277],{"type":24,"value":3024},{"type":19,"tag":20,"props":6279,"children":6280},{},[6281,6282,6287],{"type":24,"value":3029},{"type":19,"tag":2179,"props":6283,"children":6285},{"className":6284},[],[6286],{"type":24,"value":3035},{"type":24,"value":3037},{"type":19,"tag":20,"props":6289,"children":6290},{},[6291,6292,6297,6298,6303],{"type":24,"value":3042},{"type":19,"tag":2179,"props":6293,"children":6295},{"className":6294},[],[6296],{"type":24,"value":3048},{"type":24,"value":2307},{"type":19,"tag":2179,"props":6299,"children":6301},{"className":6300},[],[6302],{"type":24,"value":2338},{"type":24,"value":3056},{"type":19,"tag":20,"props":6305,"children":6306},{},[6307,6308,6313,6314,6319],{"type":24,"value":3061},{"type":19,"tag":2179,"props":6309,"children":6311},{"className":6310},[],[6312],{"type":24,"value":3067},{"type":24,"value":3069},{"type":19,"tag":2179,"props":6315,"children":6317},{"className":6316},[],[6318],{"type":24,"value":3075},{"type":24,"value":125},{"type":19,"tag":59,"props":6321,"children":6322},{"id":3079},[6323],{"type":24,"value":3082},{"type":19,"tag":20,"props":6325,"children":6326},{},[6327,6328,6333,6334,6339,6340,6345,6346,6351,6352,6357,6358,6363],{"type":24,"value":3087},{"type":19,"tag":2179,"props":6329,"children":6331},{"className":6330},[],[6332],{"type":24,"value":2331},{"type":24,"value":3094},{"type":19,"tag":2179,"props":6335,"children":6337},{"className":6336},[],[6338],{"type":24,"value":2848},{"type":24,"value":3101},{"type":19,"tag":2179,"props":6341,"children":6343},{"className":6342},[],[6344],{"type":24,"value":2305},{"type":24,"value":3108},{"type":19,"tag":2179,"props":6347,"children":6349},{"className":6348},[],[6350],{"type":24,"value":2855},{"type":24,"value":3101},{"type":19,"tag":2179,"props":6353,"children":6355},{"className":6354},[],[6356],{"type":24,"value":2297},{"type":24,"value":3121},{"type":19,"tag":2179,"props":6359,"children":6361},{"className":6360},[],[6362],{"type":24,"value":2869},{"type":24,"value":3128},{"type":19,"tag":20,"props":6365,"children":6366},{},[6367],{"type":24,"value":3133},{"type":19,"tag":1809,"props":6369,"children":6370},{},[6371,6375,6379],{"type":19,"tag":70,"props":6372,"children":6373},{},[6374],{"type":24,"value":3141},{"type":19,"tag":70,"props":6376,"children":6377},{},[6378],{"type":24,"value":3146},{"type":19,"tag":70,"props":6380,"children":6381},{},[6382,6383,6388],{"type":24,"value":3151},{"type":19,"tag":2179,"props":6384,"children":6386},{"className":6385},[],[6387],{"type":24,"value":3157},{"type":24,"value":3159},{"type":19,"tag":2460,"props":6390,"children":6392},{"className":6391,"code":3163,"language":2550,"meta":6},[2548],[6393],{"type":19,"tag":2179,"props":6394,"children":6395},{"__ignoreMap":6},[6396],{"type":24,"value":3163},{"type":19,"tag":20,"props":6398,"children":6399},{},[6400,6401,6406,6407,6412,6413,6418,6419,6424,6425,6430],{"type":24,"value":3173},{"type":19,"tag":2179,"props":6402,"children":6404},{"className":6403},[],[6405],{"type":24,"value":2331},{"type":24,"value":3180},{"type":19,"tag":2179,"props":6408,"children":6410},{"className":6409},[],[6411],{"type":24,"value":2848},{"type":24,"value":3187},{"type":19,"tag":2179,"props":6414,"children":6416},{"className":6415},[],[6417],{"type":24,"value":2305},{"type":24,"value":3194},{"type":19,"tag":2179,"props":6420,"children":6422},{"className":6421},[],[6423],{"type":24,"value":2869},{"type":24,"value":3201},{"type":19,"tag":2179,"props":6426,"children":6428},{"className":6427},[],[6429],{"type":24,"value":2297},{"type":24,"value":3208},{"type":19,"tag":3210,"props":6432,"children":6433},{"id":3212},[6434],{"type":24,"value":3215},{"type":19,"tag":20,"props":6436,"children":6437},{},[6438,6439,6444],{"type":24,"value":3220},{"type":19,"tag":2179,"props":6440,"children":6442},{"className":6441},[],[6443],{"type":24,"value":2289},{"type":24,"value":3227},{"type":19,"tag":20,"props":6446,"children":6447},{},[6448,6449,6454],{"type":24,"value":3232},{"type":19,"tag":2179,"props":6450,"children":6452},{"className":6451},[],[6453],{"type":24,"value":3238},{"type":24,"value":3240},{"type":19,"tag":59,"props":6456,"children":6457},{"id":3243},[6458],{"type":24,"value":3246},{"type":19,"tag":20,"props":6460,"children":6461},{},[6462,6463,6468,6469,6474,6475,6480,6481,6486],{"type":24,"value":3251},{"type":19,"tag":2179,"props":6464,"children":6466},{"className":6465},[],[6467],{"type":24,"value":3257},{"type":24,"value":2299},{"type":19,"tag":2179,"props":6470,"children":6472},{"className":6471},[],[6473],{"type":24,"value":3264},{"type":24,"value":2307},{"type":19,"tag":2179,"props":6476,"children":6478},{"className":6477},[],[6479],{"type":24,"value":3271},{"type":24,"value":3273},{"type":19,"tag":2179,"props":6482,"children":6484},{"className":6483},[],[6485],{"type":24,"value":3279},{"type":24,"value":3281},{"type":19,"tag":2460,"props":6488,"children":6490},{"className":6489,"code":3285,"language":2550,"meta":6},[2548],[6491],{"type":19,"tag":2179,"props":6492,"children":6493},{"__ignoreMap":6},[6494],{"type":24,"value":3285},{"type":19,"tag":20,"props":6496,"children":6497},{},[6498,6502,6503,6508,6509,6514],{"type":19,"tag":37,"props":6499,"children":6500},{},[6501],{"type":24,"value":3298},{"type":24,"value":3300},{"type":19,"tag":2179,"props":6504,"children":6506},{"className":6505},[],[6507],{"type":24,"value":3306},{"type":24,"value":3308},{"type":19,"tag":2179,"props":6510,"children":6512},{"className":6511},[],[6513],{"type":24,"value":3314},{"type":24,"value":125},{"type":19,"tag":20,"props":6516,"children":6517},{},[6518,6522,6523,6528,6529,6534,6535,6540],{"type":19,"tag":37,"props":6519,"children":6520},{},[6521],{"type":24,"value":3323},{"type":24,"value":3325},{"type":19,"tag":2179,"props":6524,"children":6526},{"className":6525},[],[6527],{"type":24,"value":3264},{"type":24,"value":3332},{"type":19,"tag":2179,"props":6530,"children":6532},{"className":6531},[],[6533],{"type":24,"value":3338},{"type":24,"value":3308},{"type":19,"tag":2179,"props":6536,"children":6538},{"className":6537},[],[6539],{"type":24,"value":3345},{"type":24,"value":3347},{"type":19,"tag":20,"props":6542,"children":6543},{},[6544,6548],{"type":19,"tag":37,"props":6545,"children":6546},{},[6547],{"type":24,"value":3355},{"type":24,"value":3357},{"type":19,"tag":20,"props":6550,"children":6551},{},[6552],{"type":24,"value":3362},{"type":19,"tag":59,"props":6554,"children":6555},{"id":3365},[6556],{"type":24,"value":3368},{"type":19,"tag":20,"props":6558,"children":6559},{},[6560,6561,6566],{"type":24,"value":3373},{"type":19,"tag":2179,"props":6562,"children":6564},{"className":6563},[],[6565],{"type":24,"value":3379},{"type":24,"value":3381},{"type":19,"tag":20,"props":6568,"children":6569},{},[6570,6571,6576],{"type":24,"value":3386},{"type":19,"tag":2179,"props":6572,"children":6574},{"className":6573},[],[6575],{"type":24,"value":3392},{"type":24,"value":3394},{"type":19,"tag":2460,"props":6578,"children":6580},{"className":6579,"code":3398,"language":2550,"meta":6},[2548],[6581],{"type":19,"tag":2179,"props":6582,"children":6583},{"__ignoreMap":6},[6584],{"type":24,"value":3398},{"type":19,"tag":20,"props":6586,"children":6587},{},[6588],{"type":24,"value":3408},{"type":19,"tag":66,"props":6590,"children":6591},{},[6592,6626,6654],{"type":19,"tag":70,"props":6593,"children":6594},{},[6595,6596,6601,6602,6607,6608,6613,6614,6619,6620,6625],{"type":24,"value":3416},{"type":19,"tag":2179,"props":6597,"children":6599},{"className":6598},[],[6600],{"type":24,"value":2260},{"type":24,"value":3423},{"type":19,"tag":2179,"props":6603,"children":6605},{"className":6604},[],[6606],{"type":24,"value":3429},{"type":24,"value":2307},{"type":19,"tag":2179,"props":6609,"children":6611},{"className":6610},[],[6612],{"type":24,"value":3436},{"type":24,"value":3438},{"type":19,"tag":2179,"props":6615,"children":6617},{"className":6616},[],[6618],{"type":24,"value":3444},{"type":24,"value":3446},{"type":19,"tag":2179,"props":6621,"children":6623},{"className":6622},[],[6624],{"type":24,"value":3452},{"type":24,"value":125},{"type":19,"tag":70,"props":6627,"children":6628},{},[6629,6630,6635,6636,6641,6642,6647,6648,6653],{"type":24,"value":3458},{"type":19,"tag":2179,"props":6631,"children":6633},{"className":6632},[],[6634],{"type":24,"value":3464},{"type":24,"value":2299},{"type":19,"tag":2179,"props":6637,"children":6639},{"className":6638},[],[6640],{"type":24,"value":3471},{"type":24,"value":2299},{"type":19,"tag":2179,"props":6643,"children":6645},{"className":6644},[],[6646],{"type":24,"value":3478},{"type":24,"value":2307},{"type":19,"tag":2179,"props":6649,"children":6651},{"className":6650},[],[6652],{"type":24,"value":3345},{"type":24,"value":3486},{"type":19,"tag":70,"props":6655,"children":6656},{},[6657],{"type":24,"value":3491},{"type":19,"tag":59,"props":6659,"children":6660},{"id":3494},[6661],{"type":24,"value":3497},{"type":19,"tag":20,"props":6663,"children":6664},{},[6665],{"type":24,"value":3502},{"type":19,"tag":2460,"props":6667,"children":6669},{"className":6668,"code":3506,"language":2550,"meta":6},[2548],[6670],{"type":19,"tag":2179,"props":6671,"children":6672},{"__ignoreMap":6},[6673],{"type":24,"value":3506},{"type":19,"tag":20,"props":6675,"children":6676},{},[6677],{"type":24,"value":3516},{"type":19,"tag":20,"props":6679,"children":6680},{},[6681,6682,6687,6688,6693,6694,6699],{"type":24,"value":3521},{"type":19,"tag":2179,"props":6683,"children":6685},{"className":6684},[],[6686],{"type":24,"value":3527},{"type":24,"value":2299},{"type":19,"tag":2179,"props":6689,"children":6691},{"className":6690},[],[6692],{"type":24,"value":3534},{"type":24,"value":2307},{"type":19,"tag":2179,"props":6695,"children":6697},{"className":6696},[],[6698],{"type":24,"value":3541},{"type":24,"value":3543},{"type":19,"tag":59,"props":6701,"children":6702},{"id":3546},[6703],{"type":24,"value":3549},{"type":19,"tag":20,"props":6705,"children":6706},{},[6707],{"type":24,"value":3554},{"type":19,"tag":2460,"props":6709,"children":6711},{"className":6710,"code":3559,"language":3560,"meta":6},[3558],[6712],{"type":19,"tag":2179,"props":6713,"children":6714},{"__ignoreMap":6},[6715],{"type":24,"value":3559},{"type":19,"tag":20,"props":6717,"children":6718},{},[6719],{"type":24,"value":3570},{"type":19,"tag":2460,"props":6721,"children":6723},{"className":6722,"code":3574,"language":3560,"meta":6},[3558],[6724],{"type":19,"tag":2179,"props":6725,"children":6726},{"__ignoreMap":6},[6727],{"type":24,"value":3574},{"type":19,"tag":20,"props":6729,"children":6730},{},[6731,6732,6737,6738,6743,6744,6749,6750,6755,6756,6761],{"type":24,"value":3584},{"type":19,"tag":2179,"props":6733,"children":6735},{"className":6734},[],[6736],{"type":24,"value":2331},{"type":24,"value":2299},{"type":19,"tag":2179,"props":6739,"children":6741},{"className":6740},[],[6742],{"type":24,"value":3015},{"type":24,"value":2307},{"type":19,"tag":2179,"props":6745,"children":6747},{"className":6746},[],[6748],{"type":24,"value":2338},{"type":24,"value":3603},{"type":19,"tag":2179,"props":6751,"children":6753},{"className":6752},[],[6754],{"type":24,"value":2345},{"type":24,"value":3610},{"type":19,"tag":2179,"props":6757,"children":6759},{"className":6758},[],[6760],{"type":24,"value":2313},{"type":24,"value":3617},{"type":19,"tag":20,"props":6763,"children":6764},{},[6765],{"type":24,"value":3622},{"type":19,"tag":59,"props":6767,"children":6768},{"id":3625},[6769],{"type":24,"value":3628},{"type":19,"tag":20,"props":6771,"children":6772},{},[6773],{"type":24,"value":3633},{"type":19,"tag":2460,"props":6775,"children":6777},{"className":6776,"code":3638,"language":3639,"meta":6},[3637],[6778],{"type":19,"tag":2179,"props":6779,"children":6780},{"__ignoreMap":6},[6781],{"type":24,"value":3638},{"type":19,"tag":269,"props":6783,"children":6784},{"id":3647},[6785],{"type":24,"value":3650},{"type":19,"tag":20,"props":6787,"children":6788},{},[6789],{"type":24,"value":3655},{"type":19,"tag":59,"props":6791,"children":6792},{"id":3658},[6793],{"type":24,"value":3661},{"type":19,"tag":2460,"props":6795,"children":6797},{"className":6796,"code":3665,"language":2751,"meta":6},[2749],[6798],{"type":19,"tag":2179,"props":6799,"children":6800},{"__ignoreMap":6},[6801],{"type":24,"value":3665},{"type":19,"tag":20,"props":6803,"children":6804},{},[6805,6806,6811],{"type":24,"value":3675},{"type":19,"tag":2179,"props":6807,"children":6809},{"className":6808},[],[6810],{"type":24,"value":3681},{"type":24,"value":3683},{"type":19,"tag":59,"props":6813,"children":6814},{"id":3686},[6815],{"type":24,"value":3689},{"type":19,"tag":20,"props":6817,"children":6818},{},[6819],{"type":24,"value":3694},{"type":19,"tag":2460,"props":6821,"children":6823},{"className":6822,"code":3698,"language":2465,"meta":6},[2463],[6824],{"type":19,"tag":2179,"props":6825,"children":6826},{"__ignoreMap":6},[6827],{"type":24,"value":3698},{"type":19,"tag":20,"props":6829,"children":6830},{},[6831],{"type":24,"value":3708},{"type":19,"tag":2460,"props":6833,"children":6835},{"className":6834,"code":3712,"language":2465,"meta":6},[2463],[6836],{"type":19,"tag":2179,"props":6837,"children":6838},{"__ignoreMap":6},[6839],{"type":24,"value":3712},{"type":19,"tag":20,"props":6841,"children":6842},{},[6843],{"type":24,"value":3722},{"type":19,"tag":20,"props":6845,"children":6846},{},[6847,6848,6853],{"type":24,"value":3727},{"type":19,"tag":2179,"props":6849,"children":6851},{"className":6850},[],[6852],{"type":24,"value":3733},{"type":24,"value":3735},{"type":19,"tag":269,"props":6855,"children":6856},{"id":3738},[6857],{"type":24,"value":3741},{"type":19,"tag":20,"props":6859,"children":6860},{},[6861,6862,6867],{"type":24,"value":3746},{"type":19,"tag":2179,"props":6863,"children":6865},{"className":6864},[],[6866],{"type":24,"value":3752},{"type":24,"value":125},{"type":19,"tag":20,"props":6869,"children":6870},{},[6871],{"type":24,"value":3758},{"type":19,"tag":2460,"props":6873,"children":6875},{"className":6874,"code":3762,"language":3560,"meta":6},[3558],[6876],{"type":19,"tag":2179,"props":6877,"children":6878},{"__ignoreMap":6},[6879],{"type":24,"value":3762},{"type":19,"tag":20,"props":6881,"children":6882},{},[6883,6884,6889],{"type":24,"value":3772},{"type":19,"tag":2179,"props":6885,"children":6887},{"className":6886},[],[6888],{"type":24,"value":3778},{"type":24,"value":3780},{"type":19,"tag":59,"props":6891,"children":6892},{"id":3783},[6893],{"type":24,"value":3786},{"type":19,"tag":20,"props":6895,"children":6896},{},[6897],{"type":24,"value":3791},{"type":19,"tag":2460,"props":6899,"children":6901},{"className":6900,"code":3795,"language":3560,"meta":6},[3558],[6902],{"type":19,"tag":2179,"props":6903,"children":6904},{"__ignoreMap":6},[6905],{"type":24,"value":3795},{"type":19,"tag":20,"props":6907,"children":6908},{},[6909,6914,6915,6920,6921,6926],{"type":19,"tag":2179,"props":6910,"children":6912},{"className":6911},[],[6913],{"type":24,"value":3809},{"type":24,"value":3811},{"type":19,"tag":2179,"props":6916,"children":6918},{"className":6917},[],[6919],{"type":24,"value":3817},{"type":24,"value":3819},{"type":19,"tag":2179,"props":6922,"children":6924},{"className":6923},[],[6925],{"type":24,"value":3809},{"type":24,"value":125},{"type":19,"tag":20,"props":6928,"children":6929},{},[6930,6931,6936],{"type":24,"value":3830},{"type":19,"tag":2179,"props":6932,"children":6934},{"className":6933},[],[6935],{"type":24,"value":3836},{"type":24,"value":3838},{"type":19,"tag":20,"props":6938,"children":6939},{},[6940,6941,6946,6947,6952],{"type":24,"value":3843},{"type":19,"tag":2179,"props":6942,"children":6944},{"className":6943},[],[6945],{"type":24,"value":3849},{"type":24,"value":3851},{"type":19,"tag":2179,"props":6948,"children":6950},{"className":6949},[],[6951],{"type":24,"value":3857},{"type":24,"value":3859},{"type":19,"tag":2460,"props":6954,"children":6956},{"className":6955,"code":3864,"language":3865,"meta":6},[3863],[6957],{"type":19,"tag":2179,"props":6958,"children":6959},{"__ignoreMap":6},[6960],{"type":24,"value":3864},{"type":19,"tag":59,"props":6962,"children":6963},{"id":3873},[6964],{"type":24,"value":3876},{"type":19,"tag":20,"props":6966,"children":6967},{},[6968],{"type":24,"value":3881},{"type":19,"tag":2460,"props":6970,"children":6972},{"className":6971,"code":3885,"language":3560,"meta":6},[3558],[6973],{"type":19,"tag":2179,"props":6974,"children":6975},{"__ignoreMap":6},[6976],{"type":24,"value":3885},{"type":19,"tag":20,"props":6978,"children":6979},{},[6980],{"type":24,"value":3895},{"type":19,"tag":20,"props":6982,"children":6983},{},[6984],{"type":24,"value":3900},{"type":19,"tag":269,"props":6986,"children":6987},{"id":3903},[6988],{"type":24,"value":3906},{"type":19,"tag":20,"props":6990,"children":6991},{},[6992],{"type":24,"value":3911},{"type":19,"tag":59,"props":6994,"children":6995},{"id":3914},[6996],{"type":24,"value":3917},{"type":19,"tag":20,"props":6998,"children":6999},{},[7000],{"type":24,"value":3922},{"type":19,"tag":20,"props":7002,"children":7003},{},[7004],{"type":24,"value":3927},{"type":19,"tag":20,"props":7006,"children":7007},{},[7008],{"type":24,"value":3932},{"type":19,"tag":20,"props":7010,"children":7011},{},[7012],{"type":24,"value":3937},{"type":19,"tag":59,"props":7014,"children":7015},{"id":3940},[7016],{"type":24,"value":3943},{"type":19,"tag":20,"props":7018,"children":7019},{},[7020],{"type":24,"value":3948},{"type":19,"tag":20,"props":7022,"children":7023},{},[7024],{"type":24,"value":3953},{"type":19,"tag":59,"props":7026,"children":7027},{"id":3956},[7028],{"type":24,"value":3959},{"type":19,"tag":20,"props":7030,"children":7031},{},[7032],{"type":24,"value":3964},{"type":19,"tag":66,"props":7034,"children":7035},{},[7036,7040,7050],{"type":19,"tag":70,"props":7037,"children":7038},{},[7039],{"type":24,"value":3972},{"type":19,"tag":70,"props":7041,"children":7042},{},[7043,7044,7049],{"type":24,"value":3977},{"type":19,"tag":2179,"props":7045,"children":7047},{"className":7046},[],[7048],{"type":24,"value":3983},{"type":24,"value":3985},{"type":19,"tag":70,"props":7051,"children":7052},{},[7053],{"type":24,"value":3990},{"type":19,"tag":269,"props":7055,"children":7056},{"id":3993},[7057],{"type":24,"value":3996},{"type":19,"tag":20,"props":7059,"children":7060},{},[7061],{"type":24,"value":4001},{"type":19,"tag":20,"props":7063,"children":7064},{},[7065],{"type":24,"value":4006},{"type":19,"tag":20,"props":7067,"children":7068},{},[7069],{"type":24,"value":4011},{"type":19,"tag":20,"props":7071,"children":7072},{},[7073],{"type":24,"value":4016},{"title":6,"searchDepth":209,"depth":209,"links":7075},[7076,7080,7084,7087,7093,7102,7106,7110,7115],{"id":2116,"depth":209,"text":2119,"children":7077},[7078,7079],{"id":2122,"depth":212,"text":2125},{"id":2143,"depth":212,"text":2111},{"id":2220,"depth":209,"text":2223,"children":7081},[7082,7083],{"id":2231,"depth":212,"text":2234},{"id":2390,"depth":212,"text":2393},{"id":2440,"depth":209,"text":2443,"children":7085},[7086],{"id":2493,"depth":212,"text":2496},{"id":2558,"depth":209,"text":2561,"children":7088},[7089,7090,7091,7092],{"id":2564,"depth":212,"text":2567},{"id":2628,"depth":212,"text":2631},{"id":2737,"depth":212,"text":2740},{"id":2874,"depth":212,"text":2877},{"id":2908,"depth":209,"text":2911,"children":7094},[7095,7096,7097,7098,7099,7100,7101],{"id":2919,"depth":212,"text":2922},{"id":3079,"depth":212,"text":3082},{"id":3243,"depth":212,"text":3246},{"id":3365,"depth":212,"text":3368},{"id":3494,"depth":212,"text":3497},{"id":3546,"depth":212,"text":3549},{"id":3625,"depth":212,"text":3628},{"id":3647,"depth":209,"text":3650,"children":7103},[7104,7105],{"id":3658,"depth":212,"text":3661},{"id":3686,"depth":212,"text":3689},{"id":3738,"depth":209,"text":3741,"children":7107},[7108,7109],{"id":3783,"depth":212,"text":3786},{"id":3873,"depth":212,"text":3876},{"id":3903,"depth":209,"text":3906,"children":7111},[7112,7113,7114],{"id":3914,"depth":212,"text":3917},{"id":3940,"depth":212,"text":3943},{"id":3956,"depth":212,"text":3959},{"id":3993,"depth":209,"text":3996},1793884850364]