00:00/00:00
3:22
00:03:22

Shortcuts ⌨️

  • SPACE to play / pause
  • ARROW RIGHT or L to go forward
  • ARROW LEFT or J to go backward
  • ARROW UP to increase volume
  • ARROW DOWN to decrease volume
  • F to toggle fullscreen
  • M to toggle mute
  • 0 to 9 to go to the corresponding part of the video
  • SHIFT + , to decrease playback speed
  • SHIFT + . or ; to increase playback speed

Unlock content 🔓

To get access to 93 hours of video, a members-only Discord server, subtitles, lesson resources, future updates and much more join us for only $95!

Want to learn more? 👋

67%

That's the end of the free part 😔

To get access to 93 hours of video, a members-only Discord server and future updates, join us for only $95!

Next lesson
48.

Mixing HTML and WebGL

Difficulty Hard

Introduction 00:00

In this lesson, we will learn how to integrate HTML into the scene. By that, I mean to have an interactive HTML element that follows a specific 3D position on the scene, so it looks like they are part of the WebGL.

To demonstrate that, we are going to add interest points to a model. Those interest points will be made with HTML and will always stick to their associated 3D position. And because those points will be made of HTML, we will be able to design them using CSS, add interactions like :hover and add transitions.

Setup 00:26

The starter is composed of what we did in the Intro and loading progress lesson on in the Post-processing lesson with the Damaged Helmet by Leonardo Carrion.

HTML 00:48

First, let's create one HTML point. At the end of the lesson, we will add more points.

In the /src/index.html file, add the point after the <canvas> and the loading bar:

<canvas class="webgl"></canvas>

<div class="loading-bar"></div>

<div class="point point-0">
    <div class="label">1</div>
    <div class="text">Lorem ipsum, dolor sit amet consectetur adipisicing elit</div>
</div>

The text we put inside that point shouldn't be visible on the page because it's hidden behind the <canvas>.

We used the point class to be able to target all the points in CSS but also the point-0 class to target this specific element in the JavaScript. Next points will have point-1, point-2, etc.

Our point is composed of a <div> with a label class and a <div> with a text class.

The label will be the small round number that looks like it's stuck onto the model, and the text will show up when we hover that label.

CSS 02:34

We are going to add the whole CSS in one row. Usually, you would have to do it progressively, but we know where we are going.

Go to the /src/style.css file and start by positioning the point in the middle of the screen:

.point
{
    position: absolute;
    top: 50%;
    left: 50%;
}

You should see the black text in the middle of the screen. We start from the center because Three.js will provide coordinates where 0 is the center of the screen.

Let's design the label first:

.point .label
{
    position: absolute;
    top: -20px;
    left: -20px;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: #00000077;
    border: 1px solid #ffffff77;
    color: #ffffff;
    font-family: Helvetica, Arial, sans-serif;
    text-align: center;
    line-height: 40px;
    font-weight: 100;
    font-size: 14px;
}

You should see the label.

Nothing too hard here. We simply rounded the element with border-radius: 50%;, used a black background having a reduced opacity with background: #00000077;; and did the same for the border with border: 1px solid #ffffff77;. Then, we centered the white text in the middle of the element.

Let's do the same for the text:

.point .text
{
    position: absolute;
    top: 30px;
    left: -120px;
    width: 200px;
    padding: 20px;
    border-radius: 4px;
    background: #00000077;
    border: 1px solid #ffffff77;
    color: #ffffff;
    line-height: 1.3em;
    font-family: Helvetica, Arial, sans-serif;
    font-weight: 100;
    font-size: 14px;
}

You should see the text below the label.

What we achieved here is very similar to the label, but with a fixed border-radius, a specific line-height, and a padding.

Now that we have our two elements let's prepare the interactions. First, we want our text to be hidden by default.

Set its opacity to 0:

.point .text
{
   /* ... */
    opacity: 0;
}

When the .point is being hovered, we want the text to appear:

.point:hover .text
{
    opacity: 1;
}

The text should show up when the label is hovered.

Instead of this crude apparition, we want the text to fade in and out. To do so, we can use a transition.

Add the transition to the text but not just when it's hovered. This way, the transition will also occur when the cursor leaves the point:

.point .text
{
    /* ... */
    transition: opacity 0.3s;
}

The text should fade in and out.

We have a small problem. We can hover the text directly while it is invisible.

To fix that, we can deactivate the pointer events on the text. This can be done with the pointer-events CSS property:

.point .text
{
    /* ... */
    pointer-events: none;
}

The text shouldn't be "hoverable".

Currently, the cursor changes to a text selection when we hover the number in the label. To fix that, we can change the cursor on the whole label with the cursor CSS property.

.point .label
{
    /* ... */
    cursor: help;
}

A "?" should appear in place of the cursor when hovering the label.

We almost completed our work with the CSS. What we need to do now is prepare a way to show and hide the label. So, we will hide them by default and show them only when there is a visible class on the point.

To hide them, we are going to use a transform with a scale, and we will also add a transition so that the scale will be animated:

.point .label
{
    /* ... */
    transform: scale(0, 0);
    transition: transform 0.3s;
}

.point.visible .label
{
    transform: scale(1, 1);
}

The labels should be gone. But if we add the visible class directly to the element using the Developer Tools panel, we should see the label showing up.

For now, let's add the visible class directly in the HTML so that we can position the points. We will remove the class later.

<div class="point point-0 visible">

The point should now be visible.

JavaScript 20:36

Now that everything is ready in both the HTML and the CSS, we can switch to the JavaScript.

Storing the points

First, we need a way to store all the points —even if we only have one right now. We are going to use an array of objects with each object corresponding to one point.

Each point object will have two properties: the 3D position and a reference to the HTML element.

Create the points array with one point inside:

const points = [
    {
        position: new THREE.Vector3(1.55, 0.3, - 0.6),
        element: document.querySelector('.point-0')
    }
]

We used a Vector3 for the position and document.querySelector(...) to retrieve the element from the HTML.

Want to learn more?

That's the end of the free part 😔

To get access to 93 hours of video, a members-only Discord server and future updates, join us for only $95!

Next lesson

Creating a scene in Blender

How to use it 🤔

  • Download the Starter pack or Final project
  • Unzip it
  • Open your terminal and go to the unzip folder
  • Run npm install to install dependencies
    (if your terminal warns you about vulnerabilities, ignore it)
  • Run npm run dev to launch the local server
    (project should open on your default browser automatically)
  • Start coding
  • The JS is located in src/script.js
  • The HTML is located in src/index.html
  • The CSS is located in src/style.css

If you get stuck and need help, join the members-only Discord server:

Discord