title | excerpt |
---|---|
With HTML/SVG |
How to get started animating HTML elements directly with Theatre.js. This tutorial doesn't require any knowledge beyond HTML + JavaScript.
|
export const htmlFileNameString = 'animation-tutorial.html'
export const htmlFileNameJSX = {htmlFileNameString}
export const htmlFilePreview = (children) => (
Preview {htmlFileNameJSX}
{children}In this tutorial, we will:
- Show the Theatre.js Studio UI on a simple HTML page
- Create a new Theatre.js Project which will control JavaScript values on the page
- Use Theatre.js to animate UI elements on our page
- Create a production (publishable) version of our Project we can share with users, collaborators, or friends
Let's start by creating a basic HTML file called {htmlFileNameJSX}. Below is a starter HTML file. It only contains the basic tags an HTML page should have, nothing Theatre.js specific yet.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Theatre.js Tutorial</title>
<style>
body {
margin: 0;
color: white;
background: black;
font-family: sans-serif;
}
</style>
</head>
<body>
<h1 id="article-heading" style="text-align: center">Welcome</h1>
<script type="module">
// mark
// Add JavaScript here
</script>
</body>
</html>
If we've saved the above HTML in a file called {htmlFileNameJSX} and open that file in our browser, it results in a Welcome page that looks like the following:
To add functionality to our static HTML page, we should first set up our Theatre.js Project.
Let's add the following JS into the <script>
towards the bottom of the HTML where it says // Add JavaScript here
:
import 'https://cdn.jsdelivr.net/npm/@theatre/browser-bundles@0.5.0-insiders.88df1ef/dist/core-and-studio.js'
// We can now access Theatre.core and Theatre.studio from here
const { core, studio } = Theatre
studio.initialize() // Start the Theatre.js UI
Now when we open / refresh the Welcome page in our browser, we should see the Theatre.js Studio on top of the HTML Welcome page. There's an "Outline Menu" button in the top left of the page and a "..." menu and "Property Editor" button in the top right:
In this tutorial, we use the `@theatre/browser-bundles` package imported via a CDN to make it easier to get started! There are other ways of importing Theatre.js using a bundler like WebPack or ESBuild.Now that we've gotten the Studio to appear, let's create a Theatre.js Project called 'HTML Animation Tutorial' containing a Sheet called 'Sheet 1' and an Object called 'Heading 1' with props "y" and "opacity":
const project = core.getProject('HTML Animation Tutorial')
const sheet = project.sheet('Sheet 1')
const obj = sheet.object('Heading 1', {
y: 0, // you can use just a simple default value
opacity: core.types.number(1, { range: [0, 1] }), // or use a type constructor to customize
})
Now we should see HTML Animation Tutorial > Sheet 1: Default > Heading 1
under the
"Outline Menu" button in the top left of our page.
We've just configured our Theatre.js Project structure, but if we try to change any values in the Details Panel on the right, they will not yet change any part of the original HTML Welcome page.
Next, let's ensure the values in Theatre.js are applied to our page's elements.
We can call the Object.onValuesChange method on obj
to listen to the value changes on our Object.
const articleHeadingElement = document.getElementById('article-heading')
obj.onValuesChange((obj) => {
articleHeadingElement.style.transform = `translateY(${obj.y}px)`
articleHeadingElement.style.opacity = obj.opacity
})
Now that our code synchronizes Theatre.js with the articleHeadingElement
's style,
try dragging or clicking on the number beside "y" or "opacity" in the Details Panel
on the right in the preview below.
The "Welcome" element you see moving around and fading in and out should behave like in the video below.
Now that we have set up our Project, let's go ahead and use the Studio to create an animation. In Theatre.js, an animation consists of a set of "Sequenced" props with "Keyframes".
First, let's try Sequencing the "y" prop and adding keyframes to it. Check the video below to see how we can sequence a prop.
Now that we've sequenced a prop and added keyframes, we can play back the resulting animation in our browser.
But the animation is, so far, only stored in your browser's local data (in localStorage
).
To share the animation with others (or include it on a website), we have to export the animation state and initialize our Theatre.js project with it.
We'll look at that in the next section.
Now that we've created a basic animation locally, we want to share it with the world! So, here's a checklist for what we need to do to share our animation / include it on a webpage.
Production (published webpage) animation checklist:
-
Export the Project's
state.json
by clicking the Project ("HTML Animation Tutorial") in the outline panel on the left and then click the "Export HTML Animation Tutorial to JSON" in the panel on the right. A file download forstate.json
should start in your browser. -
Open
state.json
in a text editor and copy its contents into your JavaScript code as a value stored in aprojectState
variable (if you use a bundler, it's possible to import thestate.json
file directly). -
In the part of the code where you created the Theatre.js Project, modify it to include your animation state like so:
const project = core.getProject('HTML Animation Tutorial', { state: projectState, })
-
Remove Studio imports
a. for simple projects using
@theatre/browser-bundles
, remove thecore-and-studio.js
part of the import URL, and replace it withcore-only.min.js
.b. for projects directly importing from
@theatre/studio
(using a bundler), don't import Studio for your production builds. -
Remove all
Theatre.studio.initialize()
calls so that the animation shows, but the Studio UI does not. -
Add some code that plays the animation! Here's some code that plays 6 seconds of the animation and loops it as soon as it has loaded:
project.ready.then(() => { sheet.sequence.play({ iterationCount: Infinity, range: [0, 6] }) })
The following shows our production HTML version of {htmlFileNameJSX} which applies the above and uses a project JSON state the author designed while writing this tutorial.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Theatre.js Tutorial</title>
<style>
body {
margin: 0;
color: white;
background: black;
font-family: sans-serif;
}
</style>
</head>
<body>
<h1 id="article-heading" style="text-align: center">Welcome</h1>
<script type="module">
// only import core
import 'https://cdn.jsdelivr.net/npm/@theatre/browser-bundles@0.5.0-insiders.88df1ef/dist/core-only.min.js'
// We can now access just Theatre.core from here
const articleHeadingElement = document.getElementById('article-heading')
// Exported by clicking the project name and "Export Project Name to JSON" button.
const projectState = {
sheetsById: {
'Sheet 1': {
staticOverrides: {
byObject: {
'Heading 1': {
opacity: 0.9936708860759493,
},
},
},
sequence: {
subUnitsPerUnit: 30,
length: 10,
type: 'PositionalSequence',
tracksByObject: {
'Heading 1': {
trackData: {
LrJ3eujCAE: {
type: 'BasicKeyframedTrack',
keyframes: [
{
id: 'i-s2GT5JFm',
position: 0,
connectedRight: true,
handles: [0.5, 1, 0.882, 0],
value: 0,
},
{
id: 'I3Suv35jmV',
position: 3.433,
connectedRight: true,
handles: [0.055, 0.969, 0.82, -0.031],
value: 96,
},
{
id: 'M_00uVAeuK',
position: 5.6,
connectedRight: true,
handles: [0.087, 1.01, 0.5, 0],
value: 0,
},
],
},
'9JzZUrUSb7': {
type: 'BasicKeyframedTrack',
__debugName: 'Heading 1:["opacity"]',
keyframes: [
{
id: 'EfAPcjrYAy',
position: 0,
connectedRight: true,
handles: [0.5, 1, 0.5, 0],
value: 0.9936708860759493,
},
{
id: 'hZ-tUkMP4C',
position: 2.367,
connectedRight: true,
handles: [0.5, 1, 0.5, 0],
value: 0,
},
{
id: 'D5PA_XGfS6',
position: 5.6,
connectedRight: true,
handles: [0.5, 1, 0.5, 0],
value: 0.9936708860759493,
},
],
},
},
trackIdByPropPath: {
'["y"]': 'LrJ3eujCAE',
'["opacity"]': '9JzZUrUSb7',
},
},
},
},
},
},
definitionVersion: '0.4.0',
revisionHistory: ['vLg01lxRrpP8eGsS'],
}
const { core } = Theatre
// We don't need studio in production
// studio.initialize()
const project = core.getProject('HTML Animation Tutorial', {
state: projectState,
})
const sheet = project.sheet('Sheet 1')
const obj = sheet.object('Heading 1', {
y: 0,
opacity: core.types.number(1, { range: [0, 1] }),
})
// animations
obj.onValuesChange((obj) => {
articleHeadingElement.style.transform = `translateY(${obj.y}px)`
articleHeadingElement.style.opacity = obj.opacity
})
// wait for project to be ready
project.ready.then(() => {
sheet.sequence.play({ iterationCount: Infinity, range: [0, 6] })
})
</script>
</body>
</html>
And here's the final product.
<TheatreTutorialCodePreview filename={'production-' + htmlFileNameString} />
Want to learn more ways to use Theatre.js? Check out another getting started guide:
<ChildCards urlPath="/docs/0.5/getting-started" exclude={(n) => n.urlPath.includes('with-html-svg')} />
Also, take a look at some more in-depth topics from our manual: