diff --git a/modules/index.ts b/modules/index.ts
index 5e53680..d5c8d27 100644
--- a/modules/index.ts
+++ b/modules/index.ts
@@ -1,4 +1,5 @@
export * from './nuc_api'
+export * from './nuc_animations'
export * from './nuc_auth'
export * from './nuc_charts'
export * from './nuc_colors'
diff --git a/modules/nuc_animations/README.md b/modules/nuc_animations/README.md
new file mode 100644
index 0000000..dccc333
--- /dev/null
+++ b/modules/nuc_animations/README.md
@@ -0,0 +1,9 @@
+#
nuc_animations
+
+Module that contains animations functions.
+
+
+
+
Contributors
+
+
diff --git a/modules/nuc_animations/_index.scss b/modules/nuc_animations/_index.scss
new file mode 100644
index 0000000..ee90acc
--- /dev/null
+++ b/modules/nuc_animations/_index.scss
@@ -0,0 +1 @@
+@import 'caterpillar', 'fade', 'rotate', 'shine';
diff --git a/modules/nuc_animations/caterpillar/_index.scss b/modules/nuc_animations/caterpillar/_index.scss
new file mode 100644
index 0000000..4e081d2
--- /dev/null
+++ b/modules/nuc_animations/caterpillar/_index.scss
@@ -0,0 +1,47 @@
+@import 'keyframes', 'mixins', 'properties';
+
+.caterpillar,
+%caterpillar {
+ background: transparent !important;
+ border: 0 !important;
+ outline: #ffffff30 1px solid !important;
+ backdrop-filter: blur(0.5em);
+ border-radius: 0 !important;
+ z-index: 1;
+ overflow: visible;
+ color: white !important;
+ text-decoration: none;
+
+ img {
+ position: relative;
+ top: -1px;
+ width: 20px;
+ height: 20px;
+ fill: white !important;
+ }
+
+ &::before {
+ content: '';
+ position: absolute;
+ inset: -1px;
+ border: 2px solid transparent !important;
+ border-image: conic-gradient(
+ from var(--angle),
+ #10b981 0deg 80deg,
+ transparent 60deg 200deg
+ )
+ 1 stretch !important;
+ animation: rotate 4s linear infinite;
+ opacity: 0;
+ transition: opacity 0.3s;
+ }
+
+ &:hover {
+ background: #ffffff09 !important;
+
+ &::before {
+ isolation: isolate;
+ opacity: 1;
+ }
+ }
+}
diff --git a/modules/nuc_animations/caterpillar/_keyframes.scss b/modules/nuc_animations/caterpillar/_keyframes.scss
new file mode 100644
index 0000000..0d4a9db
--- /dev/null
+++ b/modules/nuc_animations/caterpillar/_keyframes.scss
@@ -0,0 +1,5 @@
+@keyframes rotate {
+ to {
+ --angle: 360deg;
+ }
+}
diff --git a/modules/nuc_animations/caterpillar/_mixins.scss b/modules/nuc_animations/caterpillar/_mixins.scss
new file mode 100644
index 0000000..9656514
--- /dev/null
+++ b/modules/nuc_animations/caterpillar/_mixins.scss
@@ -0,0 +1,41 @@
+@mixin caterpillar {
+ backdrop-filter: blur(0.5em);
+ border-radius: 0 !important;
+ z-index: 1;
+ overflow: visible;
+ color: white !important;
+ text-decoration: none;
+
+ img {
+ position: relative;
+ top: -1px;
+ width: 20px;
+ height: 20px;
+ fill: white !important;
+ }
+
+ &::before {
+ content: '';
+ position: absolute;
+ inset: -1px;
+ border: 2px solid transparent !important;
+ border-image: conic-gradient(
+ from var(--angle),
+ #10b981 0deg 20deg,
+ transparent 20deg 200deg
+ )
+ 1 stretch !important;
+ animation: rotate 4s linear infinite;
+ opacity: 0;
+ transition: opacity 0.3s;
+ }
+
+ &:hover {
+ background: #ffffff09 !important;
+
+ &::before {
+ isolation: isolate;
+ opacity: 1;
+ }
+ }
+}
diff --git a/modules/nuc_animations/caterpillar/_properties.scss b/modules/nuc_animations/caterpillar/_properties.scss
new file mode 100644
index 0000000..34feeda
--- /dev/null
+++ b/modules/nuc_animations/caterpillar/_properties.scss
@@ -0,0 +1,11 @@
+@property --opacity {
+ syntax: '';
+ initial-value: 0.5;
+ inherits: false;
+}
+
+@property --angle {
+ syntax: '';
+ initial-value: 0deg;
+ inherits: false;
+}
diff --git a/modules/nuc_animations/config.json b/modules/nuc_animations/config.json
new file mode 100644
index 0000000..e515c41
--- /dev/null
+++ b/modules/nuc_animations/config.json
@@ -0,0 +1,8 @@
+{
+ "name": "nuc_animations",
+ "description": "Module that contains animation functions.",
+ "version": "0.3.1",
+ "category": "core",
+ "installed": true,
+ "enabled": true
+}
diff --git a/modules/nuc_animations/fade/_index.scss b/modules/nuc_animations/fade/_index.scss
new file mode 100644
index 0000000..71ccacc
--- /dev/null
+++ b/modules/nuc_animations/fade/_index.scss
@@ -0,0 +1,12 @@
+@import 'keyframes';
+
+%fade-in,
+.fade-in {
+ animation: fade-in 0.3s ease-in forwards;
+}
+
+%fade-out,
+.fade-out {
+ animation: fade-out 0.3s ease-in forwards;
+ opacity: 0;
+}
diff --git a/modules/nuc_animations/fade/_keyframes.scss b/modules/nuc_animations/fade/_keyframes.scss
new file mode 100644
index 0000000..5cfd80c
--- /dev/null
+++ b/modules/nuc_animations/fade/_keyframes.scss
@@ -0,0 +1,19 @@
+@keyframes fade-in {
+ 0% {
+ opacity: 0;
+ }
+
+ 100% {
+ opacity: 1;
+ }
+}
+
+@keyframes fade-out {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ }
+}
diff --git a/modules/nuc_animations/hexagons/_index.scss b/modules/nuc_animations/hexagons/_index.scss
new file mode 100644
index 0000000..2997f7d
--- /dev/null
+++ b/modules/nuc_animations/hexagons/_index.scss
@@ -0,0 +1,32 @@
+.hexagon-rows-container {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ inset: 0;
+ overflow: hidden;
+
+ .hexagon-row-container {
+ position: relative;
+ top: 30px;
+ margin-top: -13px;
+
+ .hexagon-container {
+ display: flex;
+ gap: 2px;
+
+ svg {
+ height: 48px;
+ overflow: visible;
+
+ polygon {
+ transition: all 500ms ease-in;
+ }
+ }
+
+ &.n2 {
+ margin-top: -13px;
+ margin-left: -20px;
+ }
+ }
+ }
+}
diff --git a/modules/nuc_animations/hexagons/index.ts b/modules/nuc_animations/hexagons/index.ts
new file mode 100644
index 0000000..6bb7a16
--- /dev/null
+++ b/modules/nuc_animations/hexagons/index.ts
@@ -0,0 +1 @@
+export { NucAnimationHexagons } from './index.tsx'
diff --git a/modules/nuc_animations/hexagons/index.tsx b/modules/nuc_animations/hexagons/index.tsx
new file mode 100644
index 0000000..d93326a
--- /dev/null
+++ b/modules/nuc_animations/hexagons/index.tsx
@@ -0,0 +1,78 @@
+'use client'
+
+import type { CSSProperties, JSX } from 'react'
+import React, { useEffect, useRef, useState } from 'react'
+
+import './_index.scss'
+
+import type { HexagonPatternsType } from './types'
+import { getHexagonPoints, updateImagesPerRow } from './utils'
+import { PATTERN_UPDATE_INTERVAL } from './variables'
+
+export function NucAnimationHexagons(): JSX.Element {
+ const containerRef = useRef(null)
+ const [hexagonRows, setHexagonRows] = useState([])
+
+ useEffect(() => {
+ updateImagesPerRow(
+ containerRef.current,
+ () => undefined,
+ () => undefined,
+ setHexagonRows
+ )
+
+ const interval = setInterval(() => {
+ requestAnimationFrame(() => {
+ updateImagesPerRow(
+ containerRef.current,
+ () => undefined,
+ () => undefined,
+ setHexagonRows
+ )
+ })
+ }, PATTERN_UPDATE_INTERVAL)
+
+ return () => {
+ clearInterval(interval)
+ }
+ }, [])
+
+ return (
+
+ {hexagonRows.map((row, rowIndex) => (
+
+ {['hexagon-container n1', 'hexagon-container n2'].map(
+ (containerClass, containerIndex) => (
+
+
+
+ )
+ )}
+
+ ))}
+
+ )
+}
diff --git a/modules/nuc_animations/hexagons/types/index.ts b/modules/nuc_animations/hexagons/types/index.ts
new file mode 100644
index 0000000..6b8785a
--- /dev/null
+++ b/modules/nuc_animations/hexagons/types/index.ts
@@ -0,0 +1,2 @@
+export * from './interfaces'
+export * from './variables'
diff --git a/modules/nuc_animations/hexagons/types/interfaces.ts b/modules/nuc_animations/hexagons/types/interfaces.ts
new file mode 100644
index 0000000..d7863e9
--- /dev/null
+++ b/modules/nuc_animations/hexagons/types/interfaces.ts
@@ -0,0 +1,8 @@
+export interface HexagonConfigInterface {
+ width: number
+ height: number
+ containerWidth: number
+ containerHeight: number
+ imagesPerRow: number
+ totalRows: number
+}
diff --git a/modules/nuc_animations/hexagons/types/variables.ts b/modules/nuc_animations/hexagons/types/variables.ts
new file mode 100644
index 0000000..53c52a6
--- /dev/null
+++ b/modules/nuc_animations/hexagons/types/variables.ts
@@ -0,0 +1,2 @@
+export type HexagonRowType = number[][]
+export type HexagonPatternsType = number[][][]
diff --git a/modules/nuc_animations/hexagons/utils/calculate_dimensions.ts b/modules/nuc_animations/hexagons/utils/calculate_dimensions.ts
new file mode 100644
index 0000000..50d4b5b
--- /dev/null
+++ b/modules/nuc_animations/hexagons/utils/calculate_dimensions.ts
@@ -0,0 +1,28 @@
+import type { HexagonConfigInterface } from '../types'
+import {
+ HEXAGON_HEIGHT,
+ HEXAGON_OVERLAP_FACTOR,
+ HEXAGON_WIDTH,
+ HEXAGON_WIDTH_FACTOR,
+} from '../variables'
+
+export function calculateDimensions(
+ containerWidth: number,
+ containerHeight: number
+): HexagonConfigInterface {
+ const calculatedImages: number = Math.ceil(
+ containerWidth / (HEXAGON_WIDTH / HEXAGON_WIDTH_FACTOR)
+ )
+ const calculatedRows: number = Math.ceil(
+ containerHeight / (HEXAGON_HEIGHT * HEXAGON_OVERLAP_FACTOR)
+ )
+
+ return {
+ width: HEXAGON_WIDTH,
+ height: HEXAGON_HEIGHT,
+ containerWidth,
+ containerHeight,
+ imagesPerRow: calculatedImages,
+ totalRows: calculatedRows,
+ }
+}
diff --git a/modules/nuc_animations/hexagons/utils/generate_row_pattern.ts b/modules/nuc_animations/hexagons/utils/generate_row_pattern.ts
new file mode 100644
index 0000000..8409180
--- /dev/null
+++ b/modules/nuc_animations/hexagons/utils/generate_row_pattern.ts
@@ -0,0 +1,22 @@
+import type { HexagonRowType } from '../types'
+
+export function generateRowPattern(
+ rowIndex: number,
+ totalImages: number,
+ totalRows: number
+): HexagonRowType {
+ const onesCount = Math.ceil((totalImages * (rowIndex + 1)) / (totalRows * 2))
+ const pattern = new Array(totalImages).fill(0)
+
+ let placedOnes = 0
+ while (placedOnes < onesCount) {
+ const randomIndex = Math.floor(Math.random() * totalImages)
+ if (pattern[randomIndex] === 0) {
+ pattern[randomIndex] = 1
+ placedOnes++
+ }
+ }
+
+ const half = Math.floor(totalImages / 2)
+ return [pattern.slice(0, half), pattern.slice(half)]
+}
diff --git a/modules/nuc_animations/hexagons/utils/get_hexagon_points.ts b/modules/nuc_animations/hexagons/utils/get_hexagon_points.ts
new file mode 100644
index 0000000..e8c5c3a
--- /dev/null
+++ b/modules/nuc_animations/hexagons/utils/get_hexagon_points.ts
@@ -0,0 +1,6 @@
+export function getHexagonPoints(cx: number, cy: number, r: number): string {
+ return Array.from({ length: 6 }, (_, i) => {
+ const angle = (Math.PI / 3) * i - Math.PI / 6
+ return [cx + r * Math.cos(angle), cy + r * Math.sin(angle)].join(',')
+ }).join(' ')
+}
diff --git a/modules/nuc_animations/hexagons/utils/index.ts b/modules/nuc_animations/hexagons/utils/index.ts
new file mode 100644
index 0000000..f7ac0b0
--- /dev/null
+++ b/modules/nuc_animations/hexagons/utils/index.ts
@@ -0,0 +1,5 @@
+export * from './calculate_dimensions'
+export * from './generate_row_pattern'
+export * from './get_hexagon_points'
+export * from './update_hexagon_patterns'
+export * from './update_images_per_row'
diff --git a/modules/nuc_animations/hexagons/utils/update_hexagon_patterns.ts b/modules/nuc_animations/hexagons/utils/update_hexagon_patterns.ts
new file mode 100644
index 0000000..939f189
--- /dev/null
+++ b/modules/nuc_animations/hexagons/utils/update_hexagon_patterns.ts
@@ -0,0 +1,13 @@
+import { generateRowPattern } from '.'
+import type { HexagonPatternsType } from '../types'
+
+export function updateHexagonPatterns(
+ totalRows: number,
+ imagesPerRow: number
+): HexagonPatternsType {
+ const patterns: HexagonPatternsType = []
+ for (let i = 0; i < totalRows; i++) {
+ patterns[i] = generateRowPattern(i, imagesPerRow, totalRows)
+ }
+ return patterns
+}
diff --git a/modules/nuc_animations/hexagons/utils/update_images_per_row.ts b/modules/nuc_animations/hexagons/utils/update_images_per_row.ts
new file mode 100644
index 0000000..a8d2944
--- /dev/null
+++ b/modules/nuc_animations/hexagons/utils/update_images_per_row.ts
@@ -0,0 +1,23 @@
+import { calculateDimensions, updateHexagonPatterns } from '.'
+import type { HexagonConfigInterface, HexagonPatternsType } from '../types'
+
+export const updateImagesPerRow = (
+ containerRef: HTMLElement | null,
+ setImagesPerRow: (value: number) => void,
+ setTotalRows: (value: number) => void,
+ setHexagonRows: (value: HexagonPatternsType) => void
+): void => {
+ if (!containerRef) return
+
+ const {
+ imagesPerRow: calculatedImages,
+ totalRows: calculatedRows,
+ }: HexagonConfigInterface = calculateDimensions(
+ containerRef.clientWidth,
+ containerRef.clientHeight
+ )
+
+ setImagesPerRow(calculatedImages)
+ setTotalRows(calculatedRows)
+ setHexagonRows(updateHexagonPatterns(calculatedRows, calculatedImages))
+}
diff --git a/modules/nuc_animations/hexagons/variables/index.ts b/modules/nuc_animations/hexagons/variables/index.ts
new file mode 100644
index 0000000..9ba170b
--- /dev/null
+++ b/modules/nuc_animations/hexagons/variables/index.ts
@@ -0,0 +1 @@
+export * from './options'
diff --git a/modules/nuc_animations/hexagons/variables/options.ts b/modules/nuc_animations/hexagons/variables/options.ts
new file mode 100644
index 0000000..c1160d3
--- /dev/null
+++ b/modules/nuc_animations/hexagons/variables/options.ts
@@ -0,0 +1,5 @@
+export const HEXAGON_WIDTH = 40
+export const HEXAGON_HEIGHT = 40
+export const PATTERN_UPDATE_INTERVAL = 350
+export const HEXAGON_OVERLAP_FACTOR = 2
+export const HEXAGON_WIDTH_FACTOR = 2
diff --git a/modules/nuc_animations/index.ts b/modules/nuc_animations/index.ts
new file mode 100644
index 0000000..f05cdc9
--- /dev/null
+++ b/modules/nuc_animations/index.ts
@@ -0,0 +1,13 @@
+/**
+ * Module's main file export
+ */
+export * from './nuc_animations'
+
+/**
+ * Folders exports
+ */
+export * from './hexagons'
+
+/**
+ * File exports
+ */
diff --git a/modules/nuc_animations/nuc_animations.ts b/modules/nuc_animations/nuc_animations.ts
new file mode 100644
index 0000000..b51e2bf
--- /dev/null
+++ b/modules/nuc_animations/nuc_animations.ts
@@ -0,0 +1,5 @@
+import { NucAnimationHexagons } from '.'
+
+export function registerNucAnimations(): void {
+ void NucAnimationHexagons
+}
diff --git a/modules/nuc_animations/rotate/_index.scss b/modules/nuc_animations/rotate/_index.scss
new file mode 100644
index 0000000..0cdd76a
--- /dev/null
+++ b/modules/nuc_animations/rotate/_index.scss
@@ -0,0 +1 @@
+@import 'keyframes';
diff --git a/modules/nuc_animations/rotate/_keyframes.scss b/modules/nuc_animations/rotate/_keyframes.scss
new file mode 100644
index 0000000..98e39d9
--- /dev/null
+++ b/modules/nuc_animations/rotate/_keyframes.scss
@@ -0,0 +1,9 @@
+@keyframes rotate-right {
+ 0% {
+ transform: rotate(0);
+ }
+
+ 100% {
+ transform: rotate(360deg);
+ }
+}
diff --git a/modules/nuc_animations/shine/_index.scss b/modules/nuc_animations/shine/_index.scss
new file mode 100644
index 0000000..b2fd7bc
--- /dev/null
+++ b/modules/nuc_animations/shine/_index.scss
@@ -0,0 +1,50 @@
+@import 'keyframes';
+
+.shiny,
+%shiny {
+ position: relative;
+ display: inline-block;
+
+ & > div[aria-hidden='true'] {
+ position: relative;
+ display: inline-block;
+
+ &:nth-child(1) { animation-delay: 0s; }
+ &:nth-child(2) { animation-delay: 0.2s; }
+ &:nth-child(3) { animation-delay: 0.4s; }
+ &:nth-child(4) { animation-delay: 0.6s; }
+ &:nth-child(5) { animation-delay: 0.8s; }
+ &:nth-child(6) { animation-delay: 1.0s; }
+ &:nth-child(7) { animation-delay: 1.2s; }
+ &:nth-child(8) { animation-delay: 1.4s; }
+ &:nth-child(9) { animation-delay: 1.6s; }
+ &:nth-child(10) { animation-delay: 1.8s; }
+
+ animation: letter-shine 10s linear infinite;
+ }
+
+ &:not(:has(> div[aria-hidden='true'])) {
+ animation: letter-shine 10s linear infinite;
+ }
+
+ &.first-text {
+ & > div[aria-hidden='true'] {
+ animation-duration: 5.5s;
+ }
+ }
+
+ &:not(.first-text) {
+ & > div[aria-hidden='true'] {
+ animation-duration: 5s;
+ }
+ }
+}
+
+#back-office {
+ .shiny,
+ %shiny {
+ &:not(:has(> div[aria-hidden='true'])) {
+ animation: shiny-cube 10s linear infinite;
+ }
+ }
+}
diff --git a/modules/nuc_animations/shine/_keyframes.scss b/modules/nuc_animations/shine/_keyframes.scss
new file mode 100644
index 0000000..20408d0
--- /dev/null
+++ b/modules/nuc_animations/shine/_keyframes.scss
@@ -0,0 +1,59 @@
+@keyframes shine {
+ to {
+ background-position: 200% center;
+ }
+}
+
+@keyframes letter-shine {
+ 0%, 100% {
+ color: #1bbd79;
+ text-shadow: 0 0 10px rgb(27 189 121 / 50%);
+ }
+
+ 20% {
+ color: #1bbd79;
+ text-shadow: 0 0 10px rgb(27 189 121 / 50%);
+ }
+
+ 40% {
+ color: #178a59;
+ text-shadow: 0 0 8px rgb(23 138 89 / 40%);
+ }
+
+ 60% {
+ color: #126543;
+ text-shadow: 0 0 6px rgb(18 101 67 / 30%);
+ }
+
+ 80% {
+ color: #178a59;
+ text-shadow: 0 0 8px rgb(23 138 89 / 40%);
+ }
+}
+
+@keyframes shiny-cube {
+ 0%, 100% {
+ color: $main-color-user;
+ text-shadow: 0 0 10px rgb(27 189 121 / 50%);
+ }
+
+ 20% {
+ color: $main-focus-color-user;
+ text-shadow: 0 0 10px rgb(27 189 121 / 50%);
+ }
+
+ 40% {
+ color: $main-color-user;
+ text-shadow: 0 0 8px rgb(23 138 89 / 40%);
+ }
+
+ 60% {
+ color: $main-focus-color-user;
+ text-shadow: 0 0 6px rgb(18 101 67 / 30%);
+ }
+
+ 80% {
+ color: $main-hover-color-user;
+ text-shadow: 0 0 8px rgb(23 138 89 / 40%);
+ }
+}