{"id":22619553,"url":"https://github.com/tksimeji/visualkit","last_synced_at":"2025-04-11T15:21:18.520Z","repository":{"id":265725506,"uuid":"896525769","full_name":"tksimeji/visualkit","owner":"tksimeji","description":"A Minecraft GUI framework","archived":false,"fork":false,"pushed_at":"2025-03-25T10:01:49.000Z","size":1001,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-25T11:22:02.864Z","etag":null,"topics":["bukkit","bukkit-plugin","developer-tool","framework","paper","paper-plugin","papermc","spigot","spigotmc"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tksimeji.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-30T15:44:44.000Z","updated_at":"2025-03-25T10:01:52.000Z","dependencies_parsed_at":"2025-03-11T06:35:33.610Z","dependency_job_id":null,"html_url":"https://github.com/tksimeji/visualkit","commit_stats":null,"previous_names":["tksimeji/visualkit"],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tksimeji%2Fvisualkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tksimeji%2Fvisualkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tksimeji%2Fvisualkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tksimeji%2Fvisualkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tksimeji","download_url":"https://codeload.github.com/tksimeji/visualkit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248429129,"owners_count":21101786,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bukkit","bukkit-plugin","developer-tool","framework","paper","paper-plugin","papermc","spigot","spigotmc"],"created_at":"2024-12-08T22:06:04.114Z","updated_at":"2025-04-11T15:21:18.509Z","avatar_url":"https://github.com/tksimeji.png","language":"Java","readme":"# Visualkit\n\nThe Minecraft GUI framework\n\n![Version](https://img.shields.io/badge/version-0.5.2-blue?style=flat-square)\n![Adapter](https://img.shields.io/badge/adapter-1.21.1--1.21.4-yellow?style=flat-square)\n![Licence](https://img.shields.io/badge/licence-MIT-red?style=flat-square)\n\n\u003cimg alt=\"Eye-catching\" src=\"./assets/b706df0a-22c2-4185-9813-6e4a0981ca11.png\" width=\"64%\"\u003e\n\nVisualkit is a free, open-source GUI framework for [Paper](https://papermc.io/software/paper) server.\n\n\u003e [!IMPORTANT]\n\u003e Over the past few months, I've been working on making Visualkit a modern and fast framework.\n\u003e However, I've found it difficult to maintain compatibility with the legay Visualkit.\n\u003e After careful consideration, I've decided that it's best to release these as a new framework rather than Visualkit.\n\u003e Visualkit will remain available, but the pace of development and fixes will likely slow down.\n\u003e I'm sorry, but I recommend a gradual migrating to the new framework once it's released.\n\u003e 3/25/2025\n\n\u003e [!IMPORTANT]\n\u003e 私はこの数か月間、 Visualkit をモダンで高速なフレームワークにすることに取り組んできました。\n\u003e しかし、その中で、従来の Visualkit との互換性を維持することが困難であることに気づきました。\n\u003e 熟考した結果、これらを Visualkit ではなく、新しいフレームワークとしてリリースする判断に至りました。\n\u003e Visualkit は引き続き利用できますが、今後開発や修正のペースが低下することが考えられます。\n\u003e 大変申し訳ありませんが、私は新フレームワークのリリース後は、段階的な移行を推奨します。\n\u003e 2025年3月25日\n\nMaximum respect to [Bram Moolenaar](https://github.com/brammool), the developer of [Vim](https://www.vim.org/).\n\nI also sympathized with his philanthropic side, so I decided to add the same text as the Vim startup screen to the\nVisualkit banner.\n\n![Banner](./assets/042a7581-620a-4df7-bb12-e873befa8529.png)\n\n#### \"Help poor children in Uganda!\"\n\nDonate to the future of Uganda's children!\n\n## ![Get Started](./assets/0653b226-92e7-4f8c-8903-ecc99ef7bc59.png) Get Started\n\nAdd Visualkit to your plugin's dependencies.\n\nVisualkit is available on Maven Central. To add dependency using Gradle, write the following in your `build.gradle` (\nGroovy DSL)\n\n```groovy\ndependencies {\n    compileOnly 'com.tksimeji:visualkit:x.y.z'\n}\n```\n\nor in the `build.gradle.kts` file (Kotlin DSL)\n\n```kotlin\ndependencies {\n    compileOnly(\"com.tksimeji:visualkit:x.y.z\")\n}\n```\n\nTo add a dependency using Maven, write the following in `pom.xml`\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.tksimeji\u003c/groupId\u003e\n    \u003cartifactId\u003evisualkit\u003c/artifactId\u003e\n    \u003cversion\u003ex.y.z\u003c/version\u003e\n    \u003cscope\u003eprovided\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\nNext, specify the plugin dependencies.\nWrite the following in `plugin.yml`.\n\n```yaml\ndepend:\n  - Visualkit\n```\n\nHowever, the case of `paper-plugin.yml` seems to\nbe [slightly different](https://docs.papermc.io/paper/dev/getting-started/paper-plugins).\n\nFor a plugin that uses Visualkit to work, Visualkit must be installed as a plugin on the server along with the plugin.\n\nInstalling it on the server is no different from a normal plugin.\nJust download the jar file from \"Releases\" and place it in the plugins directory on you server.\n\n![Release](./assets/f3baa37f-72de-4b1a-a48e-2b680a9afba6.png)\n\n## ![Placeholders](./assets/2deaff09-7d77-4493-8f71-39609f3b2704.png) Placeholders\n\n\u003ca id=\"2479b5e2-7a0e-4a02-8e73-9ab045086560\"\u003e\u003c/a\u003e\n\nIn GUIs created with Visualkit, you can use placeholders for text.\n\n```java\nVisualkitElement\n        .create(Material.NAME_TAG)\n        .title(Component.text(\"Hello, ${name}.\"));\n```\n\nThe placeholders are replaced with field values from the GUI implementation class\nat rendering time and automatically updated.\n\nIf these values are of type object, they will be processed with `Object#toString()`,\nexpect that the implementation of `net.kyori.adventure.text.Component` will be embedded as is.\n\nYou can also use the \"\u0026\" symbol to decorate text.\n\ne.g: ```\u0026aHello, world!```\n\n## ![Localize](./assets/3e6145d3-d123-4f27-9785-a9fa481b8074.png) Localize\n\nThe ability for players to view the UI in their own language is an important part of the UX.\nVisualkit makes it easy to implement displays that match the player's language settings.\n\nTranslations are defined by language files.\n\nThe language file must be placed directly under the jar as `lang/{Minecraft locale code}.json`.\nIn a standard configuration for build systems such as Maven or Gradle,\nit will look like this: ``src/main/resources/lang/en_us.json``.\n\nA language file has the following syntax:\n\n```json\n{\n  \"greeting\": \"\u0026d\u0026lHello, ${name}!\"\n}\n```\n\nAs you can see, every translation has a key.\nThere are no strict rules for the key, but dotted snake case is recommended.\n\nIn this way, translations are loaded into Visualkit by defining the language file in a specific location and syntax.\nNext, let's look at how to reference the translations defined in the language file from code.\n\n```java\n// Note: These return a net.kyori.adventure.text.Component\n\n// Get by locale code and full translation key\nLanguage.translate(new NamespacedKey(plugin, \"key\"), MinecraftLocale.EN_US, \"arg1=value1\", \"arg2=value2\");\n\n// Get by locale code and translation key\nLanguage.translate(MinecraftLocale.EN_US, \"key\", \"arg1=value1\", \"arg2=value2\");\n\n// Get by player and full translation key\nLanguate.translate(new NamespacedKey(plugin, \"key\"), player, \"arg1=value1\", \"arg2=value2\");\n\n// Get by player and translation key\nLanguage.translate(\"key\", player, \"arg1=value1\", \"arg2=value2\");\n```\n\nIf you pass a translation key without specifying a namespace, the namespace of the calling plugin will be automatically picked up.\n\nAlso, if a player is passed as an argument, the language setting of that player will be applied.\n\n## ![Chest GUI](./assets/a6e12e13-5b3b-4e72-a847-d19267b4422d.png) Create a chest GUI\n\nCreate a user interface using a chest.\n\n### 1. Create a class that extends `com.tksimeji.visualkit.ChestUI`\n\nYou need to implement a title() method that returns `net.kyori.adventure.text.Component`\nand a size() method that defines the size of the chest.\n\n```java\npublic class MyChestUI extends ChestUI {\n    public MyChestUI(@NotNull Player player) {\n        super(player);\n    }\n\n    @Override\n    public @NotNull Component title() {\n        return Component.text(\"Cookie clicker\").decorate(TextDecoration.BOLD);\n    }\n\n    @Override\n    public @NotNull Size size() {\n        return Size.SIZE_9;\n    }    \n}\n```\n\n### 2. Add element\n\nLet's add elements to the GUI.\n\nThe simplest way to declare an element is to define a field in the class.\n\nAdd `com.tksimeji.visualkit.api.Element` to a field of type `com.tksimeji.visualkit.element.VisualkitElement`.\n\n```java\nprivate int count;\n\n@Element(13)\nprivate final VisualkitElement cookieButton = VisualkitElement\n        .create(Material.COOKIE)\n        .title(Component.text(\"Click me!\").color(NamedTextColor.GREEN).decorate(TextDecoration.BOLD))\n        .lore(Component.text(\"Clicks: ${count}\"))\n        .sound(Sound.UI_BUTTON_CLICK, 1.0f, 1.2f);\n\n// Note: The player head API was added in 0.2.x.\n\nVisualkitElement.head()\n    .url(\"https\");\n\nVisualkitElement.head(\"http://textures.minecraft.net/texture/a60ed3827ed16f34b367ff96fdd6a56cb365f522e58122c147fc919fa90b208c\");\n\nVisualkitElement.head(UUID.fromString(\"ee54c324-9ab4-472e-aa4d-392f15b820fb\"));\n\nVisualkitElement.head(Bukkit.getPlayer(\"tksimeji\"));\n```\n\nAlternatively, you can specify an `org.bukkit.inventory.ItemStack`.\n\n```java\n@Element(13)\nprivate final ItemStack cookieButton = new ItemStack(Material.COOKIE, 1);\n```\n\nThe annotation parameter specifies the index in the GUI.\n\nYou can place it in multiple slots:\n\n```java\n@Element({2, 3, 5, 7, 11, 13, 17, 19})\n```\n\nYou can also use asm (Advanced Slot Mapping) for more advanced specifications.\n\n```java\n@Element(asm = {@Asm(from = 0, to = 8), @Asm(from = 18, to = 26), @Asm({27, 28})}, value = {29, 30})\n```\n\nIf you want to dynamically add or remove elements, use `com.tksimeji.visualkit.ChestUI#setElement(...)`\n\n```java\n// You can specify an VisualkitElement\nsetElement(0, VisualkitElement.create(Material.COOKIE).title(Component.text(\"Click me!\")));\n\n// You can specify an ItemStack\nsetElement(0, new ItemStack(Material.COOKIE, 1));\n\n// Empty a slot\nsetElement(0, null);\n```\n\n### 3. Add policy\n\nA policy defines the behavior of a slot.\n\n\u003e [!TIP]\n\u003e The default policy is `SlotPolicy.FIXATION`\n\nYou can control drops outside the window by specifying -1 in the slot.\n\n#### Defines a filed with a `com.tksimeji.visualkit.api.Policy` annotation:\n\n```java\n// The method for specifying the scope is the same as for @Element\n\n@Policy(1)\nprivate final SlotPolicy policy = SlotPolicy.VARIATION;\n\n// It can be applied to the UI as well as the player's inventory\n@Policy(1, target = PolicyTarget.INVENTORY)\nprivate final SlotPolicy policy = SlotPolicy.VARIATION;\n```\n\n#### Setting policies from code:\n\n```java\n// The target will automatically be PolicyTarget.UI\n@NotNull SlotPolicy getPolicy(int slot);\n\n@NotNull SlotPolicy getPolicy(int slot, @NotNull PolicyTarget target);\n\n// The target will automatically be PolicyTarget.UI\nvoid setPolicy(int slot, @NotNull SlotPolicy policy);\n\nvoid setPolicy(int slot, @NotNull SlotPolicy policy, @NotNull PolicyTarget target);\n```\n\n### 4. Add handler\n\nDefine a method to handle clicks on any slot.\n\nAdd a method with the annotation `com.tksimeji.visualkit.api.Handler`.\nIn addition to slots, you can add action and mouse conditions to the Handler annotation.\n\n```java\n@Handler(index = 13, action = Action.SINGLE, mouse = {Mouse.LEFT, Mouse.RIGHT})\npublic void onCookieClick() {\n    count ++;\n}\n\n// You can also specify whether to allow clicks in the return value\n\n@Handler(index = 13, action = Action.SINGLE, mouse = {Mouse.LEFT, Mouse.RIGHT})\npublic boolean onCookieClick() {\n    count ++;\n}\n\n// Alternatively, handlers can be specified directly on the element.\n\n@Element(13)\nprivate final VisualkitElement cookieButton = VisualkitElement\n        .create(Material.COOKIE)\n        .handler(() -\u003e count ++);\n\n// It can also take arguments\n\n@Element(13)\nprivate final VisualkitElement cookieButton = VisualkitElement\n        .create(Material.COOKIE)\n        .handler((slot, action, mouse) -\u003e samething());\n```\n\nOf course, you can also use asm to specify the slot.\n\n```java\n@Handler(asm = {@Asm(from = 0, to = 8)}, index = {9, 10})\n```\n\nIt can also take slot, action, and mouse state as arguments.\nHowever, these arguments are injected only if the following conditions are met:\n\n| Type                                |\n|:------------------------------------|\n| `int` / `java.lang.Integer`         |\n| `com.tksimeji.visualkit.api.Action` |\n| `com.tksimeji.visualkit.api.Mouse`  |\n| `org.bukkit.inventory.ItemStack`    |\n\nThis is useful when you specify a broad conditions in the annotation.\n\n```java\n@Handler(index = 0)\npublic void onClick(int slot, Click action, Mouse mouse, ItemStack itemStack) {\n    // do something\n}\n```\n\n### 4. Display the GUI\n\nAll you have to do is create an instance.\nBasically, you need to pass in the player as an argument.\n\n```java\nnew MyChestUI(player);\n```\n\nThe GUI will be displayed to the player specified as an argument.\n\n## ![Anvil GUI](./assets/0977cc82-2c93-4214-86d6-0caeeee1166b.png) Create a Anvil GUI\n\nThis is a GUI that uses an anvil. It is intended to be used as a text input screen.\n\n### 1. Create a class that extends `com.tksimeji.visualkit.AnvilUI`\n\n```java\npublic class MyAnvilUI extends AnvilUI {\n    // do something\n}\n```\n\n### 2. Set up placeholders and dummy item\n\nTheir implementation is optional.\n\n```java\n@Override\npublic @Nullable String placeholder() {\n    return \"Enter your search term\";\n}\n\n@Override\npublic @NotNull Material dummy() {\n    return Material.COMPASS;\n}\n```\n\n### 3. Add processing when character input is completed\n\n```java\n@Override\npublic void onTyped(@NotNull String string) {\n    player.sendMessage(Component.text(\"You typed \\\"\" + string + \"\\\".\"));\n}\n```\n\n## ![Merchant GUI](./assets/54aa3ec7-5a11-4a79-901b-da66eb9f667f.png) Create a Merchant GUI\n\nThe Merchant GUI uses the GUI used to trade with villagers and wandering traders.\n\n### 1. Create a class that extends `com.tksimeji.visualkit.MerchantUI`\n\n```java\npublic class MyMerchantUI extends MerchantUI {\n    // do something\n}\n```\n\n### 2. Add displayed transactions\n\nIf it is always constant, you can also declare it as a field.\n\n```java\n@Target(index = 0)\nprivate final @NotNull VisualkitTrade = VisualkitTrade.create(new ItemStack(Material.DIAMOND), 2)\n        .requirement(new ItemStack(Material.EMERALD, 16))\n        .onSelect(() -\u003e doSomething())\n        .onPurchare(() -\u003e doSomething());\n```\n\nOf course, you can add and remove them dynamically.\n\n```java\nsetTrade(0, VisualkitTrade.create(new ItemStack(Material.REDSTONE)));\n\naddTrade(VisualkitTrade.create(new ItemStack(Material.REDSTONE)));\n\nremoveTrade(0);\n\nremoveTrade(trade);\n```\n\n### 3. Add a handler\n\nAdd methods that will be called when selecting and purchasing a trade.\n\n```java\n@Handler(index = 0, action = Action.SELECT)\nvoid handler1() {}\n\n@Handler(index = 0, action = Action.PURCHARE)\nvoid handler2() {}\n```\n\nDetails can be passed as arguments.\n\n| type                                          | description |\n|:----------------------------------------------|-------------|\n| `int` / `java.lang.Integer`                   | index       |\n| `com.tksimeji.visualkit.trade.VisualkitTrade` | trade       |\n\nYou can also specify whether to pass the event through by returning a boolean value.\n\n## ![Panel GUI](./assets/4a48ded0-5caf-4a18-bcb4-095fffb6f8bf.png) Create a Panel GUI\n\nThe Panel GUI is a user interface that utilizes the scoreboard sidebar.\n\n### 1. Create a class that extends `com.tksimeji.visualkit.SharedPanelUI`\n\n```java\npublic class MyPanelUI extends PanelUI {\n    // do something\n}\n```\n\n### 2. Write text on the panel\n\nHere we'll use the constructor to write to it.\n\nLet's display the player's information as an example.\n[Placeholder](#2479b5e2-7a0e-4a02-8e73-9ab045086560) are used to embed values.\n\nThe values is updated using the `onTick` method.\n\n```java\nprivate String name;\nprivate int health;\nprivate int ping;\n\npublic MyPanelUI(@NotNull Player player) {\n    super(player);\n    \n    setTitle(Component.text(\"INFO\").color(NamedTextColor.YELLOW));\n    \n    addLine(Component.text(\"Hello, ${name}!\"));\n    addLine();\n    addLine(Component.text(\"Health:\").appendSpace().append(Component.text(\"${health}♥\").color(NamedTextColor.RED)));\n    setLine(3, Component.text(\"Ping:\").appendSpace().append(Component.text(\"${ping} ms\").color(NamedTextColor.GREEN)));\n}\n\n// Some code omitted //\n\n@Override\npublic void onTick() {\n    name = player.getName();\n    health = (int) player.getHealth();\n    ping = player.getPing();\n}\n```\n\nThis time we created a panel for one player,\nbut if you want to display the same panel for multiple players,\ntry extending `com.tksimeji.visualkit.SharedPanelUI`.\n\n### 3. Display the GUI\n\n![](./assets/9f1b15f3-90d9-4fba-aace-999084882d52.png)\n\n```java\n// If you extend com.tksimeji.visualkit.PanelUI\n\nnew MyPanelUI(player);\n\n// If you extend com.tksimeji.visualkit.SharedPanelUI\n\nnew MyPanelUI(player1, player2);\n\nnew MyPanelUI(List.of(player1, player2));\n\nnew MyPanelUI().addAudience(player);\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftksimeji%2Fvisualkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftksimeji%2Fvisualkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftksimeji%2Fvisualkit/lists"}