CSS 3D cuboid gauge

I'm toying around with a 3D OEE indicator idea but struggling to get the CSS to work within the contraints of Perspective.

3D OEE indicator

Figure 1. Inkscape sketch of the indicator. (Since OEE is calculated by the product of the three variables the volume of the green cuboid relative to the wireframe gives a visual indication of the individual variables and their product all in one indicator.)

I'm basing what I've done on a tutorial, Let's make a CSS cube - DEV Community 👩‍💻👨‍💻.

joeattardi 3D cube

Figure 2. The tutorial sample result.

The problem I'm having is that I can't see how to set the outer styles. In the example the faces are two levels deep in the HTML as shown below.

<div class="container">
  <div class="cube">
    <div class="face top">Top</div>
    <div class="face bottom">Bottom</div>
    <div class="face left">Left</div>
    <div class="face right">Right</div>
    <div class="face front">Front</div>
    <div class="face back">Back</div>

The associated CSS is,

.container {
  width: 200px;
  height: 200px;
  perspective: 500px;
  margin: 100px;

.cube {
  position: relative;
  width: 200px;
  height: 200px;
  transform-style: preserve-3d;

// plus more for the transforms of the individual faces.

In Perspective I would have to add the styles for both container and cube in the view root - as far as I can see. That gives me strange results.

Has anyone tried to do this?

You could use the markdown component, with the 'escape HTML' toggle turned off, to allow you to nest the arbitrary HTML structure you want, free of our interference intervention? That's basically the same thing @victordcq uses to "inject" JS into the page.

I'll have a look at that, thanks.

here i got something

its not 100% responsive, so you'll have to make sure the aspect rations are good (i didnt do that here so the edges are a bit wonky)

3dcubegaugethiny.zip (21.7 KB)


.my3dcontainer {
  width: 50%;
  height: 50%;
  perspective: 500px;
  margin: 25%;
  position: relative;

.my3dcube {
  position: absolute;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d; 

	background: green;

.my3dface {
  width: 100%;
  height: 100%;
  background: skyblue;
  border: 2px solid black;
  position: absolute;
  opacity: 0.5;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: Arial, sans-serif;
  font-size: 2rem;

.my3dfront {
  transform: rotateY(-90deg) translateX(50%) rotateY(90deg);

.my3dback {
  transform: rotateY(-90deg) translateX(-50%) rotateY(90deg) rotateY(180deg);

.my3dleft {
  transform: translateX(-50%) rotateY(-90deg);

.my3dright {
  transform: translateX(50%) rotateY(90deg);

.my3dtop {
  transform: translateY(-50%) rotateX(90deg);

.my3dbottom {
  transform: translateY(50%) rotateX(-90deg);

the trick was not doing a Z transform (because you cant use % there, but doing a couple of rotates and an x transform... rotateY(-90deg) translateX(50%) rotateY(90deg)
and scaling also with some transforms: transform: rotateY(-90deg) translateX("""+str((100-value.z*100)/2)+"""%) rotateY(90deg) scale3d("""+str(value.x)+""","""+str(value.y)+""","""+str(value.z)+""")

ah and there was an css injected styleclass in it too, to make the markdown responsive, i suppose you could have put that inside the sheet aswell...


Ha! I thought you might enjoy this.

3D rotating cube

I generated this inside a Markdown component as suggested by @PGriffith. The coding is going to be a little messy as I'll need to use a long expression to generate the HTML with parameters. Here's what's generating this.

Markdown source expression binding
'<div class="container">'
+ '  <div class="cube">'
+ '    <div class="face top">Top</div>'
+ '    <div class="face bottom">Bottom</div>'
+ '    <div class="face left">Left</div>'
+ '    <div class="face right">Right</div>'
+ '    <div class="face front">Front</div>'
+ '    <div class="face back">Back</div>'
+ '  </div>'
+ '</div>'
+ '<style>'
+ '	.container {'
+ '	  width: 200px;'
+ '	  height: 200px;'
+ '	  perspective: 500px;'
+ '	  margin: 100px;'
+ '	}'
+ ''
+ '	.cube {'
+ '	  position: relative;'
+ '	  width: 200px;'
+ '	  height: 200px;'
+ '	  transform-style: preserve-3d;'
+ '	}'
+ ''
+ '	.face {'
+ '	  width: 200px;'
+ '	  height: 200px;'
+ '	  background: skyblue;'
+ '	  border: 2px solid black;'
+ '	  position: absolute;'
+ '	  opacity: 0.5;'
+ '	  display: flex;'
+ '	  align-items: center;'
+ '	  justify-content: center;'
+ '	  font-family: Arial, sans-serif;'
+ '	  font-size: 2rem;'
+ '	}'
+ ''
+ '	.cube {'
+ '	  position: relative;'
+ '	  width: 200px;'
+ '	  height: 200px;'
+ '	  transform-style: preserve-3d;'
+ '	  transform: rotate3d(1, 1, 0, 45deg);'
+ '	}'

+ '.front {'
+ '  transform: translateZ(100px);'
+ '}'
+ '.back {'
+ '  transform: translateZ(-100px) rotateY(180deg);'
+ '}'
+ '.left {'
+ '  transform: translateX(-100px) rotateY(-90deg);'
+ '}'
+ '.right {'
+ '  transform: translateX(100px) rotateY(90deg);'
+ '}'
+ '.top {'
+ '  transform: translateY(-100px) rotateX(90deg);'
+ '}'
+ '.bottom {'
+ '  transform: translateY(100px) rotateX(-90deg);'
+ '}'
+ '@keyframes turn {'
+ '  from { transform: rotate3d(0, 0, 0, 0); }'
+ '  to { transform: rotate3d(1, 1, 0, 360deg); }'
+ '}'
+ ''
+ '.cube {'
+ '  position: relative;'
+ '  width: 200px;'
+ '  height: 200px;'
+ '  transform-style: preserve-3d;'
+ '  animation: turn 5s linear infinite;'
+ '}'
+ ''
+ '@media (prefers-reduced-motion: reduce) {'
+ '  .cube {'
+ '    animation: none;'
+ '    transform: rotate3d(1, 1, 0, 45deg);'
+ '  }'
+ '}'
+ '</style>'

Of course, I'm open to suggestions ...


i had put a demo in my post.. check it out^^
you'll have to copy the stlyesheet too or inject it in a class.
ah and turn off overflow on the markdown component, and make sure its a square

My first thought when I saw this, was why not use a typical 2D "attribute gauge" (idk what they're actually called)? It still gives a quick graphical representation of the three attributes relative to eachother, just using an area, rather than a volume.


In fact, you could programmatically generate this type of shape for any number of attributes that you'd like to compare. This would be a really cool built-in component for Ignition, especially using Perspective's dynamic items arrays like they do for menu trees and such.

Just my 2-cents.


I think that would be a class of radar chart (although three vertices isn't enough to take on the circular look of a radar screen). I'll have to think a bit about how the area relates to the product of the three variables. (To take an extreme case, if the value of the top dot is zero then the product of the three variables will be zero and the area should be zero, but it won't! There would be a green triangle in the bottom triangle making it look like something had been achieved when it hadn't.)

  • (a) has the three dots at 60% giving a product of 0.6 × 0.6 × 0.6 = 0.216. The green triangle represents 36% of the outer triangle area. Not a good match.
  • (b) has the top dot at zero giving a product of 1 × 1 × 0 = 0 but the green area is 33%. This is very misleading.
  • (c) is similar to (b) but with the curve pulled in further as the value of the top point decreases. It's still giving a non-zero area for a zero product but it's a bit better.

Thanks for the suggestion. There might be a fix for it.

I really like your c option.

I get what you're saying about the area not being representative of the actual calculated OEE, but it does give a decent idea of where the three attributes are, relative to eachother at a quick glance, letting you know which ones need improvement.

Maybe a non-linear scaling from 0 - 100 would give you a better representation in the a case.

  • I'm trying to avoid aditional stylesheets. It makes the code less portable and prone to breaking on upgrade or transfer to another gateway. The version below has all the CSS built in to the Markdown component so there shouldn't be anything else to do other than import it to a project. The grids are also generated in CSS using repeating-linear-gradient which I wasn't aware existed until now.
  • I can't find an overflow property on the Markdown component. Where is it?

Three-variable 3D indicator

Figure 1. Current version. The colors are set by parameters and in its present form only accepts theme colors.

Component_3D_3_variable_indicator_2023-01-16_1003.zip (14.8 KB)

Work to be done:

  • Fix the axis labels. I've done a couple of cludges to get an acceptable appearance but I don't seem to know how to do a proper rotate3d on them.
  • Make the view resizeable / scaleable.
  • The face colors are a bit "flat". Can we apply a little bit of gradient tint to them - and maybe a bit of difference in tint between the front, right and top faces to emphasise the 3D a little.?

The human brain is terrible at recognizing coverage. Ask anyone to look at (a) and guess what percentage of the big triangle the green one covers. And that's just 2d. So with 3d ?
Frankly, I doubt anyone can look at that cube and go "that's only 37%, we need a 26% increase in frobnubilation to reach our goals !"

It does look super cool though.

1 Like

this is not how to inject css^^

i guess you can just put it here too if you dont want any sheets

to make it scaleable, look at my example, it should scale (though it does not respect ratio so you have to be sure its a square.

edit: i found a fix for aspect ratio, well it works in the browser atleast, it doesnt work in the designer
.psc-fixMarkdownElementHeight > div{height:auto; width:100%; aspect-ratio: 1 / 1;}

Here you go!
You'll have to take an other look at the labels tho
cube.zip (5.5 KB)

though you might have to put .psc-fixMarkdownElementHeight > div{height:100%; width:auto; aspect-ratio: 1 / 1;}
You could do that with a media query maybe, idk you'll have to see what works for you.
or container queries if you have a decently updted browser i'll take alook at that tmw