Repository files navigation

Motion Frame

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

About

Motion Frame is an animation engine that is run off the concept of lambda animation functions. The way that these functions work is that you define the end state of an animation that you want in JS, and then multiply any values with the provided easing variable x (value between 0 and 1) and then let the engine work its magic :)

Usage

To use Motion Frame, run npm install motion-frame and import Motion and / or MotionChain into your project. Motion is the main class to use to initiated your animations, while MotionChain allows you to chain animations together to then play in order. To use them, you need to provide an MotionProps object in the constructor (in the the MotionChain's case, an array of MotionProps)

KeyTypeDefaultDescription
animation (required)Function (AnimationFrame)voidThe lambda animation that will run
easingFunction (x)(x) => xThe easing function that the animation will take
durationNumber1000The duration of the animation in milliseconds
reverseBooleanfalseIf the animation should play in reverse
loopLoopTypeLoopType.NONEIf the animation should loop after it finishes
beforeFunction (state)(state) => {}A function that will trigger before the animation has begun (resets after stop)
afterFunction (state)(state) => {}A function that will trigger once the animation has finished each run
stateObject{}Persistent state that can be accessed within the animation and after lambdas
resetFunctionvoidGets called immediately after the animation gets reset to its original position

Example

import{Motion}from"motion-frame";constboxElement=document.getElementById("box");constboxRect=boxElement.getBoundingClientRect();constboxAnimation=newMotion({duration: 2000,loop: LoopType.ALTERNATE,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{letdestX=(window.innerWidth-boxRect.width)/2;letamountX=(destX-boxRect.left)*frame.progress;boxElement.style.left=`${amountX}px`;},after: ()=>{boxElement.innerHTML=boxAnimation.playCount;}});boxAnimation.play();

Box animation

AnimationFrame

The animation function receives an object containing three parameters:

  • progress (number): The eased progress value (0-1) after the easing function has been applied
  • progressMs (number): (number): The unmodified progress value (0-1) before easing is applied
  • state (TState): The persistent state object

This allows you to use different progression values for different aspects of your animation:

import{Motion}from"motion-frame";constcomplexAnimation=newMotion({duration: 1000,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{const{ progress, progressMs }=frame;// Use eased value for position (accelerated movement)element.style.left=`${progress*100}px`;// Use linear value for opacity (steady fade)element.style.opacity=progressMs;}});

TODO - Future enhancements / additions

  1. Make some pre-build easing functions available
  2. Create a bunch of examples for all the different features
  3. Build out extra documentation and examples around MotionChain
  4. Unit tests

About

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Motion Frame

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

About

Motion Frame is an animation engine that is run off the concept of lambda animation functions. The way that these functions work is that you define the end state of an animation that you want in JS, and then multiply any values with the provided easing variable x (value between 0 and 1) and then let the engine work its magic :)

Usage

To use Motion Frame, run npm install motion-frame and import Motion and / or MotionChain into your project. Motion is the main class to use to initiated your animations, while MotionChain allows you to chain animations together to then play in order. To use them, you need to provide an MotionProps object in the constructor (in the the MotionChain's case, an array of MotionProps)

KeyTypeDefaultDescription
animation (required)Function (AnimationFrame)voidThe lambda animation that will run
easingFunction (x)(x) => xThe easing function that the animation will take
durationNumber1000The duration of the animation in milliseconds
reverseBooleanfalseIf the animation should play in reverse
loopLoopTypeLoopType.NONEIf the animation should loop after it finishes
beforeFunction (state)(state) => {}A function that will trigger before the animation has begun (resets after stop)
afterFunction (state)(state) => {}A function that will trigger once the animation has finished each run
stateObject{}Persistent state that can be accessed within the animation and after lambdas
resetFunctionvoidGets called immediately after the animation gets reset to its original position

Example

import{Motion}from"motion-frame";constboxElement=document.getElementById("box");constboxRect=boxElement.getBoundingClientRect();constboxAnimation=newMotion({duration: 2000,loop: LoopType.ALTERNATE,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{letdestX=(window.innerWidth-boxRect.width)/2;letamountX=(destX-boxRect.left)*frame.progress;boxElement.style.left=`${amountX}px`;},after: ()=>{boxElement.innerHTML=boxAnimation.playCount;}});boxAnimation.play();

Box animation

AnimationFrame

The animation function receives an object containing three parameters:

  • progress (number): The eased progress value (0-1) after the easing function has been applied
  • progressMs (number): (number): The unmodified progress value (0-1) before easing is applied
  • state (TState): The persistent state object

This allows you to use different progression values for different aspects of your animation:

import{Motion}from"motion-frame";constcomplexAnimation=newMotion({duration: 1000,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{const{ progress, progressMs }=frame;// Use eased value for position (accelerated movement)element.style.left=`${progress*100}px`;// Use linear value for opacity (steady fade)element.style.opacity=progressMs;}});

TODO - Future enhancements / additions

  1. Make some pre-build easing functions available
  2. Create a bunch of examples for all the different features
  3. Build out extra documentation and examples around MotionChain
  4. Unit tests

About

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Motion Frame

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

About

Motion Frame is an animation engine that is run off the concept of lambda animation functions. The way that these functions work is that you define the end state of an animation that you want in JS, and then multiply any values with the provided easing variable x (value between 0 and 1) and then let the engine work its magic :)

Usage

To use Motion Frame, run npm install motion-frame and import Motion and / or MotionChain into your project. Motion is the main class to use to initiated your animations, while MotionChain allows you to chain animations together to then play in order. To use them, you need to provide an MotionProps object in the constructor (in the the MotionChain's case, an array of MotionProps)

KeyTypeDefaultDescription
animation (required)Function (AnimationFrame)voidThe lambda animation that will run
easingFunction (x)(x) => xThe easing function that the animation will take
durationNumber1000The duration of the animation in milliseconds
reverseBooleanfalseIf the animation should play in reverse
loopLoopTypeLoopType.NONEIf the animation should loop after it finishes
beforeFunction (state)(state) => {}A function that will trigger before the animation has begun (resets after stop)
afterFunction (state)(state) => {}A function that will trigger once the animation has finished each run
stateObject{}Persistent state that can be accessed within the animation and after lambdas
resetFunctionvoidGets called immediately after the animation gets reset to its original position

Example

import{Motion}from"motion-frame";constboxElement=document.getElementById("box");constboxRect=boxElement.getBoundingClientRect();constboxAnimation=newMotion({duration: 2000,loop: LoopType.ALTERNATE,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{letdestX=(window.innerWidth-boxRect.width)/2;letamountX=(destX-boxRect.left)*frame.progress;boxElement.style.left=`${amountX}px`;},after: ()=>{boxElement.innerHTML=boxAnimation.playCount;}});boxAnimation.play();

Box animation

AnimationFrame

The animation function receives an object containing three parameters:

  • progress (number): The eased progress value (0-1) after the easing function has been applied
  • progressMs (number): (number): The unmodified progress value (0-1) before easing is applied
  • state (TState): The persistent state object

This allows you to use different progression values for different aspects of your animation:

import{Motion}from"motion-frame";constcomplexAnimation=newMotion({duration: 1000,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{const{ progress, progressMs }=frame;// Use eased value for position (accelerated movement)element.style.left=`${progress*100}px`;// Use linear value for opacity (steady fade)element.style.opacity=progressMs;}});

TODO - Future enhancements / additions

  1. Make some pre-build easing functions available
  2. Create a bunch of examples for all the different features
  3. Build out extra documentation and examples around MotionChain
  4. Unit tests

About

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Motion Frame

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

About

Motion Frame is an animation engine that is run off the concept of lambda animation functions. The way that these functions work is that you define the end state of an animation that you want in JS, and then multiply any values with the provided easing variable x (value between 0 and 1) and then let the engine work its magic :)

Usage

To use Motion Frame, run npm install motion-frame and import Motion and / or MotionChain into your project. Motion is the main class to use to initiated your animations, while MotionChain allows you to chain animations together to then play in order. To use them, you need to provide an MotionProps object in the constructor (in the the MotionChain's case, an array of MotionProps)

KeyTypeDefaultDescription
animation (required)Function (AnimationFrame)voidThe lambda animation that will run
easingFunction (x)(x) => xThe easing function that the animation will take
durationNumber1000The duration of the animation in milliseconds
reverseBooleanfalseIf the animation should play in reverse
loopLoopTypeLoopType.NONEIf the animation should loop after it finishes
beforeFunction (state)(state) => {}A function that will trigger before the animation has begun (resets after stop)
afterFunction (state)(state) => {}A function that will trigger once the animation has finished each run
stateObject{}Persistent state that can be accessed within the animation and after lambdas
resetFunctionvoidGets called immediately after the animation gets reset to its original position

Example

import{Motion}from"motion-frame";constboxElement=document.getElementById("box");constboxRect=boxElement.getBoundingClientRect();constboxAnimation=newMotion({duration: 2000,loop: LoopType.ALTERNATE,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{letdestX=(window.innerWidth-boxRect.width)/2;letamountX=(destX-boxRect.left)*frame.progress;boxElement.style.left=`${amountX}px`;},after: ()=>{boxElement.innerHTML=boxAnimation.playCount;}});boxAnimation.play();

Box animation

AnimationFrame

The animation function receives an object containing three parameters:

  • progress (number): The eased progress value (0-1) after the easing function has been applied
  • progressMs (number): (number): The unmodified progress value (0-1) before easing is applied
  • state (TState): The persistent state object

This allows you to use different progression values for different aspects of your animation:

import{Motion}from"motion-frame";constcomplexAnimation=newMotion({duration: 1000,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{const{ progress, progressMs }=frame;// Use eased value for position (accelerated movement)element.style.left=`${progress*100}px`;// Use linear value for opacity (steady fade)element.style.opacity=progressMs;}});

TODO - Future enhancements / additions

  1. Make some pre-build easing functions available
  2. Create a bunch of examples for all the different features
  3. Build out extra documentation and examples around MotionChain
  4. Unit tests

About

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Motion Frame

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

About

Motion Frame is an animation engine that is run off the concept of lambda animation functions. The way that these functions work is that you define the end state of an animation that you want in JS, and then multiply any values with the provided easing variable x (value between 0 and 1) and then let the engine work its magic :)

Usage

To use Motion Frame, run npm install motion-frame and import Motion and / or MotionChain into your project. Motion is the main class to use to initiated your animations, while MotionChain allows you to chain animations together to then play in order. To use them, you need to provide an MotionProps object in the constructor (in the the MotionChain's case, an array of MotionProps)

KeyTypeDefaultDescription
animation (required)Function (AnimationFrame)voidThe lambda animation that will run
easingFunction (x)(x) => xThe easing function that the animation will take
durationNumber1000The duration of the animation in milliseconds
reverseBooleanfalseIf the animation should play in reverse
loopLoopTypeLoopType.NONEIf the animation should loop after it finishes
beforeFunction (state)(state) => {}A function that will trigger before the animation has begun (resets after stop)
afterFunction (state)(state) => {}A function that will trigger once the animation has finished each run
stateObject{}Persistent state that can be accessed within the animation and after lambdas
resetFunctionvoidGets called immediately after the animation gets reset to its original position

Example

import{Motion}from"motion-frame";constboxElement=document.getElementById("box");constboxRect=boxElement.getBoundingClientRect();constboxAnimation=newMotion({duration: 2000,loop: LoopType.ALTERNATE,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{letdestX=(window.innerWidth-boxRect.width)/2;letamountX=(destX-boxRect.left)*frame.progress;boxElement.style.left=`${amountX}px`;},after: ()=>{boxElement.innerHTML=boxAnimation.playCount;}});boxAnimation.play();

Box animation

AnimationFrame

The animation function receives an object containing three parameters:

  • progress (number): The eased progress value (0-1) after the easing function has been applied
  • progressMs (number): (number): The unmodified progress value (0-1) before easing is applied
  • state (TState): The persistent state object

This allows you to use different progression values for different aspects of your animation:

import{Motion}from"motion-frame";constcomplexAnimation=newMotion({duration: 1000,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{const{ progress, progressMs }=frame;// Use eased value for position (accelerated movement)element.style.left=`${progress*100}px`;// Use linear value for opacity (steady fade)element.style.opacity=progressMs;}});

TODO - Future enhancements / additions

  1. Make some pre-build easing functions available
  2. Create a bunch of examples for all the different features
  3. Build out extra documentation and examples around MotionChain
  4. Unit tests

About

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Motion Frame

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

About

Motion Frame is an animation engine that is run off the concept of lambda animation functions. The way that these functions work is that you define the end state of an animation that you want in JS, and then multiply any values with the provided easing variable x (value between 0 and 1) and then let the engine work its magic :)

Usage

To use Motion Frame, run npm install motion-frame and import Motion and / or MotionChain into your project. Motion is the main class to use to initiated your animations, while MotionChain allows you to chain animations together to then play in order. To use them, you need to provide an MotionProps object in the constructor (in the the MotionChain's case, an array of MotionProps)

KeyTypeDefaultDescription
animation (required)Function (AnimationFrame)voidThe lambda animation that will run
easingFunction (x)(x) => xThe easing function that the animation will take
durationNumber1000The duration of the animation in milliseconds
reverseBooleanfalseIf the animation should play in reverse
loopLoopTypeLoopType.NONEIf the animation should loop after it finishes
beforeFunction (state)(state) => {}A function that will trigger before the animation has begun (resets after stop)
afterFunction (state)(state) => {}A function that will trigger once the animation has finished each run
stateObject{}Persistent state that can be accessed within the animation and after lambdas
resetFunctionvoidGets called immediately after the animation gets reset to its original position

Example

import{Motion}from"motion-frame";constboxElement=document.getElementById("box");constboxRect=boxElement.getBoundingClientRect();constboxAnimation=newMotion({duration: 2000,loop: LoopType.ALTERNATE,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{letdestX=(window.innerWidth-boxRect.width)/2;letamountX=(destX-boxRect.left)*frame.progress;boxElement.style.left=`${amountX}px`;},after: ()=>{boxElement.innerHTML=boxAnimation.playCount;}});boxAnimation.play();

Box animation

AnimationFrame

The animation function receives an object containing three parameters:

  • progress (number): The eased progress value (0-1) after the easing function has been applied
  • progressMs (number): (number): The unmodified progress value (0-1) before easing is applied
  • state (TState): The persistent state object

This allows you to use different progression values for different aspects of your animation:

import{Motion}from"motion-frame";constcomplexAnimation=newMotion({duration: 1000,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{const{ progress, progressMs }=frame;// Use eased value for position (accelerated movement)element.style.left=`${progress*100}px`;// Use linear value for opacity (steady fade)element.style.opacity=progressMs;}});

TODO - Future enhancements / additions

  1. Make some pre-build easing functions available
  2. Create a bunch of examples for all the different features
  3. Build out extra documentation and examples around MotionChain
  4. Unit tests

About

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Motion Frame

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

About

Motion Frame is an animation engine that is run off the concept of lambda animation functions. The way that these functions work is that you define the end state of an animation that you want in JS, and then multiply any values with the provided easing variable x (value between 0 and 1) and then let the engine work its magic :)

Usage

To use Motion Frame, run npm install motion-frame and import Motion and / or MotionChain into your project. Motion is the main class to use to initiated your animations, while MotionChain allows you to chain animations together to then play in order. To use them, you need to provide an MotionProps object in the constructor (in the the MotionChain's case, an array of MotionProps)

KeyTypeDefaultDescription
animation (required)Function (AnimationFrame)voidThe lambda animation that will run
easingFunction (x)(x) => xThe easing function that the animation will take
durationNumber1000The duration of the animation in milliseconds
reverseBooleanfalseIf the animation should play in reverse
loopLoopTypeLoopType.NONEIf the animation should loop after it finishes
beforeFunction (state)(state) => {}A function that will trigger before the animation has begun (resets after stop)
afterFunction (state)(state) => {}A function that will trigger once the animation has finished each run
stateObject{}Persistent state that can be accessed within the animation and after lambdas
resetFunctionvoidGets called immediately after the animation gets reset to its original position

Example

import{Motion}from"motion-frame";constboxElement=document.getElementById("box");constboxRect=boxElement.getBoundingClientRect();constboxAnimation=newMotion({duration: 2000,loop: LoopType.ALTERNATE,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{letdestX=(window.innerWidth-boxRect.width)/2;letamountX=(destX-boxRect.left)*frame.progress;boxElement.style.left=`${amountX}px`;},after: ()=>{boxElement.innerHTML=boxAnimation.playCount;}});boxAnimation.play();

Box animation

AnimationFrame

The animation function receives an object containing three parameters:

  • progress (number): The eased progress value (0-1) after the easing function has been applied
  • progressMs (number): (number): The unmodified progress value (0-1) before easing is applied
  • state (TState): The persistent state object

This allows you to use different progression values for different aspects of your animation:

import{Motion}from"motion-frame";constcomplexAnimation=newMotion({duration: 1000,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{const{ progress, progressMs }=frame;// Use eased value for position (accelerated movement)element.style.left=`${progress*100}px`;// Use linear value for opacity (steady fade)element.style.opacity=progressMs;}});

TODO - Future enhancements / additions

  1. Make some pre-build easing functions available
  2. Create a bunch of examples for all the different features
  3. Build out extra documentation and examples around MotionChain
  4. Unit tests

About

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Motion Frame

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

About

Motion Frame is an animation engine that is run off the concept of lambda animation functions. The way that these functions work is that you define the end state of an animation that you want in JS, and then multiply any values with the provided easing variable x (value between 0 and 1) and then let the engine work its magic :)

Usage

To use Motion Frame, run npm install motion-frame and import Motion and / or MotionChain into your project. Motion is the main class to use to initiated your animations, while MotionChain allows you to chain animations together to then play in order. To use them, you need to provide an MotionProps object in the constructor (in the the MotionChain's case, an array of MotionProps)

KeyTypeDefaultDescription
animation (required)Function (AnimationFrame)voidThe lambda animation that will run
easingFunction (x)(x) => xThe easing function that the animation will take
durationNumber1000The duration of the animation in milliseconds
reverseBooleanfalseIf the animation should play in reverse
loopLoopTypeLoopType.NONEIf the animation should loop after it finishes
beforeFunction (state)(state) => {}A function that will trigger before the animation has begun (resets after stop)
afterFunction (state)(state) => {}A function that will trigger once the animation has finished each run
stateObject{}Persistent state that can be accessed within the animation and after lambdas
resetFunctionvoidGets called immediately after the animation gets reset to its original position

Example

import{Motion}from"motion-frame";constboxElement=document.getElementById("box");constboxRect=boxElement.getBoundingClientRect();constboxAnimation=newMotion({duration: 2000,loop: LoopType.ALTERNATE,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{letdestX=(window.innerWidth-boxRect.width)/2;letamountX=(destX-boxRect.left)*frame.progress;boxElement.style.left=`${amountX}px`;},after: ()=>{boxElement.innerHTML=boxAnimation.playCount;}});boxAnimation.play();

Box animation

AnimationFrame

The animation function receives an object containing three parameters:

  • progress (number): The eased progress value (0-1) after the easing function has been applied
  • progressMs (number): (number): The unmodified progress value (0-1) before easing is applied
  • state (TState): The persistent state object

This allows you to use different progression values for different aspects of your animation:

import{Motion}from"motion-frame";constcomplexAnimation=newMotion({duration: 1000,easing: (x)=>x<0.5 ? 8*x*x*x*x : 1-Math.pow(-2*x+2,4)/2,// easeInOutQuartanimation: (frame)=>{const{ progress, progressMs }=frame;// Use eased value for position (accelerated movement)element.style.left=`${progress*100}px`;// Use linear value for opacity (steady fade)element.style.opacity=progressMs;}});

TODO - Future enhancements / additions

  1. Make some pre-build easing functions available
  2. Create a bunch of examples for all the different features
  3. Build out extra documentation and examples around MotionChain
  4. Unit tests

About

A Typescript lambda animation / easing engine built on top of requestAnimationFrame

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages