Skip to content

Commit

Permalink
Add pixi example + pixi implementation + work on timeline
Browse files Browse the repository at this point in the history
  • Loading branch information
kefniark committed Feb 28, 2023
1 parent c2af9b5 commit 5c9bc65
Show file tree
Hide file tree
Showing 36 changed files with 1,048 additions and 155 deletions.
23 changes: 14 additions & 9 deletions docs/.vuepress/navbar/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,30 @@ export default navbar([
prefix: "/features/",
children: [
{
text: "Update Loop",
text: "Multiple Targets",
icon: "creative",
link: "update/",
link: "array/",
},
{
text: "Easing",
text: "Conflict Solving",
icon: "creative",
link: "easing/",
link: "conflict/",
},
{
text: "Conflict Solving",
text: "Timeline",
icon: "creative",
link: "conflict/",
link: "timeline/",
},
{
text: "Multiple Targets",
text: "Update Loop",
icon: "creative",
link: "array/",
}
link: "update/",
},
{
text: "Easing",
icon: "creative",
link: "easing/",
},
]
},
{
Expand Down
112 changes: 112 additions & 0 deletions docs/features/timeline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Timeline

When animating multiple properties, it can quickly become complicated and verbose.

To help, **Fatina** provides a way to animate properties with keyframes:

- Use absolute timing, more human focus syntax and easier to modify
- Animations data can be serialized in JSON
- Resize and merge complex animations
- Make parallel animations more readable

To make an analogy, if normal animation are equivalent to CSS transition, this feature is similar to CSS Animation.

For example all codes below are doing exactly the same thing

::: code-tabs#ts

@tab Regular API

```ts
import { animate } from 'fatina'

await Promise.all([
animate(obj).set({ opacity: 1 }).to({ opacity: 0 }, 1200).async(),
animate(obj).to({ x: 100 }, 100).to({ x: 200, y: 200 }, 400).to({ x: 0, y: 0 }, 500).delay(200).async()
])
```

@tab:active Timeline API

```ts
import { animate } from 'fatina'

await animate(obj)
.timeline({
0: { opacity: 1 },
100: { x: 100 },
500: { x: 200, y: 200 },
1000: { x: 0, y: 0 },
1200: { opacity: 0 }
})
.async()
```

@tab:active Timeline API (with merge)

```ts
import { animate, Timeline } from 'fatina'

const fade: Timeline<Sprite> = {
0: { opacity: 1 },
1200: { opacity: 0 }
}

const move: Timeline<Sprite> = {
100: { x: 100 },
500: { x: 200, y: 200 },
1000: { x: 0, y: 0 }
}

const tl = mergeTimeline(fade, move)
await animate(obj).timeline(tl).async()
```

:::

### Manipulate Timelines

If you have multiple timeline of animations, you can merge and modify them.

::: code-tabs#ts

@tab:active Merge Timelines

```ts
import { mergeTimeline } from 'fatina'

const fade = {
0: { opacity: 0 },
1000: { opacity: 1 }
}

const move = {
0: { x: 0, y: 0 },
250: { x: 250, y: 0 },
500: { x: 250, y: 250 },
750: { x: 0, y: 250 },
1000: { x: 0, y: 0 }
}

// to merge fade & fade animations
await animate(obj).timeline(mergeTimeline(fade, move)).async()
```

@tab Resize Timeline

```ts
import { resizeTimeline } from 'fatina'

const move = {
0: { x: 0, y: 0 },
250: { x: 250, y: 0 },
500: { x: 250, y: 250 },
750: { x: 0, y: 250 },
1000: { x: 0, y: 0 }
}

// to make the same animation in 600ms
await animate(obj).timeline(resizeTimeline(move, 600)).async()
```

:::
20 changes: 20 additions & 0 deletions examples/vite-esm/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
import './style.css'
import { useFatinaAuto, animate } from 'fatina'

useFatinaAuto()

const str = 'Hello World'
const div = document.createElement('div')
div.innerText = str
document.body.appendChild(div)

const div2 = document.createElement('div')
div2.classList.add('anim')
document.body.appendChild(div2)
div2.innerHTML = str
.split(' ')
.map((word, wordIndex) => {
const content = word
.split('')
.map((letter, letterIndex) => `<span class="letter" style="--letter-index:${wordIndex * 10 + letterIndex + 1}">${letter}</span>`)
.join('')
return `<span class="word" style="--word-index:${wordIndex + 1}">${content}</span>`
})
.join(' ')

const obj = { a: 0 }
animate(obj).to({ a: 100 }, 1000)
61 changes: 61 additions & 0 deletions examples/vite-esm/src/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
.anim .word {
/* animation: */
}

.anim .letter {
font-weight: 900;
font-size: 64px;
display: inline-block;
text-transform: uppercase;
transition: all 0.25s;
animation: appear 0.5s, rainbow 5s infinite;
animation-delay: calc(.1s * var(--letter-index));
animation-fill-mode: backwards;
}

@keyframes appear {
0% {
opacity: 0;
transform: translateY(100px);
}
100% {
opacity: 1;
transform: translateY(0px);
}
}

@keyframes rainbow {
0% {
color: #000000
}
10% {
color: #ff0000
}
20% {
color: #00ff00
}
30% {
color: #ffe100
}
40% {
color: #0000ff
}
50% {
color: #823994
}
60% {
color: #ff0000
}
70% {
color: #00ff00
}
80% {
color: #ffe100
}
90% {
color: #0000ff
}
0% {
color: #000000
}
}
9 changes: 9 additions & 0 deletions examples/vite-pixi/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Vite Sample

Demo of how to use **Fatina** in a Vite Project

## Usage

```sh
yarn dev
```
12 changes: 12 additions & 0 deletions examples/vite-pixi/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + TS</title>
</head>
<body>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
22 changes: 22 additions & 0 deletions examples/vite-pixi/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "fatina-pixi",
"version": "0.0.1",
"description": "",
"private": true,
"type": "module",
"license": "UNLICENSED",
"scripts": {
"dev": "vite",
"clean": "rm -rf ./node_modules ./dist",
"build": "rm -rf ./dist && vite build"
},
"devDependencies": {
"fatina": "*",
"npm-run-all": "^4.1.5",
"typescript": "^4.9.5",
"vite": "^4.1.0"
},
"dependencies": {
"pixi.js": "^7.1.3"
}
}
17 changes: 17 additions & 0 deletions examples/vite-pixi/src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
body {
padding: 0;
margin: 0;
overflow: hidden;
background: #000;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}

canvas {
min-width: 100%;
max-height: 100%;
aspect-ratio: 800 / 600;
}
66 changes: 66 additions & 0 deletions examples/vite-pixi/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import './index.css'
import { Application, Assets, Sprite } from 'pixi.js'
import { useFatinaPixi, animatePixiArray } from 'fatina'

const app = new Application()
document.body.appendChild(app.view as HTMLCanvasElement)

// load the texture we need
const texture = await Assets.load('https://pixijs.io/examples/examples/assets/bunny.png')

const bunnies: Sprite[] = []
for (let i = 0; i < 60; i++) {
// This creates a texture from a 'bunny.png' image
const bunny = new Sprite(texture)

// Setup the position of the bunny
bunny.x = app.renderer.width / 2
bunny.y = app.renderer.height / 2

// Rotate around the center
bunny.anchor.x = 0.5
bunny.anchor.y = 0.5

// Add the bunny to the scene we are building
app.stage.addChild(bunny)
bunnies.push(bunny)
}

useFatinaPixi(app)

async function animateBunnies() {
const points: { x: number; y: number }[] = []
for (let i = 0; i < 6; i++) {
points.push({ x: (800 - 40) * Math.random() + 20, y: (600 - 40) * Math.random() + 20 })
}

const animation = animatePixiArray([...bunnies].reverse())
animation.foreach((anim, i) => {
// handle fade-in and fade-out
anim.clone()
.delay(i * 50)
.timeline({
0: { alpha: 0.1 },
500: { alpha: 1 },
3500: { alpha: 1 },
4000: { alpha: 0.1 }
})

// each bunny wait a bit before starting
anim.delay(i * 50)

// then move through the points
for (const point of points) {
anim.move(point, 4000 / points.length)
}
})

await animation.async()
}

;(async () => {
// eslint-disable-next-line no-constant-condition
while (true) {
await animateBunnies()
}
})()
1 change: 1 addition & 0 deletions examples/vite-pixi/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
19 changes: 19 additions & 0 deletions examples/vite-pixi/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ESNext", "DOM"],
"moduleResolution": "Node",
"strict": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"skipLibCheck": true
},
"include": ["src"]
}

0 comments on commit 5c9bc65

Please sign in to comment.