Using AI to generate Oracle APEX Theme Roller Styles
.... and the results are better than I expected
This blog is about asking AI to take the Vita Style from the APEX Universal Theme and make changes based on a prompt. These changes can then be loaded back into APEX Theme Roller as a new Theme Style.
You can try this out yourself! just copy my custom built Vita Style Theme Roller Config at the end of this blog and ask your favorite generative AI to make a theme from a prompt.
Let's go!
Background
I was in the kitchen one afternoon eating one of these biscuits...
... when suddenly an idea struck me⚡The idea was to use AI to generate theme-roller styles for Oracle APEX.
I'm really not sure how Butter Biscuits and AI are related.. but that's exactly how it happened!
I started by exporting the Vita style from Theme Roller. Once exported, I could ask AI to customize it.
The first issue I encountered is when I exported the Vita theme style, unless the value is modified, all you see is this.
{"classes":[],"vars":{},"customCSS":"","useCustomLess":"N"}
Therefore AI isn't going to be much good at predicting the variables to use. So I had to modify each and every value - yes, it still hurts to think about it - and then export the file with all the user-modifiable settings intact.
After modifying the colors/settings, this produces an export. A snippet of that export looks like this
{
"classes": [],
"vars": {
"@g_Accent-BG": "#9400D3",
"@g_Accent-OG": "#FA8072",
"@g_Link-Base": "#0804AA",
The second issue I had is that since I have modified the values, it's not Vita anymore! I really wanted AI to be impressed so much by Vita, that it was inspired to create an amazing new theme style.
So I had to get all the original values back. But what are the original values? and... have you noticed that sometimes when you tweak the colors in Theme Roller, some other colors are magically changed too? Yeah why is that? ... all will be revealed shortly.
Having read Plamen's blog about how to copy APEX theme styles between applications, I noticed something in the Exploring the Theme Style configuration section of his blog called Input Parameter File URLs
Long story short, this points to this file:
https://static.oracle.com/cdn/apex/23.2.1/themes/theme_42/23.2/less/theme/Vita.less
This file holds the Vita configuration. Using this, we can get each of Vita's values back by searching for each variable one by one i.e
g_Accent-BG
// Primary Accent
@g_Accent-BG: #056AC8;
g_Accent-OG
// Body Accent
@g_Accent-OG: #FDFDFD;
g_Link-Base
// Link Color
@g_Link-Base: @g_Accent-BG;
Ooh look! g_Link-Base's value is linked to g_Accent-BG. So when you use Theme Roller and change g_Accent-BG, it actually changes the color for g_Link-Base too. This explains when some colors change magically.
I put all the Vita values back one by one (AI didn't want to cooperate 😞) and boom... we have Vita in a Theme Roller file.
Lets feed this in to AI and check out the results
The Results
I imported the Opportunities app from the APEX Gallery into my workspace, then fired up Theme Roller and used the Import Feature to load in the AI generated config file.
All these Themes were generated with ChatGPT 3.5 only. Because...
The config was too long for CoPilot to deal with
Bard only wanted to give me half the theme back
Theme Styles
This was the very first attempt and a bit laughable. The prompt was:
Take this theme style and change the variable values ONLY to make a new theme style
Here's one based on my favorite theme, the Dracula Theme. Its not so bad actually, but some of the text is close to unreadable. Definitely needs some tuning!
Can you make a theme based on the "Dracula Theme" ?
How about a Leeds United Theme? .. It kinda works (but not really).
Can you make a Leeds United Theme?
This one is fabulous.
Can you make really modern, beautiful theme with the best color contrasts . Make it elegant, simple, yet awesome
How about something simple..
Create a pinky dark theme
Or a neon one?
Incorporate bright neon colors, contrasts, and a dark background to give it that classic 80s vaporwave synth feel.
Finally, the one that started all this craziness
Can you make a style based on Tower Gate Milk Chocolate Butter Biscuits
Vita Style Theme Roller Config
Want to create you own Theme Styles with AI?
Just use a prompt like this with ChatGPT.
Take this theme roller config and make me a theme style based on the Tower Gate Milk Chocolate Butter Biscuits.
Do not add any JSON comments.
Do not to add, remove or change any of the variable names.[Paste in JSON from below]
Tip 1: As Doug Gault points out, ChatGPT will occasionally add comments to JSON (which is not supported in the JSON specification), this is why you have to specifically ask it not to provide comments.
Tip 2: ChatGPT sometimes likes to add, remove, change or hallucinate extra variables. Therefore you may have to ask it not to add, remove or change any of the variable names
{
"classes": [],
"vars": {
"@g_Accent-BG": "#056AC8",
"@g_Accent-OG": "#FDFDFD",
"@g_Link-Base": "@g_Accent-BG",
"@g_Focus": "@g_Accent-BG",
"@g_Container-BorderRadius": ".125rem",
"@g_Header-BG": "@g_Accent-BG",
"@g_Header-FG": "contrast(@g_Header-BG, darken(@g_Header-BG, 80%), lighten(@g_Header-BG, 80%), 43%)",
"@g_Body-BG": "@g_Accent-OG",
"@g_Body-Text": "fade(contrast(@g_Body-BG, desaturate(darken(@g_Body-BG, 100%), 100%), desaturate(lighten(@g_Body-BG, 100%), 50%)), 100%)",
"@g_Actions-Col-BG": "contrast(@g_Accent-OG, darken(@g_Accent-OG, 1.5%), lighten(@g_Accent-OG, 1.5%), 43%)",
"@g_Actions-Col-Text": "fade(contrast(@g_Actions-Col-BG, desaturate(darken(@g_Actions-Col-BG, 100%), 100%), desaturate(lighten(@g_Actions-Col-BG, 100%), 50%)), 100%)",
"@g_Body-Title-BG": "lighten(@g_Accent-OG, 3%)",
"@g_Body-Title-FG": "fade(contrast(@g_Body-Title-BG, desaturate(darken(@g_Body-Title-BG, 100%), 100%), desaturate(lighten(@g_Body-Title-BG, 100%), 50%)), 100%)",
"@l_Left-Col-BG": "lighten(@g_Accent-OG, 5%)",
"@l_Left-Col-Text": "@g_Body-Text",
"@g_Nav_Style": "dark",
"@g_Nav-BGX": "desaturate(@g_Accent-BG, 85%)",
"@g_Nav-BG": "darken(@g_Nav-BGX, 20%)",
"@g_Nav-FG": "contrast(@g_Nav-BG, darken(@g_Nav-BG, 80%), lighten(@g_Nav-BG, 80%), 43%)",
"@g_Nav-Active-BG": "darken(@g_Nav-BG, 10%)",
"@g_Nav-Active-FG": "contrast(@g_Nav-Active-BG, darken(@g_Nav-Active-BG, 95%), lighten(@g_Nav-Active-BG, 95%), 43%)",
"@g_Nav-Accent-BG": "@g_Accent-BG",
"@g_Nav-Accent-FG": "@g_Accent-FG",
"@g_Nav-Badge-BG": "@g_Accent-BG",
"@g_Nav-Badge-FG": "@g_Accent-FG",
"@g_NavBarMenu-Active-BG": "@g_Accent-BG",
"@g_NavBarMenu-Active-FG": "@g_Accent-FG",
"@g_NavBarMenu-BG": "#FFFFFF",
"@g_NavBarMenu-FG": "fade(contrast(@g_NavBarMenu-BG, desaturate(darken(@g_NavBarMenu-BG, 85%), 100%), desaturate(lighten(@g_NavBarMenu-BG, 85%), 50%)), 100%)",
"@g_Region-Header-BG": "lighten(@g_Accent-OG, 4%)",
"@g_Region-Header-FG": "fade(contrast(@g_Region-Header-BG, desaturate(darken(@g_Region-Header-BG, 85%), 100%), desaturate(lighten(@g_Region-Header-BG, 85%), 50%)), 100%)",
"@g_Region-BG": "lighten(@g_Region-Header-BG, 20%)",
"@g_Region-FG": "fade(contrast(@g_Region-BG, desaturate(darken(@g_Region-BG, 85%), 100%), desaturate(lighten(@g_Region-BG, 85%), 50%)), 100%)",
"@g_Disabled-BG": "#707070",
"@g_Disabled-FG": "#FFFFFF",
"@g_Primary-BG": "contrast(@g_Accent-BG, darken(@g_Accent-BG, 40%), lighten(@g_Accent-BG, 40%), 43%)",
"@g_Primary-FG": "contrast(@g_Primary-BG, darken(@g_Primary-BG, 75%), lighten(@g_Primary-BG, 75%), 43%)",
"@g_Success-BG": "#278701",
"@g_Success-FG": "#FFF",
"@g_Info-BG": "#056AC8",
"@g_Info-FG": "#FFF",
"@g_Warning-BG": "#FFC628",
"@g_Warning-FG": "#000",
"@g_Danger-BG": "#CB1100",
"@g_Danger-FG": "#FFF",
"@g_Color-Palette-1": "#309FDB",
"@g_Color-Palette-1-FG": "fade(contrast(@g_Color-Palette-1, darken(@g_Color-Palette-1, 50%), lighten(@g_Color-Palette-1, 50%)), 100%)",
"@g_Color-Palette-2": "#13B6CF",
"@g_Color-Palette-2-FG": "fade(contrast(@g_Color-Palette-2, darken(@g_Color-Palette-2, 50%), lighten(@g_Color-Palette-2, 50%)), 100%)",
"@g_Color-Palette-3": "#2EBFBC",
"@g_Color-Palette-3-FG": "fade(contrast(@g_Color-Palette-3, darken(@g_Color-Palette-3, 50%), lighten(@g_Color-Palette-3, 50%)), 100%)",
"@g_Color-Palette-4": "#3CAF85",
"@g_Color-Palette-4-FG": "fade(contrast(@g_Color-Palette-4, darken(@g_Color-Palette-4, 50%), lighten(@g_Color-Palette-4, 50%)), 100%)",
"@g_Color-Palette-5": "#81BB5F",
"@g_Color-Palette-5-FG": "fade(contrast(@g_Color-Palette-5, darken(@g_Color-Palette-5, 50%), lighten(@g_Color-Palette-5, 50%)), 100%)",
"@g_Color-Palette-6": "#DDDE53",
"@g_Color-Palette-6-FG": "fade(contrast(@g_Color-Palette-6, darken(@g_Color-Palette-6, 50%), lighten(@g_Color-Palette-6, 50%)), 100%)",
"@g_Color-Palette-7": "#FBCE4A",
"@g_Color-Palette-7-FG": "fade(contrast(@g_Color-Palette-7, darken(@g_Color-Palette-7, 50%), lighten(@g_Color-Palette-7, 50%)), 100%)",
"@g_Color-Palette-8": "#ED813E",
"@g_Color-Palette-8-FG": "fade(contrast(@g_Color-Palette-8, darken(@g_Color-Palette-8, 50%), lighten(@g_Color-Palette-8, 50%)), 100%)",
"@g_Color-Palette-9": "#E95B54",
"@g_Color-Palette-9-FG": "fade(contrast(@g_Color-Palette-9, darken(@g_Color-Palette-9, 50%), lighten(@g_Color-Palette-9, 50%)), 100%)",
"@g_Color-Palette-10": "#E85D88",
"@g_Color-Palette-10-FG": "fade(contrast(@g_Color-Palette-10, darken(@g_Color-Palette-10, 50%), lighten(@g_Color-Palette-10, 50%)), 100%)",
"@g_Color-Palette-11": "#CA589D",
"@g_Color-Palette-11-FG": "fade(contrast(@g_Color-Palette-11, darken(@g_Color-Palette-11, 50%), lighten(@g_Color-Palette-11, 50%)), 100%)",
"@g_Color-Palette-12": "#854E9B",
"@g_Color-Palette-12-FG": "fade(contrast(@g_Color-Palette-12, darken(@g_Color-Palette-12, 50%), lighten(@g_Color-Palette-12, 50%)), 100%)",
"@g_Color-Palette-13": "#5A68AD",
"@g_Color-Palette-13-FG": "fade(contrast(@g_Color-Palette-13, darken(@g_Color-Palette-13, 50%), lighten(@g_Color-Palette-13, 50%)), 100%)",
"@g_Color-Palette-14": "#AFBAC5",
"@g_Color-Palette-14-FG": "fade(contrast(@g_Color-Palette-14, darken(@g_Color-Palette-14, 50%), lighten(@g_Color-Palette-14, 50%)), 100%)",
"@g_Color-Palette-15": "#6E8598",
"@g_Color-Palette-15-FG": "fade(contrast(@g_Color-Palette-15, darken(@g_Color-Palette-15, 50%), lighten(@g_Color-Palette-15, 50%)), 100%)",
"@g_Button-BG": "mix(#F0F0F0, @g_Region-BG)",
"@g_Button-Text": "contrast(@g_Button-BG, darken(@g_Button-BG, 75%), lighten(@g_Button-BG, 75%), 43%)",
"@l_Button-Hot-BG": "@g_Accent-BG",
"@l_Button-Hot-Text": "contrast(@l_Button-Hot-BG, darken(@l_Button-Hot-BG, 85%), lighten(@l_Button-Hot-BG, 85%), 43%)",
"@l_Button-Simple-BG": "#FFFFFF",
"@l_Button-Simple-Text": "fade(contrast(@l_Button-Simple-BG, darken(@l_Button-Simple-BG, 75%), lighten(@l_Button-Simple-BG, 75%)), 100%)",
"@g_Form-Label": "@g_Region-FG",
"@g_Form-BorderRadius": ".125rem",
"@g_Form-Item-BG": "contrast(@g_Region-BG, darken(@g_Region-BG, 2.5%), lighten(@g_Region-BG, 2.5%), 43%)",
"@g_Form-Item-FG": "fade(contrast(@g_Form-Item-BG, desaturate(darken(@g_Form-Item-BG, 85%), 100%), desaturate(lighten(@g_Form-Item-BG, 85%), 50%)), 100%)",
"@Head-Height": "3rem",
"@Nav-Exp": "15rem",
"@Actions-Exp": "12.5rem",
"@Side-Exp": "15rem"
},
"customCSS": "",
"useCustomLess": "N"
}
It doesn't always get it right, however....
ENJOY!
Whats the picture? Its Knaresborough. Visit Yorkshire!