Comprehensive Refinement of Circular Menu
 Implementation in Garry's Mod
 Performance Optimization in vGUI Animations: Identifying and
 Addressing Bottlenecks
 The Garry's Mod environment, particularly its vGUI (virtual graphical user interface) system, has
 long been plagued by performance bottlenecks that degrade user experience. These inefficiencies
 often manifest as Lua errors, which are frequently encountered in spawn menus during gameplay [
 5].
 For instance, recurring issues such as attempt to index field 'animFade' (a nil
 value) and attempt to index field 'btnRight' (a nil value) have been
 reported to cause significant performance degradation, blocking access to essential functionalities like
 the spawn menu. These errors not only disrupt gameplay but also highlight structural weaknesses in
 how animation logic is handled or initialized within the framework. Such problems suggest a lack of
 robust error handling mechanisms and modularity in the underlying Lua scripts, which violates
 principles like the Single Responsibility Principle (SRP). To address these challenges effectively, it is
 imperative to adopt a structured approach to bug reporting and diagnosis, as emphasized in the
 Garry’s Mod issue trackers [
 2]. Detailed bug reports, including step-by-step recreation instructions,
 version details, and crash logs, play a critical role in isolating and resolving animation-related
 bottlenecks. This systematic methodology enables developers to gather actionable data on rendering
 issues and animation-related bugs, thereby facilitating targeted optimizations.
 One notable example of performance bottlenecks can be observed in circular menus, where
 excessive computations or redundant logic significantly impact rendering efficiency. Addons like
 'Animated Props,' while enhancing gameplay through dynamic animations, have been identified as
 culprits behind severe lag during multiplayer sessions [
 3]. Users have reported thousands of errors
 when loading saves with this addon, citing issues such as 'Tried to use a NULL entity!' and
 unauthorized editing of animated props due to default prop protection settings. These errors disrupt
 rendering logic and point to significant flaws in handling dynamic data structures. Furthermore,
 combining 'Animated Props' with other tools like Stop Motion Helper exacerbates performance
 issues, likely due to inefficient resource usage or redundant computations. Such interactions
 underscore the importance of benchmarking rendering performance to identify inefficiencies and
 establish optimization priorities. By analyzing these benchmarks, developers can pinpoint areas
 where computational overhead can be reduced without compromising functionality.
 Drawing inspiration from optimization strategies implemented in other projects provides valuable
 insights into addressing vGUI animation bottlenecks. For instance, JBrowse 3.4.0 introduced
 significant performance improvements by avoiding the serialization of large features to sessions,
 thereby fixing quota exceeded errors in local storage [
 4]. Applying similar techniques to Garry’s
 Mod could reduce memory overhead related to session data management, particularly in scenarios
 involving complex UI interactions. Additionally, the introduction of fuzzy search algorithms like
 uFuzzy in JBrowse demonstrates the potential for enhancing search operations in Garry’s Mod’s
 context menus, especially when dealing with extensive datasets or intricate menu structures. Another
noteworthy optimization involves multi-sample variant rendering, where minor tweaks reduced
 unnecessary re-renders and improved responsiveness. Developers facing inefficiencies in button
 animations can leverage these granular profiling techniques to streamline animation logic without
 impacting overall system performance.
 Recent updates to Garry’s Mod further reinforce the feasibility of implementing micro
optimizations to improve rendering efficiency. The March 2025 update, for example, addressed
 structural weaknesses in the vGUI framework by fixing uninitialized or improperly managed UI
 elements such as 'animFade' and 'btnRight,' which previously caused frequent crashes and
 performance degradation [
 9]. These enhancements demonstrate practical solutions for streamlining
 rendering logic while maintaining system stability. Moreover, the addition of custom shader support
 enables modders to create advanced visual effects, inspiring innovations in UI systems, particularly
 for circular menus or other interactive elements. Localization support also received substantial
 attention, with translations extended to spawnmenu categories, ammo names, and crosshair
 customization options. Standardizing localization workflows reduces cognitive load for developers
 maintaining large Lua scripts, ensuring consistency across implementations.
 In conclusion, addressing performance bottlenecks in vGUI animations requires a multifaceted
 approach that combines structured bug reporting, benchmarking, and targeted optimizations.
 Developers should prioritize reducing computational overhead by eliminating redundant logic and
 adopting efficient data handling practices. Implementing micro-optimizations, as seen in recent
 updates, can yield significant improvements in rendering efficiency. Additionally, drawing lessons
 from projects like JBrowse highlights the importance of avoiding unnecessary session data
 serialization and leveraging advanced algorithms for search and rendering operations. Moving
 forward, fostering community engagement through platforms like Discord can provide valuable
 feedback on common pain points and emerging trends. By adhering to these actionable steps,
 developers can enhance both the usability and performance of vGUI animations, ultimately
 delivering a more seamless and enjoyable user experience.
 Evaluation of Readability Challenges in Complex Lua Scripts for
 Garry's Mod
 Readability challenges in complex Lua scripts, particularly within the context of Garry’s Mod,
 present significant obstacles to both novice and experienced developers. These challenges often stem
 from inconsistent coding practices, unclear error handling, and a lack of standardization in script
 structures [
 6]. Community feedback highlights that these issues are exacerbated in large-scale projects
 where multiple contributors work on shared codebases. For instance, undocumented functions and
 non-standardized variable naming conventions can lead to confusion, making it difficult for
 developers to understand or modify existing scripts. Furthermore, the absence of robust debugging
 tools tailored to Lua in Garry’s Mod compounds these difficulties, as developers must rely on
 generic error messages that provide limited insight into the root cause of issues.
 To address these readability challenges, adopting best practices is essential. One effective approach
 involves standardizing fonts, margins, and localization workflows, which has been shown to improve
 script clarity significantly [
 8, 
9]. Using consistent typography, such as web-safe fonts like Poppins or
 Roboto, ensures smoother rendering and reduces cognitive load when reading scripts. Similarly,
implementing localization workflows not only enhances accessibility but also streamlines
 maintenance by reducing inconsistencies across different language implementations [
 9]. For example,
 base Lua SWEPs (Scripted Weapons) now utilize standardized localization strings, resolving earlier
 issues related to mismatched ammo names and spawnmenu categories. Such practices demonstrate
 how minor adjustments can yield substantial improvements in script readability without
 compromising functionality.
 Inspiration for structuring readable GUI elements can be drawn from modular codebases like
 Roblox’s Luau implementation. As a modified version of Lua 5.1, Luau emphasizes scalability and
 adaptability, enabling developers to create reusable and efficient components while maintaining
 performance across diverse use cases [
 11]. This approach aligns closely with object-oriented patterns
 for designing GUI elements, such as buttons and menus. By examining Roblox’s architecture,
 developers can identify strategies for encapsulating UI logic within well-defined scopes, thereby
 promoting modularity and reusability. For instance, separating animation logic from rendering
 operations allows for decoupled systems that are easier to debug and extend. Applying similar
 principles in Garry’s Mod could mitigate common inefficiencies observed in button animations and
 other interactive elements.
 Tools and methodologies that enhance script clarity further contribute to addressing readability
 challenges. Debugging aids, such as enhanced error messages introduced in recent updates, play a
 critical role in simplifying troubleshooting processes [
 6]. For example, adding file paths to error
 notifications enables developers to quickly locate problematic sections of their code. Additionally,
 consistent naming conventions reduce ambiguity and improve comprehension, especially in
 collaborative environments. The refactoring of libraries like list.GetForEdit to eliminate
 redundancy exemplifies how incremental changes can enhance maintainability over time. Developers
 should also leverage profiling tools like FProfiler to benchmark performance and identify
 bottlenecks, ensuring that optimizations do not inadvertently compromise readability [
 8].
 Despite these advantages, there exist trade-offs between readability and performance that warrant
 consideration. Critics argue that prioritizing readability may introduce overhead due to increased
 abstraction layers or verbose syntax. For example, modular designs often require additional resource
 management, such as pushing and popping matrix transformations (cam.PushModelMatrix),
 which can impact rendering efficiency if not handled carefully [
 8]. Similarly, excessive reliance on
 caching mechanisms might lead to memory bloat unless lifecycle management is rigorously enforced.
 While these concerns are valid, they underscore the importance of striking a balance between clarity
 and efficiency. By adhering to SOLID principles—such as Dependency Inversion and Open-Closed
 Principle—developers can design architectures that remain flexible yet performant [
 6]. Tools like
 RenderTargets and stencil buffers offer practical solutions for achieving this equilibrium, allowing
 visually rich interfaces without embedding complex logic directly into UI components.
 In conclusion, evaluating readability challenges in complex Lua scripts reveals a multifaceted
 landscape shaped by technical constraints and community-driven innovations. Standardizing coding
 practices, drawing inspiration from modular frameworks, and leveraging advanced tools collectively
 contribute to overcoming these hurdles. However, recognizing the inherent trade-offs between
 readability and performance is crucial for sustainable development. Future research could explore
 automated methods for enforcing coding standards or developing domain-specific languages tailored
 to Garry’s Mod’s unique requirements. Ultimately, fostering a culture of collaboration and
iterative refinement will empower developers to create more accessible, maintainable, and efficient
 Lua scripts.
 Comprehensive Analysis of Bug Reports in Context Menus and
 Animation Systems
 The assessment of bug reports related to context menus and animation systems in Garry's Mod
 reveals a multifaceted landscape of technical challenges, recurring issues, and iterative resolutions.
 These problems span high-frequency Lua errors, architectural mismatches between engines,
 improper handling of advanced animation features, and inefficiencies in UI frameworks. By analyzing
 documented cases, community discussions, and implemented fixes, this section provides an in-depth
 exploration of these issues, their underlying causes, and strategies for future-proofing the system.
 One of the most frequently reported bugs involves Lua errors such as 'attempt to index field
 animFade' in dpropertysheet.lua and 'attempt to index field btnRight' in 
dhorizontalscroller.lua [
 5]. These errors occur at a high frequency, causing significant
 performance degradation and blocking access to essential menus like the spawn menu. Such issues
 are symptomatic of deeper structural weaknesses in the vGUI framework, where uninitialized or
 improperly managed UI elements disrupt gameplay. For instance, the absence of null checks or
 fallback mechanisms violates the Single Responsibility Principle (SRP), leading to runtime errors that
 cascade into broader system instability [
 5]. Community feedback highlights the reliance on third-party
 tools, such as the Lua Patcher by Piengineer12, to mitigate these widespread errors. However, while
 these patches offer temporary relief, they may introduce performance trade-offs and fail to address
 the root cause of the problem [
 5]. This underscores the need for robust error handling and
 modularity in the design of UI components.
 GitHub and forum discussions further illuminate patterns in reported issues, particularly concerning
 improper blend layer handling and uninitialized variables [
 1]. A notable example is the humanoid
 animation bug (#5218), which caused incorrect rendering of animations from models originating in
 newer Source Engine games like Counter-Strike: Global Offensive (CSGO) and Left 4 Dead 2.
 When users attempted to apply specific animations, such as 'idle_standing_fry_pan' or
 'CalmRun_Sniper,' only partial bone movements were observed, deviating significantly from
 expected behavior. This issue was traced back to differences in blend layer systems between older
 Half-Life 2 (HL2)-based engines and newer Source Engine branches [
 1]. The resolution of this bug,
 announced by contributor robotboy655 on October 18, 2024, likely involved updates to how the
 engine processes .ani files and blend layers for imported models [
 1]. This two-year timeline from
 initial report to resolution illustrates the iterative nature of debugging complex legacy systems and
 emphasizes the critical role of community feedback loops in identifying and addressing long-standing
 issues.
 Animations-related problems extend beyond blend layers to include unintended behaviors such as
 bone scaling. For example, using advanced bone tools to scale individual bones often results in
 unintended scaling of child bones, a phenomenon reported by Attention Horse on April 6, 2024 [
 3].
 This behavior stems from poorly decoupled animation logic, impacting both usability and
 performance. Similarly, combining the 'Animated Props' addon with Stop Motion Helper has been
 shown to cause severe lag during animations, likely due to inefficient resource usage or redundant
computations [
 3]. These findings highlight the importance of separating animation logic from UI
 components and managing dynamic data structures effectively.
 Successful resolutions, such as those implemented in the March 2025 update, demonstrate the
 potential for iterative refinement based on community feedback [
 9]. This update addressed critical
 issues affecting animation logic, including improper transformations during level transitions that
 previously caused unintended scaling of child bones. Additionally, the patch resolved recurring Lua
 errors related to context menus and spawnmenu functionality, such as 'attempt to index field
 animFade' in dpropertysheet.lua. These enhancements not only improved performance but
 also ensured smoother integration of dynamic animations within the vGUI framework [
 9].
 Furthermore, the introduction of custom shader support and increased MAX_MAP_BRUSHES in
 Hammer editor tools provided developers with the flexibility to design more complex interfaces
 efficiently [
 9]. Localization support also received substantial attention, with translations extended to
 spawnmenu categories, ammo names, and crosshair customization options, thereby enhancing code
 readability and maintainability [
 9].
 To prevent similar bugs in the future, it is imperative to adopt robust testing and validation
 mechanisms. Strategies include implementing comprehensive unit tests for Lua scripts, conducting
 compatibility testing for assets across different engine versions, and leveraging middleware solutions
 to bridge disparities between high-level UI components and low-level rendering modules.
 Additionally, adhering to SOLID principles, particularly Dependency Inversion, can improve
 modularity and extensibility, ensuring that the system remains adaptable to evolving requirements [
 3].
 Encapsulating button actions and descriptions into well-defined classes could prevent runtime issues
 and enhance code readability, addressing concerns raised in previous tasks [
 5].
 In conclusion, the assessment of bug reports related to context menus and animation systems in
 Garry's Mod underscores the complexity of integrating assets from newer engines into older
 frameworks. By analyzing documented cases, community discussions, and implemented fixes, this
 section highlights the importance of robust error handling, modular design, and iterative refinement.
 Future-proofing strategies should focus on addressing architectural mismatches, improving error
 handling, and fostering collaboration between developers and the community to ensure the
 continued evolution of the platform.
 Designing Class Structures for Buttons Using Object-Oriented
 Programming in Lua
 The design of class structures for graphical user interface (GUI) elements, particularly buttons, is a
 critical aspect of software development within game engines and frameworks that utilize Lua as their
 scripting language. This section explores the application of object-oriented programming (OOP)
 principles to create reusable, modular, and extensible button classes in Lua, drawing inspiration from
 frameworks like Roblox’s Luau [
 11] and existing implementations in Garry's Mod [
 2]. By leveraging
 inheritance, encapsulation, and polymorphism, developers can construct robust hierarchies for main
 buttons and sub-buttons while addressing the inherent constraints of Lua's prototype-based OOP
 system.
To begin with, understanding object-oriented patterns for GUI elements in Lua requires examining
 how popular frameworks have approached this challenge. For instance, Roblox’s Luau provides a
 structured environment where GUI components such as buttons are implemented using class-like
 constructs. These constructs allow developers to define reusable behaviors and properties, ensuring
 consistency across different instances of buttons. Similarly, Garry's Mod employs Lua to script its
 vGUI system, which includes various GUI elements like panels, labels, and buttons. Notable
 contributors to Garry's Mod have shared implementations of button classes that demonstrate
 modularity and reusability [
 2]. By analyzing these contributions, researchers can identify common
 patterns, such as the use of metatables to simulate inheritance and encapsulate core functionalities.
 Building on these insights, a proposed design for button classes involves creating a base Button class
 that encapsulates shared attributes and methods, such as rendering logic, event handling, and state
 management. Subclasses, such as MainButton and SubButton, would inherit from this base class
 while introducing specialized behaviors tailored to their roles. For example, a MainButton might
 include additional logic for managing focus states or triggering global events, whereas a SubButton
 could handle contextual actions specific to its parent element. This hierarchical approach ensures that
 core functionalities remain centralized and reusable, reducing code duplication and enhancing
 maintainability [
 12].
 However, applying OOP principles effectively within Lua presents unique challenges due to the
 language's prototype-based nature. Unlike classical OOP languages like Java or C++, Lua does not
 natively support classes or inheritance. Instead, it relies on tables and metatables to emulate these
 features. This limitation necessitates careful consideration when designing class hierarchies. Practical
 solutions include using helper libraries or utility functions to simplify the creation of class-like
 structures. For instance, defining a generic 'class' function that sets up metatables and inheritance
 chains can streamline the process of implementing complex hierarchies [
 11]. Additionally, employing
 composition over inheritance can mitigate some of the drawbacks associated with deep inheritance
 trees, promoting flexibility and scalability.
 Validating the proposed structure with examples from other platforms further reinforces its efficacy.
 Game engines like Unity and Unreal Engine, though not based on Lua, adopt similar approaches to
 designing GUI systems. In Unity, for example, UI components are built around a component-based
 architecture where each element derives from a common base class and supports extension through
 scripts. Similarly, Unreal Engine’s UMG framework allows designers to create reusable widget
 blueprints that encapsulate both visual and functional aspects. These parallels underscore the
 universality of OOP principles in GUI design and highlight the adaptability of Lua for implementing
 comparable systems [
 11].
 In conclusion, designing class structures for buttons using object-oriented programming in Lua
 involves balancing theoretical rigor with practical considerations. By studying existing
 implementations in frameworks like Roblox’s Luau and Garry's Mod, developers can derive
 valuable lessons about modularity, reusability, and extensibility. Proposing a hierarchical design that
 leverages inheritance and encapsulation addresses the need for scalable and maintainable codebases.
 Despite Lua's constraints, thoughtful strategies such as utilizing helper functions and favoring
 composition over inheritance enable effective OOP practices. Future research could explore
 advanced topics like integrating dependency injection or refining performance optimizations within
 these class structures.
Implementation of Modular Animation Logic for vGUI Elements
 in Garry's Mod
 The implementation of modular animation logic for vGUI (VGUI) elements in Garry's Mod
 necessitates a structured approach that decouples animation systems from the core UI components
 while ensuring optimal performance and maintainability. This section explores compatible tools,
 techniques for separating rendering logic, reusable frameworks, integration challenges, and
 recommendations for scalable pipelines. 
To begin with, identifying modular animation libraries compatible with Garry's Mod provides a
 foundation for developing efficient vGUI animations. One notable tool is the GMod
BlenderLuaAnimationsAPIExport [
 7], which bridges Blender’s robust animation capabilities with
 JetBoom’s Lua Animations API. By exporting animations from Blender into formats consumable
 by Garry's Mod, developers can leverage precise bone manipulation techniques to ensure seamless
 integration. For instance, animators are advised to avoid baked animations due to excessive keyframe
 generation, opting instead for manual adjustments using constraints like Inverse Kinematics (IK).
 Such practices reduce file size and computational overhead, aligning with best practices for creating
 leaner, more performant animations. Additionally, linear interpolation over cosine-based methods is
 recommended for smoother transitions, further enhancing runtime efficiency [
 7].
 Decoupling animation logic from UI components is another critical step toward achieving
 modularity. Techniques such as stencil buffers and RenderTargets play pivotal roles in this process.
 Stencil buffers allow pixel-level control over drawing conditions, enabling advanced visual effects like
 rounded corners or circular panels without embedding complex rendering logic directly into UI
 components [
 8]. This separation adheres to SOLID principles, promoting modularity and reusability.
 Similarly, RenderTargets facilitate off-screen rendering, allowing precomputed previews or texture
 modifications that do not interfere with the main graphics pipeline. Proper lifecycle management of
 RenderTargets is essential to prevent resource contention or memory bloat, making them particularly
 relevant for designing reusable animation pipelines [
 8]. Matrix animations
 (cam.PushModelMatrix) offer another avenue for creating sophisticated UI transformations,
 though their misuse—such as failing to call cam.PopModelMatrix—can lead to rendering
 artifacts or crashes. Encapsulating these operations within well-defined scopes ensures proper
 cleanup, mitigating potential issues during high-frequency updates.
 Reusable animation frameworks further enhance scalability and maintainability. Hierarchical blending
 and state machines, demonstrated in Lumberyard tutorials, provide valuable insights into organizing
 animation logic [
 10]. These techniques enable smooth transitions between different states, such as
 idle, hover, or active modes, by blending animations based on predefined rules. State machines also
 help manage complex interactions, ensuring animations respond appropriately to user input or
 environmental changes. While Lumberyard-specific examples may require adaptation for Garry's
 Mod, their underlying principles remain applicable. For example, adopting object-oriented
 programming patterns within Lua's constraints can improve code organization and readability,
 addressing challenges associated with legacy systems.
 However, integrating advanced animation systems into legacy frameworks presents compatibility
 gaps. The transition from older Source Engine games to Garry's Mod often involves structural
mismatches, particularly regarding blend layers and animation files [
 10]. Abstraction layers can
 mitigate these discrepancies, ensuring smoother integration without compromising functionality.
 Furthermore, engaging with niche forums or repositories where experienced users share proprietary
 solutions can yield innovative approaches to dependency injection and interface segregation [
 10].
 Adopting hybrid methods—combining declarative UI definitions with imperative Lua logic—may
 enhance usability while adhering to SOLID principles, especially concerning single responsibility and
 open-closed designs.
 In conclusion, implementing modular animation logic for vGUI elements requires careful
 consideration of available tools, techniques, and frameworks. Leveraging tools like the GMod
BlenderLuaAnimationsAPIExport, employing stencil buffers and RenderTargets for optimized
 rendering, and utilizing hierarchical blending and state machines from Lumberyard tutorials
 collectively contribute to a robust animation pipeline. Addressing compatibility gaps through
 abstraction layers and community collaboration ensures long-term sustainability. Future research
 should focus on refining these methodologies, exploring automated testing frameworks for
 animation systems, and evaluating emerging technologies that could further streamline the
 development process.
 Refactoring ButtonData and SubButtonData Handling Using Best
 Practices in Lua-Based Systems
 The management of dynamic data structures, particularly those involving user interface elements
 such as buttons and sub-buttons, is a critical aspect of game development using Lua scripting.
 Refactoring the handling of ButtonData and SubButtonData to align with best practices not only
 improves code maintainability but also enhances runtime performance and scalability. This section
 explores techniques for achieving these objectives through memory manipulation strategies,
 encapsulation via object-oriented design, dependency injection, factory patterns, and case studies
 demonstrating their efficacy.
 One cornerstone of effective refactoring lies in leveraging Lua’s flexibility to manage memory
 efficiently while adhering to structured methodologies. In emulators like BizHawk, developers utilize
 Lua’s memory.readbyte and memory.writebyte functions to manipulate game states
 directly [
 12]. Although primarily applied to emulator environments, this approach underscores the
 importance of precise control over memory when dealing with uninitialized variables or corrupted
 states. For instance, issues related to uninitialized fields such as animFade or btnRight in
 Garry’s Mod can be mitigated by implementing robust error-checking mechanisms during runtime.
 By adopting similar techniques, developers can ensure that ButtonData and SubButtonData are
 initialized correctly before being accessed, thereby reducing runtime errors caused by null references
 or improper state management [
 13].
 Encapsulation plays a pivotal role in modern software architecture, especially when addressing
 complex hierarchies of UI components. Encapsulating button actions and descriptions into classes
 provides a clear separation between logic and presentation layers. Consider a scenario where each
 button has associated behaviors (e.g., click events) and metadata (e.g., tooltips). Instead of managing
 these attributes as loosely coupled variables, they can be bundled into cohesive class definitions. For
 example, a base Button class could define core functionalities such as rendering and event
handling, while derived classes extend this foundation to include specialized behaviors. This
 modularity aligns with SOLID principles, particularly the Single Responsibility Principle (SRP),
 which mandates that each module should have one reason to change. Additionally, the Open-Closed
 Principle (OCP) ensures that existing functionality remains unaffected when introducing new
 features [
 15]. Such an approach simplifies debugging and testing since changes to specific button
 types do not inadvertently affect others.
 To further enhance extensibility, dependency injection (DI) and factory patterns offer powerful tools
 for decoupling high-level modules from low-level implementations. DI allows dependencies to be
 injected at runtime rather than hardcoded, enabling greater flexibility and easier maintenance. For
 example, instead of hardcoding the logic for button animations within the UI framework itself,
 developers can register animation services via a DI container. This way, new animation effects can be
 added without modifying the core UI system. Similarly, factory patterns facilitate the creation of
 objects without exposing instantiation details. A factory interface for generating buttons could
 abstract away the specifics of how different button types are constructed, allowing future
 modifications to occur seamlessly. These patterns find strong support in real-world applications; for
 instance, Alex Merzlikin demonstrates how combining DI with Entity Component System (ECS)
 architectures streamlines dependency management in Unity-based projects [
 15]. While his examples
 focus on C# and ECS frameworks, the underlying principles can be adapted to Lua-based systems
 like Garry’s Mod.
 Case studies highlight the tangible benefits of applying these refactoring techniques. One notable
 example comes from BizHawk’s implementation of controller input simulation using Lua scripts.
 The joypad.set function programmatically interacts with game logic, enabling actions such as
 making Mario run indefinitely. This separation of interaction logic from rendering mirrors potential
 improvements for Garry’s Mod’s vGUI systems. By isolating button actions into reusable classes,
 developers achieve cleaner codebases that are easier to extend and debug. Furthermore, the use of
 Lua tables to represent controller inputs offers a blueprint for organizing ButtonData and
 SubButtonData hierarchies. For instance, storing pit locations in a table (local pits =
 {[0x1C]=true}) facilitates efficient lookups and decision-making based on contextual
 conditions. Translating this methodology to Garry’s Mod could streamline inheritance models,
 ensuring that base button classes inherit core functionalities while derived classes handle specialized
 behaviors [
 12].
 Finally, transitioning current implementations toward more robust designs requires a well-defined
 roadmap. The first step involves auditing existing code to identify areas prone to runtime errors due
 to uninitialized fields or tightly coupled dependencies. Next, developers should refactor these
 sections by encapsulating button actions and descriptions into classes, thereby improving clarity and
 reducing redundancy. Simultaneously, integrating DI frameworks can automate dependency
 resolution, minimizing manual setup efforts. Additionally, adopting factory patterns ensures that
 object creation remains flexible and scalable. Throughout this process, rigorous testing must
 accompany every change to validate correctness and measure performance gains. Future research
 could explore automated reflection-based system discovery to dynamically extend button
 functionality without requiring explicit registrations, akin to Merzlikin’s proposals for Unity ECS
 workflows [
 15].
In conclusion, refactoring ButtonData and SubButtonData handling using best practices entails a
 multifaceted approach encompassing memory management, encapsulation, dependency injection,
 and factory patterns. These strategies collectively address challenges related to runtime errors,
 extensibility, and readability, ultimately leading to more resilient and adaptable codebases. As
 demonstrated through case studies and theoretical frameworks, the adoption of such methodologies
 holds significant promise for enhancing both the technical quality and user experience of Lua-based
 systems.
 Applying SOLID Principles to Enhance Extensibility and
 Maintainability in Garry's Mod UI Systems
 In the realm of software engineering, the SOLID principles—Single Responsibility Principle (SRP),
 Open-Closed Principle (OCP), Liskov Substitution Principle (LSP), Interface Segregation Principle
 (ISP), and Dependency Inversion Principle (DIP)—serve as foundational guidelines for designing
 modular, extensible, and maintainable systems. These principles are particularly relevant when
 addressing challenges in complex user interface (UI) systems such as those found in Garry's Mod,
 where frequent errors and performance bottlenecks arise from tightly coupled and poorly structured
 code [
 5]. By systematically applying these principles, developers can significantly improve both the
 functionality and reliability of UI frameworks like vGUI.
 The Single Responsibility Principle (SRP) posits that every module or class should have a single
 reason to change, encapsulating one specific responsibility. In the context of Garry's Mod, recurring
 Lua errors such as attempt to index field 'animFade' (a nil value)
 highlight violations of SRP, where animation logic is improperly entangled with rendering and
 interaction logic [
 5]. To address this, developers could refactor the vGUI framework by isolating
 animation handling into dedicated classes or modules. For instance, creating an 
AnimationManager class responsible solely for managing transitions and fades would prevent
 null pointer exceptions caused by uninitialized fields. This separation aligns with Task 20, which
 advocates dividing rendering logic from interaction logic, thereby enhancing readability and
 maintainability.
 Extending beyond SRP, the Open-Closed Principle (OCP) emphasizes designing systems that are
 open for extension but closed for modification. A practical example of adhering to OCP can be
 observed in Wireshark’s use of Lua scripting to enable protocol dissectors and post-dissectors
 without altering core functionalities [
 11]. Similarly, Garry's Mod could adopt a plugin architecture
 that allows third-party addons to extend UI capabilities through configuration files or scripts. For
 instance, implementing a system where button actions are defined via external Lua modules rather
 than hardcoded within the main UI logic ensures compliance with OCP. Such an approach not only
 reduces the risk of introducing breaking changes but also empowers users to customize their
 experience without modifying base assets.
 Dependency Inversion Principle (DIP) further reinforces modularity by advocating for high-level
 modules to depend on abstractions rather than low-level implementations. Redis exemplifies DIP by
 allowing server-side Lua scripts to perform data transformations while decoupling high-level
 operations from underlying database mechanics [
 11]. Applying this principle to Garry's Mod involves
 abstracting interactions between vGUI components and rendering logic. For example, dependency
injection (DI) frameworks similar to those used in game engines could automate the initialization of
 subsystems such as logging (ILogger) or input handling (IInputHandler). As demonstrated in
 modern ECS frameworks like Morpeh, DI containers streamline dependency management by
 resolving services automatically during runtime [
 15]. Integrating DI into Garry's Mod would
 eliminate manual setup routines, reducing maintenance overhead and improving architectural
 flexibility.
 Interface Segregation Principle (ISP) complements DIP by promoting the creation of fine-grained
 interfaces tailored to specific client needs. Instead of exposing monolithic APIs, ISP encourages
 splitting interfaces into smaller, cohesive units. Within Garry's Mod, this could manifest as distinct
 interfaces for different UI elements—such as IButton, ITextBox, and ISlider—each
 defining only the methods pertinent to its role. This granularity prevents unnecessary coupling
 between unrelated functionalities, ensuring that modifications to one component do not
 inadvertently affect others. Moreover, adopting ISP facilitates adherence to other SOLID principles,
 particularly SRP and OCP, by enforcing clear boundaries between responsibilities.
 To illustrate the benefits of adhering to SOLID principles, consider the development of modular
 vGUI systems inspired by Roblox’s Luau scripting environment. Roblox employs object-oriented
 patterns to structure reusable GUI components, enabling efficient handling of dynamic scenarios
 [
 11]. Translating this methodology to Garry's Mod entails designing well-encapsulated classes for UI
 elements such as buttons and sliders. For example, a Button class could include properties for
 action callbacks, visual states, and accessibility features, all managed independently of rendering logic.
 Real-world applications of this approach demonstrate significant improvements in code readability,
 performance, and scalability, validating its effectiveness across diverse use cases.
 Finally, to adopt SOLID principles systematically across development workflows, teams must
 establish robust coding standards and review processes. Guidelines should emphasize the importance
 of writing testable, decoupled code and discourage practices that lead to tight coupling or excessive
 complexity. Additionally, leveraging tools such as static analyzers and automated testing frameworks
 can help identify potential violations early in the development cycle. By fostering a culture of
 continuous improvement and knowledge sharing, organizations can ensure sustained adherence to
 best practices while minimizing technical debt.
 In conclusion, applying SOLID principles offers a comprehensive strategy for enhancing the
 extensibility and maintainability of Garry's Mod UI systems. From isolating responsibilities through
 SRP to enabling seamless extensions via OCP and DI, each principle contributes uniquely to a more
 resilient architecture. Drawing insights from successful implementations in Redis, Wireshark, and
 ECS frameworks underscores the versatility and impact of these principles in real-world scenarios.
 Moving forward, further research should explore advanced techniques for automating dependency
 resolution and integrating reflection-based discovery mechanisms, paving the way for even greater
 innovation in Lua-based projects.
 Analysis of Code Optimization and Refactoring Opportunities
 The provided Lua script for creating a circular menu in Garry's Mod contains several areas where
 improvements can be made to align with Object-Oriented Programming (OOP) principles, SOLID
 design, and overall optimization. Below is a structured analysis of the key findings.
Key Issues in the Current Code
 Lack of Modularization: The code is largely procedural, with functions handling multiple
 responsibilities. For example, CreateCircularMenu mixes UI creation, animation logic,
 and input handling.
 Violation of Single Responsibility Principle (SRP): Functions like ModernButtonPaint
 are responsible for both drawing and hover effects, which could be decoupled.
 Inefficient Animation Handling: Animations are managed through a mix of timers and manual
 calculations, leading to potential inefficiencies.
 Hardcoded Values: Many values, such as button sizes, positions, and colors, are hardcoded,
 reducing flexibility and maintainability.
 Error-Prone State Management: Sub-buttons and their animations rely on global state
 variables (subButtons, buttonAnims), making the system prone to bugs and harder to
 debug.
 Suggested Improvements
 To address these issues, the following table outlines specific refactorings and their benefits:
 Refactoring
 Area
 Current
 Implementation Suggested Improvement Benefits
 Modularization
 Procedural functions
 handling multiple
 tasks
 Create separate classes for 
Menu, Button, and 
SubButton
 Encapsulation of
 related logic; easier
 maintenance and
 extensibility [10]
 Animation
 Logic
 Manual calculation of
 positions and
 progress
 Use a dedicated 
AnimationManager class
 to handle all animations
 Centralized control;
 reduces redundancy
 and improves
 performance [6]
 State
 Management
 Global state variables
 (subButtons, 
buttonAnims)
 Store state within respective
 classes (e.g., Button
 manages its own animations)
 Reduces coupling;
 minimizes risk of
 unintended side
 effects [5]
 Dynamic Data
 Handling
 Hardcoded values for
 sizes, colors, and
 positions
 Use configuration tables or
 JSON files for dynamic data
 Enhances flexibility;
 simplifies updates
 without modifying
 core code [9]
 Event Handling Inline event handlers
 within UI creation
 Implement an 
EventManager class to
 register and trigger events
 Decouples
 interaction logic
 from rendering;
 1. 
2. 
3. 
4. 
5. 
Refactoring
 Area
 Current
 Implementation
 Implementation Example
 Suggested Improvement
 Below is a conceptual outline of how the refactored structure might look:
 local Menu = {}
 function Menu:new()
    local self = setmetatable({}, {__index = Menu})
    self.buttons = {}
    self.animationManager = AnimationManager:new()
    return self
 end
 function Menu:create()
    -- Initialize buttons and animations
    for i=1,8 do
 Benefits
 adheres to Open
Closed Principle [
 13]
        local button = Button:new(i)
        table.insert(self.buttons, button)
        self.animationManager:add(button:getAnimation())
    end
 end
 local Button = {}
 function Button:new(index)
    local self = setmetatable({}, {__index = Button})
    self.index = index
    self.anim = Animation:new()
    return self
 end
 function Button:paint(w, h)
    -- Paint logic encapsulated here
 end
 This modular approach ensures that each component has a clear responsibility, making the codebase
 more maintainable and scalable.
 Additional Considerations
 • 
• 
Performance Optimization: Use techniques like stencil buffers and RenderTargets to improve
 rendering efficiency [
 8].
 Error Handling: Introduce robust error-checking mechanisms, especially for uninitialized
 variables and null references [
 5].
• 
Dependency Injection: Apply DI patterns to decouple high-level UI components from low
level rendering logic [
 13].
 Conclusion
 The comprehensive evaluation and refinement of the circular menu implementation in Garry's Mod
 reveal numerous opportunities to enhance the system's performance, readability, and maintainability.
 By addressing performance bottlenecks through modular animation logic and efficient state
 management, developers can significantly reduce computational overhead and improve user
 experience. The application of SOLID principles, particularly Single Responsibility and Dependency
 Inversion, ensures that the codebase remains flexible and adaptable to future changes. Encapsulation
 of button actions and descriptions into well-defined classes not only enhances readability but also
 reduces runtime errors, fostering a more resilient architecture. Furthermore, leveraging advanced
 tools such as stencil buffers, RenderTargets, and dependency injection frameworks streamlines the
 development process, enabling scalable and reusable solutions. Collectively, these strategies
 underscore the importance of structured methodologies and community-driven innovations in
 overcoming technical challenges. Future research should focus on automating dependency resolution
 and integrating reflection-based discovery
```lua
if CLIENT then
    -- Вспомогательная функция для проверки попадания точки в круг
    local function PointInCircle(px, py, cx, cy, radius)
        local dx, dy = px - cx, py - cy
        return (dx * dx + dy * dy) <= (radius * radius)
    end

    local menuPanel = nil
    local buttonAnims = {}
    local animDuration = 0.5
    local animDelay = 0.08
    local subButtons = {}
    local descriptionPanel = nil -- Панель описания для кнопок и подкнопок
    local function ModernButtonPaint(s, w, h, idx, progress)
        -- Серый полупрозрачный круг
        local hovered = s:IsHovered()
        local baseAlpha = hovered and 180 or 120
        local borderAlpha = hovered and 220 or 150
        local textAlpha = hovered and 255 or 200
        surface.SetDrawColor(80, 80, 80, baseAlpha)
        draw.NoTexture()
        surface.DrawCircle(w / 2, h / 2, w / 2 - 2, 80, 80, 80, baseAlpha)
        -- Обводка
        surface.SetDrawColor(180, 180, 180, borderAlpha)
        surface.DrawCircle(w / 2, h / 2, w / 2 - 4, 180, 180, 180, borderAlpha)
        -- Эффект наведения (легкое высветление)
        if hovered then
            surface.SetDrawColor(255, 255, 255, 30)
            surface.DrawCircle(w / 2, h / 2, w / 2 - 2, 255, 255, 255, 30)
        end

        -- Текст
        draw.SimpleText(idx, "DermaLarge", w / 2, h / 2, Color(220, 220, 220, textAlpha), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
    end

    -- Объявляем функции CreateSubButtons и RemoveSubButtons заранее, чтобы они были видимы в CreateCircularMenu
    local function CreateSubButtons(parent, mainBtn, idx)
    end

    local function RemoveSubButtons(idx)
    end

    local function CreateCircularMenu()
        if IsValid(menuPanel) then
            menuPanel:Remove()
            menuPanel = nil
        end

        buttonAnims = {}
        local radius = 150
        local buttonsCount = 8
        local angleStep = 2 * math.pi / buttonsCount
        menuPanel = vgui.Create("DPanel")
        if not IsValid(menuPanel) then return end
        menuPanel:SetSize(ScrW(), ScrH())
        menuPanel:SetPos(0, 0)
        menuPanel:SetPaintBackground(false)
        -- Блюр фона
        menuPanel.Paint = function(self, w, h) Derma_DrawBackgroundBlur(self, self.m_fCreateTime or SysTime()) end
        menuPanel.m_fCreateTime = SysTime()
        -- Показываем курсор
        menuPanel:SetMouseInputEnabled(true)
        menuPanel:SetKeyboardInputEnabled(true)
        gui.EnableScreenClicker(true)
        local center = {
            x = ScrW() / 2,
            y = ScrH() / 2
        }

        for i = 1, buttonsCount do
            local angle = (i - 1) * angleStep - math.pi / 2
            local btnX = center.x + math.cos(angle) * radius
            local btnY = center.y + math.sin(angle) * radius
            local startY = ScrH() + 100
            local btn = vgui.Create("DButton", menuPanel)
            if not IsValid(btn) then continue end
            btn:SetSize(64, 64)
            btn:SetPos(btnX - 32, startY)
            btn:SetText("")
            btn:SetFont("DermaLarge")
            btn:SetZPos(i)
            btn.Paint = function(s, w, h)
                local anim = buttonAnims[i]
                local progress = anim and anim.progress or 1
                ModernButtonPaint(s, w, h, i, progress)
            end

            btn.OnCursorEntered = function(s)
                local anim = buttonAnims[i]
                if not anim or anim.progress < 1 then return end
                local desc = buttonData[i] and buttonData[i].desc or ("Описание кнопки " .. i)
                ShowDescription(desc)
                CreateSubButtons(menuPanel, s, i)
            end
            btn.DoClick = function()
                if buttonData[i] and buttonData[i].action then
                    buttonData[i].action()
                end
                if IsValid(menuPanel) then
                    menuPanel:Remove()
                    menuPanel = nil
                end
            end

            buttonAnims[i] = {
                start = CurTime() + (i - 1) * animDelay,
                progress = 0,
                btn = btn,
                fromY = startY,
                toY = btnY - 32,
                toX = btnX - 32
            }
        end

        menuPanel.Think = function(self)
            local allDone = true
            for i, anim in ipairs(buttonAnims) do
                local btn = anim.btn
                if not IsValid(btn) then continue end
                local t = CurTime() - anim.start
                if t < 0 then
                    btn:SetPos(anim.toX, anim.fromY)
                    allDone = false
                elseif t < animDuration then
                    local p = math.min(1, t / animDuration)
                    p = 1 - (1 - p) * (1 - p)
                    local y = Lerp(p, anim.fromY, anim.toY)
                    btn:SetPos(anim.toX, y)
                    anim.progress = p
                    allDone = false
                else
                    btn:SetPos(anim.toX, anim.toY)
                    anim.progress = 1
                end
            end

            if allDone then self.Think = nil end
        end

        menuPanel.OnRemove = function()
            gui.EnableScreenClicker(false)
            HideDescription()
        end

        -- Закрытие меню при нажатии вне панели
        menuPanel.OnMousePressed = function(self, code)
            if code == MOUSE_LEFT and not self:IsHovered() then
                self:Remove()
                menuPanel = nil
            end
        end
    end

    -- Реализация CreateSubButtons
    function CreateSubButtons(parent, mainBtn, idx)
        -- Проверяем, есть ли уже валидные подкнопки
        local needCreate = false
        if not subButtons[idx] or #subButtons[idx] ~= 4 then
            needCreate = true
        else
            for _, sbtn in ipairs(subButtons[idx]) do
                if not IsValid(sbtn) then
                    needCreate = true
                    break
                end
            end
        end

        if not needCreate then return end
        RemoveSubButtons(idx)
        local subBtnCount = 4
        local subBtnRadius = 48
        local subBtnSize = 36
        subButtons[idx] = {}
        local x, y = mainBtn:GetPos()
        local w, h = mainBtn:GetSize()
        local cx, cy = x + w / 2, y + h / 2
        for j = 1, subBtnCount do
            local angle = (j - 1) * (2 * math.pi / subBtnCount) - math.pi / 2
            local sx = cx + math.cos(angle) * subBtnRadius - subBtnSize / 2
            local sy = cy + math.sin(angle) * subBtnRadius - subBtnSize / 2
            local subBtn = vgui.Create("DButton", parent)
            subBtn:SetSize(subBtnSize, subBtnSize)
            subBtn:SetPos(cx - subBtnSize / 2, cy - subBtnSize / 2)
            subBtn:SetText("")
            subBtn:SetZPos(100 + j)
            subBtn._targetPos = {
                x = sx,
                y = sy
            }

            subBtn._anim = 0
            subBtn._mainBtn = mainBtn
            subBtn._idx = idx
            subBtn._j = j
            subBtn.Paint = function(s, w2, h2)
                local hovered = s:IsHovered()
                local baseAlpha = hovered and 200 or 140
                local borderAlpha = hovered and 240 or 180
                local textAlpha = hovered and 255 or 200
                surface.SetDrawColor(80, 80, 80, baseAlpha)
                draw.NoTexture()
                surface.DrawCircle(w2 / 2, h2 / 2, w2 / 2 - 2, 80, 80, 80, baseAlpha)
                surface.SetDrawColor(180, 180, 180, borderAlpha)
                surface.DrawCircle(w2 / 2, h2 / 2, w2 / 2 - 4, 180, 180, 180, borderAlpha)
                if hovered then
                    surface.SetDrawColor(255, 255, 255, 40)
                    surface.DrawCircle(w2 / 2, h2 / 2, w2 / 2 - 2, 255, 255, 255, 40)
                end

                draw.SimpleText(j, "DermaDefault", w2 / 2, h2 / 2, Color(220, 220, 220, textAlpha), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
            end

            subBtn.DoClick = function()
                if subButtonData[idx] and subButtonData[idx][j] and subButtonData[idx][j].action then
                    subButtonData[idx][j].action()
                else
                    print("Подкнопка " .. j .. " основной " .. idx)
                end
            end
            subBtn.OnCursorEntered = function(s)
                local desc = subButtonData[idx] and subButtonData[idx][j] and subButtonData[idx][j].desc or ("Описание подкнопки " .. j .. " основной " .. idx)
                ShowDescription(desc)
            end
            subBtn.OnCursorExited = function(s) HideDescription() end
            subBtn.Think = function(s)
                local hovered = IsValid(mainBtn) and (mainBtn:IsHovered() or s:IsHovered())
                local mx, my = input.GetCursorPos()
                local hoverRadius = 80
                if IsValid(mainBtn) then
                    local bx, by = mainBtn:GetPos()
                    local bw, bh = mainBtn:GetSize()
                    local bcx, bcy = bx + bw / 2, by + bh / 2
                    if PointInCircle(mx, my, bcx, bcy, hoverRadius) then hovered = true end
                end

                if not hovered then
                    s._anim = math.max(0, s._anim - FrameTime() * 10)
                else
                    s._anim = math.min(1, s._anim + FrameTime() * 10)
                end

                local tx = Lerp(s._anim, cx - subBtnSize / 2, s._targetPos.x)
                local ty = Lerp(s._anim, cy - subBtnSize / 2, s._targetPos.y)
                s:SetPos(tx, ty)
                s:SetAlpha(255 * s._anim)
                if s._anim < 0.05 and not hovered then s:Remove() end
            end

            table.insert(subButtons[idx], subBtn)
        end
    end

    -- Реализация RemoveSubButtons
    function RemoveSubButtons(idx)
        if not subButtons[idx] then return end
        local mainBtn = nil
        for i, anim in ipairs(buttonAnims) do
            if i == idx then
                mainBtn = anim.btn
                break
            end
        end

        if not IsValid(mainBtn) then return end
        local x, y = mainBtn:GetPos()
        local w, h = mainBtn:GetSize()
        local cx, cy = x + w / 2, y + h / 2
        local mx, my = input.GetCursorPos()
        local hoverRadius = 80
        if PointInCircle(mx, my, cx, cy, hoverRadius) then return end
        for _, sbtn in ipairs(subButtons[idx]) do
            if IsValid(sbtn) and sbtn:IsHovered() then return end
        end

        for _, sbtn in ipairs(subButtons[idx]) do
            if IsValid(sbtn) then sbtn:Remove() end
        end

        subButtons[idx] = nil
    end

    function ShowDescription(text)
        if not IsValid(descriptionPanel) then
            descriptionPanel = vgui.Create("DPanel")
            descriptionPanel:SetSize(ScrW(), 40)
            descriptionPanel:SetPos(0, 0)
            descriptionPanel:SetZPos(9999)
            descriptionPanel.Paint = function(self, w, h)
                surface.SetDrawColor(30, 30, 30, 220)
                surface.DrawRect(0, 0, w, h)
            end

            descriptionPanel.label = vgui.Create("DLabel", descriptionPanel)
            descriptionPanel.label:SetFont("DermaLarge")
            descriptionPanel.label:SetTextColor(Color(255, 255, 255))
            descriptionPanel.label:SetPos(20, 6)
            descriptionPanel.label:SetSize(ScrW() - 40, 32)
        end

        descriptionPanel.label:SetText(text)
        descriptionPanel:SetVisible(true)
    end

    function HideDescription()
        if IsValid(descriptionPanel) then descriptionPanel:SetVisible(false) end
    end

    -- Таблица с описаниями и действиями для основных кнопок
    buttonData = {
        [1] = { desc = "Отыгровка действий [По умолчанию исполнить партийное приветствие.]", action = function() print("Открыт инвентарь!") end },
        [2] = { desc = "Открыть карту", action = function() print("Открыта карта!") end },
        [3] = { desc = "Профиль игрока", action = function() print("Профиль!") end },
        [4] = { desc = "Настройки", action = function() print("Настройки!") end },
        [5] = { desc = "Помощь", action = function() print("Помощь!") end },
        [6] = { desc = "Магазин", action = function() print("Магазин!") end },
        [7] = { desc = "Достижения", action = function() print("Достижения!") end },
        [8] = { desc = "Выход", action = function() print("Выход!") end },
    }
    -- Таблица с описаниями и действиями для подкнопок
    subButtonData = {
        [1] = {
            [1] = { desc = "Подкнопка 1-1", action = function() print("Подкнопка 1-1") end },
            [2] = { desc = "Подкнопка 1-2", action = function() print("Подкнопка 1-2") end },
            [3] = { desc = "Подкнопка 1-3", action = function() print("Подкнопка 1-3") end },
            [4] = { desc = "Подкнопка 1-4", action = function() print("Подкнопка 1-4") end },
        },
        [2] = {
            [1] = { desc = "Подкнопка 2-1", action = function() print("Подкнопка 2-1") end },
            [2] = { desc = "Подкнопка 2-2", action = function() print("Подкнопка 2-2") end },
            [3] = { desc = "Подкнопка 2-3", action = function() print("Подкнопка 2-3") end },
            [4] = { desc = "Подкнопка 2-4", action = function() print("Подкнопка 2-4") end },
        },
        [3] = {
            [1] = { desc = "Подкнопка 3-1", action = function() print("Подкнопка 3-1") end },
            [2] = { desc = "Подкнопка 3-2", action = function() print("Подкнопка 3-2") end },
            [3] = { desc = "Подкнопка 3-3", action = function() print("Подкнопка 3-3") end },
            [4] = { desc = "Подкнопка 3-4", action = function() print("Подкнопка 3-4") end },
        },
        [4] = {
            [1] = { desc = "Подкнопка 4-1", action = function() print("Подкнопка 4-1") end },
            [2] = { desc = "Подкнопка 4-2", action = function() print("Подкнопка 4-2") end },
            [3] = { desc = "Подкнопка 4-3", action = function() print("Подкнопка 4-3") end },
            [4] = { desc = "Подкнопка 4-4", action = function() print("Подкнопка 4-4") end },
        },
        [5] = {
            [1] = { desc = "Подкнопка 5-1", action = function() print("Подкнопка 5-1") end },
            [2] = { desc = "Подкнопка 5-2", action = function() print("Подкнопка 5-2") end },
            [3] = { desc = "Подкнопка 5-3", action = function() print("Подкнопка 5-3") end },
            [4] = { desc = "Подкнопка 5-4", action = function() print("Подкнопка 5-4") end },
        },
        [6] = {
            [1] = { desc = "Подкнопка 6-1", action = function() print("Подкнопка 6-1") end },
            [2] = { desc = "Подкнопка 6-2", action = function() print("Подкнопка 6-2") end },
            [3] = { desc = "Подкнопка 6-3", action = function() print("Подкнопка 6-3") end },
            [4] = { desc = "Подкнопка 6-4", action = function() print("Подкнопка 6-4") end },
        },
        [7] = {
            [1] = { desc = "Подкнопка 7-1", action = function() print("Подкнопка 7-1") end },
            [2] = { desc = "Подкнопка 7-2", action = function() print("Подкнопка 7-2") end },
            [3] = { desc = "Подкнопка 7-3", action = function() print("Подкнопка 7-3") end },
            [4] = { desc = "Подкнопка 7-4", action = function() print("Подкнопка 7-4") end },
        },
        [8] = {
            [1] = { desc = "Подкнопка 8-1", action = function() print("Подкнопка 8-1") end },
            [2] = { desc = "Подкнопка 8-2", action = function() print("Подкнопка 8-2") end },
            [3] = { desc = "Подкнопка 8-3", action = function() print("Подкнопка 8-3") end },
            [4] = { desc = "Подкнопка 8-4", action = function() print("Подкнопка 8-4") end },
        },
    }

    hook.Add("OnContextMenuOpen", "OpenCircularMenu", function()
        if not IsValid(menuPanel) then CreateCircularMenu() end
        return true
    end)

    hook.Add("OnContextMenuClose", "CloseCircularMenu", function()
        if IsValid(menuPanel) then
            menuPanel:Remove()
            menuPanel = nil
            gui.EnableScreenClicker(false)
        end
    end)
end
```