



  

<!DOCTYPE html>
<html
  lang="en"
  
  data-color-mode="auto" data-light-theme="light" data-dark-theme="dark"
  data-a11y-animated-images="system" data-a11y-link-underlines="true"
  
  >




  <head>
    <meta charset="utf-8">
  <link rel="dns-prefetch" href="https://github.githubassets.com">
  <link rel="dns-prefetch" href="https://avatars.githubusercontent.com">
  <link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com">
  <link rel="dns-prefetch" href="https://user-images.githubusercontent.com/">
  <link rel="preconnect" href="https://github.githubassets.com" crossorigin>
  <link rel="preconnect" href="https://avatars.githubusercontent.com">

<script type="importmap">{"imports":{"react":"https://github.githubassets.com/assets/react-e27d1b3e03961e68.js","react-dom":"https://github.githubassets.com/assets/react-dom-e5fd46a22d5c4058.js","react-dom/client":"https://github.githubassets.com/assets/react-dom-client-1b4a3ee065998cea.js","react-is":"https://github.githubassets.com/assets/react-is-e0b593954b4706d8.js","react-reconciler":"https://github.githubassets.com/assets/react-reconciler-8e99e505c4429605.js","react/compiler-runtime":"https://github.githubassets.com/assets/react-compiler-runtime-4610bd6d3de9c049.js","react/jsx-dev-runtime":"https://github.githubassets.com/assets/react-jsx-dev-runtime-ea55d68667d559e5.js","react/jsx-runtime":"https://github.githubassets.com/assets/react-jsx-runtime-4915cb0f5b3aff04.js","scheduler":"https://github.githubassets.com/assets/scheduler-58b860b049ca307c.js"}}</script>
<meta name="react-profiling" content="0" data-turbo-transient="true" />
<meta name="react-import-map" content="react,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@777f63f87cd0" data-turbo-track="reload" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-e27d1b3e03961e68.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-compiler-runtime-4610bd6d3de9c049.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/scheduler-58b860b049ca307c.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-dom-e5fd46a22d5c4058.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-dom-client-1b4a3ee065998cea.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-is-e0b593954b4706d8.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-jsx-runtime-4915cb0f5b3aff04.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-reconciler-8e99e505c4429605.js" />

  


  <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light-5c4e9fc574bf49f3.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light_high_contrast-fb37c309e0603a69.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark-afff6c53aef9b9d1.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark_high_contrast-c409873d7987dffa.css" /><link data-color-theme="light" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light-5c4e9fc574bf49f3.css" /><link data-color-theme="light_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_high_contrast-fb37c309e0603a69.css" /><link data-color-theme="light_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind-0f910d8806d5761b.css" /><link data-color-theme="light_colorblind_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind_high_contrast-a7abd4d4c49ac593.css" /><link data-color-theme="light_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia-5fc4c4a9cb41e596.css" /><link data-color-theme="light_tritanopia_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia_high_contrast-ed0cee9214dedabd.css" /><link data-color-theme="dark" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark-afff6c53aef9b9d1.css" /><link data-color-theme="dark_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_high_contrast-c409873d7987dffa.css" /><link data-color-theme="dark_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind-78a2491d538dab5a.css" /><link data-color-theme="dark_colorblind_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind_high_contrast-c26b63d7c532d0a2.css" /><link data-color-theme="dark_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia-a6f60cea68c08405.css" /><link data-color-theme="dark_tritanopia_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia_high_contrast-f66faf28b2ea18b6.css" /><link data-color-theme="dark_dimmed" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed-6701f6218c53cf5b.css" /><link data-color-theme="dark_dimmed_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed_high_contrast-7037fa46ae124d97.css" />

  <style type="text/css">
    :root {
      --tab-size-preference: 4;
    }

    pre, code {
      tab-size: var(--tab-size-preference);
    }
  </style>

    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-primitives-97df7784617ce1ea.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-9be9fe6313f476af.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-62747e27e61258dc.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/github-b04ca6fccda778e2.css" />
  <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repository-72bd7d974b5ac1cc.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-4c5c0895f723f870.css" />

  

  <script type="application/json" id="client-env">{"locale":"en","featureFlags":["actions_caches_react_shell","actions_enable_background_steps","actions_new_hosted_runner_image_select_sizes_and_versions","actions_runners_react_shell","agent_author_search_expansion","agent_author_search_expansion_ui_pulls","alternate_user_config_repo","async_conversion_coverage_enabled","billing_billable_licenses_cost_center_bucket_fix","billing_budget_expiration","billing_cost_center_list_assigned_resources","billing_discount_threshold_notification","code_quality_enablement_banner_targeting","code_quality_remove_preview","code_view_raf_sticky_lines","codespaces_prebuild_region_target_update","coding_agent_third_party_model_ui","copilot_agent_snippy","copilot_ahp_tool_call_timing","copilot_api_agentic_issue_marshal_yaml","copilot_automation_repo_mcp_servers","copilot_automations_pagination","copilot_base_model_policy_row","copilot_chat_auto_mode_v2","copilot_chat_clear_model_selection_for_default_change","copilot_chat_early_task_provisioning","copilot_chat_persist_session_drafts","copilot_chat_vision_dotcom_chat_ga_gate","copilot_css_textarea_autosize","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_duplicate_thread","copilot_extensions_removal_on_marketplace","copilot_fix_failed_workflows_all_skus","copilot_hide_hovercard","copilot_immersive_task_hyperlinking","copilot_mc_cli_resume_any_users_task","copilot_mission_control_agent_merge_fix_ci","copilot_mission_control_agent_merge_resolve_conflicts","copilot_mission_control_awps_batching","copilot_mission_control_early_stop","copilot_mission_control_managed_sandbox_environments","copilot_mission_control_needs_attention","copilot_mission_control_reasoning_effort","copilot_mission_control_sandbox_remote_bypass","copilot_mission_control_task_alive_updates","copilot_mission_control_task_sharing","copilot_org_policy_page_focus_mode","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_swe_agent_authorization_status_ui","copilot_swe_agent_automation_resource_scoped_writes","copilot_swe_agent_discussion_comment_trigger","copilot_swe_agent_discussion_opened_trigger","copilot_swe_agent_discussion_updated_trigger","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_issue_assigned_trigger","copilot_swe_agent_issue_comment_trigger","copilot_swe_agent_issue_labeled_trigger","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_pull_request_assigned_trigger","copilot_swe_agent_pull_request_comment_trigger","copilot_swe_agent_pull_request_labeled_trigger","copilot_swe_agent_pull_request_merged_trigger","copilot_swe_agent_pull_request_opened_trigger","copilot_swe_agent_pull_request_ready_for_review_trigger","copilot_swe_agent_pull_request_review_requested_trigger","copilot_swe_agent_pull_request_review_submitted_trigger","copilot_swe_agent_pull_request_synchronize_trigger","copilot_swe_agent_sub_issue_added_trigger","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_task_scoped_alive_channel","copilot_token_based_billing","copilot_unconfigured_is_inherited","copilot_user_can_upgrade_plan_field","copilot_web_integration_cutover","copilot_workbench_sunset_redirect","dashboard_agents_module_auth_token_check","dashboard_indexeddb_caching","fgpat_permissions_selector_redesign","glc_code_quality_repo_settings_workflow_config","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","in_product_messaging_datadog_monitoring","ipm_ubb_individual_budget_banner","issue_fields_multi_select","issue_inline_avatars","issue_pinned_views","issue_pinned_views_team_vs_personal","issue_relative_time_micro","issue_viewer_paved_path","issues_expanded_file_types","issues_hide_closed_sub_issues","issues_lazy_load_comment_box_suggestions","issues_react_chrome_container_query_fix","labels_archiving","labels_archiving_info","landing_pages_ninetailed","lifecycle_label_name_updates","marketing_cookie_consent_banner","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","memex_remove_deprecated_type_issue","merge_queue_restricted_pushers_warning","merge_status_header_feedback","milestone_closed_issues_prioritization","octocaptcha_origin_optimization","primer_react_css_anchor_positioning","primer_react_merged_forwarded_refs","primer_react_timeline_list_semantics","prs_copilot_app_open_action","prs_css_anchor_positioning","pull_request_copilot_attribution_header","pull_request_overview_merge_control","pull_request_overview_panel_edit_description","pull_request_persister","pull_request_stacks_navigation_shortcuts","pull_request_virtualization_image_estimate","pull_request_virtualization_loader_batching","pull_request_virtualization_scroll_compensation","pull_request_virtualization_scroll_intent","quick_search_lazy_suggestions","react_blob_isolate_code_lines","react_blob_ssr_content_visibility","react_data_router_tanstack_allowed","react_logged_out_repository_header","react_query_props_with_key","react_sandbox_future_tanstack","repo_app_turbo","repo_issues_sidebar_layout","repo_pulls_dashboard_declutter","repo_pulls_dashboard_ga","repo_pulls_dashboard_persistence","repos_contributors_limited_default_range","review_involves_filter","rule_ignored_file_paths","rulesets_actor_list_editor","sample_network_conn_type","security_center_artifact_filters_popover","see_who_reacted","semantic_similarity_duplicate_issue_detection","session_logs_ungroup_reasoning_text","set_sha256_on_repo_creation_form","site_banner_desktop_copilot_app","site_ghca_pixel_mona","site_github_app_ga_page","site_github_app_ga_page_highlight","site_github_app_mobile_native_share","site_global_banner_dev_days_attendee","site_global_nav_spark_models_removed","speculation_rules_ui_service","suggest_custom_property_values_copilot","suppress_automated_browser_vitals","swp_forms_disable_octocaptcha","thread_resolution_reason","update_issue_suggestions","viewscreen_sandbox","warn_inaccessible_attachments","webp_support","workstream_plugin_bootstrap"],"githubDomain":"https://github.com","copilotApiOverrideUrl":"https://api.githubcopilot.com","cmcApiUrl":"https://api.github.com/cmc_internal/api"}</script>
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/high-contrast-cookie-3663bcaacc724f4c.js"></script>
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wp-runtime-721126455a2225e3.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-foundation-156c6259e31cc551.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-runtime-f6ce38f47c2e1d56.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fetch-utilities-804a14996977c014.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ser-fb5d13278eb42203.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/tp-ea613009a991e211.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/environment-107a7753389a8a2d.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/app-runtime.25915bc98fb322a6.module.css" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/catalyst-52ed81112a548e10.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/selector-observer-e8810f64c443fb9b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/relative-time-element-fe7e72f699fdf493.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/by-9da36843ba9d191d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ja9-9a1160b939f2cd52.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/3h-55903cf2303047ad.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hk-0d35a1220587d888.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/jz5-c964b1a3671f2a92.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hj-1d800d09e9a8720a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j0-1ad12374da9777f2.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/github-elements-531d35538b61fd0d.js" defer="defer"></script>
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/element-registry-bf5e3b2aee197122.js" defer="defer"></script>
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/runtime-helpers-5e0b3ae3c4036207.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/aria-live-752acdc868e2da64.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hotkey-e87ffadced20a3c9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-core-75bc55d9971828b7.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/a9-34620c7b13885011.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ur-643d2814115561a9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4t6-5d0869970ac0aac0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/pb0-a5c5ec36d311aeef.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/6n-afcf86ccabc4cad2.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/zj-f08c728cf00018aa.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/o6-2a1c68d269710ee9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/h9a-c6405aa090de0e84.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/vy6-3c3e6e96629c2ce4.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/js-4eb97d5803e657c0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/g7-baf9e817ae102b01.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/unc-96389cade7bad821.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/nu-65322a6997c6c93c.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/behaviors-5dd3809b5c8bac3c.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/react-core.3792087592bf207a.module.css" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/code-menu-4318f0f4c608f3dd.js" defer="defer"></script>
  
  <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/primer-react-7afef75d393cf294.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/op-acddf38478d45ef9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ncx-461e4b09f2e67ee5.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/qmp-c7cfba40cf5a93b0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j6-148a74299e5a01ab.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/t7l-a52ba56147f77909.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4u-ec4874f70bfd5d76.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/s0-481bd34f90bc2bd7.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/y5-ed17e73b4c0bd15e.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/n4-be595475cdbf7d4b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j8-23a3c5ff8eef412d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/la-27679061f16e1495.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/iu-9806a0291a782cbe.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ftx-39fb490e3c1d778f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/zi-32a0c3c081ea5cce.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/sg-7a5d50475874c0e1.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/pd-6a8710840033e042.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/86g-ec28c25ed7d5de06.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/sn-1bab7384818953b7.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/iq-6d4ecf6d2fb6993c.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/p2-7d8e7cee5b46cb45.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/7d-2e3cc25d719f3a95.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4d-76d8acdf21a33266.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/tsb-e0f6288ab985d9d2.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/lf-910ef220ce85c660.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/2j-2f19c1afd2ceaf93.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/me-f1476ec44a29f34a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/p2u-e654a57b1a70c47d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/5d-d97cc006d4da4d9b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/r5-38f013bc2c0fd298.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/r6s-9039f5619230a653.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/9e-cece06724bf6ea3b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/x9-3e077a3a37a73f9f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/pj-87629cb5389d7663.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/eq-3764fd5f66494289.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/13-d889936dff7e5c0f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/44-8193eea4af825ead.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/v4-9c1327d212e52a0d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/id-7f39706ba9007db6.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ah-271362a1ed227d03.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/s1g-d434d712bca59d3a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/vz-d7f4a583896f872e.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/47-c8c0ce2700acc5be.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/code-view-4118a687d0150749.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/pj.75627bfeb9ceb1da.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/ah.2623f7c6ecbe2ecd.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/47.78770c57a48a810c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-view.37656c95a9729fb9.module.css" />


  <title>freecut/CLAUDE.md at main · tepn11/freecut · GitHub</title>



  <meta name="route-pattern" content="/:user_id/:repository/blob/*name(/*path)" data-turbo-transient>
  <meta name="route-controller" content="blob" data-turbo-transient>
  <meta name="route-action" content="show" data-turbo-transient>
  <meta name="fetch-nonce" content="v2:63fd8549-0e48-a248-5131-a31bdfe013ec">

    
  <meta name="current-catalog-service-hash" content="f3abb0cc802f3d7b95fc8762b94bdcb13bf39634c40c357301c4aa1d67a256fb">


  <meta name="request-id" content="EC2E:D77D6:BB6EBF1:F3AAA94:6ACA6CCC" data-pjax-transient="true"/><meta name="html-safe-nonce" content="4d1bc24ce14f7f33c44e8b84a5ef2cec246b8ce2e3c636fb7c22ffbd169c199d" data-pjax-transient="true"/><meta name="visitor-payload" content="eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFQzJFOkQ3N0Q2OkJCNkVCRjE6RjNBQUE5NDo2QUNBNkNDQyIsInZpc2l0b3JfaWQiOiI1MTMxMTUxOTYzNzk5MDU1NTY0IiwicmVnaW9uX2VkZ2UiOiJmcmEiLCJyZWdpb25fcmVuZGVyIjoiZnJhIn0=" data-pjax-transient="true"/><meta name="visitor-hmac" content="4cbf34ab2a2e20e2d60e29c14a457528a196089bf792d8a5bb335b225667aee3" data-pjax-transient="true"/>


    <meta name="hovercard-subject-tag" content="repository:1300428482" data-turbo-transient>


  <meta name="github-keyboard-shortcuts" content="repository,source-code,file-tree,copilot" data-turbo-transient="true" />
  

  <meta name="selected-link" value="repo_source" data-turbo-transient>
  <link rel="assets" href="https://github.githubassets.com/">

    <meta name="google-site-verification" content="Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I">

<meta name="octolytics-url" content="https://collector.github.com/github/collect" />





  <meta name="analytics-location" content="/&lt;user-name&gt;/&lt;repo-name&gt;/blob/show" data-turbo-transient="true" />

  




    <meta name="user-login" content="">

  

    <meta name="viewport" content="width=device-width">

    

      <meta name="description" content="FreeCut is a professional-grade video editor that runs entirely in your browser. Professional video editing, zero installation. Create stunning videos with multi-track editing, keyframe animations, real-time preview, and high-quality exports. - freecut/CLAUDE.md at main · tepn11/freecut">

      <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">

    <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
    <meta property="fb:app_id" content="1401488693436528">
    <meta name="apple-itunes-app" content="app-id=1477376905, app-argument=https://github.com/tepn11/freecut/blob/main/CLAUDE.md" />

      <meta name="twitter:image" content="https://opengraph.githubassets.com/d1d51225ffe8a4f35fea0aed3ebf3f95f44a1bc60e17366d542b6358e88a1e4a/tepn11/freecut" /><meta name="twitter:site" content="@github" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:title" content="freecut/CLAUDE.md at main · tepn11/freecut" /><meta name="twitter:description" content="FreeCut is a professional-grade video editor that runs entirely in your browser. Professional video editing, zero installation. Create stunning videos with multi-track editing, keyframe animations,..." />
  <meta property="og:image" content="https://opengraph.githubassets.com/d1d51225ffe8a4f35fea0aed3ebf3f95f44a1bc60e17366d542b6358e88a1e4a/tepn11/freecut" /><meta property="og:image:alt" content="FreeCut is a professional-grade video editor that runs entirely in your browser. Professional video editing, zero installation. Create stunning videos with multi-track editing, keyframe animations,..." /><meta property="og:image:width" content="1200" /><meta property="og:image:height" content="600" /><meta property="og:site_name" content="GitHub" /><meta property="og:type" content="object" /><meta property="og:title" content="freecut/CLAUDE.md at main · tepn11/freecut" /><meta property="og:url" content="https://github.com/tepn11/freecut/blob/main/CLAUDE.md" /><meta property="og:description" content="FreeCut is a professional-grade video editor that runs entirely in your browser. Professional video editing, zero installation. Create stunning videos with multi-track editing, keyframe animations,..." />
  




      <meta name="hostname" content="github.com">



        <meta name="expected-hostname" content="github.com">


  <meta http-equiv="x-pjax-version" content="d05be8f8b6905b6460fc264e80447721dfee1e32cf9e4291c4bf58f160c9f705" data-turbo-track="reload">
  <meta http-equiv="x-pjax-csp-version" content="c4a65e47b0c850e1157ae8e66298070851d7e3b558038de5a3b4ff7a93e630ed" data-turbo-track="reload">
  <meta http-equiv="x-pjax-css-version" content="a80b0545b169f440b929ce2b977c76b6988f014cca6513fb83c5df6581635fb3" data-turbo-track="reload">
  <meta http-equiv="x-pjax-js-version" content="af51c6f9d659be0324665373df3ee542f817dbd7f66f352a087935f2ceabe545" data-turbo-track="reload">

  <meta name="turbo-cache-control" content="no-preview" data-turbo-transient="">

      <meta name="turbo-cache-control" content="no-cache" data-turbo-transient>

    <meta data-hydrostats="publish">

  <meta name="go-import" content="github.com/tepn11/freecut git https://github.com/tepn11/freecut.git">

  <meta name="octolytics-dimension-user_id" content="14833808" /><meta name="octolytics-dimension-user_login" content="tepn11" /><meta name="octolytics-dimension-repository_id" content="1300428482" /><meta name="octolytics-dimension-repository_nwo" content="tepn11/freecut" /><meta name="octolytics-dimension-repository_public" content="true" /><meta name="octolytics-dimension-repository_is_fork" content="true" /><meta name="octolytics-dimension-repository_parent_id" content="1097654343" /><meta name="octolytics-dimension-repository_parent_nwo" content="walterlow/freecut" /><meta name="octolytics-dimension-repository_network_root_id" content="1097654343" /><meta name="octolytics-dimension-repository_network_root_nwo" content="walterlow/freecut" />
  



    

    <meta name="turbo-body-classes" content="logged-out env-production page-responsive">
  <meta name="disable-turbo" content="false">


  <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats">


  <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors">

  <meta name="release" content="3b1bb5b10f5c7fd1769d56e38b15dfddb34052a8" data-turbo-track="reload">
  <meta name="ui-target" content="full">

  <link rel="mask-icon" href="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" color="#000000">
  <link rel="alternate icon" class="js-site-favicon" type="image/png" href="https://github.githubassets.com/favicons/favicon.png">
  <link rel="icon" class="js-site-favicon" type="image/svg+xml" href="https://github.githubassets.com/favicons/favicon.svg" data-base-href="https://github.githubassets.com/favicons/favicon">

<meta name="theme-color" content="#1e2327">
<meta name="color-scheme" content="light dark" />


  <link rel="manifest" href="/manifest.json" crossOrigin="use-credentials">

  </head>

  <body class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
    <div data-turbo-body class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
      <div id="__primerPortalRoot__" style="z-index: 1000; position: absolute; width: 100%;" data-turbo-permanent></div>
      

    <div class="position-relative header-wrapper js-header-wrapper ">
      <a href="#start-of-content" data-skip-target-assigned="false" class="px-2 tmp-py-4 color-bg-accent-emphasis color-fg-on-emphasis show-on-focus js-skip-to-content">Skip to content</a>

      <span data-view-component="true" class="progress-pjax-loader Progress position-fixed width-full">
    <span style="width: 0%;" data-view-component="true" class="Progress-item progress-pjax-loader-bar left-0 top-0 color-bg-accent-emphasis"></span>
</span>      
      <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/19-c660652a0a1639be.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/keyboard-shortcuts-dialog-47c5223d8d1af8ef.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/keyboard-shortcuts-dialog.d53d993320d57e14.module.css" />

<react-partial
  partial-name="keyboard-shortcuts-dialog"
  data-ssr="false"
  data-attempted-ssr="false"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{"docsUrl":"https://docs.github.com/get-started/accessibility/keyboard-shortcuts"}}</script>
  <div data-target="react-partial.reactRoot"></div>
</react-partial>





      

          <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-install-banner-partial-3c87deb7f0f20434.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/app-install-banner-partial.7b357012e82003e7.module.css" />

<react-partial
  partial-name="app-install-banner-partial"
  data-ssr="false"
  data-attempted-ssr="false"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{}}</script>
  <div data-target="react-partial.reactRoot"></div>
</react-partial>


          

                <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/et9-7eeec247c287fca4.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/94v-e20946127faa8f6e.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fz5-892a9e99cc92858d.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/jag-441e702bfd4c7904.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hw-8ce7888b57d0a23c.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/rq-0ec82a12cf538a4d.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/1m-a7a4c022483b2713.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/marketing-header-70703fe17422eb58.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-brand-css.fbc35b3d20e988ff.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/1m.fec8b575d0e5234f.module.css" />

<react-partial
  partial-name="marketing-header"
  data-ssr="true"
  data-attempted-ssr="true"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{"color_mode":"dark","logged_in":false,"marketing_page":false,"home_path":"/","login_path":"/login?return_to=https%3A%2F%2Fgithub.com%2Ftepn11%2Ffreecut%2Fblob%2Fmain%2FCLAUDE.md","signup_path":"/signup?ref_cta=Sign+up\u0026ref_loc=header+logged+out\u0026ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fblob%2Fshow\u0026source=header-repo\u0026source_repo=tepn11%2Ffreecut","signup_enabled":true,"is_signup_controller":false,"show_search_and_nav":true,"hide_search":false,"private_mode_enabled":false,"should_use_dotcom_links":true,"auth_hydro_click":"{\"event_type\":\"authentication.click\",\"payload\":{\"location_in_page\":\"site header menu\",\"repository_id\":null,\"auth_type\":\"SIGN_UP\",\"originating_url\":\"https://github.com/tepn11/freecut/blob/main/CLAUDE.md\",\"user_id\":null}}","auth_hydro_click_hmac":"c191bf21438b1c54322fa01bdf063ce55e6897ffdd797a45e37a49af679f45fa","overlay":false,"fixed":false}}</script>
  <div data-target="react-partial.reactRoot"><div data-color-mode="dark" data-light-theme="light" data-dark-theme="dark"><header class="MarketingHeader-module__root__Tk7n3 HeaderMktg header-logged-out" role="banner" data-marketing-header="true" data-color-mode="dark" data-light-theme="light" data-dark-theme="dark" data-is-top="true"><h2 class="MarketingHeader-module__visuallyHidden__sqKsl">Navigation Menu</h2><button type="button" class="MarketingHeader-module__backdrop__sw4RU" aria-label="Close navigation menu"></button><div class="MarketingHeader-module__bar__mBSyE"><div class="MarketingHeader-module__topRow__yeury"><div class="MarketingHeader-module__toggleSlot__hDxbh"><button type="button" class="HeaderMenuToggle-module__toggle__i8EiC" aria-label="Toggle navigation" aria-expanded="false"><span class="HeaderMenuToggle-module__toggleBar__jVN0H"></span><span class="HeaderMenuToggle-module__toggleBar__jVN0H"></span><span class="HeaderMenuToggle-module__toggleBar__jVN0H"></span></button></div><a href="/" aria-label="Homepage" class="HeaderLogo-module__logo__UFyHI" data-analytics-event="{&quot;action&quot;:&quot;homepage&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;logo&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;homepage_link_logo_header&quot;}"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mark-github" viewBox="0 0 24 24" width="32" height="32" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.226 17.284c-2.965-.36-5.054-2.493-5.054-5.256 0-1.123.404-2.336 1.078-3.144-.292-.741-.247-2.314.09-2.965.898-.112 2.111.36 2.83 1.01.853-.269 1.752-.404 2.853-.404 1.1 0 1.999.135 2.807.382.696-.629 1.932-1.1 2.83-.988.315.606.36 2.179.067 2.942.72.854 1.101 2 1.101 3.167 0 2.763-2.089 4.852-5.098 5.234.763.494 1.28 1.572 1.28 2.807v2.336c0 .674.561 1.056 1.235.786 4.066-1.55 7.255-5.615 7.255-10.646C23.5 6.188 18.334 1 11.978 1 5.62 1 .5 6.188.5 12.545c0 4.986 3.167 9.12 7.435 10.669.606.225 1.19-.18 1.19-.786V20.63a2.9 2.9 0 0 1-1.078.224c-1.483 0-2.359-.808-2.987-2.313-.247-.607-.517-.966-1.034-1.033-.27-.023-.359-.135-.359-.27 0-.27.45-.471.898-.471.652 0 1.213.404 1.797 1.235.45.651.921.943 1.483.943.561 0 .92-.202 1.437-.719.382-.381.674-.718.944-.943"></path></svg></a><div class="AuthCTAs-module__mobileActions__NNzeV"><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw AuthCTAs-module__cta__WpwQq" href="/login?return_to=https%3A%2F%2Fgithub.com%2Ftepn11%2Ffreecut%2Fblob%2Fmain%2FCLAUDE.md" data-analytics-event="{&quot;action&quot;:&quot;sign_in&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;auth_cta&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;sign_in_link_auth_cta_header&quot;}" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/tepn11/freecut/blob/main/CLAUDE.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="c191bf21438b1c54322fa01bdf063ce55e6897ffdd797a45e37a49af679f45fa"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH">Sign in</span></span></a><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw HeaderAppearanceSettings-module__trigger__hUheK" type="button" aria-haspopup="dialog" aria-labelledby="_R_3dd_"><span class="Primer_Brand__Button-module__Button__leading-visual___jjtTe" data-testid="Button-leading-visual"><svg data-component="Octicon" focusable="false" aria-hidden="true" class="octicon octicon-sliders Primer_Brand__Button-module__Button__icon-visual____qybb" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M15 2.75a.75.75 0 0 1-.75.75h-4a.75.75 0 0 1 0-1.5h4a.75.75 0 0 1 .75.75Zm-8.5.75v1.25a.75.75 0 0 0 1.5 0v-4a.75.75 0 0 0-1.5 0V2H1.75a.75.75 0 0 0 0 1.5H6.5Zm1.25 5.25a.75.75 0 0 0 0-1.5h-6a.75.75 0 0 0 0 1.5h6ZM15 8a.75.75 0 0 1-.75.75H11.5V10a.75.75 0 1 1-1.5 0V6a.75.75 0 0 1 1.5 0v1.25h2.75A.75.75 0 0 1 15 8Zm-9 5.25v-2a.75.75 0 0 0-1.5 0v1.25H1.75a.75.75 0 0 0 0 1.5H4.5v1.25a.75.75 0 0 0 1.5 0v-2Zm9 0a.75.75 0 0 1-.75.75h-6a.75.75 0 0 1 0-1.5h6a.75.75 0 0 1 .75.75Z"></path></svg></span><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH"></span></span></button><div class="Primer_Brand__Tooltip-module__Tooltip___0Eipx" data-direction="s" aria-hidden="true" id="_R_3dd_">Appearance settings</div></div></div><div class="MarketingHeader-module__menu__GIy3y"><div class="MarketingHeader-module__menuWrapper__owstH"><nav class="MarketingNavigation-module__nav__W0KYY" aria-label="Global"><ul class="MarketingNavigation-module__list__tFbMb"><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_nd_">Platform<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_nd_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5knd_">AI CODE CREATION</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5knd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/copilot" data-analytics-event="{&quot;action&quot;:&quot;github_copilot&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_copilot_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copilot NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"></path><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"></path></svg>GitHub Copilot</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Write better code with AI</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/ai/github-app" data-analytics-event="{&quot;action&quot;:&quot;github_copilot_app&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_copilot_app_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mark-github NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M6.766 11.328c-2.063-.25-3.516-1.734-3.516-3.656 0-.781.281-1.625.75-2.188-.203-.515-.172-1.609.063-2.062.625-.078 1.468.25 1.968.703.594-.187 1.219-.281 1.985-.281.765 0 1.39.094 1.953.265.484-.437 1.344-.765 1.969-.687.218.422.25 1.515.046 2.047.5.593.766 1.39.766 2.203 0 1.922-1.453 3.375-3.547 3.64.531.344.89 1.094.89 1.954v1.625c0 .468.391.734.86.547C13.781 14.359 16 11.53 16 8.03 16 3.61 12.406 0 7.984 0 3.563 0 0 3.61 0 8.031a7.88 7.88 0 0 0 5.172 7.422c.422.156.828-.125.828-.547v-1.25c-.219.094-.5.156-.75.156-1.031 0-1.64-.562-2.078-1.609-.172-.422-.36-.672-.719-.719-.187-.015-.25-.093-.25-.187 0-.188.313-.328.625-.328.453 0 .844.281 1.25.86.313.452.64.655 1.031.655s.641-.14 1-.5c.266-.265.47-.5.657-.656"></path></svg>GitHub Copilot app</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Direct agents from issue to merge</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/mcp" data-analytics-event="{&quot;action&quot;:&quot;mcp_registry&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;mcp_registry_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mcp NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5.52 1.12a3.578 3.578 0 0 1 6.078 2.98 3.578 3.578 0 0 1 2.982 6.08l-3.292 3.293a.252.252 0 0 0 0 .354l.843.843a.749.749 0 1 1-1.06 1.06l-.844-.843a1.75 1.75 0 0 1 0-2.474L13.52 9.12a2.08 2.08 0 0 0 0-2.94 2.08 2.08 0 0 0-2.94 0L7.731 9.03A.75.75 0 0 1 6.67 7.97l2.85-2.85a2.08 2.08 0 0 0 0-2.94 2.08 2.08 0 0 0-2.94 0l-4.799 4.8A.75.75 0 0 1 .72 5.92Z"></path><path d="M7.52 3.12a.749.749 0 1 1 1.06 1.06L5.731 7.03A2.079 2.079 0 0 0 8.67 9.97l2.85-2.85a.749.749 0 1 1 1.06 1.06l-2.849 2.85A3.578 3.578 0 0 1 4.67 5.97Z"></path></svg>MCP Registry</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Integrate external tools</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9knd_">DEVELOPER WORKFLOWS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9knd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/actions" data-analytics-event="{&quot;action&quot;:&quot;actions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;actions_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-workflow NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75C0 .784.784 0 1.75 0h3.5C6.216 0 7 .784 7 1.75v3.5A1.75 1.75 0 0 1 5.25 7H4v4a1 1 0 0 0 1 1h4v-1.25C9 9.784 9.784 9 10.75 9h3.5c.966 0 1.75.784 1.75 1.75v3.5A1.75 1.75 0 0 1 14.25 16h-3.5A1.75 1.75 0 0 1 9 14.25v-.75H5A2.5 2.5 0 0 1 2.5 11V7h-.75A1.75 1.75 0 0 1 0 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Zm9 9a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Z"></path></svg>Actions</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Automate any workflow</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/codespaces" data-analytics-event="{&quot;action&quot;:&quot;codespaces&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;codespaces_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-codespaces NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 11.25c0-.966.784-1.75 1.75-1.75h12.5c.966 0 1.75.784 1.75 1.75v3A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm2-9.5C2 .784 2.784 0 3.75 0h8.5C13.216 0 14 .784 14 1.75v5a1.75 1.75 0 0 1-1.75 1.75h-8.5A1.75 1.75 0 0 1 2 6.75Zm1.75-.25a.25.25 0 0 0-.25.25v5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-5a.25.25 0 0 0-.25-.25Zm-2 9.5a.25.25 0 0 0-.25.25v3c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-3a.25.25 0 0 0-.25-.25Z"></path><path d="M7 12.75a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Zm-4 0a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1-.75-.75Z"></path></svg>Codespaces</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Instant dev environments</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/issues" data-analytics-event="{&quot;action&quot;:&quot;issues&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;issues_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-issue-opened NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path></svg>Issues</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Plan and track work</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/code-review" data-analytics-event="{&quot;action&quot;:&quot;code_review&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;code_review_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path></svg>Code Review</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Manage code changes</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/code-quality" data-analytics-event="{&quot;action&quot;:&quot;code_quality&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;code_quality_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-codescan-checkmark NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.28 6.28a.75.75 0 1 0-1.06-1.06L6.25 8.19l-.97-.97a.75.75 0 0 0-1.06 1.06l1.5 1.5a.75.75 0 0 0 1.06 0l3.5-3.5Z"></path><path d="M7.5 15a7.5 7.5 0 1 1 5.807-2.754l2.473 2.474a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2.474-2.473A7.472 7.472 0 0 1 7.5 15Zm0-13.5a6 6 0 1 0 4.094 10.386.748.748 0 0 1 .293-.292 6.002 6.002 0 0 0 1.117-6.486A6.002 6.002 0 0 0 7.5 1.5Z"></path></svg>Code Quality</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enforce quality at merge</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dknd_">APPLICATION SECURITY</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dknd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security" data-analytics-event="{&quot;action&quot;:&quot;github_advanced_security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_advanced_security_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield-check NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m8.533.133 5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68a1.748 1.748 0 0 1 1.066 0Zm-.61 1.429.001.001-5.25 1.68a.251.251 0 0 0-.174.237V7c0 1.36.275 2.666 1.057 3.859.784 1.194 2.121 2.342 4.366 3.298a.196.196 0 0 0 .154 0c2.245-.957 3.582-2.103 4.366-3.297C13.225 9.666 13.5 8.358 13.5 7V3.48a.25.25 0 0 0-.174-.238l-5.25-1.68a.25.25 0 0 0-.153 0ZM11.28 6.28l-3.5 3.5a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.97-2.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg>GitHub Advanced Security</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Find and fix vulnerabilities</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security/code-security" data-analytics-event="{&quot;action&quot;:&quot;code_security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;code_security_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code-square NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25Zm7.47 3.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L10.69 8 9.22 6.53a.75.75 0 0 1 0-1.06ZM6.78 6.53 5.31 8l1.47 1.47a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg>Code security</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Secure your code as you build</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security/secret-protection" data-analytics-event="{&quot;action&quot;:&quot;secret_protection&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;secret_protection_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-lock NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M4 4a4 4 0 0 1 8 0v2h.25c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 12.25 15h-8.5A1.75 1.75 0 0 1 2 13.25v-5.5C2 6.784 2.784 6 3.75 6H4Zm8.25 3.5h-8.5a.25.25 0 0 0-.25.25v5.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25ZM10.5 6V4a2.5 2.5 0 1 0-5 0v2Z"></path></svg>Secret protection</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Stop leaks before they start</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ NavGroup-module__hasSeparator__FnMrN"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_hknd_">EXPLORE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_hknd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/why-github" data-analytics-event="{&quot;action&quot;:&quot;why_github&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;why_github_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Why GitHub</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://docs.github.com" data-analytics-event="{&quot;action&quot;:&quot;documentation&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;documentation_link_platform_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Documentation</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://github.blog" data-analytics-event="{&quot;action&quot;:&quot;blog&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;blog_link_platform_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Blog</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://github.blog/changelog" data-analytics-event="{&quot;action&quot;:&quot;changelog&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;changelog_link_platform_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Changelog</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/marketplace" data-analytics-event="{&quot;action&quot;:&quot;marketplace&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;marketplace_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Marketplace</span></a></li></ul></div></li></ul><div class="NavDropdown-module__trailingLinkContainer__VgJGL"><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/features" data-analytics-event="{&quot;action&quot;:&quot;view_all_features&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_features_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all features</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></div></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_17d_">Solutions<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_17d_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5l7d_">BY COMPANY SIZE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5l7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/enterprise" data-analytics-event="{&quot;action&quot;:&quot;enterprises&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;enterprises_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Enterprises</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/team" data-analytics-event="{&quot;action&quot;:&quot;small_and_medium_teams&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;small_and_medium_teams_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Small and medium teams</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/enterprise/startups" data-analytics-event="{&quot;action&quot;:&quot;startups&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;startups_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Startups</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/nonprofits" data-analytics-event="{&quot;action&quot;:&quot;nonprofits&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;nonprofits_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Nonprofits</span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9l7d_">BY USE CASE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9l7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/app-modernization" data-analytics-event="{&quot;action&quot;:&quot;app_modernization&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;app_modernization_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">App Modernization</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/devsecops" data-analytics-event="{&quot;action&quot;:&quot;devsecops&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;devsecops_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">DevSecOps</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/devops" data-analytics-event="{&quot;action&quot;:&quot;devops&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;devops_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">DevOps</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/ci-cd" data-analytics-event="{&quot;action&quot;:&quot;ci/cd&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;ci/cd_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">CI/CD</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/solutions/use-case" data-analytics-event="{&quot;action&quot;:&quot;view_all_use_cases&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_use_cases_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all use cases</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dl7d_">BY INDUSTRY</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dl7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/healthcare" data-analytics-event="{&quot;action&quot;:&quot;healthcare&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;healthcare_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Healthcare</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/financial-services" data-analytics-event="{&quot;action&quot;:&quot;financial_services&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;financial_services_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Financial services</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/manufacturing" data-analytics-event="{&quot;action&quot;:&quot;manufacturing&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;manufacturing_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Manufacturing</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/government" data-analytics-event="{&quot;action&quot;:&quot;government&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;government_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Government</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/solutions/industry" data-analytics-event="{&quot;action&quot;:&quot;view_all_industries&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_industries_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all industries</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></li></ul></div></li></ul><div class="NavDropdown-module__trailingLinkContainer__VgJGL"><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/solutions" data-analytics-event="{&quot;action&quot;:&quot;view_all_solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_solutions_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all solutions</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></div></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_1nd_">Resources<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_1nd_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5lnd_">EXPLORE BY TOPIC</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5lnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=ai" data-analytics-event="{&quot;action&quot;:&quot;ai&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;ai_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">AI</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=software-development" data-analytics-event="{&quot;action&quot;:&quot;software_development&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;software_development_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Software Development</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=devops" data-analytics-event="{&quot;action&quot;:&quot;devops&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;devops_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">DevOps</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=security" data-analytics-event="{&quot;action&quot;:&quot;security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;security_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Security</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/resources/articles" data-analytics-event="{&quot;action&quot;:&quot;view_all_topics&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_topics_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all topics</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9lnd_">EXPLORE BY TYPE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9lnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/customer-stories" data-analytics-event="{&quot;action&quot;:&quot;customer_stories&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;customer_stories_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Customer stories</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/events" data-analytics-event="{&quot;action&quot;:&quot;events__webinars&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;events__webinars_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Events &amp; webinars</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/whitepapers" data-analytics-event="{&quot;action&quot;:&quot;ebooks__reports&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;ebooks__reports_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Ebooks &amp; reports</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/executive-insights" data-analytics-event="{&quot;action&quot;:&quot;business_insights&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;business_insights_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Business insights</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://skills.github.com" data-analytics-event="{&quot;action&quot;:&quot;github_skills&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_skills_link_resources_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">GitHub Skills</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dlnd_">SUPPORT &amp; SERVICES</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dlnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://docs.github.com" data-analytics-event="{&quot;action&quot;:&quot;documentation&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;documentation_link_resources_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Documentation</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://support.github.com" data-analytics-event="{&quot;action&quot;:&quot;customer_support&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;customer_support_link_resources_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Customer support</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/orgs/community/discussions" data-analytics-event="{&quot;action&quot;:&quot;community_forum&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;community_forum_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Community forum</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/trust-center" data-analytics-event="{&quot;action&quot;:&quot;trust_center&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;trust_center_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Trust center</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/partners" data-analytics-event="{&quot;action&quot;:&quot;partners&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;partners_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Partners</span></a></li></ul></div></li></ul><div class="NavDropdown-module__trailingLinkContainer__VgJGL"><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/resources" data-analytics-event="{&quot;action&quot;:&quot;view_all_resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_resources_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all resources</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></div></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_27d_">Open Source<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_27d_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5m7d_">COMMUNITY</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5m7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/open-source/sponsors" data-analytics-event="{&quot;action&quot;:&quot;github_sponsors&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_sponsors_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-sponsor-tiers NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.586 1C12.268 1 13.5 2.37 13.5 4.25c0 1.745-.996 3.359-2.622 4.831-.166.15-.336.297-.509.438l1.116 5.584a.75.75 0 0 1-.991.852l-2.409-.876a.25.25 0 0 0-.17 0l-2.409.876a.75.75 0 0 1-.991-.852L5.63 9.519a13.78 13.78 0 0 1-.51-.438C3.497 7.609 2.5 5.995 2.5 4.25 2.5 2.37 3.732 1 5.414 1c.963 0 1.843.403 2.474 1.073L8 2.198l.112-.125a3.385 3.385 0 0 1 2.283-1.068L10.586 1Zm-3.621 9.495-.718 3.594 1.155-.42a1.75 1.75 0 0 1 1.028-.051l.168.051 1.154.42-.718-3.592c-.199.13-.37.235-.505.314l-.169.097a.75.75 0 0 1-.72 0 9.54 9.54 0 0 1-.515-.308l-.16-.105ZM10.586 2.5c-.863 0-1.611.58-1.866 1.459-.209.721-1.231.721-1.44 0C7.025 3.08 6.277 2.5 5.414 2.5 4.598 2.5 4 3.165 4 4.25c0 1.23.786 2.504 2.128 3.719.49.443 1.018.846 1.546 1.198l.325.21.076-.047.251-.163a13.341 13.341 0 0 0 1.546-1.198C11.214 6.754 12 5.479 12 4.25c0-1.085-.598-1.75-1.414-1.75Z"></path></svg>GitHub Sponsors</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Fund open source developers</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9m7d_">PROGRAMS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9m7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://securitylab.github.com" data-analytics-event="{&quot;action&quot;:&quot;security_lab&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;security_lab_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Security Lab</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://maintainers.github.com" data-analytics-event="{&quot;action&quot;:&quot;maintainer_community&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;maintainer_community_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Maintainer Community</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://stars.github.com" data-analytics-event="{&quot;action&quot;:&quot;github_stars&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_stars_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">GitHub Stars</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://archiveprogram.github.com" data-analytics-event="{&quot;action&quot;:&quot;archive_program&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;archive_program_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Archive Program</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dm7d_">REPOSITORIES</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dm7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/topics" data-analytics-event="{&quot;action&quot;:&quot;topics&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;topics_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Topics</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/trending" data-analytics-event="{&quot;action&quot;:&quot;trending&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;trending_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Trending</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/collections" data-analytics-event="{&quot;action&quot;:&quot;collections&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;collections_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Collections</span></a></li></ul></div></li></ul></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_2nd_">Enterprise<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_2nd_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5mnd_">ENTERPRISE SOLUTIONS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5mnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/enterprise" data-analytics-event="{&quot;action&quot;:&quot;enterprise_platform&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;enterprise_platform_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-stack NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.122.392a1.75 1.75 0 0 1 1.756 0l5.003 2.902c.83.481.83 1.68 0 2.162L8.878 8.358a1.75 1.75 0 0 1-1.756 0L2.119 5.456a1.251 1.251 0 0 1 0-2.162ZM8.125 1.69a.248.248 0 0 0-.25 0l-4.63 2.685 4.63 2.685a.248.248 0 0 0 .25 0l4.63-2.685ZM1.601 7.789a.75.75 0 0 1 1.025-.273l5.249 3.044a.248.248 0 0 0 .25 0l5.249-3.044a.75.75 0 0 1 .752 1.298l-5.248 3.044a1.75 1.75 0 0 1-1.756 0L1.874 8.814A.75.75 0 0 1 1.6 7.789Zm0 3.5a.75.75 0 0 1 1.025-.273l5.249 3.044a.248.248 0 0 0 .25 0l5.249-3.044a.75.75 0 0 1 .752 1.298l-5.248 3.044a1.75 1.75 0 0 1-1.756 0l-5.248-3.044a.75.75 0 0 1-.273-1.025Z"></path></svg>Enterprise platform</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">AI-powered developer platform</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9mnd_">AVAILABLE ADD-ONS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9mnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security" data-analytics-event="{&quot;action&quot;:&quot;github_advanced_security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_advanced_security_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield-check NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m8.533.133 5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68a1.748 1.748 0 0 1 1.066 0Zm-.61 1.429.001.001-5.25 1.68a.251.251 0 0 0-.174.237V7c0 1.36.275 2.666 1.057 3.859.784 1.194 2.121 2.342 4.366 3.298a.196.196 0 0 0 .154 0c2.245-.957 3.582-2.103 4.366-3.297C13.225 9.666 13.5 8.358 13.5 7V3.48a.25.25 0 0 0-.174-.238l-5.25-1.68a.25.25 0 0 0-.153 0ZM11.28 6.28l-3.5 3.5a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.97-2.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg>GitHub Advanced Security</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enterprise-grade security features</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/copilot/copilot-business" data-analytics-event="{&quot;action&quot;:&quot;copilot_for_business&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;copilot_for_business_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copilot NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"></path><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"></path></svg>Copilot for Business</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enterprise-grade AI features</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/enterprise/premium-support" data-analytics-event="{&quot;action&quot;:&quot;premium_support&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;premium_support_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-comment-discussion NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"></path></svg>Premium Support</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enterprise-grade 24/7 support</span></span></a></li></ul></div></li></ul></div></div></li><li><a href="https://github.com/pricing" data-analytics-event="{&quot;action&quot;:&quot;pricing&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;pricing&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;pricing_link_pricing_navbar&quot;}" class="MarketingNavigation-module__navLink__hUomM">Pricing</a></li></ul></nav><div class="MarketingHeader-module__ctaContainer__tBmPz"><div class="HeaderSearch-module__searchSlot__oVOUS"><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw HeaderSearch-module__trigger__zsF9q" type="button" aria-haspopup="dialog" aria-expanded="false" aria-label="Search or jump to, type / to search" data-analytics-event="{&quot;action&quot;:&quot;searchbar&quot;,&quot;tag&quot;:&quot;input&quot;,&quot;context&quot;:&quot;global&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;searchbar_input_global_navbar&quot;}"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH"><span class="HeaderSearch-module__content__kMpxU"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-search HeaderSearch-module__icon__wcrHX" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path></svg><span class="HeaderSearch-module__label__d1iWG">Search</span><kbd class="HeaderSearch-module__kbd__HNG0o" aria-hidden="true">/</kbd></span></span></span></button><div class="d-none"></div></div><div class="AuthCTAs-module__signInWrap__q2P60"><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw AuthCTAs-module__cta__WpwQq AuthCTAs-module__desktopActionGap__UZuXT AuthCTAs-module__hiddenBelowLg__BfKBw" href="/login?return_to=https%3A%2F%2Fgithub.com%2Ftepn11%2Ffreecut%2Fblob%2Fmain%2FCLAUDE.md" data-analytics-event="{&quot;action&quot;:&quot;sign_in&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;auth_cta&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;sign_in_link_auth_cta_header&quot;}" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/tepn11/freecut/blob/main/CLAUDE.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="c191bf21438b1c54322fa01bdf063ce55e6897ffdd797a45e37a49af679f45fa"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH">Sign in</span></span></a></div><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--secondary___gHnw_ Primer_Brand__Button-module__Button--size-small___zQrEw AuthCTAs-module__cta__WpwQq" href="/signup?ref_cta=Sign+up&amp;ref_loc=header+logged+out&amp;ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fblob%2Fshow&amp;source=header-repo&amp;source_repo=tepn11%2Ffreecut" data-analytics-event="{&quot;action&quot;:&quot;sign_up&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;auth_cta&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;sign_up_link_auth_cta_header&quot;}" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/tepn11/freecut/blob/main/CLAUDE.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="c191bf21438b1c54322fa01bdf063ce55e6897ffdd797a45e37a49af679f45fa"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-secondary___eJ0_a">Sign up</span></span></a><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw HeaderAppearanceSettings-module__trigger__hUheK" type="button" aria-haspopup="dialog" aria-labelledby="_R_fbd_"><span class="Primer_Brand__Button-module__Button__leading-visual___jjtTe" data-testid="Button-leading-visual"><svg data-component="Octicon" focusable="false" aria-hidden="true" class="octicon octicon-sliders Primer_Brand__Button-module__Button__icon-visual____qybb" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M15 2.75a.75.75 0 0 1-.75.75h-4a.75.75 0 0 1 0-1.5h4a.75.75 0 0 1 .75.75Zm-8.5.75v1.25a.75.75 0 0 0 1.5 0v-4a.75.75 0 0 0-1.5 0V2H1.75a.75.75 0 0 0 0 1.5H6.5Zm1.25 5.25a.75.75 0 0 0 0-1.5h-6a.75.75 0 0 0 0 1.5h6ZM15 8a.75.75 0 0 1-.75.75H11.5V10a.75.75 0 1 1-1.5 0V6a.75.75 0 0 1 1.5 0v1.25h2.75A.75.75 0 0 1 15 8Zm-9 5.25v-2a.75.75 0 0 0-1.5 0v1.25H1.75a.75.75 0 0 0 0 1.5H4.5v1.25a.75.75 0 0 0 1.5 0v-2Zm9 0a.75.75 0 0 1-.75.75h-6a.75.75 0 0 1 0-1.5h6a.75.75 0 0 1 .75.75Z"></path></svg></span><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH"></span></span></button><div class="Primer_Brand__Tooltip-module__Tooltip___0Eipx" data-direction="s" aria-hidden="true" id="_R_fbd_">Appearance settings</div></div></div></div></div><div class="MarketingHeader-module__bottomBorder__uZT38" aria-hidden="true"></div></header></div></div>
</react-partial>



      <div hidden="hidden" data-view-component="true" class="js-stale-session-flash stale-session-flash flash flash-warn flash-full">
  
        <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert">
    <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
</svg>
        <span class="js-stale-session-flash-signed-in" hidden>You signed in with another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span>
        <span class="js-stale-session-flash-signed-out" hidden>You signed out in another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span>
        <span class="js-stale-session-flash-switched" hidden>You switched accounts on another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span>

    <button id="icon-button-0d7d277a-80f1-43d9-ad0f-0b866890e629" aria-labelledby="tooltip-717ab1d6-357f-407d-8efa-4d8c827662fb" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium flash-close js-flash-close">  <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x Button-visual">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
</button><tool-tip id="tooltip-717ab1d6-357f-407d-8efa-4d8c827662fb" for="icon-button-0d7d277a-80f1-43d9-ad0f-0b866890e629" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Dismiss alert</tool-tip>


  
</div>
    </div>

  <div id="start-of-content" class="show-on-focus"></div>








    <div id="js-flash-container" class="flash-container" data-turbo-replace>






  <template class="js-flash-template">
    
<div class="flash flash-full   {{ className }}">
  <div >
    <button autofocus class="flash-close js-flash-close" type="button" aria-label="Dismiss this message">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
    </button>
    <div aria-atomic="true" role="alert" class="js-flash-alert">
      
      <div>{{ message }}</div>

    </div>
  </div>
</div>
  </template>
</div>


    






  <div
    class="application-main "
    data-commit-hovercards-enabled
    data-discussion-hovercards-enabled
    data-issue-and-pr-hovercards-enabled
    data-project-hovercards-enabled
  >
        <div itemscope itemtype="http://schema.org/SoftwareSourceCode" class="">
    <main id="js-repo-pjax-container" >
      
      








  

    <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ym-6bc2c9bf8112c038.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/sk2-8deeef9351be3911.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ni-3e194d222c7770bf.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/7x-71d30cb240cd901f.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wwk-ad869086822937b1.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/a1-9f79841ecac1da8e.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wzg-40a3213b3e83400b.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/5f-64f8e7d5bcbd4787.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/z5-b53a93078d026f1e.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/8h-cef26f68c1331011.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fq-3ce13a77e863807a.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/a7-596b507bd20acddc.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/xfx-c82d8352413aea0a.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j4-b3a9e87fa7878a98.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/global-nav-bar-29c7aef68ee9db41.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.2d881b4d4a503d1c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/pj.75627bfeb9ceb1da.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-nav-bar.2f2560cba06ab359.module.css" />

<react-partial
  partial-name="global-nav-bar"
  data-ssr="true"
  data-attempted-ssr="true"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{"contextRegion":{"crumbs":[{"crumb_type":"user","label":"tepn11","is_root":false,"href":"/tepn11"},{"crumb_type":"repository","label":"freecut","is_root":false,"octicon":"repo-forked","href":"/tepn11/freecut"}],"localNavigation":[{"id":"code","icon":"code","label":"Code","href":"/tepn11/freecut","selectedLinks":["repo_source","repo_downloads","repo_commits","repo_releases","repo_tags","repo_branches","repo_packages","repo_deployments","repo_attestations"],"popoverTarget":false,"commandId":"repositories:go-to-code","reactNav":{"appTarget":"code-view","anchor":"code-view-repo-link"},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"pull-requests","icon":"git-pull-request","label":"Pull requests","href":"/tepn11/freecut/pulls","selectedLinks":["repo_pulls","checks"],"count":0,"popoverTarget":false,"commandId":"repositories:go-to-pull-requests","reactNav":{"appTarget":null,"anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"actions","icon":"play","label":"Actions","href":"/tepn11/freecut/actions","selectedLinks":["repo_actions"],"popoverTarget":false,"commandId":"repositories:go-to-actions","reactNav":{"appTarget":"actions-workflows","anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"projects","icon":"table","label":"Projects","href":"/tepn11/freecut/projects","selectedLinks":["repo_projects","new_repo_project","repo_project"],"popoverTarget":false,"commandId":"repositories:go-to-projects","reactNav":{"appTarget":"repo","anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"security-and-quality","icon":"shield","label":"Security and quality","href":"/tepn11/freecut/security","selectedLinks":["security","overview","alerts","policy","token_scanning","code_scanning"],"count":0,"popoverTarget":false,"commandId":"repositories:go-to-security","reactNav":{"appTarget":null,"anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}},{"id":"insights","icon":"graph","label":"Insights","href":"/tepn11/freecut/pulse","selectedLinks":["repo_graphs","repo_contributors","dependency_graph","dependabot_updates","pulse","people","community"],"popoverTarget":false,"commandId":"repositories:go-to-insights","reactNav":{"appTarget":null,"anchor":null},"turboNav":{"frame":"repo-content-turbo-frame"}}],"localNavigationUpdateChannel":null,"selectedLink":"repo_source"},"owner":null,"headerLogo":{"href":"/","aria-label":"Homepage "},"notifications":{"indicatorMode":"disabled","websocketChannel":null,"fetchIndicatorSrc":"/notifications/indicator","fetchIndicatorEnabled":false},"issues":{"href":"/issues"},"pulls":{"href":"/pulls"},"contributedRepos":{"href":"/repos"},"copilot":{"show":false,"showAgentsButton":false,"showRelaunchAnnouncement":false,"copilotChatUrl":null,"copilotApiUrl":"https://api.githubcopilot.com"},"search":{"show":true,"showCommandPalette":false,"isSearchPage":false,"isJumpToSearch":false,"searchContext":{"scope":"repo:tepn11/freecut","current_repo_name":"freecut","current_repo_nwo":"tepn11/freecut","user_id":"tepn11"}},"commandPalette":null,"enterpriseBar":{"show":false},"globalTransactionalMessage":[],"payloadsUrl":"/_global-navigation/payloads.json?can_toggle_site_admin_and_employee_status=0\u0026is_admin_mode_on=0\u0026is_ui_opted_out=0\u0026show_ui_opt_out=0\u0026v=7","contextRegionUrl":"/_global-navigation/context-region.json"}}</script>
  <div data-target="react-partial.reactRoot"><header aria-label="Global navigation menu" data-component="Stack" class="GlobalNav styles-module__appHeader__YzYWk prc-Stack-Stack-UQ9k6" data-gap="none" data-direction="vertical" data-align="stretch" data-wrap="nowrap" data-justify="start" data-padding="none"><div data-component="Stack" class="prc-Stack-Stack-UQ9k6" data-direction="horizontal" data-align="center" data-wrap="nowrap" data-justify="center" data-padding="none"><div data-testid="top-nav-center" data-component="Stack" class="styles-module__center__R3QRv styles-module__withLocalNavigation__rjTJ_ GlobalNavBar-module__loggedOut__Jv1rk prc-Stack-Stack-UQ9k6" data-gap="condensed" data-direction="horizontal" data-align="stretch" data-wrap="nowrap" data-justify="start" data-padding="normal"><nav class="styles-module__contextRegion__VbSp2 prc-Breadcrumbs-BreadcrumbsBase-3Gb-B" aria-label="Breadcrumbs" data-overflow="menu" data-variant="normal" data-component="Breadcrumbs"><ol class="prc-Breadcrumbs-BreadcrumbsList-BKjpe"><li class="prc-Breadcrumbs-ItemWrapper-k0NLn"><a class="styles-module__contextCrumb__IzGIq prc-Breadcrumbs-Item-jcraJ" data-component="Breadcrumbs.Item" href="/tepn11" data-discover="true"><span class="">tepn11</span></a></li><li class="prc-Breadcrumbs-ItemWrapper-k0NLn"><a class="styles-module__contextCrumb__IzGIq prc-Breadcrumbs-Item-jcraJ" data-component="Breadcrumbs.Item" href="/tepn11/freecut" data-discover="true"><span class="styles-module__contextCrumbLast__tI2e3">freecut</span><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-repo-forked styles-module__trailingIcon__sCKDh" viewBox="0 0 16 16" width="12" height="12" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path></svg></a></li></ol></nav></div><div data-testid="top-nav-right" data-component="Stack" class="styles-module__right__mlBQg styles-module__withLocalNavigation__rjTJ_ styles-module__rightWithResponsiveCreateButton__SKn2W prc-Stack-Stack-UQ9k6" data-gap="condensed" data-direction="horizontal" data-align="center" data-wrap="nowrap" data-justify="start" data-padding="normal"></div></div><h2 class="prc-src-InternalVisuallyHidden-2YaI6">Repository navigation</h2><nav class="prc-components-UnderlineWrapper-eT-Yj prc-UnderlineNav-UnderlineWrapper-GWONT LocalNavigation-module__LocalNavigation__b0Xc0" aria-label="Repository" data-variant="inset" data-overflow-mode="wrap" data-hide-icons-breakpoint="medium"><ul class="prc-UnderlineNav-ItemsList-oj8gN prc-components-UnderlineItemList-xKlKC" role="list"><li role="presentation" aria-hidden="true" class="prc-UnderlineNav-WrapSpacer--aLgz"></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a aria-current="page" data-tab-item="code" data-react-nav="code-view" data-react-nav-anchor="code-view-repo-link" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/tepn11/freecut" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path></svg></span><span data-component="text" data-content="Code">Code</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="pull-requests" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/tepn11/freecut/pulls" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-git-pull-request" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path></svg></span><span data-component="text" data-content="Pull requests">Pull requests</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="actions" data-react-nav="actions-workflows" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/tepn11/freecut/actions" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-play" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path></svg></span><span data-component="text" data-content="Actions">Actions</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="projects" data-react-nav="repo" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/tepn11/freecut/projects" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-table" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM6.5 6.5v8h7.75a.25.25 0 0 0 .25-.25V6.5Zm8-1.5V1.75a.25.25 0 0 0-.25-.25H6.5V5Zm-13 1.5v7.75c0 .138.112.25.25.25H5v-8ZM5 5V1.5H1.75a.25.25 0 0 0-.25.25V5Z"></path></svg></span><span data-component="text" data-content="Projects">Projects</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="security-and-quality" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/tepn11/freecut/security" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg></span><span data-component="text" data-content="Security and quality">Security and quality</span></a></li><li class="prc-UnderlineNav-UnderlineNavItem-syRjR"><a data-tab-item="insights" data-turbo-frame="repo-content-turbo-frame" class="prc-components-UnderlineItem-7fP-n" href="/tepn11/freecut/pulse" data-discover="true"><span data-component="icon"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-graph" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg></span><span data-component="text" data-content="Insights">Insights</span></a></li></ul><div class="prc-UnderlineNav-MoreButtonContainer-Dnrq6"><div class="prc-UnderlineNav-MoreButtonDivider-dN0a-"></div><button data-component="overflow-menu-button" type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk prc-UnderlineNav-MoreButton-Y8soj" data-loading="false" data-size="medium" data-variant="invisible" id="_R_2ktp_"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3"><span>More<span class="prc-src-InternalVisuallyHidden-2YaI6"> items</span></span></span></span><span data-component="trailingAction" class="prc-Button-Visual-YNt2F prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></button></div></nav><div class="d-none"></div></header></div>
</react-partial>


  



<turbo-frame id="repo-content-turbo-frame" target="_top" data-turbo-action="advance" class="">
    <div id="repo-content-pjax-container" class="repository-content " >
    



    
      
    








<react-app
  app-name="code-view"
  initial-path="/tepn11/freecut/blob/main/CLAUDE.md"
  style="display: block; min-height: calc(100vh - 64px);"
  data-attempted-ssr="true"
  data-ssr="true"
  data-lazy="false"
  data-alternate="false"
  data-data-router-enabled="true"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-app.embeddedData">{"payload":{"codeViewBlobRoute":{"csv":null,"csvError":null,"headerInfo":{"toc":[{"level":1,"text":"FreeCut Web","anchor":"freecut-web","htmlText":"FreeCut Web"},{"level":2,"text":"Commands","anchor":"commands","htmlText":"Commands"},{"level":2,"text":"Architecture","anchor":"architecture","htmlText":"Architecture"},{"level":2,"text":"Key Patterns","anchor":"key-patterns","htmlText":"Key Patterns"},{"level":2,"text":"Code Style","anchor":"code-style","htmlText":"Code Style"},{"level":2,"text":"Testing","anchor":"testing","htmlText":"Testing"},{"level":2,"text":"Environment","anchor":"environment","htmlText":"Environment"},{"level":2,"text":"Toolchain \u0026 dependency notes","anchor":"toolchain--dependency-notes","htmlText":"Toolchain \u0026amp; dependency notes"},{"level":2,"text":"Git","anchor":"git","htmlText":"Git"},{"level":2,"text":"Gotchas","anchor":"gotchas","htmlText":"Gotchas"}]},"issueTemplate":null,"discussionTemplate":null,"richText":"\u003carticle class=\"markdown-body entry-content container-lg\" itemprop=\"text\"\u003e\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eFreeCut Web\u003c/h1\u003e\u003ca id=\"user-content-freecut-web\" class=\"anchor\" aria-label=\"Permalink: FreeCut Web\" href=\"#freecut-web\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCommands\u003c/h2\u003e\u003ca id=\"user-content-commands\" class=\"anchor\" aria-label=\"Permalink: Commands\" href=\"#commands\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"npm run dev          # Vite dev server on port 5173\nnpm run build        # Production build\nnpm run lint         # Oxlint\nnpm run format       # Oxfmt\nnpm run format:check # Check formatting with Oxfmt\nnpm run test         # Vitest (watch mode)\nnpm run test:run     # Vitest (single run)\nnpm run routes       # Regenerate TanStack Router tree (tsr generate)\"\u003e\u003cpre\u003enpm run dev          \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Vite dev server on port 5173\u003c/span\u003e\nnpm run build        \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Production build\u003c/span\u003e\nnpm run lint         \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Oxlint\u003c/span\u003e\nnpm run format       \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Oxfmt\u003c/span\u003e\nnpm run format:check \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Check formatting with Oxfmt\u003c/span\u003e\nnpm run \u003cspan class=\"pl-c1\"\u003etest\u003c/span\u003e         \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Vitest (watch mode)\u003c/span\u003e\nnpm run test:run     \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Vitest (single run)\u003c/span\u003e\nnpm run routes       \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e#\u003c/span\u003e Regenerate TanStack Router tree (tsr generate)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eArchitecture\u003c/h2\u003e\u003ca id=\"user-content-architecture\" class=\"anchor\" aria-label=\"Permalink: Architecture\" href=\"#architecture\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eBrowser-based multi-track video editor. React 19 + TypeScript + Vite.\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"src/\n├── features/              # User-facing UI modules\n│   ├── editor/            # Editor shell, toolbar, panels, stores\n│   ├── timeline/          # Multi-track timeline, actions, services\n│   ├── preview/           # Preview canvas, transform gizmo, scrub renderer\n│   ├── export/            # WebCodecs export pipeline (Web Worker)\n│   ├── effects/           # GPU effect UI panels and registry\n│   ├── keyframes/         # Keyframe animation, Bezier editor, easing\n│   ├── media-library/     # Media import, metadata, OPFS proxies, transcription\n│   ├── project-bundle/    # Project ZIP export/import\n│   ├── projects/          # Project management\n│   ├── scene-browser/     # Caption and scene search UI\n│   ├── settings/          # App settings\n│   └── workspace-gate/    # Workspace picker / permission gate\n├── runtime/               # Playback and rendering engines (not user-facing UI features)\n│   ├── composition-runtime/ # Composition rendering (sequences, items, audio, transitions)\n│   └── player/            # Clock, video source pools, composition playback\n├── infrastructure/        # Platform adapters — browser, storage, GPU, ML, audio\n│   ├── gpu-effects/       # WebGPU effect pipeline + shader definitions\n│   ├── gpu-transitions/   # WebGPU transition pipeline + shaders\n│   ├── gpu-compositor/    # WebGPU blend-mode compositor\n│   ├── gpu-masks/         # Mask combine pipeline + texture manager\n│   ├── gpu-media/         # Media render/blend pipelines\n│   ├── gpu-scopes/        # Waveform/vectorscope/histogram renderers\n│   ├── gpu-shapes/        # Shape render pipeline\n│   ├── gpu-text/          # Glyph-atlas text pipeline\n│   ├── gpu-shared/        # WGSL fragments shared across GPU modules\n│   ├── analysis/          # Scene detection, captioning, embeddings, optical flow\n│   ├── audio/             # SoundTouch-based time-stretch\n│   ├── browser/           # Blob URLs, OPFS, mediabunny adapter\n│   ├── storage/           # Workspace FS persistence + legacy IDB migration\n│   └── thumbnails/        # GPU thumbnail renderer + sampling strategy\n├── shared/                # Framework-agnostic primitives + cross-feature state\n│   ├── timeline/          # Transition engine/registry/renderers, defaults\n│   ├── projects/          # Schema migrations and normalization\n│   ├── state/             # Zustand stores (playback, selection, dialogs, editor)\n│   ├── marquee/           # Marquee-selection hook + overlay (paired unit)\n│   ├── logging/           # Structured logger, frame jitter monitor\n│   ├── ui/                # cn helper, property controls\n│   ├── typography/        # Font loading, text style presets\n│   ├── graphics/          # Shape generators and path helpers\n│   └── utils/             # Managed workers, color/curve math, easing, async, etc.\n├── components/            # shadcn/ui components + brand assets\n├── app/                   # App bootstrap, error boundary, PWA prompt, debug\n├── config/                # Hotkeys + editor layout config\n├── i18n/                  # i18next setup, supported languages, locale JSON + per-feature partials\n├── routes/                # TanStack Router (file-based, auto-generated routeTree)\n└── types/                 # Shared TypeScript types\"\u003e\u003cpre lang=\"text\" class=\"notranslate\"\u003e\u003ccode\u003esrc/\n├── features/              # User-facing UI modules\n│   ├── editor/            # Editor shell, toolbar, panels, stores\n│   ├── timeline/          # Multi-track timeline, actions, services\n│   ├── preview/           # Preview canvas, transform gizmo, scrub renderer\n│   ├── export/            # WebCodecs export pipeline (Web Worker)\n│   ├── effects/           # GPU effect UI panels and registry\n│   ├── keyframes/         # Keyframe animation, Bezier editor, easing\n│   ├── media-library/     # Media import, metadata, OPFS proxies, transcription\n│   ├── project-bundle/    # Project ZIP export/import\n│   ├── projects/          # Project management\n│   ├── scene-browser/     # Caption and scene search UI\n│   ├── settings/          # App settings\n│   └── workspace-gate/    # Workspace picker / permission gate\n├── runtime/               # Playback and rendering engines (not user-facing UI features)\n│   ├── composition-runtime/ # Composition rendering (sequences, items, audio, transitions)\n│   └── player/            # Clock, video source pools, composition playback\n├── infrastructure/        # Platform adapters — browser, storage, GPU, ML, audio\n│   ├── gpu-effects/       # WebGPU effect pipeline + shader definitions\n│   ├── gpu-transitions/   # WebGPU transition pipeline + shaders\n│   ├── gpu-compositor/    # WebGPU blend-mode compositor\n│   ├── gpu-masks/         # Mask combine pipeline + texture manager\n│   ├── gpu-media/         # Media render/blend pipelines\n│   ├── gpu-scopes/        # Waveform/vectorscope/histogram renderers\n│   ├── gpu-shapes/        # Shape render pipeline\n│   ├── gpu-text/          # Glyph-atlas text pipeline\n│   ├── gpu-shared/        # WGSL fragments shared across GPU modules\n│   ├── analysis/          # Scene detection, captioning, embeddings, optical flow\n│   ├── audio/             # SoundTouch-based time-stretch\n│   ├── browser/           # Blob URLs, OPFS, mediabunny adapter\n│   ├── storage/           # Workspace FS persistence + legacy IDB migration\n│   └── thumbnails/        # GPU thumbnail renderer + sampling strategy\n├── shared/                # Framework-agnostic primitives + cross-feature state\n│   ├── timeline/          # Transition engine/registry/renderers, defaults\n│   ├── projects/          # Schema migrations and normalization\n│   ├── state/             # Zustand stores (playback, selection, dialogs, editor)\n│   ├── marquee/           # Marquee-selection hook + overlay (paired unit)\n│   ├── logging/           # Structured logger, frame jitter monitor\n│   ├── ui/                # cn helper, property controls\n│   ├── typography/        # Font loading, text style presets\n│   ├── graphics/          # Shape generators and path helpers\n│   └── utils/             # Managed workers, color/curve math, easing, async, etc.\n├── components/            # shadcn/ui components + brand assets\n├── app/                   # App bootstrap, error boundary, PWA prompt, debug\n├── config/                # Hotkeys + editor layout config\n├── i18n/                  # i18next setup, supported languages, locale JSON + per-feature partials\n├── routes/                # TanStack Router (file-based, auto-generated routeTree)\n└── types/                 # Shared TypeScript types\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eKey Patterns\u003c/h2\u003e\u003ca id=\"user-content-key-patterns\" class=\"anchor\" aria-label=\"Permalink: Key Patterns\" href=\"#key-patterns\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003eState\u003c/strong\u003e: Zustand stores + Zundo for undo/redo\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTimeline store split\u003c/strong\u003e: \u003ccode\u003euseTimelineStore\u003c/code\u003e (from \u003ccode\u003etimeline-store.ts\u003c/code\u003e) is a \u003cstrong\u003efacade\u003c/strong\u003e over domain stores (\u003ccode\u003eitems-store\u003c/code\u003e, \u003ccode\u003etransitions-store\u003c/code\u003e, \u003ccode\u003ekeyframes-store\u003c/code\u003e, \u003ccode\u003emarkers-store\u003c/code\u003e, \u003ccode\u003etimeline-settings-store\u003c/code\u003e, \u003ccode\u003etimeline-command-store\u003c/code\u003e). Components use the facade with selectors; action code accesses domain stores via \u003ccode\u003e.getState()\u003c/code\u003e directly\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTimeline mutations\u003c/strong\u003e: Action modules in \u003ccode\u003efeatures/timeline/stores/actions/*.ts\u003c/code\u003e use \u003ccode\u003eexecute()\u003c/code\u003e wrapper from \u003ccode\u003eshared.ts\u003c/code\u003e for undo/redo integration. Never mutate timeline stores directly — use these actions\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTimelineItem composition\u003c/strong\u003e: The per-clip component in \u003ccode\u003efeatures/timeline/components/timeline-item/index.tsx\u003c/code\u003e delegates to dedicated hooks: \u003ccode\u003euseCaptionDialogState\u003c/code\u003e, \u003ccode\u003euseFadeEditors\u003c/code\u003e, \u003ccode\u003euseFadeMath\u003c/code\u003e, \u003ccode\u003euseEditPreviewShifts\u003c/code\u003e, \u003ccode\u003euseTimelineItemBounds\u003c/code\u003e, \u003ccode\u003euseSmartTrimHover\u003c/code\u003e, \u003ccode\u003euseContextMenuState\u003c/code\u003e, plus the existing \u003ccode\u003euseTimelineItemActions\u003c/code\u003e / \u003ccode\u003euseTimelineItemDropHandlers\u003c/code\u003e / \u003ccode\u003euseDragVisualState\u003c/code\u003e. The host file orchestrates these hooks and renders the JSX; sub-components live alongside (\u003ccode\u003eEdgeHalos\u003c/code\u003e, \u003ccode\u003eTransitionDropGhost\u003c/code\u003e, \u003ccode\u003eTranscribeDialogController\u003c/code\u003e, etc.). When adding new clip state, prefer a new hook over inlining\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTimeline item types\u003c/strong\u003e: \u003ccode\u003eTimelineItem\u003c/code\u003e is a discriminated union on \u003ccode\u003etype\u003c/code\u003e: \u003ccode\u003evideo | audio | text | image | shape | adjustment | composition\u003c/code\u003e — GIFs use \u003ccode\u003eimage\u003c/code\u003e type, no separate gif type. Types in \u003ccode\u003esrc/types/timeline.ts\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eItem positioning\u003c/strong\u003e: Remotion convention — \u003ccode\u003efrom\u003c/code\u003e (start frame in project FPS) + \u003ccode\u003edurationInFrames\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCompositions\u003c/strong\u003e: Pre-compositions (sub-comps) have dedicated stores (\u003ccode\u003ecompositions-store.ts\u003c/code\u003e, \u003ccode\u003ecomposition-navigation-store.ts\u003c/code\u003e). 1-level nesting only. Actions in \u003ccode\u003ecomposition-actions.ts\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMigrations\u003c/strong\u003e: \u003ccode\u003esrc/shared/projects/migrations/\u003c/code\u003e — versioned migrations + normalization run on every project load. Increment \u003ccode\u003eCURRENT_SCHEMA_VERSION\u003c/code\u003e in \u003ccode\u003etypes.ts\u003c/code\u003e when adding new migrations\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRouting\u003c/strong\u003e: TanStack Router — run \u003ccode\u003enpm run routes\u003c/code\u003e after adding/changing route files\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePath alias\u003c/strong\u003e: \u003ccode\u003e@/*\u003c/code\u003e → \u003ccode\u003esrc/*\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ei18n\u003c/strong\u003e: i18next + react-i18next, initialized in \u003ccode\u003esrc/i18n/index.ts\u003c/code\u003e (imported once from \u003ccode\u003emain.tsx\u003c/code\u003e). 9 languages (\u003ccode\u003een\u003c/code\u003e, \u003ccode\u003ees\u003c/code\u003e, \u003ccode\u003efr\u003c/code\u003e, \u003ccode\u003ede\u003c/code\u003e, \u003ccode\u003ept-BR\u003c/code\u003e, \u003ccode\u003etr\u003c/code\u003e, \u003ccode\u003eja\u003c/code\u003e, \u003ccode\u003eko\u003c/code\u003e, \u003ccode\u003ezh\u003c/code\u003e) in \u003ccode\u003esrc/i18n/languages.ts\u003c/code\u003e. Base strings in \u003ccode\u003esrc/i18n/locales/\u0026lt;lang\u0026gt;.json\u003c/code\u003e; per-feature strings live in \u003ccode\u003esrc/i18n/locales/partials/\u0026lt;lang\u0026gt;/\u0026lt;name\u0026gt;.json\u003c/code\u003e (file contains the slice directly with no language wrapper key). \u003ccode\u003een\u003c/code\u003e partials are eagerly bundled into \u003ccode\u003eapp-shell\u003c/code\u003e; all other languages load on demand via \u003ccode\u003eloadLanguageResources(lang)\u003c/code\u003e / \u003ccode\u003echangeAppLanguage(lang)\u003c/code\u003e from \u003ccode\u003e@/i18n\u003c/code\u003e. The user's persisted language is preloaded before first render via the exported \u003ccode\u003ei18nReady\u003c/code\u003e promise. In components use \u003ccode\u003econst { t } = useTranslation()\u003c/code\u003e; outside React use \u003ccode\u003eimport { i18n } from '@/i18n'\u003c/code\u003e then \u003ccode\u003ei18n.t()\u003c/code\u003e (\u003ccode\u003e@/i18n\u003c/code\u003e is allowed by the boundary checks — it's not \u003ccode\u003e@/features/*\u003c/code\u003e). For strings with inline markup use \u003ccode\u003e\u0026lt;Trans i18nKey=... components={{ strong: \u0026lt;strong/\u0026gt; }} /\u0026gt;\u003c/code\u003e. Resources are deliberately untyped (\u003ccode\u003ei18next.d.ts\u003c/code\u003e) so \u003ccode\u003et()\u003c/code\u003e accepts any key. Language selector lives in the editor Settings dialog (General); persisted to \u003ccode\u003elocalStorage\u003c/code\u003e key \u003ccode\u003efreecut-language\u003c/code\u003e by the language detector. When adding new partials, translate all 9 languages and keep identical key structure across all language dirs; never put a bare ASCII \u003ccode\u003e\"\u003c/code\u003e inside a JSON string value.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eStyling\u003c/strong\u003e: Tailwind CSS 4 + shadcn/ui (Radix primitives)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMedia processing\u003c/strong\u003e: Mediabunny for decode, WebCodecs for export, Web Workers for heavy ops\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eStorage\u003c/strong\u003e: Workspace folder via File System Access API (see \u003ccode\u003einfrastructure/storage/workspace-fs/\u003c/code\u003e). Source of truth is a user-picked directory on disk — projects, media metadata, thumbnails, waveforms, gif frames, decoded audio, transcripts all live as plain files. \u003ccode\u003eWorkspaceGate\u003c/code\u003e (\u003ccode\u003esrc/features/workspace-gate/\u003c/code\u003e) blocks app render until a workspace is granted. IndexedDB is only used for a tiny handle registry (\u003ccode\u003efreecut-handles-db\u003c/code\u003e v1, at \u003ccode\u003einfrastructure/storage/handles-db.ts\u003c/code\u003e) that stores non-serializable \u003ccode\u003eFileSystem*Handle\u003c/code\u003e references. Legacy \u003ccode\u003evideo-editor-db\u003c/code\u003e is read only by the one-time migration path under \u003ccode\u003einfrastructure/storage/legacy-idb/\u003c/code\u003e (reader.ts + migrate.ts); consumers import from the barrel \u003ccode\u003e@/infrastructure/storage\u003c/code\u003e which routes everything to workspace-fs\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCode Style\u003c/h2\u003e\u003ca id=\"user-content-code-style\" class=\"anchor\" aria-label=\"Permalink: Code Style\" href=\"#code-style\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eStrict TypeScript (\u003ccode\u003enoUnusedLocals\u003c/code\u003e, \u003ccode\u003enoUnusedParameters\u003c/code\u003e, \u003ccode\u003enoUncheckedIndexedAccess\u003c/code\u003e)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eno-console\u003c/code\u003e rule — always use \u003ccode\u003ecreateLogger\u003c/code\u003e from \u003ccode\u003esrc/shared/logging/logger.ts\u003c/code\u003e, never raw \u003ccode\u003econsole.*\u003c/code\u003e calls\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLogging\u003c/strong\u003e: Use wide event pattern for multi-step operations (export, import, save): \u003ccode\u003elog.startEvent(name, opId)\u003c/code\u003e accumulates context, emits one structured event via \u003ccode\u003e.success()\u003c/code\u003e / \u003ccode\u003e.failure()\u003c/code\u003e. Use \u003ccode\u003ecreateOperationId()\u003c/code\u003e for correlation. Include business context (project ID, item counts, codec, resolution) in events\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etypescript/no-explicit-any\u003c/code\u003e warned by Oxlint\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eTesting\u003c/h2\u003e\u003ca id=\"user-content-testing\" class=\"anchor\" aria-label=\"Permalink: Testing\" href=\"#testing\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eVitest + jsdom + @testing-library/react\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003esrc/test/setup.ts\u003c/code\u003e mocks ImageData, WebGPU APIs (\u003ccode\u003enavigator.gpu\u003c/code\u003e), and GPU constants\u003c/li\u003e\n\u003cli\u003eTests live next to source files: \u003ccode\u003e*.test.ts\u003c/code\u003e / \u003ccode\u003e*.test.tsx\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePure-logic tests opt out of jsdom.\u003c/strong\u003e \u003ccode\u003evite.config.ts\u003c/code\u003e defaults to \u003ccode\u003eenvironment: 'jsdom'\u003c/code\u003e, but a test that never touches \u003ccode\u003edocument\u003c/code\u003e / \u003ccode\u003ewindow\u003c/code\u003e / \u003ccode\u003enavigator\u003c/code\u003e / testing-library should start with \u003ccode\u003e// @vitest-environment node\u003c/code\u003e on line 1 (blank line after). Building a jsdom per file is ~30% of the suite's wall clock; 280 files already do this. Keep the jsdom default — a file wrongly marked \u003ccode\u003enode\u003c/code\u003e fails loudly with \u003ccode\u003edocument is not defined\u003c/code\u003e, whereas flipping the default would silently break any file someone forgot to annotate. Leave a file on jsdom if it merely \u003cem\u003ementions\u003c/em\u003e \u003ccode\u003ewindow\u003c/code\u003e/\u003ccode\u003enavigator\u003c/code\u003e: a \u003ccode\u003etypeof window !== 'undefined'\u003c/code\u003e branch would take the non-browser path with every assertion still green\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eOnly write tests that exercise real logic.\u003c/strong\u003e A test must be able to fail for a reason other than someone editing a constant or a string. Do NOT add tests that: re-assert a static config/registry/preset constant back to itself (config snapshots); assert \u003ccode\u003etypeof x === 'function'\u003c/code\u003e or \u003ccode\u003ehas correct initial state\u003c/code\u003e on a store; only verify a mocked function was called / returned its mock value (the real code is stubbed, so nothing real is covered); render a component and assert a passed-in prop/className/style string appears with no branching behind it; exercise library/framework behavior (Radix, jsdom events, controlled inputs). When the only collaborators are mocked, test against the real in-memory fake (e.g. workspace-fs round-trips) instead. Worth testing: algorithm/math (FPS/timeline conversions, transitions, interpolation, color/curve math), reducer/state-machine transitions, schema migrations, edge/boundary cases, and named regressions. If unsure whether a test adds value, prefer no test over a low-value one\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEnvironment\u003c/h2\u003e\u003ca id=\"user-content-environment\" class=\"anchor\" aria-label=\"Permalink: Environment\" href=\"#environment\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eVITE_SHOW_DEBUG_PANEL=false\u003c/code\u003e — set to hide debug panel in dev mode (shown by default)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eToolchain \u0026amp; dependency notes\u003c/h2\u003e\u003ca id=\"user-content-toolchain--dependency-notes\" class=\"anchor\" aria-label=\"Permalink: Toolchain \u0026amp; dependency notes\" href=\"#toolchain--dependency-notes\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eThe entire dev/build/test/lint/format stack runs through \u003cstrong\u003evite-plus\u003c/strong\u003e (\u003ccode\u003evp\u003c/code\u003e, currently 0.x / pre-1.0) — it wraps Vite, Vitest, Oxlint, Oxfmt and the task runner. There is no plain-Vite fallback configured; if \u003ccode\u003evp\u003c/code\u003e breaks, pin the last working version in package.json rather than attempting an ad-hoc migration\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eonnxruntime-web\u003c/code\u003e is intentionally pinned to a \u003cstrong\u003edev build\u003c/strong\u003e (\u003ccode\u003e1.26.0-dev.*\u003c/code\u003e) — introduced with the supertonic TTS integration. Don't \"upgrade\" it casually; moving to a stable release requires re-validating transcription, TTS and scene detection\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003elucide-react\u003c/code\u003e is held at 0.468.x deliberately (Vite pre-bundles it; see Gotchas about \u003ccode\u003eoptimizeDeps\u003c/code\u003e). A major-version bump is a deliberate task, not a routine dep update\u003c/li\u003e\n\u003cli\u003eAll production deps are exact-pinned; keep new deps exact-pinned too (no \u003ccode\u003e^\u003c/code\u003e/\u003ccode\u003e~\u003c/code\u003e)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTypeScript 7 needs the \u003ccode\u003eoverrides.typescript\u003c/code\u003e entry.\u003c/strong\u003e \u003ccode\u003ei18next\u003c/code\u003e and \u003ccode\u003ereact-i18next\u003c/code\u003e declare \u003ccode\u003epeerOptional typescript@\"^5\"\u003c/code\u003e, so any TS \u0026gt;= 6 fails a clean \u003ccode\u003enpm install\u003c/code\u003e/\u003ccode\u003enpm ci\u003c/code\u003e with ERESOLVE (an \u003cem\u003eincremental\u003c/em\u003e install over an existing tree misleadingly succeeds). The override in package.json forces one TS copy and must be bumped in lockstep with the \u003ccode\u003etypescript\u003c/code\u003e devDependency. \u003ccode\u003e@voidzero-dev/vite-plus-core\u003c/code\u003e also peers \u003ccode\u003e^5 || ^6\u003c/code\u003e, but never loads the package — it shells out to the tsgolint binary — so that one is inert\u003c/li\u003e\n\u003cli\u003eType checking does \u003cstrong\u003enot\u003c/strong\u003e run \u003ccode\u003etsc\u003c/code\u003e. \u003ccode\u003evp check\u003c/code\u003e type-checks via \u003cstrong\u003etsgolint\u003c/strong\u003e (the TypeScript-Go engine), which is why CI already had native-speed checking before the TS 7 bump. Nothing in \u003ccode\u003epackage.json\u003c/code\u003e scripts or CI invokes \u003ccode\u003etsc\u003c/code\u003e; the \u003ccode\u003etypescript\u003c/code\u003e devDependency exists for editor tsserver and ad-hoc \u003ccode\u003enpx tsc\u003c/code\u003e. TS 7.0 ships no stable programmatic API — if a tool ever needs one, alias \u003ccode\u003e@typescript/typescript6\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eThe fallow allowlists are baselines, not approvals.\u003c/strong\u003e \u003ccode\u003echeck:unused-exports\u003c/code\u003e and \u003ccode\u003echeck:unused-class-members\u003c/code\u003e are ratchets: they fail only on findings \u003cem\u003enew\u003c/em\u003e since the baseline, plus stale entries. Every entry carries a \u003ccode\u003ereason\u003c/code\u003e, and re-baselined ones are tagged — \u003ccode\u003eparked-ai-feature\u003c/code\u003e (the unwired assistant, see \u003ccode\u003eai-tab.tsx\u003c/code\u003e), \u003ccode\u003edeps-contract\u003c/code\u003e (adapter surface the boundary rules require), \u003ccode\u003ebarrel-surface\u003c/code\u003e (feature \u003ccode\u003eindex.ts\u003c/code\u003e public API), \u003ccode\u003eunreviewed\u003c/code\u003e (never traced; start here when cleaning up). Never bulk-\u003ccode\u003efallow fix\u003c/code\u003e these — trace per export. Re-baseline by regenerating both files from \u003ccode\u003efallow dead-code --format json\u003c/code\u003e, preserving existing reasons; a stale baseline makes the gate fail permanently and get ignored\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eoxlint\u003c/code\u003e / \u003ccode\u003eoxfmt\u003c/code\u003e / \u003ccode\u003e@oxc-project/types\u003c/code\u003e are \u003cstrong\u003enot\u003c/strong\u003e direct deps — vite-plus exact-pins them internally, so they only move when \u003ccode\u003evp\u003c/code\u003e moves. A \u003ccode\u003evp\u003c/code\u003e bump can therefore reformat the tree (0.2.4 brought oxfmt 0.57 and reflowed 52 files); land that churn as its own commit\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eGit\u003c/h2\u003e\u003ca id=\"user-content-git\" class=\"anchor\" aria-label=\"Permalink: Git\" href=\"#git\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003emain\u003c/code\u003e — production, \u003ccode\u003estaging\u003c/code\u003e — pre-release integration, \u003ccode\u003edevelop\u003c/code\u003e — active development\u003c/li\u003e\n\u003cli\u003ePR target: \u003ccode\u003estaging\u003c/code\u003e (feature branches and \u003ccode\u003edevelop\u003c/code\u003e PR into \u003ccode\u003estaging\u003c/code\u003e; \u003ccode\u003estaging\u003c/code\u003e is promoted to \u003ccode\u003emain\u003c/code\u003e for release). Do \u003cstrong\u003enot\u003c/strong\u003e open PRs against \u003ccode\u003emain\u003c/code\u003e directly\u003c/li\u003e\n\u003cli\u003eCommit messages: conventional commits — \u003ccode\u003etype(scope): description\u003c/code\u003e (e.g. \u003ccode\u003efix(timeline):\u003c/code\u003e, \u003ccode\u003efeat(export):\u003c/code\u003e)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eGotchas\u003c/h2\u003e\u003ca id=\"user-content-gotchas\" class=\"anchor\" aria-label=\"Permalink: Gotchas\" href=\"#gotchas\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eTrack groups are 1-level only (no nested groups). Gate behavior (mute/visible/locked) propagates from group to children via \u003ccode\u003eresolveEffectiveTrackStates()\u003c/code\u003e in \u003ccode\u003egroup-utils.ts\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eBrowser shortcut conflicts (e.g. Ctrl+E) need \u003ccode\u003eeventListenerOptions: { capture: true }\u003c/code\u003e on the hotkey to override Chrome's default behavior\u003c/li\u003e\n\u003cli\u003eFeature modules use \u003ccode\u003eindex.ts\u003c/code\u003e barrel files to define public API surface — follow this convention when adding new features\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003erouteTree.gen.ts\u003c/code\u003e is auto-generated — don't edit manually\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e*.mp4\u003c/code\u003e files are gitignored\u003c/li\u003e\n\u003cli\u003eVite pre-bundles \u003ccode\u003elucide-react\u003c/code\u003e to avoid analyzing 1500+ icons — don't remove from \u003ccode\u003eoptimizeDeps\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eWebGPU tests need mocks from \u003ccode\u003esrc/test/setup.ts\u003c/code\u003e — tests will fail without jsdom environment\u003c/li\u003e\n\u003cli\u003eBuild uses manual chunk splitting — check \u003ccode\u003evite.config.ts\u003c/code\u003e when adding large dependencies\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eHOTKEY_OPTIONS\u003c/code\u003e has \u003ccode\u003epreventDefault: true\u003c/code\u003e — the library consumes keys before the callback. For panel-scoped shortcuts, use \u003ccode\u003eonKeyDown\u003c/code\u003e on the element with \u003ccode\u003etabIndex={-1}\u003c/code\u003e + focus-on-hover + \u003ccode\u003estopPropagation()\u003c/code\u003e, not global \u003ccode\u003euseHotkeys\u003c/code\u003e with guards\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003esourceStart\u003c/code\u003e/\u003ccode\u003esourceEnd\u003c/code\u003e/\u003ccode\u003esourceDuration\u003c/code\u003e on timeline items are in \u003cstrong\u003esource-native FPS\u003c/strong\u003e frames, not project FPS. Use media's \u003ccode\u003efps\u003c/code\u003e from media library store when converting to seconds\u003c/li\u003e\n\u003cli\u003eTrack \u003ccode\u003eorder\u003c/code\u003e convention: lower value = visually higher (top of timeline). New tracks go at \u003ccode\u003eminOrder - 1\u003c/code\u003e. When creating pre-comps, place the comp item on the bottom-most (highest order) selected track; dissolve expands upward\u003c/li\u003e\n\u003cli\u003eGroup tracks (\u003ccode\u003eisGroup: true\u003c/code\u003e) are headers only — never place items on them. Filter them out when searching for candidate tracks\u003c/li\u003e\n\u003cli\u003eInline edit cancel (Escape) triggers blur on unmount — use a ref guard to prevent \u003ccode\u003eonBlur\u003c/code\u003e from committing the cancelled value\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e_splitItem()\u003c/code\u003e returns \u003ccode\u003e{ leftItem, rightItem } | null\u003c/code\u003e — capture the return for correct IDs; the original item ID is stale after split\u003c/li\u003e\n\u003cli\u003eTimeline has its own \u003ccode\u003ekeydown\u003c/code\u003e listener in \u003ccode\u003etimeline.tsx\u003c/code\u003e — new keyboard handlers on child panels must \u003ccode\u003estopPropagation()\u003c/code\u003e and timeline checks \u003ccode\u003ee.defaultPrevented\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eEffects are GPU-only\u003c/strong\u003e — all visual effects use WebGPU shaders (\u003ccode\u003etype: 'gpu-effect'\u003c/code\u003e). Legacy CSS filter, glitch, halftone, vignette, LUT types were removed in v6 migration. Effect definitions in \u003ccode\u003esrc/infrastructure/gpu-effects/effects/\u003c/code\u003e, pipeline in \u003ccode\u003eeffects-pipeline.ts\u003c/code\u003e. Specialized UI panels exist for \u003ccode\u003egpu-curves\u003c/code\u003e and \u003ccode\u003egpu-color-wheels\u003c/code\u003e; all others use the generic \u003ccode\u003eGpuEffectPanel\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTransitions are GPU-only\u003c/strong\u003e — all 13 transitions (fade, wipe, slide, flip, clockWipe, iris, dissolve, sparkles, glitch, lightLeak, pixelate, chromatic, radialBlur) render via WebGPU shaders in \u003ccode\u003einfrastructure/gpu-transitions/\u003c/code\u003e. Each renderer in \u003ccode\u003eshared/timeline/transitions/renderers/\u003c/code\u003e has \u003ccode\u003egpuTransitionId\u003c/code\u003e linking to its shader, plus a \u003ccode\u003erenderCanvas()\u003c/code\u003e Canvas 2D fallback for non-WebGPU environments. \u003ccode\u003ecalculateStyles()\u003c/code\u003e is dead code (CSS/DOM transition rendering was removed). Canvas \u003ccode\u003edrawImage\u003c/code\u003e offsets must use \u003ccode\u003eMath.round()\u003c/code\u003e to avoid sub-pixel interpolation artifacts\u003c/li\u003e\n\u003cli\u003eAfter clip edits that change position/duration, call \u003ccode\u003eapplyTransitionRepairs(changedClipIds)\u003c/code\u003e from \u003ccode\u003eshared.ts\u003c/code\u003e — transitions auto-heal or report breakages\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eshared/logging/logger.ts\u003c/code\u003e uses only \u003ccode\u003efunction\u003c/code\u003e declarations (no \u003ccode\u003eclass\u003c/code\u003e/\u003ccode\u003econst\u003c/code\u003e at module scope) to avoid temporal dead zone errors in production chunk ordering — maintain this pattern\u003c/li\u003e\n\u003cli\u003eFast scrub render loop: prewarm frames use WASM decode (40-80ms) and block the loop from processing priority frames. During playback, skip prewarm entirely (\u003ccode\u003eisPlaying\u003c/code\u003e check) — priority frames render fast via DOM video zero-copy (~1ms) and the loop must stay responsive. Background worker preseek (\u003ccode\u003ebackgroundPreseek\u003c/code\u003e in \u003ccode\u003edecoder-prewarm.ts\u003c/code\u003e) also fires on large timeline jumps (\u0026gt;3s) for all visible clips — the worker decodes off-thread and the render engine picks up the cached bitmap\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRender loop concurrency\u003c/strong\u003e — \u003ccode\u003epumpRenderLoop\u003c/code\u003e uses a single-mutex (\u003ccode\u003escrubRenderInFlightRef\u003c/code\u003e) to prevent concurrent pump iterations during scrubbing. A \u003ccode\u003escrubRenderGenerationRef\u003c/code\u003e counter is bumped ONLY on playback-start force-clear (not during scrub). The \u003ccode\u003efinally\u003c/code\u003e block releases the lock and triggers follow-up work only when the generation matches; stale pumps (from a superseded playback-start) leave the lock for the new owner. Never bump generation or force-clear the lock on sequential scrub frames — this causes unbounded concurrent pumps. The \u003ccode\u003edata-transition-hold\u003c/code\u003e attribute on DOM video elements coordinates with \u003ccode\u003evideo-content.tsx\u003c/code\u003e premount logic and \u003ccode\u003eclearTransitionPlaybackSession\u003c/code\u003e cleanup\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTransition participant video hold\u003c/strong\u003e — during transitions, the incoming clip's DOM video element is paused by \u003ccode\u003evideo-content.tsx\u003c/code\u003e premount logic. The transition provider marks it with \u003ccode\u003edata-transition-hold=\"1\"\u003c/code\u003e and calls \u003ccode\u003e.play()\u003c/code\u003e so the canvas renderer gets advancing frames. The mark is removed in \u003ccode\u003eclearTransitionPlaybackSession\u003c/code\u003e. Without this, the incoming clip shows a frozen frame during the transition\u003c/li\u003e\n\u003cli\u003eWhen updating multiple GPU effect params atomically (e.g. color wheel hue + amount), use \u003ccode\u003eonParamsBatchChange\u003c/code\u003e/\u003ccode\u003eonParamsBatchLiveChange\u003c/code\u003e — calling \u003ccode\u003eonParamChange\u003c/code\u003e twice reads stale state on the second call and overwrites the first\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eReuse rendered frames\u003c/strong\u003e — the preview scrub renderer already has fully composited frames with effects/masks/blend modes. Features needing the current frame (thumbnails, scopes, snapshots) should use \u003ccode\u003eusePreviewBridgeStore.getState().captureCanvasSource()\u003c/code\u003e first, falling back to \u003ccode\u003erenderSingleFrame()\u003c/code\u003e only when the preview is unavailable. Never spin up a new render pipeline when an existing one already has the frame\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eProgressive downscaling\u003c/strong\u003e — when scaling high-res canvases to small sizes (e.g. 1920→320 thumbnails), halve dimensions repeatedly instead of one large jump. Single-step downscaling causes moire/aliasing with high-frequency GPU effects (halftone, pixelate, etc.)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eStableVideoSequence\u003c/code\u003e's \u003ccode\u003eareGroupPropsEqual\u003c/code\u003e (defined in \u003ccode\u003estable-video-sequence-comparator.ts\u003c/code\u003e, consumed by \u003ccode\u003estable-video-sequence.tsx\u003c/code\u003e) whitelists item properties for React.memo comparison. When adding new visual properties to \u003ccode\u003eTimelineItem\u003c/code\u003e, add them to this comparison — missing properties cause stale renders during playback\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eGPU pipeline caching\u003c/strong\u003e — \u003ccode\u003eEffectsPipeline.requestCachedDevice()\u003c/code\u003e caches the WebGPU adapter + device globally. Subsequent \u003ccode\u003eEffectsPipeline.create()\u003c/code\u003e calls reuse the device (~50-100ms saved). The device-loss handler checks identity before clearing to avoid discarding a freshly acquired device. The preview component eagerly warms the GPU pipeline on mount (parallel with media resolution)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e\u003ccode\u003e__DEBUG__\u003c/code\u003e API\u003c/strong\u003e — \u003ccode\u003ewindow.__DEBUG__\u003c/code\u003e (DEV-only, tree-shaken in prod) provides console debugging: \u003ccode\u003estores()\u003c/code\u003e, \u003ccode\u003egetTransitions()\u003c/code\u003e, \u003ccode\u003egetTransitionWindows()\u003c/code\u003e, \u003ccode\u003egetPlaybackState()\u003c/code\u003e, \u003ccode\u003egetTracks()\u003c/code\u003e, \u003ccode\u003egetMediaLibrary()\u003c/code\u003e, \u003ccode\u003ejitter()\u003c/code\u003e (frame timing), \u003ccode\u003epreviewPerf()\u003c/code\u003e, \u003ccode\u003etransitionTrace()\u003c/code\u003e, \u003ccode\u003eprewarmCache()\u003c/code\u003e, \u003ccode\u003efilmstripMetrics()\u003c/code\u003e, \u003ccode\u003eperfSummary(prefix?)\u003c/code\u003e / \u003ccode\u003eperfClear()\u003c/code\u003e (User Timing aggregation, default prefix \u003ccode\u003etl.\u003c/code\u003e), plus playback control (\u003ccode\u003eseekTo\u003c/code\u003e, \u003ccode\u003eplay\u003c/code\u003e, \u003ccode\u003epause\u003c/code\u003e). All use lazy \u003ccode\u003eawait import()\u003c/code\u003e to avoid pulling in stores eagerly\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTimeline perf-marks\u003c/strong\u003e — \u003ccode\u003ewithPerfMeasure(name, fn)\u003c/code\u003e in \u003ccode\u003esrc/shared/logging/perf-marks.ts\u003c/code\u003e wraps hot paths so they appear as named entries on the User Timing track in Chrome DevTools Performance. Currently instruments \u003ccode\u003etl.action.*\u003c/code\u003e (every timeline mutation, via \u003ccode\u003eactions/shared.ts::execute\u003c/code\u003e), \u003ccode\u003etl.repairTransitions\u003c/code\u003e, and the RAF loops \u003ccode\u003etl.raf.{viewportSync,previewHover,zoomApply,scrollThumb,momentum,playheadScrub}\u003c/code\u003e. \u003ccode\u003ewithPerfMeasure\u003c/code\u003e is opt-in — gated on \u003ccode\u003ewindow.__TL_PERF__ = true\u003c/code\u003e (off by default, zero overhead) so the User Timing buffer doesn't grow unbounded in normal use; set the flag before profiling (\u003ccode\u003enpm run perf\u003c/code\u003e), then read marks via the Performance tab or \u003ccode\u003e__DEBUG__.perfSummary()\u003c/code\u003e. \u003ccode\u003eperfMarkRender(name)\u003c/code\u003e adds per-render \u003ccode\u003etl.render.*\u003c/code\u003e marks to the high-fanout components (ClipContent, TimelineItem, TimelineTrack, TimelineContent, TimelineMarkers, TimelinePlayhead, TransitionItem) — gated on \u003ccode\u003ewindow.__TL_RENDER_MARKS__ = true\u003c/code\u003e (off by default, zero overhead) for diagnosing which components re-render during a gesture\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eClip content tracks SETTLED zoom\u003c/strong\u003e — \u003ccode\u003eClipContent\u003c/code\u003e (\u003ccode\u003etimeline-item/clip-content.tsx\u003c/code\u003e) drives filmstrip/waveform width from \u003ccode\u003econtentPixelsPerSecond\u003c/code\u003e (settled, updates ~100ms after a zoom gesture ends), NOT the live per-frame \u003ccode\u003epixelsPerSecond\u003c/code\u003e. The clip shell resizes smoothly during the gesture via the \u003ccode\u003e--timeline-px-per-frame\u003c/code\u003e CSS variable (no React); the filmstrip tile grid would otherwise rebuild on every wheel/momentum frame (~73% of zoom cost). During the gesture the content is briefly at pre-zoom scale, hidden by the repeating cover-frame background (zoom-in) or \u003ccode\u003eoverflow:hidden\u003c/code\u003e clipping (zoom-out), snapping sharp on settle. The \u003ccode\u003epreferImmediateRendering\u003c/code\u003e prop opts back into live pps for active edit previews (trim/slide) where settle lag would distract\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eClip content defers mount during zoom\u003c/strong\u003e — \u003ccode\u003eClipContent\u003c/code\u003e also reads \u003ccode\u003eisZoomInteracting\u003c/code\u003e \u003cstrong\u003eonce at mount\u003c/strong\u003e via \u003ccode\u003egetState()\u003c/code\u003e (not a reactive subscription) into \u003ccode\u003edeferVisual\u003c/code\u003e state. A clip that first mounts mid-gesture (e.g. entering the viewport while zooming out) renders only its colored shell — no filmstrip/waveform — until the zoom settles, then a one-shot \u003ccode\u003euseZoomStore.subscribe\u003c/code\u003e flips it on. This was ~90% of zoom-OUT cost: zooming out brings many clips into view at once and mounting each one's tile grid + canvas draws stalled the gesture (226ms/frame → ~42ms/frame). Reading at mount (not subscribing) is critical — already-mounted clips must NOT re-render when \u003ccode\u003eisZoomInteracting\u003c/code\u003e flips, or they'd flash empty\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTransition prearm covers all types\u003c/strong\u003e — the \u003ccode\u003eforceFastScrubOverlay\u003c/code\u003e subscription uses \u003ccode\u003egetPlayingAnyTransitionPrewarmStartFrame\u003c/code\u003e (not complex-only) so all transitions get their session pinned and DOM video elements playing before entry. Also checks \u003ccode\u003egetTransitionWindowForFrame\u003c/code\u003e for playback starting inside an active transition\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eFeature boundary rules\u003c/strong\u003e — cross-feature imports must go through \u003ccode\u003edeps/\u003c/code\u003e adapter modules. The pre-push hook enforces this via \u003ccode\u003echeck:boundaries\u003c/code\u003e. (A \u003ccode\u003echeck:legacy-lib-imports\u003c/code\u003e tripwire also catches any reintroduction of \u003ccode\u003e@/lib/*\u003c/code\u003e imports — the \u003ccode\u003esrc/lib/\u003c/code\u003e layer was removed and merged into \u003ccode\u003einfrastructure/\u003c/code\u003e.)\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eGPU effect data textures\u003c/strong\u003e: effects that need LUT-like auxiliary data declare \u003ccode\u003edataTexture\u003c/code\u003e in their \u003ccode\u003eGpuEffectDefinition\u003c/code\u003e. The pipeline binds it at \u003ccode\u003e@group(0) @binding(3)\u003c/code\u003e, caches the texture per pass, rewrites same-size contents with \u003ccode\u003equeue.writeTexture\u003c/code\u003e, and invalidates bind groups only when dimensions change. \u003ccode\u003egpu-curves\u003c/code\u003e uses this for the 256x1 curve LUT; \u003ccode\u003egpu-lut\u003c/code\u003e embeds resampled \u003ccode\u003e.cube\u003c/code\u003e data in effect params so project bundles and export workers need no side channel.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eImplicit color grade controls\u003c/strong\u003e: the Color workspace renders wheels and curves even before those effects exist. \u003ccode\u003eColorGradeSection\u003c/code\u003e previews synthetic grade entries through the gizmo effects-preview path during live drags, then lazily creates the real GPU effect on commit. Do not persist synthetic \u003ccode\u003e__grade:*\u003c/code\u003e ids or attach keyframes to them.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eInterface sounds\u003c/strong\u003e: synthesized (no audio assets) via a dedicated \u003ccode\u003eAudioContext\u003c/code\u003e in \u003ccode\u003einfrastructure/audio/ui-sound/\u003c/code\u003e (\u003ccode\u003esynth.ts\u003c/code\u003e data-only \u003ccode\u003eRecipe\u003c/code\u003e → \u003ccode\u003erenderRecipe\u003c/code\u003e; \u003ccode\u003evoices.ts\u003c/code\u003e maps semantic \u003ccode\u003eSoundToken\u003c/code\u003es → recipes per swappable \u003cstrong\u003evoice\u003c/strong\u003e; \u003ccode\u003eengine.ts\u003c/code\u003e owns the lazy context + per-token rate limit). To add feedback anywhere call \u003ccode\u003eemitUiSound('\u0026lt;token\u0026gt;')\u003c/code\u003e from \u003ccode\u003e@/shared/ui/ui-sound\u003c/code\u003e at the \u003cstrong\u003eaction chokepoint\u003c/strong\u003e (the store action / toggle callback, not each call site) — emit \u003cem\u003eintent\u003c/em\u003e (\u003ccode\u003eselect\u003c/code\u003e/\u003ccode\u003econfirm\u003c/code\u003e/\u003ccode\u003edelete\u003c/code\u003e/\u003ccode\u003etoggleOn\u003c/code\u003e…), never a specific sound. It's gated: opt-in + volume-scaled via \u003ccode\u003euseUiSoundStore\u003c/code\u003e (\u003ccode\u003eshared/state/ui-sound-store.ts\u003c/code\u003e, persisted \u003ccode\u003efreecut-ui-sound\u003c/code\u003e, \u003cstrong\u003eoff by default\u003c/strong\u003e), rate-limited, and \u003cstrong\u003esuppressed while \u003ccode\u003eusePlaybackStore.isPlaying\u003c/code\u003e\u003c/strong\u003e so chirps never pollute monitored audio (exports are silent by construction — the export worker never imports the module). New voices: add to \u003ccode\u003eVOICES\u003c/code\u003e/\u003ccode\u003eVOICE_OPTIONS\u003c/code\u003e + \u003ccode\u003eVoiceName\u003c/code\u003e and the picker (Settings → General) updates automatically. \u003ccode\u003epreviewUiSound(voice, token)\u003c/code\u003e auditions a specific voice without committing it. \u003ccode\u003ehover\u003c/code\u003e is defined but intentionally unwired (too noisy for blanket use).\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/article\u003e","richTextTruncated":false,"renderedFileInfo":null,"symbols":{"timed_out":false,"not_analyzed":false,"symbols":[{"name":"FreeCut Web","fully_qualified_name":"FreeCut Web","kind":"section_1","ident_start":2,"ident_end":13,"extent_start":0,"extent_end":26700,"ident_utf16":{"start":{"line_number":0,"utf16_col":2},"end":{"line_number":0,"utf16_col":13}},"extent_utf16":{"start":{"line_number":0,"utf16_col":0},"end":{"line_number":161,"utf16_col":0}}},{"name":"Commands","fully_qualified_name":"Commands","kind":"section_2","ident_start":18,"ident_end":26,"extent_start":15,"extent_end":399,"ident_utf16":{"start":{"line_number":2,"utf16_col":3},"end":{"line_number":2,"utf16_col":11}},"extent_utf16":{"start":{"line_number":2,"utf16_col":0},"end":{"line_number":15,"utf16_col":0}}},{"name":"Architecture","fully_qualified_name":"Architecture","kind":"section_2","ident_start":402,"ident_end":414,"extent_start":399,"extent_end":4101,"ident_utf16":{"start":{"line_number":15,"utf16_col":3},"end":{"line_number":15,"utf16_col":15}},"extent_utf16":{"start":{"line_number":15,"utf16_col":0},"end":{"line_number":70,"utf16_col":0}}},{"name":"Key Patterns","fully_qualified_name":"Key Patterns","kind":"section_2","ident_start":4104,"ident_end":4116,"extent_start":4101,"extent_end":8455,"ident_utf16":{"start":{"line_number":70,"utf16_col":3},"end":{"line_number":70,"utf16_col":15}},"extent_utf16":{"start":{"line_number":70,"utf16_col":0},"end":{"line_number":87,"utf16_col":0}}},{"name":"Code Style","fully_qualified_name":"Code Style","kind":"section_2","ident_start":8458,"ident_end":8468,"extent_start":8455,"extent_end":9044,"ident_utf16":{"start":{"line_number":87,"utf16_col":3},"end":{"line_number":87,"utf16_col":13}},"extent_utf16":{"start":{"line_number":87,"utf16_col":0},"end":{"line_number":94,"utf16_col":0}}},{"name":"Testing","fully_qualified_name":"Testing","kind":"section_2","ident_start":9047,"ident_end":9054,"extent_start":9044,"extent_end":10982,"ident_utf16":{"start":{"line_number":94,"utf16_col":3},"end":{"line_number":94,"utf16_col":10}},"extent_utf16":{"start":{"line_number":94,"utf16_col":0},"end":{"line_number":102,"utf16_col":0}}},{"name":"Environment","fully_qualified_name":"Environment","kind":"section_2","ident_start":10985,"ident_end":10996,"extent_start":10982,"extent_end":11090,"ident_utf16":{"start":{"line_number":102,"utf16_col":3},"end":{"line_number":102,"utf16_col":14}},"extent_utf16":{"start":{"line_number":102,"utf16_col":0},"end":{"line_number":106,"utf16_col":0}}},{"name":"Toolchain \u0026 dependency notes","fully_qualified_name":"Toolchain \u0026 dependency notes","kind":"section_2","ident_start":11093,"ident_end":11121,"extent_start":11090,"extent_end":13895,"ident_utf16":{"start":{"line_number":106,"utf16_col":3},"end":{"line_number":106,"utf16_col":31}},"extent_utf16":{"start":{"line_number":106,"utf16_col":0},"end":{"line_number":117,"utf16_col":0}}},{"name":"Git","fully_qualified_name":"Git","kind":"section_2","ident_start":13898,"ident_end":13901,"extent_start":13895,"extent_end":14277,"ident_utf16":{"start":{"line_number":117,"utf16_col":3},"end":{"line_number":117,"utf16_col":6}},"extent_utf16":{"start":{"line_number":117,"utf16_col":0},"end":{"line_number":123,"utf16_col":0}}},{"name":"Gotchas","fully_qualified_name":"Gotchas","kind":"section_2","ident_start":14280,"ident_end":14287,"extent_start":14277,"extent_end":26700,"ident_utf16":{"start":{"line_number":123,"utf16_col":3},"end":{"line_number":123,"utf16_col":10}},"extent_utf16":{"start":{"line_number":123,"utf16_col":0},"end":{"line_number":161,"utf16_col":0}}}]}},"codeViewLayoutRoute":{"repo":{"id":1300428482,"defaultBranch":"main","name":"freecut","ownerLogin":"tepn11","currentUserCanPush":false,"isFork":true,"isEmpty":false,"createdAt":"2026-07-14T11:51:34.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/14833808?v=4","public":true,"private":false,"isOrgOwned":false,"isArchived":false},"currentUser":null,"uploadToken":"tpoFmTKY5nhfJZwOi1V3NdeorfJ2Y9gc4bjZ5NqDBH4Faw3V-k_rwQ3whhUXf7AI9cnOPmlVOgpoJBNsBmMokA","allShortcutsEnabled":false,"treeExpanded":true,"path":"CLAUDE.md","symbolsExpanded":false,"refInfo":{"name":"main","listCacheKey":"v0:1784029897.232702","canEdit":false,"currentOid":"a3ecfcef6a4456fd75f65ae55d34cad3ecf87adc"},"helpUrl":"https://docs.github.com","githubDevUrl":null},"codeViewFileTreeLayoutRoute":{"fileTree":{"":{"items":[{"name":".claude","path":".claude","contentType":"directory"},{"name":".codex","path":".codex","contentType":"directory"},{"name":".github","path":".github","contentType":"directory"},{"name":".impeccable","path":".impeccable","contentType":"directory"},{"name":".vite-hooks","path":".vite-hooks","contentType":"directory"},{"name":"docs","path":"docs","contentType":"directory"},{"name":"headless","path":"headless","contentType":"directory"},{"name":"public","path":"public","contentType":"directory"},{"name":"scripts","path":"scripts","contentType":"directory"},{"name":"src","path":"src","contentType":"directory"},{"name":".coderabbit.yaml","path":".coderabbit.yaml","contentType":"file"},{"name":".dockerignore","path":".dockerignore","contentType":"file"},{"name":".editorconfig","path":".editorconfig","contentType":"file"},{"name":".env.example","path":".env.example","contentType":"file"},{"name":".env.perf","path":".env.perf","contentType":"file"},{"name":".fallowrc.json","path":".fallowrc.json","contentType":"file"},{"name":".gitattributes","path":".gitattributes","contentType":"file"},{"name":".gitignore","path":".gitignore","contentType":"file"},{"name":".oxfmtrc.json","path":".oxfmtrc.json","contentType":"file"},{"name":".oxlintrc.json","path":".oxlintrc.json","contentType":"file"},{"name":"CHANGELOG.md","path":"CHANGELOG.md","contentType":"file"},{"name":"CLAUDE.md","path":"CLAUDE.md","contentType":"file"},{"name":"DESIGN.md","path":"DESIGN.md","contentType":"file"},{"name":"LICENSE","path":"LICENSE","contentType":"file"},{"name":"PRODUCT.md","path":"PRODUCT.md","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"},{"name":"components.json","path":"components.json","contentType":"file"},{"name":"headless.html","path":"headless.html","contentType":"file"},{"name":"index.html","path":"index.html","contentType":"file"},{"name":"package-lock.json","path":"package-lock.json","contentType":"file"},{"name":"package.json","path":"package.json","contentType":"file"},{"name":"tsconfig.json","path":"tsconfig.json","contentType":"file"},{"name":"tsr.config.json","path":"tsr.config.json","contentType":"file"},{"name":"vercel.json","path":"vercel.json","contentType":"file"},{"name":"vite.config.ts","path":"vite.config.ts","contentType":"file"}],"totalCount":35}},"fileTreeProcessingTime":18.651641,"foldersToFetch":[]},"codeViewBlobLayoutRoute":{"codeLineWrapEnabled":false,"refInfo":{"name":"main","listCacheKey":"v0:1784029897.232702","canEdit":false,"refType":"branch","currentOid":"a3ecfcef6a4456fd75f65ae55d34cad3ecf87adc","canEditOnDefaultBranch":false,"fileExistsOnDefault":true},"path":"CLAUDE.md","blob":{"copilotSWEAgentEnabled":false,"dependabotInfo":{"showConfigurationBanner":false,"configFilePath":null,"networkDependabotPath":"/tepn11/freecut/network/updates","dismissConfigurationNoticePath":"/settings/dismiss-notice/dependabot_configuration_notice","configurationNoticeDismissed":null},"displayName":"CLAUDE.md","displayUrl":"https://github.com/tepn11/freecut/blob/main/CLAUDE.md?raw=true","headerInfo":{"blobSize":"26.1 KB","deleteTooltip":"You must be signed in to make or propose changes","editTooltip":"You must be signed in to make or propose changes","ghDesktopPath":"https://desktop.github.com","isGitLfs":false,"onBranch":true,"shortPath":"7a032e0","siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Ftepn11%2Ffreecut%2Fblob%2Fmain%2FCLAUDE.md","isCSV":false,"isRichtext":true,"lineInfo":{"truncatedLoc":"161","truncatedSloc":"142"},"mode":"file"},"image":false,"isCodeownersFile":null,"isPlain":false,"isValidLegacyIssueTemplate":false,"isIssueTemplate":false,"isDiscussionTemplate":false,"language":"Markdown","languageID":222,"large":false,"planSupportInfo":{"repoIsFork":null,"repoOwnedByCurrentUser":null,"requestFullPath":"/tepn11/freecut/blob/main/CLAUDE.md","showFreeOrgGatedFeatureMessage":null,"showPlanSupportBanner":null,"upgradeDataAttributes":null,"upgradePath":null},"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_dockerfile","releasePath":"/tepn11/freecut/releases/new?marketplace=true","showPublishActionBanner":false},"rawBlobUrl":"https://github.com/tepn11/freecut/raw/refs/heads/main/CLAUDE.md","renderImageOrRaw":false,"shortPath":null,"symbolsEnabled":true,"tabSize":2,"topBannersInfo":{"overridingGlobalFundingFile":false,"globalPreferredFundingPath":null,"showInvalidCitationWarning":false,"citationHelpUrl":"https://docs.github.com/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-citation-files","actionsOnboardingTip":null},"truncated":false,"viewable":true,"workflowRedirectUrl":null},"copilotInfo":null,"copilotAccessAllowed":false,"copilotSpacesEnabled":false,"modelsAccessAllowed":false,"modelsRepoIntegrationEnabled":false,"isMarketplaceEnabled":true},"codeViewBlobLayoutRoute.StyledBlob":{"rawLines":["# FreeCut Web","","## Commands","","```bash","npm run dev          # Vite dev server on port 5173","npm run build        # Production build","npm run lint         # Oxlint","npm run format       # Oxfmt","npm run format:check # Check formatting with Oxfmt","npm run test         # Vitest (watch mode)","npm run test:run     # Vitest (single run)","npm run routes       # Regenerate TanStack Router tree (tsr generate)","```","","## Architecture","","Browser-based multi-track video editor. React 19 + TypeScript + Vite.","","```text","src/","├── features/              # User-facing UI modules","│   ├── editor/            # Editor shell, toolbar, panels, stores","│   ├── timeline/          # Multi-track timeline, actions, services","│   ├── preview/           # Preview canvas, transform gizmo, scrub renderer","│   ├── export/            # WebCodecs export pipeline (Web Worker)","│   ├── effects/           # GPU effect UI panels and registry","│   ├── keyframes/         # Keyframe animation, Bezier editor, easing","│   ├── media-library/     # Media import, metadata, OPFS proxies, transcription","│   ├── project-bundle/    # Project ZIP export/import","│   ├── projects/          # Project management","│   ├── scene-browser/     # Caption and scene search UI","│   ├── settings/          # App settings","│   └── workspace-gate/    # Workspace picker / permission gate","├── runtime/               # Playback and rendering engines (not user-facing UI features)","│   ├── composition-runtime/ # Composition rendering (sequences, items, audio, transitions)","│   └── player/            # Clock, video source pools, composition playback","├── infrastructure/        # Platform adapters — browser, storage, GPU, ML, audio","│   ├── gpu-effects/       # WebGPU effect pipeline + shader definitions","│   ├── gpu-transitions/   # WebGPU transition pipeline + shaders","│   ├── gpu-compositor/    # WebGPU blend-mode compositor","│   ├── gpu-masks/         # Mask combine pipeline + texture manager","│   ├── gpu-media/         # Media render/blend pipelines","│   ├── gpu-scopes/        # Waveform/vectorscope/histogram renderers","│   ├── gpu-shapes/        # Shape render pipeline","│   ├── gpu-text/          # Glyph-atlas text pipeline","│   ├── gpu-shared/        # WGSL fragments shared across GPU modules","│   ├── analysis/          # Scene detection, captioning, embeddings, optical flow","│   ├── audio/             # SoundTouch-based time-stretch","│   ├── browser/           # Blob URLs, OPFS, mediabunny adapter","│   ├── storage/           # Workspace FS persistence + legacy IDB migration","│   └── thumbnails/        # GPU thumbnail renderer + sampling strategy","├── shared/                # Framework-agnostic primitives + cross-feature state","│   ├── timeline/          # Transition engine/registry/renderers, defaults","│   ├── projects/          # Schema migrations and normalization","│   ├── state/             # Zustand stores (playback, selection, dialogs, editor)","│   ├── marquee/           # Marquee-selection hook + overlay (paired unit)","│   ├── logging/           # Structured logger, frame jitter monitor","│   ├── ui/                # cn helper, property controls","│   ├── typography/        # Font loading, text style presets","│   ├── graphics/          # Shape generators and path helpers","│   └── utils/             # Managed workers, color/curve math, easing, async, etc.","├── components/            # shadcn/ui components + brand assets","├── app/                   # App bootstrap, error boundary, PWA prompt, debug","├── config/                # Hotkeys + editor layout config","├── i18n/                  # i18next setup, supported languages, locale JSON + per-feature partials","├── routes/                # TanStack Router (file-based, auto-generated routeTree)","└── types/                 # Shared TypeScript types","```","","## Key Patterns","","- **State**: Zustand stores + Zundo for undo/redo","- **Timeline store split**: `useTimelineStore` (from `timeline-store.ts`) is a **facade** over domain stores (`items-store`, `transitions-store`, `keyframes-store`, `markers-store`, `timeline-settings-store`, `timeline-command-store`). Components use the facade with selectors; action code accesses domain stores via `.getState()` directly","- **Timeline mutations**: Action modules in `features/timeline/stores/actions/*.ts` use `execute()` wrapper from `shared.ts` for undo/redo integration. Never mutate timeline stores directly — use these actions","- **TimelineItem composition**: The per-clip component in `features/timeline/components/timeline-item/index.tsx` delegates to dedicated hooks: `useCaptionDialogState`, `useFadeEditors`, `useFadeMath`, `useEditPreviewShifts`, `useTimelineItemBounds`, `useSmartTrimHover`, `useContextMenuState`, plus the existing `useTimelineItemActions` / `useTimelineItemDropHandlers` / `useDragVisualState`. The host file orchestrates these hooks and renders the JSX; sub-components live alongside (`EdgeHalos`, `TransitionDropGhost`, `TranscribeDialogController`, etc.). When adding new clip state, prefer a new hook over inlining","- **Timeline item types**: `TimelineItem` is a discriminated union on `type`: `video | audio | text | image | shape | adjustment | composition` — GIFs use `image` type, no separate gif type. Types in `src/types/timeline.ts`","- **Item positioning**: Remotion convention — `from` (start frame in project FPS) + `durationInFrames`","- **Compositions**: Pre-compositions (sub-comps) have dedicated stores (`compositions-store.ts`, `composition-navigation-store.ts`). 1-level nesting only. Actions in `composition-actions.ts`","- **Migrations**: `src/shared/projects/migrations/` — versioned migrations + normalization run on every project load. Increment `CURRENT_SCHEMA_VERSION` in `types.ts` when adding new migrations","- **Routing**: TanStack Router — run `npm run routes` after adding/changing route files","- **Path alias**: `@/*` → `src/*`","- **i18n**: i18next + react-i18next, initialized in `src/i18n/index.ts` (imported once from `main.tsx`). 9 languages (`en`, `es`, `fr`, `de`, `pt-BR`, `tr`, `ja`, `ko`, `zh`) in `src/i18n/languages.ts`. Base strings in `src/i18n/locales/\u003clang\u003e.json`; per-feature strings live in `src/i18n/locales/partials/\u003clang\u003e/\u003cname\u003e.json` (file contains the slice directly with no language wrapper key). `en` partials are eagerly bundled into `app-shell`; all other languages load on demand via `loadLanguageResources(lang)` / `changeAppLanguage(lang)` from `@/i18n`. The user's persisted language is preloaded before first render via the exported `i18nReady` promise. In components use `const { t } = useTranslation()`; outside React use `import { i18n } from '@/i18n'` then `i18n.t()` (`@/i18n` is allowed by the boundary checks — it's not `@/features/*`). For strings with inline markup use `\u003cTrans i18nKey=... components={{ strong: \u003cstrong/\u003e }} /\u003e`. Resources are deliberately untyped (`i18next.d.ts`) so `t()` accepts any key. Language selector lives in the editor Settings dialog (General); persisted to `localStorage` key `freecut-language` by the language detector. When adding new partials, translate all 9 languages and keep identical key structure across all language dirs; never put a bare ASCII `\"` inside a JSON string value.","- **Styling**: Tailwind CSS 4 + shadcn/ui (Radix primitives)","- **Media processing**: Mediabunny for decode, WebCodecs for export, Web Workers for heavy ops","- **Storage**: Workspace folder via File System Access API (see `infrastructure/storage/workspace-fs/`). Source of truth is a user-picked directory on disk — projects, media metadata, thumbnails, waveforms, gif frames, decoded audio, transcripts all live as plain files. `WorkspaceGate` (`src/features/workspace-gate/`) blocks app render until a workspace is granted. IndexedDB is only used for a tiny handle registry (`freecut-handles-db` v1, at `infrastructure/storage/handles-db.ts`) that stores non-serializable `FileSystem*Handle` references. Legacy `video-editor-db` is read only by the one-time migration path under `infrastructure/storage/legacy-idb/` (reader.ts + migrate.ts); consumers import from the barrel `@/infrastructure/storage` which routes everything to workspace-fs","","## Code Style","","- Strict TypeScript (`noUnusedLocals`, `noUnusedParameters`, `noUncheckedIndexedAccess`)","- `no-console` rule — always use `createLogger` from `src/shared/logging/logger.ts`, never raw `console.*` calls","- **Logging**: Use wide event pattern for multi-step operations (export, import, save): `log.startEvent(name, opId)` accumulates context, emits one structured event via `.success()` / `.failure()`. Use `createOperationId()` for correlation. Include business context (project ID, item counts, codec, resolution) in events","- `typescript/no-explicit-any` warned by Oxlint","","## Testing","","- Vitest + jsdom + @testing-library/react","- `src/test/setup.ts` mocks ImageData, WebGPU APIs (`navigator.gpu`), and GPU constants","- Tests live next to source files: `*.test.ts` / `*.test.tsx`","- **Pure-logic tests opt out of jsdom.** `vite.config.ts` defaults to `environment: 'jsdom'`, but a test that never touches `document` / `window` / `navigator` / testing-library should start with `// @vitest-environment node` on line 1 (blank line after). Building a jsdom per file is ~30% of the suite's wall clock; 280 files already do this. Keep the jsdom default — a file wrongly marked `node` fails loudly with `document is not defined`, whereas flipping the default would silently break any file someone forgot to annotate. Leave a file on jsdom if it merely *mentions* `window`/`navigator`: a `typeof window !== 'undefined'` branch would take the non-browser path with every assertion still green","- **Only write tests that exercise real logic.** A test must be able to fail for a reason other than someone editing a constant or a string. Do NOT add tests that: re-assert a static config/registry/preset constant back to itself (config snapshots); assert `typeof x === 'function'` or `has correct initial state` on a store; only verify a mocked function was called / returned its mock value (the real code is stubbed, so nothing real is covered); render a component and assert a passed-in prop/className/style string appears with no branching behind it; exercise library/framework behavior (Radix, jsdom events, controlled inputs). When the only collaborators are mocked, test against the real in-memory fake (e.g. workspace-fs round-trips) instead. Worth testing: algorithm/math (FPS/timeline conversions, transitions, interpolation, color/curve math), reducer/state-machine transitions, schema migrations, edge/boundary cases, and named regressions. If unsure whether a test adds value, prefer no test over a low-value one","","## Environment","","- `VITE_SHOW_DEBUG_PANEL=false` — set to hide debug panel in dev mode (shown by default)","","## Toolchain \u0026 dependency notes","","- The entire dev/build/test/lint/format stack runs through **vite-plus** (`vp`, currently 0.x / pre-1.0) — it wraps Vite, Vitest, Oxlint, Oxfmt and the task runner. There is no plain-Vite fallback configured; if `vp` breaks, pin the last working version in package.json rather than attempting an ad-hoc migration","- `onnxruntime-web` is intentionally pinned to a **dev build** (`1.26.0-dev.*`) — introduced with the supertonic TTS integration. Don't \"upgrade\" it casually; moving to a stable release requires re-validating transcription, TTS and scene detection","- `lucide-react` is held at 0.468.x deliberately (Vite pre-bundles it; see Gotchas about `optimizeDeps`). A major-version bump is a deliberate task, not a routine dep update","- All production deps are exact-pinned; keep new deps exact-pinned too (no `^`/`~`)","- **TypeScript 7 needs the `overrides.typescript` entry.** `i18next` and `react-i18next` declare `peerOptional typescript@\"^5\"`, so any TS \u003e= 6 fails a clean `npm install`/`npm ci` with ERESOLVE (an *incremental* install over an existing tree misleadingly succeeds). The override in package.json forces one TS copy and must be bumped in lockstep with the `typescript` devDependency. `@voidzero-dev/vite-plus-core` also peers `^5 || ^6`, but never loads the package — it shells out to the tsgolint binary — so that one is inert","- Type checking does **not** run `tsc`. `vp check` type-checks via **tsgolint** (the TypeScript-Go engine), which is why CI already had native-speed checking before the TS 7 bump. Nothing in `package.json` scripts or CI invokes `tsc`; the `typescript` devDependency exists for editor tsserver and ad-hoc `npx tsc`. TS 7.0 ships no stable programmatic API — if a tool ever needs one, alias `@typescript/typescript6`","- **The fallow allowlists are baselines, not approvals.** `check:unused-exports` and `check:unused-class-members` are ratchets: they fail only on findings *new* since the baseline, plus stale entries. Every entry carries a `reason`, and re-baselined ones are tagged — `parked-ai-feature` (the unwired assistant, see `ai-tab.tsx`), `deps-contract` (adapter surface the boundary rules require), `barrel-surface` (feature `index.ts` public API), `unreviewed` (never traced; start here when cleaning up). Never bulk-`fallow fix` these — trace per export. Re-baseline by regenerating both files from `fallow dead-code --format json`, preserving existing reasons; a stale baseline makes the gate fail permanently and get ignored","- `oxlint` / `oxfmt` / `@oxc-project/types` are **not** direct deps — vite-plus exact-pins them internally, so they only move when `vp` moves. A `vp` bump can therefore reformat the tree (0.2.4 brought oxfmt 0.57 and reflowed 52 files); land that churn as its own commit","","## Git","","- `main` — production, `staging` — pre-release integration, `develop` — active development","- PR target: `staging` (feature branches and `develop` PR into `staging`; `staging` is promoted to `main` for release). Do **not** open PRs against `main` directly","- Commit messages: conventional commits — `type(scope): description` (e.g. `fix(timeline):`, `feat(export):`)","","## Gotchas","","- Track groups are 1-level only (no nested groups). Gate behavior (mute/visible/locked) propagates from group to children via `resolveEffectiveTrackStates()` in `group-utils.ts`","- Browser shortcut conflicts (e.g. Ctrl+E) need `eventListenerOptions: { capture: true }` on the hotkey to override Chrome's default behavior","- Feature modules use `index.ts` barrel files to define public API surface — follow this convention when adding new features","- `routeTree.gen.ts` is auto-generated — don't edit manually","- `*.mp4` files are gitignored","- Vite pre-bundles `lucide-react` to avoid analyzing 1500+ icons — don't remove from `optimizeDeps`","- WebGPU tests need mocks from `src/test/setup.ts` — tests will fail without jsdom environment","- Build uses manual chunk splitting — check `vite.config.ts` when adding large dependencies","- `HOTKEY_OPTIONS` has `preventDefault: true` — the library consumes keys before the callback. For panel-scoped shortcuts, use `onKeyDown` on the element with `tabIndex={-1}` + focus-on-hover + `stopPropagation()`, not global `useHotkeys` with guards","- `sourceStart`/`sourceEnd`/`sourceDuration` on timeline items are in **source-native FPS** frames, not project FPS. Use media's `fps` from media library store when converting to seconds","- Track `order` convention: lower value = visually higher (top of timeline). New tracks go at `minOrder - 1`. When creating pre-comps, place the comp item on the bottom-most (highest order) selected track; dissolve expands upward","- Group tracks (`isGroup: true`) are headers only — never place items on them. Filter them out when searching for candidate tracks","- Inline edit cancel (Escape) triggers blur on unmount — use a ref guard to prevent `onBlur` from committing the cancelled value","- `_splitItem()` returns `{ leftItem, rightItem } | null` — capture the return for correct IDs; the original item ID is stale after split","- Timeline has its own `keydown` listener in `timeline.tsx` — new keyboard handlers on child panels must `stopPropagation()` and timeline checks `e.defaultPrevented`","- **Effects are GPU-only** — all visual effects use WebGPU shaders (`type: 'gpu-effect'`). Legacy CSS filter, glitch, halftone, vignette, LUT types were removed in v6 migration. Effect definitions in `src/infrastructure/gpu-effects/effects/`, pipeline in `effects-pipeline.ts`. Specialized UI panels exist for `gpu-curves` and `gpu-color-wheels`; all others use the generic `GpuEffectPanel`","- **Transitions are GPU-only** — all 13 transitions (fade, wipe, slide, flip, clockWipe, iris, dissolve, sparkles, glitch, lightLeak, pixelate, chromatic, radialBlur) render via WebGPU shaders in `infrastructure/gpu-transitions/`. Each renderer in `shared/timeline/transitions/renderers/` has `gpuTransitionId` linking to its shader, plus a `renderCanvas()` Canvas 2D fallback for non-WebGPU environments. `calculateStyles()` is dead code (CSS/DOM transition rendering was removed). Canvas `drawImage` offsets must use `Math.round()` to avoid sub-pixel interpolation artifacts","- After clip edits that change position/duration, call `applyTransitionRepairs(changedClipIds)` from `shared.ts` — transitions auto-heal or report breakages","- `shared/logging/logger.ts` uses only `function` declarations (no `class`/`const` at module scope) to avoid temporal dead zone errors in production chunk ordering — maintain this pattern","- Fast scrub render loop: prewarm frames use WASM decode (40-80ms) and block the loop from processing priority frames. During playback, skip prewarm entirely (`isPlaying` check) — priority frames render fast via DOM video zero-copy (~1ms) and the loop must stay responsive. Background worker preseek (`backgroundPreseek` in `decoder-prewarm.ts`) also fires on large timeline jumps (\u003e3s) for all visible clips — the worker decodes off-thread and the render engine picks up the cached bitmap","- **Render loop concurrency** — `pumpRenderLoop` uses a single-mutex (`scrubRenderInFlightRef`) to prevent concurrent pump iterations during scrubbing. A `scrubRenderGenerationRef` counter is bumped ONLY on playback-start force-clear (not during scrub). The `finally` block releases the lock and triggers follow-up work only when the generation matches; stale pumps (from a superseded playback-start) leave the lock for the new owner. Never bump generation or force-clear the lock on sequential scrub frames — this causes unbounded concurrent pumps. The `data-transition-hold` attribute on DOM video elements coordinates with `video-content.tsx` premount logic and `clearTransitionPlaybackSession` cleanup","- **Transition participant video hold** — during transitions, the incoming clip's DOM video element is paused by `video-content.tsx` premount logic. The transition provider marks it with `data-transition-hold=\"1\"` and calls `.play()` so the canvas renderer gets advancing frames. The mark is removed in `clearTransitionPlaybackSession`. Without this, the incoming clip shows a frozen frame during the transition","- When updating multiple GPU effect params atomically (e.g. color wheel hue + amount), use `onParamsBatchChange`/`onParamsBatchLiveChange` — calling `onParamChange` twice reads stale state on the second call and overwrites the first","- **Reuse rendered frames** — the preview scrub renderer already has fully composited frames with effects/masks/blend modes. Features needing the current frame (thumbnails, scopes, snapshots) should use `usePreviewBridgeStore.getState().captureCanvasSource()` first, falling back to `renderSingleFrame()` only when the preview is unavailable. Never spin up a new render pipeline when an existing one already has the frame","- **Progressive downscaling** — when scaling high-res canvases to small sizes (e.g. 1920→320 thumbnails), halve dimensions repeatedly instead of one large jump. Single-step downscaling causes moire/aliasing with high-frequency GPU effects (halftone, pixelate, etc.)","- `StableVideoSequence`'s `areGroupPropsEqual` (defined in `stable-video-sequence-comparator.ts`, consumed by `stable-video-sequence.tsx`) whitelists item properties for React.memo comparison. When adding new visual properties to `TimelineItem`, add them to this comparison — missing properties cause stale renders during playback","- **GPU pipeline caching** — `EffectsPipeline.requestCachedDevice()` caches the WebGPU adapter + device globally. Subsequent `EffectsPipeline.create()` calls reuse the device (~50-100ms saved). The device-loss handler checks identity before clearing to avoid discarding a freshly acquired device. The preview component eagerly warms the GPU pipeline on mount (parallel with media resolution)","- **`__DEBUG__` API** — `window.__DEBUG__` (DEV-only, tree-shaken in prod) provides console debugging: `stores()`, `getTransitions()`, `getTransitionWindows()`, `getPlaybackState()`, `getTracks()`, `getMediaLibrary()`, `jitter()` (frame timing), `previewPerf()`, `transitionTrace()`, `prewarmCache()`, `filmstripMetrics()`, `perfSummary(prefix?)` / `perfClear()` (User Timing aggregation, default prefix `tl.`), plus playback control (`seekTo`, `play`, `pause`). All use lazy `await import()` to avoid pulling in stores eagerly","- **Timeline perf-marks** — `withPerfMeasure(name, fn)` in `src/shared/logging/perf-marks.ts` wraps hot paths so they appear as named entries on the User Timing track in Chrome DevTools Performance. Currently instruments `tl.action.*` (every timeline mutation, via `actions/shared.ts::execute`), `tl.repairTransitions`, and the RAF loops `tl.raf.{viewportSync,previewHover,zoomApply,scrollThumb,momentum,playheadScrub}`. `withPerfMeasure` is opt-in — gated on `window.__TL_PERF__ = true` (off by default, zero overhead) so the User Timing buffer doesn't grow unbounded in normal use; set the flag before profiling (`npm run perf`), then read marks via the Performance tab or `__DEBUG__.perfSummary()`. `perfMarkRender(name)` adds per-render `tl.render.*` marks to the high-fanout components (ClipContent, TimelineItem, TimelineTrack, TimelineContent, TimelineMarkers, TimelinePlayhead, TransitionItem) — gated on `window.__TL_RENDER_MARKS__ = true` (off by default, zero overhead) for diagnosing which components re-render during a gesture","- **Clip content tracks SETTLED zoom** — `ClipContent` (`timeline-item/clip-content.tsx`) drives filmstrip/waveform width from `contentPixelsPerSecond` (settled, updates ~100ms after a zoom gesture ends), NOT the live per-frame `pixelsPerSecond`. The clip shell resizes smoothly during the gesture via the `--timeline-px-per-frame` CSS variable (no React); the filmstrip tile grid would otherwise rebuild on every wheel/momentum frame (~73% of zoom cost). During the gesture the content is briefly at pre-zoom scale, hidden by the repeating cover-frame background (zoom-in) or `overflow:hidden` clipping (zoom-out), snapping sharp on settle. The `preferImmediateRendering` prop opts back into live pps for active edit previews (trim/slide) where settle lag would distract","- **Clip content defers mount during zoom** — `ClipContent` also reads `isZoomInteracting` **once at mount** via `getState()` (not a reactive subscription) into `deferVisual` state. A clip that first mounts mid-gesture (e.g. entering the viewport while zooming out) renders only its colored shell — no filmstrip/waveform — until the zoom settles, then a one-shot `useZoomStore.subscribe` flips it on. This was ~90% of zoom-OUT cost: zooming out brings many clips into view at once and mounting each one's tile grid + canvas draws stalled the gesture (226ms/frame → ~42ms/frame). Reading at mount (not subscribing) is critical — already-mounted clips must NOT re-render when `isZoomInteracting` flips, or they'd flash empty","- **Transition prearm covers all types** — the `forceFastScrubOverlay` subscription uses `getPlayingAnyTransitionPrewarmStartFrame` (not complex-only) so all transitions get their session pinned and DOM video elements playing before entry. Also checks `getTransitionWindowForFrame` for playback starting inside an active transition","- **Feature boundary rules** — cross-feature imports must go through `deps/` adapter modules. The pre-push hook enforces this via `check:boundaries`. (A `check:legacy-lib-imports` tripwire also catches any reintroduction of `@/lib/*` imports — the `src/lib/` layer was removed and merged into `infrastructure/`.)","- **GPU effect data textures**: effects that need LUT-like auxiliary data declare `dataTexture` in their `GpuEffectDefinition`. The pipeline binds it at `@group(0) @binding(3)`, caches the texture per pass, rewrites same-size contents with `queue.writeTexture`, and invalidates bind groups only when dimensions change. `gpu-curves` uses this for the 256x1 curve LUT; `gpu-lut` embeds resampled `.cube` data in effect params so project bundles and export workers need no side channel.","- **Implicit color grade controls**: the Color workspace renders wheels and curves even before those effects exist. `ColorGradeSection` previews synthetic grade entries through the gizmo effects-preview path during live drags, then lazily creates the real GPU effect on commit. Do not persist synthetic `__grade:*` ids or attach keyframes to them.","- **Interface sounds**: synthesized (no audio assets) via a dedicated `AudioContext` in `infrastructure/audio/ui-sound/` (`synth.ts` data-only `Recipe` → `renderRecipe`; `voices.ts` maps semantic `SoundToken`s → recipes per swappable **voice**; `engine.ts` owns the lazy context + per-token rate limit). To add feedback anywhere call `emitUiSound('\u003ctoken\u003e')` from `@/shared/ui/ui-sound` at the **action chokepoint** (the store action / toggle callback, not each call site) — emit *intent* (`select`/`confirm`/`delete`/`toggleOn`…), never a specific sound. It's gated: opt-in + volume-scaled via `useUiSoundStore` (`shared/state/ui-sound-store.ts`, persisted `freecut-ui-sound`, **off by default**), rate-limited, and **suppressed while `usePlaybackStore.isPlaying`** so chirps never pollute monitored audio (exports are silent by construction — the export worker never imports the module). New voices: add to `VOICES`/`VOICE_OPTIONS` + `VoiceName` and the picker (Settings → General) updates automatically. `previewUiSound(voice, token)` auditions a specific voice without committing it. `hover` is defined but intentionally unwired (too noisy for blanket use)."],"stylingDirectives":[[[0,13,"pl-mh"],[2,13,"pl-en"]],[],[[0,11,"pl-mh"],[3,11,"pl-en"]],[],[[0,3,"pl-s"],[3,7,"pl-en"]],[[21,51,"pl-c"],[21,22,"pl-c"]],[[21,39,"pl-c"],[21,22,"pl-c"]],[[21,29,"pl-c"],[21,22,"pl-c"]],[[21,28,"pl-c"],[21,22,"pl-c"]],[[21,50,"pl-c"],[21,22,"pl-c"]],[[8,12,"pl-c1"],[21,42,"pl-c"],[21,22,"pl-c"]],[[21,42,"pl-c"],[21,22,"pl-c"]],[[21,69,"pl-c"],[21,22,"pl-c"]],[[0,3,"pl-s"]],[],[[0,15,"pl-mh"],[3,15,"pl-en"]],[],[],[],[[0,3,"pl-s"],[3,7,"pl-en"],[7,7,"pl-c1"]],[[0,4,"pl-c1"]],[[0,51,"pl-c1"]],[[0,66,"pl-c1"]],[[0,68,"pl-c1"]],[[0,76,"pl-c1"]],[[0,67,"pl-c1"]],[[0,62,"pl-c1"]],[[0,70,"pl-c1"]],[[0,80,"pl-c1"]],[[0,54,"pl-c1"]],[[0,47,"pl-c1"]],[[0,56,"pl-c1"]],[[0,41,"pl-c1"]],[[0,63,"pl-c1"]],[[0,89,"pl-c1"]],[[0,91,"pl-c1"]],[[0,76,"pl-c1"]],[[0,81,"pl-c1"]],[[0,72,"pl-c1"]],[[0,65,"pl-c1"]],[[0,57,"pl-c1"]],[[0,68,"pl-c1"]],[[0,57,"pl-c1"]],[[0,69,"pl-c1"]],[[0,50,"pl-c1"]],[[0,54,"pl-c1"]],[[0,69,"pl-c1"]],[[0,82,"pl-c1"]],[[0,58,"pl-c1"]],[[0,64,"pl-c1"]],[[0,76,"pl-c1"]],[[0,71,"pl-c1"]],[[0,80,"pl-c1"]],[[0,75,"pl-c1"]],[[0,64,"pl-c1"]],[[0,82,"pl-c1"]],[[0,75,"pl-c1"]],[[0,68,"pl-c1"]],[[0,57,"pl-c1"]],[[0,61,"pl-c1"]],[[0,62,"pl-c1"]],[[0,83,"pl-c1"]],[[0,64,"pl-c1"]],[[0,77,"pl-c1"]],[[0,59,"pl-c1"]],[[0,99,"pl-c1"]],[[0,83,"pl-c1"]],[[0,52,"pl-c1"]],[[0,0,"pl-c1"],[0,3,"pl-s"]],[],[[0,15,"pl-mh"],[3,15,"pl-en"]],[],[[0,1,"pl-v"],[2,4,"pl-s"],[9,11,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[24,26,"pl-s"],[28,29,"pl-s"],[29,45,"pl-c1"],[45,46,"pl-s"],[53,54,"pl-s"],[54,71,"pl-c1"],[71,72,"pl-s"],[79,81,"pl-s"],[87,89,"pl-s"],[110,111,"pl-s"],[111,122,"pl-c1"],[122,123,"pl-s"],[125,126,"pl-s"],[126,143,"pl-c1"],[143,144,"pl-s"],[146,147,"pl-s"],[147,162,"pl-c1"],[162,163,"pl-s"],[165,166,"pl-s"],[166,179,"pl-c1"],[179,180,"pl-s"],[182,183,"pl-s"],[183,206,"pl-c1"],[206,207,"pl-s"],[209,210,"pl-s"],[210,232,"pl-c1"],[232,233,"pl-s"],[317,318,"pl-s"],[318,329,"pl-c1"],[329,330,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[22,24,"pl-s"],[44,45,"pl-s"],[45,82,"pl-c1"],[82,83,"pl-s"],[88,89,"pl-s"],[89,98,"pl-c1"],[98,99,"pl-s"],[113,114,"pl-s"],[114,123,"pl-c1"],[123,124,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[28,30,"pl-s"],[58,59,"pl-s"],[59,111,"pl-c1"],[111,112,"pl-s"],[143,144,"pl-s"],[144,165,"pl-c1"],[165,166,"pl-s"],[168,169,"pl-s"],[169,183,"pl-c1"],[183,184,"pl-s"],[186,187,"pl-s"],[187,198,"pl-c1"],[198,199,"pl-s"],[201,202,"pl-s"],[202,222,"pl-c1"],[222,223,"pl-s"],[225,226,"pl-s"],[226,247,"pl-c1"],[247,248,"pl-s"],[250,251,"pl-s"],[251,268,"pl-c1"],[268,269,"pl-s"],[271,272,"pl-s"],[272,291,"pl-c1"],[291,292,"pl-s"],[312,313,"pl-s"],[313,335,"pl-c1"],[335,336,"pl-s"],[339,340,"pl-s"],[340,367,"pl-c1"],[367,368,"pl-s"],[371,372,"pl-s"],[372,390,"pl-c1"],[390,391,"pl-s"],[484,485,"pl-s"],[485,494,"pl-c1"],[494,495,"pl-s"],[497,498,"pl-s"],[498,517,"pl-c1"],[517,518,"pl-s"],[520,521,"pl-s"],[521,547,"pl-c1"],[547,548,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[23,25,"pl-s"],[27,28,"pl-s"],[28,40,"pl-c1"],[40,41,"pl-s"],[70,71,"pl-s"],[71,75,"pl-c1"],[75,76,"pl-s"],[78,79,"pl-s"],[79,142,"pl-c1"],[142,143,"pl-s"],[155,156,"pl-s"],[156,161,"pl-c1"],[161,162,"pl-s"],[200,201,"pl-s"],[201,222,"pl-c1"],[222,223,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[20,22,"pl-s"],[46,47,"pl-s"],[47,51,"pl-c1"],[51,52,"pl-s"],[84,85,"pl-s"],[85,101,"pl-c1"],[101,102,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[16,18,"pl-s"],[72,73,"pl-s"],[73,94,"pl-c1"],[94,95,"pl-s"],[97,98,"pl-s"],[98,129,"pl-c1"],[129,130,"pl-s"],[166,167,"pl-s"],[167,189,"pl-c1"],[189,190,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[14,16,"pl-s"],[18,19,"pl-s"],[19,50,"pl-c1"],[50,51,"pl-s"],[128,129,"pl-s"],[129,151,"pl-c1"],[151,152,"pl-s"],[156,157,"pl-s"],[157,165,"pl-c1"],[165,166,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[11,13,"pl-s"],[37,38,"pl-s"],[38,52,"pl-c1"],[52,53,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[14,16,"pl-s"],[18,19,"pl-s"],[19,22,"pl-c1"],[22,23,"pl-s"],[26,27,"pl-s"],[27,32,"pl-c1"],[32,33,"pl-s"]],[],[[0,1,"pl-v"],[2,4,"pl-s"],[11,13,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[20,22,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[11,13,"pl-s"],[64,65,"pl-s"],[65,101,"pl-c1"],[101,102,"pl-s"],[271,272,"pl-s"],[272,285,"pl-c1"],[285,286,"pl-s"],[288,289,"pl-s"],[289,317,"pl-c1"],[317,318,"pl-s"],[419,420,"pl-s"],[420,438,"pl-c1"],[438,439,"pl-s"],[447,448,"pl-s"],[448,484,"pl-c1"],[484,485,"pl-s"],[516,517,"pl-s"],[517,534,"pl-c1"],[534,535,"pl-s"],[555,556,"pl-s"],[556,571,"pl-c1"],[571,572,"pl-s"],[623,624,"pl-s"],[624,658,"pl-c1"],[658,659,"pl-s"],[719,720,"pl-s"],[720,744,"pl-c1"],[744,745,"pl-s"]],[],[[0,13,"pl-mh"],[3,13,"pl-en"]],[],[[0,1,"pl-v"],[21,22,"pl-s"],[22,36,"pl-c1"],[36,37,"pl-s"],[39,40,"pl-s"],[40,58,"pl-c1"],[58,59,"pl-s"],[61,62,"pl-s"],[62,86,"pl-c1"],[86,87,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,13,"pl-c1"],[13,14,"pl-s"],[33,34,"pl-s"],[34,46,"pl-c1"],[46,47,"pl-s"],[53,54,"pl-s"],[54,82,"pl-c1"],[82,83,"pl-s"],[95,96,"pl-s"],[96,105,"pl-c1"],[105,106,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[11,13,"pl-s"],[88,89,"pl-s"],[89,115,"pl-c1"],[115,116,"pl-s"],[169,170,"pl-s"],[170,180,"pl-c1"],[180,181,"pl-s"],[184,185,"pl-s"],[185,195,"pl-c1"],[195,196,"pl-s"],[202,203,"pl-s"],[203,222,"pl-c1"],[222,223,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,29,"pl-c1"],[29,30,"pl-s"]],[],[[0,10,"pl-mh"],[3,10,"pl-en"]],[],[[0,1,"pl-v"],[19,41,"pl-s"],[20,41,"pl-corl"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,20,"pl-c1"],[20,21,"pl-s"],[52,53,"pl-s"],[53,66,"pl-c1"],[66,67,"pl-s"]],[[0,1,"pl-v"],[35,36,"pl-s"],[36,45,"pl-c1"],[45,46,"pl-s"],[49,50,"pl-s"],[50,60,"pl-c1"],[60,61,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[38,40,"pl-s"],[41,42,"pl-s"],[42,56,"pl-c1"],[56,57,"pl-s"],[70,71,"pl-s"],[71,91,"pl-c1"],[91,92,"pl-s"],[124,125,"pl-s"],[125,133,"pl-c1"],[133,134,"pl-s"],[137,138,"pl-s"],[138,144,"pl-c1"],[144,145,"pl-s"],[148,149,"pl-s"],[149,158,"pl-c1"],[158,159,"pl-s"],[196,197,"pl-s"],[197,224,"pl-c1"],[224,225,"pl-s"],[285,286,"pl-s"],[391,392,"pl-s"],[392,396,"pl-c1"],[396,397,"pl-s"],[416,417,"pl-s"],[417,440,"pl-c1"],[440,441,"pl-s"],[565,566,"pl-s"],[574,575,"pl-s"],[576,577,"pl-s"],[577,583,"pl-c1"],[583,584,"pl-s"],[585,586,"pl-s"],[586,595,"pl-c1"],[595,596,"pl-s"],[600,601,"pl-s"],[601,630,"pl-c1"],[630,631,"pl-s"]],[],[],[[0,14,"pl-mh"],[3,14,"pl-en"]],[],[[0,1,"pl-v"],[2,3,"pl-s"],[3,30,"pl-c1"],[30,31,"pl-s"]],[],[[0,31,"pl-mh"],[3,31,"pl-en"]],[],[[0,1,"pl-v"],[59,61,"pl-s"],[70,72,"pl-s"],[74,75,"pl-s"],[75,77,"pl-c1"],[77,78,"pl-s"],[212,213,"pl-s"],[213,215,"pl-c1"],[215,216,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,18,"pl-c1"],[18,19,"pl-s"],[49,51,"pl-s"],[60,62,"pl-s"],[64,65,"pl-s"],[65,77,"pl-c1"],[77,78,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,15,"pl-c1"],[15,16,"pl-s"],[89,90,"pl-s"],[90,102,"pl-c1"],[102,103,"pl-s"]],[[0,1,"pl-v"],[75,76,"pl-s"],[76,77,"pl-c1"],[77,78,"pl-s"],[79,80,"pl-s"],[80,81,"pl-c1"],[81,82,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[27,28,"pl-s"],[28,48,"pl-c1"],[48,49,"pl-s"],[56,58,"pl-s"],[59,60,"pl-s"],[60,67,"pl-c1"],[67,68,"pl-s"],[73,74,"pl-s"],[74,87,"pl-c1"],[87,88,"pl-s"],[97,98,"pl-s"],[98,126,"pl-c1"],[126,127,"pl-s"],[158,159,"pl-s"],[159,170,"pl-c1"],[170,171,"pl-s"],[172,173,"pl-s"],[173,179,"pl-c1"],[179,180,"pl-s"],[199,200,"pl-s"],[211,212,"pl-s"],[355,356,"pl-s"],[356,366,"pl-c1"],[366,367,"pl-s"],[383,384,"pl-s"],[384,412,"pl-c1"],[412,413,"pl-s"],[425,426,"pl-s"],[426,434,"pl-c1"],[434,435,"pl-s"]],[[0,1,"pl-v"],[21,23,"pl-s"],[26,28,"pl-s"],[33,34,"pl-s"],[34,37,"pl-c1"],[37,38,"pl-s"],[40,41,"pl-s"],[41,49,"pl-c1"],[49,50,"pl-s"],[67,69,"pl-s"],[77,79,"pl-s"],[191,192,"pl-s"],[192,204,"pl-c1"],[204,205,"pl-s"],[228,229,"pl-s"],[229,232,"pl-c1"],[232,233,"pl-s"],[239,240,"pl-s"],[240,250,"pl-c1"],[250,251,"pl-s"],[304,305,"pl-s"],[305,312,"pl-c1"],[312,313,"pl-s"],[389,390,"pl-s"],[390,413,"pl-c1"],[413,414,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[55,57,"pl-s"],[58,59,"pl-s"],[59,79,"pl-c1"],[79,80,"pl-s"],[85,86,"pl-s"],[86,112,"pl-c1"],[112,113,"pl-s"],[155,156,"pl-s"],[159,160,"pl-s"],[223,224,"pl-s"],[224,230,"pl-c1"],[230,231,"pl-s"],[268,269,"pl-s"],[269,286,"pl-c1"],[286,287,"pl-s"],[316,317,"pl-s"],[317,327,"pl-c1"],[327,328,"pl-s"],[331,332,"pl-s"],[332,345,"pl-c1"],[345,346,"pl-s"],[393,394,"pl-s"],[394,408,"pl-c1"],[408,409,"pl-s"],[419,420,"pl-s"],[420,428,"pl-c1"],[428,429,"pl-s"],[443,444,"pl-s"],[444,454,"pl-c1"],[454,455,"pl-s"],[512,513,"pl-s"],[513,523,"pl-c1"],[523,524,"pl-s"],[595,596,"pl-s"],[596,626,"pl-c1"],[626,627,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,9,"pl-c1"],[9,10,"pl-s"],[13,14,"pl-s"],[14,19,"pl-c1"],[19,20,"pl-s"],[23,24,"pl-s"],[24,42,"pl-c1"],[42,43,"pl-s"],[48,50,"pl-s"],[53,55,"pl-s"],[131,132,"pl-s"],[132,134,"pl-c1"],[134,135,"pl-s"],[145,146,"pl-s"],[146,148,"pl-c1"],[148,149,"pl-s"]],[],[[0,6,"pl-mh"],[3,6,"pl-en"]],[],[[0,1,"pl-v"],[2,3,"pl-s"],[3,7,"pl-c1"],[7,8,"pl-s"],[23,24,"pl-s"],[24,31,"pl-c1"],[31,32,"pl-s"],[60,61,"pl-s"],[61,68,"pl-c1"],[68,69,"pl-s"]],[[0,1,"pl-v"],[13,14,"pl-s"],[14,21,"pl-c1"],[21,22,"pl-s"],[45,46,"pl-s"],[46,53,"pl-c1"],[53,54,"pl-s"],[63,64,"pl-s"],[64,71,"pl-c1"],[71,72,"pl-s"],[74,75,"pl-s"],[75,82,"pl-c1"],[82,83,"pl-s"],[99,100,"pl-s"],[100,104,"pl-c1"],[104,105,"pl-s"],[123,125,"pl-s"],[128,130,"pl-s"],[148,149,"pl-s"],[149,153,"pl-c1"],[153,154,"pl-s"]],[[0,1,"pl-v"],[42,43,"pl-s"],[43,67,"pl-c1"],[67,68,"pl-s"],[75,76,"pl-s"],[76,90,"pl-c1"],[90,91,"pl-s"],[93,94,"pl-s"],[94,107,"pl-c1"],[107,108,"pl-s"]],[],[[0,10,"pl-mh"],[3,10,"pl-en"]],[],[[0,1,"pl-v"],[126,127,"pl-s"],[127,156,"pl-c1"],[156,157,"pl-s"],[161,162,"pl-s"],[162,176,"pl-c1"],[176,177,"pl-s"]],[[0,1,"pl-v"],[48,49,"pl-s"],[49,88,"pl-c1"],[88,89,"pl-s"]],[[0,1,"pl-v"],[22,23,"pl-s"],[23,31,"pl-c1"],[31,32,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,19,"pl-c1"],[19,20,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,8,"pl-c1"],[8,9,"pl-s"]],[[0,1,"pl-v"],[19,20,"pl-s"],[20,32,"pl-c1"],[32,33,"pl-s"],[85,86,"pl-s"],[86,98,"pl-c1"],[98,99,"pl-s"]],[[0,1,"pl-v"],[31,32,"pl-s"],[32,49,"pl-c1"],[49,50,"pl-s"]],[[0,1,"pl-v"],[44,45,"pl-s"],[45,59,"pl-c1"],[59,60,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,17,"pl-c1"],[17,18,"pl-s"],[23,24,"pl-s"],[24,44,"pl-c1"],[44,45,"pl-s"],[127,128,"pl-s"],[128,137,"pl-c1"],[137,138,"pl-s"],[159,160,"pl-s"],[160,173,"pl-c1"],[173,174,"pl-s"],[194,195,"pl-s"],[195,212,"pl-c1"],[212,213,"pl-s"],[226,227,"pl-s"],[227,237,"pl-c1"],[237,238,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,14,"pl-c1"],[14,15,"pl-s"],[16,17,"pl-s"],[17,26,"pl-c1"],[26,27,"pl-s"],[28,29,"pl-s"],[29,43,"pl-c1"],[43,44,"pl-s"],[70,72,"pl-s"],[89,91,"pl-s"],[129,130,"pl-s"],[130,133,"pl-c1"],[133,134,"pl-s"]],[[0,1,"pl-v"],[8,9,"pl-s"],[9,14,"pl-c1"],[14,15,"pl-s"],[94,95,"pl-s"],[95,107,"pl-c1"],[107,108,"pl-s"]],[[0,1,"pl-v"],[16,17,"pl-s"],[17,30,"pl-c1"],[30,31,"pl-s"]],[[0,1,"pl-v"],[84,85,"pl-s"],[85,91,"pl-c1"],[91,92,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,15,"pl-c1"],[15,16,"pl-s"],[25,26,"pl-s"],[26,56,"pl-c1"],[56,57,"pl-s"]],[[0,1,"pl-v"],[23,24,"pl-s"],[24,31,"pl-c1"],[31,32,"pl-s"],[45,46,"pl-s"],[46,58,"pl-c1"],[58,59,"pl-s"],[105,106,"pl-s"],[106,123,"pl-c1"],[123,124,"pl-s"],[145,146,"pl-s"],[146,164,"pl-c1"],[164,165,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[24,26,"pl-s"],[68,69,"pl-s"],[69,87,"pl-c1"],[87,88,"pl-s"],[200,201,"pl-s"],[201,240,"pl-c1"],[240,241,"pl-s"],[255,256,"pl-s"],[256,275,"pl-c1"],[275,276,"pl-s"],[310,311,"pl-s"],[311,321,"pl-c1"],[321,322,"pl-s"],[327,328,"pl-s"],[328,344,"pl-c1"],[344,345,"pl-s"],[374,375,"pl-s"],[375,389,"pl-c1"],[389,390,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[28,30,"pl-s"],[196,197,"pl-s"],[197,228,"pl-c1"],[228,229,"pl-s"],[248,249,"pl-s"],[249,287,"pl-c1"],[287,288,"pl-s"],[293,294,"pl-s"],[294,309,"pl-c1"],[309,310,"pl-s"],[341,342,"pl-s"],[342,356,"pl-c1"],[356,357,"pl-s"],[406,407,"pl-s"],[407,424,"pl-c1"],[424,425,"pl-s"],[490,491,"pl-s"],[491,500,"pl-c1"],[500,501,"pl-s"],[519,520,"pl-s"],[520,532,"pl-c1"],[532,533,"pl-s"]],[[0,1,"pl-v"],[55,56,"pl-s"],[56,94,"pl-c1"],[94,95,"pl-s"],[101,102,"pl-s"],[102,111,"pl-c1"],[111,112,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,27,"pl-c1"],[27,28,"pl-s"],[39,40,"pl-s"],[40,48,"pl-c1"],[48,49,"pl-s"],[67,68,"pl-s"],[68,73,"pl-c1"],[73,74,"pl-s"],[75,76,"pl-s"],[76,81,"pl-c1"],[81,82,"pl-s"]],[[0,1,"pl-v"],[159,160,"pl-s"],[160,169,"pl-c1"],[169,170,"pl-s"],[233,234,"pl-s"],[301,302,"pl-s"],[302,319,"pl-c1"],[319,320,"pl-s"],[324,325,"pl-s"],[325,343,"pl-c1"],[343,344,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[27,29,"pl-s"],[32,33,"pl-s"],[33,47,"pl-c1"],[47,48,"pl-s"],[70,71,"pl-s"],[71,93,"pl-c1"],[93,94,"pl-s"],[154,155,"pl-s"],[155,179,"pl-c1"],[179,180,"pl-s"],[258,259,"pl-s"],[259,266,"pl-c1"],[266,267,"pl-s"],[554,555,"pl-s"],[555,575,"pl-c1"],[575,576,"pl-s"],[626,627,"pl-s"],[627,644,"pl-c1"],[644,645,"pl-s"],[665,666,"pl-s"],[666,696,"pl-c1"],[696,697,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[37,39,"pl-s"],[113,114,"pl-s"],[114,131,"pl-c1"],[131,132,"pl-s"],[187,188,"pl-s"],[188,212,"pl-c1"],[212,213,"pl-s"],[224,225,"pl-s"],[225,232,"pl-c1"],[232,233,"pl-s"],[303,304,"pl-s"],[304,334,"pl-c1"],[334,335,"pl-s"]],[[0,1,"pl-v"],[91,92,"pl-s"],[92,111,"pl-c1"],[111,112,"pl-s"],[113,114,"pl-s"],[114,137,"pl-c1"],[137,138,"pl-s"],[149,150,"pl-s"],[150,163,"pl-c1"],[163,164,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[25,27,"pl-s"],[203,204,"pl-s"],[204,258,"pl-c1"],[258,259,"pl-s"],[283,284,"pl-s"],[284,303,"pl-c1"],[303,304,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[27,29,"pl-s"]],[[0,1,"pl-v"],[2,3,"pl-s"],[3,22,"pl-c1"],[22,23,"pl-s"],[26,27,"pl-s"],[27,45,"pl-c1"],[45,46,"pl-s"],[59,60,"pl-s"],[60,95,"pl-c1"],[95,96,"pl-s"],[110,111,"pl-s"],[111,136,"pl-c1"],[136,137,"pl-s"],[230,231,"pl-s"],[231,243,"pl-c1"],[243,244,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[24,26,"pl-s"],[29,30,"pl-s"],[30,67,"pl-c1"],[67,68,"pl-s"],[125,126,"pl-s"],[126,150,"pl-c1"],[150,151,"pl-s"],[176,177,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[4,5,"pl-s"],[5,14,"pl-c1"],[14,15,"pl-s"],[19,21,"pl-s"],[24,25,"pl-s"],[25,41,"pl-c1"],[41,42,"pl-s"],[103,104,"pl-s"],[104,112,"pl-c1"],[112,113,"pl-s"],[115,116,"pl-s"],[116,132,"pl-c1"],[132,133,"pl-s"],[135,136,"pl-s"],[136,158,"pl-c1"],[158,159,"pl-s"],[161,162,"pl-s"],[162,180,"pl-c1"],[180,181,"pl-s"],[183,184,"pl-s"],[184,195,"pl-c1"],[195,196,"pl-s"],[198,199,"pl-s"],[199,216,"pl-c1"],[216,217,"pl-s"],[219,220,"pl-s"],[220,228,"pl-c1"],[228,229,"pl-s"],[246,247,"pl-s"],[247,260,"pl-c1"],[260,261,"pl-s"],[263,264,"pl-s"],[264,281,"pl-c1"],[281,282,"pl-s"],[284,285,"pl-s"],[285,299,"pl-c1"],[299,300,"pl-s"],[302,303,"pl-s"],[303,321,"pl-c1"],[321,322,"pl-s"],[324,325,"pl-s"],[325,345,"pl-c1"],[345,346,"pl-s"],[349,350,"pl-s"],[350,361,"pl-c1"],[361,362,"pl-s"],[404,405,"pl-s"],[405,408,"pl-c1"],[408,409,"pl-s"],[435,436,"pl-s"],[436,442,"pl-c1"],[442,443,"pl-s"],[445,446,"pl-s"],[446,450,"pl-c1"],[450,451,"pl-s"],[453,454,"pl-s"],[454,459,"pl-c1"],[459,460,"pl-s"],[476,477,"pl-s"],[477,491,"pl-c1"],[491,492,"pl-s"]],[],[[0,1,"pl-v"],[2,4,"pl-s"],[36,38,"pl-s"],[41,42,"pl-s"],[42,53,"pl-c1"],[53,54,"pl-s"],[56,57,"pl-s"],[57,87,"pl-c1"],[87,88,"pl-s"],[127,128,"pl-s"],[128,150,"pl-c1"],[150,151,"pl-s"],[170,171,"pl-s"],[228,229,"pl-s"],[229,244,"pl-c1"],[244,245,"pl-s"],[306,307,"pl-s"],[307,330,"pl-c1"],[330,331,"pl-s"],[436,437,"pl-s"],[577,578,"pl-s"],[578,593,"pl-c1"],[593,594,"pl-s"],[646,647,"pl-s"],[647,671,"pl-c1"],[671,672,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[41,43,"pl-s"],[46,47,"pl-s"],[47,58,"pl-c1"],[58,59,"pl-s"],[71,72,"pl-s"],[72,89,"pl-c1"],[89,90,"pl-s"],[91,93,"pl-s"],[106,108,"pl-s"],[113,114,"pl-s"],[114,124,"pl-c1"],[124,125,"pl-s"],[161,162,"pl-s"],[162,173,"pl-c1"],[173,174,"pl-s"],[363,364,"pl-s"],[364,386,"pl-c1"],[386,387,"pl-s"],[410,411,"pl-s"],[565,566,"pl-s"],[674,675,"pl-s"],[675,692,"pl-c1"],[692,693,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[38,40,"pl-s"],[47,48,"pl-s"],[48,69,"pl-c1"],[69,70,"pl-s"],[89,90,"pl-s"],[90,130,"pl-c1"],[130,131,"pl-s"],[252,253,"pl-s"],[253,280,"pl-c1"],[280,281,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[26,28,"pl-s"],[69,70,"pl-s"],[70,75,"pl-c1"],[75,76,"pl-s"],[130,131,"pl-s"],[131,147,"pl-c1"],[147,148,"pl-s"],[153,154,"pl-s"],[154,178,"pl-c1"],[178,179,"pl-s"],[224,225,"pl-s"],[225,232,"pl-c1"],[232,233,"pl-s"],[248,249,"pl-s"],[249,257,"pl-c1"],[257,258,"pl-s"],[293,294,"pl-s"],[294,309,"pl-c1"],[309,310,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[28,30,"pl-s"],[82,83,"pl-s"],[83,94,"pl-c1"],[94,95,"pl-s"],[105,106,"pl-s"],[106,125,"pl-c1"],[125,126,"pl-s"],[153,154,"pl-s"],[154,175,"pl-c1"],[175,176,"pl-s"],[240,241,"pl-s"],[241,259,"pl-c1"],[259,260,"pl-s"],[319,320,"pl-s"],[320,330,"pl-c1"],[330,331,"pl-s"],[367,368,"pl-s"],[368,375,"pl-c1"],[375,376,"pl-s"],[394,395,"pl-s"],[395,400,"pl-c1"],[400,401,"pl-s"]],[[0,1,"pl-v"],[2,4,"pl-s"],[33,35,"pl-s"],[116,117,"pl-s"],[117,134,"pl-c1"],[134,135,"pl-s"],[303,304,"pl-s"],[304,313,"pl-c1"],[313,314,"pl-s"]],[]],"colorizedLines":null}},"title":"freecut/CLAUDE.md at main · tepn11/freecut","appPayload":{},"meta":{"title":"freecut/CLAUDE.md at main · tepn11/freecut"}}</script>
  <div data-target="react-app.reactRoot"><meta name="github-code-view-meta-stats" id="github-code-view-meta-stats" data-hydrostats="publish"/> <!-- --> <a hidden="" id="code-view-repo-link" href="/tepn11/freecut" data-discover="true"></a> <div class="d-none"></div><div><div style="--spacing:var(--spacing-none)" class="prc-PageLayout-PageLayoutRoot--KH-d" data-component="SplitPageLayout" data-has-sidebar="true"><div class="prc-PageLayout-SidebarWrapper-kLG4B CopilotSidePanelSidebar-module__SidePanel__L3O0C CopilotSidePanelSidebar-module__HiddenSidePanel__TBRGn" style="--spacing-column:var(--spacing-none)" data-is-hidden="false" data-position="end" data-sticky="true" data-responsive-variant="fullscreen"><div class="prc-PageLayout-VerticalDivider-9QRmK prc-PageLayout-SidebarVerticalDivider-0Rl0V" data-component="PageLayout.VerticalDivider" data-variant="line" data-position="end" style="--spacing:var(--spacing-none)"><div class="prc-PageLayout-DraggableHandle-9s6B4" data-component="PageLayout.DragHandle" role="slider" aria-label="Draggable pane splitter" aria-valuemin="450" aria-valuemax="768" aria-valuenow="544" aria-valuetext="Pane width 544 pixels" tabindex="0"></div></div><div class="prc-PageLayout-Sidebar-iciWg" data-component="SplitPageLayout.Sidebar" data-resizable="true" style="--spacing:var(--spacing-normal);--pane-min-width:450px;--pane-max-width:768px;--pane-width-custom:544px;--pane-width-size:var(--pane-width-custom);--pane-width:544px"><div class="height-full" data-testid="copilot-code-view-side-panel"><div id="copilot-side-panel-content" class="height-full"></div></div></div></div><div class="prc-PageLayout-PageLayoutWrapper-2BhU2" data-width="full"><div class="prc-PageLayout-PageLayoutContent-BneH9"><div id="repos-file-tree-sidebar" class="CodeViewFileTreeLayout-module__sidebar__n_Aau" tabindex="0"><div class="prc-PageLayout-PaneWrapper-pHPop ReposFileTreePane-module__Pane__rBZpI ReposFileTreePane-module__HideTree__AYZnm ReposFileTreePane-module__HidePane__VHAVt" style="--offset-header:0px;--spacing-row:var(--spacing-none);--spacing-column:var(--spacing-none)" data-is-hidden="false" data-position="start" data-sticky="true"><div class="prc-PageLayout-HorizontalDivider-JLVqp prc-PageLayout-PaneHorizontalDivider-9tbnE" data-component="PageLayout.HorizontalDivider" data-variant-regular="none" data-variant-narrow="none" data-position="start" style="--spacing-divider:var(--spacing-none);--spacing:var(--spacing-none)"></div><div class="prc-PageLayout-Pane-AyzHK" data-component="SplitPageLayout.Pane" data-resizable="true" style="--spacing:var(--spacing-none);--pane-min-width:256px;--pane-max-width:calc(100vw - var(--pane-max-width-diff));--pane-width-size:var(--pane-width-large);--pane-width:320px"></div><div class="prc-PageLayout-VerticalDivider-9QRmK prc-PageLayout-PaneVerticalDivider-le57g" data-component="PageLayout.VerticalDivider" data-variant-narrow="none" data-variant-regular="line" data-variant-wide="line" data-position="start" style="--spacing:var(--spacing-none)"><div class="prc-PageLayout-DraggableHandle-9s6B4" data-component="PageLayout.DragHandle" role="slider" aria-label="Draggable pane splitter" aria-valuemin="256" aria-valuemax="600" aria-valuenow="320" aria-valuetext="Pane width 320 pixels" tabindex="0"></div></div></div></div><div data-component="SplitPageLayout.Content" class="prc-PageLayout-ContentWrapper-gR9eG"><div class="prc-PageLayout-Content-xWL-A" data-width="full" style="--spacing:var(--spacing-none)"><div class="SharedPageLayout-module__content__IwGAp" data-selector="repos-split-pane-content" id="repos-split-pane-content" tabindex="0"> <!-- --> <div class="container CodeViewHeader-module__Box__JkPOb"><div class="CodeViewHeader-module__StickyHeader__Qn7UN" id="StickyHeader"><div class="CodeViewHeader-module__Box_1__SbNDV"><div class="CodeViewHeader-module__Box_2__TB46f"><div class="react-code-view-header-wrap--narrow CodeViewHeader-module__Box_3__q1zUL"><div class="CodeViewHeader-module__treeToggleWrapper__RQ__9"><h2 class="use-tree-pane-module__Heading__s4QbZ prc-Heading-Heading-MtWFE" data-component="Heading"><button data-component="Button" type="button" aria-label="Expand file tree" data-testid="expand-file-tree-button-mobile" class="prc-Button-ButtonBase-9n-Xk ExpandFileTreeButton-module__Button_1__Svs95" data-loading="false" data-size="medium" data-variant="invisible"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-arrow-left" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.78 12.53a.75.75 0 0 1-1.06 0L2.47 8.28a.75.75 0 0 1 0-1.06l4.25-4.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L4.81 7h7.44a.75.75 0 0 1 0 1.5H4.81l2.97 2.97a.75.75 0 0 1 0 1.06Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3">Files</span></span></button><button data-component="IconButton" type="button" data-testid="expand-file-tree-button" aria-controls="repos-file-tree" class="prc-Button-ButtonBase-9n-Xk position-relative ExpandFileTreeButton-module__expandButton__hDOcv ExpandFileTreeButton-module__filesButtonBreakpoint__zEvz3 fgColor-muted prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="invisible" aria-labelledby="_R_4lla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-sidebar-collapse" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M6.823 7.823a.25.25 0 0 1 0 .354l-2.396 2.396A.25.25 0 0 1 4 10.396V5.604a.25.25 0 0 1 .427-.177Z"></path><path d="M1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0ZM1.5 1.75v12.5c0 .138.112.25.25.25H9.5v-13H1.75a.25.25 0 0 0-.25.25ZM11 14.5h3.25a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25H11Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="se" data-component="Tooltip" aria-hidden="true" id="_R_4lla9lik5_">Expand file tree</span><div class="d-none"></div></h2></div><div class="react-code-view-header-mb--narrow mr-2"><button data-component="Button" type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="main branch" data-testid="anchor-button" data-icv-name="Switch branches/tags" class="prc-Button-ButtonBase-9n-Xk ref-selector-class RefSelectorAnchoredOverlay-module__RefSelectorOverlayBtn__a3WK3" data-loading="false" data-size="medium" data-variant="default" id="ref-picker-repos-header-ref-selector-wide"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3"><div class="RefSelectorAnchoredOverlay-module__RefSelectorOverlayContainer__yaf4p"><div style="max-width:125px" class="ref-selector-button-text-container RefSelectorAnchoredOverlay-module__RefSelectorBtnTextContainer__Di3rk"><span class="RefSelectorAnchoredOverlay-module__RefSelectorText__w_fmP">main</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-YNt2F prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><div class="d-none"></div></div><div class="react-code-view-header-mb--narrow CodeViewHeader-module__Box_5__MQ0hL"><div class="Breadcrumb-module__container__Vxvev Breadcrumb-module__lg__Rjz0A"><nav data-testid="breadcrumbs" aria-labelledby="repos-header-breadcrumb-heading" id="repos-header-breadcrumb" class="Breadcrumb-module__nav__rQFDj"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading" id="repos-header-breadcrumb-heading">Breadcrumbs</h2><ol class="Breadcrumb-module__list__ZH6zr"><li class="Breadcrumb-module__listItem__Ib0x_"><a class="Breadcrumb-module__repoLink__O2Nbs prc-Link-Link-9ZwDx" data-component="Link" data-testid="breadcrumbs-repo-link" href="/tepn11/freecut/tree/main" data-discover="true">freecut</a></li></ol></nav><div data-testid="breadcrumbs-filename" class="Breadcrumb-module__filename__equZR"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__lg__Rjz0A" aria-hidden="true">/</span><h1 class="Breadcrumb-module__filenameHeading__MNMtw Breadcrumb-module__lg__Rjz0A prc-Heading-Heading-MtWFE" data-component="Heading" tabindex="-1" id="file-name-id">CLAUDE.md</h1></div><button data-component="IconButton" type="button" class="prc-Button-ButtonBase-9n-Xk ml-2 prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_7lla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="CopyToClipboardIconButton-module__tooltip__WyiwL prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-label="Copy path" aria-hidden="true" id="_R_7lla9lik5_">Copy path</span></div></div></div><div class="react-code-view-header-element--wide"><div class="CodeViewHeader-module__Box_7___0R6c"><div class="d-flex gap-2"><div><div class="CodeViewHeader-module__FileResultsList__JDzUy"><span class="d-flex FileResultsList-module__FilesSearchBox__ivVkc TextInput-wrapper prc-components-TextInputWrapper-Hpdqi prc-components-TextInputBaseWrapper-wY-n0" data-no-trailing-action="true" data-component="TextInput" data-leading-visual="true" data-trailing-visual="true" aria-busy="false"><span class="TextInput-icon" id="_R_1cpla9lik5_" aria-hidden="true" data-component="TextInput.LeadingVisual"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-search" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path></svg></span><input type="text" aria-label="Go to file" role="combobox" aria-controls="file-results-list" aria-expanded="false" aria-haspopup="dialog" autoCorrect="off" spellCheck="false" placeholder="Go to file" aria-describedby="_R_1cpla9lik5_ _R_1cpla9lik5H1_" data-component="input" class="prc-components-Input-IwWrt" value=""/><span class="TextInput-icon" id="_R_1cpla9lik5H1_" aria-hidden="true" data-component="TextInput.TrailingVisual"></span></span></div><div class="d-none"></div></div><button data-component="Button" type="button" style="display:none" class="prc-Button-ButtonBase-9n-Xk NavigationMenu-module__Button__LpKgm" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3">Blame</span></span></button><div class="d-none"></div><button data-component="IconButton" type="button" data-testid="more-file-actions-button-nav-menu-wide" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk js-blob-dropdown-click NavigationMenu-module__IconButton__HpX3G prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-labelledby="_R_7p9la9lik5_" id="_R_99la9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-hidden="true" id="_R_7p9la9lik5_">More file actions</span></div></div></div><div class="react-code-view-header-element--narrow"><div class="CodeViewHeader-module__Box_7___0R6c"><div class="d-flex gap-2"><button data-component="Button" type="button" style="display:none" class="prc-Button-ButtonBase-9n-Xk NavigationMenu-module__Button__LpKgm" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3">Blame</span></span></button><div class="d-none"></div><button data-component="IconButton" type="button" data-testid="more-file-actions-button-nav-menu-narrow" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk js-blob-dropdown-click NavigationMenu-module__IconButton__HpX3G prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-labelledby="_R_7pdla9lik5_" id="_R_9dla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-hidden="true" id="_R_7pdla9lik5_">More file actions</span></div></div></div></div></div></div></div><div class="CodeView-module__contentWrapper__cG2JH"><div class="react-code-view-bottom-padding"><div class="BlobTopBanners-module__Box__v_nvx"></div></div> <div class="d-none"></div><div class="d-flex flex-column border rounded-2 tmp-mb-3 pl-1"><div class="LatestCommit-module__Box__B25ZT"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">Latest commit</h2><div style="width:120px" class="Skeleton Skeleton--text" data-testid="loading"> </div><div class="d-flex flex-shrink-0 gap-2"><div data-testid="latest-commit-details" class="d-none d-sm-flex flex-items-center"></div><div class="d-flex gap-2"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">History</h2><a data-component="LinkButton" href="/tepn11/freecut/commits/main/CLAUDE.md" class="prc-Button-ButtonBase-9n-Xk d-none d-lg-flex LinkButton-module__linkButton__nFnov flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3"><span class="fgColor-default">History</span></span></span></a><div class="d-sm-none"></div><div class="d-flex d-lg-none"><a data-component="LinkButton" aria-label="View commit history for this file." href="/tepn11/freecut/commits/main/CLAUDE.md" class="prc-Button-ButtonBase-9n-Xk LinkButton-module__linkButton__nFnov flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible" aria-describedby="_R_4mlala9lik5_"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span></span></a><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="s" data-component="Tooltip" role="tooltip" aria-hidden="true" id="_R_4mlala9lik5_">History</span></div></div></div></div></div><div class="d-flex flex-row"><div class="container BlobViewContent-module__blobContainer__DtH2d"><div class="react-code-size-details-banner BlobViewContent-module__codeSizeDetails__e5sUw"><div class="react-code-size-details-banner CodeSizeDetails-module__Box__VcD6l"><div class="text-mono CodeSizeDetails-module__Box_1__GVxQL"><div data-testid="blob-size" class="CodeSizeDetails-module__Truncate_1__lE93V prc-Truncate-Truncate-2G1eo" data-inline="true" title="26.1 KB" style="--truncate-max-width:100%"><span>161 lines (142 loc) · 26.1 KB</span></div></div></div></div><div class="react-blob-view-header-sticky BlobViewContent-module__stickyHeader__VwxB5" id="repos-sticky-header"><div class="BlobViewHeader-module__Box__yhm9u"><div class="react-blob-sticky-header"><div class="FileNameStickyHeader-module__outerWrapper__ZL4Xc FileNameStickyHeader-module__outerWrapperHidden__Zpynk"><div class="FileNameStickyHeader-module__Box_1__Hazu5"><div class="FileNameStickyHeader-module__Box_2__hoolP"><div class="FileNameStickyHeader-module__Box_3__MVKsk"><button data-component="Button" type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="main branch" data-testid="anchor-button" data-icv-name="Switch branches/tags" class="prc-Button-ButtonBase-9n-Xk ref-selector-class RefSelectorAnchoredOverlay-module__RefSelectorOverlayBtn__a3WK3" data-loading="false" data-size="medium" data-variant="default" id="ref-picker-repos-header-ref-selector"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3"><div class="RefSelectorAnchoredOverlay-module__RefSelectorOverlayContainer__yaf4p"><div style="max-width:125px" class="ref-selector-button-text-container RefSelectorAnchoredOverlay-module__RefSelectorBtnTextContainer__Di3rk"><span class="RefSelectorAnchoredOverlay-module__RefSelectorText__w_fmP">main</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-YNt2F prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><div class="d-none"></div></div><div class="FileNameStickyHeader-module__Box_4__FLhtt"><div class="Breadcrumb-module__container__Vxvev Breadcrumb-module__md__Wb1Gs"><nav data-testid="breadcrumbs" aria-labelledby="sticky-breadcrumb-heading" id="sticky-breadcrumb" class="Breadcrumb-module__nav__rQFDj"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading" id="sticky-breadcrumb-heading">Breadcrumbs</h2><ol class="Breadcrumb-module__list__ZH6zr"><li class="Breadcrumb-module__listItem__Ib0x_"><a class="Breadcrumb-module__repoLink__O2Nbs prc-Link-Link-9ZwDx" data-component="Link" data-testid="breadcrumbs-repo-link" href="/tepn11/freecut/tree/main" data-discover="true">freecut</a></li></ol></nav><div data-testid="breadcrumbs-filename" class="Breadcrumb-module__filename__equZR"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__md__Wb1Gs" aria-hidden="true">/</span><h1 class="Breadcrumb-module__filenameHeading__MNMtw Breadcrumb-module__md__Wb1Gs prc-Heading-Heading-MtWFE" data-component="Heading" tabindex="-1" id="sticky-file-name-id">CLAUDE.md</h1></div><button data-component="IconButton" type="button" class="prc-Button-ButtonBase-9n-Xk ml-2 prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_7lcpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="CopyToClipboardIconButton-module__tooltip__WyiwL prc-TooltipV2-Tooltip-tLeuB" data-direction="s" data-component="Tooltip" aria-label="Copy path" aria-hidden="true" id="_R_7lcpala9lik5_">Copy path</span></div></div></div><button data-component="Button" type="button" class="prc-Button-ButtonBase-9n-Xk FileNameStickyHeader-module__Button__LSEU_ FileNameStickyHeader-module__GoToTopButton__nxAFn" data-loading="false" data-size="small" data-variant="invisible"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-arrow-up" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.47 7.78a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0l4.25 4.25a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018L9 4.81v7.44a.75.75 0 0 1-1.5 0V4.81L4.53 7.78a.75.75 0 0 1-1.06 0Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3">Top</span></span></button></div></div></div><div class="BlobViewHeader-module__Box_1__VEmuQ"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">File metadata and controls</h2><div class="BlobViewHeader-module__Box_2__icUs2"><ul aria-label="File view" class="prc-SegmentedControl-SegmentedControl-lqIXp BlobTabButtons-module__SegmentedControl__jen2u" data-variant="default" data-size="small" data-component="SegmentedControl"><li class="prc-SegmentedControl-Item-tSCQh" data-selected="" data-component="SegmentedControl.Button"><button aria-pressed="true" class="prc-SegmentedControl-Button-E48xz" type="button" style="--separator-color:transparent"><span class="prc-SegmentedControl-Content-1COlk segmentedControl-content"><div class="prc-SegmentedControl-Text-7S2y2 segmentedControl-text" data-text="Preview">Preview</div></span></button></li><li class="prc-SegmentedControl-Item-tSCQh" data-component="SegmentedControl.Button"><button aria-pressed="false" class="prc-SegmentedControl-Button-E48xz" type="button" style="--separator-color:var(--borderColor-default)"><span class="prc-SegmentedControl-Content-1COlk segmentedControl-content"><div class="prc-SegmentedControl-Text-7S2y2 segmentedControl-text" data-text="Code">Code</div></span></button></li><li class="prc-SegmentedControl-Item-tSCQh" data-component="SegmentedControl.Button"><button aria-pressed="false" class="prc-SegmentedControl-Button-E48xz" type="button" style="--separator-color:var(--borderColor-default)"><span class="prc-SegmentedControl-Content-1COlk segmentedControl-content"><div class="prc-SegmentedControl-Text-7S2y2 segmentedControl-text" data-text="Blame">Blame</div></span></button></li></ul><div class="d-none"></div><div class="react-code-size-details-in-header CodeSizeDetails-module__Box__VcD6l"><div class="text-mono CodeSizeDetails-module__Box_1__GVxQL"><div data-testid="blob-size" class="CodeSizeDetails-module__Truncate_1__lE93V prc-Truncate-Truncate-2G1eo" data-inline="true" title="26.1 KB" style="--truncate-max-width:100%"><span>161 lines (142 loc) · 26.1 KB</span></div></div></div></div><div class="BlobViewHeader-module__Box_3__ng6v2"><div class="d-none"></div><div class="react-blob-header-edit-and-raw-actions BlobViewHeader-module__Box_4__J4Y4W"><div class="d-none"></div><div class="prc-ButtonGroup-ButtonGroup-vFUrY" data-component="ButtonGroup"><div class="prc-ButtonGroup-Item-PqvDl"><a data-component="LinkButton" href="https://github.com/tepn11/freecut/raw/refs/heads/main/CLAUDE.md" data-testid="raw-button" class="prc-Button-ButtonBase-9n-Xk LinkButton-module__linkButton__nFnov BlobViewHeader-module__LinkButton__X9kx2" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3">Raw</span></span></a></div><div class="prc-ButtonGroup-Item-PqvDl"><button data-component="IconButton" type="button" data-testid="copy-raw-button" class="prc-Button-ButtonBase-9n-Xk prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default" aria-labelledby="_R_qaucpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="n" data-component="Tooltip" aria-hidden="true" id="_R_qaucpala9lik5_">Copy raw file</span></div><div class="prc-ButtonGroup-Item-PqvDl"><button data-component="IconButton" type="button" data-testid="download-raw-button" class="prc-Button-ButtonBase-9n-Xk BlobViewHeader-module__downloadButton__ef459 prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default" aria-labelledby="_R_eaucpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-download" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z"></path><path d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06l1.97 1.969Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="n" data-component="Tooltip" aria-hidden="true" id="_R_eaucpala9lik5_">Download raw file</span></div></div></div><button data-component="IconButton" type="button" aria-pressed="false" class="prc-Button-ButtonBase-9n-Xk tmp-mr-2 TableOfContents-module__IconButton__jrlNM prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_3ucpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-list-unordered" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5.75 2.5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5ZM2 14a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-6a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM2 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="n" data-component="Tooltip" aria-hidden="true" id="_R_3ucpala9lik5_">Outline</span><div class="react-blob-header-edit-and-raw-actions-combined"><button data-component="IconButton" type="button" title="More file actions" data-testid="more-file-actions-button" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk js-blob-dropdown-click BlobViewHeader-module__IconButton__XrMQY prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_fkecpala9lik5_" id="_R_kecpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-hidden="true" id="_R_fkecpala9lik5_">Edit and raw actions</span></div></div></div></div><div></div></div><div class="BlobViewContent-module__blobContentWrapper__JS0W6"><section aria-labelledby="file-name-id-wide file-name-id-mobile" class="BlobContent-module__blobContentSection__VOgZq BlobContent-module__blobContentSectionMarkdown__mPLOK" style="margin-top:46px"><div class="js-snippet-clipboard-copy-unpositioned BlobContent-module__markdownBlob__T8jpG" data-hpc="true" containertiming="hpc"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">FreeCut Web</h1><a id="user-content-freecut-web" class="anchor" aria-label="Permalink: FreeCut Web" href="#freecut-web"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Commands</h2><a id="user-content-commands" class="anchor" aria-label="Permalink: Commands" href="#commands"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="npm run dev          # Vite dev server on port 5173
npm run build        # Production build
npm run lint         # Oxlint
npm run format       # Oxfmt
npm run format:check # Check formatting with Oxfmt
npm run test         # Vitest (watch mode)
npm run test:run     # Vitest (single run)
npm run routes       # Regenerate TanStack Router tree (tsr generate)"><pre>npm run dev          <span class="pl-c"><span class="pl-c">#</span> Vite dev server on port 5173</span>
npm run build        <span class="pl-c"><span class="pl-c">#</span> Production build</span>
npm run lint         <span class="pl-c"><span class="pl-c">#</span> Oxlint</span>
npm run format       <span class="pl-c"><span class="pl-c">#</span> Oxfmt</span>
npm run format:check <span class="pl-c"><span class="pl-c">#</span> Check formatting with Oxfmt</span>
npm run <span class="pl-c1">test</span>         <span class="pl-c"><span class="pl-c">#</span> Vitest (watch mode)</span>
npm run test:run     <span class="pl-c"><span class="pl-c">#</span> Vitest (single run)</span>
npm run routes       <span class="pl-c"><span class="pl-c">#</span> Regenerate TanStack Router tree (tsr generate)</span></pre></div>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Architecture</h2><a id="user-content-architecture" class="anchor" aria-label="Permalink: Architecture" href="#architecture"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">Browser-based multi-track video editor. React 19 + TypeScript + Vite.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="src/
├── features/              # User-facing UI modules
│   ├── editor/            # Editor shell, toolbar, panels, stores
│   ├── timeline/          # Multi-track timeline, actions, services
│   ├── preview/           # Preview canvas, transform gizmo, scrub renderer
│   ├── export/            # WebCodecs export pipeline (Web Worker)
│   ├── effects/           # GPU effect UI panels and registry
│   ├── keyframes/         # Keyframe animation, Bezier editor, easing
│   ├── media-library/     # Media import, metadata, OPFS proxies, transcription
│   ├── project-bundle/    # Project ZIP export/import
│   ├── projects/          # Project management
│   ├── scene-browser/     # Caption and scene search UI
│   ├── settings/          # App settings
│   └── workspace-gate/    # Workspace picker / permission gate
├── runtime/               # Playback and rendering engines (not user-facing UI features)
│   ├── composition-runtime/ # Composition rendering (sequences, items, audio, transitions)
│   └── player/            # Clock, video source pools, composition playback
├── infrastructure/        # Platform adapters — browser, storage, GPU, ML, audio
│   ├── gpu-effects/       # WebGPU effect pipeline + shader definitions
│   ├── gpu-transitions/   # WebGPU transition pipeline + shaders
│   ├── gpu-compositor/    # WebGPU blend-mode compositor
│   ├── gpu-masks/         # Mask combine pipeline + texture manager
│   ├── gpu-media/         # Media render/blend pipelines
│   ├── gpu-scopes/        # Waveform/vectorscope/histogram renderers
│   ├── gpu-shapes/        # Shape render pipeline
│   ├── gpu-text/          # Glyph-atlas text pipeline
│   ├── gpu-shared/        # WGSL fragments shared across GPU modules
│   ├── analysis/          # Scene detection, captioning, embeddings, optical flow
│   ├── audio/             # SoundTouch-based time-stretch
│   ├── browser/           # Blob URLs, OPFS, mediabunny adapter
│   ├── storage/           # Workspace FS persistence + legacy IDB migration
│   └── thumbnails/        # GPU thumbnail renderer + sampling strategy
├── shared/                # Framework-agnostic primitives + cross-feature state
│   ├── timeline/          # Transition engine/registry/renderers, defaults
│   ├── projects/          # Schema migrations and normalization
│   ├── state/             # Zustand stores (playback, selection, dialogs, editor)
│   ├── marquee/           # Marquee-selection hook + overlay (paired unit)
│   ├── logging/           # Structured logger, frame jitter monitor
│   ├── ui/                # cn helper, property controls
│   ├── typography/        # Font loading, text style presets
│   ├── graphics/          # Shape generators and path helpers
│   └── utils/             # Managed workers, color/curve math, easing, async, etc.
├── components/            # shadcn/ui components + brand assets
├── app/                   # App bootstrap, error boundary, PWA prompt, debug
├── config/                # Hotkeys + editor layout config
├── i18n/                  # i18next setup, supported languages, locale JSON + per-feature partials
├── routes/                # TanStack Router (file-based, auto-generated routeTree)
└── types/                 # Shared TypeScript types"><pre lang="text" class="notranslate"><code>src/
├── features/              # User-facing UI modules
│   ├── editor/            # Editor shell, toolbar, panels, stores
│   ├── timeline/          # Multi-track timeline, actions, services
│   ├── preview/           # Preview canvas, transform gizmo, scrub renderer
│   ├── export/            # WebCodecs export pipeline (Web Worker)
│   ├── effects/           # GPU effect UI panels and registry
│   ├── keyframes/         # Keyframe animation, Bezier editor, easing
│   ├── media-library/     # Media import, metadata, OPFS proxies, transcription
│   ├── project-bundle/    # Project ZIP export/import
│   ├── projects/          # Project management
│   ├── scene-browser/     # Caption and scene search UI
│   ├── settings/          # App settings
│   └── workspace-gate/    # Workspace picker / permission gate
├── runtime/               # Playback and rendering engines (not user-facing UI features)
│   ├── composition-runtime/ # Composition rendering (sequences, items, audio, transitions)
│   └── player/            # Clock, video source pools, composition playback
├── infrastructure/        # Platform adapters — browser, storage, GPU, ML, audio
│   ├── gpu-effects/       # WebGPU effect pipeline + shader definitions
│   ├── gpu-transitions/   # WebGPU transition pipeline + shaders
│   ├── gpu-compositor/    # WebGPU blend-mode compositor
│   ├── gpu-masks/         # Mask combine pipeline + texture manager
│   ├── gpu-media/         # Media render/blend pipelines
│   ├── gpu-scopes/        # Waveform/vectorscope/histogram renderers
│   ├── gpu-shapes/        # Shape render pipeline
│   ├── gpu-text/          # Glyph-atlas text pipeline
│   ├── gpu-shared/        # WGSL fragments shared across GPU modules
│   ├── analysis/          # Scene detection, captioning, embeddings, optical flow
│   ├── audio/             # SoundTouch-based time-stretch
│   ├── browser/           # Blob URLs, OPFS, mediabunny adapter
│   ├── storage/           # Workspace FS persistence + legacy IDB migration
│   └── thumbnails/        # GPU thumbnail renderer + sampling strategy
├── shared/                # Framework-agnostic primitives + cross-feature state
│   ├── timeline/          # Transition engine/registry/renderers, defaults
│   ├── projects/          # Schema migrations and normalization
│   ├── state/             # Zustand stores (playback, selection, dialogs, editor)
│   ├── marquee/           # Marquee-selection hook + overlay (paired unit)
│   ├── logging/           # Structured logger, frame jitter monitor
│   ├── ui/                # cn helper, property controls
│   ├── typography/        # Font loading, text style presets
│   ├── graphics/          # Shape generators and path helpers
│   └── utils/             # Managed workers, color/curve math, easing, async, etc.
├── components/            # shadcn/ui components + brand assets
├── app/                   # App bootstrap, error boundary, PWA prompt, debug
├── config/                # Hotkeys + editor layout config
├── i18n/                  # i18next setup, supported languages, locale JSON + per-feature partials
├── routes/                # TanStack Router (file-based, auto-generated routeTree)
└── types/                 # Shared TypeScript types
</code></pre></div>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Key Patterns</h2><a id="user-content-key-patterns" class="anchor" aria-label="Permalink: Key Patterns" href="#key-patterns"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul dir="auto">
<li><strong>State</strong>: Zustand stores + Zundo for undo/redo</li>
<li><strong>Timeline store split</strong>: <code>useTimelineStore</code> (from <code>timeline-store.ts</code>) is a <strong>facade</strong> over domain stores (<code>items-store</code>, <code>transitions-store</code>, <code>keyframes-store</code>, <code>markers-store</code>, <code>timeline-settings-store</code>, <code>timeline-command-store</code>). Components use the facade with selectors; action code accesses domain stores via <code>.getState()</code> directly</li>
<li><strong>Timeline mutations</strong>: Action modules in <code>features/timeline/stores/actions/*.ts</code> use <code>execute()</code> wrapper from <code>shared.ts</code> for undo/redo integration. Never mutate timeline stores directly — use these actions</li>
<li><strong>TimelineItem composition</strong>: The per-clip component in <code>features/timeline/components/timeline-item/index.tsx</code> delegates to dedicated hooks: <code>useCaptionDialogState</code>, <code>useFadeEditors</code>, <code>useFadeMath</code>, <code>useEditPreviewShifts</code>, <code>useTimelineItemBounds</code>, <code>useSmartTrimHover</code>, <code>useContextMenuState</code>, plus the existing <code>useTimelineItemActions</code> / <code>useTimelineItemDropHandlers</code> / <code>useDragVisualState</code>. The host file orchestrates these hooks and renders the JSX; sub-components live alongside (<code>EdgeHalos</code>, <code>TransitionDropGhost</code>, <code>TranscribeDialogController</code>, etc.). When adding new clip state, prefer a new hook over inlining</li>
<li><strong>Timeline item types</strong>: <code>TimelineItem</code> is a discriminated union on <code>type</code>: <code>video | audio | text | image | shape | adjustment | composition</code> — GIFs use <code>image</code> type, no separate gif type. Types in <code>src/types/timeline.ts</code></li>
<li><strong>Item positioning</strong>: Remotion convention — <code>from</code> (start frame in project FPS) + <code>durationInFrames</code></li>
<li><strong>Compositions</strong>: Pre-compositions (sub-comps) have dedicated stores (<code>compositions-store.ts</code>, <code>composition-navigation-store.ts</code>). 1-level nesting only. Actions in <code>composition-actions.ts</code></li>
<li><strong>Migrations</strong>: <code>src/shared/projects/migrations/</code> — versioned migrations + normalization run on every project load. Increment <code>CURRENT_SCHEMA_VERSION</code> in <code>types.ts</code> when adding new migrations</li>
<li><strong>Routing</strong>: TanStack Router — run <code>npm run routes</code> after adding/changing route files</li>
<li><strong>Path alias</strong>: <code>@/*</code> → <code>src/*</code></li>
<li><strong>i18n</strong>: i18next + react-i18next, initialized in <code>src/i18n/index.ts</code> (imported once from <code>main.tsx</code>). 9 languages (<code>en</code>, <code>es</code>, <code>fr</code>, <code>de</code>, <code>pt-BR</code>, <code>tr</code>, <code>ja</code>, <code>ko</code>, <code>zh</code>) in <code>src/i18n/languages.ts</code>. Base strings in <code>src/i18n/locales/&lt;lang&gt;.json</code>; per-feature strings live in <code>src/i18n/locales/partials/&lt;lang&gt;/&lt;name&gt;.json</code> (file contains the slice directly with no language wrapper key). <code>en</code> partials are eagerly bundled into <code>app-shell</code>; all other languages load on demand via <code>loadLanguageResources(lang)</code> / <code>changeAppLanguage(lang)</code> from <code>@/i18n</code>. The user's persisted language is preloaded before first render via the exported <code>i18nReady</code> promise. In components use <code>const { t } = useTranslation()</code>; outside React use <code>import { i18n } from '@/i18n'</code> then <code>i18n.t()</code> (<code>@/i18n</code> is allowed by the boundary checks — it's not <code>@/features/*</code>). For strings with inline markup use <code>&lt;Trans i18nKey=... components={{ strong: &lt;strong/&gt; }} /&gt;</code>. Resources are deliberately untyped (<code>i18next.d.ts</code>) so <code>t()</code> accepts any key. Language selector lives in the editor Settings dialog (General); persisted to <code>localStorage</code> key <code>freecut-language</code> by the language detector. When adding new partials, translate all 9 languages and keep identical key structure across all language dirs; never put a bare ASCII <code>"</code> inside a JSON string value.</li>
<li><strong>Styling</strong>: Tailwind CSS 4 + shadcn/ui (Radix primitives)</li>
<li><strong>Media processing</strong>: Mediabunny for decode, WebCodecs for export, Web Workers for heavy ops</li>
<li><strong>Storage</strong>: Workspace folder via File System Access API (see <code>infrastructure/storage/workspace-fs/</code>). Source of truth is a user-picked directory on disk — projects, media metadata, thumbnails, waveforms, gif frames, decoded audio, transcripts all live as plain files. <code>WorkspaceGate</code> (<code>src/features/workspace-gate/</code>) blocks app render until a workspace is granted. IndexedDB is only used for a tiny handle registry (<code>freecut-handles-db</code> v1, at <code>infrastructure/storage/handles-db.ts</code>) that stores non-serializable <code>FileSystem*Handle</code> references. Legacy <code>video-editor-db</code> is read only by the one-time migration path under <code>infrastructure/storage/legacy-idb/</code> (reader.ts + migrate.ts); consumers import from the barrel <code>@/infrastructure/storage</code> which routes everything to workspace-fs</li>
</ul>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Code Style</h2><a id="user-content-code-style" class="anchor" aria-label="Permalink: Code Style" href="#code-style"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul dir="auto">
<li>Strict TypeScript (<code>noUnusedLocals</code>, <code>noUnusedParameters</code>, <code>noUncheckedIndexedAccess</code>)</li>
<li><code>no-console</code> rule — always use <code>createLogger</code> from <code>src/shared/logging/logger.ts</code>, never raw <code>console.*</code> calls</li>
<li><strong>Logging</strong>: Use wide event pattern for multi-step operations (export, import, save): <code>log.startEvent(name, opId)</code> accumulates context, emits one structured event via <code>.success()</code> / <code>.failure()</code>. Use <code>createOperationId()</code> for correlation. Include business context (project ID, item counts, codec, resolution) in events</li>
<li><code>typescript/no-explicit-any</code> warned by Oxlint</li>
</ul>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Testing</h2><a id="user-content-testing" class="anchor" aria-label="Permalink: Testing" href="#testing"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul dir="auto">
<li>Vitest + jsdom + @testing-library/react</li>
<li><code>src/test/setup.ts</code> mocks ImageData, WebGPU APIs (<code>navigator.gpu</code>), and GPU constants</li>
<li>Tests live next to source files: <code>*.test.ts</code> / <code>*.test.tsx</code></li>
<li><strong>Pure-logic tests opt out of jsdom.</strong> <code>vite.config.ts</code> defaults to <code>environment: 'jsdom'</code>, but a test that never touches <code>document</code> / <code>window</code> / <code>navigator</code> / testing-library should start with <code>// @vitest-environment node</code> on line 1 (blank line after). Building a jsdom per file is ~30% of the suite's wall clock; 280 files already do this. Keep the jsdom default — a file wrongly marked <code>node</code> fails loudly with <code>document is not defined</code>, whereas flipping the default would silently break any file someone forgot to annotate. Leave a file on jsdom if it merely <em>mentions</em> <code>window</code>/<code>navigator</code>: a <code>typeof window !== 'undefined'</code> branch would take the non-browser path with every assertion still green</li>
<li><strong>Only write tests that exercise real logic.</strong> A test must be able to fail for a reason other than someone editing a constant or a string. Do NOT add tests that: re-assert a static config/registry/preset constant back to itself (config snapshots); assert <code>typeof x === 'function'</code> or <code>has correct initial state</code> on a store; only verify a mocked function was called / returned its mock value (the real code is stubbed, so nothing real is covered); render a component and assert a passed-in prop/className/style string appears with no branching behind it; exercise library/framework behavior (Radix, jsdom events, controlled inputs). When the only collaborators are mocked, test against the real in-memory fake (e.g. workspace-fs round-trips) instead. Worth testing: algorithm/math (FPS/timeline conversions, transitions, interpolation, color/curve math), reducer/state-machine transitions, schema migrations, edge/boundary cases, and named regressions. If unsure whether a test adds value, prefer no test over a low-value one</li>
</ul>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Environment</h2><a id="user-content-environment" class="anchor" aria-label="Permalink: Environment" href="#environment"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul dir="auto">
<li><code>VITE_SHOW_DEBUG_PANEL=false</code> — set to hide debug panel in dev mode (shown by default)</li>
</ul>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Toolchain &amp; dependency notes</h2><a id="user-content-toolchain--dependency-notes" class="anchor" aria-label="Permalink: Toolchain &amp; dependency notes" href="#toolchain--dependency-notes"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul dir="auto">
<li>The entire dev/build/test/lint/format stack runs through <strong>vite-plus</strong> (<code>vp</code>, currently 0.x / pre-1.0) — it wraps Vite, Vitest, Oxlint, Oxfmt and the task runner. There is no plain-Vite fallback configured; if <code>vp</code> breaks, pin the last working version in package.json rather than attempting an ad-hoc migration</li>
<li><code>onnxruntime-web</code> is intentionally pinned to a <strong>dev build</strong> (<code>1.26.0-dev.*</code>) — introduced with the supertonic TTS integration. Don't "upgrade" it casually; moving to a stable release requires re-validating transcription, TTS and scene detection</li>
<li><code>lucide-react</code> is held at 0.468.x deliberately (Vite pre-bundles it; see Gotchas about <code>optimizeDeps</code>). A major-version bump is a deliberate task, not a routine dep update</li>
<li>All production deps are exact-pinned; keep new deps exact-pinned too (no <code>^</code>/<code>~</code>)</li>
<li><strong>TypeScript 7 needs the <code>overrides.typescript</code> entry.</strong> <code>i18next</code> and <code>react-i18next</code> declare <code>peerOptional typescript@"^5"</code>, so any TS &gt;= 6 fails a clean <code>npm install</code>/<code>npm ci</code> with ERESOLVE (an <em>incremental</em> install over an existing tree misleadingly succeeds). The override in package.json forces one TS copy and must be bumped in lockstep with the <code>typescript</code> devDependency. <code>@voidzero-dev/vite-plus-core</code> also peers <code>^5 || ^6</code>, but never loads the package — it shells out to the tsgolint binary — so that one is inert</li>
<li>Type checking does <strong>not</strong> run <code>tsc</code>. <code>vp check</code> type-checks via <strong>tsgolint</strong> (the TypeScript-Go engine), which is why CI already had native-speed checking before the TS 7 bump. Nothing in <code>package.json</code> scripts or CI invokes <code>tsc</code>; the <code>typescript</code> devDependency exists for editor tsserver and ad-hoc <code>npx tsc</code>. TS 7.0 ships no stable programmatic API — if a tool ever needs one, alias <code>@typescript/typescript6</code></li>
<li><strong>The fallow allowlists are baselines, not approvals.</strong> <code>check:unused-exports</code> and <code>check:unused-class-members</code> are ratchets: they fail only on findings <em>new</em> since the baseline, plus stale entries. Every entry carries a <code>reason</code>, and re-baselined ones are tagged — <code>parked-ai-feature</code> (the unwired assistant, see <code>ai-tab.tsx</code>), <code>deps-contract</code> (adapter surface the boundary rules require), <code>barrel-surface</code> (feature <code>index.ts</code> public API), <code>unreviewed</code> (never traced; start here when cleaning up). Never bulk-<code>fallow fix</code> these — trace per export. Re-baseline by regenerating both files from <code>fallow dead-code --format json</code>, preserving existing reasons; a stale baseline makes the gate fail permanently and get ignored</li>
<li><code>oxlint</code> / <code>oxfmt</code> / <code>@oxc-project/types</code> are <strong>not</strong> direct deps — vite-plus exact-pins them internally, so they only move when <code>vp</code> moves. A <code>vp</code> bump can therefore reformat the tree (0.2.4 brought oxfmt 0.57 and reflowed 52 files); land that churn as its own commit</li>
</ul>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Git</h2><a id="user-content-git" class="anchor" aria-label="Permalink: Git" href="#git"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul dir="auto">
<li><code>main</code> — production, <code>staging</code> — pre-release integration, <code>develop</code> — active development</li>
<li>PR target: <code>staging</code> (feature branches and <code>develop</code> PR into <code>staging</code>; <code>staging</code> is promoted to <code>main</code> for release). Do <strong>not</strong> open PRs against <code>main</code> directly</li>
<li>Commit messages: conventional commits — <code>type(scope): description</code> (e.g. <code>fix(timeline):</code>, <code>feat(export):</code>)</li>
</ul>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Gotchas</h2><a id="user-content-gotchas" class="anchor" aria-label="Permalink: Gotchas" href="#gotchas"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul dir="auto">
<li>Track groups are 1-level only (no nested groups). Gate behavior (mute/visible/locked) propagates from group to children via <code>resolveEffectiveTrackStates()</code> in <code>group-utils.ts</code></li>
<li>Browser shortcut conflicts (e.g. Ctrl+E) need <code>eventListenerOptions: { capture: true }</code> on the hotkey to override Chrome's default behavior</li>
<li>Feature modules use <code>index.ts</code> barrel files to define public API surface — follow this convention when adding new features</li>
<li><code>routeTree.gen.ts</code> is auto-generated — don't edit manually</li>
<li><code>*.mp4</code> files are gitignored</li>
<li>Vite pre-bundles <code>lucide-react</code> to avoid analyzing 1500+ icons — don't remove from <code>optimizeDeps</code></li>
<li>WebGPU tests need mocks from <code>src/test/setup.ts</code> — tests will fail without jsdom environment</li>
<li>Build uses manual chunk splitting — check <code>vite.config.ts</code> when adding large dependencies</li>
<li><code>HOTKEY_OPTIONS</code> has <code>preventDefault: true</code> — the library consumes keys before the callback. For panel-scoped shortcuts, use <code>onKeyDown</code> on the element with <code>tabIndex={-1}</code> + focus-on-hover + <code>stopPropagation()</code>, not global <code>useHotkeys</code> with guards</li>
<li><code>sourceStart</code>/<code>sourceEnd</code>/<code>sourceDuration</code> on timeline items are in <strong>source-native FPS</strong> frames, not project FPS. Use media's <code>fps</code> from media library store when converting to seconds</li>
<li>Track <code>order</code> convention: lower value = visually higher (top of timeline). New tracks go at <code>minOrder - 1</code>. When creating pre-comps, place the comp item on the bottom-most (highest order) selected track; dissolve expands upward</li>
<li>Group tracks (<code>isGroup: true</code>) are headers only — never place items on them. Filter them out when searching for candidate tracks</li>
<li>Inline edit cancel (Escape) triggers blur on unmount — use a ref guard to prevent <code>onBlur</code> from committing the cancelled value</li>
<li><code>_splitItem()</code> returns <code>{ leftItem, rightItem } | null</code> — capture the return for correct IDs; the original item ID is stale after split</li>
<li>Timeline has its own <code>keydown</code> listener in <code>timeline.tsx</code> — new keyboard handlers on child panels must <code>stopPropagation()</code> and timeline checks <code>e.defaultPrevented</code></li>
<li><strong>Effects are GPU-only</strong> — all visual effects use WebGPU shaders (<code>type: 'gpu-effect'</code>). Legacy CSS filter, glitch, halftone, vignette, LUT types were removed in v6 migration. Effect definitions in <code>src/infrastructure/gpu-effects/effects/</code>, pipeline in <code>effects-pipeline.ts</code>. Specialized UI panels exist for <code>gpu-curves</code> and <code>gpu-color-wheels</code>; all others use the generic <code>GpuEffectPanel</code></li>
<li><strong>Transitions are GPU-only</strong> — all 13 transitions (fade, wipe, slide, flip, clockWipe, iris, dissolve, sparkles, glitch, lightLeak, pixelate, chromatic, radialBlur) render via WebGPU shaders in <code>infrastructure/gpu-transitions/</code>. Each renderer in <code>shared/timeline/transitions/renderers/</code> has <code>gpuTransitionId</code> linking to its shader, plus a <code>renderCanvas()</code> Canvas 2D fallback for non-WebGPU environments. <code>calculateStyles()</code> is dead code (CSS/DOM transition rendering was removed). Canvas <code>drawImage</code> offsets must use <code>Math.round()</code> to avoid sub-pixel interpolation artifacts</li>
<li>After clip edits that change position/duration, call <code>applyTransitionRepairs(changedClipIds)</code> from <code>shared.ts</code> — transitions auto-heal or report breakages</li>
<li><code>shared/logging/logger.ts</code> uses only <code>function</code> declarations (no <code>class</code>/<code>const</code> at module scope) to avoid temporal dead zone errors in production chunk ordering — maintain this pattern</li>
<li>Fast scrub render loop: prewarm frames use WASM decode (40-80ms) and block the loop from processing priority frames. During playback, skip prewarm entirely (<code>isPlaying</code> check) — priority frames render fast via DOM video zero-copy (~1ms) and the loop must stay responsive. Background worker preseek (<code>backgroundPreseek</code> in <code>decoder-prewarm.ts</code>) also fires on large timeline jumps (&gt;3s) for all visible clips — the worker decodes off-thread and the render engine picks up the cached bitmap</li>
<li><strong>Render loop concurrency</strong> — <code>pumpRenderLoop</code> uses a single-mutex (<code>scrubRenderInFlightRef</code>) to prevent concurrent pump iterations during scrubbing. A <code>scrubRenderGenerationRef</code> counter is bumped ONLY on playback-start force-clear (not during scrub). The <code>finally</code> block releases the lock and triggers follow-up work only when the generation matches; stale pumps (from a superseded playback-start) leave the lock for the new owner. Never bump generation or force-clear the lock on sequential scrub frames — this causes unbounded concurrent pumps. The <code>data-transition-hold</code> attribute on DOM video elements coordinates with <code>video-content.tsx</code> premount logic and <code>clearTransitionPlaybackSession</code> cleanup</li>
<li><strong>Transition participant video hold</strong> — during transitions, the incoming clip's DOM video element is paused by <code>video-content.tsx</code> premount logic. The transition provider marks it with <code>data-transition-hold="1"</code> and calls <code>.play()</code> so the canvas renderer gets advancing frames. The mark is removed in <code>clearTransitionPlaybackSession</code>. Without this, the incoming clip shows a frozen frame during the transition</li>
<li>When updating multiple GPU effect params atomically (e.g. color wheel hue + amount), use <code>onParamsBatchChange</code>/<code>onParamsBatchLiveChange</code> — calling <code>onParamChange</code> twice reads stale state on the second call and overwrites the first</li>
<li><strong>Reuse rendered frames</strong> — the preview scrub renderer already has fully composited frames with effects/masks/blend modes. Features needing the current frame (thumbnails, scopes, snapshots) should use <code>usePreviewBridgeStore.getState().captureCanvasSource()</code> first, falling back to <code>renderSingleFrame()</code> only when the preview is unavailable. Never spin up a new render pipeline when an existing one already has the frame</li>
<li><strong>Progressive downscaling</strong> — when scaling high-res canvases to small sizes (e.g. 1920→320 thumbnails), halve dimensions repeatedly instead of one large jump. Single-step downscaling causes moire/aliasing with high-frequency GPU effects (halftone, pixelate, etc.)</li>
<li><code>StableVideoSequence</code>'s <code>areGroupPropsEqual</code> (defined in <code>stable-video-sequence-comparator.ts</code>, consumed by <code>stable-video-sequence.tsx</code>) whitelists item properties for React.memo comparison. When adding new visual properties to <code>TimelineItem</code>, add them to this comparison — missing properties cause stale renders during playback</li>
<li><strong>GPU pipeline caching</strong> — <code>EffectsPipeline.requestCachedDevice()</code> caches the WebGPU adapter + device globally. Subsequent <code>EffectsPipeline.create()</code> calls reuse the device (~50-100ms saved). The device-loss handler checks identity before clearing to avoid discarding a freshly acquired device. The preview component eagerly warms the GPU pipeline on mount (parallel with media resolution)</li>
<li><strong><code>__DEBUG__</code> API</strong> — <code>window.__DEBUG__</code> (DEV-only, tree-shaken in prod) provides console debugging: <code>stores()</code>, <code>getTransitions()</code>, <code>getTransitionWindows()</code>, <code>getPlaybackState()</code>, <code>getTracks()</code>, <code>getMediaLibrary()</code>, <code>jitter()</code> (frame timing), <code>previewPerf()</code>, <code>transitionTrace()</code>, <code>prewarmCache()</code>, <code>filmstripMetrics()</code>, <code>perfSummary(prefix?)</code> / <code>perfClear()</code> (User Timing aggregation, default prefix <code>tl.</code>), plus playback control (<code>seekTo</code>, <code>play</code>, <code>pause</code>). All use lazy <code>await import()</code> to avoid pulling in stores eagerly</li>
<li><strong>Timeline perf-marks</strong> — <code>withPerfMeasure(name, fn)</code> in <code>src/shared/logging/perf-marks.ts</code> wraps hot paths so they appear as named entries on the User Timing track in Chrome DevTools Performance. Currently instruments <code>tl.action.*</code> (every timeline mutation, via <code>actions/shared.ts::execute</code>), <code>tl.repairTransitions</code>, and the RAF loops <code>tl.raf.{viewportSync,previewHover,zoomApply,scrollThumb,momentum,playheadScrub}</code>. <code>withPerfMeasure</code> is opt-in — gated on <code>window.__TL_PERF__ = true</code> (off by default, zero overhead) so the User Timing buffer doesn't grow unbounded in normal use; set the flag before profiling (<code>npm run perf</code>), then read marks via the Performance tab or <code>__DEBUG__.perfSummary()</code>. <code>perfMarkRender(name)</code> adds per-render <code>tl.render.*</code> marks to the high-fanout components (ClipContent, TimelineItem, TimelineTrack, TimelineContent, TimelineMarkers, TimelinePlayhead, TransitionItem) — gated on <code>window.__TL_RENDER_MARKS__ = true</code> (off by default, zero overhead) for diagnosing which components re-render during a gesture</li>
<li><strong>Clip content tracks SETTLED zoom</strong> — <code>ClipContent</code> (<code>timeline-item/clip-content.tsx</code>) drives filmstrip/waveform width from <code>contentPixelsPerSecond</code> (settled, updates ~100ms after a zoom gesture ends), NOT the live per-frame <code>pixelsPerSecond</code>. The clip shell resizes smoothly during the gesture via the <code>--timeline-px-per-frame</code> CSS variable (no React); the filmstrip tile grid would otherwise rebuild on every wheel/momentum frame (~73% of zoom cost). During the gesture the content is briefly at pre-zoom scale, hidden by the repeating cover-frame background (zoom-in) or <code>overflow:hidden</code> clipping (zoom-out), snapping sharp on settle. The <code>preferImmediateRendering</code> prop opts back into live pps for active edit previews (trim/slide) where settle lag would distract</li>
<li><strong>Clip content defers mount during zoom</strong> — <code>ClipContent</code> also reads <code>isZoomInteracting</code> <strong>once at mount</strong> via <code>getState()</code> (not a reactive subscription) into <code>deferVisual</code> state. A clip that first mounts mid-gesture (e.g. entering the viewport while zooming out) renders only its colored shell — no filmstrip/waveform — until the zoom settles, then a one-shot <code>useZoomStore.subscribe</code> flips it on. This was ~90% of zoom-OUT cost: zooming out brings many clips into view at once and mounting each one's tile grid + canvas draws stalled the gesture (226ms/frame → ~42ms/frame). Reading at mount (not subscribing) is critical — already-mounted clips must NOT re-render when <code>isZoomInteracting</code> flips, or they'd flash empty</li>
<li><strong>Transition prearm covers all types</strong> — the <code>forceFastScrubOverlay</code> subscription uses <code>getPlayingAnyTransitionPrewarmStartFrame</code> (not complex-only) so all transitions get their session pinned and DOM video elements playing before entry. Also checks <code>getTransitionWindowForFrame</code> for playback starting inside an active transition</li>
<li><strong>Feature boundary rules</strong> — cross-feature imports must go through <code>deps/</code> adapter modules. The pre-push hook enforces this via <code>check:boundaries</code>. (A <code>check:legacy-lib-imports</code> tripwire also catches any reintroduction of <code>@/lib/*</code> imports — the <code>src/lib/</code> layer was removed and merged into <code>infrastructure/</code>.)</li>
<li><strong>GPU effect data textures</strong>: effects that need LUT-like auxiliary data declare <code>dataTexture</code> in their <code>GpuEffectDefinition</code>. The pipeline binds it at <code>@group(0) @binding(3)</code>, caches the texture per pass, rewrites same-size contents with <code>queue.writeTexture</code>, and invalidates bind groups only when dimensions change. <code>gpu-curves</code> uses this for the 256x1 curve LUT; <code>gpu-lut</code> embeds resampled <code>.cube</code> data in effect params so project bundles and export workers need no side channel.</li>
<li><strong>Implicit color grade controls</strong>: the Color workspace renders wheels and curves even before those effects exist. <code>ColorGradeSection</code> previews synthetic grade entries through the gizmo effects-preview path during live drags, then lazily creates the real GPU effect on commit. Do not persist synthetic <code>__grade:*</code> ids or attach keyframes to them.</li>
<li><strong>Interface sounds</strong>: synthesized (no audio assets) via a dedicated <code>AudioContext</code> in <code>infrastructure/audio/ui-sound/</code> (<code>synth.ts</code> data-only <code>Recipe</code> → <code>renderRecipe</code>; <code>voices.ts</code> maps semantic <code>SoundToken</code>s → recipes per swappable <strong>voice</strong>; <code>engine.ts</code> owns the lazy context + per-token rate limit). To add feedback anywhere call <code>emitUiSound('&lt;token&gt;')</code> from <code>@/shared/ui/ui-sound</code> at the <strong>action chokepoint</strong> (the store action / toggle callback, not each call site) — emit <em>intent</em> (<code>select</code>/<code>confirm</code>/<code>delete</code>/<code>toggleOn</code>…), never a specific sound. It's gated: opt-in + volume-scaled via <code>useUiSoundStore</code> (<code>shared/state/ui-sound-store.ts</code>, persisted <code>freecut-ui-sound</code>, <strong>off by default</strong>), rate-limited, and <strong>suppressed while <code>usePlaybackStore.isPlaying</code></strong> so chirps never pollute monitored audio (exports are silent by construction — the export worker never imports the module). New voices: add to <code>VOICES</code>/<code>VOICE_OPTIONS</code> + <code>VoiceName</code> and the picker (Settings → General) updates automatically. <code>previewUiSound(voice, token)</code> auditions a specific voice without committing it. <code>hover</code> is defined but intentionally unwired (too noisy for blanket use).</li>
</ul>
</article></div><div class="d-none"></div></section></div></div></div> </div> <!-- --> </div></div></div></div></div></div><div class="ScrollMarksContainer-module__scrollMarksContainer__Eu7uU" id="find-result-marks-container"></div><div class="d-none"></div><div class="d-none"></div></div> <!-- --> <!-- --> </div>
</react-app>




  </div>

</turbo-frame>

    </main>
  </div>

  </div>

          <footer class="footer f6 color-fg-muted color-border-subtle tmp-pt-7 tmp-pb-6 p-responsive" role="contentinfo"  >
  <h2 class='sr-only'>Footer</h2>

  


  <div class="d-flex flex-justify-center flex-items-center flex-column-reverse flex-lg-row flex-wrap flex-lg-nowrap">
    <div class="d-flex flex-items-center flex-shrink-0 mx-2">
      <a aria-label="GitHub Homepage" class="footer-octicon mr-2" href="https://github.com">
        <svg aria-hidden="true" data-component="Octicon" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-mark-github">
    <path d="M10.226 17.284c-2.965-.36-5.054-2.493-5.054-5.256 0-1.123.404-2.336 1.078-3.144-.292-.741-.247-2.314.09-2.965.898-.112 2.111.36 2.83 1.01.853-.269 1.752-.404 2.853-.404 1.1 0 1.999.135 2.807.382.696-.629 1.932-1.1 2.83-.988.315.606.36 2.179.067 2.942.72.854 1.101 2 1.101 3.167 0 2.763-2.089 4.852-5.098 5.234.763.494 1.28 1.572 1.28 2.807v2.336c0 .674.561 1.056 1.235.786 4.066-1.55 7.255-5.615 7.255-10.646C23.5 6.188 18.334 1 11.978 1 5.62 1 .5 6.188.5 12.545c0 4.986 3.167 9.12 7.435 10.669.606.225 1.19-.18 1.19-.786V20.63a2.9 2.9 0 0 1-1.078.224c-1.483 0-2.359-.808-2.987-2.313-.247-.607-.517-.966-1.034-1.033-.27-.023-.359-.135-.359-.27 0-.27.45-.471.898-.471.652 0 1.213.404 1.797 1.235.45.651.921.943 1.483.943.561 0 .92-.202 1.437-.719.382-.381.674-.718.944-.943"></path>
</svg>
</a>
      <span>
        &copy; 2026 GitHub,&nbsp;Inc.
      </span>
    </div>

    <nav aria-label="Footer">
      <h3 class="sr-only" id="sr-footer-heading">Footer navigation</h3>

      <ul class="list-style-none d-flex flex-justify-center flex-wrap mb-2 mb-lg-0" aria-labelledby="sr-footer-heading">


          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to Terms&quot;,&quot;label&quot;:&quot;text:terms&quot;}" href="https://docs.github.com/site-policy/github-terms/github-terms-of-service" data-view-component="true" class="Link--secondary Link">Terms</a>
          </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to privacy&quot;,&quot;label&quot;:&quot;text:privacy&quot;}" href="https://docs.github.com/site-policy/privacy-policies/github-privacy-statement" data-view-component="true" class="Link--secondary Link">Privacy</a>
          </li>


            <li class="mx-2">
              <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to security&quot;,&quot;label&quot;:&quot;text:security&quot;}" href="https://github.com/security" data-view-component="true" class="Link--secondary Link">Security</a>
            </li>

            <li class="mx-2">
              <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to status&quot;,&quot;label&quot;:&quot;text:status&quot;}" href="https://www.githubstatus.com/" data-view-component="true" class="Link--secondary Link">Status</a>
            </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to community&quot;,&quot;label&quot;:&quot;text:community&quot;}" href="https://github.community/" data-view-component="true" class="Link--secondary Link">Community</a>
          </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to docs&quot;,&quot;label&quot;:&quot;text:docs&quot;}" href="https://docs.github.com/" data-view-component="true" class="Link--secondary Link">Docs</a>
          </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to contact&quot;,&quot;label&quot;:&quot;text:contact&quot;}" href="https://support.github.com?tags=dotcom-footer" data-view-component="true" class="Link--secondary Link">Contact</a>
          </li>

          
<li class="mx-2" >
  <cookie-consent-link>
    <button
      type="button"
      class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent"
      data-action="click:cookie-consent-link#showConsentManagement"
      data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;cookies&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;cookies_link_subfooter_footer&quot;}"
    >
      Manage cookies
    </button>
  </cookie-consent-link>
</li>

  <li class="mx-2">
    <cookie-consent-link>
      <button
        type="button"
        class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent text-left"
        data-action="click:cookie-consent-link#showConsentManagement"
        data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;dont_share_info&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;dont_share_info_link_subfooter_footer&quot;}"
      >
        Do not share my personal information
      </button>
    </cookie-consent-link>
  </li>

      </ul>
    </nav>
  </div>
</footer>



    <ghcc-consent id="ghcc" class="position-fixed bottom-0 left-0" style="z-index: 999999"
      data-locale="en"
      data-initial-cookie-consent-allowed=""
      data-cookie-consent-required="true"
    ></ghcc-consent>




  <div id="ajax-error-message" class="ajax-error-message flash flash-error" hidden>
    <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert">
    <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
</svg>
    <button type="button" class="flash-close js-ajax-error-dismiss" aria-label="Dismiss error">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
    </button>
    You can’t perform that action at this time.
  </div>

    <template id="site-details-dialog">
  <details class="details-reset details-overlay details-overlay-dark lh-default color-fg-default hx_rsm" open>
    <summary role="button" aria-label="Close dialog"></summary>
    <details-dialog class="Box Box--overlay d-flex flex-column anim-fade-in fast hx_rsm-dialog hx_rsm-modal">
      <button class="Box-btn-octicon m-0 btn-octicon position-absolute right-0 top-0" type="button" aria-label="Close dialog" data-close-dialog>
        <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
      </button>
      <div class="octocat-spinner tmp-my-6 js-details-dialog-spinner"></div>
    </details-dialog>
  </details>
</template>

    <div class="Popover js-hovercard-content position-absolute" style="display: none; outline: none;">
  <div class="Popover-message Popover-message--bottom-left Popover-message--large Box color-shadow-large" style="width:360px;">
  </div>
</div>

    <template id="snippet-clipboard-copy-button">
  <div class="zeroclipboard-container position-absolute right-0 top-0">
    <clipboard-copy aria-label="Copy code to clipboard" class="ClipboardButton btn js-clipboard-copy m-2 p-0" data-copy-feedback="Copied!" data-tooltip-direction="w">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon m-2 tmp-m-2">
    <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
</svg>
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none m-2 tmp-m-2">
    <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path>
</svg>
    </clipboard-copy>
  </div>
</template>
<template id="snippet-clipboard-copy-button-unpositioned">
  <div class="zeroclipboard-container">
    <clipboard-copy aria-label="Copy code to clipboard" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon">
    <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
</svg>
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none">
    <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path>
</svg>
    </clipboard-copy>
  </div>
</template>




    </div>
    <div id="js-global-screen-reader-notice" class="sr-only mt-n1" aria-live="polite" aria-atomic="true" ></div>
    <div id="js-global-screen-reader-notice-assertive" class="sr-only mt-n1" aria-live="assertive" aria-atomic="true"></div>
  </body>
</html>

