diff --git a/Assets/Scripts.meta b/Assets/Scripts.meta
new file mode 100644
index 0000000..bad281c
--- /dev/null
+++ b/Assets/Scripts.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5c194c683aa28491a8619be39f6eb721
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Game.meta b/Assets/Scripts/Game.meta
new file mode 100644
index 0000000..7cb8ef5
--- /dev/null
+++ b/Assets/Scripts/Game.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 83d33fbff670449c3946494137623be9
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Game/DerivativePopAnimator.cs.meta b/Assets/Scripts/Game/DerivativePopAnimator.cs.meta
new file mode 100644
index 0000000..1ab328a
--- /dev/null
+++ b/Assets/Scripts/Game/DerivativePopAnimator.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 1af5b27b1c8234106ab2bc0f7907f835
\ No newline at end of file
diff --git a/First Principles/Assets/Resources/Localization/MathArticle/en.txt b/First Principles/Assets/Resources/Localization/MathArticle/en.txt
index 2a46f31..54a23c9 100644
--- a/First Principles/Assets/Resources/Localization/MathArticle/en.txt
+++ b/First Principles/Assets/Resources/Localization/MathArticle/en.txt
@@ -1,7 +1,9 @@
+@@SECTION=intro
Math concepts — in-game reader
The game First Principles takes its name from public remarks by Elon Musk on a first-principles approach to business and to solving problems in life and work—then teaches calculus-first ideas on the graph as a matching metaphor.
Use Math concepts while playing, or Math tips & snippets on Level select — same scrollable notes. Tap the dark backdrop or Close to dismiss.
+@@SECTION=how_graph
How this game teaches calculus (read the graph while you play)
• Main curve — the thick path on the Cartesian grid is \(y = f(x)\) for this stage. Your character tries to stand on platforms that follow that shape. The Equation label (when visible) names the rule being plotted.
@@ -17,9 +19,11 @@
Everything below is a topic glossary you can skim between deaths or after finishing a graph — plus a First principles thinking (business) section before exam prep.
+@@SECTION=s1
1. Derivatives = slope & rate
The derivative \(f'(x)\) measures how steeply \(f(x)\) rises or falls. In physics it is often a rate: how fast position changes (velocity), how fast temperature changes along a bar, etc. In this game, the derivative helps decide where the ground exists.
+@@SECTION=rules
──────── Differentiation rules — your skill tree ────────
These are the combo moves for turning \(f(x)\) into \(f'(x)\) without rebuilding from the limit every time. Read them like perks that change how your main curve and derivative HUD stay in sync.
@@ -43,6 +47,7 @@ If \(y = f(g(x))\), then \(\displaystyle \frac{dy}{dx} = f'(g(x))\cdot g'(x)\).
The game still draws \(f'\) with a numeric sampler on wild stages, but these identities explain why textbook curves snap into clean forms — and what AP / TMUA expects you to simplify before you sketch. Longer write-up: docs/derivative-rules.md.
+@@SECTION=int_block
──────── Integrals: definite vs indefinite — score vs loadout ────────
Indefinite \(\displaystyle \int f(x)\,dx\) asks for an antiderivative — a whole family \(F(x)+C\) whose derivative is \(f\). Think loadout class: many valid builds differ by +\(C\) (same gameplay up to vertical shift in \(F\)). Definite \(\displaystyle \int_a^b f(x)\,dx\) is a single number (signed area from \(a\) to \(b\)) — like a run score for one fixed segment. No “+\(C\)” in the answer: endpoints pin it down.
@@ -54,42 +59,55 @@ Rectangles (left / right / midpoint) estimate the definite score before y
More detail: docs/definite-indefinite-integrals.md. (Graphing calculator / FTC proofs — see course notes; this is the game glossary.)
+@@SECTION=s2
2. Parabola (power / quadratic)
A quadratic \(y = a(x-h)^2+k\) is the shape of projectile motion in ideal textbook setups and many optimization problems (min/max). One smooth hump; the slope switches sign at the vertex.
+@@SECTION=s3
3. Sine & cosine = waves & rotation
Sines and cosines describe vibrations, AC signals, sound, and anything that repeats. Cosine is sine shifted: same wave, different starting phase. Complex numbers (below) make these waves easier to solve in circuits and vibrations.
+@@SECTION=s4
4. Absolute value & kinks
\(|x|\) bends the graph so there is a corner on the axis. The derivative jumps there in ideal math — in real programs we plot smooth samples, but the idea matters: nonsmooth points need special care in analysis and simulation.
+@@SECTION=s5
5. Taylor & Maclaurin series
Smooth functions can be approximated near a point by polynomials with matching derivatives. Maclaurin means “expand around \(0\).” More terms usually improve the fit nearby; the full infinite sum is the series (where it converges).
+@@SECTION=s6
6. Geometric series
Sums \(u^0+u^1+u^2+\cdots\) appear in probability, signal processing, and digital math. When \(|u|<1\) the tail shrinks and the infinite sum has a clean closed form; that is the same mood as stability and “things settle.”
+@@SECTION=s7
7. Multivariable slices
Surfaces \(z = f(x,y)\) can be cut by fixing \(y=y_0\) — you get a 1D curve in \(x\). That is how higher-dimensional calculus is often reasoned about in engineering: fix all but one variable, take partial derivatives, gradients, directional slopes.
+@@SECTION=s8
8. Integrals & area (Riemann sums)
The definite integral \(\displaystyle \int_a^b f(x)\,dx\) is the signed area under the curve. Riemann sums chop \([a,b]\) into thin rectangles: pick sample heights (left, right, midpoint), add \(f(x^\ast)\,\Delta x\). More rectangles → closer to the true integral.
+@@SECTION=s9
9. Engineering math — modeling mindset
Engineering math picks tools that match the world: linear algebra for structures and networks, complex numbers / phasors for steady AC, differential equations for motion and heat, transforms (Laplace/Fourier) for signals and control. The goal is a usable model, then check it against reality.
+@@SECTION=s10
10. Damped oscillation
Many systems lose energy while oscillating: \(e^{-\alpha t}\sin(\omega t)\) style decay is the cartoon of that idea — envelope shrinks, oscillation persists briefly. Mechanical damping, resistor–capacitor–inductor circuits, and control systems all share this language.
+@@SECTION=s11
11. Catenary & cosh
A hanging cable under its own weight forms a catenary; \(\cosh\) is the hyperbolic cosine that models that ideal shape (and shows up in hyperbolic PDEs and relativity too). Different from a parabola even if both look “like arches.”
+@@SECTION=s12
12. Rectified sine \(|\sin|\)
Full-wave rectification flips negative lobes upward — a first step in turning AC into something closer to DC for power supplies. Corners at zeros mean derivatives jump — a reminder that idealized circuits still start from calculus intuitions.
+@@SECTION=s13
13. Circle \((x-h)^2 + (y-k)^2 = R^2\)
A circle is usually written implicitly. Solving for \(y\) gives two branches (\(\pm\sqrt{\cdot}\)). The game’s circle stage uses the upper semicircle so the path stays a function \(y(x)\) over one sweep. Implicit differentiation yields \(\frac{dy}{dx} = -\frac{x-h}{y-k}\); at the ends of the diameter the tangent is vertical (slope blows up).
+@@SECTION=aero
──────── Aerospace engineering & aerodynamics ────────
Levels prefixed Aerospace: turn textbook flight‑vehicle math into paths you run. They are toy models for pedagogy — not CFD, flight test, or ITAR‑grade simulations.
@@ -101,6 +119,7 @@ A circle is usually written implicitly. Solving for \(y\) gives two branches (\(
See docs/engineering-math.md § Aerospace for a longer map.
+@@SECTION=biz
──────── First principles thinking (business) ────────
Startup culture often cites Elon Musk for reviving first principles at places like Tesla / SpaceX: stop trusting “the market always prices it this way,” and instead unpack assumptions until you hit bedrock facts (materials, energy, physics, true unit costs), then reason upward into a new design. The idea is older than any one founder — but the habit matches this game’s visuals.
@@ -112,6 +131,7 @@ A circle is usually written implicitly. Solving for \(y\) gives two branches (\(
This is not legal, tax, or investing advice — a thinking drill you can pair with real advisors and data. Full write-up: docs/first-principles-business.md on GitHub Pages.
+@@SECTION=exam
──────── Exam prep (separate tracks) ────────
Competition mathematics (contest lens)
diff --git a/First Principles/Assets/Resources/Localization/ar.txt b/First Principles/Assets/Resources/Localization/ar.txt
index 8204374..0c85d4b 100644
--- a/First Principles/Assets/Resources/Localization/ar.txt
+++ b/First Principles/Assets/Resources/Localization/ar.txt
@@ -12,9 +12,6 @@ ui.jump=قفز
ui.move=تحرك
ui.keyboard_hint_mobile=(لوحة المفاتيح: الأسهم / المسافة)
hud.stage=المرحلة
-controls.mobile=تحرك ◀ ▶ · قفز مس (لوحة المفاتيح: الأسهم / المسافة)
-controls.desktop=تحرك ← → · قفز مسافة
-controls.calculator=آلة رسومية اكتب f(u) · Trans · Scale · قرصة · رجوع
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x) عندما x>0 · min(x,3)...
graph.status_enter=Enter / اضغط خارج الحقل للرسم
@@ -22,7 +19,7 @@ graph.status_graphed=تم الرسم
graph.line1=وضع آلة الرسوم البيانية
graph.line2=اكتب f(u) أدناه (المتغير x في المربع = u الداخلي). ثم:
graph.line3=Trans ← {0} · نقرتان + · اضغط مطولًا − · Scale تكبير باللمس / اضغط مطولًا للتصغير · قرصة بإصبعين
-graph.line4=A={0} k={1} C={2} D={3} x في [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x في [{4},{5}]
graph.param_a=A (مقياس عمودي)
graph.param_k=k (مقياس أفقي)
graph.param_c=C (إزاحة عمودية)
@@ -65,20 +62,28 @@ level.30=BC: طور وحركة توافقية بسيطة (طاقة)
level.31=BC: تكعيب ونقطة انعطاف (رسم)
level.32=BC: b^x و d/dx b^x
level.33=دائرة: (x−h)² + (y−k)² = R²
-level.34=طيران: رفع C_L(α) خطي + انفصال
-level.35=طيران: قطب السحب (طفيلي، مُستحثّ، إجمالي)
-level.36=طيران: جو متساوي الحرارة ρ(h)
-level.37=طيران: حركة مجنحة / اهتزاز مُخمَّد
-level.38=طيران: نيوتوني Cp ~ sin²α
-level.39=طيران: Strouhal / نبرة انبعاث دوامات
-level.40=طيران: غلاف دخول غلاف جوي (تسخين ρV)
-level.41=اقتصاد: فقاعة الدوت كوم والانهيار (مؤشر توضيحي)
-level.42=اقتصاد: أزمة 2008 والتعافي (مؤشر توضيحي)
-level.43=الزعيم: شريحة هروب ماندلبروت (كسيري)
-level.44=فيزياء C: الديناميكا الحرارية (P–V أديباتي، γ من N)
-level.45=زعيم: لولب النسبة الذهبية (قطبي لوغاريتمي)
-level.46=تحويلات: فورييه — طيف sinc
-level.47=تحويلات: لابلاس — تضاؤل أسي
-level.48=زعيم: ماندلبروت — الختام (شريحة هروب كسيرية)
-level.49=زعيم: فراشة لورينز — الختام (جذاب غريب)
+level.34=فيزياء C: الديناميكا الحرارية (P–V أديباتي، γ من N)
+level.35=طيران: رفع C_L(α) خطي + انفصال
+level.36=طيران: قطب السحب (طفيلي، مُستحثّ، إجمالي)
+level.37=طيران: جو متساوي الحرارة ρ(h)
+level.38=طيران: حركة مجنحة / اهتزاز مُخمَّد
+level.39=طيران: نيوتوني Cp ~ sin²α
+level.40=طيران: Strouhal / نبرة انبعاث دوامات
+level.41=طيران: غلاف دخول غلاف جوي (تسخين ρV)
+level.42=اقتصاد: فقاعة الدوت كوم والانهيار (مؤشر توضيحي)
+level.43=اقتصاد: أزمة 2008 والتعافي (مؤشر توضيحي)
+level.44=تحويلات: فورييه — طيف sinc
+level.45=تحويلات: لابلاس — تضاؤل أسي
+level.46=زعيم: لولب النسبة الذهبية (قطبي لوغاريتمي)
+level.47=زعيم: ماندلبروت — الختام (شريحة هروب كسيرية)
+level.48=زعيم: جاذب لورينز — نظرية الفوضى (جذاب غريب)
+level.49=زعيم: ثقب أسود — بئر جاذبية (مقطع 1/r)
level.50=فيزياء C: نابض–كتلة حركة توافقية (قانون هوك، بلا تخميد)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
diff --git a/First Principles/Assets/Resources/Localization/cs.txt b/First Principles/Assets/Resources/Localization/cs.txt
index ec1eef5..d53fcac 100644
--- a/First Principles/Assets/Resources/Localization/cs.txt
+++ b/First Principles/Assets/Resources/Localization/cs.txt
@@ -7,10 +7,11 @@ level_select.cat.integration=Mult proměnné a integrály
level_select.cat.engineering=Inženýrství
level_select.cat.ap_bc=AP Calculus BC a fyzika C
level_select.cat.aerospace=Letectví a kosmonautika
-level_select.cat.finale=Pokročilé a boss
+level_select.cat.economics=Ekonomie
level_select.cat.transforms=Transformace
level_select.cat.final_boss=Finální boss
level_select.cat.spring_physics=Pružina a SHM
+level_select.cat.big_o=Notace Big O
ui.math_tips=Tipy k matematice
ui.back_menu=Zpět do menu
ui.graphing_calculator_mode=Grafická kalkulačka
@@ -24,9 +25,6 @@ ui.jump=Skok
ui.move=Pohyb
ui.keyboard_hint_mobile=(klávesnice: šipky / Mezerník)
hud.stage=FÁZE
-controls.mobile=Pohyb ◀ ▶ · Skok klepnutí (klávesnice: šipky / Mezerník)
-controls.desktop=Pohyb ← → · Skok Mezerník
-controls.calculator=Grafická kalkulačka Zadejte f(u) · Trans · Měřítko · Špetka · Zpět
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x) pro x>0 · min(x,3)...
graph.status_enter=Enter / klepněte mimo pro graf
@@ -34,7 +32,7 @@ graph.status_graphed=Vykresleno
graph.line1=Režim grafické kalkulačky
graph.line2=Napište f(u) níže (proměnná x v poli = vnitřní u). Pak:
graph.line3=Trans → {0} · dvojité klepnutí + · podržte − · Měřítko přiblížení / podržte oddálení · špetka dvěma prsty
-graph.line4=A={0} k={1} C={2} D={3} x v [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x v [{4},{5}]
graph.param_a=A (svislé měřítko)
graph.param_k=k (vodorovné měřítko)
graph.param_c=C (svislý posun)
@@ -85,20 +83,28 @@ level.30=BC: fáze a SHM (výměna energie)
level.31=BC: kubická a inflexe (náčrt)
level.32=BC: b^x a d/dx b^x
level.33=Kružnice: (x−h)² + (y−k)² = R²
-level.34=Aerospace: vztlak C_L(α) lineární + vývrt
-level.35=Aerospace: polára odporu (parazitní, indukovaná, celková)
-level.36=Aerospace: isotermická atmosféra ρ(h)
-level.37=Aerospace: fugoid / tlumený režim výška–klopení
-level.38=Aerospace: Newtonovské Cp ~ sin²α
-level.39=Aerospace: Strouhal / tón von Kármána
-level.40=Aerospace: obal útlumu při vstupu (ρV teplo)
-level.41=Ekonomika: bublina dot-com a pád (stylizovaný index)
-level.42=Ekonomika: krize 2008 a oživení (stylizovaný index)
-level.43=BOSS: řez úniku Mandelbrota (fraktálová nálada)
-level.44=Fyzika C: termodynamika (adiabatické P–V, γ z N)
-level.45=BOSS: zlatá spirála (logaritmická polární)
-level.46=Transformace: Fourier — sinc (spektrum)
-level.47=Transformace: Laplace — exponenciální pokles
-level.48=BOSS: Mandelbrot — finále (fraktálový únikový řez)
-level.49=BOSS: Lorenzův motýl — finále (podivný atraktor)
-level.50=Fyzika C: pružina–hmota SHM (Hookeův zákon, bez tlumení)
\ No newline at end of file
+level.34=Fyzika C: termodynamika (adiabatické P–V, γ z N)
+level.35=Aerospace: vztlak C_L(α) lineární + vývrt
+level.36=Aerospace: polára odporu (parazitní, indukovaná, celková)
+level.37=Aerospace: isotermická atmosféra ρ(h)
+level.38=Aerospace: fugoid / tlumený režim výška–klopení
+level.39=Aerospace: Newtonovské Cp ~ sin²α
+level.40=Aerospace: Strouhal / tón von Kármána
+level.41=Aerospace: obal útlumu při vstupu (ρV teplo)
+level.42=Ekonomika: bublina dot-com a pád (stylizovaný index)
+level.43=Ekonomika: krize 2008 a oživení (stylizovaný index)
+level.44=Transformace: Fourier — sinc (spektrum)
+level.45=Transformace: Laplace — exponenciální pokles
+level.46=BOSS: zlatá spirála (logaritmická polární)
+level.47=BOSS: Mandelbrot — finále (fraktálový únikový řez)
+level.48=BOSS: Lorenzův atraktor — teorie chaosu (podivný atraktor)
+level.49=BOSS: černá díra — gravitační jáma (řez ∝ 1/r)
+level.50=Fyzika C: pružina–hmota SHM (Hookeův zákon, bez tlumení)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
\ No newline at end of file
diff --git a/First Principles/Assets/Resources/Localization/de.txt b/First Principles/Assets/Resources/Localization/de.txt
index c44dffe..3d5ec57 100644
--- a/First Principles/Assets/Resources/Localization/de.txt
+++ b/First Principles/Assets/Resources/Localization/de.txt
@@ -12,9 +12,6 @@ ui.jump=Sprung
ui.move=Bewegen
ui.keyboard_hint_mobile=(Tastatur: Pfeile / Leertaste)
hud.stage=PHASE
-controls.mobile=Bewegen ◀ ▶ · Sprung Tipp (Tastatur: Pfeile / Leertaste)
-controls.desktop=Bewegen ← → · Sprung Leertaste
-controls.calculator=Grafikrechner f(u) eingeben · Trans · Maßstab · Pinch · Zurück
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x) für x>0 · min(x,3)...
graph.status_enter=Eingabe / außerhalb tippen zum Zeichnen
@@ -22,7 +19,7 @@ graph.status_graphed=Gezeichnet
graph.line1=Grafikrechner-Modus
graph.line2=Geben Sie unten f(u) ein (Variable x im Feld = inneres u). Dann:
graph.line3=Trans → {0} · Doppeltipp + · halten − · Maßstab hereinzoomen / halten herauszoomen · Zweifinger-Pinch
-graph.line4=A={0} k={1} C={2} D={3} x in [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x in [{4},{5}]
graph.param_a=A (vertikaler Maßstab)
graph.param_k=k (horizontaler Maßstab)
graph.param_c=C (vertikale Verschiebung)
@@ -65,20 +62,28 @@ level.30=BC: Phase & SHM (Energie)
level.31=BC: Kubik & Wendepunkt (Skizze)
level.32=BC: b^x & d/dx b^x
level.33=Kreis: (x−h)² + (y−k)² = R²
-level.34=Luftfahrt: Auftrieb C_L(α) linear + Strömungsabriss
-level.35=Luftfahrt: Widerstandspolare (profil-, induziert, gesamt)
-level.36=Luftfahrt: isotherme Atmosphäre ρ(h)
-level.37=Luftfahrt: Phugoid / gedämpfte Nick-Hubbewegung
-level.38=Luftfahrt: newtonsch Cp ~ sin²α
-level.39=Luftfahrt: Strouhal / Wirbelabwurf-Ton
-level.40=Luftfahrt: Wiedereintritts-Hülle (ρV Erwärmung)
-level.41=Wirtschaft: Dotcom-Blase & Crash (stilisierter Index)
-level.42=Wirtschaft: Krise 2008 & Erholung (stilisierter Index)
-level.43=BOSS: Mandelbrot-Escapeschnitt (Fraktal)
-level.44=Physik C: Thermodynamik (adiabater P–V-Verlauf, γ aus N)
-level.45=BOSS: Goldener-Spiralen-Logarithmus (Polar)
-level.46=Transformationen: Fourier — sinc-Spektrum
-level.47=Transformationen: Laplace — exponentieller Abfall
-level.48=BOSS: Mandelbrot — Finale (Fraktal-Escape-Schnitt)
-level.49=BOSS: Lorenz-Attraktor — Finale (seltsamer Attraktor)
+level.34=Physik C: Thermodynamik (adiabater P–V-Verlauf, γ aus N)
+level.35=Luftfahrt: Auftrieb C_L(α) linear + Strömungsabriss
+level.36=Luftfahrt: Widerstandspolare (profil-, induziert, gesamt)
+level.37=Luftfahrt: isotherme Atmosphäre ρ(h)
+level.38=Luftfahrt: Phugoid / gedämpfte Nick-Hubbewegung
+level.39=Luftfahrt: newtonsch Cp ~ sin²α
+level.40=Luftfahrt: Strouhal / Wirbelabwurf-Ton
+level.41=Luftfahrt: Wiedereintritts-Hülle (ρV Erwärmung)
+level.42=Wirtschaft: Dotcom-Blase & Crash (stilisierter Index)
+level.43=Wirtschaft: Krise 2008 & Erholung (stilisierter Index)
+level.44=Transformationen: Fourier — sinc-Spektrum
+level.45=Transformationen: Laplace — exponentieller Abfall
+level.46=BOSS: Goldener-Spiralen-Logarithmus (Polar)
+level.47=BOSS: Mandelbrot — Finale (Fraktal-Escape-Schnitt)
+level.48=BOSS: Lorenz-Attraktor — Chaos-Theorie (seltsamer Attraktor)
+level.49=BOSS: Schwarzes Loch — Gravitationsbrunnen (1/r-Schnitt)
level.50=Physik C: Feder–Masse SHM (Hooke, ungedämpft)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
diff --git a/First Principles/Assets/Resources/Localization/en.txt b/First Principles/Assets/Resources/Localization/en.txt
index 4313118..8eeddaa 100644
--- a/First Principles/Assets/Resources/Localization/en.txt
+++ b/First Principles/Assets/Resources/Localization/en.txt
@@ -8,10 +8,12 @@ level_select.cat.integration=Multivar & integration
level_select.cat.engineering=Engineering
level_select.cat.ap_bc=AP Calculus BC & Physics C
level_select.cat.aerospace=Aerospace
-level_select.cat.finale=Advanced & boss
+level_select.cat.astrophysics=Astrophysics
+level_select.cat.economics=Economics
level_select.cat.transforms=Transforms
level_select.cat.final_boss=Final boss
level_select.cat.spring_physics=Spring & SHM
+level_select.cat.big_o=Big O notation
ui.math_tips=Math tips & snippets
ui.back_menu=Back to Menu
ui.graphing_calculator_mode=Graphing\ncalculator
@@ -20,14 +22,14 @@ ui.language=Language
ui.tap_change_language=Tap to change
ui.stage_intro_hint=Tap anywhere to continue
ui.close=Close
+ui.coming_soon=Coming soon!
+ui.coming_soon_tap=Tap anywhere to close
ui.math_concepts=Math concepts
ui.jump=Jump
ui.move=Move
ui.keyboard_hint_mobile=(keyboard: arrows / Space)
hud.stage=STAGE
-controls.mobile=Move ◀ ▶ · Jump tap (keyboard: arrows / Space)
-controls.desktop=Move ← → · Jump Space
-controls.calculator=Graphing calculator Type f(u) · Deriv · ∫ · Trans · Scale · Pinch · Back
+hud.points=PTS
graph.calc_deriv=Deriv
graph.calc_integral=∫ area
graph.calc_primitive_prefix=Primitive (guess):
@@ -39,7 +41,7 @@ graph.status_graphed=Graphed
graph.line1=Graphing calculator mode
graph.line2=Type f(u) below (variable x in the box = inner u). Then:
graph.line3=Deriv adds f′ once (numeric) · ∫ area Riemann strips once + primitive guess · Trans → {0} · double-tap + · hold − · Scale / pinch
-graph.line4=A={0} k={1} C={2} D={3} x in [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x in [{4},{5}]
graph.param_a=A (vertical scale)
graph.param_k=k (horizontal scale)
graph.param_c=C (vertical shift)
@@ -49,13 +51,13 @@ graph.polar.param_a=A (r scale)
graph.polar.param_k=k (θ scale)
graph.polar.param_c=C (r shift)
graph.polar.param_d=D (θ phase / axis shift)
-graph.polar.line4=A={0} k={1} C={2} D={3} θ∈[{4},{5}]
-graph.calculator_intro=Graphing calculator mode\nType almost any f(u) in the field (variable x in your formula); Trans adjusts A, k, C, D; Scale & pinch zoom the window.
-# Prepended to story text for every Aerospace stage (indices 34–40).
+graph.polar.line4=A={0} k={1} C={2} D={3} θ∈[{4},{5}]
+graph.calculator_intro=Graphing calculator mode\nType almost any f(u) in the field (variable x in your formula); Trans adjusts A, k, C, D; Scale · pinch zoom the window.
+# Prepended to story text for every Aerospace stage (indices 35–41).
aerospace.story_drag_polar_preamble=Drag polar refresher (every Aerospace stage)\nParasitic (zero-lift) drag — skin friction, form drag, interference lumped as CD0 in the parabolic model (roughly not the part that grows with lift).\nInduced drag — the cost of making lift: trailing vortices add ~ K CL² (higher CL / tighter turns → more induced).\nOverall drag polar — CD = CD0 + K CL²: an upward-opening parabola in CL; min-drag CL sits between “too slow / high α” and “too fast / low α” for real missions.
menu.tutorial_button=How to play
menu.tutorial_title=How to play
-menu.tutorial_body=Goal\nMove along the graph, use platforms (green), avoid red hazards, and reach the bright exit on the right.\n\nControls\n• Move — arrows / WASD, or on-screen buttons.\n• Jump — Space (or mobile jump). You jump from solid platforms.\n\nThe two curves\n• Main curve — the function you walk on.\n• Derivative f′ — slope information; it’s drawn as a second line.\n\nAir jump on the derivative\nWhile you are in the air, if your character overlaps the derivative curve, press Jump again for an extra hop.\n\nThe derivative line brightens when you touch it. You get one bonus jump each time you brush it until you leave the curve or land. On phones you may feel a short vibration when you touch f′; on PC a sound plays when vibration isn’t available.\n\nSelect level\nOn this screen, stages are grouped (Core, Engineering, AP Calculus, Aerospace …). Tap How to play at the bottom to reopen this help. Pick a group, then a level.
+menu.tutorial_body=Goal\nMove along the graph, use platforms (green), avoid red hazards, and reach the bright exit on the right.\n\nControls\n• Move — arrows / WASD, or on a phone hold the left / right half of the screen.\n• Jump — Space, or on a phone tap with a second finger while holding left/right. You jump from solid platforms.\n\nThe two curves\n• Main curve — the function you walk on.\n• Derivative f′ — slope information; it’s drawn as a second line.\n\nAir jump on the derivative\nWhile you are in the air, if your character overlaps the derivative curve, press Jump again for an extra hop.\n\nThe derivative line brightens when you touch it. You get one bonus jump each time you brush it until you leave the curve or land. On phones you may feel a short vibration when you touch f′; on PC a sound plays when vibration isn’t available.\n\nSelect level\nOn this screen, stages are grouped (Core, Engineering, AP Calculus, Aerospace …). Tap How to play at the bottom to reopen this help. Pick a group, then a level.
menu.player_icon_title=Player icon
menu.player_icon_set=Player icon
menu.player_icon_hint=Tap a symbol — it’s your avatar in levels.
@@ -97,20 +99,29 @@ level.30=BC: phase & SHM (energy swaps)
level.31=BC: cubic & inflection (sketching)
level.32=BC: b^x & d/dx b^x
level.33=Circle: (x−h)² + (y−k)² = R²
-level.34=Aerospace: lift C_L(α) linear + stall
-level.35=Aerospace: drag polar (parasitic, induced, total)
-level.36=Aerospace: isothermal atmosphere ρ(h)
-level.37=Aerospace: phugoid / damped pitch–heave mood
-level.38=Aerospace: Newtonian Cp ~ sin²α
-level.39=Aerospace: Strouhal / vortex shedding tone
-level.40=Aerospace: re-entry decay envelope (ρV heating mood)
-level.41=Economics: dot-com bubble & crash (stylized index)
-level.42=Economics: 2008 crisis & recovery (stylized index)
-level.43=BOSS: Mandelbrot escape slice (fractal boundary mood)
-level.44=Physics C: thermodynamics (adiabatic P–V, γ from N)
-level.45=BOSS: golden ratio spiral (logarithmic polar)
-level.46=Transforms: Fourier — sinc spectrum (rect ↔ sinc)
-level.47=Transforms: Laplace — causal exponential decay
-level.48=BOSS: Mandelbrot — finale (fractal escape slice)
-level.49=BOSS: Lorenz butterfly — finale (strange attractor)
+level.34=Physics C: thermodynamics (adiabatic P–V, γ from N)
+level.35=Aerospace: lift C_L(α) linear + stall
+level.36=Aerospace: drag polar (parasitic, induced, total)
+level.37=Aerospace: isothermal atmosphere ρ(h)
+level.38=Aerospace: phugoid / damped pitch–heave mood
+level.39=Aerospace: Newtonian Cp ~ sin²α
+level.40=Aerospace: Strouhal / vortex shedding tone
+level.41=Aerospace: re-entry decay envelope (ρV heating mood)
+level.42=Economics: dot-com bubble & crash (stylized index)
+level.43=Economics: 2008 crisis & recovery (stylized index)
+level.44=Transforms: Fourier — sinc spectrum (rect ↔ sinc)
+level.45=Transforms: Laplace — causal exponential decay
+level.46=BOSS: golden ratio spiral (logarithmic polar)
+level.47=BOSS: Mandelbrot — finale (fractal escape slice)
+level.48=BOSS: Lorenz attractor — Chaos Theory (strange attractor)
+level.49=BOSS: Black hole — gravity well (1/r slice)
level.50=Physics C: spring–mass SHM (Hooke's law, undamped)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
+level.59=Astrophysics: Hohmann transfer
diff --git a/First Principles/Assets/Resources/Localization/es.txt b/First Principles/Assets/Resources/Localization/es.txt
index 3e5dd9b..cf2e452 100644
--- a/First Principles/Assets/Resources/Localization/es.txt
+++ b/First Principles/Assets/Resources/Localization/es.txt
@@ -12,9 +12,6 @@ ui.jump=Saltar
ui.move=Mover
ui.keyboard_hint_mobile=(teclado: flechas / Espacio)
hud.stage=FASE
-controls.mobile=Mover ◀ ▶ · Saltar tocar (teclado: flechas / Espacio)
-controls.desktop=Mover ← → · Saltar Espacio
-controls.calculator=Calculadora gráfica Escribir f(u) · Trans · Escala · Pellizco · Atrás
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x) para x>0 · min(x,3)...
graph.status_enter=Intro / tocar fuera para graficar
@@ -22,7 +19,7 @@ graph.status_graphed=Graficado
graph.line1=Modo calculadora gráfica
graph.line2=Escribe f(u) abajo (la variable x en el cuadro = u interior). Luego:
graph.line3=Trans → {0} · doble toque + · mantén − · Escala acercar / mantén alejar · pellizco con dos dedos
-graph.line4=A={0} k={1} C={2} D={3} x en [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x en [{4},{5}]
graph.param_a=A (escala vertical)
graph.param_k=k (escala horizontal)
graph.param_c=C (desplazamiento vertical)
@@ -65,20 +62,28 @@ level.30=BC: fase y MAS (energía)
level.31=BC: cúbica e inflexión (boceto)
level.32=BC: b^x y d/dx b^x
level.33=Círculo: (x−h)² + (y−k)² = R²
-level.34=Aero: sustentación C_L(α) lineal + pérdida
-level.35=Aero: polar de arrastre (parásita, inducida, total)
-level.36=Aero: atmósfera isoterma ρ(h)
-level.37=Aero: fugoide / cabeceo–heave amortiguado
-level.38=Aero: newtoniano Cp ~ sin²α
-level.39=Aero: Strouhal / tono de vórtices
-level.40=Aero: envolvente de reentrada (calor ρV)
-level.41=Economía: burbuja dotcom y crash (índice estilizado)
-level.42=Economía: crisis 2008 y recuperación (índice estilizado)
-level.43=JEFE: corte de escape Mandelbrot (fractal)
-level.44=Física C: termodinámica (P–V adiabático, γ desde N)
-level.45=JEFE: espiral áurea (polar logarítmica)
-level.46=Transformadas: Fourier — sinc (espectro)
-level.47=Transformadas: Laplace — decaimiento exponencial
-level.48=JEFE: Mandelbrot — final (corte de escape fractal)
-level.49=JEFE: mariposa de Lorenz — final (atractor extraño)
+level.34=Física C: termodinámica (P–V adiabático, γ desde N)
+level.35=Aero: sustentación C_L(α) lineal + pérdida
+level.36=Aero: polar de arrastre (parásita, inducida, total)
+level.37=Aero: atmósfera isoterma ρ(h)
+level.38=Aero: fugoide / cabeceo–heave amortiguado
+level.39=Aero: newtoniano Cp ~ sin²α
+level.40=Aero: Strouhal / tono de vórtices
+level.41=Aero: envolvente de reentrada (calor ρV)
+level.42=Economía: burbuja dotcom y crash (índice estilizado)
+level.43=Economía: crisis 2008 y recuperación (índice estilizado)
+level.44=Transformadas: Fourier — sinc (espectro)
+level.45=Transformadas: Laplace — decaimiento exponencial
+level.46=JEFE: espiral áurea (polar logarítmica)
+level.47=JEFE: Mandelbrot — final (corte de escape fractal)
+level.48=JEFE: atractor de Lorenz — teoría del caos (atractor extraño)
+level.49=JEFE: agujero negro — pozo gravitatorio (corte 1/r)
level.50=Física C: resorte–masa SHM (ley de Hooke, sin amortiguación)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
diff --git a/First Principles/Assets/Resources/Localization/fr.txt b/First Principles/Assets/Resources/Localization/fr.txt
index 515a3d3..fbdcb0d 100644
--- a/First Principles/Assets/Resources/Localization/fr.txt
+++ b/First Principles/Assets/Resources/Localization/fr.txt
@@ -12,9 +12,6 @@ ui.jump=Saut
ui.move=Déplacer
ui.keyboard_hint_mobile=(clavier : flèches / Espace)
hud.stage=NIVEAU
-controls.mobile=Déplacer ◀ ▶ · Saut tapoter (clavier : flèches / Espace)
-controls.desktop=Déplacer ← → · Saut Espace
-controls.calculator=Calculatrice graphique Saisir f(u) · Trans · Échelle · Pincer · Retour
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x) si x>0 · min(x,3)...
graph.status_enter=Entrée / toucher ailleurs pour tracer
@@ -22,7 +19,7 @@ graph.status_graphed=Tracé
graph.line1=Mode calculatrice graphique
graph.line2=Saisissez f(u) ci-dessous (la variable x dans la zone = u interne). Ensuite :
graph.line3=Trans → {0} · double appui + · maintenir − · Échelle zoom avant / maintenir zoom arrière · pincer deux doigts
-graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}]
graph.param_a=A (échelle verticale)
graph.param_k=k (échelle horizontale)
graph.param_c=C (translation verticale)
@@ -65,20 +62,28 @@ level.30=BC : phase & MHS (échanges d’énergie)
level.31=BC : cubique & inflexion (esquisse)
level.32=BC : b^x & d/dx b^x
level.33=Cercle : (x−h)² + (y−k)² = R²
-level.34=Aéro : portance C_L(α) linéaire + décrochage
-level.35=Aéro : polaire (traînée de profil, induite, totale)
-level.36=Aéro : atmosphère isotherme ρ(h)
-level.37=Aéro : phugoïde / oscillation amortie tangage–pilonnement
-level.38=Aéro : newtonien Cp ~ sin²α
-level.39=Aéro : Strouhal / tonalité tourbillonnaire
-level.40=Aéro : enveloppe rentrée (échauffement ρV)
-level.41=Éco : bulle internet & krach (indice stylisé)
-level.42=Éco : crise 2008 & reprise (indice stylisé)
-level.43=BOSS : tranche d’échappement Mandelbrot (fractale)
-level.44=Physique C : thermodynamique (adiabatique P–V, γ depuis N)
-level.45=BOSS : spirale d’or (polaire logarithmique)
-level.46=Transformations : Fourier — sinc (spectre)
-level.47=Transformations : Laplace — décroissance exponentielle
-level.48=BOSS : Mandelbrot — finale (tranche d’échappement fractale)
-level.49=BOSS : papillon de Lorenz — finale (attracteur étrange)
+level.34=Physique C : thermodynamique (adiabatique P–V, γ depuis N)
+level.35=Aéro : portance C_L(α) linéaire + décrochage
+level.36=Aéro : polaire (traînée de profil, induite, totale)
+level.37=Aéro : atmosphère isotherme ρ(h)
+level.38=Aéro : phugoïde / oscillation amortie tangage–pilonnement
+level.39=Aéro : newtonien Cp ~ sin²α
+level.40=Aéro : Strouhal / tonalité tourbillonnaire
+level.41=Aéro : enveloppe rentrée (échauffement ρV)
+level.42=Éco : bulle internet & krach (indice stylisé)
+level.43=Éco : crise 2008 & reprise (indice stylisé)
+level.44=Transformations : Fourier — sinc (spectre)
+level.45=Transformations : Laplace — décroissance exponentielle
+level.46=BOSS : spirale d’or (polaire logarithmique)
+level.47=BOSS : Mandelbrot — finale (tranche d’échappement fractale)
+level.48=BOSS : attracteur de Lorenz — théorie du chaos (attracteur étrange)
+level.49=BOSS : trou noir — puits de gravité (tranche 1/r)
level.50=Physique C : ressort–masse SHM (loi de Hooke, non amorti)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
diff --git a/First Principles/Assets/Resources/Localization/hi.txt b/First Principles/Assets/Resources/Localization/hi.txt
index aa2fc05..f729fbc 100644
--- a/First Principles/Assets/Resources/Localization/hi.txt
+++ b/First Principles/Assets/Resources/Localization/hi.txt
@@ -13,9 +13,6 @@ ui.jump=कूद
ui.move=चलें
ui.keyboard_hint_mobile=(कीबोर्ड: तीर / स्पेस)
hud.stage=चरण
-controls.mobile=चलें ◀ ▶ · कूद टैप (कीबोर्ड: तीर / स्पेस)
-controls.desktop=चलें ← → · कूद स्पेस
-controls.calculator=ग्राफ़िंग कैलकुलेटर f(u) लिखें · Trans · Scale · पिंच · वापस
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x) जब x>0 · min(x,3)...
graph.status_enter=Enter / ग्राफ़ के लिए बाहर टैप करें
@@ -23,7 +20,7 @@ graph.status_graphed=ग्राफ़ तैयार
graph.line1=ग्राफ़िंग कैलकुलेटर मोड
graph.line2=नीचे f(u) लिखें (बॉक्स में चर x = आंतरिक u)। फिर:
graph.line3=Trans → {0} · + पर डबल-टैप · − दबाकर रखें · Scale ज़ूम इन / आउट दबाकर रखें · दो उंगलियों से पिंच
-graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}]
graph.param_a=A (लंबवत स्केल)
graph.param_k=k (क्षैतिज स्केल)
graph.param_c=C (लंबवत खिसकाव)
@@ -67,20 +64,28 @@ level.30=BC: कला व सरल हार्मोनिक गति
level.31=BC: घन व प्रगाढ़ता (रेखाचित्र)
level.32=BC: b^x व d/dx b^x
level.33=वृत्त: (x−h)² + (y−k)² = R²
-level.34=एयरोस्पेस: लिफ़्ट C_L(α) रैखिक + स्टॉल
-level.35=एयरोस्पेस: ड्रैग पोलर (पैरासिटिक, प्रेरित, कुल)
-level.36=एयरोस्पेस: समतापमान वायुमंडल ρ(h)
-level.37=एयरोस्पेस: फ्यूगॉइड / डैम्प्ड पिच-हीव
-level.38=एयरोस्पेस: न्यूटोनियन Cp ~ sin²α
-level.39=एयरोस्पेस: स्ट्रौहल / वॉर्टेक्स शेडिंग
-level.40=एयरोस्पेस: पुनः प्रवेश क्षय लिफ़ाफ़ा (ρV ताप मूड)
-level.41=अर्थव्यवस्था: डॉट-कॉम बुलबुला व पतन (नमूना सूचकांक)
-level.42=अर्थव्यवस्था: 2008 संकट व रिकवरी (नमूना सूचकांक)
-level.43=BOSS: मैंडेलब्रॉट एस्केप स्लाइस (फ्रैक्टल)
-level.44=भौतिकी C: ऊष्मागतिकी (एडियाबैटिक P–V, γ का मान N से)
-level.45=BOSS: स्वर्ण अनुपात सर्पिल (लघुगणकीय ध्रुवीय)
-level.46=रूपांतरण: फूरियर — सिंक स्पेक्ट्रम
-level.47=रूपांतरण: लाप्लास — घातांकी क्षय
-level.48=BOSS: मैंडेलब्रॉट — अंतिम (फ्रैक्टल एस्केप स्लाइस)
-level.49=BOSS: लोरेंज तितली — अंतिम (विलक्षण आकर्षक)
+level.34=भौतिकी C: ऊष्मागतिकी (एडियाबैटिक P–V, γ का मान N से)
+level.35=एयरोस्पेस: लिफ़्ट C_L(α) रैखिक + स्टॉल
+level.36=एयरोस्पेस: ड्रैग पोलर (पैरासिटिक, प्रेरित, कुल)
+level.37=एयरोस्पेस: समतापमान वायुमंडल ρ(h)
+level.38=एयरोस्पेस: फ्यूगॉइड / डैम्प्ड पिच-हीव
+level.39=एयरोस्पेस: न्यूटोनियन Cp ~ sin²α
+level.40=एयरोस्पेस: स्ट्रौहल / वॉर्टेक्स शेडिंग
+level.41=एयरोस्पेस: पुनः प्रवेश क्षय लिफ़ाफ़ा (ρV ताप मूड)
+level.42=अर्थव्यवस्था: डॉट-कॉम बुलबुला व पतन (नमूना सूचकांक)
+level.43=अर्थव्यवस्था: 2008 संकट व रिकवरी (नमूना सूचकांक)
+level.44=रूपांतरण: फूरियर — सिंक स्पेक्ट्रम
+level.45=रूपांतरण: लाप्लास — घातांकी क्षय
+level.46=BOSS: स्वर्ण अनुपात सर्पिल (लघुगणकीय ध्रुवीय)
+level.47=BOSS: मैंडेलब्रॉट — अंतिम (फ्रैक्टल एस्केप स्लाइस)
+level.48=BOSS: लोरेंज आकर्षक — अराजकता सिद्धांत (विलक्षण आकर्षक)
+level.49=BOSS: ब्लैक होल — गुरुत्वाकर्षण कुआँ (1/r स्लाइस)
level.50=फिजिक्स C: स्प्रिंग–द्रव्यमान SHM (हूक का नियम, अवमंदन रहित)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
diff --git a/First Principles/Assets/Resources/Localization/it.txt b/First Principles/Assets/Resources/Localization/it.txt
index e109b7e..243ddd4 100644
--- a/First Principles/Assets/Resources/Localization/it.txt
+++ b/First Principles/Assets/Resources/Localization/it.txt
@@ -7,10 +7,11 @@ level_select.cat.integration=Multivariabile e integrazione
level_select.cat.engineering=Ingegneria
level_select.cat.ap_bc=AP Calculus BC e Fisica C
level_select.cat.aerospace=Aerospaziale
-level_select.cat.finale=Avanzati e boss
+level_select.cat.economics=Economia
level_select.cat.transforms=Trasformate
level_select.cat.final_boss=Boss finale
level_select.cat.spring_physics=Molla e SHM
+level_select.cat.big_o=Notazione Big O
ui.math_tips=Suggerimenti di matematica
ui.back_menu=Torna al menu
ui.graphing_calculator_mode=Calcolatrice grafica
@@ -24,9 +25,6 @@ ui.jump=Salta
ui.move=Muoviti
ui.keyboard_hint_mobile=(tastiera: frecce / Spazio)
hud.stage=STADIO
-controls.mobile=Muoviti ◀ ▶ · Salta tocco (tastiera: frecce / Spazio)
-controls.desktop=Muoviti ← → · Salta Spazio
-controls.calculator=Calcolatrice grafica Digita f(u) · Trasf · Scala · Pizzica · Indietro
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x) per x>0 · min(x,3)...
graph.status_enter=Invio / tocca fuori per tracciare
@@ -34,7 +32,7 @@ graph.status_graphed=Tracciato
graph.line1=Modalità calcolatrice grafica
graph.line2=Digita f(u) sotto (la variabile x nella casella = u interno). Poi:
graph.line3=Trasf → {0} · doppio tocco + · tieni premuto − · Scala zoom avanti / tieni zoom indietro · pizzica a due dita
-graph.line4=A={0} k={1} C={2} D={3} x in [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x in [{4},{5}]
graph.param_a=A (scala verticale)
graph.param_k=k (scala orizzontale)
graph.param_c=C (traslazione verticale)
@@ -85,20 +83,28 @@ level.30=BC: fase e moto armonico (scambio energia)
level.31=BC: cubica e flesso (schizzo)
level.32=BC: b^x e d/dx b^x
level.33=Cerchio: (x−h)² + (y−k)² = R²
-level.34=Aerospaziale: portanza C_L(α) lineare + stallo
-level.35=Aerospaziale: polare di resistenza (parassita, indotta, totale)
-level.36=Aerospaziale: atmosfera isoterma ρ(h)
-level.37=Aerospaziale: fugoide / modo smorzato beccheggio‑altitudine
-level.38=Aerospaziale: newtoniano Cp ~ sin²α
-level.39=Aerospaziale: Strouhal / tono di scia vorticosa
-level.40=Aerospaziale: inviluppo decadimento rientro (mood riscaldamento ρV)
-level.41=Economia: bolla dot-com e crollo (indice stilizzato)
-level.42=Economia: crisi 2008 e ripresa (indice stilizzato)
-level.43=BOSS: sezione escape Mandelbrot (mood frattale)
-level.44=Fisica C: termodinamica (P–V adiabatico, γ da N)
-level.45=BOSS: spirale aurea (polare logaritmica)
-level.46=Trasformate: Fourier — sinc (spettro)
-level.47=Trasformate: Laplace — decadimento esponenziale
-level.48=BOSS: Mandelbrot — finale (sezione escape frattale)
-level.49=BOSS: farfalla di Lorenz — finale (attrattore strano)
+level.34=Fisica C: termodinamica (P–V adiabatico, γ da N)
+level.35=Aerospaziale: portanza C_L(α) lineare + stallo
+level.36=Aerospaziale: polare di resistenza (parassita, indotta, totale)
+level.37=Aerospaziale: atmosfera isoterma ρ(h)
+level.38=Aerospaziale: fugoide / modo smorzato beccheggio‑altitudine
+level.39=Aerospaziale: newtoniano Cp ~ sin²α
+level.40=Aerospaziale: Strouhal / tono di scia vorticosa
+level.41=Aerospaziale: inviluppo decadimento rientro (mood riscaldamento ρV)
+level.42=Economia: bolla dot-com e crollo (indice stilizzato)
+level.43=Economia: crisi 2008 e ripresa (indice stilizzato)
+level.44=Trasformate: Fourier — sinc (spettro)
+level.45=Trasformate: Laplace — decadimento esponenziale
+level.46=BOSS: spirale aurea (polare logaritmica)
+level.47=BOSS: Mandelbrot — finale (sezione escape frattale)
+level.48=BOSS: attrattore di Lorenz — teoria del caos (attrattore strano)
+level.49=BOSS: buco nero — pozzo gravitazionale (sezione 1/r)
level.50=Fisica C: molla–massa SHM (legge di Hooke, non smorzato)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
diff --git a/First Principles/Assets/Resources/Localization/ja.txt b/First Principles/Assets/Resources/Localization/ja.txt
index e2ba1ae..4a78070 100644
--- a/First Principles/Assets/Resources/Localization/ja.txt
+++ b/First Principles/Assets/Resources/Localization/ja.txt
@@ -12,9 +12,6 @@ ui.jump=ジャンプ
ui.move=移動
ui.keyboard_hint_mobile=(キーボード:矢印/スペース)
hud.stage=ステージ
-controls.mobile=移動 ◀ ▶ · ジャンプ タップ (キーボード:矢印/スペース)
-controls.desktop=移動 ← → · ジャンプ スペース
-controls.calculator=グラフ電卓 f(u) を入力 · Trans · Scale · ピンチ · 戻る
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x) (x>0)· min(x,3)...
graph.status_enter=Enter/外側タップでグラフ描画
@@ -22,7 +19,7 @@ graph.status_graphed=描画済み
graph.line1=グラフ電卓モード
graph.line2=下にf(u)を入力(欄内の変数xは内側の u)。次に:
graph.line3=Trans → {0} · ダブルタップ + · 長押し − · Scale はタップで拡大/長押しで縮小 · 2本指ピンチ
-graph.line4=A={0} k={1} C={2} D={3} x は [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x は [{4},{5}]
graph.param_a=A(縦スケール)
graph.param_k=k(横スケール)
graph.param_c=C(縦シフト)
@@ -65,20 +62,28 @@ level.30=BC:位相と単振動(エネルギー)
level.31=BC:三次関数と変曲点(スケッチ)
level.32=BC:b^x と d/dx b^x
level.33=円:(x−h)² + (y−k)² = R²
-level.34=航空:揚力C_L(α) 線形+失速
-level.35=航空:抗力極曲線(プロファイル·誘導·合計)
-level.36=航空:等温大気 ρ(h)
-level.37=航空:フゴイド/減衰ピッチ・上下動
-level.38=航空:ニュートン流 Cp ~ sin²α
-level.39=航空:ストルーハル/渦放出音
-level.40=航空:再突入減衰包絡線(ρV加熱)
-level.41=経済:ドットコムバブルと暴落(模式化インデックス)
-level.42=経済:2008年危機と回復(模式化インデックス)
-level.43=BOSS:マンデルブロ脱出断面(フラクタル)
-level.44=物理C:熱力学(断熱P–V、γはNから)
-level.45=BOSS:黄金螺旋(対数・極座標)
-level.46=変換:フーリエ — sincスペクトラム
-level.47=変換:ラプラス — 指数減衰
-level.48=BOSS:マンデルブロ — フィナーレ(フラクタル脱出断面)
-level.49=BOSS:ローレンツの蝶 — フィナーレ(ストレンジアトラクター)
+level.34=物理C:熱力学(断熱P–V、γはNから)
+level.35=航空:揚力C_L(α) 線形+失速
+level.36=航空:抗力極曲線(プロファイル·誘導·合計)
+level.37=航空:等温大気 ρ(h)
+level.38=航空:フゴイド/減衰ピッチ・上下動
+level.39=航空:ニュートン流 Cp ~ sin²α
+level.40=航空:ストルーハル/渦放出音
+level.41=航空:再突入減衰包絡線(ρV加熱)
+level.42=経済:ドットコムバブルと暴落(模式化インデックス)
+level.43=経済:2008年危機と回復(模式化インデックス)
+level.44=変換:フーリエ — sincスペクトラム
+level.45=変換:ラプラス — 指数減衰
+level.46=BOSS:黄金螺旋(対数・極座標)
+level.47=BOSS:マンデルブロ — フィナーレ(フラクタル脱出断面)
+level.48=BOSS:ローレンツアトラクター — カオス理論(ストレンジアトラクター)
+level.49=BOSS:ブラックホール — 重力の井戸(1/r 断面)
level.50=物理C:ばね–質点の単振動(フックの法則、減衰なし)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
diff --git a/First Principles/Assets/Resources/Localization/ko.txt b/First Principles/Assets/Resources/Localization/ko.txt
index b703cd5..b931127 100644
--- a/First Principles/Assets/Resources/Localization/ko.txt
+++ b/First Principles/Assets/Resources/Localization/ko.txt
@@ -13,10 +13,11 @@ level_select.cat.integration=다변수 & 적분
level_select.cat.engineering=공학
level_select.cat.ap_bc=AP 미적분 BC · 물리 C
level_select.cat.aerospace=항공우주
-level_select.cat.finale=심화 & 보스
+level_select.cat.economics=경제
level_select.cat.transforms=변환
level_select.cat.final_boss=최종 보스
level_select.cat.spring_physics=스프링·단진동
+level_select.cat.big_o=빅오 표기법
ui.math_tips=수학 팁 모음
ui.back_menu=메뉴로
ui.graphing_calculator_mode=그래프 계산기
@@ -29,9 +30,6 @@ ui.jump=점프
ui.move=이동
ui.keyboard_hint_mobile=(키보드: 방향키 / 스페이스)
hud.stage=스테이지
-controls.mobile=이동 ◀ ▶ · 점프 탭 (키보드: 방향키 / 스페이스)
-controls.desktop=이동 ← → · 점프 스페이스
-controls.calculator=그래프 계산기 f(u) 입력 · Trans · Scale · 핀치 · 뒤로
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x) (x>0) · min(x,3)...
graph.status_enter=Enter / 바깥 탭으로 그래프
@@ -39,7 +37,7 @@ graph.status_graphed=그래프 완료
graph.line1=그래프 계산기 모드
graph.line2=아래에 f(u) 입력(상자 안 변수 x = 내부 u). 그다음:
graph.line3=Trans → {0} · 더블탭 + · 길게 − · Scale 탭 확대 / 길게 축소 · 두 손가락 핀치
-graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}]
graph.param_a=A (세로 스케일)
graph.param_k=k (가로 스케일)
graph.param_c=C (세로 이동)
@@ -83,20 +81,28 @@ level.30=BC: 위상과 단진동 (에너지)
level.31=BC: 삼차함수와 변곡점 (스케치)
level.32=BC: b^x와 d/dx b^x
level.33=원: (x−h)² + (y−k)² = R²
-level.34=항공: 양력 C_L(α) 선형 및 실속
-level.35=항공: 항력 극곡선 (패러사이틱·유도·합)
-level.36=항공: 등온 대기 ρ(h)
-level.37=항공: 퓨고이드 / 감쇠 피치-헤이브
-level.38=항공: 뉴턴 Cp ~ sin²α
-level.39=항공: 스트루할 / 와류 방출 음
-level.40=항공: 재진입 감쇠 포락선 (ρV 가열)
-level.41=경제: 닷컴 버블·붕괴 (스타일화 지수)
-level.42=경제: 2008 위기·회복 (스타일화 지수)
-level.43=보스: 만델브로 탈출 단면 (프랙탈)
-level.44=물리 C: 열역학 (단열 P–V, γ는 N에서)
-level.45=보스: 황금비 나선 (로그 극좌표)
-level.46=변환: 푸리에 — sinc 스펙트럼
-level.47=변환: 라플라스 — 지수 감쇠
-level.48=보스: 만델브로 — 피날레 (프랙탈 탈출 단면)
-level.49=보스: 로렌츠 나비 — 피날레 (이상한 끌개)
+level.34=물리 C: 열역학 (단열 P–V, γ는 N에서)
+level.35=항공: 양력 C_L(α) 선형 및 실속
+level.36=항공: 항력 극곡선 (패러사이틱·유도·합)
+level.37=항공: 등온 대기 ρ(h)
+level.38=항공: 퓨고이드 / 감쇠 피치-헤이브
+level.39=항공: 뉴턴 Cp ~ sin²α
+level.40=항공: 스트루할 / 와류 방출 음
+level.41=항공: 재진입 감쇠 포락선 (ρV 가열)
+level.42=경제: 닷컴 버블·붕괴 (스타일화 지수)
+level.43=경제: 2008 위기·회복 (스타일화 지수)
+level.44=변환: 푸리에 — sinc 스펙트럼
+level.45=변환: 라플라스 — 지수 감쇠
+level.46=보스: 황금비 나선 (로그 극좌표)
+level.47=보스: 만델브로 — 피날레 (프랙탈 탈출 단면)
+level.48=보스: 로렌츠 어트랙터 — 카오스 이론 (이상한 끌개)
+level.49=보스: 블랙홀 — 중력 우물 (1/r 단면)
level.50=물리 C: 스프링–질점 SHM (훅의 법칙, 비감쇠)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
diff --git a/First Principles/Assets/Resources/Localization/pl.txt b/First Principles/Assets/Resources/Localization/pl.txt
index fe27aa8..e16f0d3 100644
--- a/First Principles/Assets/Resources/Localization/pl.txt
+++ b/First Principles/Assets/Resources/Localization/pl.txt
@@ -7,10 +7,11 @@ level_select.cat.integration=Zmienne wielowymiarowe i całki
level_select.cat.engineering=Inżynieria
level_select.cat.ap_bc=AP Calculus BC i Fizyka C
level_select.cat.aerospace=Lotnictwo i kosmonautyka
-level_select.cat.finale=Zaawansowane i boss
+level_select.cat.economics=Ekonomia
level_select.cat.transforms=Transformaty
level_select.cat.final_boss=Finałowy boss
level_select.cat.spring_physics=Sprężyna i SHM
+level_select.cat.big_o=Notacja dużego O
ui.math_tips=Wskazówki matematyczne
ui.back_menu=Powrót do menu
ui.graphing_calculator_mode=Kalkulator graficzny
@@ -24,9 +25,6 @@ ui.jump=Skok
ui.move=Ruch
ui.keyboard_hint_mobile=(klawiatura: strzałki / Spacja)
hud.stage=ETAP
-controls.mobile=Ruch ◀ ▶ · Skok dotknij (klawiatura: strzałki / Spacja)
-controls.desktop=Ruch ← → · Skok Spacja
-controls.calculator=Kalkulator graficzny Wpisz f(u) · Trans · Skala · Szczyp · Wstecz
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x) dla x>0 · min(x,3)...
graph.status_enter=Enter / dotknij poza pole, aby narysować
@@ -34,7 +32,7 @@ graph.status_graphed=Narysowano
graph.line1=Tryb kalkulatora graficznego
graph.line2=Wpisz f(u) poniżej (zmienna x w polu = wewnętrzne u). Potem:
graph.line3=Trans → {0} · podwójne dotknięcie + · przytrzymaj − · Skala przybliż / przytrzymaj oddal · szczyp dwoma palcami
-graph.line4=A={0} k={1} C={2} D={3} x w [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x w [{4},{5}]
graph.param_a=A (skala pionowa)
graph.param_k=k (skala pozioma)
graph.param_c=C (przesunięcie pionowe)
@@ -85,20 +83,28 @@ level.30=BC: faza i drgania harmoniczne (wymiana energii)
level.31=BC: sześcienny i punkt przegięcia
level.32=BC: b^x i d/dx b^x
level.33=Okrąg: (x−h)² + (y−k)² = R²
-level.34=Aerospace: siła nośna C_L(α) liniowa + przeciągnięcie
-level.35=Aerospace: polara oporu (pasożytniczy, indukowany, całkowity)
-level.36=Aerospace: atmosfera izotermiczna ρ(h)
-level.37=Aerospace: fugoide / stłumiony tryb przechylenia
-level.38=Aerospace: newtonowskie Cp ~ sin²α
-level.39=Aerospace: Strouhal / ton wirów
-level.40=Aerospace: obwiednia zaniku przy wejściu (ρV ciepło)
-level.41=Ekonomia: bańka dot-com i krach (stylizowany indeks)
-level.42=Ekonomia: kryzys 2008 i odbicie (stylizowany indeks)
-level.43=BOSS: przekrój ucieczki Mandelbrota (nastrój fraktalny)
-level.44=Fizyka C: termodynamika (adiabatyczny P–V, γ z N)
-level.45=BOSS: spirala złotego podziału (logarytmiczna, biegunowa)
-level.46=Transformaty: Fourier — sinc (widmo)
-level.47=Transformaty: Laplace — wykładniczy zanik
-level.48=BOSS: Mandelbrot — finał (fraktalny przekrój ucieczki)
-level.49=BOSS: motyl Lorenza — finał (dziwny atraktor)
+level.34=Fizyka C: termodynamika (adiabatyczny P–V, γ z N)
+level.35=Aerospace: siła nośna C_L(α) liniowa + przeciągnięcie
+level.36=Aerospace: polara oporu (pasożytniczy, indukowany, całkowity)
+level.37=Aerospace: atmosfera izotermiczna ρ(h)
+level.38=Aerospace: fugoide / stłumiony tryb przechylenia
+level.39=Aerospace: newtonowskie Cp ~ sin²α
+level.40=Aerospace: Strouhal / ton wirów
+level.41=Aerospace: obwiednia zaniku przy wejściu (ρV ciepło)
+level.42=Ekonomia: bańka dot-com i krach (stylizowany indeks)
+level.43=Ekonomia: kryzys 2008 i odbicie (stylizowany indeks)
+level.44=Transformaty: Fourier — sinc (widmo)
+level.45=Transformaty: Laplace — wykładniczy zanik
+level.46=BOSS: spirala złotego podziału (logarytmiczna, biegunowa)
+level.47=BOSS: Mandelbrot — finał (fraktalny przekrój ucieczki)
+level.48=BOSS: atraktor Lorenza — teoria chaosu (dziwny atraktor)
+level.49=BOSS: czarna dziura — studnia grawitacji (przekrój 1/r)
level.50=Fizyka C: sprężyna–masa SHM (prawo Hooka, nietłumione)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
diff --git a/First Principles/Assets/Resources/Localization/ru.txt b/First Principles/Assets/Resources/Localization/ru.txt
index 38e7881..595cc09 100644
--- a/First Principles/Assets/Resources/Localization/ru.txt
+++ b/First Principles/Assets/Resources/Localization/ru.txt
@@ -7,10 +7,11 @@ level_select.cat.integration=Многие переменные и интегра
level_select.cat.engineering=Инженерия
level_select.cat.ap_bc=AP Calculus BC и физика C
level_select.cat.aerospace=Аэрокосмос
-level_select.cat.finale=Сложные и босс
+level_select.cat.economics=Экономика
level_select.cat.transforms=Преобразования
level_select.cat.final_boss=Финальный босс
level_select.cat.spring_physics=Пружина и ГС
+level_select.cat.big_o=О-нотация
ui.math_tips=Советы по математике
ui.back_menu=В меню
ui.graphing_calculator_mode=Графический калькулятор
@@ -24,9 +25,6 @@ ui.jump=Прыжок
ui.move=Движение
ui.keyboard_hint_mobile=(клавиатура: стрелки / Пробел)
hud.stage=ЭТАП
-controls.mobile=Движение ◀ ▶ · Прыжок тап (клавиатура: стрелки / Пробел)
-controls.desktop=Движение ← → · Прыжок Пробел
-controls.calculator=Граф. калькулятор Ввод f(u) · Транс · Масштаб · Щипок · Назад
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x) при x>0 · min(x,3)...
graph.status_enter=Enter / тап вне поля для графика
@@ -34,7 +32,7 @@ graph.status_graphed=Построено
graph.line1=Режим графического калькулятора
graph.line2=Введите f(u) ниже (переменная x в поле = внутреннее u). Затем:
graph.line3=Транс → {0} · двойной тап + · удерживайте − · Масштаб увеличить / удерживайте уменьшить · щипок двумя пальцами
-graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}]
graph.param_a=A (вертикальный масштаб)
graph.param_k=k (горизонтальный масштаб)
graph.param_c=C (вертикальный сдвиг)
@@ -85,20 +83,28 @@ level.30=BC: фаза и гармонические колебания
level.31=BC: кубическая и точка перегиба
level.32=BC: b^x и d/dx b^x
level.33=Окружность: (x−h)² + (y−k)² = R²
-level.34=Aerospace: подъёмная сила C_L(α) линейно + срыв
-level.35=Aerospace: поляра сопротивления (паразит., индукт., суммарн.)
-level.36=Aerospace: изотерм. атмосфера ρ(h)
-level.37=Aerospace: фюгоид / затух. тангаж-высота
-level.38=Aerospace: ньютоновское Cp ~ sin²α
-level.39=Aerospace: Струхал / тон вихревой дорожки
-level.40=Aerospace: оболочка затухания при входе (ρV тепло)
-level.41=Экономика: пузырь dot-com и крах (стилиз. индекс)
-level.42=Экономика: кризис 2008 и восстановление (стилиз. индекс)
-level.43=БОСС: сечение убегания Мандельброта (фрактал)
-level.44=Физика C: термодинамика (адиабата P–V, γ из N)
-level.45=БОСС: золотая спираль (логарифмическая, полярная)
-level.46=Преобразования: Фурье — sinc-спектр
-level.47=Преобразования: Лаплас — затухание
-level.48=БОСС: Мандельброт — финал (фрактальный срез побега)
-level.49=БОСС: эффект бабочки Лоренца — финал (странный аттрактор)
+level.34=Физика C: термодинамика (адиабата P–V, γ из N)
+level.35=Aerospace: подъёмная сила C_L(α) линейно + срыв
+level.36=Aerospace: поляра сопротивления (паразит., индукт., суммарн.)
+level.37=Aerospace: изотерм. атмосфера ρ(h)
+level.38=Aerospace: фюгоид / затух. тангаж-высота
+level.39=Aerospace: ньютоновское Cp ~ sin²α
+level.40=Aerospace: Струхал / тон вихревой дорожки
+level.41=Aerospace: оболочка затухания при входе (ρV тепло)
+level.42=Экономика: пузырь dot-com и крах (стилиз. индекс)
+level.43=Экономика: кризис 2008 и восстановление (стилиз. индекс)
+level.44=Преобразования: Фурье — sinc-спектр
+level.45=Преобразования: Лаплас — затухание
+level.46=БОСС: золотая спираль (логарифмическая, полярная)
+level.47=БОСС: Мандельброт — финал (фрактальный срез побега)
+level.48=БОСС: аттрактор Лоренца — теория хаоса (странный аттрактор)
+level.49=БОСС: чёрная дыра — гравитационная яма (сечение 1/r)
level.50=Физика C: пружина–масса ГС (закон Гука, без затухания)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
diff --git a/First Principles/Assets/Resources/Localization/ur.txt b/First Principles/Assets/Resources/Localization/ur.txt
index e9c290f..982201c 100644
--- a/First Principles/Assets/Resources/Localization/ur.txt
+++ b/First Principles/Assets/Resources/Localization/ur.txt
@@ -13,9 +13,6 @@ ui.jump=چھلانگ
ui.move=حرکت
ui.keyboard_hint_mobile=(کی بورڈ: تیر / اسپیس)
hud.stage=اسٹیج
-controls.mobile=حرکت ◀ ▶ · چھلانگ تھپتھی (کی بورڈ: تیر / اسپیس)
-controls.desktop=حرکت ← → · چھلانگ اسپیس
-controls.calculator=گرافنگ کیلکولیٹر f(u) لکھیں · Trans · Scale · پنچ · واپس
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x) جب x>0 · min(x,3)...
graph.status_enter=Enter / گراف کے لیے باہر تھپتھپائیں
@@ -23,7 +20,7 @@ graph.status_graphed=گراف مکمل
graph.line1=گرافنگ کیلکولیٹر موڈ
graph.line2=f(u) نیچے لکھیں (باکس میں متغیر x = اندرونی u)۔ پھر:
graph.line3=Trans → {0} · + پر ڈبل-تھپتھی · − دبائے رکھیں · Scale زوم اندر / باہر دبائے رکھیں · دو انگلیوں سے پنچ
-graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}]
+graph.line4=A={0} k={1} C={2} D={3} x ∈ [{4},{5}]
graph.param_a=A (عمودی پیمانہ)
graph.param_k=k (افقی پیمانہ)
graph.param_c=C (عمودی بِدائل)
@@ -67,20 +64,28 @@ level.30=BC: مرحلہ اور SHM
level.31=BC: مکعب اور انفلیکشن
level.32=BC: b^x و d/dx b^x
level.33=دائرہ: (x−h)² + (y−k)² = R²
-level.34=ایرواسپیس: لفٹ C_L(α) + اسٹال
-level.35=ایرواسپیس: ڈریگ پولر (پیراسٹک، انڈیوسڈ، کل)
-level.36=ایرواسپیس: ہمحرارتی فضا ρ(h)
-level.37=ایرواسپیس: فیگوئڈ / ڈیمپڈ موڈ
-level.38=ایرواسپیس: نیوٹنی Cp ~ sin²α
-level.39=ایرواسپیس: اسٹروہل / وورٹیکس شیڈنگ
-level.40=ایرواسپیس: دوبارہ دخول زوال
-level.41=معیشت: ڈاٹ کام ببل اور حادثہ (اسٹائل شدہ انڈیکس)
-level.42=معیشت: 2008 بحران اور بحالی (اسٹائل شدہ انڈیکس)
-level.43=بوس: مینڈلبرو فرکٹل سلائس
-level.44=فزکس C: تھرموڈائنانمکس (ایڈیابیٹک P–V، γ از N)
-level.45=بوس: سنہری تناسب سنئلی (لوگ قطبی)
-level.46=تبدیل: فوریے — سینک سپیکٹرم
-level.47=تبدیل: لاپلاس — نماتی زوال
-level.48=بوس: مینڈلبرو — اختتام (فرکٹل فرار سلائس)
-level.49=بوس: لورینز تیتلی — اختتام (عجیب اٹریکٹر)
+level.34=فزکس C: تھرموڈائنانمکس (ایڈیابیٹک P–V، γ از N)
+level.35=ایرواسپیس: لفٹ C_L(α) + اسٹال
+level.36=ایرواسپیس: ڈریگ پولر (پیراسٹک، انڈیوسڈ، کل)
+level.37=ایرواسپیس: ہمحرارتی فضا ρ(h)
+level.38=ایرواسپیس: فیگوئڈ / ڈیمپڈ موڈ
+level.39=ایرواسپیس: نیوٹنی Cp ~ sin²α
+level.40=ایرواسپیس: اسٹروہل / وورٹیکس شیڈنگ
+level.41=ایرواسپیس: دوبارہ دخول زوال
+level.42=معیشت: ڈاٹ کام ببل اور حادثہ (اسٹائل شدہ انڈیکس)
+level.43=معیشت: 2008 بحران اور بحالی (اسٹائل شدہ انڈیکس)
+level.44=تبدیل: فوریے — سینک سپیکٹرم
+level.45=تبدیل: لاپلاس — نماتی زوال
+level.46=بوس: سنہری تناسب سنئلی (لوگ قطبی)
+level.47=بوس: مینڈلبرو — اختتام (فرکٹل فرار سلائس)
+level.48=بوس: لورینز اٹریکٹر — کیس تھیوری (عجیب اٹریکٹر)
+level.49=باس: بلیک ہول — کشش ثقل کنواں (1/r سلائس)
level.50=فزکس C: سپرنگ–عنصر جرم SHM (ہوک کا قانون، ڈیمپنگ کے بغیر)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
diff --git a/First Principles/Assets/Resources/Localization/zh.txt b/First Principles/Assets/Resources/Localization/zh.txt
index 6f990e4..83dcc99 100644
--- a/First Principles/Assets/Resources/Localization/zh.txt
+++ b/First Principles/Assets/Resources/Localization/zh.txt
@@ -12,9 +12,6 @@ ui.jump=跳跃
ui.move=移动
ui.keyboard_hint_mobile=(键盘:方向键 / 空格)
hud.stage=阶段
-controls.mobile=移动 ◀ ▶ · 跳跃 点按 (键盘:方向键 / 空格)
-controls.desktop=移动 ← → · 跳跃 空格
-controls.calculator=图形计算器 输入 f(u) · Trans · Scale · 双指缩放 · 返回
graph.label_fu=f(u) =
graph.placeholder=x^2 + sin(x) · ln(x)(x>0)· min(x,3)...
graph.status_enter=回车 / 点击外部绘制图象
@@ -22,7 +19,7 @@ graph.status_graphed=已绘制
graph.line1=图形计算器模式
graph.line2=在下方输入 f(u)(框内变量 x 为内层 u)。然后:
graph.line3=Trans → {0} · 双击 + · 长按 − · Scale 点按放大 / 长按缩小 · 双指 捏合
-graph.line4=A={0} k={1} C={2} D={3} x 在 [{4},{5}] 内
+graph.line4=A={0} k={1} C={2} D={3} x 在 [{4},{5}] 内
graph.param_a=A(纵向缩放)
graph.param_k=k(横向缩放)
graph.param_c=C(纵向平移)
@@ -65,20 +62,28 @@ level.30=BC:相位与简谐振动(能量)
level.31=BC:三次与拐点(作图)
level.32=BC:b^x 与 d/dx b^x
level.33=圆:(x−h)² + (y−k)² = R²
-level.34=航空:升力 C_L(α) 线性+失速
-level.35=航空:阻力极曲线(型阻·诱导·总阻)
-level.36=航空:等温大气 ρ(h)
-level.37=航空:起伏运动 / 阻尼俯仰-沉浮
-level.38=航空:牛顿流 Cp ~ sin²α
-level.39=航空:斯特劳哈尔 / 涡脱落音
-level.40=航空:再入衰减包络(ρV 加热)
-level.41=经济:互联网泡沫与崩盘(示意指数曲线)
-level.42=经济:2008 危机与复苏(示意指数曲线)
-level.43=BOSS:曼德博逃逸截面(分形)
-level.44=物理C:热力学(绝热P–V,γ由N给出)
-level.45=BOSS:黄金比例螺旋(对数极坐标)
-level.46=变换:傅里叶 — sinc 频谱
-level.47=变换:拉普拉斯 — 指数衰减
-level.48=BOSS:曼德博 — 终章(分形逃逸截面)
-level.49=BOSS:洛伦兹蝴蝶 — 终章(奇异吸引子)
+level.34=物理C:热力学(绝热P–V,γ由N给出)
+level.35=航空:升力 C_L(α) 线性+失速
+level.36=航空:阻力极曲线(型阻·诱导·总阻)
+level.37=航空:等温大气 ρ(h)
+level.38=航空:起伏运动 / 阻尼俯仰-沉浮
+level.39=航空:牛顿流 Cp ~ sin²α
+level.40=航空:斯特劳哈尔 / 涡脱落音
+level.41=航空:再入衰减包络(ρV 加热)
+level.42=经济:互联网泡沫与崩盘(示意指数曲线)
+level.43=经济:2008 危机与复苏(示意指数曲线)
+level.44=变换:傅里叶 — sinc 频谱
+level.45=变换:拉普拉斯 — 指数衰减
+level.46=BOSS:黄金比例螺旋(对数极坐标)
+level.47=BOSS:曼德博 — 终章(分形逃逸截面)
+level.48=BOSS:洛伦兹吸引子 — 混沌理论(奇异吸引子)
+level.49=BOSS:黑洞 — 引力势阱(1/r 切片)
level.50=物理C:弹簧–质点简谐振动(胡克定律,无阻尼)
+level.51=Big O: O(1) — constant time
+level.52=Big O: O(log n) — logarithmic growth
+level.53=Big O: O(√n) — sublinear root growth
+level.54=Big O: O(n) — linear growth
+level.55=Big O: O(n log n) — n log n growth
+level.56=Big O: O(n²) — quadratic growth
+level.57=Big O: O(n³) — cubic growth
+level.58=Big O: O(2ⁿ) — exponential (base 2)
diff --git a/First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader b/First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader
new file mode 100644
index 0000000..0a6dbbc
--- /dev/null
+++ b/First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader
@@ -0,0 +1,208 @@
+// GPU backdrop for the gravity-well boss: Schwarzschild equatorial null geodesics.
+// Math: photon Binet equation d²u/dφ² + u = 3 M u² with u = 1/r (G = c = 1).
+// First integral (conserved b = L/E): (du/dφ)² = (1−2Mu)²/b² − u² + 2M u³.
+// Ray is stepped in φ; emission samples a thin equatorial accretion disk (multiple passes = lensed images).
+// Not full Kerr (Gargantua is rotating); Schwarzschild is the documented GR core here.
+Shader "UI/BlackHoleGargantuaBackdrop"
+{
+ Properties
+ {
+ [PerRendererData] _MainTex ("Dummy", 2D) = "white" {}
+ _Color ("Multiply", Color) = (1, 1, 1, 0.78)
+ _Mass ("M (geometric units, Rs=2M)", Float) = 1
+ _CamDist ("Observer Schwarzschild r", Float) = 16
+ _BMin ("Impact param b min", Float) = 3.3
+ _BMax ("Impact param b max", Float) = 14
+ _DiskIn ("Disk inner r / M", Float) = 3.35
+ _DiskOut ("Disk outer r / M", Float) = 9
+ _DiskSpin ("Disk phase speed", Float) = 0.35
+ _DiskBright ("Disk emissivity", Float) = 2.4
+ _PhotonRing ("Photon ring boost", Float) = 1.15
+ _Dphi ("φ step (radians)", Float) = 0.045
+ _Steps ("Integration steps", Int) = 88
+ _Aspect ("UV width / height", Float) = 1.7
+ _TimeLive ("Time (set from C#)", Float) = 0
+ _StarField ("Star field strength", Float) = 0.085
+ }
+
+ SubShader
+ {
+ Tags
+ {
+ "Queue" = "Transparent"
+ "IgnoreProjector" = "True"
+ "RenderType" = "Transparent"
+ "PreviewType" = "Plane"
+ "CanUseSpriteAtlas" = "True"
+ }
+
+ ZWrite Off
+ ZTest Always
+ Blend SrcAlpha OneMinusSrcAlpha
+ Cull Off
+
+ Pass
+ {
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+ #pragma target 3.0
+ #include "UnityCG.cginc"
+
+ sampler2D _MainTex;
+ float4 _MainTex_ST;
+ float4 _Color;
+ float _Mass;
+ float _CamDist;
+ float _BMin;
+ float _BMax;
+ float _DiskIn;
+ float _DiskOut;
+ float _DiskSpin;
+ float _DiskBright;
+ float _PhotonRing;
+ float _Dphi;
+ int _Steps;
+ float _Aspect;
+ float _TimeLive;
+ float _StarField;
+
+ struct appdata
+ {
+ float4 vertex : POSITION;
+ float4 color : COLOR;
+ float2 texcoord : TEXCOORD0;
+ };
+
+ struct v2f
+ {
+ float4 vertex : SV_POSITION;
+ float4 color : COLOR;
+ float2 uv : TEXCOORD0;
+ };
+
+ v2f vert(appdata v)
+ {
+ v2f o;
+ o.vertex = UnityObjectToClipPos(v.vertex);
+ o.color = v.color;
+ o.uv = v.texcoord;
+ return o;
+ }
+
+ // Cheap hash for star speckle (not physical, background only).
+ float n2(float2 p)
+ {
+ return frac(sin(dot(p, float2(127.1, 311.7))) * 43758.5453);
+ }
+
+ void rk4Step(inout float u, inout float v, inout float phi, float M, float h)
+ {
+ float h2 = h * 0.5;
+ float k1u = v;
+ float k1v = 3.0 * M * u * u - u;
+ float u2 = u + h2 * k1u;
+ float v2 = v + h2 * k1v;
+ float k2u = v2;
+ float k2v = 3.0 * M * u2 * u2 - u2;
+ u2 = u + h2 * k2u;
+ v2 = v + h2 * k2v;
+ float k3u = v2;
+ float k3v = 3.0 * M * u2 * u2 - u2;
+ u2 = u + h * k3u;
+ v2 = v + h * k3v;
+ float k4u = v2;
+ float k4v = 3.0 * M * u2 * u2 - u2;
+ u += h * (k1u + 2.0 * k2u + 2.0 * k3u + k4u) / 6.0;
+ v += h * (k1v + 2.0 * k2v + 2.0 * k3v + k4v) / 6.0;
+ phi += h;
+ }
+
+ fixed4 frag(v2f i) : SV_Target
+ {
+ float2 uv = i.uv;
+ float M = max(_Mass, 0.05);
+ float Rs = 2.0 * M;
+ float rObs = max(_CamDist, Rs * 1.5);
+ float u = 1.0 / rObs;
+ float b = lerp(_BMin, _BMax, uv.x);
+ b = max(b, Rs * 1.01);
+ float fMu = 1.0 - 2.0 * M * u;
+ if (fMu <= 0.001)
+ return fixed4(0, 0, 0, _Color.a * i.color.a);
+
+ float disc = (1.0 / (b * b)) * fMu * fMu - u * u + 2.0 * M * u * u * u;
+ if (disc < 0.0)
+ disc = 0.0;
+ float v = sqrt(disc);
+ float vy = (uv.y - 0.5) * 2.2;
+ v *= 1.0 + vy * 0.18;
+
+ float phi = 0.0;
+ int steps = clamp(_Steps, 24, 128);
+ float h = max(_Dphi, 0.012);
+
+ float3 acc = float3(0, 0, 0);
+ float dIn = _DiskIn * M;
+ float dOut = _DiskOut * M;
+ float rPhIn = 2.95 * M;
+ float rPhOut = 3.15 * M;
+
+ for (int k = 0; k < 128; k++)
+ {
+ if (k >= steps)
+ break;
+
+ float r = 1.0 / max(u, 1e-5);
+ if (r < Rs + 0.015)
+ {
+ acc += float3(0, 0, 0.015);
+ break;
+ }
+
+ float x = r * cos(phi);
+ float z = r * sin(phi);
+ float rho = sqrt(x * x + z * z);
+
+ if (rho > dIn && rho < dOut)
+ {
+ float t = saturate((rho - dIn) / max(dOut - dIn, 1e-3));
+ float band = smoothstep(0.0, 0.08, t) * smoothstep(1.0, 0.92, t);
+ float spin = phi + _TimeLive * _DiskSpin;
+ float dop = 1.0 + 0.42 * sin(spin + uv.x * 6.28318);
+ dop *= 1.0 - 0.22 * sin(spin * 0.5 + vy * 3.14);
+ float3 hot = lerp(float3(1.0, 0.18, 0.02), float3(1.0, 0.55, 0.2), t);
+ hot = lerp(hot, float3(1.0, 0.85, 0.55), pow(t, 2.2));
+ acc += hot * band * dop * _DiskBright * h * 2.8;
+ }
+
+ if (rho > rPhIn && rho < rPhOut)
+ {
+ float pr = smoothstep(rPhIn, rPhIn + 0.04 * M, rho) * smoothstep(rPhOut, rPhOut - 0.04 * M, rho);
+ acc += float3(1.0, 0.95, 0.78) * pr * _PhotonRing * h * 0.45;
+ }
+
+ rk4Step(u, v, phi, M, h);
+
+ if (u < 0.0 || u > 200.0)
+ break;
+
+ if (u > 1.0 / max(Rs * 0.98, 1e-4))
+ break;
+ }
+
+ float2 suv = uv * float2(_Aspect * 120.0, 120.0);
+ float stars = pow(n2(floor(suv)), 12.0) * _StarField;
+ acc += float3(0.55, 0.62, 1.0) * stars;
+
+ float lum = max(max(acc.x, acc.y), acc.z);
+ acc = acc / (lum + 0.85);
+ fixed4 outc = fixed4(acc, _Color.a * i.color.a);
+ outc.rgb *= _Color.rgb * i.color.rgb;
+ return outc;
+ }
+ ENDCG
+ }
+ }
+ FallBack Off
+}
diff --git a/First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader.meta b/First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader.meta
new file mode 100644
index 0000000..10331f2
--- /dev/null
+++ b/First Principles/Assets/Resources/UI_BlackHoleGargantuaBackdrop.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 6fa2973b396514f74aff0c0946fabcf4
+ShaderImporter:
+ externalObjects: {}
+ defaultTextures: []
+ nonModifiableTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader b/First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader
new file mode 100644
index 0000000..0639d9f
--- /dev/null
+++ b/First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader
@@ -0,0 +1,121 @@
+// Procedural logarithmic spiral mood (golden ratio boss): φ-growth arms in polar view,
+// warm gold on deep field — matches r ∝ φ^{kθ} teaching language on the stage.
+Shader "UI/GoldenSpiralBackdrop"
+{
+ Properties
+ {
+ [PerRendererData] _MainTex ("Dummy", 2D) = "white" {}
+ _Color ("Tint & alpha", Color) = (1, 0.85, 0.45, 0.48)
+ _Aspect ("UV width / height", Float) = 1.7
+ _TimeLive ("Time", Float) = 0
+ }
+
+ SubShader
+ {
+ Tags
+ {
+ "Queue" = "Transparent"
+ "IgnoreProjector" = "True"
+ "RenderType" = "Transparent"
+ "PreviewType" = "Plane"
+ "CanUseSpriteAtlas" = "True"
+ }
+
+ ZWrite Off
+ ZTest Always
+ Blend SrcAlpha OneMinusSrcAlpha
+ Cull Off
+
+ Pass
+ {
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+ #include "UnityCG.cginc"
+
+ sampler2D _MainTex;
+ float4 _MainTex_ST;
+ float4 _Color;
+ float _Aspect;
+ float _TimeLive;
+
+ struct appdata
+ {
+ float4 vertex : POSITION;
+ float4 color : COLOR;
+ float2 texcoord : TEXCOORD0;
+ };
+
+ struct v2f
+ {
+ float4 vertex : SV_POSITION;
+ float4 color : COLOR;
+ float2 uv : TEXCOORD0;
+ };
+
+ v2f vert(appdata v)
+ {
+ v2f o;
+ o.vertex = UnityObjectToClipPos(v.vertex);
+ o.color = v.color;
+ o.uv = v.texcoord;
+ return o;
+ }
+
+ fixed4 frag(v2f i) : SV_Target
+ {
+ float2 uv = i.uv;
+ float asp = max(_Aspect, 0.25);
+ float2 p = (uv - 0.5) * 2.0;
+ p.x *= asp;
+
+ float r = length(p);
+ float ang = atan2(p.y, p.x);
+
+ // Golden ratio φ; log-spiral with one arm per 2π matches r ∝ φ^{θ/(2π)}.
+ float phi = 1.618033988749;
+ float twoPi = 6.28318530718;
+ float b = log(phi) / twoPi;
+
+ float t = _TimeLive * 0.22;
+
+ float phase1 = log(r + 0.07) - b * ang;
+ float spiral1 = abs(frac(phase1 * 2.15 + t * 0.045) - 0.5);
+
+ float phase2 = log(r + 0.09) - b * (ang + 2.399963); // ~ golden angle
+ float spiral2 = abs(frac(phase2 * 2.15 - t * 0.032) - 0.5);
+
+ float phase3 = log(r + 0.05) - b * (-ang + 0.73);
+ float spiral3 = abs(frac(phase3 * 1.85 + t * 0.028) - 0.5);
+
+ float arms =
+ smoothstep(0.13, 0.0, spiral1) +
+ smoothstep(0.13, 0.0, spiral2) * 0.72 +
+ smoothstep(0.11, 0.0, spiral3) * 0.45;
+
+ float radPhase = log(r + 0.04) / log(phi) * 2.8 + t * 0.06;
+ float rings = smoothstep(0.09, 0.0, abs(frac(radPhase) - 0.5)) * 0.35;
+
+ float vign = smoothstep(1.55, 0.28, r);
+ float core = smoothstep(0.02, 0.14, r);
+
+ float3 bgDeep = float3(0.05, 0.04, 0.1);
+ float3 bgWarm = float3(0.12, 0.07, 0.04);
+ float3 baseCol = lerp(bgDeep, bgWarm, saturate(r * 0.35 + uv.y * 0.25));
+
+ float3 goldHi = float3(1.0, 0.9, 0.42);
+ float3 goldMid = float3(0.92, 0.62, 0.22);
+ float3 glow = lerp(goldMid, goldHi, arms * 0.65 + rings * 0.4);
+
+ float intensity = (arms * 0.62 + rings * 0.28) * vign * (0.35 + 0.65 * core);
+ float3 col = baseCol + glow * intensity;
+
+ col = saturate(col);
+ float a = _Color.a * i.color.a;
+ return fixed4(col * _Color.rgb * i.color.rgb, a);
+ }
+ ENDCG
+ }
+ }
+ FallBack Off
+}
diff --git a/First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader.meta b/First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader.meta
new file mode 100644
index 0000000..b39048b
--- /dev/null
+++ b/First Principles/Assets/Resources/UI_GoldenSpiralBackdrop.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: a8e3c91d4f2b4069b7c5d8e1f3a2940b
+ShaderImporter:
+ externalObjects: {}
+ defaultTextures: []
+ nonModifiableTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader b/First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader
new file mode 100644
index 0000000..70dd08c
--- /dev/null
+++ b/First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader
@@ -0,0 +1,156 @@
+// Procedural wind-tunnel mood (aerospace stages): left→right freestream,
+// smoke/schlieren streaks, faint test-section grid, subtle symmetric airfoil silhouette.
+Shader "UI/WindTunnelBackdrop"
+{
+ Properties
+ {
+ [PerRendererData] _MainTex ("Dummy", 2D) = "white" {}
+ _Color ("Tint & alpha", Color) = (0.9, 0.96, 1, 0.54)
+ _FlowSpeed ("Flow speed", Float) = 0.55
+ _StreakScale ("Streak scale", Float) = 9
+ _Aspect ("UV width / height", Float) = 1.7
+ }
+
+ SubShader
+ {
+ Tags
+ {
+ "Queue" = "Transparent"
+ "IgnoreProjector" = "True"
+ "RenderType" = "Transparent"
+ "PreviewType" = "Plane"
+ "CanUseSpriteAtlas" = "True"
+ }
+
+ ZWrite Off
+ ZTest Always
+ Blend SrcAlpha OneMinusSrcAlpha
+ Cull Off
+
+ Pass
+ {
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+ #include "UnityCG.cginc"
+
+ sampler2D _MainTex;
+ float4 _MainTex_ST;
+ float4 _Color;
+ float _FlowSpeed;
+ float _StreakScale;
+ float _Aspect;
+
+ struct appdata
+ {
+ float4 vertex : POSITION;
+ float4 color : COLOR;
+ float2 texcoord : TEXCOORD0;
+ };
+
+ struct v2f
+ {
+ float4 vertex : SV_POSITION;
+ float4 color : COLOR;
+ float2 uv : TEXCOORD0;
+ };
+
+ v2f vert(appdata v)
+ {
+ v2f o;
+ o.vertex = UnityObjectToClipPos(v.vertex);
+ o.color = v.color;
+ o.uv = v.texcoord;
+ return o;
+ }
+
+ float hash21(float2 p)
+ {
+ float h = dot(p, float2(127.1, 311.7));
+ return frac(sin(h) * 43758.5453123);
+ }
+
+ float noise2(float2 p)
+ {
+ float2 i = floor(p);
+ float2 f = frac(p);
+ f = f * f * (3.0 - 2.0 * f);
+ float a = hash21(i);
+ float b = hash21(i + float2(1, 0));
+ float c = hash21(i + float2(0, 1));
+ float d = hash21(i + float2(1, 1));
+ return lerp(lerp(a, b, f.x), lerp(c, d, f.x), f.y);
+ }
+
+ float fbm(float2 p)
+ {
+ float s = 0.0;
+ float a = 0.5;
+ for (int k = 0; k < 5; k++)
+ {
+ s += a * noise2(p);
+ p *= 2.02;
+ a *= 0.5;
+ }
+ return s;
+ }
+
+ // Thin symmetric airfoil thickness (teaching shape): y_t(x) ~ semi-ellipse chord.
+ float airfoilThickness(float xNorm)
+ {
+ xNorm = abs(xNorm);
+ if (xNorm >= 1.0)
+ return 0.0;
+ return 0.18 * sqrt(1.0 - xNorm * xNorm);
+ }
+
+ fixed4 frag(v2f i) : SV_Target
+ {
+ float2 uv = i.uv;
+ float t = _Time.y * _FlowSpeed;
+ float asp = max(_Aspect, 0.25);
+
+ float2 p = (uv - 0.5) * 2.0;
+ p.x *= asp;
+
+ // Freestream along +x (wind enters from left of screen).
+ float2 flow = float2(uv.x * asp * _StreakScale * 0.35 + t * 0.9, uv.y * _StreakScale * 0.55);
+ float sm = fbm(flow);
+ float sm2 = fbm(flow * 1.6 + float2(3.1, -t * 0.4));
+
+ // Streaks: elongated along x.
+ float streak = pow(sm * sm2, 1.4);
+ streak *= smoothstep(0.15, 0.55, streak);
+
+ // Wake wobble behind nominal chord (x in p space ~ -0.2 to 0.5).
+ float chordX = p.x / 0.62;
+ float yt = airfoilThickness(chordX);
+ float distWing = abs(p.y) - yt;
+ float wingMask = 1.0 - smoothstep(-0.02, 0.06, distWing);
+ float wake = smoothstep(0.05, 0.45, p.x) * exp(-abs(p.y) * 2.2) * (1.0 - smoothstep(-0.35, 0.55, p.x));
+
+ float turbWake = fbm(float2(p.x * 4.0 - t * 1.2, p.y * 8.0 + sin(p.x * 6.0 + t))) * wake * 0.55;
+
+ // Test-section vertical rails (window frames).
+ float rail = smoothstep(0.02, 0.0, abs(uv.x - 0.08)) + smoothstep(0.02, 0.0, abs(uv.x - 0.92));
+ rail *= 0.15;
+
+ // Cool tunnel base gradient (floor darker) — slightly lifted for readability.
+ float3 baseCol = lerp(float3(0.06, 0.1, 0.15), float3(0.13, 0.18, 0.26), uv.y);
+ baseCol += float3(0.08, 0.12, 0.17) * (1.0 - uv.y) * rail;
+
+ float3 mist = float3(0.58, 0.76, 0.98) * streak * 0.72;
+ mist += float3(0.5, 0.66, 0.92) * turbWake * 1.12;
+ mist += float3(0.32, 0.42, 0.58) * wingMask * 0.16;
+
+ float3 col = baseCol + mist;
+ col = saturate(col);
+
+ float a = _Color.a * i.color.a;
+ return fixed4(col * _Color.rgb * i.color.rgb, a);
+ }
+ ENDCG
+ }
+ }
+ FallBack Off
+}
diff --git a/First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader.meta b/First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader.meta
new file mode 100644
index 0000000..2fb8240
--- /dev/null
+++ b/First Principles/Assets/Resources/UI_WindTunnelBackdrop.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 6426e7063d26b4ffbb3950a79360b1cc
+ShaderImporter:
+ externalObjects: {}
+ defaultTextures: []
+ nonModifiableTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/First Principles/Assets/Scenes/Game.unity b/First Principles/Assets/Scenes/Game.unity
index 24e72d6..333a2c6 100644
--- a/First Principles/Assets/Scenes/Game.unity
+++ b/First Principles/Assets/Scenes/Game.unity
@@ -2871,7 +2871,7 @@ MonoBehaviour:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.122641504, g: 0.122641504, b: 0.122641504, a: 1}
- m_RaycastTarget: 1
+ m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
diff --git a/First Principles/Assets/Scenes/Menu.unity b/First Principles/Assets/Scenes/Menu.unity
index d03d1c7..91d53c6 100644
--- a/First Principles/Assets/Scenes/Menu.unity
+++ b/First Principles/Assets/Scenes/Menu.unity
@@ -436,8 +436,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
- m_AnchoredPosition: {x: 0, y: -380}
- m_SizeDelta: {x: 964.3611, y: 110}
+ m_AnchoredPosition: {x: 0, y: -452}
+ m_SizeDelta: {x: 964.3611, y: 132}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1004057114
MonoBehaviour:
diff --git a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs
index e253d30..d4ebbb0 100644
--- a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs
+++ b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs
@@ -47,6 +47,9 @@ public class FunctionPlotter : MonoBehaviour
public bool differentiate = false;
+ [Tooltip("Level mode: wind-tunnel GPU backdrop (set from LevelDefinition for aerospace stages).")]
+ public bool showWindTunnelBackdrop = false;
+
[Tooltip("Level mode: vertically scale f and f′ so the band fits the grid (flat curves read clearly).")]
public bool autoScaleVertical = true;
@@ -57,6 +60,9 @@ public class FunctionPlotter : MonoBehaviour
[Tooltip("Level mode: horizontally scale the domain window [xStart,xEnd] so it fills most of the grid.")]
public bool autoScaleHorizontal = true;
+ [Tooltip("Graphing calculator: match vertical scale to horizontal zoom so one grid column and one row span the same plotter x/y units (pinch/Scale zoom x and y together). Ignored for polar plot styles.")]
+ public bool lockVerticalPlotScaleToHorizontalWindow = false;
+
[Tooltip("Fraction of half the grid width (from center) used by the fitted x-window.")]
[Range(0.38f, 0.92f)]
public float horizontalFillFraction = 0.74f;
@@ -131,7 +137,12 @@ void UpdateGraphRevealAnimation()
}
float dur = Mathf.Max(0.05f, graphRevealDurationSeconds);
- _graphRevealT01 = Mathf.MoveTowards(_graphRevealT01, 1f, Time.deltaTime / dur);
+ // Lorenz / chaos-theory stage already animates via _lorenzPhaseScroll; horizontal alpha reveal uses grid-x and
+ // can zero the whole polyline when revealX sits on gx0 (progress 0 → all vertices faded).
+ if (functionType == FunctionType.ChaosLorenzButterflyX)
+ _graphRevealT01 = 1f;
+ else
+ _graphRevealT01 = Mathf.MoveTowards(_graphRevealT01, 1f, Time.deltaTime / dur);
if (functionType == FunctionType.ChaosLorenzButterflyX)
{
@@ -145,7 +156,8 @@ int ComputeGraphRevealParamsHash()
{
int a = HashCode.Combine(functionType, xStart, xEnd, step, transA, transK);
int b = HashCode.Combine(transC, transD, power, baseN, customExpression ?? "");
- int c = HashCode.Combine(autoScaleVertical, autoScaleHorizontal, verticalFillFraction, horizontalFillFraction);
+ int c = HashCode.Combine(autoScaleVertical, autoScaleHorizontal, lockVerticalPlotScaleToHorizontalWindow,
+ verticalFillFraction, horizontalFillFraction);
return HashCode.Combine(a, b, c);
}
@@ -158,16 +170,17 @@ void PushGraphRevealToRenderers()
float gx0 = MapDisplayX(xStart) + go.x;
float gx1 = MapDisplayX(xEnd) + go.x;
- lineRenderer.SetGraphRevealFade(_graphRevealT01, gx0, gx1);
+ float revealT = functionType == FunctionType.ChaosLorenzButterflyX ? 1f : _graphRevealT01;
+ lineRenderer.SetGraphRevealFade(revealT, gx0, gx1);
if (derivRenderer != null)
- derivRenderer.SetGraphRevealFade(_graphRevealT01, gx0, gx1);
+ derivRenderer.SetGraphRevealFade(revealT, gx0, gx1);
if (functionType == FunctionType.AeroDragPolarTriple)
{
if (overlayParasitic != null)
- overlayParasitic.SetGraphRevealFade(_graphRevealT01, gx0, gx1);
+ overlayParasitic.SetGraphRevealFade(revealT, gx0, gx1);
if (overlayInduced != null)
- overlayInduced.SetGraphRevealFade(_graphRevealT01, gx0, gx1);
+ overlayInduced.SetGraphRevealFade(revealT, gx0, gx1);
}
}
@@ -177,7 +190,8 @@ public void ApplyGraphRevealToLineRenderer(LineRendererUI lr)
if (lr == null || lineRenderer == null)
return;
Vector2Int go = lineRenderer.gridSize / 2;
- lr.SetGraphRevealFade(_graphRevealT01, MapDisplayX(xStart) + go.x, MapDisplayX(xEnd) + go.x);
+ float revealT = functionType == FunctionType.ChaosLorenzButterflyX ? 1f : _graphRevealT01;
+ lr.SetGraphRevealFade(revealT, MapDisplayX(xStart) + go.x, MapDisplayX(xEnd) + go.x);
}
public void InitPlotFunction()
@@ -194,6 +208,8 @@ public void RefreshLine()
public void RefreshDeriv()
{
+ if (derivRenderer == null)
+ return;
derivRenderer.enabled = false;
derivRenderer.enabled = true;
}
@@ -331,6 +347,13 @@ private void PlotFunction(FunctionType type)
lineRenderer = LineRendererUI.FindPrimaryCurve();
derivRenderer = FindAnyObjectByType();
+ // Lorenz: disable per-vertex horizontal fade (see UpdateGraphRevealAnimation); derivative uses same flag.
+ bool lorenzButterfly = type == FunctionType.ChaosLorenzButterflyX;
+ if (lineRenderer != null)
+ lineRenderer.enableHorizontalGraphReveal = !lorenzButterfly;
+ if (derivRenderer != null)
+ derivRenderer.enableHorizontalGraphReveal = !lorenzButterfly;
+
if (lineRenderer != null)
{
points.Clear();
@@ -368,16 +391,23 @@ private void PlotFunction(FunctionType type)
else if (differentiate == false)
{
dPoints.Clear();
-
- // Refresh ONLY the derivative graph & hide on the UI
- RefreshDeriv();
+ // Do not call RefreshDeriv() here — it re-enabled the Graphic every frame while stale
+ // points could remain on DerivRendererUI (list is only aliased to dPoints when differentiate is true).
+ if (derivRenderer != null)
+ {
+ derivRenderer.points.Clear();
+ derivRenderer.enabled = false;
+ }
}
- // Boss: show classic Mandelbrot set in c-plane behind the grid (1D slice curve on top).
+ // Stage backdrops: Mandelbrot; black hole; golden φ-spiral; wind tunnel (aerospace).
if (lineRenderer != null)
{
var gridRt = lineRenderer.transform.parent as RectTransform;
MandelbrotFractalBackdrop.Sync(gridRt, this);
+ BlackHoleGargantuaBackdrop.Sync(gridRt, this);
+ GoldenSpiralBackdrop.Sync(gridRt, this);
+ WindTunnelBackdrop.Sync(gridRt, this);
PushGraphRevealToRenderers();
}
}
@@ -402,6 +432,12 @@ public void ComputeGraph(FunctionType functionType, float transA, float transK,
ComputeVerticalAutoFit(lineRenderer.gridSize.y, fLo, fHi);
ComputeHorizontalAutoFit(lineRenderer.gridSize.x, xStart, xEnd);
+ if (lockVerticalPlotScaleToHorizontalWindow && !IsPolarPlotStyle(functionType))
+ {
+ _autoMid = 0f;
+ _autoScale = _autoScaleX;
+ }
+
// --- Pass 2: build polylines with display mapping ---
for (float i = xStart; i <= xEnd; i += step)
{
@@ -577,9 +613,15 @@ private float EvaluateFunctionY(FunctionType type, float transA, float transK, f
FunctionType.TransformFourierSinc => TransformFourierSincY(u, transA, transC),
FunctionType.TransformLaplaceCausalDecay => TransformLaplaceCausalDecayY(u, transA, transC, baseN),
- // Final boss: Lorenz x(t) slice (normalized), “butterfly” chaotic sensitivity.
+ // Final boss: Lorenz x(t) slice (normalized); chaos theory / sensitive dependence.
FunctionType.ChaosLorenzButterflyX => ChaosLorenzButterflyYEval(u, transA, transC),
+ // Boss: Newtonian-style potential slice Φ ∝ −1/√(r²+ε²) (softened 1/r “gravity well”).
+ FunctionType.PhysicsGravityWellInverseSqrt => GravityWellInverseSqrtY(u, transA, transC, transD),
+
+ // CS / algorithms: growth shape n ln n for n>0 (u plays the role of n on the horizontal axis).
+ FunctionType.BigONLogN => BigONLogNY(u, transA, transC),
+
_ => 0f
};
}
@@ -729,6 +771,19 @@ float ChaosLorenzButterflyYEval(float u, float a, float c)
return a * LorenzAttractorSamples.SampleNormalizedX(t) + c;
}
+ static float GravityWellInverseSqrtY(float u, float a, float c, float softFromD)
+ {
+ float eps = Mathf.Max(0.08f, Mathf.Abs(softFromD));
+ float r2 = u * u + eps * eps;
+ return a * (-1f / Mathf.Sqrt(r2)) + c;
+ }
+
+ static float BigONLogNY(float u, float a, float c)
+ {
+ float n = Mathf.Max(u, 0.02f);
+ return a * (n * Mathf.Log(n)) + c;
+ }
+
/// y = k + √(R² − u²) for |u|≤R; outside domain uses k so samples stay finite (flat shoulder).
private static float CircleUpperY(float u, float radiusSigned, float k)
{
@@ -1012,9 +1067,19 @@ private void UpdateEquationText(FunctionType type, float transA, float transK, f
}
case FunctionType.ChaosLorenzButterflyX:
equationText.text =
- $@"\(\text{{Butterfly effect}}\) — Lorenz \(x(t)\), \(\sigma=10,\rho=28,\beta=8/3\), \(u={k}(x-{d})\approx t\)\n" +
+ $@"\(\text{{Chaos theory}}\) — Lorenz \(x(t)\), \(\sigma=10,\rho=28,\beta=8/3\), \(u={k}(x-{d})\approx t\)\n" +
$@"Tiny initial changes diverge on the attractor — this curve is a time slice of that chaos, normalized to read on the grid.";
break;
+ case FunctionType.PhysicsGravityWellInverseSqrt:
+ equationText.text =
+ $@"\(\text{{Gravity well}}\) slice \(f \propto -1/\sqrt{{u^{2}+\varepsilon^{2}}}+C,\; u={k}(x-{d}),\; \varepsilon\sim |{d}|\)\n" +
+ $@"Softened \(1/r\) potential — steep near the center, flattens away; a readable stand-in for “falling into” a deep well.";
+ break;
+ case FunctionType.BigONLogN:
+ equationText.text =
+ $@"\(O(n\log n)\) growth mood: \(f \propto u\ln u + C,\; u=\max({k}(x-{d}),\text{{small}})\)\n" +
+ $@"Classic merge-sort / balanced-tree flavor: work grows a bit faster than linear, slower than quadratic.";
+ break;
case FunctionType.CustomExpression:
{
string esc = EscapeTmpRichText(customExpression);
@@ -1188,8 +1253,14 @@ public enum FunctionType
/// Causal \(H(t)\,e^{-st}\) — Laplace-table exponential decay for \(t\ge 0\); \(s\sim \texttt{baseN}/100\).
TransformLaplaceCausalDecay,
- /// Final boss: Lorenz attractor \(x(t)\) (normalized), butterfly / sensitive dependence visualization.
- ChaosLorenzButterflyX
+ /// Final boss: Lorenz attractor \(x(t)\) (normalized); chaos theory / sensitive dependence visualization.
+ ChaosLorenzButterflyX,
+
+ /// Boss: softened \(1/r\) gravitational potential slice (deep well at \(u=0\)).
+ PhysicsGravityWellInverseSqrt,
+
+ /// CS: \(O(n\log n)\) growth shape via \(u\ln u\) (positive branch).
+ BigONLogN
}
/*
diff --git a/First Principles/Assets/Scripts/Game/DerivativePopAnimator.cs b/First Principles/Assets/Scripts/Game/DerivativePopAnimator.cs
index e42e80e..705b8c6 100644
--- a/First Principles/Assets/Scripts/Game/DerivativePopAnimator.cs
+++ b/First Principles/Assets/Scripts/Game/DerivativePopAnimator.cs
@@ -14,17 +14,23 @@ public class DerivativePopAnimator : MonoBehaviour
[SerializeField] private float thicknessMultiplier = 1.8f;
[SerializeField] private float popDurationSeconds = 0.25f;
- private float baseThickness;
- private Color baseColor;
+ ///
+ /// Baseline stroke width for f′ (not the momentary boosted value). Stopping a pop mid-animation used to leave
+ /// elevated; the next pop then multiplied that again — runaway “thick line”.
+ ///
+ private float _restThickness = DerivRendererUI.DefaultThicknessPixels;
public void SetTarget(DerivRendererUI target)
{
this.target = target;
- if (this.target != null)
- {
- baseThickness = this.target.thickness;
- baseColor = this.target.color;
- }
+ SyncRestThicknessFromTarget();
+ }
+
+ /// Call after resetting on level load / theme apply.
+ public void SyncRestThicknessFromTarget()
+ {
+ if (target != null)
+ _restThickness = Mathf.Max(0.25f, target.thickness);
}
public void Pop(Color popColor)
@@ -33,7 +39,12 @@ public void Pop(Color popColor)
return;
if (popRoutine != null)
+ {
StopCoroutine(popRoutine);
+ popRoutine = null;
+ // Interrupted mid-pulse — snap back so the next pop does not compound thickness.
+ target.thickness = _restThickness;
+ }
popRoutine = StartCoroutine(PopRoutine(popColor));
}
@@ -42,16 +53,16 @@ private IEnumerator PopRoutine(Color popColor)
{
float elapsed = 0f;
- baseThickness = target.thickness;
- baseColor = target.color;
+ Color colorBeforePop = target.color;
Color c = popColor;
if (c.a <= 0f)
c.a = 1f;
target.color = c;
- float startThickness = baseThickness;
- float endThickness = baseThickness * thicknessMultiplier;
+ float restT = _restThickness;
+ float startThickness = restT;
+ float endThickness = restT * thicknessMultiplier;
while (elapsed < popDurationSeconds * 0.5f)
{
@@ -67,12 +78,16 @@ private IEnumerator PopRoutine(Color popColor)
{
settleT += Time.deltaTime;
float t = Mathf.Clamp01(settleT / (popDurationSeconds * 0.5f));
- target.thickness = Mathf.Lerp(fromThickness, startThickness, t);
+ target.thickness = Mathf.Lerp(fromThickness, restT, t);
yield return null;
}
+ target.thickness = restT;
+
var restored = target.color;
- restored.a = baseColor.a;
+ restored.a = colorBeforePop.a;
target.color = restored;
+
+ popRoutine = null;
}
}
diff --git a/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs b/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs
index 0c01328..d856e7c 100644
--- a/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs
+++ b/First Principles/Assets/Scripts/Game/GameLevelCatalog.cs
@@ -69,6 +69,7 @@ public static class GameLevelCatalog
"BC: cubic & inflection (sketching)",
"BC: b^x & d/dx b^x",
"Circle: (x−h)² + (y−k)² = R²",
+ "Physics C: thermodynamics (adiabatic P–V, γ from N)",
// --- Aerospace engineering & aerodynamics (order must match LevelManager.BuildSampleLevels) ---
"Aerospace: lift C_L(α) linear + stall",
"Aerospace: drag polar (parasitic, induced, total)",
@@ -79,18 +80,33 @@ public static class GameLevelCatalog
"Aerospace: re-entry decay envelope (ρV heating mood)",
"Economics: dot-com bubble & crash (stylized index)",
"Economics: 2008 crisis & recovery (stylized index)",
- "BOSS: Mandelbrot escape slice (fractal boundary mood)",
- "Physics C: thermodynamics (adiabatic P–V, γ from N)",
- "BOSS: golden ratio spiral (logarithmic polar)",
"Transforms: Fourier — sinc spectrum (rect ↔ sinc)",
"Transforms: Laplace — causal exponential decay",
+ "BOSS: golden ratio spiral (logarithmic polar)",
"BOSS: Mandelbrot — finale (fractal escape slice)",
- "BOSS: Lorenz butterfly — finale (strange attractor)",
- "Physics C: spring–mass SHM (Hooke's law, undamped)"
+ "BOSS: Lorenz attractor — Chaos Theory (strange attractor)",
+ "BOSS: Black hole — gravity well (1/r slice)",
+ "Physics C: spring–mass SHM (Hooke's law, undamped)",
+ "Big O: O(1) — constant time",
+ "Big O: O(log n) — logarithmic growth",
+ "Big O: O(√n) — sublinear root growth",
+ "Big O: O(n) — linear growth",
+ "Big O: O(n log n) — n log n growth",
+ "Big O: O(n²) — quadratic growth",
+ "Big O: O(n³) — cubic growth",
+ "Big O: O(2ⁿ) — exponential (base 2)",
+ // Placeholder: listed in Level Select but not built in LevelManager yet (see IsComingSoonLevel).
+ "Astrophysics: Hohmann transfer"
};
public static int LevelCount => DisplayNames.Length;
+ /// Level index reserved for a future stage; shows “coming soon” instead of loading Game.
+ public const int HohmannTransferComingSoonLevelIndex = 59;
+
+ public static bool IsComingSoonLevel(int index) =>
+ index == HohmannTransferComingSoonLevelIndex;
+
///
/// Grouped picker on the Level Select scene (indices must match / ).
///
@@ -99,19 +115,21 @@ public static class GameLevelCatalog
new LevelSelectCategory("level_select.cat.core", "Core & series", 0, 8),
new LevelSelectCategory("level_select.cat.integration", "Multivar & integration", 9, 13),
new LevelSelectCategory("level_select.cat.engineering", "Engineering", 14, 16),
- new LevelSelectCategory("level_select.cat.ap_bc", "AP Calculus BC & Physics C", 17, 33),
- new LevelSelectCategory("level_select.cat.aerospace", "Aerospace", 34, 40),
- new LevelSelectCategory("level_select.cat.finale", "Advanced & boss", 41, 45),
- new LevelSelectCategory("level_select.cat.transforms", "Transforms", 46, 47),
- new LevelSelectCategory("level_select.cat.final_boss", "Final boss", 48, 49),
+ new LevelSelectCategory("level_select.cat.ap_bc", "AP Calculus BC & Physics C", 17, 34),
+ new LevelSelectCategory("level_select.cat.aerospace", "Aerospace", 35, 41),
+ new LevelSelectCategory("level_select.cat.astrophysics", "Astrophysics", 59, 59),
+ new LevelSelectCategory("level_select.cat.economics", "Economics", 42, 43),
+ new LevelSelectCategory("level_select.cat.transforms", "Transforms", 44, 45),
new LevelSelectCategory("level_select.cat.spring_physics", "Spring & SHM", 50, 50),
+ new LevelSelectCategory("level_select.cat.big_o", "Big O notation", 51, 58),
+ new LevelSelectCategory("level_select.cat.final_boss", "Final boss", 46, 49),
};
/// First index of the contiguous Aerospace: block (must match sample levels).
- public const int AerospaceLevelsBeginIndex = 34;
+ public const int AerospaceLevelsBeginIndex = 35;
/// Inclusive last index of the Aerospace block (re-entry stage).
- public const int AerospaceLevelsEndIndex = 40;
+ public const int AerospaceLevelsEndIndex = 41;
/// True for levels whose titles start with Aerospace: in the catalog.
public static bool IsAerospaceLevel(int index) =>
diff --git a/First Principles/Assets/Scripts/Game/GameplayViewportBounds.cs b/First Principles/Assets/Scripts/Game/GameplayViewportBounds.cs
index 4a88c1b..36c59c0 100644
--- a/First Principles/Assets/Scripts/Game/GameplayViewportBounds.cs
+++ b/First Principles/Assets/Scripts/Game/GameplayViewportBounds.cs
@@ -42,11 +42,21 @@ public static GameplayPlayBounds Compute(RectTransform cartesianPlane, Vector2In
? Mathf.Max(16f, w * 0.022f)
: Mathf.Max(10f, w * 0.018f);
+ // Narrow portrait: reserve a bit more side margin so the playfield matches the visibly inset graph.
+ float aspectTall = h / Mathf.Max(1f, w);
+ if (!DeviceLayout.IsTabletLike() && aspectTall > 1.45f)
+ hPad = Mathf.Max(hPad, w * 0.026f);
+
float topPad = Mathf.Max(44f, h * 0.065f);
float bottomPad = Mathf.Max(12f, h * 0.022f);
if (DeviceLayout.PreferOnScreenGameControls)
- bottomPad = Mathf.Max(bottomPad, DeviceLayout.TouchControlBarHeight + 36f);
+ {
+ if (DeviceLayout.GameplayUsesFullScreenTouchZones)
+ bottomPad = Mathf.Max(bottomPad, 28f);
+ else
+ bottomPad = Mathf.Max(bottomPad, DeviceLayout.TouchControlBarHeight + 36f);
+ }
float xMin = hPad / unitX;
float xMax = gridSize.x - hPad / unitX;
diff --git a/First Principles/Assets/Scripts/Game/GraphCalculatorAnalysisControls.cs b/First Principles/Assets/Scripts/Game/GraphCalculatorAnalysisControls.cs
index 19d4463..4b3afae 100644
--- a/First Principles/Assets/Scripts/Game/GraphCalculatorAnalysisControls.cs
+++ b/First Principles/Assets/Scripts/Game/GraphCalculatorAnalysisControls.cs
@@ -107,7 +107,7 @@ void LateUpdate()
&& (!Mathf.Approximately(integralCachedXStart, plotter.xStart)
|| !Mathf.Approximately(integralCachedXEnd, plotter.xEnd)))
{
- riemann.RebuildForGraphingCalculator(plotter, RiemannRectCount, RiemannRule.Midpoint, CalculatorRiemannFill);
+ riemann.RebuildForGraphingCalculator(plotter, primaryCurve, RiemannRectCount, RiemannRule.Midpoint, CalculatorRiemannFill);
integralCachedXStart = plotter.xStart;
integralCachedXEnd = plotter.xEnd;
if (primaryCurve.transform.parent != null)
@@ -168,7 +168,7 @@ void OnIntegralPressed()
integralBarsActive = true;
RefreshButtonInteractable();
- riemann.RebuildForGraphingCalculator(plotter, RiemannRectCount, RiemannRule.Midpoint, CalculatorRiemannFill);
+ riemann.RebuildForGraphingCalculator(plotter, primaryCurve, RiemannRectCount, RiemannRule.Midpoint, CalculatorRiemannFill);
integralCachedXStart = plotter.xStart;
integralCachedXEnd = plotter.xEnd;
if (primaryCurve != null && primaryCurve.transform.parent != null)
@@ -340,4 +340,15 @@ void DestroyUiButtons()
derivButton = null;
integralButton = null;
}
+
+ ///
+ /// Top edge of the Deriv / ∫ row in the same bottom‑anchored space as
+ /// (anchoredPosition.y + button height).
+ ///
+ public static float DerivativeIntegralRowTopFromBottom(float transRowBottomY, bool tablet)
+ {
+ float h = tablet ? 108f : 100f;
+ float row2Bottom = transRowBottomY + h + 10f;
+ return row2Bottom + h * 0.92f;
+ }
}
diff --git a/First Principles/Assets/Scripts/Game/GraphCalculatorEquationPanel.cs b/First Principles/Assets/Scripts/Game/GraphCalculatorEquationPanel.cs
index 2e4c23b..56e4c36 100644
--- a/First Principles/Assets/Scripts/Game/GraphCalculatorEquationPanel.cs
+++ b/First Principles/Assets/Scripts/Game/GraphCalculatorEquationPanel.cs
@@ -8,14 +8,18 @@
///
public static class GraphCalculatorEquationPanel
{
- private const string RootName = "GraphicCalculatorEquationRoot";
+ public const string EquationRootObjectName = "GraphicCalculatorEquationRoot";
+ private const string RootName = EquationRootObjectName;
private const string LegacyRootName = "FaxasEquationInputRoot";
private static TextMeshProUGUI labelTmp;
private static TextMeshProUGUI placeholderTmp;
private static TextMeshProUGUI statusTmp;
- public static void Ensure(RectTransform parent, FunctionPlotter plotter, TextMeshProUGUI typographyReference, float bottomY, float panelHeight)
+ /// When is null: anchored Y from bottom of parent (legacy placement).
+ /// When set: panel is top-anchored directly under this banner (graphing calculator).
+ public static void Ensure(RectTransform parent, FunctionPlotter plotter, TextMeshProUGUI typographyReference, float bottomY, float panelHeight,
+ RectTransform layoutBelowStory = null, float gapBelowStory = 10f)
{
if (parent == null || plotter == null)
return;
@@ -24,6 +28,11 @@ public static void Ensure(RectTransform parent, FunctionPlotter plotter, TextMes
if (existing != null)
{
ApplyEquationPanelFontAndWeight(existing, typographyReference, plotter);
+ var ert = existing.GetComponent();
+ if (layoutBelowStory != null)
+ ApplyEquationPanelLayoutBelowStory(ert, layoutBelowStory, gapBelowStory, panelHeight);
+ else
+ ApplyEquationPanelBottomLayout(ert, parent, bottomY, panelHeight);
return;
}
@@ -32,6 +41,11 @@ public static void Ensure(RectTransform parent, FunctionPlotter plotter, TextMes
{
legacyRoot.name = RootName;
ApplyEquationPanelFontAndWeight(legacyRoot, typographyReference, plotter);
+ var legacyRt = legacyRoot.GetComponent();
+ if (layoutBelowStory != null)
+ ApplyEquationPanelLayoutBelowStory(legacyRt, layoutBelowStory, gapBelowStory, panelHeight);
+ else
+ ApplyEquationPanelBottomLayout(legacyRt, parent, bottomY, panelHeight);
return;
}
@@ -40,12 +54,17 @@ public static void Ensure(RectTransform parent, FunctionPlotter plotter, TextMes
var root = new GameObject(RootName);
var rt = root.AddComponent();
- rt.SetParent(parent, false);
- rt.anchorMin = new Vector2(0.5f, 0f);
- rt.anchorMax = new Vector2(0.5f, 0f);
- rt.pivot = new Vector2(0.5f, 0f);
- rt.anchoredPosition = new Vector2(0f, bottomY);
- rt.sizeDelta = new Vector2(w, panelHeight);
+ rt.SetParent(layoutBelowStory != null ? layoutBelowStory.parent : parent, false);
+ if (layoutBelowStory != null)
+ ApplyEquationPanelLayoutBelowStory(rt, layoutBelowStory, gapBelowStory, panelHeight);
+ else
+ {
+ rt.anchorMin = new Vector2(0.5f, 0f);
+ rt.anchorMax = new Vector2(0.5f, 0f);
+ rt.pivot = new Vector2(0.5f, 0f);
+ rt.anchoredPosition = new Vector2(0f, bottomY);
+ rt.sizeDelta = new Vector2(w, panelHeight);
+ }
var bg = root.AddComponent();
RuntimeUiPolish.UseRoundedSliced(bg);
@@ -53,13 +72,13 @@ public static void Ensure(RectTransform parent, FunctionPlotter plotter, TextMes
bg.raycastTarget = true;
var labelGo = new GameObject("Label");
- var lrt = labelGo.AddComponent();
- lrt.SetParent(rt, false);
- lrt.anchorMin = new Vector2(0f, 1f);
- lrt.anchorMax = new Vector2(0f, 1f);
- lrt.pivot = new Vector2(0f, 1f);
- lrt.anchoredPosition = new Vector2(tablet ? 16f : 12f, -6f);
- lrt.sizeDelta = new Vector2(220f, 28f);
+ var labelRt = labelGo.AddComponent();
+ labelRt.SetParent(rt, false);
+ labelRt.anchorMin = new Vector2(0f, 1f);
+ labelRt.anchorMax = new Vector2(0f, 1f);
+ labelRt.pivot = new Vector2(0f, 1f);
+ labelRt.anchoredPosition = new Vector2(tablet ? 16f : 12f, -6f);
+ labelRt.sizeDelta = new Vector2(220f, 28f);
var label = labelGo.AddComponent();
label.text = LocalizationManager.Get("graph.label_fu", "f(u) =");
label.fontSize = UiTypography.Scale(tablet ? 26 : 24);
@@ -266,4 +285,34 @@ static void ApplyStatusHintLayoutAndSize(TextMeshProUGUI status, RectTransform s
srt.sizeDelta = new Vector2(-24f, 28f);
}
}
+
+ /// Top-anchored panel flush under the intro banner (same horizontal stretch as ).
+ static void ApplyEquationPanelLayoutBelowStory(RectTransform eqRt, RectTransform storyRt, float gap, float panelHeight)
+ {
+ if (eqRt == null || storyRt == null)
+ return;
+
+ eqRt.SetParent(storyRt.parent, false);
+ eqRt.anchorMin = storyRt.anchorMin;
+ eqRt.anchorMax = storyRt.anchorMax;
+ eqRt.pivot = new Vector2(0.5f, 1f);
+ eqRt.sizeDelta = new Vector2(0f, panelHeight);
+ float storyH = storyRt.sizeDelta.y;
+ eqRt.anchoredPosition = new Vector2(storyRt.anchoredPosition.x, storyRt.anchoredPosition.y - storyH - gap);
+ }
+
+ static void ApplyEquationPanelBottomLayout(RectTransform eqRt, RectTransform parent, float bottomY, float panelHeight)
+ {
+ if (eqRt == null || parent == null)
+ return;
+
+ bool tablet = DeviceLayout.IsTabletLike();
+ float w = tablet ? 980f : 900f;
+ eqRt.SetParent(parent, false);
+ eqRt.anchorMin = new Vector2(0.5f, 0f);
+ eqRt.anchorMax = new Vector2(0.5f, 0f);
+ eqRt.pivot = new Vector2(0.5f, 0f);
+ eqRt.anchoredPosition = new Vector2(0f, bottomY);
+ eqRt.sizeDelta = new Vector2(w, panelHeight);
+ }
}
diff --git a/First Principles/Assets/Scripts/Game/GraphCalculatorToolbar.cs b/First Principles/Assets/Scripts/Game/GraphCalculatorToolbar.cs
index b7d2402..8fdf9d2 100644
--- a/First Principles/Assets/Scripts/Game/GraphCalculatorToolbar.cs
+++ b/First Principles/Assets/Scripts/Game/GraphCalculatorToolbar.cs
@@ -128,6 +128,10 @@ private void ApplyZoomWindow(float halfWidthMultiplier)
plot.xStart = mid - half;
plot.xEnd = mid + half;
plot.step = Mathf.Clamp((plot.xEnd - plot.xStart) / 480f, 0.004f, 0.42f);
+ plot.InitPlotFunction();
+ var lm = FindAnyObjectByType();
+ if (lm != null)
+ lm.RefreshAllTickLabels();
}
private void RefreshHint()
@@ -164,9 +168,9 @@ private void RefreshHint()
float th1 = plot.transK * (plot.xEnd - plot.transD);
string line4Fmt = polar
? LocalizationManager.Get("graph.polar.line4",
- "A={0} k={1} C={2} D={3} θ∈[{4},{5}]")
+ "A={0} k={1} C={2} D={3} θ∈[{4},{5}]")
: LocalizationManager.Get("graph.line4",
- "A={0} k={1} C={2} D={3} x∈[{4},{5}]");
+ "A={0} k={1} C={2} D={3} x∈[{4},{5}]");
string line4 = polar
? string.Format(line4Fmt,
plot.transA.ToString("0.##"),
diff --git a/First Principles/Assets/Scripts/Game/GraphObstacleGenerator.cs b/First Principles/Assets/Scripts/Game/GraphObstacleGenerator.cs
index 3312a34..3a89be4 100644
--- a/First Principles/Assets/Scripts/Game/GraphObstacleGenerator.cs
+++ b/First Principles/Assets/Scripts/Game/GraphObstacleGenerator.cs
@@ -43,6 +43,36 @@ public class GraphWorld
/// When true, keeps the avatar inside horizontally and uses them for fall death.
public bool hasPlayBounds;
public GameplayPlayBounds playBounds;
+
+ /// Call after is recomputed (e.g. rotation) so the exit band stays in the padded region.
+ public void RefreshFinishFromPlayBounds()
+ {
+ if (!hasPlayBounds)
+ return;
+ const float finishWidth = 1f;
+ var b = playBounds;
+ finish = new GridRect(Mathf.Max(b.XMax - finishWidth, b.XMin), b.XMax, b.YMin, b.YMax);
+ }
+}
+
+/// Caches grid-space AABB for a platform/hazard/finish visual; reapplies pixel rect when the plane size changes.
+public sealed class GraphObstacleUILayout : MonoBehaviour
+{
+ public GridRect gridRect;
+
+ public void ApplyPixelLayout(float unitWidth, float unitHeight)
+ {
+ var rt = transform as RectTransform;
+ if (rt == null)
+ return;
+
+ float pxX = gridRect.xMin * unitWidth;
+ float pxY = gridRect.yMin * unitHeight;
+ float pxW = (gridRect.xMax - gridRect.xMin) * unitWidth;
+ float pxH = (gridRect.yMax - gridRect.yMin) * unitHeight;
+ rt.anchoredPosition = new Vector2(pxX, pxY);
+ rt.sizeDelta = new Vector2(pxW, pxH);
+ }
}
///
@@ -67,6 +97,16 @@ public void SetLayout(RectTransform obstaclesRoot, Vector2Int gridSize, float un
obstacleSprite = RuntimeUiPolish.Rounded9Slice != null ? RuntimeUiPolish.Rounded9Slice : TryGetSquareSprite();
}
+ /// Repositions platform/hazard/finish quads after the Cartesian plane is scaled (rotation, safe area).
+ public void RefreshObstaclePixelLayout()
+ {
+ if (obstaclesRoot == null)
+ return;
+ var layouts = obstaclesRoot.GetComponentsInChildren(true);
+ for (int i = 0; i < layouts.Length; i++)
+ layouts[i].ApplyPixelLayout(unitWidth, unitHeight);
+ }
+
/// Required for Riemann stair mode; used to evaluate exact f at sample x.
/// Inset AABB in grid units; null = full grid, no player hard clamp.
public GraphWorld GenerateWorld(
@@ -433,6 +473,9 @@ private void CreateFinishExitGradient(GridRect finishBand)
rt.anchoredPosition = new Vector2(pxX, pxY);
rt.sizeDelta = new Vector2(pxW, pxH);
+ var finishLayout = go.AddComponent();
+ finishLayout.gridRect = rect;
+
var grad = go.AddComponent();
grad.raycastTarget = false;
grad.SetGradientColors(
@@ -463,6 +506,9 @@ private void CreateRectVisual(string name, GridRect rect, Color color)
rt.anchoredPosition = new Vector2(pxX, pxY);
rt.sizeDelta = new Vector2(pxW, pxH);
+ var layout = go.AddComponent();
+ layout.gridRect = rect;
+
var img = go.AddComponent();
img.sprite = obstacleSprite;
bool isHazard = name.StartsWith("Hazard", System.StringComparison.OrdinalIgnoreCase);
diff --git a/First Principles/Assets/Scripts/Game/GraphPinchZoom.cs b/First Principles/Assets/Scripts/Game/GraphPinchZoom.cs
index 7d54d90..c850611 100644
--- a/First Principles/Assets/Scripts/Game/GraphPinchZoom.cs
+++ b/First Principles/Assets/Scripts/Game/GraphPinchZoom.cs
@@ -52,5 +52,9 @@ private void ApplyHalfWidthScale(float ratio)
plot.xStart = mid - half;
plot.xEnd = mid + half;
plot.step = Mathf.Clamp((plot.xEnd - plot.xStart) / 520f, 0.004f, 0.42f);
+ plot.InitPlotFunction();
+ var lm = FindAnyObjectByType();
+ if (lm != null)
+ lm.RefreshAllTickLabels();
}
}
diff --git a/First Principles/Assets/Scripts/Game/LearningArticleLibrary.cs b/First Principles/Assets/Scripts/Game/LearningArticleLibrary.cs
index 90b79d4..5ec1d85 100644
--- a/First Principles/Assets/Scripts/Game/LearningArticleLibrary.cs
+++ b/First Principles/Assets/Scripts/Game/LearningArticleLibrary.cs
@@ -1,26 +1,118 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
using UnityEngine;
///
/// Plain-language math snippets for the in-game reader (TextMesh Pro rich text).
/// Mathematical parts use LaTeX delimiters \( … \) / \[ … \]; converts them at load time.
/// Body text loads from Resources/Localization/MathArticle/{language}.txt (fallback: en.txt) so every locale can ship a translation.
-/// Mirror ideas in docs (MathJax on GitHub Pages).
+/// Optional lines @@SECTION=id split the article; in-game can request a subset by level.
///
public static class LearningArticleLibrary
{
private const string MathArticleResourcePrefix = "Localization/MathArticle/";
+ private const string SectionDirectivePrefix = "@@SECTION=";
- /// Large TMP block; per-locale file is UTF-8 with meaningful newlines.
- public static string GetLevelSelectArticleRichText()
+ /// Full glossary (level select, or locales without section markers).
+ public static string GetLevelSelectArticleRichText() => GetArticleRichTextForOverlay(forLevelIndex: null);
+
+ /// = entire article (section directive lines stripped). Otherwise sections from .
+ public static string GetArticleRichTextForOverlay(int? forLevelIndex)
{
string raw = LoadRawArticleForCurrentLanguage();
- return TmpLatex.Process(raw);
+ string selected = SelectRawForOverlay(raw, forLevelIndex);
+ return ProcessArticleBody(selected);
+ }
+
+ private static string ProcessArticleBody(string raw)
+ {
+ string processed = TmpLatex.Process(raw);
+ return processed.Replace("&", "&");
+ }
+
+ private static string SelectRawForOverlay(string raw, int? forLevelIndex)
+ {
+ if (string.IsNullOrEmpty(raw) || raw.IndexOf(SectionDirectivePrefix, StringComparison.Ordinal) < 0)
+ return raw;
+
+ if (forLevelIndex == null)
+ return StripSectionDirectiveLines(raw);
+
+ Dictionary sections = ParseSectionDictionary(raw);
+ if (sections.Count == 0)
+ return StripSectionDirectiveLines(raw);
+
+ IReadOnlyList keys = MathArticleLevelSectionMap.GetSectionKeysForLevel(forLevelIndex.Value);
+ var sb = new StringBuilder();
+ foreach (string key in keys)
+ {
+ if (!sections.TryGetValue(key, out string chunk) || string.IsNullOrWhiteSpace(chunk))
+ continue;
+ if (sb.Length > 0)
+ sb.Append("\n\n");
+ sb.Append(chunk.Trim());
+ }
+
+ if (sb.Length == 0)
+ return StripSectionDirectiveLines(raw);
+
+ return sb.ToString();
+ }
+
+ private static string StripSectionDirectiveLines(string raw)
+ {
+ string[] lines = raw.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
+ var sb = new StringBuilder();
+ foreach (string line in lines)
+ {
+ if (line.TrimStart().StartsWith(SectionDirectivePrefix, StringComparison.Ordinal))
+ continue;
+ if (sb.Length > 0)
+ sb.Append('\n');
+ sb.Append(line);
+ }
+
+ return sb.ToString();
+ }
+
+ private static Dictionary ParseSectionDictionary(string raw)
+ {
+ var d = new Dictionary(StringComparer.Ordinal);
+ string[] lines = raw.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
+ string currentKey = null;
+ var chunk = new StringBuilder();
+
+ void Flush()
+ {
+ if (currentKey != null)
+ d[currentKey] = chunk.ToString().TrimEnd();
+ chunk.Clear();
+ }
+
+ foreach (string line in lines)
+ {
+ string t = line.Trim();
+ if (t.StartsWith(SectionDirectivePrefix, StringComparison.Ordinal) && t.Length > SectionDirectivePrefix.Length)
+ {
+ Flush();
+ currentKey = t.Substring(SectionDirectivePrefix.Length).Trim();
+ continue;
+ }
+
+ if (chunk.Length > 0)
+ chunk.Append('\n');
+ chunk.Append(line);
+ }
+
+ Flush();
+ return d;
}
private static string LoadRawArticleForCurrentLanguage()
{
string code = LocalizationManager.CurrentLanguage;
- var ta = Resources.Load($"{MathArticleResourcePrefix}{code}");
+ TextAsset ta = Resources.Load($"{MathArticleResourcePrefix}{code}");
if (ta == null || string.IsNullOrWhiteSpace(ta.text))
ta = Resources.Load($"{MathArticleResourcePrefix}en");
diff --git a/First Principles/Assets/Scripts/Game/LevelDefinition.cs b/First Principles/Assets/Scripts/Game/LevelDefinition.cs
index aeef65f..398c104 100644
--- a/First Principles/Assets/Scripts/Game/LevelDefinition.cs
+++ b/First Principles/Assets/Scripts/Game/LevelDefinition.cs
@@ -88,6 +88,9 @@ public class LevelDefinition : ScriptableObject
[Tooltip("Tint the background grid to match this level’s mood.")]
public bool applyGridTheming = false;
+ [Tooltip("GPU wind-tunnel / schlieren backdrop (aerospace category).")]
+ public bool showWindTunnelBackdrop = false;
+
public Color gridCenterLineTheming = new Color(1f, 1f, 1f, 0.39f);
public Color gridOutsideLineTheming = new Color(1f, 1f, 1f, 0.14f);
diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs
index af7be04..4f84d71 100644
--- a/First Principles/Assets/Scripts/Game/LevelManager.cs
+++ b/First Principles/Assets/Scripts/Game/LevelManager.cs
@@ -41,6 +41,9 @@ public class LevelManager : MonoBehaviour
private DerivRendererUI derivRenderer;
private GridRendererUI gridRenderer;
private RectTransform cartesianPlaneRect;
+ /// Scene-authored Cartesian plane size (fallback 1820×980); used to scale down on narrow portrait screens.
+ private Vector2 _cartesianGameplayDesignSize = new Vector2(1820f, 980f);
+ private Vector2 _lastSyncedCartesianRectSize = new Vector2(-1f, -1f);
private GraphObstacleGenerator obstacleGenerator;
private PlayerControllerUI2D playerController;
@@ -51,7 +54,7 @@ public class LevelManager : MonoBehaviour
private TextMeshProUGUI storyText;
private TextMeshProUGUI stageHudText;
- private TextMeshProUGUI controlsHintText;
+ private TextMeshProUGUI scoreHudText;
private int lastStageHudKey = int.MinValue;
private Sprite cachedHudPanelSprite;
private float storyMiddlePauseSeconds = 1.65f;
@@ -64,6 +67,12 @@ public class LevelManager : MonoBehaviour
private readonly List levels = new List();
private int currentLevelIndex;
+ private const int GameplayStartingScore = 100;
+ private const int DerivativeTouchPenaltyPoints = 5;
+
+ /// Touch f′ penalty score (starts at each level).
+ private int gameplayScore = GameplayStartingScore;
+
/// How many stage boundary thresholds the player has already crossed (derivative pops).
private int nextStageIndex;
private List stageTriggerXGrid;
@@ -121,38 +130,29 @@ private void OnDisable()
private void OnLocalizationChanged()
{
- RefreshControlsHintLocalized();
RefreshMathConceptsLabelLocalized();
RefreshStageHudLocalizedForce();
if (graphCalculatorMode)
+ {
RefreshStoryBannerForCurrentMode(null);
+ TightenGraphCalculatorStoryBanner();
+ var canvas = FindAnyObjectByType