Universal Usage
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
🌐 Universal Animation System - Use Anywhere!
One animation system. Infinite possibilities. Use it everywhere across your entire monorepo.
🎯 Philosophy
The Animation Presets Gallery isn't just for scroll triggers - it's a universal animation system that works:
- ✅ Scroll Triggers - Animate on scroll
- ✅ Flash Animations - Instant animations (hover, click, focus)
- ✅ Angular Animations - Native Angular animation system
- ✅ CSS Animations - Pure CSS keyframes
- ✅ Editor Integration - Inside
editor-web - ✅ Any Component - Anywhere in your monorepo!
🚀 Usage Modes
1. Gallery Mode (Showcase)
Use Case: Display all animations for users to explore
import { AnimationPresetsGalleryComponent } from '@widgets-editor/scroll-trigger';
@Component({
template: `
<!-- Pure showcase - no integration features -->
<lib-animation-presets-gallery mode="gallery">
</lib-animation-presets-gallery>
`
})
Features in Gallery Mode:
- ✅ Browse all presets
- ✅ Click preview to see animation
- ✅ Search & filter
- ✅ Favorites (persisted)
- ❌ No "Apply" button
- ❌ No integration events
2. Integration Mode (Default)
Use Case: Pick animations to apply to elements
@Component({
template: `
<!-- Full integration features -->
<lib-animation-presets-gallery
mode="integration"
(presetApplied)="applyToElement($event)"
(presetSelected)="showPreview($event)">
</lib-animation-presets-gallery>
`
})
export class MyComponent {
applyToElement(preset: FlashAnimationPreset) {
// Apply animation to your element
console.log('Applying:', preset);
}
}
Features in Integration Mode:
- ✅ Everything from Gallery Mode
- ✅ "Apply" button on each card
- ✅
(presetApplied)event - ✅
(presetSelected)event - ✅ Integration with your components
🎨 Application Methods
Method 1: Scroll Trigger (Scroll-Based)
Best For: Animations triggered by scrolling
<div enhancedScrollTrigger="my-element"
[animationPreset]="selectedPreset()"
[start]="'top bottom'"
[end]="'80%'"
[showTriggers]="true">
Animates on scroll!
</div>
Integration Example:
@Component({
template: `
<lib-animation-presets-gallery
mode="integration"
(presetApplied)="currentPreset.set($event)">
</lib-animation-presets-gallery>
<div enhancedScrollTrigger="hero"
[animationPreset]="currentPreset()"
[start]="'top bottom'"
[end]="'80%'">
{{ content }}
</div>
`
})
export class MyComponent {
currentPreset = signal<FlashAnimationPreset>('fade-in');
}
Method 2: Flash Animations (Event-Based)
Best For: Hover, click, focus animations
<button [flashAnim]="selectedPreset()"
flashAnimTrigger="hover"
flashAnimSpeed="fast">
Hover me!
</button>
<div [flashAnim]="selectedPreset()"
flashAnimTrigger="click">
Click me!
</div>
<input [flashAnim]="selectedPreset()"
flashAnimTrigger="focus">
Integration Example:
@Component({
template: `
<lib-animation-presets-gallery
(presetApplied)="buttonAnimation.set($event)">
</lib-animation-presets-gallery>
<button [flashAnim]="buttonAnimation()"
flashAnimTrigger="hover"
flashAnimSpeed="elegant">
Animated Button
</button>
`
})
export class MyComponent {
buttonAnimation = signal<FlashAnimationPreset>('pulse');
}
Method 3: Angular Animations (Native)
Best For: Route transitions, programmatic animations
import { trigger, transition, style, animate } from '@angular/animations';
@Component({
animations: [
trigger('fadeIn', [
transition(':enter', [
style({ opacity: 0, transform: 'translateY(20px)' }),
animate('400ms ease-out', style({ opacity: 1, transform: 'translateY(0)' }))
])
])
],
template: `
<div [@fadeIn]="animationState()">
Content
</div>
`
})
Map Presets to Angular Animations:
const presetToAngularAnimation = {
'fade-in': { opacity: [0, 1] },
'slide-up': { transform: ['translateY(100px)', 'translateY(0)'] },
'scale-in': { transform: ['scale(0.5)', 'scale(1)'] }
// ... more mappings
};
Method 4: Pure CSS (No JavaScript)
Best For: Performance-critical animations, simple effects
Step 1: Extract keyframes from preset
// Generate CSS from animation preset
generateCSS(preset: FlashAnimationPreset): string {
const keyframes = this.presetKeyframes[preset];
return `
@keyframes ${preset} {
${keyframes.map((kf, i) => `
${i * 100 / (keyframes.length - 1)}% {
${Object.entries(kf).map(([k, v]) => `${k}: ${v}`).join(';')}
}
`).join('')}
}
.${preset} {
animation: ${preset} 600ms ease-out;
}
`;
}
Step 2: Apply CSS class
<div class="fade-in">Animated with CSS!</div>
Pre-Generated CSS (add to your global styles):
/* Fade In */
@keyframes fade-in {
0% { opacity: 0; }
100% { opacity: 1; }
}
/* Slide Up */
@keyframes slide-up {
0% { opacity: 0; transform: translateY(30px); }
100% { opacity: 1; transform: translateY(0); }
}
/* Scale In */
@keyframes scale-in {
0% { opacity: 0; transform: scale(0.8); }
100% { opacity: 1; transform: scale(1); }
}
/* Apply */
.animate-fade-in { animation: fade-in 600ms ease-out; }
.animate-slide-up { animation: slide-up 600ms ease-out; }
.animate-scale-in { animation: scale-in 600ms ease-out; }
Method 5: Editor-Web Integration
Best For: Visual editor, drag-and-drop builder
// Inside editor-web components
import { AnimationPresetsGalleryComponent } from '@widgets-editor/scroll-trigger';
@Component({
template: `
<!-- Animation picker for selected widget -->
<div class="property-panel">
<h3>Widget Animations</h3>
<lib-animation-presets-gallery
mode="integration"
(presetApplied)="applyToWidget($event)">
</lib-animation-presets-gallery>
</div>
`
})
export class WidgetPropertiesPanel {
applyToWidget(preset: FlashAnimationPreset) {
const widget = this.selectedWidget();
widget.animation = preset;
this.saveWidget(widget);
}
}
🎯 Common Integration Patterns
Pattern 1: Dynamic Preset Switcher
@Component({
template: `
<!-- Preset Gallery -->
<lib-animation-presets-gallery
(presetApplied)="activePreset.set($event)">
</lib-animation-presets-gallery>
<!-- Live Preview -->
<div class="preview-area">
<h3>Preview: {{ activePreset() }}</h3>
<div [flashAnim]="activePreset()"
flashAnimTrigger="manual"
#previewElement>
Preview Content
</div>
<button (click)="triggerPreview()">Play Animation</button>
</div>
`
})
export class DynamicSwitcher {
activePreset = signal<FlashAnimationPreset>('fade-in');
@ViewChild('previewElement') previewEl!: ElementRef;
triggerPreview() {
// Manually trigger animation
this.flashAnimController.trigger(this.previewEl.nativeElement, this.activePreset());
}
}
Pattern 2: Multi-Element Control
@Component({
template: `
<!-- Control Panel -->
<lib-animation-presets-gallery
(presetApplied)="applyToAll($event)">
</lib-animation-presets-gallery>
<!-- Multiple Elements -->
@for (item of items(); track item.id) {
<div [flashAnim]="item.animation"
flashAnimTrigger="hover">
{{ item.label }}
</div>
}
`
})
export class MultiElementController {
items = signal([
{ id: 1, label: 'Item 1', animation: 'fade-in' },
{ id: 2, label: 'Item 2', animation: 'slide-up' }
]);
applyToAll(preset: FlashAnimationPreset) {
this.items.update(items =>
items.map(item => ({ ...item, animation: preset }))
);
}
}
Pattern 3: Context-Aware Application
@Component({
template: `
<!-- Context Selector -->
<select [(ngModel)]="targetContext">
<option value="hover">On Hover</option>
<option value="click">On Click</option>
<option value="scroll">On Scroll</option>
</select>
<lib-animation-presets-gallery
(presetApplied)="applyWithContext($event)">
</lib-animation-presets-gallery>
<!-- Conditional Application -->
@switch (targetContext) {
@case ('hover') {
<div [flashAnim]="currentPreset()"
flashAnimTrigger="hover">
Hover Effect
</div>
}
@case ('click') {
<button [flashAnim]="currentPreset()"
flashAnimTrigger="click">
Click Effect
</button>
}
@case ('scroll') {
<div [enhancedScrollTrigger]="'scroll-elem'"
[animationPreset]="currentPreset()">
Scroll Effect
</div>
}
}
`
})
export class ContextAwareApplicator {
targetContext = 'hover';
currentPreset = signal<FlashAnimationPreset>('pulse');
applyWithContext(preset: FlashAnimationPreset) {
this.currentPreset.set(preset);
console.log(`Applied ${preset} to ${this.targetContext} context`);
}
}
📦 Exporting for Reuse
Export Animation Configs
// Export current animation setup
exportAnimationConfig() {
const config = {
preset: this.currentPreset(),
trigger: this.triggerType(),
speed: this.animationSpeed(),
delay: this.animationDelay()
};
// Download as JSON
const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `animation-config-${config.preset}.json`;
a.click();
}
// Import animation config
importAnimationConfig(file: File) {
const reader = new FileReader();
reader.onload = (e) => {
const config = JSON.parse(e.target.result as string);
this.applyConfig(config);
};
reader.readAsText(file);
}
Share via URL
// Generate shareable URL with animation config
shareAnimation() {
const config = btoa(JSON.stringify({
preset: this.currentPreset(),
trigger: this.triggerType()
}));
const url = `${window.location.origin}/preview?config=${config}`;
navigator.clipboard.writeText(url);
}
// Parse config from URL
ngOnInit() {
const params = new URLSearchParams(window.location.search);
const configStr = params.get('config');
if (configStr) {
const config = JSON.parse(atob(configStr));
this.applyConfig(config);
}
}
🎭 Best Practices
1. Choose the Right Method
| Use Case | Best Method | Why |
|---|---|---|
| Scroll-based animations | Scroll Trigger | Built-in viewport detection |
| Interactive elements | Flash Animations | Event-based, performant |
| Route transitions | Angular Animations | Native integration |
| Static pages | CSS | Zero JS overhead |
| Visual builder | Integration Mode | User-friendly picker |
2. Performance Tips
// ✅ Good: Reuse animation instances
const fadeIn = signal<FlashAnimationPreset>('fade-in');
// ❌ Bad: Create new animations constantly
() => Math.random() > 0.5 ? 'fade-in' : 'slide-up'
// ✅ Good: Batch updates
this.items.update(items =>
items.map(item => ({ ...item, animation: newPreset }))
);
// ❌ Bad: Update one by one
this.items().forEach((item, i) => {
this.items.update(items => {
items[i].animation = newPreset;
return [...items];
});
});
3. Accessibility
// Respect user preferences
@Component({
template: `
<div [flashAnim]="prefersReducedMotion() ? undefined : activePreset()">
Content
</div>
`
})
export class AccessibleAnimations {
prefersReducedMotion = signal(
window.matchMedia('(prefers-reduced-motion: reduce)').matches
);
}
🎉 Summary
One Animation System. Everywhere.
- 🎨 30+ Presets - Beautiful, pre-built animations
- 🔄 Universal - Works with scroll, hover, click, CSS, Angular
- 💾 Persistent - Favorites saved automatically
- 🎯 Two Modes - Gallery showcase or full integration
- 📦 Reusable - Export, import, share configs
- ⚡ Performant - Optimized for 60fps
- ♿ Accessible - Respects user preferences
Ready to animate everything? Pick a preset and go! 🚀