LogoFlexColorScheme

Themes Playground

This chapter goes through the basics of how to use the Themes Playground. Generally it is easy, and you probably don't need a guide, but if you get stuck on some finer points, you can find answers here.

This chapter has not yet been updated to fully cover FlexColorScheme version 7.1 and Flutter 3.10. When it has been fully updated, this notice will be removed.

The Themes Playground is a useful tool to find FlexColorScheme themes and settings you like. You can use it to discover what you can do with FlexColorScheme. The playground persists all its settings, and you can reset them back to their default values, so don't be afraid to experiment.

The most useful and popular feature of the Themes Playground is that it can generate the Dart and Flutter FlexColorScheme setup code needed to produce the shown active theme configuration. It even shows and modifies the code as you change settings, and you can see the code side-by-side as you change settings. This is a fun way to get familiar with the API. Beware, fiddling with all the different themes and settings can be quite addictive, happy theming! 💙

The latest stable version of Themes Playground can be used as a web app here.

Open Source#

The Themes Playground application is open source and bundled with the FlexColorScheme package in the example sub-folder. In its GitHub repository you can find it here /example/lib/example5_themes_playground.

The playground is also the last step in the package tutorial series. The tutorial goes through its main used features that are relevant to using FlexColorScheme, and features that differ from the previous examples. It does not go through all the details of the Playground application, only highlights. You are welcome to study its source code for more insights. It is on purposes a bit excessively commented to guide you if you do. The tutorial also briefly talks about its background, design choices and limitations.

All the example apps are built from the example folder source code included with the package. The web builds and deployments are automated using GitHub actions, that are included in the GitHub repository as well.

Background#

The Themes Playground is as mentioned example number 5 in the package repository. Originally it was only intended to be the last step in the "how to use FlexColorScheme" training tutorial. Since its humble introduction, it has grown into a notable and quite extensive application of its own. It is too extensive to serve as a very helpful tutorial step anymore. Despite having many advanced and useful features as a companion application to the FlexColorScheme package, it is still architecturally identical to examples 3 and 4 in the tutorial.

As a tutorial and example app, the Themes Playground has never had any functional guarantees or even any tests at all of its own. This is still the case. The FlexColorScheme package has and always aims for 100% test coverage in its stable releases.

Despite Themes Playground not having any formal guarantees, it is extensively used and user tested during development of FlexColorScheme releases. In addition to being a very useful tool to configure and experiment with different themes for Flutter apps, and to quickly copy needed API configuration to get the same theme in your app. It is also an excellent tool to use during development of the FlexColorScheme package. It is used to visually see and verify that all features in the package actually do what is expected of them. The changes to the Themes Playground app are also generally already quite thoroughly tracked in the changelog, going back many releases.

Future plans#

Due to its humble background and origins, the Themes Playground application has an architecture that is a bit too simplistic to be extended to offer all features users are asking for. Even a simple export/import falls into that category, it was never intended to do that. There is a mid/long term plan to refactor the Themes Playground and make it into a proper stand-alone application, developed in its own repo.

If that happens, this is potentially the last major release of the Themes Playground in its current form and as being included with the FlexColorScheme package as "just an example and tutorial" on how to use the package to build a dynamically themed app. The Playground will still remain in all minor and fix versions of FlexColorScheme v7, but may be removed in a future major version. Earliest removal point would be version 8 of the FlexColorScheme package, but it might also happen much later.

There are many features that could be considered for a professional version of the Themes Playground app. For example, using a back-end to store and share multiple theme configurations, privately in a team or publicly. Its features could also be made more designer friendly. Currently, the Themes Playground is mainly focused on being an API configuration tool for developers that use the FlexColorScheme package. While it also allows for very flexible and extensive theme configuration, and to interactively try and experiment with different colors and styles on components, it is currently not trying to be or intended to be a designer tool. It does for example not offer any form of import/export compatibility with popular tools like for example Figma. Nor will it do so in its current version and architecture. In a future pro version of Themes Playground, such features may of course be considered.

General export and import of theme configurations could be supported. Distribution of precompiled executables for Windows and macOS, in addition to the web build, may also be included. This version of the Themes Playground would probably no longer be open source. It would remain free to use at a feature level exceeding current features, but also offer a paid tier for development teams. Cloud storage of themes and sharing them within a team would be in the paid tier. Export/import of theme configs is touch and go, they might fall into the paid tier or not. Some new theming features that don't exist yet might also only be in the paid tier. The free tier would be better and also have more features than it currently has. Obviously the open source free FlexColorScheme package API would always support anything the paid tier can do in the Playground, bu some Playground theming features might only be in the paid tier. Challenge with many of the pro and designer leaning features asked for, is that most of them require a backend, which is not free. Delivering them would require a means to cover the costs. It is not expected that the app would bring any major income, nor would it be priced to aim for that. Theming a Flutter app is probably not a big business opportunity, but it would still need to generate enough revenue to cover the backend service costs. At this stage it is unknown if there is enough interest to do that.

Versions#

To use the Themes Playground together with the FlexColorScheme package, you should use the same major version of the Playground as the package. Minor later versions of the package may have added new properties and latest version of Playground will include those properties in generated code. If you are using a lower minor version of the package than the current same major Playground version release is on, the generated Themes Playground config code may include APIs not supported be the lower minor version of the package you use. You can then just delete those rows in the API config, or even better, update your FCS package to the same minor release that the Themes Playground web app build is on.

Version 7.1#

If you are using the FlexColorScheme version 7.1, you can go here to use Themes Playground V7.1 and generate API setup code for FCS version 7.1. It supports new Material 3 features in Flutter stable 3.10. Read more about it in the what's new chapter. You can also use this faster web version of the Themes Playground with FlexColorScheme version 7.0. There are only a few new APIs not supported by FCS 7.0 potentially generated by your Themes Playground 7.1 config. You can just remove them if you are using FCS 7.0. Which you may still be doing if you cannot update to Flutter 3.10 quite yet.

Version 7.0#

If you are using the FlexColorScheme version 7.0, you can go here to use Themes Playground V7.0 and generate API setup code for FCS version 7. It supports new Material 3 features in Flutter stable 3.7. Read more about it in the what's new chapter.

Version 6#

If you are using the FlexColorScheme version 6, you can go here to use Themes Playground V6 and generate API setup code for FCS version 6, it supports FlexColorScheme version 6.1. You can also use this version of the Playground with FlexColorScheme version 6.0. If you do, you may have to delete some generated API config setup code for properties only available in version 6.1 that are not supported by FlexColorScheme 6.0. You will see those as unsupported API errors when you copy/paste the Themes Playground code to Flutter if you use FCS 6.0 and not 6.1. Delete such rows, or you can of course upgrade the package to 6.1 to get those features.

Version 5#

If you are using FlexColorScheme version 5, you can go here to use Themes Playground V5 and generate API setup code for it.

Version 4#

If you are using FlexColorScheme version 4 you should really upgrade. Here you can still use Themes Playground V4. It does not offer any API code generation, since version 4 did not have that feature.

Custom build#

You can also build a local Windows, macOS or Linux desktop version of the Themes Playground. This is highly recommended, as it runs much smoother and nicer than the WEB version. As mentioned above, the Themes Playground app is bundled with the package GitHub repository as Example 5. If you need a Themes Playground companion build for a specific older FlexColorScheme version, you can download a ZIP bundle from the GitHub repo for any past release here.

Two Layouts#

The Themes Playground application offers two view modes.

  1. Topic based page views.
  2. Topic based collapsible panels, in a large masonry style grid view.

Both views have their pros and cons. On most smaller screens and phone devices, the topic based page view is more practical to use.

The masonry based grid view is best experienced at as high resolution as possible, preferably even pixel native 4k. On the web a full 4k render with all panels open, is not so super smooth, on desktop builds it typically works well.

Both views are very responsive and work very well down to small phone media sizes, even in landscape mode. Still, they both benefit a lot from larger media sizes. Mostly because when you use a larger screen with high resolution, you can see the result of more settings at a glance.

The page view becomes more useful at typical landscape tablet sizes or larger. At those sizes you can see the generated setup code in a side-by-side view with each page's configuration topic.

With the masonry grid, you can open and close multiple panels, including the code view, and change settings across multiple panels and see the impact on all of them. Sometimes having the right combination of panels with different topics open at the same time, is useful in order to see and understand the impact of different theme settings. While some settings are by their nature limited to only affecting the components shown on the same topic page. We will explore some examples of both cases.

Interactive Theme#

When you change settings in this application, be it colors, border radius and other styles, it is important to recognize that there is no code in this application, or the other examples, that sets color and style on any of the displayed components being modified.

What is happening is that you are manipulating the global theme for the application, and the application is being rebuilt with a new theme interactively and in real time. Every time you modify settings, it creates a new ThemeData object that the application uses. This is probably not something you would do in a typical application, not to the extent this application does it anyway. Still as demonstrated in this application, you clearly can.

Some theme changes can be a bit taxing calculation wise. Some changes that appear to be lagging behind, do so only due to the theme change animation. The MaterialApp always lerp animates a theme change from all its previous ThemeData property values, to its new ThemeData property values. So when you drag sliders to change border radius, this triggers an animation from a complete ThemeData based on the previous slider value to the next one, based on the new slider value, for every rapid slider value change. This can be seen as a slight delay in the manifestation of the latest value, as the theme is animating to the last slider value. This can certainly be avoided by not triggering a theme change until the slider change is complete, but in this case we preferred to show the change as the slider is being adjusted.

border change radius demo
ThemeData animated change continues a bit after slider change stops, plus realtime code update.

In the above recording you can see how the application's look, and all widgets in it, change as we switch FlexColorScheme theming from being completely OFF to ON, and then turn on using component sub-themes, and lastly as we manipulate the defaultBorder radius for all widgets. Observe that it also changes all buttons, cards and other elements used by the application itself.

Code Generation#

When you open the page view on a large enough screen you will see the generated setup code, side-by-side with the settings you are changing. Not only is the entire theme of the application changing as you modify settings interactively, the generated code that you need to define the same theme, is changing as you change settings too.

In the above screen recoding you can see this. Pay for example attention to the defaultRadius value above as the slider is dragged around.

The generated code aims to exclude code when API default values can be used, and to also exclude settings that become redundant if covered by some other value.

Copy Setup Code#

Whenever you want the code, you can copy it to the clipboard with the copy button and paste it into your project to use it.

You can also at any time, use the drawer, side rail or side menu action item "Copy theme code". This will open a dialog that shows the current theme setup code, with a copy icon button as well. This action button and dialog view can be practical on smaller sized media where you cannot see the code side-by-side with the configuration controls.

Copy code
Copy theme setup code, via side action or COPY button in code view.

When you have copied the code for the setup you configured, you can paste it into your application and use it as-is, or use it as a base for further modifications. You can also paint and select only parts of the code, and copy just a few lines. This might be useful if you only modified a few settings from previous configuration.

If you want to quickly test out themes on a pre-made template app, you can use the Copy Playground Theme. It is useful since it includes presentation of all colors and common Flutter Material UI widgets. You can use them to verify that the theme looks as intended.

Smart Controls#

The user interface disables controls and settings that are not available in a given configuration. For example, when you turn OFF FlexColorScheme, there are not many controls that can be operated, with opinionated component sub-themes OFF, most controls are still disabled.

When you enable component sub-themes, most controls are available. However, there are a few that are disabled in certain combinations, or only appear under some given conditions. Like using computed dark theme, or which color input to use on custom dark theme as keep color for the seeded ColorSchemes, to mention a few.

Controls also know and show different default values depending on your settings. If you turn OFF using FlexColorScheme, toggle using component sub-themes, and even change using the default radius to a fixed value. Widgets know and tell you what their default value is in each situation.

The default value in each situation, means the default style and behavior a component will use, when a given property value is undefined. When you turn OFF using component themes, or FlexColorscheme entirely, it shows the default for that mode. In the above example the radius widget also becomes disabled.

The undefined defaults are different if FlexColorScheme is not used at all, then you are looking at Flutter SDK default behavior for the widget. If you turn ON FlexColorScheme, but keep component sub-themes OFF, then you are looking at the FlexColorScheme core defaults. Mostly they are the same as when not using FlexColorScheme at all, but for certain colors and elevations they differ. The FlexColorScheme core defaults explains, how, when and why FlexColorScheme without component themes enabled, differs from Flutter SDK defaults.

With component sub-themes ON, you again get different defaults, especially for border radius that default to Material 3 specifications where border radius varies per component type.

If you when using component sub-themes keep defaultRadius undefined, then each component widget will use its Material 3 default border radius value, and show that value when an individual widget border radius has not been specified with its slider.

When you set a global default radius, component themes will show and use that value as their default border radius when not defined, and also state that it comes from the global border radius default. If a component widget has specified its own border radius, it shows that value. If you then turn OFF component sub-themes, it will get disabled and show Flutter SDK Material 2 default border radius (4 dp) again.

This type of logic applies so far to border radius, various differences in default colors and elevations, when FlexColorScheme is not used at all, is used, but component themes are not enabled, and when they are enabled.

Small details like this, helps you keep on top of what default values are used when. Controls that are only available when they actually have an impact on the resulting theme, means they can only be operated when they can impact the resulting theme. This helps you avoid trying to adjust things that have no impact in a given mode.

Input Colors#

The input colors is your view into your scheme's raw input colors, as the color values are defined by each built-in theme. There are a few settings you can use to modify these input colors with, before they are used to create the effective ColorScheme for the theme.

You can swap primary and secondary colors, including their container colors. Reduce the amount of used colors, and in dark mode use computed dark theme. Using a computed dark theme is useful when making a custom theme if you have only defined custom colors for your light theme, you can then let FlexColorScheme compute the colors for your dark theme.

In the above case, using the masonry grid view on a large screen is helpful, since we can open and close panels to configure the view like above, and then see the input colors and the detailed full effective ColorScheme at the same time.

Seeded ColorScheme#

Using seeded ColorScheme is a way to use the Material 3 color scheme generation algorithms, that generate complete and balanced color schemes for both light and dark theme mode, from only one or a few input key color values.

Flutter only directly offers using a single color, a main or primary color, as seed color for the generated ColorScheme. With FlexColorScheme, you can use the same setup, but you can optionally also use the secondary and tertiary input colors as additional keys used to generate the effective ColorScheme.

The used input key colors could also be extracted and sourced from images, like e.g. the device wall-paper, or even from image used in an app or seen in a flow of images, and then used in FlexColorScheme to generate the ColorScheme from them. In a future version of the Themes Playground this might be added as a way to generate a ColorScheme and theme from it. There are no additions needed in FlexColorScheme to do this, all it needs is one to three key colors extracted from an image to generate a theme using them.

Using a Seeded ColorScheme is also a form of input color modifier, since it takes the color values defined for the light theme's primary, secondary and tertiary colors, and computes an entirely new derived ColorScheme from them.

Below we can see the Flutter Dash theme:

  1. As defined by built-in colors, with no seeded ColorScheme.

  2. With a single color, the built-in light theme mode primary color from the Flutter Dash theme, used as key color to seed the generated ColorScheme used to make the theme. This is identical to the ColorScheme we get when we use Flutter SDK ColorScheme.fromSeed with the primary light theme mode color.

  3. Using three key colors, from the built-in light theme mode Flutter Dash theme. Its primary, secondary and tertiary colors are used for each main generated Tonal Palette. This type of seed generated ColorScheme is not directly available in the Flutter SDK.

  4. In the last version we lock the main colors, primary, secondary and tertiary, to keep using their defined Flutter Dash "brand" colors, but let all the other colors for the ColorScheme be computed. Generally they look very balanced and nice and will typically make an app using Material 3 color system look great, but you may often need to keep using main colors as defined by the brand or customer requirements.

Tonal Palettes#

What are Tonal Palettes? They are described in detail in the Material 3 color system guide here. The short version, a Material 3 ColorScheme uses six different Tonal Palettes, with 13 colors tones (shades) each:

  • Primary palette
  • Secondary palette
  • Tertiary palette
  • Error palette
  • Neutral palette
  • Neutral variant palette

The ColorScheme uses colors from these palettes for its colors, by using a predefined tone for each color from a given palettes. The light and matching dark mode ColorScheme use the same tonal palettes, they just use different tones from the same palette for corresponding colors.

The Material 3 color system calculation algorithm produces the above tonal palettes based on given input color and then colors from the palettes are assigned to the resulting ColorScheme.

When you use seed generated ColorSchemes in the Themes Playground, you can see all the generated Tonal Palettes, they are shown in the above order.

Below we can see the Tonal Palettes when using the Flutter SDK default Material 3 based ColorScheme tonal palette generation algorithm, using a single input key color. It is shown in both light and dark theme. We can see that the Tonal Palettes for both light and dark theme modes are identical, what varies is which tones are used for each color by the light and dark theme mode ColorScheme.

For example, tone 40 is used from primary Tonal Palette for the ColorScheme.primary color in light theme mode, while tone 80 is used in dark theme mode. On the web and a desktop build of the app, if you hover with the mouse over a seeded ColorScheme color, its source color will be highlighted in the computed Tonal Palette.

For comparison, we above see the same Flutter Dash theme based generated Tonal Palettes when using primary, secondary and tertiary colors as seed key input colors, instead of only primary color. In the "all keys" setup we as an example show the tone mapping of the tertiary container color, in light and dark theme mode.

Flex Tones#

Above we saw that even when we used three input color as keys, we did not get so much of the chroma in the used input color in the resulting Tonal Palettes for the secondary and tertiary colors. This is because the default Material 3 tonal palette calculation algorithm locks chroma for secondary tonal palette generation to 16, and it uses the hue from the same used key color.

For the tertiary tonal palette, chroma is locked to 24, so a bit more colorful than secondary, which can also be seen in the produced palettes. Additionally, hue is rotated +60 degrees from the input key color hue, effectively generating a new hue, based on the single input key color.

The primary tonal palette uses the chroma and hue from the key color, but chroma is only used if it is higher than 48, if it is lower, 48 is used. This ensures that is always has a suitably high color saturation.

The neutral palettes are also using the same key color as input, but with very low chroma, 4 for the neutral palette and 8 for the neutral variant palette. This will create neutral surface colors that contain a hint of the key (primary) color in the surfaces as well. This is similar in concept to the primary color surface blends that FlexColorScheme has used since version 1.0. In the Surface Blends chapter below, we see that surface blends can optionally also be used when using seed generated ColorSchemes. Many of the example screenshots above already did so.

Lastly the error tonal palette is simply made from a fixed color value, having hue 25 and chroma 84.

When we used key colors also for the secondary and tertiary tonal palette generation, it substituted the hue used for secondary and tertiary tonal palettes, to use the hue in their own input key colors, and no longer relied on the values derived from the single input main/primary seed color. We did, however, not do anything to the chroma limits, used by the default Material 3 design specification Tonal Palette color generation algorithm's parameters.

FlexColorScheme, would not be "flex" if it would not let us modify this too. We can define custom parameters for the key colors, that define the chroma limits. Using them can modify the limits for the input colors when we generate their tonal palettes. We can lock it to a given value, or we can let it use whatever chroma it has, or we can say it can use whatever chroma it has, as long as it is over a certain limit. This is useful because if the chroma is very low in the input key color, we basically get an almost greyscale tonal palette, like the neutral tonal palette colors.

With the FlexTones API you can define these limits as desired for the tonal palette generation. We don't have to limit the design to the default parameters used by ColorScheme.fromSeed. We can tweak them, but still use the same algorithm and principles, but tuned to fit our design goals, while still benefiting from these marvelous color generation algorithms.

We can do even more than this, we can also modify the mapping of which tone is used for what color in the ColorScheme from the generated Tonal Palettes, as long as it is from the source palette intended for the target color in the ColorScheme. Not all tones are useful, but for some use cases and design goals, you can very well go up or down a tone, for some colors in the ColorScheme mapping. This can give you a stronger more contrasty look or an even more muted one than the Material 3 default design.

Current version of Themes Playground "only" lets you change FlexTone settings between nine pre-made configurations. It is however very simple to make custom configurations with the API. The pre-made ones are mainly intended as examples. You can read more about FlexTones and its usage in the package FlexSeedScheme API reference. If you make a very nice one, please do share it in the FlexColorScheme GitHub discussions show and tell section, perhaps we can add it as another pre-made config.

Maybe in some future version of the Themes Playground, custom interactive configuration of FlexTones will be added. For now let us compare some of the built-in ones we can swap between in the current version. When you select a pre-made FlexTones configuration, the Theme Playground app shows a brief summary of its configuration, here are some examples:

The "Vivid" colors may actually not always be more "vivid" than the Material 3 FlexTones configuration. It depends on the used seed key colors. For the secondary and tertiary tonal palettes, the actual chroma values of the used input key colors are used. This means you will get a generated ColorScheme that looks a bit more like the input colors you used.

Surface Blends#

With surface blends FlexColorScheme refers to using alpha blends to mix in a hint of a color, typically primary color, into different Material surface colors.

The Material 2 guide also talks about using alpha blends to create branded surface colors, especially in dark mode. In this tweet I show an example of how to create such color tinted background and surface colors, using the Color.alphaBlend function.

Tweet surface blends 2020
Creating branded surfaces - tweet anno 2020, but still valid.

The above is exactly what FlexColorScheme does when you configure it to use surface blends. It also adds different blend modes and variable alpha blend levels, basically just the percentage above, that is then varied per surface type. Or with a bit more detail, the different surface blend modes varies the defined alpha blend level value using different fractional factors for different Flutter surface types.

It mainly affects the two main ColorScheme surface colors surface and background, and their derivatives in the ColorScheme. However, FlexColorScheme also creates surface blends for the Scaffold background color, and in some modes even for the dialog background color, treating them as their own themed surface colors.

In addition to being able to blend in primary color into surfaces, starting with version 5, the color of a container, can be blended into its own onColor using a blend level as well. This gives the onColor itself a hint of the color it is on, instead of being plain white or black/dark grey. For onPrimary, onSecondary, onTertiary and onError, it can be turned OFF completely, while still being used by all the other onColors.

This was added because Material 3 design keeps the onColors for the main colors white in light theme mode, but in dark theme mode that is not the case. With this setting you can decide if you follow this principle or not, when you are not using Material 3 seed generate ColorSchemes. When using the seed generated ColorScheme, this depends on the tone mapping in used FlexTones.

Seed generated ColorSchemes can also use surface blends. Since Material 3 style generated color schemes already include a hint of primary color in all neutral tones, it means that they start with some primary color baked in. When you add surface blends to them, you further strength the effect. Since they don't start at white and almost black, like pure Material 2 surfaces, it means they get much stronger primary color surface blends at same blend level, compared to a none seed generated ColorsScheme. So be more gentle with the blend level, it is easy to overdo it.

If you want a pure Material 3 guide design intent, keep blend level at zero with seed generated ColorSchemes. A bit more is pretty nice too though.

Seed color generated color schemes do not use onColor blending. This is because such themes already covers this design aspect by using tones from the Tonal Palettes that effectively accomplishes the same thing, and often with a better, or let's call it, with a more balanced looking result.

However, when you "keep" e.g. primary color in a seed generated ColorScheme, its onPrimary color can then use onColor blending. Therefore, this setting is not disabled when using Seeded ColorScheme, but using it will only impact onColors belonging to main or container colors being kept at their original input color.

The above may sound complicated, but using it is not. You can just fiddle with settings until you find something you like. The screen recording below show the surface blend modes at same mid-level, and then one of the surface modes from no blend, to maximum blend level.

The second screen recording above shows the onColor blending options and levels. The onColor impacts the color you should use for text and icons on container surfaces, when you use and place them on its none "on" colored container. The impact of this is not so visible above. Generally in an application, they still create a remarkable subtle toned difference. Most notice it, but might not be able to immediately explain what causes the difference in how the design is perceived.

This is especially true for the Material 3 generated ColorSchemes, that use the matching lighter/darker tones for their onColors, which are often brighter and more impactful than the simpler alpha blended version.

In both cases above, pay attention to effective surface, container colors and their onColors, and how they change. Also look at the app to see how it visually changes as blends are varied.

Custom Colors#

You can copy any pre-made color scheme to the last scheme in the Themes Playground, and use its colors as a base for a completely custom colored theme. You can select and edit colors with the FlexColorPicker. The color picker also allows you to enter or paste in color values to it to define the custom color for each input color in the customizable theme.

custom colors
Copying color values and making a custom theme.

Pretty much any color in a box and color code you see in the Themes Playground can be tapped and its color value is then copied to the Clipboard in Dart format. This is handy if you want to snipe any color you see in the playground. This works with the individual generated Tonal Palette colors too.

Copy ColorScheme#

Only want the raw ColorScheme of the active theme you are looking at? No problem, you can copy it too and get a ready-made standard Flutter ColorScheme class definition for it.

Copy active ColorScheme
Copy active ColorScheme.

You can use this feature if you prefer to not use any of FlexColorScheme's theming features. Maybe you would like to build your custom theme from scratch, but still find creating ColorScheme objects with the Themes Playground helpful.