[{"data":1,"prerenderedAt":88},["ShallowReactive",2],{"site":3,"config-slug-site":15,"config-product-en-x3d-menu":21,"config-public-x3d-menu":83},{"site":4,"contact":10,"seo":13,"payment":14},{"name":5,"host":6,"default_locale":7,"locales":8},"X3D Developer","fivem.x3d-developer.com","th",[7,9],"en",{"discord_invite":11,"email":12,"line":12},"https:\u002F\u002Fdiscord.gg\u002FNA5kPVynFv","",{"google_site_verification":12,"bing_site_verification":12},{"bank_name":12,"account_name":12,"account_no":12,"promptpay_id":12},{"site":16,"contact":18,"seo":19,"payment":20},{"name":5,"host":6,"default_locale":7,"locales":17},[7,9],{"discord_invite":11,"email":12,"line":12},{"google_site_verification":12,"bing_site_verification":12},{"bank_name":12,"account_name":12,"account_no":12,"promptpay_id":12},{"id":22,"slug":23,"name":24,"summary":25,"price_thb":26,"license_mode":27,"cover_key":28,"cover_url":29,"category_slugs":30,"tags":32,"latest_version":48,"latest_released_at":49,"published_at":50,"has_docs":51,"config":52,"rent_price_satang":53,"description_md":54,"docs_md":55,"seo_title":56,"seo_description":57,"media":58,"versions":72},"7337afbc-ca0d-4071-9de4-2cc04bd1b4e6","x3d-menu","X3D Main Menu","A server main menu: system cards, announcements, timed events, an in-game guidebook and per-player settings. No database, any framework.",0,"none","public\u002Fproducts\u002Fx3d-menu\u002Fcover\u002F8a1dbb30861b0387.jpg","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-menu\u002Fcover\u002F8a1dbb30861b0387.jpg",[31],"hud",[33,34,35,36,37,38,39,40,41,42,43,44,45,46,47],"esx","standalone","เมนูหลัก","main menu","menu","ประกาศ","อีเวนต์","คู่มือเมือง","ฟรี","free","เมนูเมือง","กฎเมือง","เมนู F4","ตั้งค่าผู้เล่น","แบนเนอร์อีเวนต์","1.1.4","2026-10-12T17:21:29.681926Z","2026-09-21T04:20:29.437521Z",true,"public",null,"# A main menu with systems, announcements, events, a guide and player settings — free, no database required\r\n\r\nEvery server needs a main menu — a single grid of cards players can click instead of memorizing commands, timed announcements and events on the home tab, a categorized rules\u002Fguide tab, and a settings tab other scripts can add switches to. `x3d_menu` does all of it in one resource, through a ready-made Nuxt 4 panel.\r\n\r\n---\r\n\r\n## Features\r\n\r\n- [+] Easy setup: tune everything in config, or set it through the web builder\r\n- [+] System cards that open other scripts' commands, hidden if the resource is not running\r\n- [+] Pin favorites and search systems, with a separate quick-shortcut grid\r\n- [+] Home-tab announcements with your own image, color and order\r\n- [+] Events with a start and end time that disappear on their own\r\n- [+] A categorized city guide with a search box\r\n- [+] Admins edit announcements, events and the guide in-game, no restart\r\n- [+] Other scripts can add switches to the player settings tab\r\n- [+] Players pick the peach \u002F jade theme, their own color and Thai\u002FEnglish\r\n- [+] Discord, YouTube and Facebook links on the home tab\r\n- [+] No database and no framework needed, with an optional MySQL switch\r\n- [+] Hook into other scripts through addons\u002F\r\n\r\n---\r\n\r\n## System cards split into \"systems\" and \"convenience\", auto-hidden when their resource isn't installed\r\n\r\nAdd cards through `Config.Systems` or the runtime export `RegisterSystem`. Each card can bind to its own `resource` — if that resource isn't `started`, the card hides itself automatically, no manual cleanup needed. `category` splits full-feature cards (`'system'`) from pin\u002Fquick-toggle style shortcuts (`'qol'`) into their own grid. The command a card fires comes from a server-side cache only — it never trusts a command string sent by the panel itself.\r\n\r\n## Announcements, time-windowed events, a categorized guide — edited from admin commands, no restart\r\n\r\nEvents take `start_at`\u002F`end_at`; once outside that window they disappear from the panel even with `is_active` on. The home-tab banner tells you itself whether an event is \"starting soon\", \"N days left\", or \"live\". Everything (systems\u002Fannouncements\u002Fevents\u002Fguide) seeds from `config.lua` only the first time the resource starts — after that, edit it through the admin commands `\u002Fmenusystem` `\u002Fmenuevent` `\u002Fmenuannouncement` `\u002Fmenuguide`: add\u002Fedit\u002Fremove\u002Flist, no server restart needed.\r\n\r\n## Player settings: peach\u002Fjade theme, a custom color, and switches any script can add\r\n\r\n`RegisterSetting` adds a toggle\u002Fselect\u002Fslider switch to the settings tab from any resource. The player's actual value lives client-side in KVP, then replicates up to `LocalPlayer.state` so another resource can read it instantly through the `GetSetting` export or the state bag directly, plus an `x3d_menu:onSetting` hook that fires whenever a player changes anything.\r\n\r\n## No database required\r\n\r\nAdmin-managed content (systems\u002Fannouncements\u002Fevents\u002Fguide) is stored as a JSON file inside the resource itself, flushed every 30 seconds and on player drop \u002F a graceful stop. Need MySQL for a busier server? Swap four functions in one file for the commented oxmysql block, and run the included `install.sql`.\r\n\r\n## Requirements\r\n\r\nNone. No database, no framework, no license. Drop it in and `ensure` it.\r\n\r\n**Free** · modify it as you like · just don't resell it or re-upload it under another name.\r\n","## Installation\n\n1. Unzip and **rename the folder to `x3d_menu`** (other scripts call the exports by this name)\n2. Drop it in `resources\u002F`\n3. Add to `server.cfg`:\n\n```\nensure x3d_menu\n```\n\nNo database, no framework, no license. Works on ESX, QBCore and standalone.\n\nOpen it with **F4** or `\u002Fmenu`.\n\n## Systems (the \"Systems\" tab)\n\nCards that fire another script's command. They come from `Config.Systems` (seeded once) or from the `RegisterSystem` export at runtime:\n\n| field | what it does |\n|---|---|\n| `system_id` | Unique key — used for favourites and as the id `\u002Fmenusystem edit\\|remove` looks up |\n| `label` \u002F `description` \u002F `icon` | Card text and its heroicons icon |\n| `command` | The command fired on click — omit it and the card is not clickable |\n| `resource` | The resource this card belongs to — the card is hidden while it is not `started` (unless `always_show`) |\n| `always_show` | Show regardless of the resource state |\n| `category` | `'system'` (default) renders in the full grid; `'qol'` renders in its own \"convenience\" grid. Anything else is rejected |\n| `sort_order` | Ascending |\n\nThe command actually executed comes from the client's cache of what the server just sent — a command string posted by the NUI is never trusted.\n\nShipped examples: `x3d_mailbox` and `x3d_dailylogin` cards (hidden unless those resources are installed) and a working `qol` card that clears your waypoint.\n\nFavourites (the star on a card) are per player and stored client-side.\n\n## Announcements and events (the \"Home\" tab)\n\n`Config.Announcements` — cards with `title`, `content`, `image_url`, `color`, `is_active`, `sort_order`.\n\n`Config.Events` — the banner at the top, with `start_at` \u002F `end_at` as unix seconds; omit one side for no bound. An event outside its window never renders even with `is_active = true` (the server filters before sending), and the banner reads \"starting\", \"N days left\" or \"running\" from the current time.\n\nBoth are seeded from config once and edited afterwards with `\u002Fmenuannouncement` and `\u002Fmenuevent`.\n\n## Guidebook (the \"Guide\" tab)\n\n`Config.Guide` — rows with `category`, `title`, `content`, `image_url`, `is_active`, `sort_order`. The panel groups by `category` and adds a search box. Edit with `\u002Fmenuguide`.\n\n## Settings (the \"Settings\" tab)\n\n`Config.Settings` is the spec of which controls to draw — not the player's values. Another resource can add one at runtime:\n\n```lua\nexports['x3d_menu']:RegisterSetting('General', {\n    id = 'show_minimap', label = 'Show minimap', type = 'toggle', default_value = true,\n})\nexports['x3d_menu']:RegisterSetting('Graphics', {\n    id = 'quality', label = 'Effect quality', type = 'select', default_value = 'high',\n    options = { { value = 'low', label = 'Low' }, { value = 'high', label = 'High' } },\n})\n```\n\n`type` is `'toggle'`, `'select'` or `'slider'` (`min`\u002F`max` for a slider). A duplicate `id` is rejected, and the reserved ids `theme`, `custom_color` and `favorites` cannot be registered over. A newly registered spec is broadcast to clients immediately so its default becomes readable without the player opening the panel.\n\nIn the panel itself: th\u002Fen language (kept in the browser's `localStorage` — it is the panel's own language, it never goes through the server), the peach\u002Fjade themes and a custom accent colour. Every player gets all of them; no theme is locked behind an item.\n\n## Where the data lives — two places, two jobs\n\n**Per player** (theme, custom colour, toggle\u002Fselect\u002Fslider values, favourites) — client-side only, in resource KVP, republished to `LocalPlayer.state` under `x3dmenu:\u003Cid>`. Another resource reads it server-side through the `GetSetting` export or `Player(src).state['x3dmenu:\u003Cid>']` directly. It is `nil` until that player has a value for that id.\n\n**Admin-managed content** (systems, announcements, events, guidebook) — server-side through the storage adapter: one JSON file (`Config.Storage.File`, default `data\u002Fmenu.json`), loaded once at resource start, written back every `Config.Storage.FlushSeconds`, on player drop and on a graceful stop. A corrupt file is preserved as `data\u002Fmenu.broken.json` and the store starts empty. `Config.Systems` \u002F `Config.Events` \u002F `Config.Announcements` \u002F `Config.Guide` are imported into storage **only the first time the resource runs** — editing `config.lua` afterwards changes nothing, use the admin commands.\n\nTo use MySQL for the admin content instead (player data stays in client KVP either way):\n\n1. Run `install.sql` through oxmysql\n2. Open `addons\u002Fstorage\u002Fserver.lua`, scroll to the bottom and copy the oxmysql block over the four `Storage.Get\u002FSet\u002FAll\u002FFlush` functions above it\n\n## Exports\n\n```lua\n-- a new system card — returns false on a duplicate system_id, an incomplete def,\n-- or a category that is not 'system' or 'qol'\nexports['x3d_menu']:RegisterSystem({\n    system_id = 'my_shop', label = 'Shop', description = 'Buy supplies',\n    icon = 'i-heroicons-shopping-cart', command = 'openmyshop', resource = 'my_shop',\n    always_show = false, is_active = true, sort_order = 5, category = 'system',\n})\n\nexports['x3d_menu']:RegisterSetting(section, def)   --> boolean\nexports['x3d_menu']:GetSetting(src, 'show_hud')     --> the value, or nil if never set\n```\n\n## Hook — server-internal, not a net event\n\n```lua\nAddEventHandler('x3d_menu:onSetting', function(src, id, value)\n    if id == 'show_hud' then\n        print(('player %s set show_hud = %s'):format(src, tostring(value)))\n    end\nend)\n```\n\nIt fires whenever any player changes anything under `x3dmenu:*`, including `theme`, `custom_color` and `favorites`, not only the ids declared in `Config.Settings`.\n\n## Admin commands\n\nFour collections (`systems`, `events`, `announcements`, `guide`). Always available from the server console; an in-game player needs the ace in `Config.AdminAce` (default `x3d_menu.admin`):\n\n```\n\u002Fmenusystem add \u003Cjson>          -- json needs system_id and label\n\u002Fmenusystem edit \u003Csystem_id> \u003Cjson>\n\u002Fmenusystem remove \u003Csystem_id>\n\u002Fmenusystem list\n\n\u002Fmenuevent add \u003Cjson>           -- json needs title\n\u002Fmenuevent edit \u003Cid> \u003Cjson>\n\u002Fmenuevent remove \u003Cid>\n\u002Fmenuevent list\n\n\u002Fmenuannouncement add \u003Cjson>    -- json needs title\n\u002Fmenuannouncement edit \u003Cid> \u003Cjson>\n\u002Fmenuannouncement remove \u003Cid>\n\u002Fmenuannouncement list\n\n\u002Fmenuguide add \u003Cjson>           -- json needs title, content and category\n\u002Fmenuguide edit \u003Cid> \u003Cjson>\n\u002Fmenuguide remove \u003Cid>\n\u002Fmenuguide list\n```\n\n`add` and `edit` validate the fields the panel indexes — a row missing one is refused and nothing is written. `edit` cannot move a row onto an id that already exists. `remove`\u002F`edit` on an unknown id answer \"not found\" instead of throwing. `list` prints the collection's raw JSON and mutates nothing.\n\n## Safety, backed by tests\n\n- **A card's command comes from the server's own cache**, never from a string the NUI posted\n- **Every admin row is validated before it is written**, on `add` and on the merged result of an `edit`\n- **The reserved ids (`theme`, `custom_color`, `favorites`) cannot be registered or written over**, server-side and client-side\n- **Every request answers, even when refused** — one call per second per player per action, and a player's throttle buckets are cleared the moment they disconnect\n- **The storage key is always a stable identifier**, never a server id\n\n```bash\npip install lupa\npython tools\u002Flua-test\u002Fx3d_menu_check.py\n```\n\n## Config (`config.lua`)\n\n| Key | What it does |\n|---|---|\n| `Config.Locale` | Default language of the Lua-side strings (`th`\u002F`en`) — separate from the panel's own language |\n| `Config.Command` \u002F `Config.Key` | The open command (`\u002Fmenu`) and the key binding (`F4`) |\n| `Config.AdminAce` | The ace required for `\u002Fmenusystem`, `\u002Fmenuevent`, `\u002Fmenuannouncement`, `\u002Fmenuguide` |\n| `Config.Storage.File` \u002F `.FlushSeconds` | Where the admin content is written and how often |\n| `Config.SocialLinks` | The social links on the home tab |\n| `Config.Systems` \u002F `Config.Events` \u002F `Config.Announcements` \u002F `Config.Guide` | Seed data, imported into storage once |\n| `Config.Settings` | The spec of the controls in the settings tab |\n\n## Not ported from the original\n\nThis is a dependency-free port, so the original's Discord avatar and image uploads, its buff display, its PVP-shard toggle and its item-gated themes are not here — each of them needed a resource this product deliberately does not require.\n\n## Support\n\nDiscord: discord.gg\u002Fx3d-developer · Web: x3d-developer.com\n","Free FiveM Main Menu Script, No Database","Free FiveM main menu: system cards, announcements, timed events, an in-game guidebook, per-player settings and themes. No database, admins edit in game.",[59,62,64,66,68,70],{"kind":60,"url":61},"image","\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-menu\u002Fmedia\u002Fdf5554e733bb3344.png",{"kind":60,"url":63},"\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-menu\u002Fmedia\u002Fb69a7d2d674141e6.png",{"kind":60,"url":65},"\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-menu\u002Fmedia\u002Fac244d9e6dbda554.png",{"kind":60,"url":67},"\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-menu\u002Fmedia\u002F6d4299351032214d.png",{"kind":60,"url":69},"\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-menu\u002Fmedia\u002F60886675555c9c64.png",{"kind":60,"url":71},"\u002Fapi\u002Fv1\u002Fmedia\u002Fpublic\u002Fproducts\u002Fx3d-menu\u002Fmedia\u002F4a5b1d1684d6d441.png",[73,75,79],{"version":48,"released_at":49,"changelog_md":74},"### Changed\n\n- Store images now carry English captions for the English store page",{"version":76,"released_at":77,"changelog_md":78},"1.1.1","2026-10-12T03:26:17.490932Z","### Changed\n\n- UI font is now Kanit (one family for Thai and English), bundled inside the script; the Thai font now really loads in game (FiveM's browser dropped the old font declaration and fell back to a system font)",{"version":80,"released_at":81,"changelog_md":82},"1.0.0","2026-09-21T04:20:20.653667Z","### Added\n- Main menu panel (`\u002Fmenu`, F4) ported from cc_menu: home with announcements and a timed event banner, systems grid with favourites, guidebook with categories and search, settings tab\n- Systems come from `Config.Systems` or the `RegisterSystem` export, split into the full `system` grid and the `qol` convenience grid, hidden automatically while their resource is not started\n- Events carry a `start_at`\u002F`end_at` window and are filtered server-side, so an out-of-window event never reaches the panel\n- Settings spec from `Config.Settings` plus the `RegisterSetting` export, with `toggle`, `select` and `slider` controls; a newly registered spec is broadcast so its default is readable without the player opening the panel\n- Per-player theme, custom colour, setting values and favourites live in client KVP and are republished to `LocalPlayer.state` under `x3dmenu:\u003Cid>`, readable server-side through `GetSetting(src, id)` or the state bag directly\n- Admin-managed content (systems, announcements, events, guidebook) lives in the storage adapter: a JSON file by default, with an oxmysql block shipped commented in the same file\n- Admin commands `\u002Fmenusystem`, `\u002Fmenuevent`, `\u002Fmenuannouncement`, `\u002Fmenuguide` with `add`, `edit`, `remove` and `list`, gated by the `x3d_menu.admin` ace and always available from the console\n- Server event `x3d_menu:onSetting(src, id, value)` for reacting to a player's choice\n- Every net event resolves `source` itself, is rate limited per action per second, validates its arguments before use and always answers; a card's command is taken from the server's cache, never from the NUI",{"slug":23,"version":48,"latest_version":48,"files":84,"options":53},[85],{"path":86,"content":87},"config.lua","Config = {}\n\n-- ===== ทั่วไป \u002F General =====\n\n-- เฟรมเวิร์ก: 'auto' (ตรวจอัตโนมัติ) | 'esx' | 'standalone'\n-- Framework: 'auto' (detect automatically) | 'esx' | 'standalone'\nConfig.Framework = 'auto'\n\n-- ภาษาเริ่มต้นของข้อความฝั่ง Lua: 'th' | 'en' \u002F Default language for Lua-side messages: 'th' | 'en'\nConfig.Locale  = 'th'\n\n-- คำสั่งเปิดเมนู (\u002Fmenu) \u002F Command that opens the menu (\u002Fmenu)\nConfig.Command = 'menu'\n\n-- ปุ่มเปิดเมนู ('' = ไม่ผูกปุ่ม) \u002F Key that opens the menu ('' = no key bound)\nConfig.Key     = 'F4'\n\n-- สิทธิ์ ACE ของแอดมิน (ใช้กับ \u002Fmenusystem \u002Fmenuevent \u002Fmenuannouncement \u002Fmenuguide)\n-- Admin ACE permission (used by \u002Fmenusystem \u002Fmenuevent \u002Fmenuannouncement \u002Fmenuguide)\nConfig.AdminAce = 'x3d_menu.admin'\n\n-- ===== ที่เก็บข้อมูล \u002F Storage =====\n\n-- ไฟล์ JSON ที่เก็บเนื้อหาที่แอดมินแก้ และความถี่การเซฟ (วินาที)\n-- JSON file holding admin-managed content, and how often it is saved (seconds)\nConfig.Storage = {\n    File         = 'data\u002Fmenu.json',\n    FlushSeconds = 30,\n}\n\n-- ===== ลิงก์โซเชียล \u002F Social links =====\n\n-- ลิงก์โซเชียลบนหน้าแรก — ปิดอันไหนก็ตั้ง enabled = false\n-- Social links on the home tab; set enabled = false to hide one\n-- เช่น \u002F e.g. { id = 'discord', label = 'Discord', icon = 'i-simple-icons-discord', url = 'https:\u002F\u002Fdiscord.gg\u002Fexample', enabled = true }\nConfig.SocialLinks = {\n    { id = 'discord',  label = 'Discord',  icon = 'i-simple-icons-discord',  url = 'https:\u002F\u002Fdiscord.gg\u002Fexample',      enabled = true },\n    { id = 'youtube',  label = 'YouTube',  icon = 'i-simple-icons-youtube',  url = 'https:\u002F\u002Fyoutube.com\u002F@example',    enabled = true },\n    { id = 'facebook', label = 'Facebook', icon = 'i-simple-icons-facebook', url = 'https:\u002F\u002Ffacebook.com\u002Fexample',    enabled = true },\n}\n\n-- ===== ระบบในเมนู \u002F Menu systems =====\n\n-- ═══════════════════════════════════════════════════════════════\n--  ระบบในเมนู (การ์ดในแท็บ \"ระบบ\") — seed เข้า storage แค่ครั้งแรกที่ resource\n--  เริ่มทำงานเท่านั้น (ตรวจจาก storage key `_seeded`) หลังจากนั้นแก้ไข\u002Fเพิ่ม\u002Fลบ\n--  ทำผ่านคำสั่ง \u002Fmenusystem หรือ export RegisterSystem — แก้ไฟล์นี้ทีหลังจะไม่มีผลอีก\n--\n--  resource     (ไม่บังคับ) ชื่อ resource ของระบบนี้ — ถ้าใส่ไว้แล้ว resource นั้นไม่ได้\n--                start จะไม่โชว์การ์ดนี้ในเมนู เว้นแต่ always_show = true\n--  always_show  โชว์เสมอไม่สนสถานะ resource (หรือไม่ได้ใส่ resource เลยก็โชว์เสมออยู่แล้ว)\n--  category     'system' (ค่าเริ่มต้นถ้าไม่ใส่) = การ์ดระบบเต็มรูปแบบ ขึ้นแท็บ \"ระบบทั้งหมด\";\n--                'qol' = ทางลัดความสะดวก (ปักหมุด\u002Fสลับด่วน ไม่มี UI เป็นของตัวเอง) ขึ้นกริดแยก\n--                \"ความสะดวก\" ด้านล่าง — ใส่ค่าอื่นนอกจากสองตัวนี้จะถูกปฏิเสธที่ RegisterSystem\n--\n--  System cards (the \"Systems\" tab) — seeded into storage only the first time the resource\n--  starts (checked by the storage key `_seeded`); after that edit\u002Fadd\u002Fremove through\n--  \u002Fmenusystem or the RegisterSystem export — changing this file later has no effect\n--\n--  resource     (optional) the system's resource name — if set and that resource is not\n--                started, the card is hidden unless always_show = true\n--  always_show  show regardless of resource state (a card without resource is always shown)\n--  category     'system' (default) = full system card in the \"all systems\" tab;\n--                'qol' = quick convenience shortcut (pin \u002F quick toggle, no UI of its own) in the\n--                separate \"convenience\" grid below — any other value is rejected by RegisterSystem\n-- ═══════════════════════════════════════════════════════════════\nConfig.Systems = {\n    -- ตัวอย่างที่เปิดใช้จริง — ผูกกับ resource ของ X3D เอง ถ้าเซิร์ฟไม่ได้ลงไว้\n    -- การ์ดจะถูกซ่อนอัตโนมัติ (resource + always_show = false) ไม่ต้องมาลบเอง\n    -- Live examples bound to X3D resources; if the server does not run them\n    -- the card hides itself (resource + always_show = false), no cleanup needed\n    {\n        system_id   = 'x3d_mailbox',\n        label       = 'กล่องจดหมาย',\n        description = 'รับของจากทีมงานและโค้ดรับของ',\n        icon        = 'i-heroicons-envelope',\n        command     = 'mailbox',\n        resource    = 'x3d_mailbox',\n        always_show = false,\n        is_active   = true,\n        sort_order  = 1,\n        category    = 'system',\n    },\n    {\n        system_id   = 'x3d_dailylogin',\n        label       = 'เช็คอินรายวัน',\n        description = 'รับรางวัลประจำวันและโบนัสเวลาเล่น',\n        icon        = 'i-heroicons-calendar-days',\n        command     = 'dailylogin',\n        resource    = 'x3d_dailylogin',\n        always_show = false,\n        is_active   = true,\n        sort_order  = 2,\n        category    = 'system',\n    },\n    {\n        system_id   = 'qol_waypoint_clear',\n        label       = 'ล้างหมุดนำทาง',\n        description = 'ลบหมุดบนแผนที่ทิ้ง',\n        icon        = 'i-heroicons-map-pin',\n        command     = 'x3dmenu_clearwaypoint',\n        always_show = true,\n        is_active   = true,\n        sort_order  = 100,\n        category    = 'qol',\n    },\n\n    -- {\n    --     system_id   = 'inventory',\n    --     label       = 'กระเป๋าเป้',\n    --     description = 'เปิดกระเป๋าเป้ของคุณ',\n    --     icon        = 'i-heroicons-shopping-bag',\n    --     command     = 'openInventory',\n    --     badge_image = nil,\n    --     resource    = 'ox_inventory',\n    --     always_show = false,\n    --     is_active   = true,\n    --     sort_order  = 1,\n    --     category    = 'system',\n    -- },\n    -- {\n    --     system_id   = 'qol_waypoint_home',\n    --     label       = 'ปักหมุดบ้าน',\n    --     description = 'ตั้งเส้นทางไปบ้านของคุณ',\n    --     icon        = 'i-heroicons-home',\n    --     command     = 'waypointhome',\n    --     resource    = 'esx_property',\n    --     always_show = false,\n    --     is_active   = true,\n    --     sort_order  = 100,\n    --     category    = 'qol',\n    -- },\n    -- {\n    --     system_id   = 'qol_waypoint_job',\n    --     label       = 'ปักหมุดที่ทำงาน',\n    --     description = 'ตั้งเส้นทางไปจุดทำงานล่าสุด',\n    --     icon        = 'i-heroicons-briefcase',\n    --     command     = 'waypointjob',\n    --     always_show = true,\n    --     is_active   = true,\n    --     sort_order  = 101,\n    --     category    = 'qol',\n    -- },\n}\n\n-- ===== ประกาศ \u002F Announcements =====\n\n-- ประกาศหน้าแรก — seed ครั้งแรกเหมือนกัน แก้ทีหลังผ่าน \u002Fmenuannouncement\n-- Home-tab announcements, also seeded once; edit later through \u002Fmenuannouncement\n-- เช่น \u002F e.g. { title = 'ยินดีต้อนรับ', content = 'ขอบคุณที่เข้ามาเล่นกับเรา', color = '#F59E0B', is_active = true, sort_order = 1 }\nConfig.Announcements = {\n    -- { title = 'ยินดีต้อนรับ', content = 'ขอบคุณที่เข้ามาเล่นกับเรา',\n    --   image_url = nil, color = '#F59E0B', is_active = true, sort_order = 1 },\n}\n\n-- ===== อีเวนต์ \u002F Events =====\n\n-- อีเวนต์ที่มีช่วงเวลา — start_at\u002Fend_at เป็น unix timestamp (วินาที), ไม่ใส่ = ไม่จำกัดฝั่งนั้น\n-- นอกช่วงเวลาจะไม่โชว์ในพาเนลแม้ is_active = true\n-- Timed events: start_at\u002Fend_at are unix timestamps (seconds), omitted = unlimited on that side\n-- Outside the window the event is hidden in the panel even when is_active = true\n-- เช่น \u002F e.g. { title = 'อีเวนต์ทดสอบ', start_at = 1790000000, end_at = 1790100000, is_active = true, sort_order = 1 }\nConfig.Events = {\n    -- { title = 'อีเวนต์ทดสอบ', description = 'รายละเอียดอีเวนต์', image_url = nil, color = '#F59E0B',\n    --   start_at = 1790000000, end_at = 1790100000, is_active = true, sort_order = 1 },\n}\n\n-- ===== คู่มือ \u002F Guide =====\n\n-- คู่มือ\u002Fกฎเมือง — จัดกลุ่มด้วย category\n-- City guide \u002F rules, grouped by category\n-- เช่น \u002F e.g. { category = 'ทั่วไป', title = 'เริ่มต้นเล่น', content = 'ข้อความคู่มือ...', is_active = true, sort_order = 1 }\nConfig.Guide = {\n    -- { category = 'ทั่วไป', title = 'เริ่มต้นเล่น', content = 'ข้อความคู่มือ...',\n    --   image_url = nil, is_active = true, sort_order = 1 },\n}\n\n-- ===== ตั้งค่าผู้เล่น \u002F Player settings =====\n\n-- ═══════════════════════════════════════════════════════════════\n--  ตั้งค่าในพาเนล (แท็บ \"ตั้งค่า\") — เก็บฝั่ง client เท่านั้น (KVP) ไม่ผ่าน server เลย\n--  เพิ่มจาก resource อื่นตอน runtime ได้ด้วย export RegisterSetting(section, def)\n--  type: 'toggle' | 'select' | 'slider'\n--\n--  Panel settings (the \"Settings\" tab) — stored client side only (KVP), never sent to the server\n--  Other resources can add more at runtime with the RegisterSetting(section, def) export\n--  type: 'toggle' | 'select' | 'slider'\n-- ═══════════════════════════════════════════════════════════════\nConfig.Settings = {\n    {\n        -- ชื่อหมวดในแท็บตั้งค่า \u002F Section name in the settings tab\n        section = 'ทั่วไป',\n        -- สวิตช์ในหมวดนี้: id = คีย์เก็บค่า, label = ชื่อที่โชว์, default_value = ค่าเริ่มต้น\n        -- Switches in this section: id = storage key, label = shown name, default_value = default\n        items = {\n            { id = 'show_hud',       label = 'แสดง HUD',       type = 'toggle', default_value = true },\n            { id = 'show_crosshair', label = 'แสดง Crosshair', type = 'toggle', default_value = false },\n        },\n    },\n}\n",1792316315787]