It started back in early 2005 with an idea to recreate the visuals of macOS Aqua buttons in Java2D

and quickly grew to cover a wider range of Swing components under the umbrella of Substance look-and-feel, on the now discontinued java.net. The name came from trying to capture the spirit of Aqua visuals grounded in physicality of material, texture and lighting. The first commit was on April 15, 2005, and the first release of Substance was on May 30, 2005.
A few months later in September 2005, I started working on Flamingo as a proof-of-concept to implement the overall ribbon structure as a Swing component. Later in 2009, common animation APIs were extracted from Substance and made into the Trident animation library, hosted on the now as well discontinued kenai.com.
After taking a break from these libraries in 2010 (during that period the various libraries were forked under the Insubstantial umbrella between 2011 and 2013), I came back to working on them in late 2016, adding support for high DPI displays and reducing visual noise across all components. A couple years later in mid 2018 all the separate projects were brought under the unified Radiance umbrella brand, switching to the industry standard Gradle build system, publishing Maven artifacts for all the libraries, and adding Kotlin DSL extensions.
And now, twenty years after that very first public Substance release, the next major milestone of the Radiance libraries is here. Radiance 8, code-named Marble, brings the biggest rewrite in the project history so far – a new color system. Code-named Project Chroma, it spanned about 700 commits and touched around 27K lines of code:

Radiance 8 uses the Chroma color system from the Ephemeral design library, which builds on the core foundations of the Material color utilities. Over the next few weeks I’ll write more about what Chroma is, and the new capabilities it unlocks for Swing developers that use Radiance as their look-and-feel. In the meanwhile, as always, I’ll list the changes and fixes that went into Radiance 8, using emojis to mark different parts of it:
💔 marks an incompatible API / binary change
🎁 marks new features
🔧 marks bug fixes and general improvements
A new color system
Project Chroma – adding color palettes in Radiance
Theming
- 🔧 Use “Minimize” rather than “Iconify” terminology for window-level actions
- 🔧 Fix application window jumps when moving between displays
- 🔧 Fix exception in setting fonts for
JTree
components
- 🔧 Consistent handling of selection highlights of disabled renderer-based components (lists, tables, trees)
- 🔧 Always show scroll thumb for scrollable content
- 🔧 Fix issues with slider track and thumb during printing
- 🔧 Fix visuals of internal frame header areas under skins that use matte decoration painter
Component
- 🎁 Update flow ribbon bands to accept a
BaseProjection
as components
- 🔧 Fix user interaction with comboboxes in minimized ribbon content
- 🔧 Fix application of icon filter strategies to ribbon application menu commands
- 🔧 Fix passing command overlays to secondary menu commands
- 🔧 Fix crash when some ribbon bands start in collapsed state
- 🔧 Fix active rollover / pressed state visuals for disabled command buttons
- 🔧 Fix command buttons to be updated when secondary content model is updated
- 🔧 Fix display of key tips in collapsed ribbon bands hosted in popups
The new color system in Radiance unlocks a lot of things that we’ve seen in modern desktop, web and mobile interfaces in the last few years. If you’re in the business of writing elegant and high-performing desktop applications in Swing, I’d love for you to take this Radiance release for a spin. Click here to get the instructions on how to add Radiance to your builds. And don’t forget that all of the modules require Java 9 to build and run.
It gives me great pleasure to announce the next major release of Radiance. Let’s get to what’s been fixed, and what’s been added. First, I’m going to use emojis to mark different parts of it like this:
💔 marks an incompatible API / binary change
🎁 marks new features
🔧 marks bug fixes and general improvements
Component
Theming
There’s still a long road ahead to continue exploring the ever-fascinating depths of what it takes to write elegant and high-performing desktop applications in Swing. If you’re in the business of writing just such apps, I’d love for you to take this Radiance release for a spin. Click here to get the instructions on how to add Radiance to your builds. And don’t forget that all of the modules require Java 9 to build and run.
It gives me great pleasure to announce the next major release of Radiance. Let’s get to what’s been fixed, and what’s been added. First, I’m going to use emojis to mark different parts of it like this:
💔 marks an incompatible API / binary change
🎁 marks new features
🔧 marks bug fixes and general improvements
Component
- 🎁 Add tri-state checkbox component
- 🎁 Add switch component
- 🎁 Migrate previously internal circular progress component to public API
- 🎁💔 Revisit layout configuration of command button panels. Support fixed-column and adaptive layout spec for row fill and column fill panels.
- 🎁 Support configurable content padding in command buttons and command button panels
- 🎁 Add more presentation model options for command button panels
- 🎁 Add presentation model for rich tooltips
- 🔧 Fix crash on displaying rich tooltips under Java 17+
- 🔧 Fix text wrap logic in command buttons under big presentation state
- 🔧 Fix vertical positioning of command button content under tile presentation state
- 🔧 Fix issues with command popup menus not closing in certain scenarios
Theming
- 🎁💔 Revisit configuration of popup content. Full documentation here.
- 🎁💔 Unify fill and highlight painters.
- 🎁💔 Revisit how specular fill painter is configured.
- 🔧 Fix crash in specular fill painter
- 🔧 Fix crash in table UI delegate
- 🔧 Fix crash in opening the window title pane menu
- 🔧 Fix crash in update font of a tree component
- 🔧 Fix incorrect offset of vertical scrollbars during scrolling
Kotlin extensions
- 🎁 Add indexed access operator overload for
ResourceBundle.getString
I’ve wanted to get this release out a bit earlier than anticipated to cover the functionality gaps between Radiance and Aurora, and to address some crasher bugs that snuck into the last major rewrite of Radiance’s rendering pipeline. With this release out of the door, the roadmap for 2023 remains as planned:
- Add the ribbon / command bar component to Aurora
- Revisit the way colors are defined and used in both Radiance and Aurora
There’s still a long road ahead to continue exploring the ever-fascinating depths of what it takes to write elegant and high-performing desktop applications in Swing. If you’re in the business of writing just such apps, I’d love for you to take this Radiance release for a spin. Click here to get the instructions on how to add Radiance to your builds. And don’t forget that all of the modules require Java 9 to build and run.
It gives me great pleasure to announce the next major release of Radiance. Let’s get to what’s been fixed, and what’s been added. First, I’m going to use emojis to mark different parts of it like this:
💔 marks an incompatible API / binary change
🎁 marks new features
🔧 marks bug fixes and general improvements
Dependencies for core libraries
- Gradle: 7.2 ➡ 7.5.1
- Kotlin: 1.5.31 ➡ 1.7.10
- Kotlin coroutines: 1.5.2 ➡ 1.6.4
General
- 🔧💔 A new direct rendering model for all core and custom components in Radiance
- Instead of rendering components as multi-layer combinations of cached offscreen images, Radiance now uses direct rendering to the
Graphics
objects passed to the relevant UI delegates and painting methods
- Use
RadianceCommonCortex.paintAtScale1x
for visuals that need to “fall” on exact pixels, line single-pixel borders, separators, etc
- 🔧 Remove all usages of java.security APIs (that are deprecated in Java 17 going forward)
Animation
- 🎁 New default animation pulse source that is based on the display refresh rate
Component
- 🎁💔 Unify fire action trigger logic for command buttons by replacing
CommandButtonPresentationModel.isFireActionOnRollover
and CommandButtonPresentationModel.isFireActionOnPress
with a single actionFireTrigger
enum that has three values:
OnRollover
to fire action on rollover
OnPressed
to fire action on press
OnPressReleased
to fire action on press release (the default)
- 🎁💔 Unify text action/popup click logic for command buttons by replacing
CommandButtonPresentationModel.isTextClickAction
and CommandButtonPresentationModel.isTextClickPopup
with a single textClick
enum field that has two values:
Action
to activate action on text click
Popup
to activate secondary content on text click
- 🎁💔 Revisit breadcrumb bar APIs
- Remove exception propagation APIs (they were no-op in any case since it wasn’t wired)
- Remove index tracking in
BreadcrumbItem
(not wired to anything)
- Switch
BreadcrumbBarCallBack
APIs from StringValuePair
to BreadcrumbItem
- Also rename
getLeafs
to getLeaves
- Rename
BreadcrumbBarCallBack
to BreadcrumbBarContentProvider`
- Rename
BreadcrumbBarModel
to BreadcrumbBarContentModel
- Add
BreadcrumbBarPresentationModel
and support icon filtering
- Remove
StringValuePair
from the API surface altogether
- Revisit the API surface of
BreadcrumbItem
- 🎁💔 Switch presentation models to use
BackgroundAppearanceStrategy
across all components. This applies to
CommandButtonPresentationModel.setFlat
CommandButtonPresentationModel.Overlay.setFlat
CommandStripPresentationModel.setFlat
CommandPresentationModel.setFlat
- 🎁 Add single row resize policy to ribbon flow bands
- 🔧 Fix lost breadcrumb bar path after skin change
- 🔧 Fix separator drawing over the last text character in
MEDIUM
command buttons that don’t display icons
- 🔧 Command menus now toggle open and close on clicks
- 🔧 Fix issues with command popup menus not closing in certain scenarios
Theming
- 💔 Simplified visuals of tabbed panes
- Remove
SINGLE_FULL and DOUBLE_FULL
from TabContentPaneBorderKind
. Apps that wish to draw border around the content area will need to do so explicitly.
- Remove
RadianceSkin.setTabFadeStart
and RadianceSkin.setTabFadeEnd
and do consistent indication for the selected / rollover tab with no alpha fade gradient.
- Consistent corner radius of tabs across all skins.
- 💔 Clean up the signature of fill painters, removing
isFocused
(not used anywhere, and shouldn’t be since the focus indication is painted separately) and hasShine
(specific to StandardFillPainter
visuals).
- 🔧 Fix issues with various color chooser panels, including the correct wiring of the “Reset” button across all the panels
- 🔧 Fix incorrect bounds of maximized decorated frames on Windows
- 🔧 Fix inverted logic of
ComponentOrParentChainScope.setExtraWidgetsPresence
- 🔧 Fix null pointer exception in rollover button listeners
SVG transcoder
- 🔧 Simplify generated code by not emitting identity affine transforms
- 💔 Remove plain templates
As always, I’d love for you to take this Radiance release for a spin. Click here to get the instructions on how to add Radiance to your builds. And don’t forget that all of the modules require Java 9 to build and run.
And now for the next big thing or two.
This release took almost a year to complete. I needed this time to figure out how to continue evolving Radiance in a meaningful way over the next decade or so. The considerations for what went into this work were laid out last October in this post. The two major areas I wanted to focus on are direct rendering and API consistency.
Direct rendering has touched the UI delegates for every single core Swing component, and almost every custom Radiance component, from command buttons all the way up to the ribbon. API consistency has been driven by the ongoing work in Aurora, as well as the drive to clean up the API surfaces that have been misaligned across the codebase for a while.
Making meaningful changes also means making hard choices about backwards compatibility. Deprecating existing APIs but leaving them available leads to a confusing API surface and increases the cost of maintaining and evolving the codebase. Leaving existing APIs in place, and trying to redirect them under the hood to a “v2” variant places noticeable constraints on what is feasible to do. If I want Radiance to be here in the next 10-15 years, the only practical way forward is to cut out APIs that have not aged well, remove them from the codebase and introduce new ones as necessary. I understand that it causes friction during dependency upgrades on the application side of things, but the only other alternative is abandoning any new development altogether.
With all this in mind, what is next, for 2023 and beyond?
The first major change in Radiance is going to be around defining and using colors. Code-named Chroma, this effort aims to bring more clarity and control over working with colors in core and custom Radiance skins, inspired by the ongoing evolution of design systems such as Material and others.
This change will also find its way into Aurora, as these two projects are twins, in a sense. Once Compose for Desktop hits its official 1.2 release, Aurora will go to 1.2 as well. Afterwards, I will work on window APIs, and will start the long-planned work to port the ribbon component to Aurora.
And last but most definitely not the least, are the plans to explore the third twin to Radiance and Aurora, and bring the theming layer and all the components to the world of Flutter.
As I said last October, it’s going to be a long road, and it may take a bit of time again until the next major release of Radiance. The current goal is to fully complete the color work across both Radiance and Aurora, and have them released at the same time. This will probably happen after the ribbon component is added to Aurora. As for the Flutter twin, it is going to be an exciting, and yet completely unpredictable adventure. I may or may not have something for you to play with in 2023. Time will tell.