diff --git a/app/(core)/components/Funfact.jsx b/app/(core)/components/Funfact.jsx
new file mode 100644
index 0000000..cd3a739
--- /dev/null
+++ b/app/(core)/components/Funfact.jsx
@@ -0,0 +1,52 @@
+import React from "react";
+import funFacts from "../data/facts";
+
+function SparkleIcon() {
+ return (
+
+ );
+}
+
+function Funfact({ chapterId, setshow }) {
+ const facts = funFacts.find((item) => item.id === chapterId);
+
+ if (!facts) return null;
+
+ return (
+
+
+
+
+
+
+
+
+
+ Did you know
+
+
+
{facts.fact}
+
+ );
+}
+
+export default Funfact;
diff --git a/app/(core)/components/TopSim.tsx b/app/(core)/components/TopSim.tsx
index d481879..22b4044 100644
--- a/app/(core)/components/TopSim.tsx
+++ b/app/(core)/components/TopSim.tsx
@@ -3,6 +3,8 @@ import simulations from "../data/chapters";
import { usePathname } from "next/navigation";
import useMobile from "../hooks/useMobile";
import useTranslation from "../hooks/useTranslation.ts";
+import Funfact from "./Funfact.jsx";
+import { useEffect, useState } from "react";
export default function TopSim() {
const { t, meta } = useTranslation();
@@ -10,6 +12,12 @@ export default function TopSim() {
const location = usePathname();
const idx = simulations.findIndex((sim) => sim.link === location);
const isMobile = useMobile();
+ const [show, setshow] = useState(true);
+ useEffect(() => {
+ setTimeout(() => {
+ setshow(false);
+ }, 5000);
+ }, [simulations[idx].id]);
function getPrevious() {
if (idx === -1) return "/";
@@ -53,7 +61,11 @@ export default function TopSim() {
content={t("Next")}
/>
- {!isMobile && }
+ {!isMobile && idx !== -1 && (
+
+
+
+ )}
);
}
diff --git a/app/(core)/data/facts.js b/app/(core)/data/facts.js
new file mode 100644
index 0000000..2279e50
--- /dev/null
+++ b/app/(core)/data/facts.js
@@ -0,0 +1,63 @@
+const funFacts = [
+ {
+ id: 1,
+ fact: "A perfectly elastic ball can bounce forever in a frictionless environment because no kinetic energy is lost.",
+ },
+ {
+ id: 2,
+ fact: "Vector addition depends on both magnitude and direction, which is why two forces can cancel each other completely.",
+ },
+ {
+ id: 3,
+ fact: "Acceleration is the rate of change of velocity, not speed. An object moving in a circle accelerates even at constant speed.",
+ },
+ {
+ id: 4,
+ fact: "On Earth, all objects fall with the same acceleration (9.8 m/s²) if air resistance is ignored.",
+ },
+ {
+ id: 5,
+ fact: "According to Hooke's Law, the restoring force of a spring is proportional to its displacement from equilibrium.",
+ },
+ {
+ id: 6,
+ fact: "For small angles, the period of a simple pendulum depends only on its length and gravity—not on its mass.",
+ },
+ {
+ id: 7,
+ fact: "Projectile motion combines constant horizontal velocity with vertically accelerated motion due to gravity.",
+ },
+ {
+ id: 8,
+ fact: "Increasing the incline angle increases the component of gravity pulling the object down the slope.",
+ },
+ {
+ id: 9,
+ fact: "An object in uniform circular motion constantly changes direction, requiring centripetal acceleration.",
+ },
+ {
+ id: 10,
+ fact: "The three-body problem has no general analytical solution and often exhibits chaotic behavior.",
+ },
+ {
+ id: 11,
+ fact: "The frequency of a horizontal spring-mass system increases when the spring constant increases.",
+ },
+ {
+ id: 12,
+ fact: "The double pendulum is one of the simplest systems that demonstrates deterministic chaos.",
+ },
+ {
+ id: 13,
+ fact: "In an elastic collision, both momentum and kinetic energy are conserved.",
+ },
+ {
+ id: 14,
+ fact: "Physics simulations often stress CPUs more than GPUs because they involve complex mathematical calculations.",
+ },
+ {
+ id: 15,
+ fact: "The number of collisions between two blocks can reveal the digits of π when their masses follow powers of 100.",
+ },
+];
+export default funFacts;
diff --git a/app/(core)/styles/index.css b/app/(core)/styles/index.css
index b102e9a..a9ff5e6 100644
--- a/app/(core)/styles/index.css
+++ b/app/(core)/styles/index.css
@@ -71,14 +71,17 @@
background: rgba(0, 184, 184, 0.1);
box-shadow: 0 4px 12px rgba(0, 184, 184, 0.2);
}
+
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
+
html {
scroll-behavior: smooth;
}
+
body {
color: var(--text-color);
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
@@ -257,14 +260,16 @@ nav a:hover::after {
.nav-underline {
position: absolute;
- bottom: -3px; /* adjust distance below text */
+ bottom: -3px;
+ /* adjust distance below text */
left: 0;
height: 2px;
background: var(--accent-color);
border-radius: 2px;
transition:
left 0.3s ease,
- width 0.3s ease; /* smooth slide */
+ width 0.3s ease;
+ /* smooth slide */
z-index: 100;
}
@@ -432,7 +437,8 @@ nav a:hover::after {
.horizontal-menu-container.open {
grid-template-rows: 1fr;
- max-height: 500px; /* Set a max height when open */
+ max-height: 500px;
+ /* Set a max height when open */
border-radius: var(--border-radius);
transition:
grid-template-rows 0.3s ease-out,
@@ -449,7 +455,8 @@ nav a:hover::after {
padding-bottom: 8px;
-webkit-overflow-scrolling: touch;
- scrollbar-width: thin; /* Firefox */
+ scrollbar-width: thin;
+ /* Firefox */
padding: 1rem 0.5rem;
}
@@ -457,6 +464,7 @@ nav a:hover::after {
.horizontal-menu::-webkit-scrollbar {
height: 4px;
}
+
.horizontal-menu::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.1);
border-radius: 10px;
@@ -661,12 +669,14 @@ nav a:hover::after {
/* Horizontal filters container */
.horizontal-menu-container {
width: 100%;
- display: none; /* hidden by default */
+ display: none;
+ /* hidden by default */
overflow: visible;
}
.horizontal-menu-container.open {
- display: block; /* show when filter button clicked */
+ display: block;
+ /* show when filter button clicked */
}
.horizontal-menu {
@@ -760,9 +770,11 @@ main.simulations-page {
display: flex;
flex-direction: column;
align-items: center;
- justify-content: center; /* ⬅️ key */
+ justify-content: center;
+ /* ⬅️ key */
padding: 4rem 0;
}
+
.simulations-content > * {
width: 1000%;
}
@@ -773,46 +785,55 @@ main.simulations-page {
animation-duration: 1.3s;
animation-delay: 0s;
}
+
.wind-streak.streak1 {
left: 15%;
animation-duration: 1.5s;
animation-delay: 0.1s;
}
+
.wind-streak.streak2 {
left: 25%;
animation-duration: 1.4s;
animation-delay: 0.2s;
}
+
.wind-streak.streak3 {
left: 35%;
animation-duration: 1.6s;
animation-delay: 0.05s;
}
+
.wind-streak.streak4 {
left: 45%;
animation-duration: 1.3s;
animation-delay: 0.15s;
}
+
.wind-streak.streak5 {
left: 55%;
animation-duration: 1.45s;
animation-delay: 0.1s;
}
+
.wind-streak.streak6 {
left: 65%;
animation-duration: 1.5s;
animation-delay: 0.2s;
}
+
.wind-streak.streak7 {
left: 75%;
animation-duration: 1.6s;
animation-delay: 0s;
}
+
.wind-streak.streak8 {
left: 85%;
animation-duration: 1.4s;
animation-delay: 0.12s;
}
+
.wind-streak.streak9 {
left: 95%;
animation-duration: 1.5s;
@@ -824,9 +845,11 @@ main.simulations-page {
transform: translateX(0) translateY(100%) rotate(10deg);
opacity: 0;
}
+
20% {
opacity: 0.4;
}
+
100% {
transform: translateX(-30px) translateY(0%) rotate(15deg);
opacity: 0;
@@ -1147,13 +1170,16 @@ main.simulations-page {
0% {
left: -100%;
}
+
65% {
left: 120%;
}
+
80% {
left: 120%;
opacity: 0;
}
+
100% {
left: -100%;
opacity: 0;
@@ -1314,7 +1340,8 @@ footer {
cursor: pointer;
opacity: 0;
bottom: -20px;
- pointer-events: none; /* non cliccabile quando invisibile */
+ pointer-events: none;
+ /* non cliccabile quando invisibile */
transition:
transform 0.3s,
opacity 0.4s ease,
@@ -1368,11 +1395,13 @@ footer {
opacity: 0;
transform: translateY(20px);
}
+
to {
opacity: 1;
transform: translateY(0);
}
}
+
.page-404 > * {
animation: fadeInUp 0.8s ease-out both;
}
@@ -1426,6 +1455,7 @@ footer {
transform: scale(1.05);
transition: transform 0.5s;
}
+
.btn-glow:active {
transform: scale(0.95);
transition: transform 0.1s;
@@ -1777,6 +1807,7 @@ footer {
border-radius: 50%;
aspect-ratio: 1;
}
+
.color-input::-webkit-color-swatch-wrapper {
padding: 0;
border: none;
@@ -1817,9 +1848,9 @@ footer {
.top-nav-sim {
position: relative;
display: flex;
- align-items: stretch;
+ align-items: center;
width: 100%;
- margin-top: 5rem;
+ margin-top: 6rem;
}
.top-nav-sim-inner {
@@ -1833,6 +1864,7 @@ footer {
box-sizing: border-box;
max-width: 80%;
margin: 0 auto;
+ padding-left: 10px;
flex-wrap: wrap;
}
@@ -1848,7 +1880,96 @@ footer {
}
.top-nav-sim-filler {
- width: 20%;
+ width: 30%;
+ transition:
+ opacity 0.4s ease,
+ transform 0.4s ease;
+ align-items: center;
+ justify-content: center;
+}
+
+.top-nav-sim-filler.hide {
+ opacity: 0;
+ transform: translateX(20px);
+ pointer-events: none;
+}
+
+.fun-fact {
+ position: relative;
+ max-width: 460px;
+ overflow: hidden;
+ border-radius: 16px;
+ padding: 18px 20px;
+ background: var(--card-bg);
+ border: 1px solid rgba(45, 212, 191, 0.35);
+ box-shadow:
+ 0 0 0 1px rgba(45, 212, 191, 0.08),
+ 0 8px 24px rgba(0, 0, 0, 0.35);
+}
+
+.fun-fact-header {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin-bottom: 12px;
+}
+
+.fun-fact-icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ width: 30px;
+ height: 30px;
+ border-radius: 9px;
+ background: rgba(45, 212, 191, 0.12);
+ border: 1px solid rgba(45, 212, 191, 0.3);
+ color: var(--accent);
+}
+
+.fun-fact-label {
+ font-size: 11px;
+ font-weight: 500;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+ color: var(--accent);
+}
+
+.fun-fact-text {
+ margin: 0;
+ font-size: 14.5px;
+ line-height: 1.65;
+ color: var(--text);
+}
+
+.fun-fact {
+ position: relative;
+}
+
+.fun-fact-close {
+ position: absolute;
+ top: 12px;
+ right: 12px;
+}
+
+.btn-close {
+ width: 28px;
+ height: 28px;
+ border: none;
+ border-radius: 50%;
+ background: transparent;
+ color: #5eead4;
+ font-size: 16px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.2s ease;
+}
+
+.btn-close:hover {
+ background: rgba(45, 212, 191, 0.15);
+ transform: scale(1.1);
}
/* Wind icon for Ball Gravity Simulation*/
@@ -1880,6 +2001,7 @@ footer {
from {
transform: translateY(0);
}
+
to {
transform: translateY(-3px);
}
@@ -2257,11 +2379,13 @@ footer {
opacity: 0.6;
transform: scale(1);
}
+
50% {
opacity: 1;
transform: scale(1.05);
}
}
+
.animate-pulse-strong {
animation: pulse-strong 1.2s ease-in-out infinite;
}
@@ -2272,11 +2396,13 @@ footer {
opacity: 0;
transform: translateY(20px);
}
+
to {
opacity: 1;
transform: translateY(0);
}
}
+
.animate-fadeInUp {
animation: fadeInUp 0.6s ease forwards;
}
@@ -2292,7 +2418,8 @@ footer {
font-size: 0.7rem;
padding: 0.7rem;
border-radius: var(--border-radius);
- pointer-events: auto; /* serve per cliccare i bottoni */
+ pointer-events: auto;
+ /* serve per cliccare i bottoni */
transition:
padding 0.3s ease,
width 0.3s ease,
@@ -2350,6 +2477,7 @@ footer {
height 0.3s ease;
overflow: hidden;
}
+
.sim-info-panel.collapsed .sim-info-header {
margin: 0.3rem 0;
justify-content: center;
@@ -2403,7 +2531,8 @@ footer {
padding: 0.5rem;
border-radius: var(--border-radius);
overflow-y: auto;
- max-height: 40vh; /* pannello non troppo alto */
+ max-height: 40vh;
+ /* pannello non troppo alto */
}
.sim-info-header {
@@ -2428,7 +2557,8 @@ footer {
.sim-info-btn,
.sim-info-toggle {
- font-size: 1rem; /* più grandi per touch */
+ font-size: 1rem;
+ /* più grandi per touch */
padding: 0.2rem 0.4rem;
}
}
@@ -2941,7 +3071,8 @@ footer {
/* --- MOBILE: Menu a tendina --- */
@media (max-width: 767px) {
.simulation-controls {
- flex-direction: column; /* Colonna per ospitare il menu sotto */
+ flex-direction: column;
+ /* Colonna per ospitare il menu sotto */
gap: 0;
}
@@ -2955,9 +3086,11 @@ footer {
}
.extra-controls-wrapper {
- display: none; /* Nascondi di base */
+ display: none;
+ /* Nascondi di base */
width: 100%;
- flex-direction: column; /* O "row wrap" se preferisci i tasti piccoli */
+ flex-direction: column;
+ /* O "row wrap" se preferisci i tasti piccoli */
gap: 0.5rem;
padding: 1rem 0;
border-top: 1px solid rgba(255, 255, 255, 0.1);
@@ -2989,7 +3122,8 @@ footer {
border: 1px solid color-mix(in oklab, var(--accent-color), transparent 75%);
font-weight: 500;
margin-left: 1rem;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); /* subtle shadow */
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+ /* subtle shadow */
}
/* Blogs section page */
diff --git a/tsconfig.json b/tsconfig.json
index e81a500..1045bf8 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -32,7 +32,8 @@
"**/*.mts",
"app/hooks/useSimInfo.ts",
"app/components/LandingPart.jsx",
- "app/(pages)/blog/[slug]/page.jsx"
+ "app/(pages)/blog/[slug]/page.jsx",
+ "app/(core)/components/Funfact.jsx"
],
"exclude": ["node_modules"]
}