2 Commits

Author SHA1 Message Date
Alex Fox
7e019fd335 Updated readme to point to lax.js urls 2020-05-11 11:24:54 +01:00
Alex Fox
7fc92ed6c9 Added lax 2.0 link 2020-05-07 18:00:43 +01:00
66 changed files with 3352 additions and 4397 deletions

View File

@@ -1,8 +1,3 @@
{
"presets": [
"@babel/preset-env"
],
"plugins": [
"@babel/plugin-proposal-class-properties"
]
}
"presets": ["@babel/preset-env"]
}

View File

@@ -1,17 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**lax.js version**
Please note, only bugs in v2.0 or later will be fixed.
**Describe the bug**
A clear and concise description of what the bug is.
**Code**
Please provide a link to a repo or code example of the issue in question.

View File

@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

1
.gitignore vendored
View File

@@ -1,3 +1,2 @@
node_modules/
.DS_Store
LaxLogo.sketch

1
.npmignore Normal file
View File

@@ -0,0 +1 @@
.babelrc

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2020 Alex Fox
Copyright (c) 2019 Alex Fox
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

549
README.md
View File

@@ -1,366 +1,299 @@
# lax.js
Simple & lightweight (<4kb gzipped) vanilla JavaScript library to create smooth & beautiful animations when you scroll.
Simple & light weight (<3kb gzipped) vanilla javascript plugin to create *smooth* & beautiful animations when you scrolllll! Harness the power of the most intuitive interaction and make your websites come alive!
![Lax 2.0 Gif](https://i.imgur.com/XNvvAOv.gif)
[>>> DEMO <<<](https://alexfox.dev/lax.js/)
[>> DEMO <<](https://alexfox.dev/lax.js/)
![](https://i.imgur.com/Jbkna80.gif)
[>>> MARIO DEMO <<<](https://alexfox.dev/lax.js/sprite.html)
![](https://i.imgur.com/GGQFucZ.gif)
---
## What's new with Lax.js 2.0
Lax.js 2.0 has been completely re-written with a focus on modularity and flexibility giving you more tools to create awesome animations.
- New javascript animation syntax, allowing for more advanced effect combos
- Use any value to drive animations, for example mouse position, time of day .. and of course scroll!
- Animations can be given inertia when scrolling
- Create custom CSS bindings
- Animation easings
- And much more..
## Examples
- [Scroll effect](https://alexfox.dev/lax.js/examples/scroll)
- [Horizontal snap scroll](https://alexfox.dev/lax.js/examples/snap-scroll)
- [Inertia](https://alexfox.dev/lax.js/examples/inertia)
- [Video/Gif playback](https://alexfox.dev/lax.js/examples/sprite)
- [Cursor position](https://alexfox.dev/lax.js/examples/cursor)
- [Text input](https://alexfox.dev/lax.js/examples/input)
- [Update HTML content](https://alexfox.dev/lax.js/examples/on-update)
- [Preset Explorer](https://alexfox.dev/lax.js/preset-explorer)
## lax 2.0
For those daring enough ;) there is an alpha version of lax.js 2.0 available. Have a play: https://github.com/alexfoxy/lax.js/tree/version-2
---
# Documentation
### 1. Getting started
- [Setup](#setup)
- [Using presets](#using-presets)
- [Usage with UI frameworks](#dom-behavior-and-usage-with-frameworks)
- [Adding drivers](#adding-drivers)
- [Adding elements](#adding-elements)
### 2. Going deeper
- [Custom animations](#custom-animations)
- [Optimising performance](#optimising-performance)
### 3. Glossary
- [CSS properties](#css-properties)
- [Special values](#special-values)
- [Supported easings](#supported-easings)
# Getting started
## Getting Started
### NPM Setup
```bash
# https://www.npmjs.com/package/lax.js
npm install lax.js
yarn add lax.js
```
```js
import lax from 'lax.js'
```
### HTML setup
### Basic Browser Setup
1) Add lax.js to your html
```html
<script src="path-to-lax.min.js"></script>
<script src="lib/lax.min.js" >
<!-- or via CDN -->
<script src="https://cdn.jsdelivr.net/npm/lax.js" ></script>
```
2) Initialize the plugin
## Setup
```javascript
window.onload = function() {
lax.setup() // init
To implement lax you need to create at least one _driver_, to provide values for animations, as well as the element animation bindings. Below is a simple example:
const updateLax = () => {
lax.update(window.scrollY)
window.requestAnimationFrame(updateLax)
}
window.requestAnimationFrame(updateLax)
}
```
3) Add class and attributes to the HTML tags you want to animate e.g.
```html
<!-- JS -->
<script>
window.onload = function () {
lax.init()
// Add a driver that we use to control our animations
lax.addDriver('scrollY', function () {
return window.scrollY
})
// Add animation bindings to elements
lax.addElements('.selector', {
scrollY: {
translateX: [
["elInY", "elCenterY", "elOutY"],
[0, 'screenWidth/2', 'screenWidth'],
]
}
})
}
</script>
<!-- HTML -->
<div class="selector">Hello</div>
<p class="lax" data-lax-preset="spin fadeInOut">Look at me goooooo!</p>
```
## Using presets
4) Scroll and enjoy!
The easiest way to get started is to use presets via html classes. For example:
### Usage With React, Vue.js, EmberJS & DOM Changes
To increase performance lax.js indexes the list of elements to animate when the page loads. If you're using a library like React, vue.js or EmberJS, it is likely that you are adding elements after the initial `window.onload`. Because of this you will need to call `lax.addElement(domElement)` when you add components to the DOM that you want to animate.
See below for working examples:
* [react](https://codepen.io/alexfoxy/pen/PLaKaE)
* [react (using hooks)](https://github.com/arthurdenner/use-lax)
* [vue](https://codepen.io/alexfoxy/pen/ZPRZBq)
* [ember](https://github.com/redpencilio/ember-lax)
You can also call `lax.removeElement(domElement)` when the component unmounts.
## Presets
The easiest way to get started is to use the presets via the `data-lax-preset` attribute. You can chain multiple presets together for e.g. `data-lax-preset="blurOut fadeOut spin"`. Some presets also support an optional strength e.g. `data-lax-preset="blurOut-50"`.
See the list of [Supported Presets](#supported-presets) for details.
## Custom Animations
You can easily create your own effects. Just add an attribute to your HTML tag (see [Supported Attribute Keys](#supported-attribute-keys)) with an array of values. These arrays take the format of `scrollPos val, scrollPos val, ... | option=val` e.g:
```html
<div class="lax lax_preset_fadeIn:50:100 lax_preset_spin"></div>
<p class="lax" data-lax-opacity="0 1, 100 1, 200 0 | loop=200">
I start to fade out after the window scrolls 100px
and then I'm gone by 200px!
</p>
```
Multiple presets can be chained together and they can be customised to suit your needs. Use the [preset explorer](https://alexfox.dev/lax.js/preset-explorer) to explore effects and see a simple example [here](https://alexfox.dev/lax.js/html-inline).
## DOM behavior and usage with Frameworks
To increase performance, `lax.js` indexes the list of elements to animate when the page loads. If you're using a library like React, Vue or EmberJS, it is likely that you are adding elements after the initial window.onload. Because of this you will need to call `lax.addElements` when you add components to the DOM that you want to animate, and `lax.removeElements` when the component unmounts.
Please find a React example [here](https://codesandbox.io/s/laxjs-react-example-nc4h7). Other examples will be available soon for Vue.js and Angular.
## Adding drivers
Drivers provide the values that _drive_ your animations. To set up a driver just call `lax.addDriver` with a name and a function which returns a number. This method is called every frame to calculate the animations so keep the method as computationally _light_ as possible. The example below will be the most common use case for lax which returns the scrollY position of the window.
```javascript
lax.addDriver(
'scrollY', // Driver name
function(laxFrame) {
return window.scrollY // Value method
},
{ } // Options
)
By default the `scrollPos` is `window.scrollY` but you can use an element distance from the top of the screen instead. You can either pass in a selector `data-lax-anchor="#bio"` or set it to use itself `data-lax-anchor="self"` (this is the default for all presets) e.g.
```html
<p class="lax" data-lax-opacity="200 1, 100 1, 0 0" data-lax-anchor="self">
I start to fade out after I'm 100px away from the top of the window
and then I'm gone by the time I reach the top!
</p>
```
### Driver options
### Special Values
#### `inertiaEnabled: boolean = false`
| Key | Value |
| ------------- | ------------- |
| vw | window.innerWidth |
| vh | window.innerHeight |
| elw | targetElement.clientWidth |
| elh | targetElement.clientHeight |
If enabled, the driver will calculate the speed at which its value is changing. Used to add inertia to elements using the [inertia element option](#inertia-number).
See this in action in the [here](https://alexfox.dev/lax.js/examples/inertia).
#### `frameStep: number = 1`
By default each driver updates its value every animation frame, around ~60 times per second. You can use the `frameStep` to reduce frequency of the driver value updating. For example a value of `2` would only update ~30 times per second and a value of `60` would only update about once per second.
## Adding elements
You can add lax animations to an element using the `addElements` method:
```javascript
lax.addElements(
'.selector', // Element selector rule
{ // Animation data
scrollY: {
opacity: [
[0, 100],
[1, 0]
]
}
},
{
style: {} // Element options
}
)
You can use these instead of integer values for the scrollPos e.g.
```html
<p class="lax" data-lax-opacity="0 1, vh 0">
I fade out as the page scrolls down and
I'm gone when the page has scrolled the view port height!
</p>
```
### Element options
### Calculated Values
#### `style: StyleObject`
Add static CSS to each element, for example:
```css
{
transform: '200ms scale ease-in-out';
}
```
#### `onUpdate: (driverValues: Object, domElement: DomElement) => void`
A method called every frame with the current driverValues and domElement. This could be used to toggle classes on an element or set innerHTML. See it in action [here](https://alexfox.dev/lax.js/examples/on-update).
The driver values are formatted as follows:
```js
{
scrollY: [ // Driver name
100, // Driver value
0 // Driver inertia
]
}
```
# Going deeper
## Custom animations
Custom animations are defined using an object.
```javascript
// Animation data
{
scrollY: { // Driver name
translateX: [ // CSS property
['elInY', 'elOutY'], // Driver value map
[0, 'screenWidth'], // Animation value map
{
inertia: 10 // Options
}
],
opacity: [
// etc
]
}
}
```
### Driver name
The name of the driver you want to use as a source of values to map to your animation, for example, the document's scrollY position. Read about adding drivers [here](#adding-drivers).
### CSS property
The name of the CSS property you want to animate, for example `opacity` or `rotate`. See a list of supported properties [here](#css-properties).
> Some CSS properties, for example `box-shadow`, require a custom function to build the style string. To do this use the [cssFn](#cssfn-value-number--string) element option.
### Value maps
The value maps are used to interpolate the driver value and output a value for your CSS property. For example:
```javascript
[0, 200, 800] // Driver value map
[0, 10, 20] // Animation value map
// Result
| In | Out |
| --- | --- |
| 0 | 0 |
| 100 | 5 |
| 200 | 10 |
| 500 | 15 |
| 800 | 20 |
```
Within the maps you can use strings for simple formulas as well as use special values. e.g:
```javascript
['elInY', 'elCenterY-200', 'elCenterY',
```
See a list of available values [here](#special-values).
You can also use mobile breakpoints within animation maps for more flexibility.
```javascript
scrollY: {
translateX: [
['elInY', 'elCenterY', 'elOutY'],
{
500: [10, 20, 50], // Screen width < 500
900: [30, 40, 60], // Screen width > 500 and < 900
1400: [30, 40, 60], // Screen width > 900
},
];
}
You can also use vanilla JS within `( )` for calculations and access to more variables e.g.
```html
<p class="lax" data-lax-opacity="0 1, (document.body.scrollHeight*0.5) 0">
I fade out as the page scrolls down and
I'm gone when the page has scrolled 50%
down the entire page height!
</p>
```
### Options
#### `modValue: number | undefined`
Set this option to modulus the value from the driver, for example if you want to loop the animation value as the driver value continues to increase.
You can pass options into your custom animations for more control e.g.
#### `frameStep: number = 1`
By default each animation updates its value every animation frame, around ~60 times per second. You can use the `frameStep` to reduce frequency of the animation updating. For example a value of `2` would only update ~30 times per second and a value of `60` would only update about once per second.
#### `inertia: number`
Use to add inertia to your animations. Use in combination with the [inertiaEnabled](#inertiaenabled-boolean--false) driver option.
See inertia in action [here](https://alexfox.dev/lax.js/examples/inertia).
#### `inertiaMode: "normal" | "absolute"`
Use in combination with `inertia`. If set to `absolute` the inertia value will always be a positive number via the `Math.abs` operator.
#### `cssUnit: string = ""`
Define the unit to be appended to the end of the value, for example
For example `px` `deg`
#### `cssFn: (value: number, domElement: DomElement) => number | string`
Some CSS properties require more complex strings as values. For example, `box-shadow` has multiple values that could be modified by a lax animation.
```javascript
// Box-shadow example
(val) => {
return `${val}px ${val}px ${val}px rgba(0,0,0,0.5)`;
};
```html
<p class="lax" data-lax-opacity="0 1, 100 0, 200 100 | loop=200 offset=100 speed=2">
I start at 0 opacity and
fade in and out every 50px
</p>
```
#### `easing: string`
See a list of available values [here](#supported-easings).
| Option | Effect |
| ------------- | ------------- |
| loop | modulus the input scrollY position so the animation will loop every `loop` pixels |
| offset | add `offset` to scrollY position so the animation will begin at this point |
| speed | multiplies the input scrollY position by `speed` to change the speed of the animation |
## Optimising performance
Lax.js has been designed to be performant but there are a few things to bare in mind when creating your websites.
- Smaller elements perform better.
- Postion `fixed` and `absolute` elements perform best as they do not trigger a layout change when updated.
- Off-screen elements do not need to be updated so consider that when creating your animation value maps.
- The css properties `blur`, `hue-rotate` and `brightness` are graphically intensive and do not run as smoothly as the other available properties.
# Glossary
## Responsive Design
You can set multiple presets and animations for different screen widths. When setting up lax you need to pass in your screen width breakpoints e.g.
```javascript
lax.setup({
breakpoints: { small: 0, large: 992 }
})
```
Then you can define presets or transforms per breakpoint.
```html
<p class="lax" data-lax-preset_small="spin">
I only spin when the screen is smaller than 992px.
</p>
## CSS properties
<p class="lax" data-lax-scale_small="0 1, 500 0" data-lax-scale_large="0 1, 500 2">
I shrink when the screen is smaller than 992px but grow when the screen is larger 992px.
</p>
```
| name |
| ---------- |
| opacity |
| scaleX |
| scaleY |
| scale |
| skewX |
| skewY |
| skew |
| rotateX |
| rotateY |
| rotate |
| translateX |
| translateY |
| translateZ |
| blur |
| hue-rotate |
| brightness |
## Supported Presets
## Special values
| Preset | Default Strength |
| ------------- | ------------- |
| linger | n/a |
| lazy | 100 |
| eager | 100 |
| lazy | 100 |
| slalom | 50 |
| crazy | n/a |
| spin | 360 |
| spinRev | 360 |
| spinIn | 360 |
| spinOut | 360 |
| blurInOut | 40 |
| blurIn | 40 |
| blurOut | 40 |
| fadeInOut | n/a |
| fadeIn | n/a |
| fadeOut | n/a |
| driftLeft | 100 |
| driftRight | 100 |
| leftToRight | 1 |
| rightToLeft | 1 |
| zoomInOut | 0.2 |
| zoomIn | 0.2 |
| zoomOut | 0.2 |
| swing | 30 |
| speedy | 30 |
| key | value |
| ------------ | -------------------------------------------------------------------------------- |
| screenWidth | current width of the screen |
| screenHeight | current height of the screen |
| pageWidth | width of the document |
| pageHeight | height of the document |
| elWidth | width of the element |
| elHeight | height of the element |
| elInY | window scrollY position when element will appear at the bottom of the screen |
| elOutY | window scrollY position when element will disappear at the top of the screen |
| elCenterY | window scrollY position when element will be centered vertically on the screen |
| elInX | window scrollX position when element will appear at the right of the screen |
| elOutX | window scrollX position when element will disappear at the left of the screen |
| elCenterX | window scrollX position when element will be centered horizontally on the screen |
| index | index of the element when added using `lax.addElements` |
## Supported Attribute Keys
## Supported easings
Transforms
| Transform | Key |
| ------------- | ------------- |
| opacity | data-lax-opacity |
| translate | data-lax-translate |
| translateX | data-lax-translate-x |
| translateY | data-lax-translate-y |
| scale | data-lax-scale |
| scaleX | data-lax-scale-x |
| scaleY | data-lax-scale-y |
| skew | data-lax-skew |
| skewX | data-lax-skew-x |
| skewY | data-lax-skew-y |
| rotate | data-lax-rotate |
| rotateX | data-lax-rotate-x |
| rotateY | data-lax-rotate-y |
Filters (note - these may be unperformant on low powered machines)
| Filter | Key |
| ------------- | ------------- |
| brightness | data-lax-brightness |
| contrast | data-lax-contrast |
| hue-rotate | data-lax-hue-rotate |
| blur | data-lax-blur |
| invert | data-lax-invert |
| saturate | data-lax-saturate |
| grayscale | data-lax-grayscale |
Other
| Filter | Key |
| ------------- | ------------- |
| background position | data-lax-bg-pos |
| background position-x | data-lax-bg-pos-x |
| background position-y | data-lax-bg-pos-y |
## Sprite Sheet Animations
You can create animations using sprite sheets. See a demo [here](https://alexfox.dev/lax.js/sprite.html).
The `data-lax-sprite-data` is required and formated like so `[frameWidth, frameHeight, frameCount, columnCount, scrollStep]`. You can either set the image using CSS or the `data-lax-sprite-image` attribute. e.g.
```html
<div
class="lax"
data-lax-sprite-data="500,500,36,36,10"
data-lax-sprite-image="./spritesheet.png"
/>
```
You can turn a gif or a video into a sprite sheet with this tool: https://ezgif.com/gif-to-sprite
Note: current implimentation requires the element to be the same size as the frame width & height.
## Custom Presets
To avoid duplicate code you can define your own presets with a list of attributes e.g.
```javascript
lax.addPreset("myCoolPreset", function() {
return {
"data-lax-opacity": "(-vh*0.8) 40, (-vh*0.6) 0",
"data-lax-rotate": "(-vh*2) 1000, (-vh*0.5) 0"
}
})
```
You can then access this preset like this:
```html
<p class="lax" data-lax-preset="myCoolPreset">
I'm the coolest preset in the world 😎
</p>
```
## Performance Tips
* Avoid nesting lax enabled elements within each other, you'll get better performance using lax with smaller elements in the dom tree.
* Avoid transforms on large elements, e.g. full screen backgrounds.
* By default elements that have opacity 0 aren't updated. You can either manually set up a `data-lax-opacity` to control this yourself or use `data-lax-optimize` which will set the elements opacity to 0 when it goes off -screen.
* By default `-webkit-backface-visibility: hidden;` is added to your elements style to encourage the browser to render that object as a layer on the GPU and increase performance. To turn this off add `data-lax-use-gpu="false"` to your element.
## Notes
### Screen Rotating & Resizing
As some values (vh, vw, elh, elw) are calculated on load, when the screen size changes or rotates you might want to recalculate these. E.g.
```
window.addEventListener("resize", function() {
lax.updateElements()
});
```
Be warned, on mobile, a resize event is fired when you scroll and the toolbar is hidden so you might want to check if the width or orientation has changed.
### Scroll Wheels
Scroll wheels only increment the scroll position in steps which can cause the animations to look janky.
### Merging Existing Styles
Only inline styles for transforms and filters will be merged in to the animation. Transforms and filters derived from CSS will be overwritten.
## To Do / Ideas
* Implement a tween for scroll wheels to remove reliance on smoothscroll
* A way to add weight/momentum to moving objecs
* More cool demos
* More concise read me for react / vue.js
* ~~Support for sprite sheet animations~~
| name |
| -------------- |
| easeInQuad |
| easeOutQuad |
| easeInOutQuad |
| easeInCubic |
| easeOutCubic |
| easeInOutCubic |
| easeInQuart |
| easeOutQuart |
| easeInOutQuart |
| easeInQuint |
| easeOutQuint |
| easeInOutQuint |
| easeOutBounce |
| easeInBounce |
| easeOutBack |
| easeInBack |

0
changelog Normal file
View File

69
dev/inertia.html Normal file
View File

@@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=0.75, maximum-scale=0.75, minimum-scale=0.75">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,600,800" rel="stylesheet">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<script src="./lib/lax.min.js"></script>
<!-- <script src="../src/lax.js"></script> -->
<script type="text/javascript">
window.onload = function() {
document.getElementById("main").classList.add("loaded")
lax.setup()
let toAdd = 0
let lastY = 0
const scrolls = [0,0,0,0,0]
const update = () => {
scrolls.unshift()
if(lastY !== window.scrollY) scrolls.push(window.scrollY)
lastY = window.scrollY
const sum = scrolls.reduce(function(a, b) { return a + b; });
const y = sum / scrolls.length
lax.update(y)
window.requestAnimationFrame(update)
}
window.requestAnimationFrame(update)
}
</script>
<style>
body,html {
margin:0;
padding:0;
color: #F3F4F5;
background: #191818;
overflow-x: hidden;
height: 10000vh;
font-family: 'Montserrat', sans-serif;
}
#letter {
width: 10vw;
margin-left: 10vw;
position: fixed;
top: 20vh;
}
</style>
</head>
<body>
<div id="main">
<div id="header" class="section">
<img src="./img/a.png" id="letter" data-lax-translate-x="0 0, 1000 1000" />
</div>
</div>
</body>

5
dev/js/stats.js Normal file
View File

@@ -0,0 +1,5 @@
// stats.js - http://github.com/mrdoob/stats.js
(function(f,e){"object"===typeof exports&&"undefined"!==typeof module?module.exports=e():"function"===typeof define&&define.amd?define(e):f.Stats=e()})(this,function(){var f=function(){function e(a){c.appendChild(a.dom);return a}function u(a){for(var d=0;d<c.children.length;d++)c.children[d].style.display=d===a?"block":"none";l=a}var l=0,c=document.createElement("div");c.style.cssText="position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000";c.addEventListener("click",function(a){a.preventDefault();
u(++l%c.children.length)},!1);var k=(performance||Date).now(),g=k,a=0,r=e(new f.Panel("FPS","#0ff","#002")),h=e(new f.Panel("MS","#0f0","#020"));if(self.performance&&self.performance.memory)var t=e(new f.Panel("MB","#f08","#201"));u(0);return{REVISION:16,dom:c,addPanel:e,showPanel:u,begin:function(){k=(performance||Date).now()},end:function(){a++;var c=(performance||Date).now();h.update(c-k,200);if(c>g+1E3&&(r.update(1E3*a/(c-g),100),g=c,a=0,t)){var d=performance.memory;t.update(d.usedJSHeapSize/
1048576,d.jsHeapSizeLimit/1048576)}return c},update:function(){k=this.end()},domElement:c,setMode:u}};f.Panel=function(e,f,l){var c=Infinity,k=0,g=Math.round,a=g(window.devicePixelRatio||1),r=80*a,h=48*a,t=3*a,v=2*a,d=3*a,m=15*a,n=74*a,p=30*a,q=document.createElement("canvas");q.width=r;q.height=h;q.style.cssText="width:80px;height:48px";var b=q.getContext("2d");b.font="bold "+9*a+"px Helvetica,Arial,sans-serif";b.textBaseline="top";b.fillStyle=l;b.fillRect(0,0,r,h);b.fillStyle=f;b.fillText(e,t,v);
b.fillRect(d,m,n,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d,m,n,p);return{dom:q,update:function(h,w){c=Math.min(c,h);k=Math.max(k,h);b.fillStyle=l;b.globalAlpha=1;b.fillRect(0,0,r,m);b.fillStyle=f;b.fillText(g(h)+" "+e+" ("+g(c)+"-"+g(k)+")",t,v);b.drawImage(q,d+a,m,n-a,p,d,m,n-a,p);b.fillRect(d+n-a,m,a,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d+n-a,m,a,g((1-h/w)*p))}}};return f});

66
dev/performance.html Normal file
View File

@@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=0.75, maximum-scale=0.75, minimum-scale=0.75">
<script src="../src/lax.js"></script>
<script src="./js/stats.js"></script>
<script type="text/javascript">
window.onload = function() {
var stats = new Stats();
stats.showPanel( 0 ); // 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild( stats.dom );
for(let i=0; i<1000; i++) {
const el = document.createElement("img")
el.src="../docs/img/a.png"
el.className="lax"
el.style.width = 50 + 'px'
el.style.height = 50 + 'px'
el.style.left = 50*(i%25) + 'px'
el.style.top = 50*Math.floor(i/25) + 'px'
el.style.position = "absolute"
el.setAttribute("data-lax-rotate","0 0, 500 1000")
el.setAttribute("data-lax-opacity","0 1, 500 0")
el.setAttribute("data-lax-scale","0 1, 500 0.5")
document.body.appendChild(el)
}
lax.setup()
let i = 0
const update = () => {
stats.begin();
lax.update(i%500)
i++
stats.end();
window.requestAnimationFrame(update)
}
window.requestAnimationFrame(update)
}
</script>
<style>
body,html {
margin:0;
padding:0;
color: #F3F4F5;
background: #191818;
overflow-x: hidden;
height: 500vh;
font-family: 'Montserrat', sans-serif;
}
img {
position: fixed;
}
</style>
</head>
<body>
</body>

90
dev/reactive.html Normal file
View File

@@ -0,0 +1,90 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=0.75, maximum-scale=0.75, minimum-scale=0.75">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,600,800" rel="stylesheet">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<!-- <script src="./lib/lax.min.js"></script> -->
<script src="../src/lax.js"></script>
<script type="text/javascript">
window.onload = function() {
document.getElementById("main").classList.add("loaded")
lax.setup({
breakpoints: { xs: 0, s: 576, m: 768, l: 992 }
})
const update = () => {
lax.update(window.scrollY)
window.requestAnimationFrame(update)
}
window.requestAnimationFrame(update)
let w = window.innerWidth
window.addEventListener("resize", function() {
if(w !== window.innerWidth) {
lax.populateElements()
}
});
}
</script>
<style>
body,html {
margin:0;
padding:0;
color: #F3F4F5;
background: #191818;
overflow-x: hidden;
height: 500vh;
font-family: 'Montserrat', sans-serif;
}
#main {
opacity: 0;
transition: opacity 200ms;
}
#main.loaded {
opacity: 1;
}
#header {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100vw;
z-index: 2;
height: 100vh;
}
#header img {
width: 78pt;
margin-top: 12pt;
position: fixed;
transform: scale(0.5)
}
</style>
</head>
<body>
<div id="main">
<div id="header" class="section">
<img src="./img/a.png"
class="lax"
data-lax-scale="0 1, vh 5"
data-lax-scale_s="0 1, vh 1"
data-lax-preset_s="fadeInOut"
data-lax-scale_xs="0 1, vh 0"
/>
</div>
</div>
</body>

64
dev/smoothscroll.html Normal file
View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=0.75, maximum-scale=0.75, minimum-scale=0.75">
<!-- <script src="./lib/lax.min.js"></script> -->
<script src="../src/lax.js"></script>
<script type="text/javascript">
window.onload = function() {
document.getElementById("main").classList.add("loaded")
lax.setup()
let scrollPosTarget = 0
let currentVal = 0
const maxStep = 10
const update = () => {
if(scrollPosTarget != window.scrollY) {
scrollPosTarget = window.scrollY
}
const d = scrollPosTarget - currentVal
currentVal += Math.abs(d) > maxStep ? (d > 0 ? maxStep : -maxStep) : d
lax.update(currentVal)
window.requestAnimationFrame(update)
}
window.requestAnimationFrame(update)
}
</script>
<style>
body,html {
margin:0;
padding:0;
color: #F3F4F5;
background: #191818;
overflow-x: hidden;
height: 10000vh;
}
#letter {
width: 10vw;
margin-left: 10vw;
position: fixed;
top: 20vh;
}
</style>
</head>
<body>
<div id="main">
<div id="header" class="section">
<img src="../docs/img/a.png" class="lax" id="letter" data-lax-translate-x="0 0, 1000 1000" />
</div>
</div>
</body>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 576 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

158
docs/demo.html Normal file
View File

@@ -0,0 +1,158 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,600,800" rel="stylesheet">
<style>
body,html {
margin:0;
padding:0;
color: rgb(10,10,10);
background: white;
overflow-x: hidden;
height: 10000vh;
font-family: "Raleway", "HelveticaNeue", sans-serif;
}
h4 {
font-size: 2rem;
line-height: 1.35;
letter-spacing: -.08rem;
}
#main {
opacity: 0;
transition: opacity 200ms;
}
#main.loaded {
opacity: 1;
}
#background {
position: fixed;
}
.leaf1 {
width: 200pt;
height: 80pt;
position: absolute;
background: url('img/leaf1.svg') no-repeat;
mix-blend-mode: multiply;
opacity: 0.7;
}
.leaf {
width: 200pt;
height: 100pt;
position: absolute;
mix-blend-mode: multiply;
opacity: 0.7;
}
#center {
display: flex;
flex-direction: column;
align-items: center;
width: 100vw;
}
#avatar {
width: 150pt;
height: 150pt;
background: gray;
border-radius: 75pt;
margin-top: 50pt
}
#bio {
width: 400pt;
position: fixed;
}
#bio p {
font-size: 14pt;
line-height: 26pt;
font-weight: 100;
}
.github-corner {
z-index: 1000;
display: block;
position: fixed;
top: 0;
right: 0;
transform: scale(1.2);
}
</style>
<!-- <script src="./lib/lax.min.js"></script> -->
<script src="../src/lax.js"></script>
<script type="text/javascript">
window.onload = function() {
document.getElementById("main").classList.add("loaded")
lax.setup()
const update = () => {
lax.update(window.scrollY)
window.requestAnimationFrame(update)
}
window.requestAnimationFrame(update)
}
</script>
</head>
<body>
<div id="main">
<div id="background">
<div
class="lax leaf"
style="transform: scale(1.5); background: url('img/leaf1.svg') no-repeat;"
data-lax-rotate= "0 -20, 900 20, 2000 -20 | loop=2000 offset=200"
data-lax-translate-x= "0 110, 800 -100, 900 -110, 1900 100, 2000 110 | loop=2000 offset=200"
data-lax-translate-y= "0 -elh, (vh*10) (vh+elh) | loop=(vh*10) offset=1000 speed=1"
></div>
<div
class="lax leaf"
style="transform: scale(2); background: url('img/leaf2.svg') no-repeat;"
data-lax-rotate= "0 -20, 900 20, 2000 -20 | loop=2000 offset=500 speed=1.5"
data-lax-translate-x= "0 110, 800 -100, 900 -110, 1900 100, 2000 110 | loop=2000 offset=500 speed=1.5"
data-lax-translate-y= "0 -elh, (vh*10) (vh+elh) | loop=(vh*10) offset=1000 speed=1"
></div>
<div
class="lax leaf"
style="transform: scale(1.2); background: url('img/leaf3.svg') no-repeat;"
data-lax-rotate= "0 -20, 900 20, 2000 -20 | loop=2000 offset=1000"
data-lax-translate-x= "0 110, 800 -100, 900 -110, 1900 100, 2000 110 | loop=2000 offset=1000"
data-lax-translate-y= "0 -elh, (vh*10) (vh+elh) | loop=(vh*10) offset=400 speed=1"
></div>
</div>
<div id="center">
<div
id="avatar"
class="lax"
/></div>
<div id="bio">
<h4>Scroll Dowwwnn...</h4>
</div>
</div>
</div>
<a href="https://github.com/alexfoxy/laxxx" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#000000; color:#ffffff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
</body>

View File

@@ -1,143 +0,0 @@
<head>
<script type="application/javascript" src="../lib/lax.min.js"></script>
<script type="application/javascript">
window.onload = function () {
lax.init()
// Setup mouse move listener
document.addEventListener('mousemove', function (e) {
lax.__cursorX = e.clientX
lax.__cursorY = e.clientY
}, false)
// Add lax driver for cursorX
lax.addDriver('cursorX', function () {
return lax.__cursorX || 0
})
// Add lax driver for cursorY
lax.addDriver('cursorY', function () {
return lax.__cursorY || 0
})
// Add lax driver for cursorXY
lax.addDriver('cursorDistanceFromCenter', function () {
var pageHeight = document.body.scrollHeight
var pageWidth = document.body.scrollWidth
var pageCenterX = pageWidth / 2
var pageCenterY = pageHeight / 2
var absDistanceFromCenterY = Math.abs((lax.__cursorY || 0) - pageCenterY) / pageCenterY
var absDistanceFromCenterX = Math.abs((lax.__cursorX || 0) - pageCenterX) / pageCenterX
return absDistanceFromCenterX + absDistanceFromCenterY
})
lax.addElements(".text", {
'cursorX': {
"translateX": [
[0, 'screenWidth'],
['index * 10', 'index * -10'],
],
},
'cursorY': {
"translateY": [
[0, 'screenHeight'],
['index * 10', 'index * -10'],
],
},
'cursorDistanceFromCenter': {
"scale": [
[0, 1],
[1, '1 + (index * 0.05 )'],
],
}
})
lax.addElements(".container", {
'cursorX': {
"filter": [
[0, 'screenWidth'],
[0, 'screenWidth/2'],
{
"cssFn": (val) => {
return `hue-rotate(${val % 360}deg)`
}
}
],
},
})
}
</script>
</head>
<style>
body {
padding: 0;
margin: 0;
font-family: Arial, Helvetica, sans-serif;
}
.text {
width: 100vw;
text-align: center;
position: fixed;
top: 0;
left: 0;
margin-top: calc(50vh - 40px);
z-index: 1000;
font-size: 100px;
transform-origin: 50% 50%;
}
.text.a {
color: #a94fe4;
}
.text.b {
color: #68e4f1;
}
.text.c {
color: #ffe773;
}
.text.d {
color: #f544ad;
}
.container {
background-color: #f5922c;
position: fixed;
width: 100vw;
height: 100vh;
}
</style>
<body>
<div class="container">
<h1 class='text a'>Lax.js</h1>
<h1 class='text b'>Lax.js</h1>
<h1 class='text c'>Lax.js</h1>
<h1 class='text d'>Lax.js</h1>
<h1 class='text a'>Lax.js</h1>
<h1 class='text b'>Lax.js</h1>
<h1 class='text c'>Lax.js</h1>
<h1 class='text d'>Lax.js</h1>
<h1 class='text a'>Lax.js</h1>
<h1 class='text b'>Lax.js</h1>
<h1 class='text c'>Lax.js</h1>
<h1 class='text d'>Lax.js</h1>
<h1 class='text a'>Lax.js</h1>
<h1 class='text b'>Lax.js</h1>
<h1 class='text c'>Lax.js</h1>
<h1 class='text d'>Lax.js</h1>
<h1 class='text a'>Lax.js</h1>
<h1 class='text b'>Lax.js</h1>
<h1 class='text c'>Lax.js</h1>
<h1 class='text d'>Lax.js</h1>
</div>
</body>

View File

@@ -1,41 +0,0 @@
<head>
<script type="application/javascript" src="../lib/lax.min.js"></script>
<script type="application/javascript">
window.onload = function () {
lax.init()
lax.addDriver('scrollY', function () {
return window.scrollY
})
}
</script>
</head>
<style>
.square {
height: 200px;
width: 200px;
background-color: #a26ddc;
margin-bottom: 0px;
margin-left: -100px;
margin-top: -100px;
left: 50vw;
top: 50vh;
position: fixed;
}
body {
padding: 0;
background-color: #dedbde;
background-image: linear-gradient(rgba(255, 255, 255, .2) 50%, transparent 50%, transparent);
margin: 0;
background-size: 700px 700px;
height: 1000000px;
}
</style>
<body>
<div class="square lax lax_preset_spin:400:360 lax_preset_flipX"></div>
</body>

View File

@@ -1,82 +0,0 @@
<head>
<script type="application/javascript" src="../lib/lax.min.js"></script>
<script type="application/javascript">
window.onload = function () {
lax.init()
lax.addDriver('scrollY', function () {
return window.scrollY
}, { inertiaEnabled: true })
lax.addElements(".circle", {
scrollY: {
perspective: [
[0],
[1000],
],
rotateX: [
[0],
[0],
{
inertia: -1
}
],
"box-shadow": [
[0],
[0],
{
inertia: -1,
cssFn: (val) => {
return `0px ${Math.abs(val)}px 30px rgba(0,0,0,0.2)`
}
}
],
translateY: [
[0],
[0],
{
inertia: -1
}
],
brightness: [
[0],
[1],
{
inertia: -0.01
}
]
},
})
}
</script>
</head>
<style>
.circle {
height: 200px;
width: 200px;
background-color: #a26ddc;
margin-bottom: 0px;
margin-left: -100px;
margin-top: -100px;
border-radius: 20px;
left: 50vw;
top: 50vh;
position: fixed;
}
body {
padding: 0;
background-color: #dedbde;
background-image: linear-gradient(rgba(255, 255, 255, .2) 50%, transparent 50%, transparent);
margin: 0;
background-size: 700px 700px;
height: 1000000px;
}
</style>
<body>
<div class="circle">
</div>
</body>

View File

@@ -1,55 +0,0 @@
<head>
<script type="application/javascript" src="../lib/lax.min.js"></script>
<script type="application/javascript">
window.onload = function () {
lax.init()
const input = document.getElementById('input')
// Add lax driver for inputLength
lax.addDriver('inputLength', function () {
return input.value.length
})
lax.addElements("#input", {
'inputLength': {
"rotate": [
[0, 100],
[0, 360],
],
}
})
}
</script>
</head>
<style>
body {
padding: 0;
margin: 0;
font-family: Arial, Helvetica, sans-serif;
}
#input {
text-align: center;
width: calc(100vw - 200px);
transform-origin: center;
margin-left: 100px;
margin-top: calc(50vh - 50px);
position: fixed;
font-size: 40px;
border: 0;
outline: 0;
background-color: #f544ad;
padding: 20px;
box-sizing: border-box;
color: white;
border-radius: 50px;
}
</style>
<body>
<input id='input' placeholder="type something..." autocomplete="false" autofocus />
</body>

View File

@@ -1,61 +0,0 @@
<head>
<script type="application/javascript" src="../lib/lax.min.js"></script>
<script type="application/javascript">
window.onload = function () {
lax.init()
lax.addDriver('scrollY', function () {
return window.scrollY
})
lax.addElements("#text", {}, {
onUpdate: function (driverValues, domElement) {
const scrollY = driverValues.scrollY[0]
const oCount = Math.floor((scrollY / 10) + 1)
const oString = Array.from({ length: oCount }, (v, i) => "o").join("")
domElement.innerHTML = "scr" + oString + "ll"
if (scrollY > 1000) {
domElement.classList.add('pink')
} else {
domElement.classList.remove('pink')
}
}
})
}
</script>
</head>
<style>
#text {
width: calc(100vw - 40px);
left: 20;
top: 20;
position: fixed;
font-size: 60px;
font-family: sans-serif;
color: #a26ddc;
overflow-wrap: anywhere;
font-weight: bold;
}
#text.pink {
color: #ff568c;
}
body {
padding: 0;
background-color: #dedbde;
background-image: linear-gradient(rgba(255, 255, 255, .2) 50%, transparent 50%, transparent);
margin: 0;
background-size: 700px 700px;
height: 1000000px;
}
</style>
<body>
<div id="text">
</div>
</body>

View File

@@ -1,91 +0,0 @@
<head>
<script type="application/javascript" src="../lib/lax.min.js"></script>
<script type="application/javascript">
window.onload = function () {
lax.init()
lax.addDriver('scrollY', function () {
return window.scrollY
})
const container = document.querySelector('.container')
const count = 100
for (let i = 0; i < count; i++) {
const el = document.createElement('div')
el.className = "circle"
container.appendChild(el)
}
lax.addElements(".circle", {
scrollY: {
translateX: [
["elInY", "elCenterY", "elOutY"],
[0, 'screenWidth/2', 'screenWidth'],
{
easing: 'easeInOutQuart',
}
],
opacity: [
["elInY", "elCenterY", "elOutY"],
[0, 1, 0],
{
easing: 'easeInOutCubic'
}
],
"border-radius": [
["elInY+200", "elCenterY", "elOutY-200"],
[0, 100, 0],
{
easing: 'easeInOutQuint',
}
],
"box-shadow": [
["elInY+200", "elCenterY", "elOutY-200"],
[50, 0, 50],
{
easing: 'easeInOutQuint',
cssFn: (val) => {
return `${val}px ${val}px ${val}px rgba(0,0,0,0.5)`
}
}
],
}
})
}
</script>
</head>
<style>
.circle {
height: 100px;
width: 100px;
background-color: #a26ddc;
margin-bottom: 0px;
margin-left: -50px;
margin-bottom: 40px;
position: relative;
}
.container {
padding-top: 50vh;
width: 100vw;
overflow-y: hidden;
}
body {
padding: 0;
margin: 0;
padding: 0;
background-color: #dedbde;
background-image: linear-gradient(rgba(255, 255, 255, .2) 50%, transparent 50%, transparent);
margin: 0;
background-size: 700px 700px;
}
</style>
<body>
<div class="container">
</div>
</body>

View File

@@ -1,228 +0,0 @@
<head>
<script type="application/javascript" src="../lib/lax.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=0.8, maximum-scale=0.8, minimum-scale=0.8">
<link href="https://fonts.googleapis.com/css2?family=Comfortaa:wght@300;700&display=swap" rel="stylesheet">
<script type="application/javascript">
window.onload = function () {
lax.init()
const container = document.querySelector('.container')
lax.addDriver('containerScrollX', function () {
return container.scrollLeft
})
lax.addElements(".bg", {
containerScrollX: {
"opacity": [
["screenWidth * (index-1)", "screenWidth * index", "screenWidth * (index+1)"],
[0, 1, 0],
],
}
})
const imageAnimationMap = ["elCenterX-elWidth", "elCenterX", "elCenterX+elWidth"]
const textAnimationMap = ["elCenterX-(elWidth/3)", "elCenterX", "elCenterX+(elWidth/3)"]
lax.addElements(".page h1", {
containerScrollX: {
translateY: [
textAnimationMap,
[200, 0, 200],
{
easing: 'easeInOutQuad',
}
],
opacity: [
textAnimationMap,
[0, 1, 0],
],
}
})
lax.addElements(".page p", {
containerScrollX: {
translateY: [
textAnimationMap,
[500, 0, 500],
{
easing: 'easeInOutQuad',
}
],
opacity: [
textAnimationMap,
[0, 1, 0],
],
}
})
lax.addElements(".page .image", {
containerScrollX: {
translateY: [
imageAnimationMap,
[-100, 0, -100],
{
easing: 'easeInOutQuad',
}
],
scale: [
imageAnimationMap,
[0.8, 1, 0.8],
{
easing: 'easeInOutQuad',
}
],
}
})
}
</script>
</head>
<style>
.background {
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
background-size: cover;
}
.page {
flex-shrink: 0;
width: 100vw;
height: 100vh;
scroll-snap-align: center;
scroll-snap-stop: always;
position: relative;
display: inline-block;
background-size: cover;
}
.bg {
width: 100vw;
height: 100vh;
position: fixed;
background-size: cover;
}
.image {
height: 60vh;
width: 80%;
left: 10%;
position: absolute;
transform-origin: center top;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
top: 5vh;
}
.container {
display: flex;
overflow-x: auto;
overflow-y: hidden;
scroll-snap-type: x mandatory;
direction: ltr;
width: 100vw;
-webkit-overflow-scrolling: touch;
}
h1 {
top: 67vh;
position: absolute;
width: 100%;
font-weight: 100;
text-align: center;
color: white;
font-weight: 800;
font-size: 60px;
}
p {
top: 70vh;
position: absolute;
width: 100%;
font-weight: 100;
text-align: center;
color: white;
font-size: 18px;
line-height: 28px;
padding: 10vh;
padding-left: 200px;
padding-right: 200px;
box-sizing: border-box;
}
@media only screen and (max-width: 600px) {
p {
padding: 50px;
top: 55vh;
}
h1 {
top: 48vh;
}
.image {
top: -2vh;
}
}
body {
padding: 0;
margin: 0;
background-color: black;
overflow-y: hidden;
overflow-x: hidden;
font-family: 'Comfortaa', arial;
}
html {
height: 100vh;
overflow: hidden;
}
#controls {
position: fixed;
top: 0;
left: 0;
}
</style>
<body>
<div class="background">
<div class="bg" style="background-image: url('../assets/bg3.jpg');"></div>
<div class="bg" style="background-image: url('../assets/bg1.jpg');"></div>
<div class="bg" style="background-image: url('../assets/bg2.jpg');"></div>
</div>
<div class="container" id="scroller">
<div class="page">
<div class="image" style="background-image: url('../assets/shoe3.png');"></div>
<h1>Superstar</h1>
<p>
Classics never go out of style. An instant icon since their debut, adidas Superstar Shoes first rose to fame on
the basketball courts of the '70s and haven't slowed their roll since.
</p>
</div>
<div class="page"">
<div class=" image" style="background-image: url('../assets/shoe1.png');"></div>
<h1>Retrorun</h1>
<p>
Retro design with a modern twist. Check out a busy side street or stroll to the corner store in these adidas
running-inspired shoes. Suede overlays and contrast 3-Stripes give the flexible upper a sleek, sporty finish.
</p>
</div>
<div class="page">
<div class="image" style="background-image: url('../assets/shoe2.png');"></div>
<h1>Grand Court</h1>
<p>
A '70s style reborn. These shoes take inspiration from iconic sport styles of the past and move them into the
future. The shoes craft an everyday look with a leather-like upper.
</p>
</div>
</body>

View File

@@ -1,59 +0,0 @@
<head>
<script type="application/javascript" src="../lib/lax.min.js"></script>
<script type="application/javascript">
window.onload = function () {
lax.init()
lax.addDriver('scrollY', function () {
return window.scrollY
})
const frameWidth = 370
const frameCount = 12
lax.addElements(".sprite", {
scrollY: {
"background-position": [
[0, 1e9],
[0, 1e9],
{
cssFn: function (val) {
const frame = Math.floor(val / 10) % frameCount
const x = frame * frameWidth
return `-${x}px 0px`
},
}
]
}
})
}
</script>
</head>
<style>
.sprite {
height: 370px;
width: 370px;
background-image: url('../assets/spritesheet.jpg');
background-repeat: no-repeat;
position: fixed;
left: calc(50vw - 185px);
top: calc(50vh - 185px);
}
body {
padding: 0;
background-color: #dedbde;
background-image: linear-gradient(rgba(255, 255, 255, .2) 50%, transparent 50%, transparent);
margin: 0;
background-size: 700px 700px;
height: 1000000px;
}
</style>
<body>
<div class="sprite">
</div>
</body>

BIN
docs/img/a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
docs/img/bart.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

BIN
docs/img/bball.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
docs/img/bowser-sprite.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 122 KiB

BIN
docs/img/l.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

1
docs/img/leaf1.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 155.56 54.07"><defs><style>.cls-1{fill:url(#linear-gradient);}</style><linearGradient id="linear-gradient" x1="17.69" y1="36.08" x2="165.43" y2="35.97" gradientTransform="translate(-20.45 21.43) rotate(-18.21)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#c135d4"/><stop offset="1" stop-color="#6c56e3"/></linearGradient></defs><title>leaf1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M155.56,27c-17.91,16.44-46.08,27-77.77,27S17.91,43.47,0,27C17.91,10.59,46.09,0,77.79,0S137.65,10.59,155.56,27Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 684 B

1
docs/img/leaf2.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 155.56 54.07"><defs><style>.cls-1{fill:url(#linear-gradient);}</style><linearGradient id="linear-gradient" x1="-18.84" y1="30.22" x2="128.9" y2="30.11" gradientTransform="translate(16.08 15.58) rotate(-18.21)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#d4b43d"/><stop offset="1" stop-color="#ff309e"/></linearGradient></defs><title>leaf2</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M155.56,27c-17.91,16.44-46.08,27-77.77,27S17.91,43.47,0,27C17.91,10.59,46.09,0,77.79,0S137.65,10.59,155.56,27Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 683 B

1
docs/img/leaf3.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 155.56 54.07"><defs><style>.cls-1{fill:url(#linear-gradient);}</style><linearGradient id="linear-gradient" x1="-0.57" y1="33.15" x2="147.16" y2="33.04" gradientTransform="translate(-2.19 18.5) rotate(-18.21)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#008ad4"/><stop offset="1" stop-color="#57ffb6"/></linearGradient></defs><title>leaf3</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M155.56,27c-17.91,16.44-46.08,27-77.77,27S17.91,43.47,0,27C17.91,10.59,46.09,0,77.79,0S137.65,10.59,155.56,27Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 682 B

1
docs/img/leaf4.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 155.56 54.07"><defs><style>.cls-1{fill:url(#linear-gradient);}</style><linearGradient id="linear-gradient" x1="-17.27" y1="74.53" x2="130.46" y2="74.42" gradientTransform="translate(0.75 -26.02) rotate(-18.21)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#393fe3"/><stop offset="1" stop-color="#16d7de"/></linearGradient></defs><title>leaf4</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M155.56,27c-17.91,16.44-46.08,27-77.77,27S17.91,43.47,0,27C17.91,10.59,46.09,0,77.79,0S137.65,10.59,155.56,27Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 684 B

1
docs/img/leaf5.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 155.56 54.07"><defs><style>.cls-1{fill:url(#linear-gradient);}</style><linearGradient id="linear-gradient" x1="0.99" y1="77.45" x2="148.73" y2="77.34" gradientTransform="translate(-17.52 -23.09) rotate(-18.21)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#cce371"/><stop offset="1" stop-color="#37e310"/></linearGradient></defs><title>leaf5</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M155.56,27c-17.91,16.44-46.08,27-77.77,27S17.91,43.47,0,27C17.91,10.59,46.09,0,77.79,0S137.65,10.59,155.56,27Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/img/mario-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/img/mario-sprite.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
docs/img/mario-stars.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/img/nyan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
docs/img/x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,472 +1,378 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5">
<meta name="viewport" content="width=device-width, initial-scale=0.75, maximum-scale=0.75, minimum-scale=0.75">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,600,800" rel="stylesheet">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<script src="./lib/lax.min.js"></script>
<!-- <script src="../src/lax.js"></script> -->
<script type="text/javascript">
window.scrollTo(0, 0)
window.onload = function() {
document.getElementById("main").classList.add("loaded")
window.onload = function () {
lax.setup()
lax.init()
const update = () => {
lax.update(window.scrollY)
window.requestAnimationFrame(update)
}
lax.addDriver(
"scrollY",
function () {
return document.documentElement.scrollTop;
},
{ frameStep: 1 }
);
window.requestAnimationFrame(update)
lax.addElements(".letter-x", {
scrollY: {
translateY: [[-400, 0, 100], [300, 0, 100]],
scale: [[100, "screenHeight"], [0.25, 10]],
opacity: [[0, "screenHeight/2", "screenHeight"], [1, 1, 0]],
let w = window.innerWidth
window.addEventListener("resize", function() {
if(w !== window.innerWidth) {
lax.updateElements()
}
});
lax.addElements(".letter-l", {
scrollY: {
translateY: [[-400, 0], [100, 0]],
translateX: [[0, "screenHeight"], [0, 400]],
opacity: [[0, "screenHeight/2"], [1, 0]]
}
});
lax.addElements(".letter-a", {
scrollY: {
translateY: [[-400, 0], [200, 0]],
translateX: [[0, "screenHeight"], [0, -400]],
opacity: [[0, "screenHeight/2"], [1, 0]]
}
});
lax.addElements(".scrolldown", {
scrollY: {
"letter-spacing": [
[0, "screenHeight"],
[0, 150],
{
cssUnit: "px"
}
],
opacity: [["screenHeight*0.25", "screenHeight*0.75"], [1, 0]],
translateX: [[0, "screenHeight"], [0, 80]],
}
});
lax.addElements(".oooh", {
scrollY: {
translateX: [["elInY", "elOutY"], [0, "screenWidth-200"]]
}
});
lax.addElements(".aaah", {
scrollY: {
translateX: [["elInY", "elOutY"], [0, "-screenWidth-200"]]
}
});
lax.addElements(".wheee", {
scrollY: {
translateX: [["elInY", "elOutY"], [-400, "screenWidth+100"]],
skewX: [["elInY", "elOutY"], [40, -40]],
}
});
lax.addElements(".bubble", {
scrollY: {
translateY: [
["screenHeight/4", "screenHeight * 3"],
["Math.random()*screenHeight", "Math.random()*screenHeight*3"]
],
opacity: [
["screenHeight/4", "screenHeight/2"],
[0, 1]
],
scale: [[0], ["(Math.random()*0.8)+0.2"]],
translateX: [[0], ["index*(screenWidth/25)-50"]],
transform: [
[0, 4000],
[0, "(Math.random() + 0.8) * 1000"],
{
cssFn: function (val) {
return `rotateX(${val % 360}deg)`
}
}
],
rotate: [
[0, 4000],
[0, "(Math.random() - 0.5) * 1000"],
],
}
});
lax.addElements('#pinkZag', {
scrollY: {
translateY: [
["elInY", "elOutY"],
[0, -300]
],
}
})
lax.addElements('#tealZag', {
scrollY: {
translateY: [
["elInY", "elOutY"],
[0, 200]
],
}
})
lax.addElements('#purpleZag', {
scrollY: {
translateY: [
["elInY", "elOutY"],
[0, 700]
],
}
})
lax.addElements(".downarrows img", {
scrollY: {
translateY: [
[0, 200],
[0, 200]
],
opacity: [
[0, "screenHeight"],
[1, 0]
]
}
})
lax.addElements(".bottombutton", {
scrollY: {
"background-position": [
["elInY", "elOutY"],
[0, 400],
{
cssFn: function (val) {
return `${val}px 0`
}
}
],
scale: [
["elInY", "elCenterY"],
[3, 1],
]
},
})
}
</script>
<style>
html {
body,html {
margin:0;
padding:0;
color: #F3F4F5;
background: #191818;
overflow-x: hidden;
width: 100%;
font-family: 'Montserrat', sans-serif;
}
body {
padding: 0;
overflow-x: hidden;
width: 100%;
background-color: #242224;
margin: 0;
height: 480vh;
color: white;
font-family: "Montserrat", sans-serif;
position: relative;
#main {
opacity: 0;
transition: opacity 200ms;
}
.bottombutton {
background-image: url(./assets/button-bg.jpg);
width: 250px;
height: 70px;
background-size: 160px;
color: white;
font-weight: 800;
text-align: center;
line-height: 70px;
font-size: 30px;
text-decoration: none;
position: absolute;
top: 425vh;
border-radius: 20px;
left: 50vw;
margin-left: -125px;
z-index: 100;
pointer-events: all;
cursor: pointer;
#main.loaded {
opacity: 1;
}
#header {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100vw;
z-index: 2;
height: 100vh;
}
.bottombg {
background-color: #8d77ed;
.bg {
position: fixed;
width: 100vw;
height: 100vh;
top: 380vh;
z-index: 50;
position: absolute;
top: 0;
z-index: 1;
}
.letter-l {
margin-top: 100px;
width: 200px;
left: 50vw;
margin-left: -75px;
position: fixed;
left: 50vw;
margin-left: -75px;
#header img {
width: 78pt;
margin-top: 12pt;
}
.letter-a {
margin-top: 158px;
position: fixed;
left: 50vw;
margin-left: -77px;
width: 150px;
}
.letter-x {
margin-top: 85px;
position: fixed;
left: 50vw;
margin-left: -300px;
transform: scale(0.25);
transform-origin: 50% 50%;
width: 600px;
height: 600px;
}
.letter-x img {
width: 600px;
position: absolute;
}
.scrolldown {
bottom: 90px;
height: 40px;
position: fixed;
width: 300vw;
left: -100vw;
font-size: 40px;
#header h2 {
margin-top: 60pt;
font-size: 24pt;
font-weight: 600;
text-align: center;
}
.oooh {
font-size: 150px;
#header h4 {
font-size: 16pt;
font-weight: 300;
text-align: center;
}
#header i {
font-size: 14pt;
background: white;
color: black;
width: 30pt;
text-align: center;
height: 30pt;
line-height: 30pt;
border-radius: 15pt;
margin-top: -10pt;
}
.left {
position: absolute;
left: 0;
top: 140vh;
left: 80pt;
}
.aaah {
font-size: 150px;
.right {
position: absolute;
right: 0;
top: 170vh;
right: 80pt;
}
.wheee {
top: 230vh;
.chunkyText {
font-size: 80pt;
font-weight: 1000;
}
.crazyText {
font-size: 40pt;
font-weight: 1000;
color: #5ee5d5;
position: absolute;
left: 0;
height: 50px;
font-size: 100px;
}
.downarrows {
bottom: 60px;
position: fixed;
left: 50vw;
width: 70px;
margin-left: -35px;
height: 26px;
}
.downarrows img {
width: 70px;
position: absolute;
}
.bubbles {
top: -100vh;
position: fixed;
-webkit-transform: translate3d(0, 0, 0);
z-index: 5;
width: 100vw;
text-align: center;
margin-top: 500pt;
}
.bubble {
width: 140px;
height: 140px;
opacity: 1;
position: absolute;
margin-top: 100pt;
}
.bubble.red {
background: #a94fe4;
.block {
position: absolute;
width: 60pt;
height: 60pt;
}
.bubble.blue {
background: #68e4f1;
.bubble.a {
width: 100pt;
height: 100pt;
border-radius: 50pt
}
.bubble.yellow {
background: #ffe773;
.bubble.b {
width: 130pt;
height: 130pt;
border-radius: 65pt
}
.zags {
margin-top: 250vh;
z-index: 100;
.bubble.c {
width: 50pt;
height: 50pt;
border-radius: 25pt
}
.section {
z-index: 2;
display: block;
position: relative;
overflow: hidden;
height: 150vh;
}
.zag {
width: 100vw;
height: 150vh;
#section1 {
height: 750pt;
}
#section2 {
height: 200pt;
}
#section3 {
padding: 0 20pt;
font-size: 20pt;
line-height: 30pt;
align-items: center;
display: flex;
flex-direction: column;
height: 85vh;
}
p {
max-width: 500pt;
text-align: center;
margin-bottom: 100pt;
font-weight: 300;
}
.button {
padding: 10pt 50pt;
background: url(img/button-bg.jpg);
background-size: 100pt;
border-radius: 10pt;
font-weight: 600;
color: black !important;
}
a {
text-decoration: none;
}
a:visited {
color: black !important;
}
.button:hover {
background: white;
color: black !important;
cursor: pointer;
}
.github-corner {
z-index: 1000;
display: block;
position: absolute;
top: 0;
right: 0;
transform: scale(1.2);
}
#pinkZag {
background-image: url(./assets/pink-zag.png);
background-size: 200px;
background-repeat: repeat-x;
background-position-y: bottom;
}
#tealZag {
background-image: url(./assets/teal-zag.png);
background-size: 200px;
background-repeat: repeat-x;
background-position-y: bottom;
}
#purpleZag {
background-image: url(./assets/purple-zag.png);
background-size: 200px;
background-repeat: repeat-x;
background-position-y: bottom;
}
.bottom {
margin-top: 400vh;
}
</style>
</head>
<body>
<img src="./assets/l.png" class="letter-l" />
<img src="./assets/a.png" class="letter-a" />
<div class="letter-x">
<img src="./assets/x.png" />
</div>
<h2 class="scrolldown">scroll down</h2>
<div id="main">
<div id="header" class="section">
<img src="./img/l.png" class="lax" style="width: 103pt; margin-left: 26pt; margin-bottom: -4pt;" data-lax-translate-x="0 0, vh 200" data-lax-optimize=true />
<img src="./img/a.png" class="lax" data-lax-translate-x="0 0, vh -200" data-lax-optimize=true />
<img src="./img/x.png" class="lax" data-lax-opacity="0 1, (0.8*vh) 0" />
<img src="./img/x.png" class="lax" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 200" data-lax-opacity="0 1, (0.8*vh) 0" />
<img class="lax" src="./img/x.png" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 400" data-lax-opacity="0 1, (0.8*vh) 0" />
<img class="lax" src="./img/x.png" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 600" data-lax-opacity="0 1, (0.8*vh) 0" />
<img class="lax" src="./img/x.png" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 800" data-lax-opacity="0 1, (0.8*vh) 0" />
<img class="lax" src="./img/x.png" style="margin-top: -79pt" data-lax-translate-y="0 0, vh 1000" data-lax-opacity="0 1, (0.8*vh) 0" />
<h2 class="lax" data-lax-scale="0 1, vh 0.2" data-lax-translate-y="0 0, vh 1200" data-lax-opacity="0 1, (vh*0.5) 0">awesum scroll effects</h2>
<div class="downarrows">
<img src="./assets/downarrow.png" />
</div>
<div class="zags">
<div id="pinkZag" class="zag"></div>
<div id="tealZag" class="zag"></div>
<div id="purpleZag" class="zag"></div>
</div>
<div class="bubbles">
<div class="bubble blue"></div>
<div class="bubble red"></div>
<div class="bubble yellow"></div>
<div class="bubble red"></div>
<div class="bubble blue"></div>
<div class="bubble yellow"></div>
<div class="bubble blue"></div>
<div class="bubble red"></div>
<div class="bubble yellow"></div>
<div class="bubble red"></div>
<div class="bubble blue"></div>
<div class="bubble blue"></div>
<div class="bubble red"></div>
<div class="bubble yellow"></div>
<div class="bubble red"></div>
<div class="bubble blue"></div>
<div class="bubble yellow"></div>
<div class="bubble blue"></div>
<div class="bubble red"></div>
<div class="bubble yellow"></div>
<div class="bubble red"></div>
<div class="bubble blue"></div>
<div class="bubble yellow"></div>
<div class="bubble blue"></div>
<div class="bubble red"></div>
</div>
<h1 class="oooh">oooh</h1>
<h1 class="aaah">aaah</h1>
<h1 class="wheee">wheee!</h1>
<div class="bottombg"></div>
<a href="https://github.com/alexfoxy/lax.js">
<div class="bottombutton">
Get lax.js
<h4 class="lax" data-lax-opacity="0 1, (vh*0.05) 0">scroll down</h4>
<i class="lax fas fa-chevron-down"
data-lax-opacity="0 1, (vh*0.1) 0"
data-lax-translate-y="0 0, 200 100">
</i>
</div>
</a>
<a href="https://github.com/alexfoxy/lax.js" class="github-corner" aria-label="View source on GitHub"><svg width="80"
height="80" viewBox="0 0 250 250"
style="fill:#fff; color:#151513; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
<path
d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
<path
d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
fill="currentColor" class="octo-body"></path>
</svg></a>
<style>
.github-corner:hover .octo-arm {
animation: octocat-wave 560ms ease-in-out
}
<div id="section1" class="section">
<div class="left">
<div class="lax bubble a"
style="background: #EDD943"
data-lax-preset="lazy-250"
></div>
@keyframes octocat-wave {
<div class="lax bubble c"
style="background: #ED2471; margin-left: 80pt"
data-lax-preset="lazy-100"
></div>
0%,
100% {
transform: rotate(0)
}
<div class="lax bubble b"
style="background: #35D5E5; margin-left: 160pt"
data-lax-preset="lazy-300"
></div>
20%,
60% {
transform: rotate(-25deg)
}
<h3 data-lax-preset="driftRight" data-lax-optimize=true class="lax chunkyText" style="color: #35D5E5;">oooh!</h3>
</div>
40%,
80% {
transform: rotate(10deg)
}
}
<div class="right">
<div class="lax bubble a"
style="background: #35D5E5; margin-left: 120pt"
data-lax-preset="lazy-200"
></div>
@media (max-width:500px) {
.github-corner:hover .octo-arm {
animation: none
}
<div class="lax bubble c"
style="background: #EDD943; margin-left: -20pt"
data-lax-preset="lazy-150"
></div>
.github-corner .octo-arm {
animation: octocat-wave 560ms ease-in-out
}
}
</style>
</body>
<div class="lax bubble b"
style="background: #ED2471; margin-left: 20pt; margin-top: 200pt"
data-lax-preset="lazy-350"
></div>
<h3 data-lax-optimize=true data-lax-preset="driftLeft" class="lax chunkyText" style="color: #ED2471; margin-top: 200pt;">aaah!</h3>
</div>
<h3 data-lax-preset="crazy zoomInOut" class="lax crazyText" data-lax-optimize=true>sooo crazy</h3>
</div>
<div id="section2" class="section">
<div class="lax blockContainer" data-lax-preset="leftToRight-1.1 fadeInOut">
<div class="lax block"
style="background: #35D5E5;"
data-lax-preset="spin"
></div>
</div>
<div class="lax blockContainer" data-lax-preset="leftToRight-1.2 fadeInOut">
<div class="lax block"
style="background: #EDD943; margin-top: -50pt; margin-left: -50pt; width: 40pt; height: 40pt;"
data-lax-preset="spinRev-500"
></div>
</div>
<div class="lax blockContainer" data-lax-preset="leftToRight-1.4 fadeInOut">
<div class="lax block"
style="background: #ED2471; margin-top: -90pt; margin-left: -0pt;"
data-lax-preset="spin-500"
></div>
</div>
<div class="lax blockContainer" data-lax-preset="leftToRight-1.5 fadeInOut">
<div class="lax block"
style="background: #EDD943; margin-top: 70pt; margin-left: -150pt; width: 40pt; height: 40pt;"
data-lax-preset="spinRev-500"
></div>
</div>
<div class="lax blockContainer" data-lax-preset="leftToRight-1.3 fadeInOut">
<div class="lax block"
style="background: #EDD943; margin-top: 100pt; margin-left: -60pt; width: 25pt; height: 25pt;"
data-lax-preset="spin-500"
></div>
</div>
<div class="lax blockContainer" data-lax-preset="leftToRight-1.05 fadeInOut">
<div class="lax block"
style="background: #ED2471; margin-top: -30pt; margin-left: -70pt;"
data-lax-preset="spin"
></div>
</div>
<h3 data-lax-preset="leftToRight-0.8 speedy" data-lax-optimize=true class="lax chunkyText" style="
color: #white; position: absolute; margin-top: -20pt; margin-left: -100pt">
wheee!
</h3>
<div class="lax blockContainer" data-lax-preset="leftToRight-1.15 fadeInOut">
<div class="lax block"
style="background: #35D5E5; margin-top: -70pt; margin-left: -20pt; width: 40pt; height: 40pt;"
data-lax-preset="spinRev-500"
></div>
</div>
<div class="lax blockContainer" data-lax-preset="leftToRight-1.45 fadeInOut">
<div class="lax block"
style="background: #ED2471; margin-top: -50pt; margin-left: -50pt; width: 25pt; height: 25pt;"
data-lax-preset="spin-500"
></div>
</div>
<div class="lax blockContainer" data-lax-preset="leftToRight-1.5 fadeInOut">
<div class="lax block"
style="background: #35D5E5; margin-top: 30pt; margin-left: -20pt;"
data-lax-preset="spinRev-500"
></div>
</div>
<div class="lax blockContainer" data-lax-preset="leftToRight-1.25 fadeInOut">
<div class="lax block"
style="background: #ED2471; margin-top: 80pt; margin-left: -10pt;"
data-lax-preset="spin-500"
></div>
</div>
</div>
<div id="section3" class="lax section">
<p class="lax" data-lax-preset="linger" data-lax-optimize=true>
Harness the power of scrolling and make your websites come alive!
</p>
<a class="lax button" data-lax-preset="linger" data-lax-optimize=true data-lax-bg-pos-x="0 0, 3000 1000" href="https://github.com/alexfoxy/laxxx">
Get lax.js
</a>
</div>
</div>
<a href="https://github.com/alexfoxy/laxxx" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#fff; color:#151513; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
</body>

2
docs/lib/lax.min.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,488 +0,0 @@
<head>
<script src="https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js"></script>
<script type="application/javascript" src="./lib/lax.min.js"></script>
<script type="application/javascript">
window.copyPreset = function () {
const input = document.getElementById("presetString")
input.select()
input.setSelectionRange(0, 99999)
document.execCommand("copy")
alert("Copied the text: " + input.value)
}
window.onload = function () {
/*
Setup control data
*/
const baseSettings = {
fade: [
{
name: 'Distance',
limits: [100, window.innerHeight / 3],
value: window.innerHeight / 4
},
{
name: 'Starting Opacity',
limits: [0, 0.9],
step: 0.1,
value: 0
}
],
blur: [
{
name: 'Distance',
limits: [100, window.innerHeight / 3],
value: window.innerHeight / 4
},
{
name: 'Strength',
limits: [0, 50],
value: 20
}
],
spin: [
{
name: 'Distance',
limits: [10, 3000],
value: window.innerHeight
},
{
name: 'Stength',
limits: [1, 360],
value: 360
}
],
scale: [
{
name: 'Distance',
limits: [50, window.innerHeight / 3],
value: window.innerHeight / 4
},
{
name: 'Starting Scale',
limits: [0, 1],
step: 0.1,
value: 0.6
}
],
slide: [
{
name: 'Distance',
limits: [50, window.innerHeight],
value: window.innerHeight / 4
},
{
name: 'Amount',
limits: [-1000, 1000],
value: 500
}
]
}
const enabledPresets = ["fadeInOut", "seesaw"]
const controlData = {
fadeIn: [...baseSettings.fade],
fadeOut: [...baseSettings.fade],
fadeInOut: [...baseSettings.fade],
scaleIn: [...baseSettings.scale],
scaleOut: [...baseSettings.scale],
scaleInOut: [...baseSettings.scale],
slideX: [...baseSettings.slide],
slideY: [...baseSettings.slide],
jiggle: [
{
name: 'Distance',
limits: [40, 200],
value: 50
},
{
name: 'Stength',
limits: [1, 100],
value: 20
}
],
seesaw: [
{
name: 'Distance',
limits: [40, 200],
value: 140
},
{
name: 'Stength',
limits: [1, 40],
value: 20
}
],
zigzag: [
{
name: 'Distance',
limits: [40, 200],
value: 170
},
{
name: 'Stength',
limits: [1, 500],
value: 200
}
],
hueRotate: [...baseSettings.spin],
spin: [...baseSettings.spin],
flipX: [...baseSettings.spin],
flipY: [...baseSettings.spin],
blurIn: [...baseSettings.blur],
blurOur: [...baseSettings.blur],
blurInOut: [...baseSettings.blur],
}
/*
UI Update methods
*/
function updateLaxSettings() {
lax.removeElements("#laxLogo")
const presets = []
enabledPresets.forEach((presetName) => {
const control = controlData[presetName]
const controlStr = control ? ":" + control.map(c => c.value).join(":") : ''
const settingString = `${presetName}${controlStr}`
presets.push(settingString)
})
lax.addElements("#laxLogo", {
scrollY: {
presets
}
})
presetString.value = presets.map((p) => {
return `lax_preset_${p}`
}).join(" ")
}
function onSliderUpdate(name, value) {
const valueEl = document.getElementById(name + '-value')
if (valueEl) valueEl.innerHTML = value
updateLaxSettings()
}
function onCheckBoxUpdate(controlName) {
const index = enabledPresets.indexOf(controlName)
const enabled = index >= 0
const sliders = document.getElementById(controlName + "-controls")
if (enabled) {
enabledPresets.splice(index, 1)
if (sliders) sliders.classList.remove('visible')
} else {
enabledPresets.push(controlName)
if (sliders) sliders.classList.add('visible')
}
const checkbox = document.getElementById(controlName + "-checkbox")
if (checkbox) checkbox.checked = !enabled
}
/*
Build UI
*/
const controlsContainer = document.getElementById('controlsContainer')
const presetString = document.getElementById('presetString')
function renderSlider(control, controlName) {
const container = document.createElement('div')
container.className = "slider"
const slider = document.createElement('input')
const id = [controlName.toLowerCase(), control.name.toLowerCase()].join("-")
slider.type = 'range'
slider.min = control.limits[0]
slider.max = control.limits[1]
slider.step = control.step || 1
slider.value = control.value
slider.oninput = function (el) {
control.value = el.target.value
onSliderUpdate(id, el.target.value)
}
const labelContainer = document.createElement('div')
labelContainer.className = "labelContainer"
const label = document.createElement('label')
label.innerHTML = control.name
const value = document.createElement('label')
value.innerHTML = control.value
value.id = id + "-value"
labelContainer.appendChild(label)
labelContainer.appendChild(value)
container.appendChild(labelContainer)
container.appendChild(slider)
return container
}
function renderCheckbox(controlName) {
const container = document.createElement('div')
container.className = "checkBox"
const checkbox = document.createElement('input')
checkbox.id = controlName + "-checkbox"
checkbox.type = "checkbox"
const enabled = enabledPresets.indexOf(controlName) > -1
checkbox.checked = enabled
const id = [controlName.toLowerCase(), name.toLowerCase()].join()
checkbox.oninput = function (el) {
["blur", "scale", "fade"].forEach((type) => {
if (controlName.includes(type)) {
enabledPresets.forEach((presetName) => {
if (presetName !== controlName && presetName.includes(type)) {
onCheckBoxUpdate(presetName, true)
}
})
}
})
onCheckBoxUpdate(controlName, enabled)
updateLaxSettings()
}
const label = document.createElement('label')
label.innerHTML = controlName
container.appendChild(label)
container.appendChild(checkbox)
return container
}
function renderControl(controlName) {
const controls = controlData[controlName]
const container = document.createElement('div')
container.className = 'control'
const checkbox = renderCheckbox(controlName)
container.appendChild(checkbox)
const sliderControls = document.createElement('div')
sliderControls.className = 'sliderControls'
sliderControls.id = controlName + "-controls"
controls.forEach((control, i) => {
const slider = renderSlider(control, controlName)
sliderControls.appendChild(slider)
})
const enabled = enabledPresets.indexOf(controlName) > -1
if (enabled) sliderControls.classList.add("visible")
container.appendChild(sliderControls)
controlsContainer.appendChild(container)
}
Object.keys(controlData).forEach((controlName) => renderControl(controlName))
/*
Initialise lax
*/
lax.init()
lax.addDriver('scrollY', function () {
return window.scrollY
})
updateLaxSettings()
}
</script>
</head>
<style>
body {
padding: 0;
background-color: #dedbde;
background-image: linear-gradient(rgba(255, 255, 255, .2) 50%, transparent 50%, transparent);
margin: 0;
background-size: 700px 700px;
height: 220vh;
font-family: 'Montserrat', sans-serif;
overflow-x: hidden;
}
#laxLogo {
margin-top: 100vh;
left: 0;
z-index: 1000;
font-size: 100px;
text-align: center;
transform-origin: 50% 50%;
color: #a94fe4;
width: 240px;
margin-left: calc(50vw - 150px - 120px);
position: absolute;
pointer-events: none;
}
.hint {
left: 0;
width: 100%;
opacity: 0.2;
z-index: 1000;
font-size: 24px;
text-align: center;
position: absolute;
margin-bottom: 0;
}
#controlsContainer {
position: fixed;
width: 300px;
background: white;
height: 100vh;
box-shadow: 0px 0px 15px 3px rgba(0, 0, 0, 0.2);
padding: 20;
box-sizing: border-box;
overflow-y: auto;
padding-bottom: 100px;
}
#controlsContainer h1 {
margin: 0;
font-size: 20px;
margin-bottom: 20px;
}
#canvas {
width: calc(100vw - 300px);
margin-left: 300px;
position: relative;
height: 220vh;
}
#presetString {
background: #4a525a;
color: white;
font-family: monospace;
padding: 10px;
border: 0;
border-radius: 10px;
width: 195px;
margin-right: 5px;
outline: none;
}
#presetStringContainer {
position: fixed;
bottom: 0;
background: #e1e8e8;
left: 0;
width: 260px;
padding: 20px 20px;
}
.control {
border-top: 1px solid #d8d7d7;
}
.checkBox,
.labelContainer {
display: flex;
align-items: baseline;
justify-content: space-between;
;
}
.sliderControls {
height: 0px;
overflow-y: hidden;
overflow-x: visible;
transition: height 200ms ease-out;
}
.sliderControls.visible {
height: 105px;
}
.slider input {
width: 100%;
margin-bottom: 10px;
margin-top: 5px;
}
label {
font-weight: lighter;
font-size: 14px;
}
.checkBox label {
font-weight: 800;
margin-bottom: 15px;
margin-top: 15px;
}
#copyButton {
border: 0;
width: 55px;
height: 36px;
padding: 0;
margin: 0;
background: #a26ddc;
border-radius: 10px;
font-family: inherit;
font-weight: bold;
color: white;
outline: none;
}
#copyButton:hover {
opacity: 0.8;
cursor: pointer;
}
#presetTextHelper {
margin-bottom: 10px;
font-size: 12px;
display: flex;
justify-content: space-between;
}
</style>
<body>
<div id="controlsContainer">
<h1>Lax preset explorer</h1>
<div id="presetStringContainer">
<div id="presetTextHelper">
<span>Preset code</span>
<a href="https://github.com/alexfoxy/lax.js#using-presets">How to use</a>
</div>
<input id="presetString" />
<button onclick="copyPreset()" id="copyButton">Copy</button>
</div>
</div>
<div id="canvas">
<h4 class='hint' style="top: 120px;">Scroll Down..</h4>
<h4 class='hint' style="bottom: 140px;">Scroll Up..</h4>
<img src="assets/lax.png" id="laxLogo" />
</div>
</body>

206
docs/sprite.html Normal file
View File

@@ -0,0 +1,206 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5">
<style>
body,html {
margin:0;
padding:0;
color: #F3F4F5;
background: #3c2d7f;
overflow-x: hidden;
height: 10000vh;
font-family: 'Montserrat', sans-serif;
}
#main {
opacity: 0;
transition: opacity 200ms;
}
#main.loaded {
opacity: 1;
}
#mario {
width: 256px;
height: 256px;
/*left: 0;*/
position: fixed;
top: calc(70vh - 256px)
}
#bowser {
width: 524px;
height: 350px;
/*left: 100vw;*/
position: fixed;
top: calc(70vh - 330px)
}
#stars {
width: 100vw;
height: 70vh;
background: url("img/mario-stars.gif");
background-size: 800px;
position: fixed;
opacity: 0.7;
top: 0;
}
#foreground {
width: 100vw;
height: 30vh;
background: url("img/mario-foreground.png");
background-size: 15vh;
position: fixed;
top: 70vh;
}
#nyan {
width: 300px;
height: 119px;
position: fixed;
top: 20vh;
left: 0;
}
#logo {
width: 300pt;
height: 100pt;
background: url(img/mario-logo.png) no-repeat center top;
background-size: contain;
position: fixed;
top: 10vh;
left: calc(50vw - 150pt);
z-index: 200;
}
#scrolltext {
width: 300pt;
height: 50pt;
background: url(img/mario-scrolldown.png) no-repeat center top;
background-size: contain;
position: fixed;
top: 83vh;
left: calc(50vw - 150pt);
}
#planet1 {
width: 30vw;
height: 30vw;
position: fixed;
left: 100vw;
bottom: 29vh;
}
#planet2 {
width: 20vw;
height: 20vw;
top: 10vh;
left: 30pt;
position: fixed;
}
.github-corner {
z-index: 1000;
display: block;
position: fixed;
top: 0;
right: 0;
transform: scale(1.2);
}
</style>
<script src="./lib/lax.min.js"></script>
<!-- <script src="../src/lax.js"></script> -->
<script type="text/javascript">
window.onload = function() {
document.getElementById("main").classList.add("loaded")
lax.setup()
const update = () => {
lax.update(window.scrollY)
window.requestAnimationFrame(update)
}
window.requestAnimationFrame(update)
}
</script>
</head>
<body>
<div id="main">
<div id="header" class="section">
<div
id="stars"
class="lax"
data-lax-bg-pos-x="0 0, 10000 -800 | loop=10000"
></div>
<div
id="planet1"
class="lax"
data-lax-translate-x="0 0, 5000 (-vw-elw)"
data-lax-sprite-data="382,382,15,5,10"
data-lax-sprite-image="./img/bart.png"
></div>
<div
id="foreground"
class="lax"
data-lax-bg-pos-x="0 0, 7000 (-15*vh) | loop=7000"
></div>
<div
id="logo"
></div>
<div
id="scrolltext"
data-lax-translate-y="0 0, 360 350"
class="lax"
></div>
<div
id="nyan"
data-lax-sprite-data="300,119,12,4,10"
data-lax-translate-x="0 vw, 600 -elw | loop=600"
data-lax-sprite-image="./img/nyan.png"
class="lax"
></div>
<div
id="mario"
class="lax"
data-lax-translate-x="0 -elw, 720 (vw+elw) | loop=720"
data-lax-translate-y="0 0, 240 0, 300 -500, 420 0, 720 0 | loop=720"
data-lax-sprite-data="256,256,12,4,5"
data-lax-sprite-image="./img/mario-sprite.png"
></div>
<div
id="bowser"
class="lax"
data-lax-translate-x="0 vw, 720 -elw | loop=720"
data-lax-sprite-data="524,350,8,4,10"
data-lax-sprite-image="./img/bowser-sprite.png"
></div>
</div>
</div>
<a href="https://github.com/alexfoxy/laxxx" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#fff; color:#151513; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
</body>

View File

@@ -1,5 +0,0 @@
{
"compilerOptions": {
"checkJs": true
},
}

1173
lib/lax.js

File diff suppressed because it is too large Load Diff

2
lib/lax.min.js vendored

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -1,36 +1,29 @@
{
"name": "lax.js",
"version": "2.0.3",
"scripts": {
"build": "babel src -d lib && uglifyjs lib/lax.js -o lib/lax.min.js -c -m && gzip -c lib/lax.min.js > lib/lax.min.js.gz && cp lib/lax.min.js docs/lib/lax.min.js"
},
"devDependencies": {
"@babel/cli": "^7.12.1",
"@babel/core": "^7.12.3",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/preset-env": "^7.12.1",
"uglify-js": "^3.9.4"
},
"description": "Simple & lightweight (<4kb gzipped) vanilla JavaScript library to create smooth & beautiful animations when you scroll.",
"license": "MIT",
"author": "alexfoxy@gmail.com",
"repository": {
"type": "git",
"url": "https://github.com/alexfoxy/lax.js"
},
"main": "lib/lax.min.js",
"keywords": [
"javascript",
"lax",
"laxxx",
"lax.js",
"laxjs",
"parallax",
"scroll",
"animation",
"effects",
"css",
"html"
],
"dependencies": {}
"name": "lax.js",
"version": "1.2.5",
"scripts": {
"build": "babel src -d lib; uglifyjs lib/lax.js -o lib/lax.min.js -c -m; gzip < lib/lax.min.js > lib/lax.min.js.gz;"
},
"devDependencies": {
"@babel/cli": "^7.5.0",
"@babel/core": "^7.5.0",
"@babel/preset-env": "^7.5.0"
},
"description": "Simple & light weight (2kb minified & zipped) vanilla javascript plugin to create smooth & beautiful animations when you scrolllll! Harness the power of the most intuitive interaction and make your websites come alive!",
"license": "MIT",
"author": "alexfoxy@gmail.com",
"repository": {
"type": "git",
"url": "https://github.com/alexfoxy/laxxx"
},
"main": "lib/lax.min.js",
"keywords": [
"javascript",
"parallax",
"scroll",
"animation",
"effects",
"css",
"html"
]
}

View File

@@ -1,612 +1,406 @@
//
// lax v1.2.3 (Alex Fox)
// Simple & light weight vanilla javascript plugin to create beautiful animations things when you scrolllll!!
//
// Licensed under the terms of the MIT license.
//
// You may use it in your theme if you credit me.
// It is also free to use on any individual website.
//
// Exception:
// The only restriction is to not publish any
// extension for browsers or native application
// without getting a written permission first.
//
(() => {
const inOutMap = (y = 30) => {
return ["elInY+elHeight", `elCenterY-${y}`, "elCenterY", `elCenterY+${y}`, "elOutY-elHeight"]
}
const lax = (() => {
const lax = {
elements: []
}
const laxPresets = {
fadeInOut: (y = 30, str = 0) => ({
"opacity": [
inOutMap(y),
[str, 1, 1, 1, str]
],
}),
fadeIn: (y = 'elCenterY', str = 0) => ({
"opacity": [
["elInY+elHeight", y],
[str, 1],
],
}),
fadeOut: (y = 'elCenterY', str = 0) => ({
"opacity": [
[y, "elOutY-elHeight"],
[1, str],
],
}),
blurInOut: (y = 100, str = 20) => ({
"blur": [
inOutMap(y),
[str, 0, 0, 0, str],
],
}),
blurIn: (y = 'elCenterY', str = 20) => ({
"blur": [
["elInY+elHeight", y],
[str, 0],
],
}),
blurOut: (y = 'elCenterY', str = 20) => ({
"opacity": [
[y, "elOutY-elHeight"],
[0, str],
],
}),
scaleInOut: (y = 100, str = 0.6) => ({
"scale": [
inOutMap(y),
[str, 1, 1, 1, str],
],
}),
scaleIn: (y = 'elCenterY', str = 0.6) => ({
"scale": [
["elInY+elHeight", y],
[str, 1],
],
}),
scaleOut: (y = 'elCenterY', str = 0.6) => ({
"scale": [
[y, "elOutY-elHeight"],
[1, str],
],
}),
slideX: (y = 0, str = 500) => ({
"translateX": [
['elInY', y],
[0, str],
],
}),
slideY: (y = 0, str = 500) => ({
"translateY": [
['elInY', y],
[0, str],
],
}),
spin: (y = 1000, str = 360) => ({
"rotate": [
[0, y],
[0, str],
{
modValue: y,
}
],
}),
flipX: (y = 1000, str = 360) => ({
"rotateX": [
[0, y],
[0, str],
{
modValue: y
}
],
}),
flipY: (y = 1000, str = 360) => ({
"rotateY": [
[0, y],
[0, str],
{
modValue: y
}
],
}),
jiggle: (y = 50, str = 40) => ({
"skewX": [
[0, y * 1, y * 2, y * 3, y * 4],
[0, str, 0, -str, 0],
{
modValue: y * 4,
}
],
}),
seesaw: (y = 50, str = 40) => ({
"skewY": [
[0, y * 1, y * 2, y * 3, y * 4],
[0, str, 0, -str, 0],
{
modValue: y * 4,
}
],
}),
zigzag: (y = 100, str = 100) => ({
"translateX": [
[0, y * 1, y * 2, y * 3, y * 4],
[0, str, 0, -str, 0],
{
modValue: y * 4,
}
],
}),
hueRotate: (y = 600, str = 360) => ({
"hue-rotate": [
[0, y],
[0, str],
{
modValue: y,
}
],
}),
}
let lastY = 0;
let currentBreakpoint = 'default'
const breakpointsSeparator = "_"
const laxInstance = (() => {
const transformKeys = ["perspective", "scaleX", "scaleY", "scale", "skewX", "skewY", "skew", "rotateX", "rotateY", "rotate"]
const filterKeys = ["blur", "hue-rotate", "brightness"]
const translate3dKeys = ["translateX", "translateY", "translateZ"]
const transformFns = {
"data-lax-opacity": (style, v) => { style.opacity = v },
"data-lax-translate": (style, v) => { style.transform += ` translate(${v}px, ${v}px)` },
"data-lax-translate-x": (style, v) => { style.transform += ` translateX(${v}px)` },
"data-lax-translate-y": (style, v) => { style.transform += ` translateY(${v}px)` },
"data-lax-scale": (style, v) => { style.transform += ` scale(${v})` },
"data-lax-scale-x": (style, v) => { style.transform += ` scaleX(${v})` },
"data-lax-scale-y": (style, v) => { style.transform += ` scaleY(${v})` },
"data-lax-skew": (style, v) => { style.transform += ` skew(${v}deg, ${v}deg)` },
"data-lax-skew-x": (style, v) => { style.transform += ` skewX(${v}deg)` },
"data-lax-skew-y": (style, v) => { style.transform += ` skewY(${v}deg)` },
"data-lax-rotate": (style, v) => { style.transform += ` rotate(${v}deg)` },
"data-lax-rotate-x": (style, v) => { style.transform += ` rotateX(${v}deg)` },
"data-lax-rotate-y": (style, v) => { style.transform += ` rotateY(${v}deg)` },
"data-lax-brightness": (style, v) => { style.filter += ` brightness(${v}%)` },
"data-lax-contrast": (style, v) => { style.filter += ` contrast(${v}%)` },
"data-lax-hue-rotate": (style, v) => { style.filter += ` hue-rotate(${v}deg)` },
"data-lax-blur": (style, v) => { style.filter += ` blur(${v}px)` },
"data-lax-invert": (style, v) => { style.filter += ` invert(${v}%)` },
"data-lax-saturate": (style, v) => { style.filter += ` saturate(${v}%)` },
"data-lax-grayscale": (style, v) => { style.filter += ` grayscale(${v}%)` },
"data-lax-bg-pos": (style, v) => { style.backgroundPosition = `${v}px ${v}px` },
"data-lax-bg-pos-x": (style, v) => { style.backgroundPositionX = `${v}px` },
"data-lax-bg-pos-y": (style, v) => { style.backgroundPositionY = `${v}px` }
}
const pxUnits = ["perspective", "border-radius", "blur", "translateX", "translateY", "translateZ"]
const degUnits = ["hue-rotate", "rotate", "rotateX", "rotateY", "skew", "skewX", "skewY"]
let crazy = ""
function getArrayValues(arr, windowWidth) {
if (Array.isArray(arr)) return arr
for(let i=0;i<20;i++) {
crazy += " " + i*5 + " " + (i*47)%360 + ", "
}
const keys = Object.keys(arr).map(x => parseInt(x)).sort((a, b) => a > b ? 1 : -1)
lax.presets = {
linger: (v) => {
return { "data-lax-translate-y": `(vh*0.7) 0, 0 200, -500 0` }
},
lazy: (v=100) => {
return { "data-lax-translate-y": `(vh) 0, (-elh) ${v}` }
},
eager: (v=100) => {
return { "data-lax-translate-y": `(vh) 0, (-elh) -${v}` }
},
slalom: (v=50) => {
return { "data-lax-translate-x": `vh ${v}, (vh*0.8) ${-v}, (vh*0.6) ${v}, (vh*0.4) ${-v}, (vh*0.2) ${v}, (vh*0) ${-v}, (-elh) ${v}` }
},
crazy: (v) => {
return { "data-lax-hue-rotate": `${crazy} | loop=20` }
},
spin: (v=360) => {
return { "data-lax-rotate": `(vh) 0, (-elh) ${v}` }
},
spinRev: (v=360) => {
return { "data-lax-rotate": `(vh) 0, (-elh) ${-v}` }
},
spinIn: (v=360) => {
return { "data-lax-rotate": `vh ${v}, (vh*0.5) 0` }
},
spinOut: (v=360) => {
return { "data-lax-rotate": `(vh*0.5) 0, -elh ${v}` }
},
blurInOut: (v=40) => {
return { "data-lax-blur": `(vh) ${v}, (vh*0.8) 0, (vh*0.2) 0, 0 ${v}` }
},
blurIn: (v=40) => {
return { "data-lax-blur": `(vh) ${v}, (vh*0.7) 0` }
},
blurOut: (v=40) => {
return { "data-lax-blur": `(vh*0.3) 0, 0 ${v}` }
},
fadeInOut: () => {
return { "data-lax-opacity": "(vh) 0, (vh*0.8) 1, (vh*0.2) 1, 0 0" }
},
fadeIn: () => {
return { "data-lax-opacity": "(vh) 0, (vh*0.7) 1" }
},
fadeOut: () => {
return { "data-lax-opacity": "(vh*0.3) 1, 0 0" }
},
driftLeft: (v=100) => {
return { "data-lax-translate-x": `vh ${v}, -elh ${-v}` }
},
driftRight: (v=100) => {
return { "data-lax-translate-x": `vh ${-v}, -elh ${v}` }
},
leftToRight: (v=1) => {
return { "data-lax-translate-x": `vh 0, -elh (vw*${v})` }
},
rightToLeft: (v=1) => {
return { "data-lax-translate-x": `vh 0, -elh (vw*${-v})` }
},
zoomInOut: (v=0.2) => {
return { "data-lax-scale": `(vh) ${v}, (vh*0.8) 1, (vh*0.2) 1, -elh ${v}` }
},
zoomIn: (v=0.2) => {
return { "data-lax-scale": `(vh) ${v}, (vh*0.7) 1` }
},
zoomOut: (v=0.2) => {
return { "data-lax-scale": `(vh*0.3) 1, -elh ${v}` }
},
speedy: (v=30) => {
return { "data-lax-skew-x": `(vh) ${v}, -elh ${-v}` }
},
swing: (v=30) => {
return { "data-lax-skew-y": `(vh) ${v}, -elh ${-v}` }
}
}
let retKey = keys[keys.length - 1]
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
if (windowWidth < key) {
retKey = key
lax.addPreset = (p, o) => {
lax.presets[p] = o
}
function intrp(t, v) {
let i = 0
while(t[i][0] <= v && t[i+1] !== undefined) {
i+=1
}
const x = t[i][0]
const prevX = t[i-1] === undefined ? x : t[i-1][0]
const y = t[i][1]
const prevY = t[i-1] === undefined ? y : t[i-1][1]
const xPoint = Math.min(Math.max((v-prevX)/(x-prevX),0),1)
const yPoint = (xPoint*(y-prevY)) + prevY
return yPoint
}
function fnOrVal(s) {
if(s[0] === "(") return eval(s)
else return parseFloat(s)
}
lax.setup = (o={}) => {
lax.breakpoints = o.breakpoints || {}
lax.selector = o.selector || '.lax'
lax.populateElements()
}
lax.removeElement = (el) => {
const i = lax.elements.findIndex(o => o.el === el)
if(i > -1) {
lax.elements.splice(i, 1)
}
}
lax.createLaxObject = (el) => {
const o = {
el: el,
originalStyle: {
transform: el.style.transform,
filter: el.style.filter
},
transforms: {}
}
return o
}
lax.calcTransforms = (o) => {
const { el } = o
//find presets in data attributes
const presets = []
for(let i=0; i<el.attributes.length; i++) {
const a = el.attributes[i]
if(a.name.indexOf("data-lax-preset") > -1) {
presets.push(a);
}
}
//unwrap presets into transformations
for(let i=0; i<presets.length; i++) {
const a = presets[i]
const b = a.name.split(breakpointsSeparator)
const breakpoint = b[1] ? `${breakpointsSeparator}${b[1]}` : ''
a.value.split(" ").forEach((p) => {
const bits = p.split("-")
const fn = lax.presets[bits[0]]
if(!fn) {
console.log(`lax error: preset ${bits[0]} is not defined`)
} else {
const d = fn(bits[1])
for(let k in d) {
el.setAttribute(`${k}${breakpoint}`, d[k])
}
}
})
const currentAnchor = el.getAttribute("data-lax-anchor")
if(!currentAnchor || currentAnchor === "") el.setAttribute("data-lax-anchor", "self")
el.attributes.removeNamedItem(a.name)
}
// use gpu
const useGpu = !(el.attributes["data-lax-use-gpu"] && el.attributes["data-lax-use-gpu"].value === 'false')
if(useGpu) {
el.style["backface-visibility"] = "hidden"
el.style["-webkit-backface-visibility"] = "hidden"
}
if(el.attributes["data-lax-use-gpu"]) el.attributes.removeNamedItem("data-lax-use-gpu")
// optmise off screen
o.optimise = false
if(el.attributes["data-lax-optimize"] && el.attributes["data-lax-optimize"].value === 'true') {
o.optimise = true
const bounds = el.getBoundingClientRect()
el.setAttribute("data-lax-opacity", `${-bounds.height-1} 0, ${-bounds.height} 1, ${window.innerHeight} 1, ${window.innerHeight+1} 0`)
el.attributes.removeNamedItem("data-lax-optimize")
}
// build transform list
for(let i=0; i<el.attributes.length; i++) {
const a = el.attributes[i]
if(a.name.indexOf("data-lax") < 0) continue
const b = a.name.split(breakpointsSeparator)
const bits = b[0].split("-")
const breakpoint = b[1] || "default"
if(bits[1] === "lax") {
if(a.name === "data-lax-anchor") {
o["data-lax-anchor"] = a.value === "self" ? el : document.querySelector(a.value)
const rect = o["data-lax-anchor"].getBoundingClientRect()
o.anchorTop = Math.floor(rect.top) + window.scrollY
} else {
const tString = a.value
.replace(/vw/g, window.innerWidth)
.replace(/vh/g, window.innerHeight)
.replace(/elh/g, el.clientHeight)
.replace(/elw/g, el.clientWidth)
.replace(/\s+/g," ")
const [arrString, optionString] = tString.split("|")
const options = {}
if(optionString) {
optionString.split(" ").forEach((o) => {
const [key, val] = o.split("=")
options[key] = key && fnOrVal(val)
})
}
const name = b[0]
const valueMap = arrString.split(",").map((x) => {
return x.trim().split(" ").map(fnOrVal)
}).sort((a,b) => {
return a[0] - b[0]
})
if(!o.transforms[name]) {
o.transforms[name] = {}
}
o.transforms[name][breakpoint] = { valueMap, options }
}
}
}
// sprite sheet animation
const spriteData = el.attributes["data-lax-sprite-data"] && el.attributes["data-lax-sprite-data"].value
if(spriteData) {
o.spriteData = spriteData.split(",").map(x => parseInt(x))
el.style.height = o.spriteData[1] + "px"
el.style.width = o.spriteData[0] + "px"
const spriteImage = el.attributes["data-lax-sprite-image"] && el.attributes["data-lax-sprite-image"].value
if(spriteImage) {
el.style.backgroundImage = `url(${spriteImage})`
}
}
return o
}
lax.addElement = (el) => {
const o = lax.calcTransforms(lax.createLaxObject(el))
lax.elements.push(o)
lax.updateElement(o)
}
lax.populateElements = () => {
lax.elements = []
document.querySelectorAll(lax.selector).forEach(lax.addElement)
currentBreakpoint = lax.getCurrentBreakPoint()
}
lax.updateElements = () => {
lax.elements.forEach((o) => {
lax.calcTransforms(o)
lax.updateElement(o)
})
currentBreakpoint = lax.getCurrentBreakPoint()
}
lax.getCurrentBreakPoint = () => {
let b = 'default'
const w = window.innerWidth
for(let i in lax.breakpoints) {
const px = parseFloat(lax.breakpoints[i])
if(px <= w) {
b = i
} else {
break
}
}
return arr[retKey]
return b
}
function lerp(start, end, t) {
return start * (1 - t) + end * t
}
lax.updateElement = (o) => {
const { originalStyle, anchorTop, transforms, spriteData, el } = o
function invlerp(a, b, v) {
return (v - a) / (b - a)
}
let r = anchorTop ? anchorTop-lastY : lastY
function interpolate(arrA, arrB, v, easingFn) {
let k = 0
arrA.forEach((a) => {
if (a < v) k++
})
if (k <= 0) {
return arrB[0]
const style = {
transform: originalStyle.transform,
filter: originalStyle.filter
}
if (k >= arrA.length) {
return arrB[arrA.length - 1]
}
for(let i in transforms) {
const transformData = transforms[i][currentBreakpoint] || transforms[i]["default"]
const j = k - 1
let vector = invlerp(arrA[j], arrA[k], v)
if (easingFn) vector = easingFn(vector)
const lerpVal = lerp(arrB[j], arrB[k], vector)
return lerpVal
}
const easings = {
easeInQuad: t => t * t,
easeOutQuad: t => t * (2 - t),
easeInOutQuad: t => t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
easeInCubic: t => t * t * t,
easeOutCubic: t => (--t) * t * t + 1,
easeInOutCubic: t => t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
easeInQuart: t => t * t * t * t,
easeOutQuart: t => 1 - (--t) * t * t * t,
easeInOutQuart: t => t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t,
easeInQuint: t => t * t * t * t * t,
easeOutQuint: t => 1 + (--t) * t * t * t * t,
easeInOutQuint: t => t < .5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t,
easeOutBounce: t => {
const n1 = 7.5625;
const d1 = 2.75;
if (t < 1 / d1) {
return n1 * t * t;
} else if (t < 2 / d1) {
return n1 * (t -= 1.5 / d1) * t + 0.75;
} else if (t < 2.5 / d1) {
return n1 * (t -= 2.25 / d1) * t + 0.9375;
} else {
return n1 * (t -= 2.625 / d1) * t + 0.984375;
}
},
easeInBounce: t => {
return 1 - easings.easeOutBounce(1 - t);
},
easeOutBack: t => {
const c1 = 1.70158;
const c3 = c1 + 1;
return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
},
easeInBack: t => {
const c1 = 1.70158;
const c3 = c1 + 1;
return c3 * t * t * t - c1 * t * t;
},
}
function flattenStyles(styles) {
const flattenedStyles = {
transform: '',
filter: ''
}
const translate3dValues = {
translateX: 0.00001,
translateY: 0.00001,
translateZ: 0.00001
}
Object.keys(styles).forEach((key) => {
const val = styles[key]
const unit = pxUnits.includes(key) ? 'px' : (degUnits.includes(key) ? 'deg' : '')
if (translate3dKeys.includes(key)) {
translate3dValues[key] = val
} else if (transformKeys.includes(key)) {
flattenedStyles.transform += `${key}(${val}${unit}) `
} else if (filterKeys.includes(key)) {
flattenedStyles.filter += `${key}(${val}${unit}) `
} else {
flattenedStyles[key] = `${val}${unit} `
}
})
flattenedStyles.transform = `translate3d(${translate3dValues.translateX}px, ${translate3dValues.translateY}px, ${translate3dValues.translateZ}px) ${flattenedStyles.transform}`
return flattenedStyles
}
// https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY#Notes
function getScrollPosition() {
const supportPageOffset = window.pageXOffset !== undefined
const isCSS1Compat = ((document.compatMode || '') === 'CSS1Compat')
const x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft
const y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop
return [y, x]
}
function parseValue(val, { width, height, x, y }, index) {
if (typeof val === 'number') {
return val
}
const pageHeight = document.body.scrollHeight
const pageWidth = document.body.scrollWidth
const screenWidth = window.innerWidth
const screenHeight = window.innerHeight
const [scrollTop, scrollLeft] = getScrollPosition()
const left = x + scrollLeft
const right = left + width
const top = y + scrollTop
const bottom = top + height
return Function(`return ${val
.replace(/screenWidth/g, screenWidth)
.replace(/screenHeight/g, screenHeight)
.replace(/pageHeight/g, pageHeight)
.replace(/pageWidth/g, pageWidth)
.replace(/elWidth/g, width)
.replace(/elHeight/g, height)
.replace(/elInY/g, top - screenHeight)
.replace(/elOutY/g, bottom)
.replace(/elCenterY/g, top + (height / 2) - (screenHeight / 2))
.replace(/elInX/g, left - screenWidth)
.replace(/elOutX/g, right)
.replace(/elCenterX/g, left + (width / 2) - (screenWidth / 2))
.replace(/index/g, index)
}`)()
}
class LaxDriver {
getValueFn
name = ''
lastValue = 0
frameStep = 1
m1 = 0
m2 = 0
inertia = 0
inertiaEnabled = false
constructor(name, getValueFn, options = {}) {
this.name = name
this.getValueFn = getValueFn
Object.keys(options).forEach((key) => {
this[key] = options[key]
})
this.lastValue = this.getValueFn(0)
}
getValue = (frame) => {
let value = this.lastValue
if (frame % this.frameStep === 0) {
value = this.getValueFn(frame)
if(!transformData) {
// console.log(`lax error: there is no setting for key ${i} and screen size ${currentBreakpoint}. Try adding a default value!`)
continue
}
if (this.inertiaEnabled) {
const delta = value - this.lastValue
const damping = 0.8
let _r = r
if(transformData.options.offset) _r = _r+transformData.options.offset
if(transformData.options.speed) _r = _r*transformData.options.speed
if(transformData.options.loop) _r = _r%transformData.options.loop
this.m1 = this.m1 * damping + delta * (1 - damping)
this.m2 = this.m2 * damping + this.m1 * (1 - damping)
this.inertia = Math.round(this.m2 * 5000) / 15000
const t = transformFns[i]
const v = intrp(transformData.valueMap, _r)
if(!t) {
// console.info(`lax: error ${i} is not supported`)
continue
}
this.lastValue = value
return [this.lastValue, this.inertia]
t(style, v)
}
if(spriteData) {
const [frameW,frameH,numFrames,cols,scrollStep] = spriteData
const frameNo = Math.floor(lastY/scrollStep) % numFrames
const framePosX = frameNo%cols
const framePosY = Math.floor(frameNo/cols)
style.backgroundPosition = `-${framePosX*frameW}px -${framePosY*frameH}px`
}
if(style.opacity === 0) { // if opacity 0 don't update
el.style.opacity = 0
} else {
for(let k in style) {
el.style[k] = style[k]
}
}
}
class LaxElement {
domElement
transformsData
styles = {}
selector = ''
groupIndex = 0
laxInstance
onUpdate
constructor(selector, laxInstance, domElement, transformsData, groupIndex = 0, options = {}) {
this.selector = selector
this.laxInstance = laxInstance
this.domElement = domElement
this.transformsData = transformsData
this.groupIndex = groupIndex
const { style = {}, onUpdate } = options
Object.keys(style).forEach(key => {
domElement.style.setProperty(key, style[key])
})
if (onUpdate) this.onUpdate = onUpdate
this.calculateTransforms()
}
update = (driverValues, frame) => {
const { transforms } = this
const styles = {}
for (let driverName in transforms) {
const styleBindings = transforms[driverName]
if (!driverValues[driverName]) {
console.error("No lax driver with name: ", driverName)
}
const [value, inertiaValue] = driverValues[driverName]
for (let key in styleBindings) {
const [arr1, arr2, options = {}] = styleBindings[key]
const { modValue, frameStep = 1, easing, inertia, inertiaMode, cssFn, cssUnit = '' } = options
const easingFn = easings[easing]
if (frame % frameStep === 0) {
const v = modValue ? value % modValue : value
let interpolatedValue = interpolate(arr1, arr2, v, easingFn)
if (inertia) {
let inertiaExtra = inertiaValue * inertia
if (inertiaMode === 'absolute') inertiaExtra = Math.abs((inertiaExtra))
interpolatedValue += inertiaExtra
}
const unit = cssUnit || pxUnits.includes(key) ? 'px' : (degUnits.includes(key) ? 'deg' : '')
const dp = unit === 'px' ? 0 : 3
const val = interpolatedValue.toFixed(dp)
styles[key] = cssFn ? cssFn(val, this.domElement) : val + cssUnit
}
}
}
this.applyStyles(styles)
if (this.onUpdate) this.onUpdate(driverValues, this.domElement)
}
calculateTransforms = () => {
this.transforms = {}
const windowWidth = this.laxInstance.windowWidth
for (let driverName in this.transformsData) {
let styleBindings = this.transformsData[driverName]
const parsedStyleBindings = {}
const { presets = [] } = styleBindings
presets.forEach((presetString) => {
const [presetName, y, str] = presetString.split(":")
const presetFn = window.lax.presets[presetName]
if (!presetFn) {
console.error("Lax preset cannot be found with name: ", presetName)
} else {
const preset = presetFn(y, str)
Object.keys(preset).forEach((key) => {
styleBindings[key] = preset[key]
})
}
})
delete styleBindings.presets
for (let key in styleBindings) {
let [arr1 = [-1e9, 1e9], arr2 = [-1e9, 1e9], options = {}] = styleBindings[key]
const bounds = this.domElement.getBoundingClientRect()
const parsedArr1 = getArrayValues(arr1, windowWidth).map(i => parseValue(i, bounds, this.groupIndex))
const parsedArr2 = getArrayValues(arr2, windowWidth).map(i => parseValue(i, bounds, this.groupIndex))
parsedStyleBindings[key] = [parsedArr1, parsedArr2, options]
}
this.transforms[driverName] = parsedStyleBindings
}
}
applyStyles = (styles) => {
const mergedStyles = flattenStyles(styles)
Object.keys(mergedStyles).forEach((key) => {
this.domElement.style.setProperty(key, mergedStyles[key])
})
}
lax.update = (y) => {
if(lastY === y) return
lastY = y
lax.elements.forEach(lax.updateElement)
}
class Lax {
drivers = []
elements = []
frame = 0
debug = false
windowWidth = 0
windowHeight = 0
presets = laxPresets
debugData = {
frameLengths: []
}
init = () => {
this.findAndAddElements()
window.requestAnimationFrame(this.onAnimationFrame)
this.windowWidth = document.body.clientWidth
this.windowHeight = document.body.clientHeight
window.onresize = this.onWindowResize
}
onWindowResize = () => {
const changed = document.body.clientWidth !== this.windowWidth ||
document.body.clientHeight !== this.windowHeight
if (changed) {
this.windowWidth = document.body.clientWidth
this.windowHeight = document.body.clientHeight
this.elements.forEach(el => el.calculateTransforms())
}
}
onAnimationFrame = (e) => {
if (this.debug) {
this.debugData.frameStart = Date.now()
}
const driverValues = {}
this.drivers.forEach((driver) => {
driverValues[driver.name] = driver.getValue(this.frame)
})
this.elements.forEach((element) => {
element.update(driverValues, this.frame)
})
if (this.debug) {
this.debugData.frameLengths.push(Date.now() - this.debugData.frameStart)
}
if (this.frame % 60 === 0 && this.debug) {
const averageFrameTime = Math.ceil((this.debugData.frameLengths.reduce((a, b) => a + b, 0) / 60))
console.log(`Average frame calculation time: ${averageFrameTime}ms`)
this.debugData.frameLengths = []
}
this.frame++
window.requestAnimationFrame(this.onAnimationFrame)
}
addDriver = (name, getValueFn, options = {}) => {
this.drivers.push(
new LaxDriver(name, getValueFn, options)
)
}
removeDriver = (name) => {
this.drivers = this.drivers.filter(driver => driver.name !== name)
}
findAndAddElements = () => {
this.elements = []
const elements = document.querySelectorAll(".lax")
elements.forEach((domElement) => {
const driverName = "scrollY"
const presets = []
domElement.classList.forEach((className) => {
if (className.includes("lax_preset")) {
const preset = className.replace("lax_preset_", "")
presets.push(preset)
}
})
const transforms = {
[driverName]: {
presets
}
}
this.elements.push(new LaxElement('.lax', this, domElement, transforms, 0, {}))
})
}
addElements = (selector, transforms, options) => {
const domElements = document.querySelectorAll(selector)
domElements.forEach((domElement, i) => {
this.elements.push(new LaxElement(selector, this, domElement, transforms, i, options))
})
}
removeElements = (selector) => {
this.elements = this.elements.filter(element => element.selector !== selector)
}
addElement = (domElement, transforms, options) => {
this.elements.push(new LaxElement('', this, domElement, transforms, 0, options))
}
removeElement = (domElement) => {
this.elements = this.elements.filter(element => element.domElement !== domElement)
}
}
return new Lax()
})()
return lax;
})();
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined')
module.exports = laxInstance;
module.exports = lax;
else
window.lax = laxInstance;
})()
window.lax = lax;
})();

2340
yarn.lock

File diff suppressed because it is too large Load Diff