[This article was first published on Rtask, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.You can read the original post in its original format on Rtask website by ThinkR here: From URL to Theme: How {css2r} Steals a Website’s Colours, and Where It Gives UpYou have thirty minutes before the demo, and your Shiny app still looks like Bootstrap 5 out of the box.We have all been there. The analysis is solid, the model is good, the tables are clean. And then someone from the communication team walks past your screen and says, very politely, that “it doesn’t really look like us”. They are right. Your app is blue-ish, your company is orange. Somewhere there is a 60-page brand book you have never opened, and you have no intention of reading it before 2pm.So here is the naive question we asked ourselves at ThinkR: the company website already carries the brand. The colours are in its CSS, right there, publicly served over HTTP. Why not just go and take them?That is {css2r}, and the small Shiny app that wraps it, Shiny Copy. You give it a URL, it gives you a bslib::bs_theme() call. It is live at connect.thinkr.fr/css2r. Open it in another tab, paste your company’s address, and come back. This article will still be here.It works. And the interesting part of this article is not that it works. It is everything the web refuses to give you along the way. Buckle up, we’re talking about CSS. Thirty seconds: a URL in, a theme outremotes::install_github("ThinkR-open/css2r")library(css2r)thinkr ✔ Internet ok#> ✔ html page downloaded#> ✔ CSS links extracted#> ✔ CSS links filtered#> ✔ CSS downloaded#> ✔ Colors extracted successfully#> ✔ Colors analyzed successfully.#> ℹ No Google Fonts detected.#> ✔ Shiny theme code generated.Nine steps, a few seconds, and the object holds everything it found:thinkr$top_colors#> $white_black#> Color Count#> 32 #FFFFFF 1#>#> $top_colors#> Color Count#> 1 #38404C 133#> 2 #0046C8 72#> 3 #F05622 40#> 4 #20B8D6 23cat(thinkr$shiny_code)#> fluidPage(#> theme = bslib::bs_theme(#> bg = "#FFFFFF",#> fg = "#38404C",#> primary = "#38404C",#> secondary = "#0046C8"#> ),#> h1("Hello World primary", class = "text-center text-secondary"),#> h1("Hello World secondary", class = "text-center text-primary")#> )Copy, paste into your app_ui.R, done.And if you prefer clicking to typing, that is exactly what the hosted version does: swatches, a copy button, and a live Bootstrap mockup showing what your app would look like before you write a single line. Locally, css2r::run_app() launches the same thing.Now look at that theme again. Look at it properly.#F05622 is the ThinkR orange. The one on the logo, on the slides, on the mugs. It came third, with 40 occurrences. It is nowhere in the generated theme. What {css2r} picked as primary is #38404C, a dark slate grey: the body-text colour, which by construction appears everywhere.We ran our own tool on our own website and it did not find our own brand colour. That deserves an explanation, and the explanation is the rest of this article.Under the hood: nine steps and one regular expressionThe css2r R6 class is deliberately small. The pipeline is linear and every step can be called by hand with on_initialize = FALSE:check_internet(), via {curl}download_html(), via {rvest}extract_css_links(), every filter_css_links(), keeping only the ones on the same domaindownload_css_files(), via {httr}extract_colors(), the heart of the machineanalyze_colors(), splitting neutrals from brand coloursdetect_google_fonts(), reading the Google Fonts URL parametersgenerate_shiny_code(), assembling the bs_theme() callStep 6, the one that does all the real work, is five lines:pattern as.data.frame(stringsAsFactors = FALSE)Find every six-digit hex code, count how many times each one appears, sort. Then analyze_colors() puts #FFFFFF and #000000 aside as neutrals, keeps the top four, and generate_shiny_code() assigns background and foreground by relative luminance:hex_luminance = function(hex) { hex