Consolidate project documentation and attribution

Add public-alias credits and a tested in-game credits page, centralize project guidance and asset provenance, import the complete authored fur channel maps, and keep starter-island collision synchronized with imported props.
This commit is contained in:
Alexander Sellite 2026-08-12 22:12:11 -04:00
parent 1940ae13e5
commit db6074ddfa
59 changed files with 1638 additions and 1032 deletions

View file

@ -1,26 +0,0 @@
# Bubble menu authoring
Instance `bubble_button.tscn` for each action, or attach `bubble_button.gd`
to an existing Button. Set its neutral size, desktop and compact anchors,
font-size limits, and deterministic motion values in the Inspector. A label
child can be assigned through `label_control_path` when wrapped text is needed.
Text size is calculated once per layout from the neutral smaller dimension and
the profile ratio.
Place the buttons under a Control using `bubble_cluster.gd`. Give the cluster
the ordered BubbleButton references with `configure()`, then call
`apply_layout()` when its available size or responsive layout changes. The
button order defines explicit keyboard and controller focus neighbors. Compact
anchors and minimum sizes remain authored per button.
The shared profile owns the palette, rounded styles, proportional-font ratio,
hover response, and contact tuning. Labels, actions, sizes, anchors, per-button
motion, responsive wrapping, availability, and confirmation behavior remain
owned by the menu. Connect each Button's `pressed` signal in that parent menu.
`motion_scale` defaults to `1.0`. Setting it to `0.0` removes idle drift and
deformation while retaining hover and focus feedback.
Contact is a deterministic, bounded visual correction around authored anchors.
Real physics is intentionally avoided so layouts, focus order, and hit targets
remain stable.

87
ui/title_credits_page.gd Normal file
View file

@ -0,0 +1,87 @@
class_name TitleCreditsPage
extends Control
signal back_requested(restore_navigation_focus: bool)
@onready var _paper: PanelContainer = %Paper
@onready var _back_button: Button = %CreditsBackButton
var _navigation_focus_active: bool = false
func _ready() -> void:
UtilityPageStyle.apply_page(self)
_paper.add_theme_stylebox_override(
"panel", UtilityPageStyle.panel_style()
)
UtilityPageStyle.apply_ocean_button(_back_button)
_back_button.pressed.connect(_request_back)
hide()
func open_page(use_navigation_focus: bool) -> void:
_navigation_focus_active = use_navigation_focus
show()
UtilityPageStyle.animate_in(self)
if use_navigation_focus:
call_deferred("_focus_back")
else:
_release_page_focus()
func close_page() -> void:
_navigation_focus_active = false
_release_page_focus()
hide()
scale = Vector2.ONE
modulate.a = 1.0
func handle_input(event: InputEvent) -> bool:
if not visible:
return false
if event is InputEventMouseMotion:
_navigation_focus_active = false
_release_page_focus()
return false
if event is InputEventKey and (event as InputEventKey).echo:
return false
var moves_focus: bool = (
event.is_action_pressed("ui_up")
or event.is_action_pressed("ui_down")
or event.is_action_pressed("ui_left")
or event.is_action_pressed("ui_right")
)
if moves_focus:
_navigation_focus_active = true
if not _page_has_focus():
_back_button.grab_focus()
return true
if event.is_action_pressed("ui_cancel"):
_request_back()
return true
return false
func get_back_button() -> Button:
return _back_button
func _focus_back() -> void:
if visible and _navigation_focus_active:
_back_button.grab_focus()
func _request_back() -> void:
back_requested.emit(_navigation_focus_active)
func _page_has_focus() -> bool:
var focus_owner: Control = get_viewport().gui_get_focus_owner()
return focus_owner != null and is_ancestor_of(focus_owner)
func _release_page_focus() -> void:
var focus_owner: Control = get_viewport().gui_get_focus_owner()
if focus_owner != null and is_ancestor_of(focus_owner):
focus_owner.release_focus()

View file

@ -0,0 +1 @@
uid://c07nehcd5yw6m

180
ui/title_credits_page.tscn Normal file
View file

@ -0,0 +1,180 @@
[gd_scene load_steps=3 format=3]
[ext_resource type="Script" path="res://ui/title_credits_page.gd" id="1_script"]
[ext_resource type="Theme" path="res://ui/game_theme.tres" id="2_theme"]
[node name="TitleCreditsPage" type="Control"]
visible = false
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
theme = ExtResource("2_theme")
script = ExtResource("1_script")
[node name="Paper" type="PanelContainer" parent="."]
unique_name_in_owner = true
layout_mode = 0
offset_left = 160.0
offset_top = 38.0
offset_right = 1120.0
offset_bottom = 682.0
[node name="Margin" type="MarginContainer" parent="Paper"]
layout_mode = 2
theme_override_constants/margin_left = 52
theme_override_constants/margin_top = 26
theme_override_constants/margin_right = 52
theme_override_constants/margin_bottom = 24
[node name="Layout" type="VBoxContainer" parent="Paper/Margin"]
layout_mode = 2
theme_override_constants/separation = 10
[node name="Title" type="Label" parent="Paper/Margin/Layout"]
layout_mode = 2
theme_override_colors/font_color = Color(0.902, 0.969, 0.969, 1)
theme_override_font_sizes/font_size = 36
text = "credits"
horizontal_alignment = 1
[node name="Subtitle" type="Label" parent="Paper/Margin/Layout"]
layout_mode = 2
theme_override_colors/font_color = Color(0.624, 0.812, 0.824, 1)
theme_override_font_sizes/font_size = 18
text = "NETfishing is created by Woofmeow"
horizontal_alignment = 1
[node name="Columns" type="HBoxContainer" parent="Paper/Margin/Layout"]
layout_mode = 2
size_flags_vertical = 3
theme_override_constants/separation = 52
[node name="CreativeCredits" type="VBoxContainer" parent="Paper/Margin/Layout/Columns"]
custom_minimum_size = Vector2(404, 0)
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/separation = 5
[node name="CreativeHeading" type="Label" parent="Paper/Margin/Layout/Columns/CreativeCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.902, 0.969, 0.969, 1)
theme_override_font_sizes/font_size = 23
text = "creative team"
[node name="VoyagerName" type="Label" parent="Paper/Margin/Layout/Columns/CreativeCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.902, 0.969, 0.969, 1)
theme_override_font_sizes/font_size = 18
text = "Voyager"
[node name="VoyagerRoles" type="Label" parent="Paper/Margin/Layout/Columns/CreativeCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.624, 0.812, 0.824, 1)
theme_override_font_sizes/font_size = 15
text = "co-owner • development • project direction • 3d art • music"
autowrap_mode = 2
[node name="EndeavourName" type="Label" parent="Paper/Margin/Layout/Columns/CreativeCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.902, 0.969, 0.969, 1)
theme_override_font_sizes/font_size = 18
text = "Endeavour"
[node name="EndeavourRoles" type="Label" parent="Paper/Margin/Layout/Columns/CreativeCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.624, 0.812, 0.824, 1)
theme_override_font_sizes/font_size = 15
text = "co-owner • development • 2d art"
autowrap_mode = 2
[node name="ContributorSpacer" type="Control" parent="Paper/Margin/Layout/Columns/CreativeCredits"]
custom_minimum_size = Vector2(0, 9)
layout_mode = 2
[node name="ContributorHeading" type="Label" parent="Paper/Margin/Layout/Columns/CreativeCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.902, 0.969, 0.969, 1)
theme_override_font_sizes/font_size = 23
text = "additional contributors"
[node name="ChillnfillName" type="Label" parent="Paper/Margin/Layout/Columns/CreativeCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.902, 0.969, 0.969, 1)
theme_override_font_sizes/font_size = 18
text = "chillnfill"
[node name="ChillnfillCredit" type="Label" parent="Paper/Margin/Layout/Columns/CreativeCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.624, 0.812, 0.824, 1)
theme_override_font_sizes/font_size = 15
text = "original 3d models for character bodies and arms, ears and tails, and multiple world props and decorative assets including trees and bridges"
autowrap_mode = 2
[node name="TekgatorName" type="Label" parent="Paper/Margin/Layout/Columns/CreativeCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.902, 0.969, 0.969, 1)
theme_override_font_sizes/font_size = 18
text = "Tekgator"
[node name="TekgatorCredit" type="Label" parent="Paper/Margin/Layout/Columns/CreativeCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.624, 0.812, 0.824, 1)
theme_override_font_sizes/font_size = 15
text = "cooler-capacity and barrier-power shop icon artwork"
autowrap_mode = 2
[node name="AdditionalCredits" type="VBoxContainer" parent="Paper/Margin/Layout/Columns"]
custom_minimum_size = Vector2(404, 0)
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/separation = 5
[node name="AudioHeading" type="Label" parent="Paper/Margin/Layout/Columns/AdditionalCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.902, 0.969, 0.969, 1)
theme_override_font_sizes/font_size = 23
text = "additional audio"
[node name="AudioCredits" type="Label" parent="Paper/Margin/Layout/Columns/AdditionalCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.624, 0.812, 0.824, 1)
theme_override_font_sizes/font_size = 15
text = "tosha73 • fishing reel sounds\nkkenny101 • ocean ambience\nqubodup • water impact\nAyton • rain ambience\nivolipa • dog bark\nChristyboy100 • cat meow"
[node name="TechnologySpacer" type="Control" parent="Paper/Margin/Layout/Columns/AdditionalCredits"]
custom_minimum_size = Vector2(0, 9)
layout_mode = 2
[node name="TechnologyHeading" type="Label" parent="Paper/Margin/Layout/Columns/AdditionalCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.902, 0.969, 0.969, 1)
theme_override_font_sizes/font_size = 23
text = "fonts & technology"
[node name="TechnologyCredits" type="Label" parent="Paper/Margin/Layout/Columns/AdditionalCredits"]
layout_mode = 2
theme_override_colors/font_color = Color(0.624, 0.812, 0.824, 1)
theme_override_font_sizes/font_size = 15
text = "Tuffy • Thatcher Ulrich, Karoly Barta & Michael Evans\nSeattle Avenue • JLH Fonts\nbuilt with Godot Engine"
autowrap_mode = 2
[node name="Notice" type="Label" parent="Paper/Margin/Layout"]
layout_mode = 2
theme_override_colors/font_color = Color(0.624, 0.812, 0.824, 1)
theme_override_font_sizes/font_size = 13
text = "complete attribution, licensing, and asset provenance are included with every release"
horizontal_alignment = 1
autowrap_mode = 2
[node name="BackCenter" type="CenterContainer" parent="Paper/Margin/Layout"]
layout_mode = 2
[node name="CreditsBackButton" type="Button" parent="Paper/Margin/Layout/BackCenter"]
unique_name_in_owner = true
custom_minimum_size = Vector2(112, 50)
layout_mode = 2
text = "back"

View file

@ -16,6 +16,7 @@ const BubbleClusterType = preload(
const TitleConfirmationBubblePageType = preload(
"res://ui/title_confirmation_bubble_page.gd"
)
const TitleCreditsPageType = preload("res://ui/title_credits_page.gd")
const NetworkSessionType = preload("res://network/network_session.gd")
const SavedServerStoreType = preload("res://network/saved_server_store.gd")
const JoinGamePageType = preload("res://ui/network/join_game_page.gd")
@ -70,7 +71,7 @@ const LOGO_MAX_WIDTH: float = 662.0
const TITLE_HORIZONTAL_MARGIN: float = 48.0
const TITLE_DESKTOP_REFERENCE_SIZE: Vector2 = Vector2(1280.0, 720.0)
const TITLE_COMPACT_REFERENCE_SIZE: Vector2 = Vector2(640.0, 480.0)
const BUBBLE_FIELD_MAX_WIDTH: float = 396.0
const BUBBLE_FIELD_MAX_WIDTH: float = 440.0
const BUBBLE_FIELD_DESKTOP_HEIGHT: float = 318.0
const BUBBLE_FIELD_COMPACT_WIDTH: float = 294.0
const BUBBLE_FIELD_COMPACT_HEIGHT: float = 200.0
@ -99,6 +100,7 @@ enum ConfirmationAction {
@onready var _continue_button: BubbleButtonType = %ContinueButton
@onready var _new_game_button: BubbleButtonType = %NewGameButton
@onready var _settings_button: BubbleButtonType = %SettingsButton
@onready var _credits_button: BubbleButtonType = %CreditsButton
@onready var _delete_button: BubbleButtonType = %DeleteSaveButton
@onready var _quit_button: BubbleButtonType = %QuitButton
@onready var _join_game_button: BubbleButtonType = %JoinGameButton
@ -134,6 +136,7 @@ enum ConfirmationAction {
@onready var _start_prompt_center: CenterContainer = %StartPromptCenter
@onready var _start_prompt_label: Label = %StartPromptLabel
@onready var _join_game_page: JoinGamePageType = %JoinGamePage
@onready var _credits_page: TitleCreditsPageType = %CreditsPage
var _save_manager: SaveManagerType
var _settings_manager: SettingsManagerType
@ -200,6 +203,7 @@ func _ready() -> void:
_new_game_button.pressed.connect(_on_new_game_pressed)
_join_game_button.pressed.connect(_open_join_game)
_settings_button.pressed.connect(_open_settings)
_credits_button.pressed.connect(_open_credits)
_delete_button.pressed.connect(_on_delete_pressed)
%QuitButton.pressed.connect(_on_quit_pressed)
_confirmation_page.confirmed.connect(_on_confirmation_accepted)
@ -211,6 +215,7 @@ func _ready() -> void:
_settings_panel.navigation_transition_started.connect(
_emit_navigation_bubble_flurry
)
_credits_page.back_requested.connect(_close_credits)
_bubble_field.configure(_get_title_buttons())
_decorative_fish_timer.timeout.connect(_on_decorative_fish_timer_timeout)
_decorative_bubble_event_timer.timeout.connect(
@ -261,6 +266,7 @@ func reopen() -> void:
_reset_confirmation()
_settings_panel.hide()
_join_game_page.close_page()
_credits_page.close_page()
_refresh_save_inspection()
show()
_start_decorative_presentation()
@ -274,6 +280,7 @@ func open_join_game_page(endpoint: String = "") -> void:
_presentation_center.hide()
_settings_panel.hide()
_confirmation_page.hide_page()
_credits_page.close_page()
_join_game_page.open_page(endpoint)
@ -286,7 +293,11 @@ func report_network_error(message: String) -> void:
func _open_join_game() -> void:
if _action_in_progress or _is_confirmation_active():
if (
_action_in_progress
or _is_confirmation_active()
or _credits_page.visible
):
return
open_join_game_page()
@ -299,6 +310,39 @@ func _close_join_game() -> void:
_focus_initial_button()
func _open_credits() -> void:
if (
_action_in_progress
or _is_confirmation_active()
or _settings_panel.visible
or _join_game_page.visible
or _credits_page.visible
):
return
_hide_continue_stats_context()
var restore_navigation_focus: bool = _navigation_focus_active
_set_title_bubbles_interactive(false)
_release_primary_menu_focus()
_presentation_center.hide()
_start_prompt_center.hide()
_credits_page.open_page(restore_navigation_focus)
func _close_credits(restore_navigation_focus: bool) -> void:
_credits_page.close_page()
_presentation_center.show()
_button_center.show()
_start_prompt_center.hide()
_set_title_bubbles_interactive(true)
if restore_navigation_focus:
_navigation_focus_active = true
_credits_button.grab_focus()
else:
_navigation_focus_active = false
_release_title_focus()
_update_continue_stats_visibility()
func is_awaiting_start_input() -> bool:
return _awaiting_start_input
@ -403,6 +447,7 @@ func _get_title_buttons() -> Array[BubbleButton]:
_new_game_button,
_join_game_button,
_settings_button,
_credits_button,
_delete_button,
_quit_button,
]
@ -498,6 +543,10 @@ func _input(event: InputEvent) -> void:
and _settings_panel.is_controller_mapping_capturing()
):
return
if _credits_page.visible:
if _credits_page.handle_input(event):
get_viewport().set_input_as_handled()
return
if _join_game_page.visible:
if event.is_action_pressed("ui_cancel"):
_close_join_game()
@ -549,6 +598,7 @@ func _handle_primary_menu_focus_input(event: InputEvent) -> bool:
not _button_center.visible
or _is_confirmation_active()
or _settings_panel.visible
or _credits_page.visible
):
return false
if event is InputEventMouseMotion:
@ -1186,6 +1236,7 @@ func _open_settings() -> void:
_is_confirmation_active()
or _action_in_progress
or _settings_panel.visible
or _credits_page.visible
or _title_settings_transition_active
):
return
@ -1398,6 +1449,7 @@ func _focus_initial_button() -> void:
or not visible
or _awaiting_start_input
or not _button_center.visible
or _credits_page.visible
):
return
if not _continue_button.disabled:
@ -1413,6 +1465,7 @@ func _on_quit_pressed() -> void:
not _action_in_progress
and not _is_confirmation_active()
and not _settings_panel.visible
and not _credits_page.visible
):
_hide_continue_stats_context()
quit_requested.emit()
@ -1430,6 +1483,7 @@ func _on_title_visibility_changed() -> void:
_navigation_focus_active = false
_modal_restore_navigation_focus = false
_reset_confirmation()
_credits_page.close_page()
_stop_decorative_presentation()

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=17 format=3]
[gd_scene load_steps=18 format=3]
[ext_resource type="Script" path="res://ui/title_screen.gd" id="1_script"]
[ext_resource type="Theme" path="res://ui/game_theme.tres" id="2_theme"]
@ -14,6 +14,7 @@
[ext_resource type="Texture2D" path="res://ui/icons/pictograms/online_dark.png" id="12_online_dark"]
[ext_resource type="Texture2D" path="res://ui/icons/pictograms/settings_dark.png" id="13_settings_dark"]
[ext_resource type="Texture2D" path="res://ui/icons/pictograms/x_dark.png" id="14_x_dark"]
[ext_resource type="PackedScene" path="res://ui/title_credits_page.tscn" id="15_credits_page"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_title_water"]
shader = ExtResource("4_water_shader")
@ -224,21 +225,21 @@ layout_mode = 2
[node name="BubbleLayoutSlot" type="Control" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter"]
unique_name_in_owner = true
custom_minimum_size = Vector2(396, 318)
custom_minimum_size = Vector2(440, 318)
layout_mode = 2
[node name="BubbleMotionRoot" type="Control" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot"]
unique_name_in_owner = true
layout_mode = 0
offset_right = 396.0
offset_right = 440.0
offset_bottom = 318.0
mouse_filter = 2
[node name="BubbleField" type="Control" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot/BubbleMotionRoot"]
unique_name_in_owner = true
custom_minimum_size = Vector2(396, 318)
custom_minimum_size = Vector2(440, 318)
layout_mode = 0
offset_right = 396.0
offset_right = 440.0
offset_bottom = 318.0
script = ExtResource("8_bubble_cluster")
profile = ExtResource("9_bubble_profile")
@ -322,6 +323,30 @@ motion_period = 4.9
motion_phase = 2.5
deformation_period = 6.3
[node name="CreditsButton" type="Button" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot/BubbleMotionRoot/BubbleField"]
unique_name_in_owner = true
offset_left = 330.0
offset_top = 125.0
offset_right = 414.0
offset_bottom = 207.0
text = "credits"
tooltip_text = "credits"
accessibility_name = "credits"
script = ExtResource("7_bubble_button")
profile = ExtResource("9_bubble_profile")
neutral_size = Vector2(84, 82)
desktop_anchor = Vector2(372, 166)
compact_anchor = Vector2(372, 166)
compact_minimum_size = Vector2(62, 62)
minimum_font_size = 12
maximum_font_size = 17
horizontal_amplitude = 1.4
vertical_amplitude = 3.0
motion_period = 5.0
motion_phase = 1.8
deformation_amplitude = 0.015
deformation_period = 5.6
[node name="JoinGameButton" type="Button" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent/ButtonCenter/BubbleLayoutSlot/BubbleMotionRoot/BubbleField"]
unique_name_in_owner = true
offset_left = 126.0
@ -444,6 +469,16 @@ offset_bottom = 300.0
grow_horizontal = 2
grow_vertical = 2
[node name="CreditsPage" parent="ResponsiveTitleStage/TitlePresentationScaleRoot" instance=ExtResource("15_credits_page")]
unique_name_in_owner = true
z_index = 220
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="JoinGamePage" parent="ResponsiveTitleStage/TitlePresentationScaleRoot" instance=ExtResource("11_join_page")]
unique_name_in_owner = true
z_index = 220