diff --git a/CREDITS.md b/CREDITS.md
index 6d85900..19b2395 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -4,11 +4,11 @@ Use this file for **in-app parity**, **App Store Connect** (description / promot
## Developers
-**GAME GENESIS** ([itch.io](https://game-genesis.itch.io) · [Rayan Kaissi](https://github.com/rkaissi/)) × **ORCH AEROSPACE** ([orchaerospace.com](https://orchaerospace.com) · [John Wonmo Seong](https://github.com/wonmor))
+**ORCH AEROSPACE** ([orchaerospace.com](https://orchaerospace.com) · [John Wonmo Seong](https://github.com/wonmor)) × **GAME GENESIS** ([itch.io](https://game-genesis.itch.io) · [Rayan Kaissi](https://github.com/rkaissi/))
**Proud graduates of Garth Webb Secondary School, Oakville.**
-**Copyright © 2022-2026** Game Genesis (Rayan Kaissi), Orch Aerospace (John Wonmo Seong). All rights reserved.
+**Copyright © 2022-2026** Orch Aerospace (John Wonmo Seong), Game Genesis (Rayan Kaissi). All rights reserved.
## Development & support
@@ -32,7 +32,7 @@ Use this file for **in-app parity**, **App Store Connect** (description / promot
| **Nanum Gothic (font)** | Copyright as listed in Nanum Gothic. Licensed under **SIL OFL 1.1** — see `First Principles/Assets/Resources/Fonts/LICENSE-NanumGothic-OFL.txt`. Used as a **fallback** for Korean (and Latin coverage) alongside **Noto** fonts under `Assets/Resources/Fonts/`. |
| **Noto Sans** (Arabic, Devanagari, Bengali, Nastaliq Urdu, SC, JP, KR, etc.) | Copyright © Google Inc. **SIL OFL 1.1** — see `First Principles/Assets/Resources/Fonts/LICENSE-Noto-OFL.txt`. Runtime TextMesh Pro fallbacks. |
| **Outfit (font, optional)** | Copyright © The Outfit Project Authors. **SIL OFL 1.1** — `First Principles/Assets/Fonts/Outfit-OFL.txt`. Optional alternate UI face via **Apply Outfit for all TextMesh Pro**. |
-| **Nunito (font)** | Bundled SDF asset under `Assets/Fonts/` (legacy / alternate). |
+| **Nunito (font)** | Bundled SDF asset under `First Principles/Assets/Resources/Fonts/` (Menu/Game + runtime-built UI load the same face via `Resources`). |
For other assets under `Assets/`, check any `LICENSE`, `*.txt`, or `Third Party Notices` files next to those assets.
diff --git a/First Principles/Assets/Fonts/Nunito-VariableFont_wght SDF.asset b/First Principles/Assets/Resources/Fonts/Nunito-VariableFont_wght SDF.asset
similarity index 100%
rename from First Principles/Assets/Fonts/Nunito-VariableFont_wght SDF.asset
rename to First Principles/Assets/Resources/Fonts/Nunito-VariableFont_wght SDF.asset
diff --git a/First Principles/Assets/Fonts/Nunito-VariableFont_wght SDF.asset.meta b/First Principles/Assets/Resources/Fonts/Nunito-VariableFont_wght SDF.asset.meta
similarity index 100%
rename from First Principles/Assets/Fonts/Nunito-VariableFont_wght SDF.asset.meta
rename to First Principles/Assets/Resources/Fonts/Nunito-VariableFont_wght SDF.asset.meta
diff --git a/First Principles/Assets/Resources/Localization/MathArticle/ar.txt b/First Principles/Assets/Resources/Localization/MathArticle/ar.txt
index 295b62c..552445c 100644
--- a/First Principles/Assets/Resources/Localization/MathArticle/ar.txt
+++ b/First Principles/Assets/Resources/Localization/MathArticle/ar.txt
@@ -116,4 +116,4 @@
للمزيد من القراءة
docs/math-concepts.md (فهرس)، docs/first-principles-business.md، docs/engineering-math.md، وملفات الامتحانات أعلاه على GitHub Pages.
-— © 2022-2026 · GAME GENESIS × ORCH AEROSPACE · First Principles
+— © 2022-2026 · ORCH AEROSPACE × GAME GENESIS · First Principles
diff --git a/First Principles/Assets/Resources/Localization/MathArticle/cs.txt b/First Principles/Assets/Resources/Localization/MathArticle/cs.txt
index a29bdf0..49bf0d5 100644
--- a/First Principles/Assets/Resources/Localization/MathArticle/cs.txt
+++ b/First Principles/Assets/Resources/Localization/MathArticle/cs.txt
@@ -20,4 +20,4 @@ V anglické verzi článku níže najdete kompletní glosář §1–13, aerospac
Kde číst dál
docs/math-concepts.md, docs/derivative-rules.md, docs/definite-indefinite-integrals.md, docs/first-principles-business.md, docs/engineering-math.md, přípravné soubory AP / AMC / TMUA / MAT.
-— © 2022-2026 · GAME GENESIS × ORCH AEROSPACE · First Principles
+— © 2022-2026 · ORCH AEROSPACE × GAME GENESIS · First Principles
diff --git a/First Principles/Assets/Resources/Localization/MathArticle/en.txt b/First Principles/Assets/Resources/Localization/MathArticle/en.txt
index 54a23c9..b08a41a 100644
--- a/First Principles/Assets/Resources/Localization/MathArticle/en.txt
+++ b/First Principles/Assets/Resources/Localization/MathArticle/en.txt
@@ -155,4 +155,4 @@ BC stacks series & Taylor, parametric / polar / vector-valued moti
Where to read more
docs/math-concepts.md (index), docs/first-principles-business.md (Musk-popularized builder lens ↔ game), docs/competition-math.md & docs/amc-10-12.md (contest / MAA map), docs/engineering-math.md (applied circuits/oscillations), and the exam-prep files above on GitHub Pages.
-— © 2022-2026 · GAME GENESIS × ORCH AEROSPACE · First Principles
+— © 2022-2026 · ORCH AEROSPACE × GAME GENESIS · First Principles
diff --git a/First Principles/Assets/Resources/Localization/MathArticle/it.txt b/First Principles/Assets/Resources/Localization/MathArticle/it.txt
index 0aaf5ca..310007f 100644
--- a/First Principles/Assets/Resources/Localization/MathArticle/it.txt
+++ b/First Principles/Assets/Resources/Localization/MathArticle/it.txt
@@ -135,4 +135,4 @@ Meccanica ed E&M calcolo‑first: \(v = dr/dt\), \(a = dv/dt\), integ
Dove leggere di più
docs/math-concepts.md (indice), docs/first-principles-business.md (lente builder popolarizzata da Musk ↔ gioco), docs/competition-math.md & docs/amc-10-12.md (mappa concorsi / MAA), docs/engineering-math.md (circuiti/oscillazioni applicate) e i file d’esame sopra su GitHub Pages.
-— © 2022-2026 · GAME GENESIS × ORCH AEROSPACE · First Principles
+— © 2022-2026 · ORCH AEROSPACE × GAME GENESIS · First Principles
diff --git a/First Principles/Assets/Resources/Localization/MathArticle/pl.txt b/First Principles/Assets/Resources/Localization/MathArticle/pl.txt
index cff6800..5b2e46e 100644
--- a/First Principles/Assets/Resources/Localization/MathArticle/pl.txt
+++ b/First Principles/Assets/Resources/Localization/MathArticle/pl.txt
@@ -20,4 +20,4 @@ Pełny glosariusz §1–13, aerospace, „first principles” i mapa egzaminów
Gdzie czytać dalej
docs/math-concepts.md, docs/derivative-rules.md, docs/definite-indefinite-integrals.md, docs/first-principles-business.md, docs/engineering-math.md oraz pliki przygotowawcze AP / AMC / TMUA / MAT.
-— © 2022-2026 · GAME GENESIS × ORCH AEROSPACE · First Principles
+— © 2022-2026 · ORCH AEROSPACE × GAME GENESIS · First Principles
diff --git a/First Principles/Assets/Resources/Localization/MathArticle/ru.txt b/First Principles/Assets/Resources/Localization/MathArticle/ru.txt
index 732cd8b..2a7379f 100644
--- a/First Principles/Assets/Resources/Localization/MathArticle/ru.txt
+++ b/First Principles/Assets/Resources/Localization/MathArticle/ru.txt
@@ -20,4 +20,4 @@
Где читать дальше
docs/math-concepts.md, docs/derivative-rules.md, docs/definite-indefinite-integrals.md, docs/first-principles-business.md, docs/engineering-math.md и файлы подготовки AP / AMC / TMUA / MAT.
-— © 2022-2026 · GAME GENESIS × ORCH AEROSPACE · First Principles
+— © 2022-2026 · ORCH AEROSPACE × GAME GENESIS · First Principles
diff --git a/First Principles/Assets/Resources/PerformanceTestRunInfo.json b/First Principles/Assets/Resources/PerformanceTestRunInfo.json
new file mode 100644
index 0000000..37f0b9a
--- /dev/null
+++ b/First Principles/Assets/Resources/PerformanceTestRunInfo.json
@@ -0,0 +1 @@
+{"TestSuite":"","Date":0,"Player":{"Development":false,"ScreenWidth":0,"ScreenHeight":0,"ScreenRefreshRate":0,"Fullscreen":false,"Vsync":0,"AntiAliasing":0,"Batchmode":false,"RenderThreadingMode":"MultiThreaded","MtRendering":false,"GraphicsJobs":false,"GpuSkinning":false,"Platform":"","ColorSpace":"","AnisotropicFiltering":"","BlendWeights":"","GraphicsApi":"","ScriptingBackend":"Mono2x","AndroidTargetSdkVersion":"AndroidApiLevelAuto","AndroidBuildSystem":"Gradle","BuildTarget":"Android","StereoRenderingPath":"MultiPass"},"Hardware":{"OperatingSystem":"","DeviceModel":"","DeviceName":"","ProcessorType":"","ProcessorCount":0,"GraphicsDeviceName":"","SystemMemorySizeMB":0},"Editor":{"Version":"6000.4.0f1","Branch":"6000.4/staging","Changeset":"8cf496087c8f","Date":1773430047},"Dependencies":["com.unity.2d.animation@14.0.3","com.unity.2d.pixel-perfect@5.1.1","com.unity.2d.psdimporter@13.0.2","com.unity.2d.sprite@1.0.0","com.unity.2d.spriteshape@14.0.1","com.unity.2d.tilemap@1.0.0","com.unity.ai.navigation@2.0.11","com.unity.collab-proxy@2.11.4","com.unity.ide.rider@3.0.39","com.unity.ide.visualstudio@2.0.27","com.unity.ide.vscode@1.2.4","com.unity.inputsystem@1.16.0","com.unity.multiplayer.center@1.0.1","com.unity.test-framework@1.6.0","com.unity.timeline@1.8.11","com.unity.ugui@2.0.0","com.unity.modules.accessibility@1.0.0","com.unity.modules.adaptiveperformance@1.0.0","com.unity.modules.ai@1.0.0","com.unity.modules.androidjni@1.0.0","com.unity.modules.animation@1.0.0","com.unity.modules.assetbundle@1.0.0","com.unity.modules.audio@1.0.0","com.unity.modules.cloth@1.0.0","com.unity.modules.director@1.0.0","com.unity.modules.imageconversion@1.0.0","com.unity.modules.imgui@1.0.0","com.unity.modules.jsonserialize@1.0.0","com.unity.modules.particlesystem@1.0.0","com.unity.modules.physics@1.0.0","com.unity.modules.physics2d@1.0.0","com.unity.modules.screencapture@1.0.0","com.unity.modules.terrain@1.0.0","com.unity.modules.terrainphysics@1.0.0","com.unity.modules.tilemap@1.0.0","com.unity.modules.ui@1.0.0","com.unity.modules.uielements@1.0.0","com.unity.modules.umbra@1.0.0","com.unity.modules.unityanalytics@1.0.0","com.unity.modules.unitywebrequest@1.0.0","com.unity.modules.unitywebrequestassetbundle@1.0.0","com.unity.modules.unitywebrequestaudio@1.0.0","com.unity.modules.unitywebrequesttexture@1.0.0","com.unity.modules.unitywebrequestwww@1.0.0","com.unity.modules.vectorgraphics@1.0.0","com.unity.modules.vehicles@1.0.0","com.unity.modules.video@1.0.0","com.unity.modules.vr@1.0.0","com.unity.modules.wind@1.0.0","com.unity.modules.xr@1.0.0","com.unity.modules.subsystems@1.0.0","com.unity.modules.hierarchycore@1.0.0","com.unity.ext.nunit@2.0.5","com.unity.2d.common@13.0.1","com.unity.mathematics@1.3.3","com.unity.collections@6.4.0","com.unity.burst@1.8.28","com.unity.nuget.mono-cecil@1.11.6","com.unity.test-framework.performance@3.2.0"],"Results":[]}
\ No newline at end of file
diff --git a/First Principles/Assets/Resources/PerformanceTestRunInfo.json.meta b/First Principles/Assets/Resources/PerformanceTestRunInfo.json.meta
new file mode 100644
index 0000000..d4d9733
--- /dev/null
+++ b/First Principles/Assets/Resources/PerformanceTestRunInfo.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: f02f9f9335b0a4160940f1e6540c4b60
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/First Principles/Assets/Resources/PerformanceTestRunSettings.json b/First Principles/Assets/Resources/PerformanceTestRunSettings.json
new file mode 100644
index 0000000..49438ae
--- /dev/null
+++ b/First Principles/Assets/Resources/PerformanceTestRunSettings.json
@@ -0,0 +1 @@
+{"MeasurementCount":-1}
\ No newline at end of file
diff --git a/First Principles/Assets/Resources/PerformanceTestRunSettings.json.meta b/First Principles/Assets/Resources/PerformanceTestRunSettings.json.meta
new file mode 100644
index 0000000..bf80355
--- /dev/null
+++ b/First Principles/Assets/Resources/PerformanceTestRunSettings.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: dbc686885050d46718f6c481c235bcd1
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs
index d4ebbb0..6b44716 100644
--- a/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs
+++ b/First Principles/Assets/Scripts/Functions/FunctionPlotter.cs
@@ -2,7 +2,8 @@
* FunctionPlotter.cs — John Seong / First Principles
*
* Maintenance overview:
- * • Each Update() calls InitPlotFunction → samples f and numeric f' over [xStart,xEnd].
+ * • Update() only runs a full replot when parameters change or the Lorenz attractor is animating;
+ * during the left→right reveal, it only refreshes vertex alpha. (Avoids sampling f/f′ every frame.)
* • Points are in “grid space”: (MapDisplayX(xPlot) + gridOrigin.x, MapDisplayY(yPlot) + gridOrigin.y).
* • To add a new curve: extend FunctionType, EvaluateFunctionY, and UpdateEquationText.
* • LevelManager sets public fields to match LevelDefinition; differentiate=true feeds DerivRendererUI.
@@ -93,6 +94,9 @@ public class FunctionPlotter : MonoBehaviour
private LineRendererUI lineRenderer;
private DerivRendererUI derivRenderer;
+ /// Last after a full — skips redundant work in .
+ private int _cachedPlotParamHash = int.MinValue;
+
[Tooltip("Seconds for the main f and f′ curves to fade in left→right after the graph parameters change.")]
public float graphRevealDurationSeconds = 2.1f;
@@ -121,10 +125,45 @@ private void OnValidate()
private void Update()
{
UpdateGraphRevealAnimation();
- InitPlotFunction();
- RefreshGrid();
+
+ // Lorenz stage scrolls phase every frame — full resample required.
+ if (functionType == FunctionType.ChaosLorenzButterflyX)
+ {
+ InitPlotFunction();
+ return;
+ }
+
+ int paramHash = ComputePlotInvalidationHash();
+ if (paramHash != _cachedPlotParamHash)
+ {
+ InitPlotFunction();
+ return;
+ }
+
+ // Graph reveal: only push fade uniforms + remesh existing points (no ComputeGraph).
+ if (_graphRevealT01 < 0.999f)
+ {
+ if (lineRenderer == null)
+ lineRenderer = LineRendererUI.FindPrimaryCurve();
+ if (derivRenderer == null)
+ derivRenderer = FindAnyObjectByType();
+
+ PushGraphRevealToRenderers();
+ if (lineRenderer != null)
+ lineRenderer.SetVerticesDirty();
+ if (derivRenderer != null && differentiate)
+ derivRenderer.SetVerticesDirty();
+ }
}
+ /// When this changes, must run (same inputs that affect ).
+ int ComputePlotInvalidationHash() =>
+ HashCode.Combine(
+ ComputeGraphRevealParamsHash(),
+ differentiate,
+ showWindTunnelBackdrop,
+ equationExtraSuffix ?? "");
+
void UpdateGraphRevealAnimation()
{
int h = ComputeGraphRevealParamsHash();
@@ -410,6 +449,8 @@ private void PlotFunction(FunctionType type)
WindTunnelBackdrop.Sync(gridRt, this);
PushGraphRevealToRenderers();
}
+
+ _cachedPlotParamHash = ComputePlotInvalidationHash();
}
public void ComputeGraph(FunctionType functionType, float transA, float transK, float transC, float transD, int power, int baseN)
diff --git a/First Principles/Assets/Scripts/Game/LevelDefinition.cs b/First Principles/Assets/Scripts/Game/LevelDefinition.cs
index 398c104..074e789 100644
--- a/First Principles/Assets/Scripts/Game/LevelDefinition.cs
+++ b/First Principles/Assets/Scripts/Game/LevelDefinition.cs
@@ -20,7 +20,7 @@ public class LevelDefinition : ScriptableObject
public string levelName = "Stage";
[TextArea(4, 12)]
public string storyText = "Follow the curve. Watch the derivative.";
- [Tooltip("Extra seconds the story stays readable after fading in (0 = use LevelManager default).")]
+ [Tooltip("Extra seconds the story stays readable after fading in (0 = use LevelManager default, ~3.25 s).")]
public float storyPauseSeconds = 0f;
[Header("Graph Parameters (FunctionPlotter)")]
diff --git a/First Principles/Assets/Scripts/Game/LevelManager.cs b/First Principles/Assets/Scripts/Game/LevelManager.cs
index 4f84d71..eb6ba6b 100644
--- a/First Principles/Assets/Scripts/Game/LevelManager.cs
+++ b/First Principles/Assets/Scripts/Game/LevelManager.cs
@@ -69,6 +69,10 @@ public class LevelManager : MonoBehaviour
private const int GameplayStartingScore = 100;
private const int DerivativeTouchPenaltyPoints = 5;
+ /// How long the top story banner stays at full opacity after fading in (per-level override via ).
+ private const float DefaultStoryBannerReadableSeconds = 3.25f;
+ /// Preferred height for the top StoryText block so longer level copy fits above the graph.
+ private const float StoryBannerLayoutHeightPx = 400f;
/// Touch f′ penalty score (starts at each level).
private int gameplayScore = GameplayStartingScore;
@@ -837,7 +841,7 @@ private void CreateStoryTextIfNeeded()
rt.anchorMax = new Vector2(0.96f, 1f);
rt.pivot = new Vector2(0.5f, 1f);
rt.anchoredPosition = new Vector2(0, -64f);
- rt.sizeDelta = new Vector2(0f, 280f);
+ rt.sizeDelta = new Vector2(0f, StoryBannerLayoutHeightPx);
tmp.color = new Color(1f, 1f, 1f, 0f);
@@ -2857,7 +2861,7 @@ private void ApplyLevelTheme(LevelDefinition def)
for (int i = 1; i <= popN; i++)
stageTriggerXGrid.Add((i / (float)(popN + 1)) * width);
- storyMiddlePauseSeconds = def.storyPauseSeconds > 0.01f ? def.storyPauseSeconds : 1.65f;
+ storyMiddlePauseSeconds = def.storyPauseSeconds > 0.01f ? def.storyPauseSeconds : DefaultStoryBannerReadableSeconds;
if (gridRenderer != null)
{
diff --git a/First Principles/Assets/Scripts/Game/PlayerControllerUI2D.cs b/First Principles/Assets/Scripts/Game/PlayerControllerUI2D.cs
index 003f5e0..c8f6dc4 100644
--- a/First Principles/Assets/Scripts/Game/PlayerControllerUI2D.cs
+++ b/First Principles/Assets/Scripts/Game/PlayerControllerUI2D.cs
@@ -232,16 +232,19 @@ private void Update()
// Gravity.
velGrid.y -= gravityGridPerSec2 * dt;
- Vector2 prevPos = posGrid;
Vector2 nextPos = posGrid;
// Horizontal step + collision.
nextPos.x = posGrid.x + velGrid.x * dt;
ResolveHorizontalPlatforms(ref nextPos);
+ // Vertical sweep should use Y from before this frame's vertical move but X after horizontal
+ // (matches diagonal motion; avoids false collisions when strafing along stepped platforms).
+ Vector2 prevForVerticalSweep = new Vector2(nextPos.x, posGrid.y);
+
// Vertical step + collision.
nextPos.y = posGrid.y + velGrid.y * dt;
- ResolveVerticalPlatforms(prevPos, ref nextPos, ref grounded);
+ ResolveVerticalPlatforms(prevForVerticalSweep, ref nextPos, ref grounded);
// Hazard check.
if (OverlapsAny(world.hazards, nextPos))
@@ -353,8 +356,10 @@ private void UpdateDerivativeTouchAndHighlight(float dt)
private void PlayDerivativeLineHitFeedback()
{
bool usedHaptic = derivativeHitHaptic && Application.isMobilePlatform;
+#if UNITY_ANDROID || UNITY_IOS
if (usedHaptic)
Handheld.Vibrate();
+#endif
// Sound only where vibration isn’t used (no haptic on this platform/path).
if (usedHaptic)
@@ -534,7 +539,7 @@ private void ResolveHorizontalPlatforms(ref Vector2 pos)
}
}
- /// Land on platform tops when falling; bonk head when rising through thin solids.
+ /// Land on platform tops when falling; bonk head when rising into a true overhead solid.
private void ResolveVerticalPlatforms(Vector2 prevPos, ref Vector2 pos, ref bool groundedOut)
{
groundedOut = false;
@@ -551,6 +556,12 @@ private void ResolveVerticalPlatforms(Vector2 prevPos, ref Vector2 pos, ref bool
float pxMax = pos.x + halfW;
const float eps = 0.001f;
+ // Graph levels use ~1-column × thin-slab platforms along the curve. The slab's bottom (yMin) sits
+ // under the walkable top (yMax); jumping forward along rising steps hits that underside and used to
+ // zero vy mid-air. Skip that "bonk" while the feet are still clearly below the step top.
+ const float maxLedgeSlabThicknessGrid = 0.95f;
+ const float maxLedgeSlabWidthGrid = 1.28f;
+ const float feetBelowStepTopClearanceGrid = 0.1f;
foreach (var p in world.platforms)
{
@@ -569,8 +580,14 @@ private void ResolveVerticalPlatforms(Vector2 prevPos, ref Vector2 pos, ref bool
groundedOut = true;
}
}
- else // Rising into platform
+ else // Rising — only bonk real ceilings, not the underside lip of the next stair tread.
{
+ float platW = p.xMax - p.xMin;
+ float platH = p.yMax - p.yMin;
+ bool thinStairSlab = platW <= maxLedgeSlabWidthGrid && platH <= maxLedgeSlabThicknessGrid;
+ if (thinStairSlab && nextBottom < p.yMax - feetBelowStepTopClearanceGrid)
+ continue;
+
bool crossedBottomSurface = prevTop <= p.yMin + eps && nextTop >= p.yMin - eps;
if (crossedBottomSurface)
{
diff --git a/First Principles/Assets/Scripts/UI/UiTypography.cs b/First Principles/Assets/Scripts/UI/UiTypography.cs
index 0e42767..4b18938 100644
--- a/First Principles/Assets/Scripts/UI/UiTypography.cs
+++ b/First Principles/Assets/Scripts/UI/UiTypography.cs
@@ -1,3 +1,4 @@
+using System;
using TMPro;
using UnityEngine;
@@ -14,19 +15,35 @@ public static class UiTypography
public static float Scale(float px) => Mathf.Max(1f, Mathf.Round(px * GlobalScale));
+ /// Same asset referenced by Menu/Game scenes; must live under a Resources folder for .
+ const string ProjectPrimaryTmpFontResourcePath = "Fonts/Nunito-VariableFont_wght SDF";
+
///
- /// Assigns (e.g. Quicksand after font setup) so runtime-built UI
- /// matches the project TMP default instead of whatever happens to be first in the scene.
+ /// Picks a TMP font for runtime-built UI (level select, overlays, etc.): uses
+ /// when you have replaced the stock Liberation default (e.g. Quicksand menu command); otherwise loads
+ /// Resources/ so level select matches Menu/Game (Nunito in this repo).
///
public static void ApplyDefaultFontAsset(TextMeshProUGUI target)
{
if (target == null)
return;
- var font = TMP_Settings.defaultFontAsset;
+ TMP_FontAsset settingsFont = TMP_Settings.defaultFontAsset;
+ TMP_FontAsset fromResources = Resources.Load(ProjectPrimaryTmpFontResourcePath);
+
+ TMP_FontAsset font = fromResources;
+ if (settingsFont != null && !IsLikelyStockLiberationSans(settingsFont))
+ font = settingsFont;
+ if (font == null)
+ font = settingsFont;
if (font == null)
return;
+
target.font = font;
if (font.material != null)
target.fontSharedMaterial = font.material;
}
+
+ static bool IsLikelyStockLiberationSans(TMP_FontAsset f) =>
+ f != null && f.name != null &&
+ f.name.IndexOf("Liberation", StringComparison.OrdinalIgnoreCase) >= 0;
}
diff --git a/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset b/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset
index 8897c1f..95e5166 100644
--- a/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset
+++ b/First Principles/Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF - Fallback.asset
@@ -1342,6 +1342,33 @@ MonoBehaviour:
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
+ - {fileID: 0}
m_FontWeightTable:
- regularTypeface: {fileID: 0}
italicTypeface: {fileID: 0}
diff --git a/First Principles/ProjectSettings/ProjectSettings.asset b/First Principles/ProjectSettings/ProjectSettings.asset
index 006f5e1..3ea4b67 100644
--- a/First Principles/ProjectSettings/ProjectSettings.asset
+++ b/First Principles/ProjectSettings/ProjectSettings.asset
@@ -12,7 +12,7 @@ PlayerSettings:
targetDevice: 2
useOnDemandResources: 0
accelerometerFrequency: 60
- companyName: Game Genesis; Orch Aerospace
+ companyName: Orch Aerospace and Game Genesis
productName: First Principles
defaultCursor: {fileID: 0}
cursorHotspot: {x: 0, y: 0}
@@ -41,8 +41,8 @@ PlayerSettings:
height: 1
m_SplashScreenLogos: []
m_VirtualRealitySplashScreen: {fileID: 0}
- defaultScreenWidth: 1920
- defaultScreenHeight: 1080
+ defaultScreenWidth: 900
+ defaultScreenHeight: 1440
defaultScreenWidthWeb: 960
defaultScreenHeightWeb: 600
m_StereoRenderingPath: 0
@@ -80,7 +80,7 @@ PlayerSettings:
androidAutoRotationBehavior: 1
androidPredictiveBackSupport: 1
androidApplicationEntry: 1
- defaultIsNativeResolution: 1
+ defaultIsNativeResolution: 0
macRetinaSupport: 1
runInBackground: 0
muteOtherAudioSources: 0
@@ -95,7 +95,7 @@ PlayerSettings:
bakeCollisionMeshes: 0
forceSingleInstance: 0
useFlipModelSwapchain: 1
- resizableWindow: 0
+ resizableWindow: 1
useMacAppStoreValidation: 0
macAppStoreCategory: public.app-category.games
gpuSkinning: 0
@@ -107,7 +107,7 @@ PlayerSettings:
xboxEnableFitness: 0
visibleInBackground: 1
allowFullscreenSwitch: 1
- fullscreenMode: 1
+ fullscreenMode: 3
xboxSpeechDB: 0
xboxEnableHeadOrientation: 0
xboxEnableGuest: 0
diff --git a/First Principles/UserSettings/Layouts/default-6000.dwlt b/First Principles/UserSettings/Layouts/default-6000.dwlt
index 2b0068b..31e96ad 100644
--- a/First Principles/UserSettings/Layouts/default-6000.dwlt
+++ b/First Principles/UserSettings/Layouts/default-6000.dwlt
@@ -19,87 +19,12 @@ MonoBehaviour:
width: 1728
height: 995
m_ShowMode: 4
- m_Title: Console
- m_RootView: {fileID: 5}
+ m_Title: Game
+ m_RootView: {fileID: 2}
m_MinSize: {x: 875, y: 300}
m_MaxSize: {x: 10000, y: 10000}
m_Maximized: 1
--- !u!114 &2
-MonoBehaviour:
- m_ObjectHideFlags: 52
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 0}
- m_Enabled: 1
- m_EditorHideFlags: 0
- m_Script: {fileID: 12004, guid: 0000000000000000e000000000000000, type: 0}
- m_Name:
- m_EditorClassIdentifier: UnityEditor.dll::UnityEditor.ContainerWindow
- m_PixelRect:
- serializedVersion: 2
- x: 163
- y: 307
- width: 725
- height: 578
- m_ShowMode: 0
- m_Title: Build Profiles
- m_RootView: {fileID: 4}
- m_MinSize: {x: 725, y: 426}
- m_MaxSize: {x: 4000, y: 4026}
- m_Maximized: 0
---- !u!114 &3
-MonoBehaviour:
- m_ObjectHideFlags: 52
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 0}
- m_Enabled: 1
- m_EditorHideFlags: 0
- m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0}
- m_Name: BuildProfileWindow
- m_EditorClassIdentifier: UnityEditor.dll::UnityEditor.DockArea
- m_Children: []
- m_Position:
- serializedVersion: 2
- x: 0
- y: 0
- width: 725
- height: 578
- m_MinSize: {x: 725, y: 426}
- m_MaxSize: {x: 4000, y: 4026}
- m_ActualView: {fileID: 15}
- m_Panes:
- - {fileID: 15}
- m_Selected: 0
- m_LastSelected: 0
---- !u!114 &4
-MonoBehaviour:
- m_ObjectHideFlags: 52
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 0}
- m_Enabled: 1
- m_EditorHideFlags: 0
- m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0}
- m_Name:
- m_EditorClassIdentifier: UnityEditor.dll::UnityEditor.SplitView
- m_Children:
- - {fileID: 3}
- m_Position:
- serializedVersion: 2
- x: 0
- y: 0
- width: 725
- height: 578
- m_MinSize: {x: 725, y: 426}
- m_MaxSize: {x: 4000, y: 4026}
- vertical: 0
- controlID: 508
- draggingID: 0
---- !u!114 &5
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -112,9 +37,9 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Children:
- - {fileID: 6}
- - {fileID: 8}
- - {fileID: 7}
+ - {fileID: 3}
+ - {fileID: 5}
+ - {fileID: 4}
m_Position:
serializedVersion: 2
x: 0
@@ -127,7 +52,7 @@ MonoBehaviour:
m_TopViewHeight: 36
m_UseBottomView: 1
m_BottomViewHeight: 20
---- !u!114 &6
+--- !u!114 &3
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -148,8 +73,8 @@ MonoBehaviour:
height: 36
m_MinSize: {x: 50, y: 50}
m_MaxSize: {x: 4000, y: 4000}
- m_ActualView: {fileID: 16}
---- !u!114 &7
+ m_ActualView: {fileID: 12}
+--- !u!114 &4
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -170,7 +95,7 @@ MonoBehaviour:
height: 20
m_MinSize: {x: 0, y: 0}
m_MaxSize: {x: 0, y: 0}
---- !u!114 &8
+--- !u!114 &5
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -183,8 +108,8 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Children:
- - {fileID: 9}
- - {fileID: 14}
+ - {fileID: 6}
+ - {fileID: 11}
m_Position:
serializedVersion: 2
x: 0
@@ -194,9 +119,9 @@ MonoBehaviour:
m_MinSize: {x: 300, y: 112}
m_MaxSize: {x: 24288, y: 16192}
vertical: 0
- controlID: 52
+ controlID: 171
draggingID: 0
---- !u!114 &9
+--- !u!114 &6
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -209,8 +134,8 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Children:
+ - {fileID: 7}
- {fileID: 10}
- - {fileID: 13}
m_Position:
serializedVersion: 2
x: 0
@@ -220,9 +145,9 @@ MonoBehaviour:
m_MinSize: {x: 200, y: 112}
m_MaxSize: {x: 16192, y: 16192}
vertical: 1
- controlID: 53
+ controlID: 172
draggingID: 0
---- !u!114 &10
+--- !u!114 &7
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -235,8 +160,8 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Children:
- - {fileID: 11}
- - {fileID: 12}
+ - {fileID: 8}
+ - {fileID: 9}
m_Position:
serializedVersion: 2
x: 0
@@ -246,9 +171,9 @@ MonoBehaviour:
m_MinSize: {x: 200, y: 56}
m_MaxSize: {x: 16192, y: 8096}
vertical: 0
- controlID: 54
+ controlID: 173
draggingID: 0
---- !u!114 &11
+--- !u!114 &8
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -269,12 +194,12 @@ MonoBehaviour:
height: 605
m_MinSize: {x: 201, y: 226}
m_MaxSize: {x: 4001, y: 4026}
- m_ActualView: {fileID: 17}
+ m_ActualView: {fileID: 13}
m_Panes:
- - {fileID: 17}
+ - {fileID: 13}
m_Selected: 0
m_LastSelected: 0
---- !u!114 &12
+--- !u!114 &9
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -295,14 +220,14 @@ MonoBehaviour:
height: 605
m_MinSize: {x: 202, y: 226}
m_MaxSize: {x: 4002, y: 4026}
- m_ActualView: {fileID: 18}
+ m_ActualView: {fileID: 14}
m_Panes:
- - {fileID: 18}
- - {fileID: 19}
- - {fileID: 20}
+ - {fileID: 14}
+ - {fileID: 15}
+ - {fileID: 16}
m_Selected: 0
m_LastSelected: 1
---- !u!114 &13
+--- !u!114 &10
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -323,13 +248,13 @@ MonoBehaviour:
height: 334
m_MinSize: {x: 101, y: 126}
m_MaxSize: {x: 4001, y: 4026}
- m_ActualView: {fileID: 22}
+ m_ActualView: {fileID: 18}
m_Panes:
- - {fileID: 21}
- - {fileID: 22}
+ - {fileID: 17}
+ - {fileID: 18}
m_Selected: 1
m_LastSelected: 0
---- !u!114 &14
+--- !u!114 &11
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -350,50 +275,12 @@ MonoBehaviour:
height: 939
m_MinSize: {x: 276, y: 76}
m_MaxSize: {x: 4001, y: 4026}
- m_ActualView: {fileID: 23}
+ m_ActualView: {fileID: 19}
m_Panes:
- - {fileID: 23}
+ - {fileID: 19}
m_Selected: 0
m_LastSelected: 0
---- !u!114 &15
-MonoBehaviour:
- m_ObjectHideFlags: 52
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 0}
- m_Enabled: 1
- m_EditorHideFlags: 0
- m_Script: {fileID: 15004, guid: 0000000000000000e000000000000000, type: 0}
- m_Name:
- m_EditorClassIdentifier: UnityEditor.BuildProfileModule.dll::UnityEditor.Build.Profile.BuildProfileWindow
- m_MinSize: {x: 725, y: 400}
- m_MaxSize: {x: 4000, y: 4000}
- m_TitleContent:
- m_Text: Build Profiles
- m_Image: {fileID: 0}
- m_Tooltip:
- m_TextWithWhitespace: "Build Profiles\u200B"
- m_Pos:
- serializedVersion: 2
- x: 0
- y: 26
- width: 725
- height: 552
- m_SerializedDataModeController:
- m_DataMode: 0
- m_PreferredDataMode: 0
- m_SupportedDataModes:
- isAutomatic: 1
- m_ViewDataDictionary: {fileID: 0}
- m_OverlayCanvas:
- m_LastAppliedPresetName: Default
- m_SaveData: []
- m_ContainerData: []
- m_DynamicPanelContainerData: []
- m_OverlaysVisible: 1
- m_DynamicPanelBehavior: 0
---- !u!114 &16
+--- !u!114 &12
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -659,7 +546,7 @@ MonoBehaviour:
m_DynamicPanelContainerData: []
m_OverlaysVisible: 1
m_DynamicPanelBehavior: 0
---- !u!114 &17
+--- !u!114 &13
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -704,14 +591,48 @@ MonoBehaviour:
m_LastClickedID:
m_Data: 0
m_ExpandedIDs:
- - m_Data: -62118
- - m_Data: -60778
- - m_Data: -60660
- - m_Data: -60636
- - m_Data: -60622
- - m_Data: -60586
- - m_Data: -35118
- - m_Data: -34368
+ - m_Data: -135860
+ - m_Data: -135756
+ - m_Data: -135740
+ - m_Data: -135734
+ - m_Data: -135706
+ - m_Data: -133212
+ - m_Data: -133108
+ - m_Data: -133092
+ - m_Data: -133086
+ - m_Data: -133058
+ - m_Data: -130614
+ - m_Data: -130496
+ - m_Data: -130480
+ - m_Data: -130474
+ - m_Data: -130446
+ - m_Data: -128134
+ - m_Data: -128016
+ - m_Data: -128000
+ - m_Data: -127994
+ - m_Data: -127966
+ - m_Data: -126196
+ - m_Data: -126078
+ - m_Data: -126062
+ - m_Data: -126056
+ - m_Data: -126028
+ - m_Data: -120834
+ - m_Data: -120716
+ - m_Data: -120700
+ - m_Data: -120694
+ - m_Data: -120666
+ - m_Data: -118892
+ - m_Data: -118774
+ - m_Data: -118758
+ - m_Data: -118752
+ - m_Data: -118724
+ - m_Data: -117112
+ - m_Data: -116206
+ - m_Data: -116088
+ - m_Data: -116072
+ - m_Data: -116066
+ - m_Data: -116038
+ - m_Data: -1750
m_RenameOverlay:
m_UserAcceptedRename: 0
m_Name:
@@ -738,7 +659,7 @@ MonoBehaviour:
m_IsLocked: 0
m_CurrentSortingName: TransformSorting
m_WindowGUID: 46b7a0fefa812c44ca6fda42b4d7b176
---- !u!114 &18
+--- !u!114 &14
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -1409,7 +1330,7 @@ MonoBehaviour:
m_LastSceneViewRotation: {x: 0.31118897, y: 0.09269961, z: -0.030600414, w: 0.9453927}
m_LastSceneViewOrtho: 1
m_Viewpoint:
- m_SceneView: {fileID: 18}
+ m_SceneView: {fileID: 14}
m_CameraOverscanSettings:
m_Opacity: 50
m_Scale: 1
@@ -1422,7 +1343,7 @@ MonoBehaviour:
name: Contributors / Receivers
section: Lighting
m_ViewIsLockedToObject: 0
---- !u!114 &19
+--- !u!114 &15
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -1466,7 +1387,7 @@ MonoBehaviour:
m_ShowGizmos: 0
m_TargetDisplay: 0
m_ClearColor: {r: 0, g: 0, b: 0, a: 0}
- m_TargetSize: {x: 1468, y: 1116}
+ m_TargetSize: {x: 2560, y: 1440}
m_TextureFilterMode: 0
m_TextureHideFlags: 61
m_RenderIMGUI: 1
@@ -1481,10 +1402,10 @@ MonoBehaviour:
m_VRangeLocked: 0
hZoomLockedByDefault: 0
vZoomLockedByDefault: 0
- m_HBaseRangeMin: -367
- m_HBaseRangeMax: 367
- m_VBaseRangeMin: -279
- m_VBaseRangeMax: 279
+ m_HBaseRangeMin: -640
+ m_HBaseRangeMax: 640
+ m_VBaseRangeMin: -360
+ m_VBaseRangeMax: 360
m_HAllowExceedBaseRangeMin: 1
m_HAllowExceedBaseRangeMax: 1
m_VAllowExceedBaseRangeMin: 1
@@ -1504,7 +1425,7 @@ MonoBehaviour:
y: 21
width: 734
height: 558
- m_Scale: {x: 1, y: 1}
+ m_Scale: {x: 0.5734375, y: 0.5734375}
m_Translation: {x: 367, y: 279}
m_MarginLeft: 0
m_MarginRight: 0
@@ -1512,12 +1433,12 @@ MonoBehaviour:
m_MarginBottom: 0
m_LastShownAreaInsideMargins:
serializedVersion: 2
- x: -367
- y: -279
- width: 734
- height: 558
+ x: -640
+ y: -486.5395
+ width: 1280
+ height: 973.079
m_MinimalGUI: 1
- m_defaultScale: 1
+ m_defaultScale: 0.5734375
m_LastWindowPixelSize: {x: 1468, y: 1158}
m_ClearInEditMode: 1
m_NoCameraWarning: 1
@@ -1525,7 +1446,7 @@ MonoBehaviour:
m_XRRenderMode: 0
m_RenderTexture: {fileID: 0}
m_showToolbar: 1
---- !u!114 &20
+--- !u!114 &16
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -1563,7 +1484,7 @@ MonoBehaviour:
m_DynamicPanelContainerData: []
m_OverlaysVisible: 1
m_DynamicPanelBehavior: 0
---- !u!114 &21
+--- !u!114 &17
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -1636,9 +1557,7 @@ MonoBehaviour:
m_Data: 40708
m_ExpandedIDs:
- m_Data: 0
- - m_Data: 34560
- - m_Data: 1000000000
- - m_Data: 2147483647
+ - m_Data: 34742
m_RenameOverlay:
m_UserAcceptedRename: 0
m_Name:
@@ -1656,7 +1575,7 @@ MonoBehaviour:
m_OriginalEventType: 11
m_IsRenamingFilename: 1
m_TrimLeadingAndTrailingWhitespace: 0
- m_ClientGUIView: {fileID: 13}
+ m_ClientGUIView: {fileID: 10}
m_SearchString:
m_CreateAssetUtility:
m_EndAction: {fileID: 0}
@@ -1672,9 +1591,7 @@ MonoBehaviour:
m_Data: 0
m_ExpandedIDs:
- m_Data: 0
- - m_Data: 34560
- - m_Data: 1000000000
- - m_Data: 2147483647
+ - m_Data: 34742
m_RenameOverlay:
m_UserAcceptedRename: 0
m_Name:
@@ -1692,7 +1609,7 @@ MonoBehaviour:
m_OriginalEventType: 11
m_IsRenamingFilename: 1
m_TrimLeadingAndTrailingWhitespace: 0
- m_ClientGUIView: {fileID: 13}
+ m_ClientGUIView: {fileID: 10}
m_SearchString:
m_CreateAssetUtility:
m_EndAction: {fileID: 0}
@@ -1724,7 +1641,7 @@ MonoBehaviour:
m_OriginalEventType: 11
m_IsRenamingFilename: 1
m_TrimLeadingAndTrailingWhitespace: 0
- m_ClientGUIView: {fileID: 13}
+ m_ClientGUIView: {fileID: 10}
m_CreateAssetUtility:
m_EndAction: {fileID: 0}
m_EntityId:
@@ -1737,7 +1654,7 @@ MonoBehaviour:
m_GridSize: 16
m_SkipHiddenPackages: 0
m_DirectoriesAreaWidth: 199
---- !u!114 &22
+--- !u!114 &18
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
@@ -1775,7 +1692,7 @@ MonoBehaviour:
m_DynamicPanelContainerData: []
m_OverlaysVisible: 1
m_DynamicPanelBehavior: 0
---- !u!114 &23
+--- !u!114 &19
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
diff --git a/LICENSE b/LICENSE
index 0d2c4c4..00b942d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
PROPRIETARY LICENSE
-Copyright (c) 2022-2026 Game Genesis (Rayan Kaissi), Orch Aerospace (John Wonmo Seong)
+Copyright (c) 2022-2026 Orch Aerospace (John Wonmo Seong), Game Genesis (Rayan Kaissi)
All rights reserved.
diff --git a/README.md b/README.md
index c52518a..589b1b6 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,25 @@
# First Principles: An Interactive Module
A **graphing calculator** and **derivative-driven platformer** built in **Unity 6**. The **name** nods to **Elon Musk**’s comments on a **first-principles approach** to **business** and to **problem-solving in life and work**—paired here with **calculus** on the graph as the literal teaching layer ([`docs/first-principles-business.md`](docs/first-principles-business.md)).
-Credits: **GAME GENESIS** ([itch.io](https://game-genesis.itch.io) · [Rayan Kaissi](https://github.com/rkaissi/)) × **ORCH AEROSPACE** ([orchaerospace.com](https://orchaerospace.com) · [John Wonmo Seong](https://github.com/wonmor)). **Proprietary** — see [`LICENSE`](LICENSE) and [`CREDITS.md`](CREDITS.md) for terms, App Store–style attribution, and third-party notices. **Orch Avionic 1 EFB** (promo): [`docs/orch-avionic-efb.md`](docs/orch-avionic-efb.md).
+Credits: **ORCH AEROSPACE** ([orchaerospace.com](https://orchaerospace.com) · [John Wonmo Seong](https://github.com/wonmor)) × **GAME GENESIS** ([itch.io](https://game-genesis.itch.io) · [Rayan Kaissi](https://github.com/rkaissi/)). **Proprietary** — see [`LICENSE`](LICENSE) and [`CREDITS.md`](CREDITS.md) for terms, App Store–style attribution, and third-party notices. **Orch Avionic 1 EFB** (promo): [`docs/orch-avionic-efb.md`](docs/orch-avionic-efb.md).
---
-## Beta build 1.0
+| iOS and iPadOS |
+|:-:|
+| [
](https://apps.apple.com/us/app/first-principles-2d-platformer/id6760980245) |
+
+---
+
+## Screenshots
+
+
+
+
+
+---
+
+## Official Release 1.0
The project pairs a **Cartesian graph UI** (functions + numeric derivatives) with **Limbo-style** gameplay: **platforms** follow the curve and **gaps / hazards** follow derivative rules, with **staged progression** (HUD), **level select**, primer plus **Taylor / Maclaurin / series / multivar** levels, **area-under-the-curve / Riemann sum** stages (left, right, midpoint rectangles + optional stair platforms), an **AP Calculus BC** extension (polar rose/cardioid, logistic, inverse trig, transcendental-tooling levels), **AP Physics C** hooks (decay, projectile, angular momentum / rotation stories), and **aerospace / aerodynamics** stages (lift vs α & stall, drag polar, atmosphere ρ(h), phugoid mood, Newtonian sin²α, Strouhal shedding, re-entry decay envelope), with typography matched to the main equation label. **Mobile / touch:** portrait-oriented scaler, **safe-area** UI, **scrollable** level list, and **on-screen move/jump** controls on handheld / touch builds.
@@ -72,14 +86,6 @@ Topics covered: **Unity 6000.4.0f1** project path (`First Principles/`), **Menu
---
-## Screenshots
-
-
-
-
-
----
-
## Dependencies
- [**Unity**](https://unity.com) **6** (6000.4.0f1)
diff --git a/_MacBuildOut/build.log b/_MacBuildOut/build.log
new file mode 100644
index 0000000..ce36ffb
--- /dev/null
+++ b/_MacBuildOut/build.log
@@ -0,0 +1,30 @@
+Unity Editor version: 6000.4.0f1 (8cf496087c8f)
+Branch: 6000.4/staging
+Build type: Release
+Batch mode: YES
+macOS version: Version 26.3.1 (a) (Build 25D771280a)
+Darwin version: 25.3.0
+Architecture: arm64
+Running under Rosetta: NO
+Available memory: 32768 MB
+Date: 2026-03-23T04:29:19Z
+[Licensing::Module] Trying to connect to existing licensing client channel...
+[Licensing::IpcConnector] Successfully connected to: "LicenseClient-johnseong" at "2026-03-23T04:29:19.671953Z"
+Launching external process: /Applications/Unity/Hub/Editor/6000.4.0f1/Unity.app/Contents/Helpers/PackageManager/Server/UnityPackageManager
+
+COMMAND LINE ARGUMENTS:
+/Applications/Unity/Hub/Editor/6000.4.0f1/Unity.app/Contents/MacOS/Unity
+-batchmode
+-nographics
+-quit
+-projectPath
+/Users/johnseong/Documents/GitHub2/First-Principles/First Principles
+-buildTarget
+StandaloneOSX
+-buildPath
+/Users/johnseong/Documents/GitHub2/First-Principles/_MacBuildOut/First Principles.app
+-logFile
+/Users/johnseong/Documents/GitHub2/First-Principles/_MacBuildOut/build.log
+Successfully changed project path to: /Users/johnseong/Documents/GitHub2/First-Principles/First Principles
+/Users/johnseong/Documents/GitHub2/First-Principles/First Principles
+[Package Manager] Server process was shutdown
diff --git a/docs/gameplay.md b/docs/gameplay.md
index 4448941..153ec39 100644
--- a/docs/gameplay.md
+++ b/docs/gameplay.md
@@ -60,7 +60,7 @@ Legacy **Trans** / **Scale** tuning buttons on the Game UI are **disabled**; tun
## Level flow
-1. **Menu** — Entry and scene fade; footer shows **Credits** (GAME GENESIS × ORCH AEROSPACE), version, proprietary / initiative line, and **Unity** trademark notice ([`CREDITS.md`](../CREDITS.md) for full attribution).
+1. **Menu** — Entry and scene fade; footer shows **Credits** (ORCH AEROSPACE × GAME GENESIS), version, proprietary / initiative line, and **Unity** trademark notice ([`CREDITS.md`](../CREDITS.md) for full attribution).
2. **LevelSelect** — `LevelSelectController` builds a **scrollable** list from **`GameLevelCatalog.DisplayNames`**, plus **Math tips & snippets** (`MathArticlesOverlay` / `LearningArticleLibrary`). Choosing a level calls **`LevelSelection.SetSelectedLevel`** and loads **Game**.
3. **Game** — `LevelManager` reads **`LevelSelection.ConsumeSelectedLevel`**, applies the level theme to **`FunctionPlotter`**, regenerates obstacles, and spawns / resets the player. The **Menu** scene shows title/version + credits (`MenuCreditsBlock` / `SceneCreditsFooter.BuildMenuFooterRichText()` → `menu.version_line` + `menu.credits_line`); gameplay HUD does not duplicate it above the controls hint. Per-level story banners use **`story.N`** from `Localization/LevelStories/{locale}.txt` when present (see `Localization/README.md`).
diff --git a/docs/privacy-policy.md b/docs/privacy-policy.md
index 51b7884..9e08014 100644
--- a/docs/privacy-policy.md
+++ b/docs/privacy-policy.md
@@ -10,7 +10,7 @@ permalink: /privacy-policy/
*This page mirrors the repository root [`privacy-policy.md`](../privacy-policy.md). Update both when the policy changes.*
-This policy describes how the **First Principles** mobile app (the “App”) handles information when you install and use it. The App is developed by **Game Genesis** (Rayan Kaissi) and **Orch Aerospace** (John Wonmo Seong). By using the App, you agree to this policy.
+This policy describes how the **First Principles** mobile app (the “App”) handles information when you install and use it. The App is developed by **Orch Aerospace** (John Wonmo Seong) and **Game Genesis** (Rayan Kaissi). By using the App, you agree to this policy.
If anything here conflicts with **Apple App Store** or **Google Play** terms, the store terms apply for distribution and payments.
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index f5b6a3f..94aa03a 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -62,3 +62,39 @@ If you delete the bootstrap or duplicate `EventSystem` setups in new scenes, ens
If **Package Manager** fails to resolve `com.unity.inputsystem`, open **Window → Package Manager**, select **Input System**, and use the **version Unity recommends** for your editor; then align `Packages/manifest.json` with that version.
If you see **`TypeLoadException` … `InputActionAsset` from assembly `Unity.InputSystem`**, the Input System DLLs in `Library/` are often out of sync: close Unity, delete the project’s **`Library`** folder (and let the editor reimport), or **Reimport** the Input System package. The repo pins a version verified for **Unity 6000.4** (`manifest.json`); adjust if your patch release differs.
+
+## macOS / Mac standalone build fails in a few seconds
+
+**Symptoms:** Console shows **Build completed with a result of 'Failed'** and a stack trace mentioning **`EditorApplication:Internal_CallDelayFunctions`**. That line is only where Unity reported the failure — the **real errors are a few lines above** (red **`error CS…`**, **`BuildFailedException`**, **`IOException`**, missing module, etc.).
+
+**What to do first**
+
+1. Open **Console** (clear it), run **Build** again, and scroll to the **first red error** — copy that full message (and the one after it if it says “2 errors”).
+2. In **Unity Hub** → your **6000.4.x** editor → gear → **Add modules**: enable **Mac Build Support (Mono)** and, if you use IL2CPP for Mac, **Mac Build Support (IL2CPP)**. Without the right module, the build can fail almost immediately.
+3. **Player Settings → Other Settings → Company Name** must not use characters that break **bundle IDs / Info.plist** (e.g. avoid **`;`** in the name). This project uses a plain **`Orch Aerospace and Game Genesis`** style string for that field; full legal attribution stays in **`CREDITS.md`** / **`LICENSE`**.
+4. **Close other Unity instances** using the same project before running a **command-line** build; only one editor may own the `Library` folder at a time.
+
+**CLI build (optional, captures a log)** — quit the Unity Editor for this project, then (adjust the editor path if yours differs):
+
+```bash
+mkdir -p _MacBuildOut
+"/Applications/Unity/Hub/Editor/6000.4.0f1/Unity.app/Contents/MacOS/Unity" \
+ -batchmode -nographics -quit \
+ -projectPath "/path/to/First Principles" \
+ -buildTarget StandaloneOSX \
+ -buildPath "/path/to/_MacBuildOut/First Principles.app" \
+ -logFile "/path/to/_MacBuildOut/build.log"
+tail -100 "/path/to/_MacBuildOut/build.log"
+```
+
+If the log mentions **code signing** or **hardened runtime**, configure **Player Settings → macOS** (signing team, entitlements) for distribution builds; unsigned local builds usually still work for testing on your own Mac.
+
+If the Console shows **`error CS0103: The name 'Handheld' does not exist`**, some script is calling **`UnityEngine.Handheld`** (e.g. **`Handheld.Vibrate()`**), which only exists for **iOS/Android** player builds — not for **Mac / Windows / Linux** standalone. Wrap those calls in **`#if UNITY_ANDROID || UNITY_IOS`** (or remove them on desktop). This project does that for derivative-line haptics in **`PlayerControllerUI2D`**.
+
+## Mac / desktop build feels slow or crashes
+
+**Cause (fixed in repo):** **`FunctionPlotter.Update`** used to run a **full graph resample** (`ComputeGraph` over `[xStart,xEnd]` with step `h`) **every frame** and toggled **`GridRendererUI`** off/on every frame to “refresh” it. On **Retina Macs** that is a huge amount of UI mesh work and can **stutter**, **heat-throttle**, or **OOM / crash**.
+
+**Fix:** Updates now **replot only when** curve parameters change or the **Lorenz** stage is animating; during the **left→right reveal**, only **vertex / fade** refresh runs. The grid is **not** toggled every frame.
+
+If problems remain: lower **Quality** in **Project Settings → Quality** for **Standalone**, close other heavy apps, and capture **`~/Library/Logs/Unity/Player.log`** after a crash for the native stack.
diff --git a/privacy-policy.md b/privacy-policy.md
index c0c89e7..d52723e 100644
--- a/privacy-policy.md
+++ b/privacy-policy.md
@@ -4,7 +4,7 @@
*A copy formatted for **GitHub Pages** lives in [`docs/privacy-policy.md`](docs/privacy-policy.md); keep both files aligned when you edit this policy.*
-This policy describes how the **First Principles** mobile app (the “App”) handles information when you install and use it. The App is developed by **Game Genesis** (Rayan Kaissi) and **Orch Aerospace** (John Wonmo Seong). By using the App, you agree to this policy.
+This policy describes how the **First Principles** mobile app (the “App”) handles information when you install and use it. The App is developed by **Orch Aerospace** (John Wonmo Seong) and **Game Genesis** (Rayan Kaissi). By using the App, you agree to this policy.
If anything here conflicts with **Apple App Store** or **Google Play** terms, the store terms apply for distribution and payments.