Rebrand app as RanaZe Step 3 Trainer

This commit is contained in:
hz
2026-07-20 00:04:29 -05:00
parent 743399f647
commit d176640cff
25 changed files with 206 additions and 92 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
# STEP 3 Arcade
# RanaZe: Step 3 Trainer
Godot study game with a bundled ASP.NET Core Questions API.
Godot-based USMLE Step 3 study trainer with a bundled ASP.NET Core Questions API.
## Local API
@@ -43,8 +43,8 @@ public sealed class StripeDonationGateway(IConfiguration configuration) : IStrip
UnitAmount = amountCents,
ProductData = new SessionLineItemPriceDataProductDataOptions
{
Name = "Support MedMind",
Description = "One-time contribution supporting MedMind development and medical education content."
Name = "Support RanaZe: Step 3 Trainer",
Description = "One-time contribution supporting RanaZe development and medical education content."
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 972 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://vbg5y0aqkray"
path="res://.godot/imported/ranaze-app-icon.png-a240a5596e5240a654bcbed9e8cd6d33.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/branding/ranaze-app-icon.png"
dest_files=["res://.godot/imported/ranaze-app-icon.png-a240a5596e5240a654bcbed9e8cd6d33.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

+40
View File
@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://r26p83m2qj1l"
path="res://.godot/imported/ranaze-mark.png-f1c512eea015b3fe17fffb1aff9edd53.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/branding/ranaze-mark.png"
dest_files=["res://.godot/imported/ranaze-mark.png-f1c512eea015b3fe17fffb1aff9edd53.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
+4 -4
View File
@@ -1,6 +1,6 @@
# Stripe Donations
MedMind accepts authenticated, one-time USD contributions through Stripe-hosted Checkout. The API enforces a minimum contribution of $5 and a maximum of $10,000. Payment card data never passes through or is stored by MedMind.
RanaZe: Step 3 Trainer accepts authenticated, one-time USD contributions through Stripe-hosted Checkout. The API enforces a minimum contribution of $5 and a maximum of $10,000. Payment card data never passes through or is stored by RanaZe.
Contributions are not tax-deductible.
@@ -29,17 +29,17 @@ The deployment workflow writes these values to the Kubernetes secret `medmind-st
## Stripe account settings
Configure MedMind branding in Stripe Checkout and enable successful-payment email receipts in Stripe customer email settings. Stripe Checkout collects the contributor's email address.
Configure RanaZe branding in Stripe Checkout and enable successful-payment email receipts in Stripe customer email settings. Stripe Checkout collects the contributor's email address.
## Verification
After deployment:
1. Sign in to MedMind and open **Support MedMind** from the sidebar.
1. Sign in to RanaZe and open **Support RanaZe** from the sidebar.
2. Confirm that amounts below $5 and above $10,000 are rejected.
3. Start a $5 test contribution.
4. Complete Checkout using Stripe's standard test card `4242 4242 4242 4242`, any future expiration date, and any CVC.
5. Return to MedMind and confirm the contribution changes from pending to confirmed.
5. Return to RanaZe and confirm the contribution changes from pending to confirmed.
6. In Stripe, confirm the Checkout Session and webhook delivery both succeeded.
7. In MongoDB, confirm the corresponding `Donations` document has `Status: "paid"` and a populated `PaidUtc` value.
+1 -1
View File
@@ -22,7 +22,7 @@ vram_texture_compression/for_desktop=true
vram_texture_compression/for_mobile=true
html/export_icon=true
html/custom_html_shell="res://web/medmind_shell.html"
html/head_include="<meta name=\"description\" content=\"MedMind pre-alpha - Think like a physician.\">"
html/head_include="<meta name=\"description\" content=\"RanaZe: Step 3 Trainer pre-alpha - Focused practice for better clinical decisions.\">"
html/canvas_resize_policy=2
html/focus_canvas_on_start=true
html/experimental_virtual_keyboard=false
+4 -2
View File
@@ -10,11 +10,13 @@ config_version=5
[application]
config/name="MedMind"
config/name="RanaZe: Step 3 Trainer"
config/version="pre-alpha"
run/main_scene="res://scenes/main.tscn"
config/features=PackedStringArray("4.6", "GL Compatibility")
config/icon="res://assets/branding/medmind-icon.png"
config/icon="res://assets/branding/ranaze-app-icon.png"
config/use_custom_user_dir=true
config/custom_user_dir_name="MedMind"
[autoload]
+1 -1
View File
@@ -163,7 +163,7 @@ func _on_profile_completed(result: int, response_code: int, _headers: PackedStri
func _save_archive(content: String) -> void:
var filename := "medmind-account-export-%s.json" % Time.get_date_string_from_system()
var filename := "ranaze-account-export-%s.json" % Time.get_date_string_from_system()
if OS.has_feature("web"):
var encoded := Marshalls.raw_to_base64(content.to_utf8_buffer())
JavaScriptBridge.eval("(function(){const a=document.createElement('a');a.href='data:application/json;base64,%s';a.download=%s;document.body.appendChild(a);a.click();a.remove();})();" % [encoded, JSON.stringify(filename)], true)
+1 -1
View File
@@ -140,7 +140,7 @@ func _on_status_completed(result: int, response_code: int, _headers: PackedStrin
func _prepare_browser_window() -> void:
if OS.has_feature("web"):
JavaScriptBridge.eval(
"window.localStorage.removeItem('%s'); window.medmindDonationWindow = window.open('about:blank', 'medmind_donation_checkout'); if (window.medmindDonationWindow) { var medmindWaitingWindow = window.medmindDonationWindow; medmindWaitingWindow.document.title = 'MedMind secure checkout'; medmindWaitingWindow.document.body.innerHTML = '<main id=\"medmind-checkout\" style=\"font:16px system-ui;padding:48px;color:#172033\"><strong>Opening secure checkout...</strong><p>This window will continue to Stripe.</p></main>'; medmindWaitingWindow.setInterval(function () { var checkoutUrl = medmindWaitingWindow.localStorage.getItem('%s'); if (checkoutUrl) { var checkout = medmindWaitingWindow.document.getElementById('medmind-checkout'); checkout.innerHTML = '<strong>Secure checkout is ready.</strong><p><a id=\"medmind-checkout-link\" style=\"color:#2563eb;font-weight:600\">Continue to Stripe</a></p>'; medmindWaitingWindow.document.getElementById('medmind-checkout-link').href = checkoutUrl; medmindWaitingWindow.localStorage.removeItem('%s'); medmindWaitingWindow.location.replace(checkoutUrl); } }, 150); }" % [CHECKOUT_STORAGE_KEY, CHECKOUT_STORAGE_KEY, CHECKOUT_STORAGE_KEY],
"window.localStorage.removeItem('%s'); window.medmindDonationWindow = window.open('about:blank', 'medmind_donation_checkout'); if (window.medmindDonationWindow) { var medmindWaitingWindow = window.medmindDonationWindow; medmindWaitingWindow.document.title = 'RanaZe secure checkout'; medmindWaitingWindow.document.body.innerHTML = '<main id=\"medmind-checkout\" style=\"font:16px system-ui;padding:48px;color:#172033\"><strong>Opening secure checkout...</strong><p>This window will continue to Stripe.</p></main>'; medmindWaitingWindow.setInterval(function () { var checkoutUrl = medmindWaitingWindow.localStorage.getItem('%s'); if (checkoutUrl) { var checkout = medmindWaitingWindow.document.getElementById('medmind-checkout'); checkout.innerHTML = '<strong>Secure checkout is ready.</strong><p><a id=\"medmind-checkout-link\" style=\"color:#2563eb;font-weight:600\">Continue to Stripe</a></p>'; medmindWaitingWindow.document.getElementById('medmind-checkout-link').href = checkoutUrl; medmindWaitingWindow.localStorage.removeItem('%s'); medmindWaitingWindow.location.replace(checkoutUrl); } }, 150); }" % [CHECKOUT_STORAGE_KEY, CHECKOUT_STORAGE_KEY, CHECKOUT_STORAGE_KEY],
true)
+3 -3
View File
@@ -51,7 +51,7 @@ func _build_ui() -> void:
scroll.add_child(page)
var title := Label.new()
title.text = "Support MedMind"
title.text = "Support RanaZe"
title.add_theme_font_override("font", Brand.font)
title.add_theme_font_size_override("font_size", 36)
page.add_child(title)
@@ -79,7 +79,7 @@ func _build_ui() -> void:
mission.add_theme_constant_override("separation", 18)
mission_panel.add_child(mission)
mission.add_child(_heading("Our mission", 26))
mission.add_child(_body("MedMind exists to make rigorous, clinically grounded medical education more accessible. We are building an independent Step 3 study experience that helps learners develop clinical judgment through original questions, realistic CCS cases, transparent explanations, and continuous improvement driven by learner feedback."))
mission.add_child(_body("RanaZe exists to make rigorous, clinically grounded medical education more accessible. We are building an independent Step 3 study experience that helps learners develop clinical judgment through original questions, realistic CCS cases, transparent explanations, and continuous improvement driven by learner feedback."))
mission.add_child(HSeparator.new())
mission.add_child(_heading("What your support makes possible", 20))
for item_text in [
@@ -215,7 +215,7 @@ func _on_checkout_started(_donation_id: String, _checkout_url: String) -> void:
func _on_donation_status_changed(status: String, _donation: Dictionary) -> void:
match status:
"paid": _set_validation_state("Thank you for supporting MedMind. Your contribution has been confirmed.", false, Brand.SUCCESS)
"paid": _set_validation_state("Thank you for supporting RanaZe. Your contribution has been confirmed.", false, Brand.SUCCESS)
"failed": _set_validation_state("Stripe could not complete the contribution. No payment was confirmed.", true)
"expired": _set_validation_state("The checkout session expired. Start a new checkout when you are ready.", true)
+36 -25
View File
@@ -126,27 +126,37 @@ func _build_ui() -> void:
brand_row.add_theme_constant_override("separation", 24)
left_brand.add_child(brand_row)
var large_icon := TextureRect.new()
large_icon.texture = preload("res://assets/branding/medmind-icon.png")
large_icon.texture = Brand.ranaze_mark_texture()
large_icon.custom_minimum_size = Vector2(190, 190)
large_icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
large_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
large_icon.material = Brand.logo_cutout_material()
brand_row.add_child(large_icon)
var wordmark := HBoxContainer.new()
wordmark.add_theme_constant_override("separation", 0)
var wordmark := VBoxContainer.new()
wordmark.add_theme_constant_override("separation", 4)
brand_row.add_child(wordmark)
var med_wordmark := Label.new()
med_wordmark.text = "Med"
med_wordmark.add_theme_font_size_override("font_size", 76)
med_wordmark.add_theme_font_override("font", Brand.font)
wordmark.add_child(med_wordmark)
var mind_wordmark := Label.new()
mind_wordmark.text = "Mind"
mind_wordmark.add_theme_font_size_override("font_size", 76)
mind_wordmark.add_theme_font_override("font", Brand.font)
mind_wordmark.add_theme_color_override("font_color", Brand.PURPLE)
mind_wordmark.set_meta("brand_accent", true)
wordmark.add_child(mind_wordmark)
var name_row := HBoxContainer.new()
name_row.add_theme_constant_override("separation", 0)
wordmark.add_child(name_row)
var rana_wordmark := Label.new()
rana_wordmark.text = "Rana"
rana_wordmark.add_theme_font_size_override("font_size", 76)
rana_wordmark.add_theme_font_override("font", Brand.font)
name_row.add_child(rana_wordmark)
var ze_wordmark := Label.new()
ze_wordmark.text = "Ze"
ze_wordmark.add_theme_font_size_override("font_size", 76)
ze_wordmark.add_theme_font_override("font", Brand.font)
ze_wordmark.add_theme_color_override("font_color", Brand.SKY_BLUE)
ze_wordmark.set_meta("brand_accent", true)
name_row.add_child(ze_wordmark)
var trainer_wordmark := Label.new()
trainer_wordmark.text = "STEP 3 TRAINER"
trainer_wordmark.add_theme_font_size_override("font_size", 22)
trainer_wordmark.add_theme_font_override("font", Brand.font)
trainer_wordmark.add_theme_color_override("font_color", Brand.muted_color(true))
trainer_wordmark.set_meta("brand_subtitle", true)
trainer_wordmark.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
wordmark.add_child(trainer_wordmark)
brand_tagline = RichTextLabel.new()
brand_tagline.bbcode_enabled = true
brand_tagline.fit_content = true
@@ -177,11 +187,10 @@ func _build_ui() -> void:
panel_header.add_theme_constant_override("separation", 18)
panel_content.add_child(panel_header)
var small_icon := TextureRect.new()
small_icon.texture = preload("res://assets/branding/medmind-icon.png")
small_icon.texture = Brand.ranaze_mark_texture()
small_icon.custom_minimum_size = Vector2(72, 72)
small_icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
small_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
small_icon.material = Brand.logo_cutout_material()
panel_header.add_child(small_icon)
var titles := VBoxContainer.new()
titles.size_flags_horizontal = Control.SIZE_EXPAND_FILL
@@ -231,7 +240,7 @@ func _build_login_view() -> VBoxContainer:
view.add_child(steam)
submit_buttons.append(steam)
var create := Button.new()
create.text = "New to MedMind? Create an account"
create.text = "New to RanaZe? Create an account"
create.flat = true
create.pressed.connect(func(): _set_mode("register"))
view.add_child(create)
@@ -272,12 +281,12 @@ func _build_reset_view() -> VBoxContainer:
func _build_steam_view() -> VBoxContainer:
var view := _new_form()
var help := Label.new()
help.text = "Steam was verified. Create a MedMind account or link an existing one."
help.text = "Steam was verified. Create a RanaZe account or link an existing one."
help.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
view.add_child(help)
steam_action = OptionButton.new()
steam_action.add_item("Create a new MedMind account")
steam_action.add_item("Link an existing MedMind account")
steam_action.add_item("Create a new RanaZe account")
steam_action.add_item("Link an existing RanaZe account")
steam_action.item_selected.connect(_on_steam_action_changed)
view.add_child(steam_action)
steam_username_input = _add_field(view, "Username or email", "Choose a username")
@@ -405,9 +414,9 @@ func _set_mode(next_mode: String) -> void:
reset_view.visible = mode == "reset"
steam_view.visible = mode == "steam"
match mode:
"register": heading.text = "Create your account"; subheading.text = "Start studying with MedMind"
"register": heading.text = "Create your account"; subheading.text = "Start studying with RanaZe"
"reset": heading.text = "Reset your password"; subheading.text = "We will email you a verification code"
"steam": heading.text = "Finish Steam sign in"; subheading.text = "Connect Steam to MedMind"
"steam": heading.text = "Finish Steam sign in"; subheading.text = "Connect Steam to RanaZe"
_: heading.text = "Welcome back"; subheading.text = "Sign in to continue"
_clear_message()
_update_responsive_layout()
@@ -467,7 +476,9 @@ func _apply_theme() -> void:
for node in find_children("*", "Label", true, false):
var label := node as Label
if label.has_meta("brand_accent"):
label.add_theme_color_override("font_color", Brand.PURPLE if dark else Brand.ROYAL_BLUE)
label.add_theme_color_override("font_color", Brand.SKY_BLUE if dark else Brand.ROYAL_BLUE)
elif label.has_meta("brand_subtitle"):
label.add_theme_color_override("font_color", Brand.muted_color(dark))
else:
label.add_theme_color_override("font_color", Brand.text_color(dark))
for input in fields:
+14 -15
View File
@@ -358,8 +358,7 @@ func _populate_navigation(container: VBoxContainer, include_brand: bool) -> void
brand_row.add_theme_constant_override("separation", 10)
container.add_child(brand_row)
var mark := TextureRect.new()
mark.texture = preload("res://assets/branding/medmind-icon.png")
mark.material = Brand.logo_cutout_material()
mark.texture = Brand.ranaze_mark_texture()
mark.custom_minimum_size = Vector2(46, 46)
mark.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
mark.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
@@ -367,17 +366,17 @@ func _populate_navigation(container: VBoxContainer, include_brand: bool) -> void
var wordmark := HBoxContainer.new()
wordmark.add_theme_constant_override("separation", 0)
brand_row.add_child(wordmark)
var med := Label.new()
med.text = "Med"
med.add_theme_font_override("font", Brand.font)
med.add_theme_font_size_override("font_size", 27)
wordmark.add_child(med)
var mind := Label.new()
mind.text = "Mind"
mind.add_theme_font_override("font", Brand.font)
mind.add_theme_font_size_override("font_size", 27)
mind.add_theme_color_override("font_color", Brand.PURPLE)
wordmark.add_child(mind)
var rana := Label.new()
rana.text = "Rana"
rana.add_theme_font_override("font", Brand.font)
rana.add_theme_font_size_override("font_size", 27)
wordmark.add_child(rana)
var ze := Label.new()
ze.text = "Ze"
ze.add_theme_font_override("font", Brand.font)
ze.add_theme_font_size_override("font_size", 27)
ze.add_theme_color_override("font_color", Brand.SKY_BLUE)
wordmark.add_child(ze)
container.add_child(HSeparator.new())
_add_nav_button(container, "home", "Dashboard", "chart-no-axes-column-increasing", true)
@@ -391,7 +390,7 @@ func _populate_navigation(container: VBoxContainer, include_brand: bool) -> void
spacer.size_flags_vertical = Control.SIZE_EXPAND_FILL
container.add_child(spacer)
container.add_child(HSeparator.new())
_add_nav_button(container, "donations", "Support MedMind", "heart-pulse", true)
_add_nav_button(container, "donations", "Support RanaZe", "heart-pulse", true)
_add_nav_button(container, "performance", "Profile", "user-round", true)
_add_nav_button(container, "settings", "Settings", "settings", true)
_add_nav_button(container, "logout", "Log out", "log-out", true)
@@ -448,7 +447,7 @@ func _update_header_title(screen_name: String) -> void:
"settings": "Settings",
"notes": "Notes",
"bookmarks": "Bookmarks",
"donations": "Support MedMind"
"donations": "Support RanaZe"
}
header_title.text = str(titles.get(screen_name, ""))
+13 -6
View File
@@ -3,9 +3,9 @@ extends RefCounted
const DEEP_NAVY := Color("0b1324")
const ROYAL_BLUE := Color("2563eb")
const SKY_BLUE := Color("38bdf8")
const PURPLE := Color("7c3aed")
const MAGENTA := Color("d946ef")
const TEAL := Color("14b8a6")
const PURPLE := Color("1d4ed8")
const MAGENTA := Color("ef4444")
const TEAL := Color("38bdf8")
const SUCCESS := Color("22c55e")
const AMBER := Color("f59e0b")
const SUN_ICON := preload("res://assets/icons/lucide/sun.svg")
@@ -22,6 +22,13 @@ const LIGHT_MUTED := Color("64748b")
static var font: Font = preload("res://assets/fonts/Inter-Variable.ttf")
static func ranaze_mark_texture() -> AtlasTexture:
var texture := AtlasTexture.new()
texture.atlas = preload("res://assets/branding/ranaze-mark.png")
texture.region = Rect2(400, 150, 736, 736)
return texture
static func text_color(dark: bool) -> Color:
return DARK_TEXT if dark else LIGHT_TEXT
@@ -45,8 +52,8 @@ void fragment() {
vec3 base = dark_mode ? vec3(0.018, 0.043, 0.090) : vec3(0.965, 0.975, 0.990);
float left_glow = 1.0 - smoothstep(0.0, 0.58, distance(uv, vec2(-0.02, 0.12)));
float right_glow = 1.0 - smoothstep(0.0, 0.58, distance(uv, vec2(1.02, 0.92)));
vec3 blue = dark_mode ? vec3(0.075, 0.055, 0.35) : vec3(0.70, 0.80, 1.0);
vec3 purple = dark_mode ? vec3(0.18, 0.035, 0.52) : vec3(0.86, 0.78, 1.0);
vec3 blue = dark_mode ? vec3(0.035, 0.16, 0.42) : vec3(0.70, 0.84, 1.0);
vec3 purple = dark_mode ? vec3(0.02, 0.28, 0.55) : vec3(0.76, 0.90, 1.0);
vec3 color = base + blue * left_glow * (dark_mode ? 0.55 : 0.28);
color += purple * right_glow * (dark_mode ? 0.62 : 0.12);
COLOR = vec4(color, 1.0);
@@ -155,7 +162,7 @@ static func badge_box(dark: bool, accent: Color) -> StyleBoxFlat:
static func gradient_button_box() -> StyleBoxTexture:
var gradient := Gradient.new()
gradient.colors = PackedColorArray([Color("1677ff"), Color("8f3ff4")])
gradient.colors = PackedColorArray([ROYAL_BLUE, SKY_BLUE])
var texture := GradientTexture2D.new()
texture.gradient = gradient
texture.width = 512
+3 -3
View File
@@ -90,7 +90,7 @@ func _build() -> void:
func _profile_summary_card() -> PanelContainer:
var body := VBoxContainer.new()
body.add_theme_constant_override("separation", 14)
body.add_child(_section_header("Profile Summary", "Your MedMind account"))
body.add_child(_section_header("Profile Summary", "Your RanaZe account"))
var row := HBoxContainer.new()
row.add_theme_constant_override("separation", 18)
var avatar := PanelContainer.new()
@@ -147,7 +147,7 @@ func _study_identity_card() -> PanelContainer:
func _performance_card() -> PanelContainer:
var body := VBoxContainer.new()
body.add_theme_constant_override("separation", 12)
body.add_child(_section_header("Performance Summary", "Your cumulative MedMind activity"))
body.add_child(_section_header("Performance Summary", "Your cumulative RanaZe activity"))
var grid := GridContainer.new()
grid.columns = 3
grid.add_theme_constant_override("h_separation", 10)
@@ -361,7 +361,7 @@ func _open_password_dialog() -> void:
func _open_delete_dialog() -> void:
var dialog := _dialog("Permanently delete account")
var warning := _label("This permanently removes your account and all MedMind study data. This cannot be undone.", 13, Brand.MAGENTA)
var warning := _label("This permanently removes your account and all RanaZe study data. This cannot be undone.", 13, Brand.MAGENTA)
warning.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
dialog.add_field(warning)
var password := _password_field("Current password")
+1 -1
View File
@@ -25,7 +25,7 @@ func _ready() -> void:
add_child(title)
var subtitle := Label.new()
subtitle.text = "Adjust MedMind's appearance and interface sounds."
subtitle.text = "Adjust RanaZe's appearance and interface sounds."
subtitle.add_theme_font_override("font", Brand.font)
subtitle.add_theme_font_size_override("font_size", 17)
subtitle.add_theme_color_override("font_color", Brand.SLATE)
+1 -1
View File
@@ -19,7 +19,7 @@ func _initialize() -> void:
_assert(NavigationRoutes.key_for_screen("settings") == "settings", "settings should activate Settings")
_assert(NavigationRoutes.key_for_screen("notes") == "notes", "notes should activate Notes")
_assert(NavigationRoutes.key_for_screen("bookmarks") == "bookmarks", "bookmarks should activate Bookmarks")
_assert(NavigationRoutes.key_for_screen("donations") == "donations", "donations should activate Support MedMind")
_assert(NavigationRoutes.key_for_screen("donations") == "donations", "donations should activate Support RanaZe")
quit(1 if failures > 0 else 0)
+5 -2
View File
@@ -7,6 +7,9 @@ var failures := 0
func _initialize() -> void:
_assert(ProjectSettings.get_setting("application/config/name") == "RanaZe: Step 3 Trainer", "the public application name should use the RanaZe brand")
_assert(bool(ProjectSettings.get_setting("application/config/use_custom_user_dir")), "the rebrand should preserve a stable custom user-data directory")
_assert(ProjectSettings.get_setting("application/config/custom_user_dir_name") == "MedMind", "existing standalone user data should remain discoverable after the rebrand")
Style.set_dark_mode(true)
var root := Control.new()
var background := ColorRect.new()
@@ -22,9 +25,9 @@ func _initialize() -> void:
_assert(root.theme.get_color("default_color", "RichTextLabel").is_equal_approx(Style.TEXT), "rich text should use the light text color")
var light_box := panel.get_theme_stylebox("panel") as StyleBoxFlat
_assert(light_box.bg_color.is_equal_approx(Color("fffffe")), "custom panel surface should switch to light mode")
_assert(Brand.background_color(false).is_equal_approx(Color("f1f5f9")), "MedMind light background should match the style guide")
_assert(Brand.background_color(false).is_equal_approx(Color("f1f5f9")), "RanaZe light background should match the style guide")
var light_card := Brand.content_card_box(false, true, Brand.ROYAL_BLUE)
_assert(light_card.bg_color.is_equal_approx(Color.WHITE), "MedMind light cards should use white surfaces")
_assert(light_card.bg_color.is_equal_approx(Color.WHITE), "RanaZe light cards should use white surfaces")
_assert(light_card.border_color.is_equal_approx(Brand.ROYAL_BLUE), "active light cards should use the primary blue border")
var light_field := Brand.field_box(false)
_assert(light_field.border_color.is_equal_approx(Brand.LIGHT_BORDER), "light fields should use the semantic cool-gray border")
+1 -1
View File
@@ -75,7 +75,7 @@ func _run() -> void:
var profile_nav := main_screen.sidebar.find_child("NavPerformance", true, false) as Button
var settings_nav := main_screen.sidebar.find_child("NavSettings", true, false) as Button
var donation_nav := main_screen.sidebar.find_child("NavDonations", true, false) as Button
_assert(donation_nav != null and donation_nav.text == "Support MedMind", "the shell should expose donation navigation")
_assert(donation_nav != null and donation_nav.text == "Support RanaZe", "the shell should expose donation navigation")
_assert(profile_nav != null and settings_nav != null and profile_nav.get_index() + 1 == settings_nav.get_index(), "Profile should sit directly above Settings in the lower navigation group")
var theme_service = root.get_node("UIThemeService")
var prior_dark_mode: bool = theme_service.is_dark_mode()
+2 -2
View File
@@ -33,12 +33,12 @@ RUN mkdir -p /build \
&& sed -i "s|custom_template/release=\"\"|custom_template/release=\"/root/.local/share/godot/export_templates/${GODOT_TEMPLATE_DIR}/web_nothreads_release.zip\"|" export_presets.cfg \
&& godot --headless --editor --path /src --quit \
&& godot --verbose --headless --path /src --export-release Web /build/index.html \
&& cp /src/assets/branding/medmind-loader-mark.png /build/medmind-loader-icon.png \
&& cp /src/assets/branding/ranaze-mark.png /build/ranaze-loader-icon.png \
&& cp /src/assets/fonts/Inter-Variable.ttf /build/medmind-inter.ttf \
&& cp /src/web/donation-complete.html /build/donation-complete.html \
&& cp /src/web/donation-canceled.html /build/donation-canceled.html \
&& test -s /build/index.html \
&& test -s /build/medmind-loader-icon.png \
&& test -s /build/ranaze-loader-icon.png \
&& test -s /build/medmind-inter.ttf \
&& test -s /build/donation-complete.html \
&& test -s /build/donation-canceled.html \
+2 -2
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Checkout canceled | MedMind</title>
<title>Checkout canceled | RanaZe</title>
<style>
@font-face{font-family:Inter;src:url('/medmind-inter.ttf') format('truetype');font-display:swap}
:root{color-scheme:dark light;--bg:#071224;--surface:#0b1427;--border:#33415d;--text:#f8fafc;--muted:#a9b5ca;--accent:#38bdf8}
@@ -15,5 +15,5 @@
</style>
</head>
<script>try{document.documentElement.dataset.theme=localStorage.getItem('medmind-color-scheme')||''}catch(e){}</script>
<body><main><img src="/medmind-loader-icon.png" alt="MedMind"><h1>Checkout canceled</h1><p>No contribution was completed. You can close this tab and return to MedMind.</p></main></body>
<body><main><img src="/ranaze-loader-icon.png" alt="RanaZe"><h1>Checkout canceled</h1><p>No contribution was completed. You can close this tab and return to RanaZe.</p></main></body>
</html>
+2 -2
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Contribution received | MedMind</title>
<title>Contribution received | RanaZe</title>
<style>
@font-face{font-family:Inter;src:url('/medmind-inter.ttf') format('truetype');font-display:swap}
:root{color-scheme:dark light;--bg:#071224;--surface:#0b1427;--border:#33415d;--text:#f8fafc;--muted:#a9b5ca;--accent:#38bdf8;--success:#22c55e}
@@ -15,5 +15,5 @@
</style>
</head>
<script>try{document.documentElement.dataset.theme=localStorage.getItem('medmind-color-scheme')||''}catch(e){}</script>
<body><main><img src="/medmind-loader-icon.png" alt="MedMind"><h1>Thank you for supporting MedMind</h1><p class="status">Your checkout is complete.</p><p>You can close this tab and return to MedMind. Stripe will send your receipt by email.</p></main></body>
<body><main><img src="/ranaze-loader-icon.png" alt="RanaZe"><h1>Thank you for supporting RanaZe</h1><p class="status">Your checkout is complete.</p><p>You can close this tab and return to RanaZe. Stripe will send your receipt by email.</p></main></body>
</html>
+27 -15
View File
@@ -32,7 +32,7 @@
:root {
color-scheme: light;
--background: #f8faff;
--background-accent: rgba(124, 58, 237, 0.12);
--background-accent: rgba(56, 189, 248, 0.12);
--background-accent-secondary: rgba(37, 99, 235, 0.08);
--dot: rgba(99, 102, 241, 0.26);
--brand-dark: #0b1324;
@@ -46,7 +46,7 @@
:root[data-theme="dark"] {
color-scheme: dark;
--background: #020b1d;
--background-accent: rgba(124, 58, 237, 0.3);
--background-accent: rgba(37, 99, 235, 0.3);
--background-accent-secondary: rgba(37, 99, 235, 0.18);
--dot: rgba(61, 91, 210, 0.68);
--brand-dark: #f8fafc;
@@ -141,19 +141,19 @@
}
.corner-accent--top {
background: radial-gradient(circle at 35% 65%, rgba(124, 58, 237, 0.04), rgba(99, 102, 241, 0.13));
background: radial-gradient(circle at 35% 65%, rgba(56, 189, 248, 0.04), rgba(37, 99, 235, 0.13));
right: max(-150px, -10vw);
top: max(-180px, -13vw);
}
.corner-accent--bottom {
background: radial-gradient(circle at 65% 35%, rgba(124, 58, 237, 0.02), rgba(99, 102, 241, 0.1));
background: radial-gradient(circle at 65% 35%, rgba(56, 189, 248, 0.02), rgba(37, 99, 235, 0.1));
bottom: max(-210px, -16vw);
left: max(-180px, -13vw);
}
:root[data-theme="dark"] .corner-accent--top {
background: radial-gradient(circle at 30% 70%, rgba(124, 58, 237, 0.18), rgba(49, 46, 129, 0.72));
background: radial-gradient(circle at 30% 70%, rgba(56, 189, 248, 0.18), rgba(30, 64, 175, 0.72));
}
:root[data-theme="dark"] .corner-accent--bottom {
@@ -162,6 +162,7 @@
.loader-logo-wrap {
height: clamp(112px, 16vw, 154px);
overflow: hidden;
position: relative;
width: clamp(112px, 16vw, 154px);
}
@@ -170,6 +171,7 @@
display: block;
height: 100%;
object-fit: contain;
transform: scale(2.1);
width: 100%;
}
@@ -181,17 +183,26 @@
margin: 12px 0 0;
}
.wordmark-med {
.wordmark-rana {
color: var(--brand-dark);
}
.wordmark-mind {
background: linear-gradient(90deg, #2563eb 0%, #7c3aed 58%, #d946ef 100%);
.wordmark-ze {
background: linear-gradient(90deg, #2563eb 0%, #38bdf8 100%);
background-clip: text;
color: transparent;
-webkit-background-clip: text;
}
.wordmark-trainer {
color: var(--muted);
display: block;
font-size: 0.27em;
font-weight: 650;
letter-spacing: 0.12em;
margin-top: 14px;
}
.loader-tagline {
color: var(--muted);
font-size: clamp(20px, 2.3vw, 28px);
@@ -216,7 +227,7 @@
}
.progress-value {
background: linear-gradient(90deg, #2563eb 0%, #7c3aed 60%, #a855f7 100%);
background: linear-gradient(90deg, #2563eb 0%, #38bdf8 100%);
border-radius: inherit;
height: 100%;
transform-origin: left center;
@@ -309,13 +320,14 @@
<div class="corner-accent corner-accent--bottom"></div>
<div class="loader">
<div class="loader-logo-wrap">
<img class="loader-logo" src="medmind-loader-icon.png" alt="MedMind">
<img class="loader-logo" src="ranaze-loader-icon.png" alt="RanaZe">
</div>
<div class="loader-wordmark" aria-label="MedMind">
<span class="wordmark-med">Med</span><span class="wordmark-mind">Mind</span>
<div class="loader-wordmark" aria-label="RanaZe: Step 3 Trainer">
<span class="wordmark-rana">Rana</span><span class="wordmark-ze">Ze</span>
<span class="wordmark-trainer">STEP 3 TRAINER</span>
</div>
<p class="loader-tagline">Think like a physician.</p>
<div id="status-progress" class="progress-row" role="progressbar" aria-label="Loading MedMind" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
<p class="loader-tagline">Focused practice. Better clinical decisions.</p>
<div id="status-progress" class="progress-row" role="progressbar" aria-label="Loading RanaZe" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
<div class="progress-track"><div id="status-progress-value" class="progress-value"></div></div>
<span id="status-progress-percent" class="progress-percent">0%</span>
</div>
@@ -357,7 +369,7 @@
? error.message
: (typeof error === 'string' ? error : 'An unknown error occurred.');
statusProgress.style.display = 'none';
statusMessage.textContent = 'MedMind could not finish loading.';
statusMessage.textContent = 'RanaZe could not finish loading.';
statusNotice.textContent = message;
statusNotice.style.display = 'block';
initializing = false;
+1 -1
View File
@@ -43,7 +43,7 @@ server {
# Godot exports reuse these filenames across releases. Revalidate them so a
# newly deployed index never boots an older cached project package.
location ~ ^/(index\.(js|pck|wasm)|medmind-loader-icon\.png|medmind-inter\.ttf)$ {
location ~ ^/(index\.(js|pck|wasm)|ranaze-loader-icon\.png|medmind-inter\.ttf)$ {
add_header Cache-Control "no-cache, no-store, must-revalidate" always;
add_header X-Content-Type-Options "nosniff" always;
try_files $uri =404;