Initial sketch of the pumpkin

Last week I've finished my 3D CSS-only Halloween Jack-o'-lantern pumpkin, and I thought why not to write about it at least a bit. In this article I'm focusing on the body of the pumpkin and cursor following.

This is how the finished pumpkin looks like:

The pumpkin

The body

It all started with an idea of a CSS pumpkin as a rotating sections which scales up and down creating the humps. (Humps - is that the right word? Quite hard to translate such a thing.) I wanted to make the pen CSS-only, so I just used an rectangle with rounded corners. CSS offers you an option to set different horizontal and vertical border-radius. I know about this for a long time, but I think I never quite had and opportunity to use it. So this may be the first time. And it worked really well, the shape looks quite real.

There are multiple these rectangles rotated around the central vertical Y axis. Sass calculates a distance of each individual slice from the middle of the hump and scales it adequately in both directions. Also the color is gradually darkened when going further from the middle of the hump. This creates nice illusion of a shadows. Without that it would be hard to distinguish the shape, you would see only overall silhouette.

The following animation shows the individual steps as well as the SCSS code. Important parts have comments.

The stem

The pumpkin body was finished the very same evening I had the original idea. But it looked too plain. So I had to add a stem.

At first, I tried horizontal circles as slices of gradually thickening stem. But the problem was that they were hardly visible from the side as opposed to the pumpkin body which disappears when looking directly from the top. So I tried adding vertical slices in both directions using pseudoelements on the circles. That worked well. After amending connection of these individual planes using another rotation and skewing, I decided to remove the horizontal circles altogether. That was just too much shapes for the stem, but the body was more important. I left just one circle on the bottom to help visually finish the silhouette of the stem. That worked quite well.

But something was still missing… Hmm, I'll probably have to also add some face.

The face

At first I just wanted to place few triangles in space using just empiric transforms on them. But that's not so easy when you don't have some placeholder there. Soon after that I decided to create a 3D CSS mesh from rectangles and carve the face from it using clip-path. And working on that kept me busy for much longer time…

Sketches for the face and calculations

I'm writing a separate post called "Mapping polygonal shapes to 3D CSS mesh" in which I'm detailing all the steps including the trigonometry beyond the calculations. I'm going to finish it soon. Link to the article will appear here.

The scene

I should also mention the setup of the scene. It is quite simple but doing its job really great. At first I just tried rotating the pumpkin in multiple directions with multiple CSS animations for each direction. When creating the animations I had an idea to use multiple nested containers for animation in each direction. This solves really nicely the problem with individual CSS transforms being all set in just one property. When you want to animate each property separately that's usually a problem.

  <div class="scene">
  <div class="scene-x">
    <div class="scene-y">
      <div class="scene-z">
        <!-- content goes here -->
      </div>
    </div>
  </div>
</div>

  .scene-x {
  transform: rotateX(-10deg);
}

.scene-y {
  transform: rotateY(20deg);
}

.scene-z {
  transform: rotateZ(0deg);
}

Using just animations was too static, I wanted to add interactivity. So I tried tracking users pointer and change the angles of rotations to make the pumpkin follow the cursor. For that I used the trick with a mesh of elements with :hover state and general sibling selector ~ to change the angles of rotation. When there's no tracking device but touch is supported, tapping each segment changes its state to :focus thanks to tabindex="-1" set on each element. So I also used that together with the :hover state.

Take a look at the following example:

And voilà, the pumpkin followed the cursor. I also change the color of the face along with the rotation. When the cursor is in the middle the face seems (at least that was my intention) to be candle backlit. I use custom properties for the angle of rotation and the color of the face. Both could be done without that in this case, but this is much cleaner.

And that's about it…


👻 👻 👻
Happy Halloween to you all!
🎃 🎃 🎃


108 2 3