Our impact is delivered through integrated human performance specialists, customized education and training, and tech resources - geared towards elevating culture, improving mental and physical well-being, supporting healthy lifestyles, and reducing healthcare costs associated with injuries and illnesses.
Whether our client’s target is to reduce cardiac disease, cancer rates, suicides, orthopedic injuries, post-traumatic stress or simply strengthen culture and performance - O2X helps individuals and organizations implement the most optimal and effective strategy to do so.
O2X provides customized wellness programs for high performing organizations that optimize every aspect of their most valuable resource: people. Our multidisciplinary approach consolidates all aspects of human performance (sleep, nutrition, conditioning, resilience, and stress management) into a simplified EAT SWEAT THRIVE™ methodology.
“The O2X program provides focused training that helps us maintain a level of physical and mental fitness that fire and EMS requires. Our continued partnership results in a more resilient workforce that is better equipped to handle the unique challenges of our profession’...‘Loudoun County fully supports this program, and it is our intent to continue this training into the foreseeable future.”
Assistant Chief Travis Preau
Loudoun County Fire and Rescue
“We’re excited to partner with O2X Human Performance and to be able to provide these invaluable resources to our nation’s heroes’...‘We believe that this workshop will have a lasting impact on the physical and mental health of our veterans.”
Founder and CEO Andy Pujol
Building Homes for Heroes
“The curriculum of Eat, Sweat, Thrive that O2X Human Performance has put together is in total alignment with the program that our Wellness team is promoting to our members currently,’...‘We are excited to give our members exposure to this incredible and intelligent program design to spread and expand the Wellness mission to our members.”
Lieutenant Jackie Fehr
Denver Fire Department
“A comprehensive wellness program is important to the overall health of our firefighters. Partnering with an experienced and proven company like O2X Human Performance, who has provided similar programs for other public safety agencies, will be valuable in the development and implementation of our new program."
Chief Louis Winston
Howard County Department of Fire and Rescue Services
“More than ever, Norfolk Fire-Rescue recognizes the value of making both physical and mental health a top priority for our members’...‘O2X is that valuable tool in our toolbox which reinforces our commitment to ensuring healthier lifestyles throughout our careers and beyond.”
Chief John DiBacco
Norfolk Fire-Rescue
“Firefighters cannot underplay the deleterious effects of sleep deprivation and long shifts. O2X is the industry leader in bolstering up our tactical athletes, and bringing us the tools to have healthy, well-balanced careers. We extend our heartfelt thanks to FirstNet for providing us this amazing opportunity to support our California Firefighters.”
Chief Heather Marques
Alameda County Fire Department
“The Berkeley Police Department is eager to address the negative impact of the stressors with the support and guidance of O2X On-Site Specialists. We are optimistic that by offering the O2X holistic, entire body wellness program to our police employees, they will be provided the tools necessary to achieve the strength and resiliency necessary to see the finish line of a long rewarding career.”
Lieutenant Jen Tate
Berkeley Police Department
Featured On
tag)
document.addEventListener("DOMContentLoaded", function() {
// Check if GSAP is loaded
if (typeof gsap === 'undefined') {
return;
}
// Configuration
const config = {
// Default animation settings
duration: 0.8,
ease: "power2.out",
yDistance: 30,
stagger: 0.2,
// ScrollTrigger settings (fallback)
triggerStart: "top 85%",
triggerEnd: "bottom 15%",
// Intersection Observer settings
intersectionThreshold: 0.1, // Trigger when 10% of element is visible
intersectionRootMargin: "0px 0px -100px 0px" // Trigger 100px before element enters viewport
};
// Store created timelines for cleanup
const createdTimelines = new Map();
const observedElements = new Set();
// Initialize fade animations
function initFadeAnimations() {
// Find all elements with fade attributes
const fadeElements = document.querySelectorAll('[data-fade]');
if (fadeElements.length === 0) {
return;
}
// Group elements by their container or sequence
const fadeGroups = {};
fadeElements.forEach(element => {
const fadeType = element.getAttribute('data-fade');
const sequence = element.getAttribute('data-fade-sequence') || 'default';
const container = element.getAttribute('data-fade-container') || 'global';
const groupKey = `${container}-${sequence}`;
if (!fadeGroups[groupKey]) {
fadeGroups[groupKey] = [];
}
fadeGroups[groupKey].push({
element: element,
type: fadeType,
delay: parseFloat(element.getAttribute('data-fade-delay')) || 0,
duration: parseFloat(element.getAttribute('data-fade-duration')) || config.duration,
yDistance: parseFloat(element.getAttribute('data-fade-y')) || config.yDistance,
order: parseInt(element.getAttribute('data-fade-order')) || fadeGroups[groupKey].length
});
});
// Sort groups by order and create animations
Object.keys(fadeGroups).forEach(groupKey => {
const group = fadeGroups[groupKey].sort((a, b) => a.order - b.order);
createFadeAnimation(group, groupKey);
});
}
// Create Intersection Observer for consecutive sections
function createIntersectionObserver(element) {
// Get threshold and root margin from element attributes or use defaults
const threshold = parseFloat(element.getAttribute('data-fade-threshold')) || config.intersectionThreshold;
const rootMargin = element.getAttribute('data-fade-root-margin') || config.intersectionRootMargin;
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const timeline = createdTimelines.get(entry.target);
if (timeline && !timeline.isActive()) {
timeline.play();
}
} else {
// Handle reverse animation if specified
const firstFadeElement = entry.target.querySelector('[data-fade]');
if (firstFadeElement && firstFadeElement.getAttribute('data-fade-reverse') === 'true') {
const timeline = createdTimelines.get(entry.target);
if (timeline) {
timeline.reverse();
}
}
}
});
}, {
threshold: threshold,
rootMargin: rootMargin
});
return observer;
}
// Create fade animation for a group of elements
function createFadeAnimation(group, groupKey) {
const timeline = gsap.timeline({
paused: true
});
// Set initial states for all elements in the group
// Force override any existing inline styles (like from Webflow)
group.forEach(item => {
gsap.set(item.element, {
opacity: 0,
y: item.yDistance,
scale: item.type === 'scale' ? 0.8 : 1,
clearProps: "all", // Clear any existing transform properties
force3D: true
});
// Remove any conflicting inline styles
item.element.style.removeProperty('translate');
item.element.style.removeProperty('rotate');
item.element.style.removeProperty('scale');
item.element.style.removeProperty('transform');
item.element.style.removeProperty('opacity');
});
// Add animations to timeline
group.forEach((item, index) => {
const animationProps = {
opacity: 1,
y: 0,
duration: item.duration,
ease: config.ease
};
// Add scale animation if specified
if (item.type === 'scale') {
animationProps.scale = 1;
}
// Add rotation if specified
if (item.type === 'rotate') {
gsap.set(item.element, { rotation: -5 });
animationProps.rotation = 0;
}
// Add to timeline with stagger
timeline.to(item.element, animationProps, index * config.stagger + item.delay);
});
// Determine trigger element and animation method
const triggerElement = group[0].element.closest('[data-fade-container]') || group[0].element;
const triggerMethod = group[0].element.getAttribute('data-fade-trigger') || 'intersection';
const useIntersection = triggerMethod === 'intersection';
const useScrollTrigger = triggerMethod === 'scroll';
const useImmediate = triggerMethod === 'immediate';
// Store timeline for later reference
createdTimelines.set(triggerElement, timeline);
if (useIntersection) {
// Use Intersection Observer (recommended for consecutive sections)
if (!observedElements.has(triggerElement)) {
const observer = createIntersectionObserver(triggerElement);
observer.observe(triggerElement);
observedElements.add(triggerElement);
}
} else if (useScrollTrigger && typeof ScrollTrigger !== 'undefined') {
// Use ScrollTrigger for viewport-based animation
ScrollTrigger.create({
trigger: triggerElement,
start: config.triggerStart,
end: config.triggerEnd,
onEnter: () => timeline.play(),
onLeave: () => {
if (group[0].element.getAttribute('data-fade-reverse') === 'true') {
timeline.reverse();
}
},
onEnterBack: () => timeline.play(),
onLeaveBack: () => {
if (group[0].element.getAttribute('data-fade-reverse') === 'true') {
timeline.reverse();
}
}
});
} else if (useImmediate) {
// Immediate animation (useful for hero sections)
setTimeout(() => {
timeline.play();
}, 100);
} else {
// Default to intersection observer if no method specified
if (!observedElements.has(triggerElement)) {
const observer = createIntersectionObserver(triggerElement);
observer.observe(triggerElement);
observedElements.add(triggerElement);
}
}
}
// Cleanup function for dynamic content
function cleanup() {
// Clear existing timelines
createdTimelines.forEach(timeline => {
timeline.kill();
});
createdTimelines.clear();
observedElements.clear();
// Kill ScrollTrigger instances if they exist
if (typeof ScrollTrigger !== 'undefined') {
ScrollTrigger.getAll().forEach(trigger => {
if (trigger.trigger && trigger.trigger.hasAttribute('data-fade')) {
trigger.kill();
}
});
}
}
// Initialize animations with delay to override Webflow
setTimeout(() => {
initFadeAnimations();
}, 500); // Wait for Webflow animations to complete
// Re-initialize on dynamic content changes
const observer = new MutationObserver(function(mutations) {
let shouldReinitialize = false;
mutations.forEach(function(mutation) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(function(node) {
if (node.nodeType === 1 && (node.hasAttribute('data-fade') || node.querySelector('[data-fade]'))) {
shouldReinitialize = true;
}
});
}
});
if (shouldReinitialize) {
cleanup();
setTimeout(initFadeAnimations, 100);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
// Cleanup on page unload
window.addEventListener('beforeunload', cleanup);
});