create-pixi-vn 2.0.12 → 2.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/package.json +1 -1
  2. package/template-react-vite-muijoy-ink/.vscode/extensions.json +2 -1
  3. package/template-react-vite-muijoy-ink/.vscode/settings.json +6 -1
  4. package/template-react-vite-muijoy-ink/_gitignore +1 -0
  5. package/template-react-vite-muijoy-ink/ink/second_part.ink +571 -0
  6. package/template-react-vite-muijoy-ink/ink/start.ink +214 -0
  7. package/template-react-vite-muijoy-ink/package-lock.json +230 -4
  8. package/template-react-vite-muijoy-ink/package.json +3 -1
  9. package/template-react-vite-muijoy-ink/src/App.tsx +25 -25
  10. package/template-react-vite-muijoy-ink/src/assets/index.ts +2 -4
  11. package/template-react-vite-muijoy-ink/src/assets/ink-manifest.gen.json +4 -1
  12. package/template-react-vite-muijoy-ink/src/content/ink/hashtag-commands.ts +38 -0
  13. package/template-react-vite-muijoy-ink/src/content/ink/text-replaces.ts +19 -0
  14. package/template-react-vite-muijoy-ink/src/lib/hooks/ink-hooks.tsx +12 -0
  15. package/template-react-vite-muijoy-ink/src/lib/i18n.ts +22 -1
  16. package/template-react-vite-muijoy-ink/src/pixi-vn-keys.gen.d.ts +2 -0
  17. package/template-react-vite-muijoy-ink/src/routes/__root.tsx +4 -0
  18. package/template-react-vite-muijoy-ink/vite.config.ts +6 -0
  19. package/template-react-vite-muijoy-ink-tauri/.assetpack.ts +9 -0
  20. package/template-react-vite-muijoy-ink-tauri/.vscode/extensions.json +5 -1
  21. package/template-react-vite-muijoy-ink-tauri/.vscode/launch.json +11 -0
  22. package/template-react-vite-muijoy-ink-tauri/.vscode/settings.json +6 -1
  23. package/template-react-vite-muijoy-ink-tauri/.vscode/tasks.json +47 -0
  24. package/template-react-vite-muijoy-ink-tauri/README.md +3 -3
  25. package/template-react-vite-muijoy-ink-tauri/_github/workflows/desktop.yml +188 -0
  26. package/template-react-vite-muijoy-ink-tauri/_github/workflows/mobile.yml +270 -0
  27. package/template-react-vite-muijoy-ink-tauri/_gitignore +11 -0
  28. package/template-react-vite-muijoy-ink-tauri/ink/second_part.ink +571 -0
  29. package/template-react-vite-muijoy-ink-tauri/ink/start.ink +214 -0
  30. package/template-react-vite-muijoy-ink-tauri/package-lock.json +480 -4
  31. package/template-react-vite-muijoy-ink-tauri/package.json +13 -2
  32. package/template-react-vite-muijoy-ink-tauri/src/App.tsx +25 -25
  33. package/template-react-vite-muijoy-ink-tauri/src/assets/index.ts +2 -4
  34. package/template-react-vite-muijoy-ink-tauri/src/assets/ink-manifest.gen.json +4 -1
  35. package/template-react-vite-muijoy-ink-tauri/src/components/menus/main-menu.tsx +16 -1
  36. package/template-react-vite-muijoy-ink-tauri/src/components/menus/settings/quick-menus.tsx +17 -1
  37. package/template-react-vite-muijoy-ink-tauri/src/components/menus/settings/system-controls.tsx +11 -1
  38. package/template-react-vite-muijoy-ink-tauri/src/content/ink/hashtag-commands.ts +55 -0
  39. package/template-react-vite-muijoy-ink-tauri/src/content/ink/text-replaces.ts +19 -0
  40. package/template-react-vite-muijoy-ink-tauri/src/lib/hooks/ink-hooks.tsx +12 -0
  41. package/template-react-vite-muijoy-ink-tauri/src/lib/hooks/quit-hooks.ts +24 -0
  42. package/template-react-vite-muijoy-ink-tauri/src/lib/i18n.ts +22 -1
  43. package/template-react-vite-muijoy-ink-tauri/src/lib/query/settings-query.ts +7 -1
  44. package/template-react-vite-muijoy-ink-tauri/src/lib/steam.ts +143 -0
  45. package/template-react-vite-muijoy-ink-tauri/src/pixi-vn-keys.gen.d.ts +2 -0
  46. package/template-react-vite-muijoy-ink-tauri/src/routes/__root.tsx +4 -0
  47. package/template-react-vite-muijoy-ink-tauri/src-tauri/Cargo.toml +50 -0
  48. package/template-react-vite-muijoy-ink-tauri/src-tauri/build.rs +46 -0
  49. package/template-react-vite-muijoy-ink-tauri/src-tauri/capabilities/default.json +21 -0
  50. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/128x128.png +0 -0
  51. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/128x128@2x.png +0 -0
  52. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/32x32.png +0 -0
  53. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square107x107Logo.png +0 -0
  54. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square142x142Logo.png +0 -0
  55. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square150x150Logo.png +0 -0
  56. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square284x284Logo.png +0 -0
  57. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square30x30Logo.png +0 -0
  58. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square310x310Logo.png +0 -0
  59. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square44x44Logo.png +0 -0
  60. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square71x71Logo.png +0 -0
  61. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square89x89Logo.png +0 -0
  62. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/StoreLogo.png +0 -0
  63. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/icon.icns +0 -0
  64. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/icon.ico +0 -0
  65. package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/icon.png +0 -0
  66. package/template-react-vite-muijoy-ink-tauri/src-tauri/src/lib.rs +64 -0
  67. package/template-react-vite-muijoy-ink-tauri/src-tauri/src/main.rs +6 -0
  68. package/template-react-vite-muijoy-ink-tauri/src-tauri/src/steam.rs +238 -0
  69. package/template-react-vite-muijoy-ink-tauri/src-tauri/tauri.conf.json +50 -0
  70. package/template-react-vite-muijoy-ink-tauri/vite.config.ts +30 -0
  71. package/template-react-vite-muijoy-tauri/.assetpack.ts +9 -0
  72. package/template-react-vite-muijoy-tauri/.vscode/extensions.json +4 -1
  73. package/template-react-vite-muijoy-tauri/.vscode/launch.json +11 -0
  74. package/template-react-vite-muijoy-tauri/.vscode/tasks.json +47 -0
  75. package/template-react-vite-muijoy-tauri/README.md +3 -3
  76. package/template-react-vite-muijoy-tauri/_github/workflows/desktop.yml +188 -0
  77. package/template-react-vite-muijoy-tauri/_github/workflows/mobile.yml +270 -0
  78. package/template-react-vite-muijoy-tauri/_gitignore +10 -0
  79. package/template-react-vite-muijoy-tauri/package-lock.json +250 -0
  80. package/template-react-vite-muijoy-tauri/package.json +10 -1
  81. package/template-react-vite-muijoy-tauri/src/components/menus/main-menu.tsx +16 -1
  82. package/template-react-vite-muijoy-tauri/src/components/menus/settings/quick-menus.tsx +17 -1
  83. package/template-react-vite-muijoy-tauri/src/components/menus/settings/system-controls.tsx +11 -1
  84. package/template-react-vite-muijoy-tauri/src/lib/hooks/quit-hooks.ts +24 -0
  85. package/template-react-vite-muijoy-tauri/src/lib/query/settings-query.ts +7 -1
  86. package/template-react-vite-muijoy-tauri/src/lib/steam.ts +143 -0
  87. package/template-react-vite-muijoy-tauri/src-tauri/Cargo.toml +50 -0
  88. package/template-react-vite-muijoy-tauri/src-tauri/build.rs +46 -0
  89. package/template-react-vite-muijoy-tauri/src-tauri/capabilities/default.json +21 -0
  90. package/template-react-vite-muijoy-tauri/src-tauri/icons/128x128.png +0 -0
  91. package/template-react-vite-muijoy-tauri/src-tauri/icons/128x128@2x.png +0 -0
  92. package/template-react-vite-muijoy-tauri/src-tauri/icons/32x32.png +0 -0
  93. package/template-react-vite-muijoy-tauri/src-tauri/icons/Square107x107Logo.png +0 -0
  94. package/template-react-vite-muijoy-tauri/src-tauri/icons/Square142x142Logo.png +0 -0
  95. package/template-react-vite-muijoy-tauri/src-tauri/icons/Square150x150Logo.png +0 -0
  96. package/template-react-vite-muijoy-tauri/src-tauri/icons/Square284x284Logo.png +0 -0
  97. package/template-react-vite-muijoy-tauri/src-tauri/icons/Square30x30Logo.png +0 -0
  98. package/template-react-vite-muijoy-tauri/src-tauri/icons/Square310x310Logo.png +0 -0
  99. package/template-react-vite-muijoy-tauri/src-tauri/icons/Square44x44Logo.png +0 -0
  100. package/template-react-vite-muijoy-tauri/src-tauri/icons/Square71x71Logo.png +0 -0
  101. package/template-react-vite-muijoy-tauri/src-tauri/icons/Square89x89Logo.png +0 -0
  102. package/template-react-vite-muijoy-tauri/src-tauri/icons/StoreLogo.png +0 -0
  103. package/template-react-vite-muijoy-tauri/src-tauri/icons/icon.icns +0 -0
  104. package/template-react-vite-muijoy-tauri/src-tauri/icons/icon.ico +0 -0
  105. package/template-react-vite-muijoy-tauri/src-tauri/icons/icon.png +0 -0
  106. package/template-react-vite-muijoy-tauri/src-tauri/src/lib.rs +64 -0
  107. package/template-react-vite-muijoy-tauri/src-tauri/src/main.rs +6 -0
  108. package/template-react-vite-muijoy-tauri/src-tauri/src/steam.rs +238 -0
  109. package/template-react-vite-muijoy-tauri/src-tauri/tauri.conf.json +50 -0
  110. package/template-react-vite-muijoy-tauri/vite.config.ts +24 -0
  111. package/template-react-vite-muijoy-ink/src/content/labels/second.label.ts +0 -1207
  112. package/template-react-vite-muijoy-ink/src/content/labels/start.label.ts +0 -566
  113. package/template-react-vite-muijoy-ink-tauri/src/content/labels/second.label.ts +0 -1207
  114. package/template-react-vite-muijoy-ink-tauri/src/content/labels/start.label.ts +0 -566
@@ -1,7 +1,5 @@
1
1
  import generatedManifestJson from "@/assets/manifest.gen.json";
2
2
  import { AUDIO_BUNDLE_NAME } from "@/constants";
3
- import { secondPart } from "@/content/labels/second.label";
4
- import { startLabel } from "@/content/labels/start.label";
5
3
  import type { FileRouteTypes } from "@/routeTree.gen";
6
4
  import type { AssetsManifest } from "@drincs/pixi-vn";
7
5
 
@@ -37,7 +35,7 @@ export const manifest: AssetsManifest = {
37
35
  },
38
36
  // labels
39
37
  {
40
- name: startLabel.id,
38
+ name: "start",
41
39
  assets: [
42
40
  {
43
41
  alias: "bg01-hallway",
@@ -46,7 +44,7 @@ export const manifest: AssetsManifest = {
46
44
  ],
47
45
  },
48
46
  {
49
- name: secondPart.id,
47
+ name: "second_part",
50
48
  assets: [
51
49
  {
52
50
  alias: "bg02-dorm",
@@ -1 +1,4 @@
1
- []
1
+ [
2
+ "/ink-json/second_part.gen.json",
3
+ "/ink-json/start.gen.json"
4
+ ]
@@ -0,0 +1,38 @@
1
+ import { RegisteredCharacters } from "@drincs/pixi-vn";
2
+ import { HashtagCommands } from "@drincs/pixi-vn-ink";
3
+ import zod from "zod";
4
+
5
+ HashtagCommands.add(
6
+ async (script, { navigate }) => {
7
+ await navigate({ to: script[1] });
8
+ return true;
9
+ },
10
+ {
11
+ name: "navigate",
12
+ description: `Navigates to a specified route within the game.
13
+
14
+ \`\`\`ink
15
+ # navigate <route>
16
+ \`\`\``,
17
+ validation: zod.tuple([zod.literal("navigate"), zod.string()]),
18
+ },
19
+ );
20
+
21
+ HashtagCommands.add(
22
+ async (script) => {
23
+ const character = RegisteredCharacters.get(script[1]);
24
+ if (character) {
25
+ character.name = script[2];
26
+ }
27
+ return true;
28
+ },
29
+ {
30
+ name: "character rename",
31
+ description: `Renames a character in the game.
32
+
33
+ \`\`\`ink
34
+ # rename <characterId> <newName>
35
+ \`\`\``,
36
+ validation: zod.tuple([zod.literal("rename"), zod.string(), zod.string()]),
37
+ },
38
+ );
@@ -0,0 +1,19 @@
1
+ import { RegisteredCharacters } from "@drincs/pixi-vn";
2
+ import { TextReplaces } from "@drincs/pixi-vn-ink";
3
+
4
+ TextReplaces.add((key) => RegisteredCharacters.get(key)?.name, {
5
+ name: "character name",
6
+ validation: "characterId",
7
+ type: "after-translation",
8
+ i18nInterpolation: true,
9
+ description: "Replaces a character ID with the character's name in the game.",
10
+ });
11
+
12
+ TextReplaces.add(() => "Stephanie", {
13
+ name: "steph_fullname",
14
+ validation: /steph_fullname/,
15
+ type: "after-translation",
16
+ i18nInterpolation: true,
17
+ description:
18
+ "Replaces the placeholder 'steph_fullname' with the full name of the character Stephanie.",
19
+ });
@@ -0,0 +1,12 @@
1
+ import { onInkTranslate } from "@drincs/pixi-vn-ink";
2
+ import { useEffect } from "react";
3
+ import { useTranslation } from "react-i18next";
4
+
5
+ export default function useInkInitialization() {
6
+ const { t } = useTranslation(["narration"]);
7
+ useEffect(() => {
8
+ onInkTranslate(t);
9
+ }, [t]);
10
+
11
+ return null;
12
+ }
@@ -1,3 +1,4 @@
1
+ import { generateJsonInkTranslation } from "@drincs/pixi-vn-ink";
1
2
  import i18n, { type ReadCallback } from "i18next";
2
3
  import LanguageDetector from "i18next-browser-languagedetector";
3
4
  import ChainedBackend from "i18next-chained-backend";
@@ -44,9 +45,29 @@ function getLocalesResource(lng: string): Promise<Record<string, Record<string,
44
45
  return import(`./../locales/${lng}.json`);
45
46
  }
46
47
 
48
+ async function generateResourceToTranslate(lng: string): Promise<any> {
49
+ let res = await getLocalesResource(lng);
50
+ res = { ...res };
51
+ if (!res) {
52
+ res = {};
53
+ }
54
+ if (!res.narration) {
55
+ res.narration = {};
56
+ }
57
+ if (res.default) {
58
+ delete res.default;
59
+ }
60
+ const manifest = await import("@/assets/ink-manifest.gen.json");
61
+ for (const path of manifest.default) {
62
+ const element = await fetch(path).then((r) => r.json());
63
+ element && (await generateJsonInkTranslation(element, res.narration));
64
+ }
65
+ return res;
66
+ }
67
+
47
68
  export async function downloadResourceToTranslate() {
48
69
  const lng = i18n.options.fallbackLng?.toString() || "en";
49
- const data = await getLocalesResource(lng);
70
+ const data = await generateResourceToTranslate(lng);
50
71
  const jsonString = JSON.stringify(data);
51
72
  // download the save data as a JSON file
52
73
  const blob = new Blob([jsonString], { type: "application/json" });
@@ -15,6 +15,8 @@ declare module "@drincs/pixi-vn/narration" {
15
15
  "animation_01": never;
16
16
  "second_part": never;
17
17
  "start": never;
18
+ "start_|_c-0": never;
19
+ "start_|_c-1": never;
18
20
  }
19
21
  }
20
22
  export {};
@@ -3,6 +3,7 @@ import { SettingsDialogue } from "@/components/menus/settings";
3
3
  import { OfflineAllert } from "@/components/modals/error-allerts";
4
4
  import { RootProvider } from "@/components/providers/root-provider";
5
5
  import { INTERFACE_DATA_USE_QUERY_KEY } from "@/constants";
6
+ import useInkInitialization from "@/lib/hooks/ink-hooks";
6
7
  import { useConfirmBackNavigation } from "@/lib/hooks/navigation-hooks";
7
8
  import { useAutoSaveOnPageClose } from "@/lib/hooks/save-hooks";
8
9
  import { useI18n } from "@/lib/i18n";
@@ -11,6 +12,7 @@ import { defineAssets } from "@/lib/utils/assets-utility";
11
12
  import { initializeIndexedDB } from "@/lib/utils/db-utility";
12
13
  import { loadRefreshSave } from "@/lib/utils/save-utility";
13
14
  import type { RouterContext } from "@/router";
15
+ import { setupInkHmrListener } from "@drincs/pixi-vn-ink/vite-listener";
14
16
  import { setupPixivnViteData } from "@drincs/pixi-vn/vite-listener";
15
17
  import { TanStackDevtools } from "@tanstack/react-devtools";
16
18
  import { hotkeysDevtoolsPlugin } from "@tanstack/react-hotkeys-devtools";
@@ -26,6 +28,7 @@ export const Route = createRootRouteWithContext<RouterContext>()({
26
28
  // Game.onNavigate(async (to) => redirect({ to }));
27
29
  await Promise.all([import("@/content"), initializeIndexedDB(), defineAssets(), useI18n()]);
28
30
  await setupPixivnViteData();
31
+ await setupInkHmrListener();
29
32
  if (location.pathname !== "/") {
30
33
  const isRefreshSaveExist = await loadRefreshSave();
31
34
  if (isRefreshSaveExist) {
@@ -43,6 +46,7 @@ export const Route = createRootRouteWithContext<RouterContext>()({
43
46
  });
44
47
 
45
48
  function RootComponent() {
49
+ useInkInitialization();
46
50
  useAutoSaveOnPageClose();
47
51
  useConfirmBackNavigation();
48
52
 
@@ -1,4 +1,5 @@
1
1
  import { AssetPack } from "@assetpack/core";
2
+ import { vitePluginInk } from "@drincs/pixi-vn-ink/vite";
2
3
  import { vitePluginPixivn } from "@drincs/pixi-vn/vite";
3
4
  import tailwindcss from "@tailwindcss/vite";
4
5
  import { devtools } from "@tanstack/devtools-vite";
@@ -37,6 +38,11 @@ export default defineConfig(({ mode }) => ({
37
38
  labels: "./src/content/labels/*.label.ts",
38
39
  typeFilePath: "./src/pixi-vn-keys.gen.d.ts",
39
40
  }),
41
+ vitePluginInk({
42
+ inkGlob: "./ink/**/*.ink",
43
+ inkJsonOutputPattern: "./public/ink-json/[path][name].gen.json",
44
+ inkJsonManifestPath: "./src/assets/ink-manifest.gen.json",
45
+ }),
40
46
  VitePWA({
41
47
  // generate icons with: npm run icon
42
48
  includeAssets: ["favicon.ico", "apple-touch-icon-180x180.png"],
@@ -1,6 +1,9 @@
1
1
  import type { AssetPackConfig } from "@assetpack/core";
2
2
  import { pixiPipes } from "@assetpack/core/pixi";
3
3
 
4
+ // TAURI_ENV_TARGET_TRIPLE is set by `tauri build` before running beforeBuildCommand
5
+ const isTauri = !!process.env.TAURI_ENV_TARGET_TRIPLE;
6
+
4
7
  const config: AssetPackConfig = {
5
8
  entry: "./src/assets",
6
9
  output: "./public/assets",
@@ -11,6 +14,12 @@ const config: AssetPackConfig = {
11
14
  output: "src/assets/manifest.gen.json",
12
15
  createShortcuts: true,
13
16
  },
17
+ // For Tauri: skip @0.5x mipmaps (unused on desktop, WebView handles DPR)
18
+ resolutions: isTauri ? { default: 1 } : undefined,
19
+ // For Tauri: raise WebP quality — files are local so bandwidth is not a concern
20
+ compression: isTauri
21
+ ? { png: true, jpg: true, webp: { quality: 88, alphaQuality: 88 } }
22
+ : undefined,
14
23
  }),
15
24
  ],
16
25
  };
@@ -3,6 +3,10 @@
3
3
  "ms-vscode.vscode-typescript-next",
4
4
  "anseki.vscode-color",
5
5
  "pflannery.vscode-versionlens",
6
- "biomejs.biome"
6
+ "biomejs.biome",
7
+ "drincs-productions.pixi-vn-ink-vscode",
8
+ "tauri-apps.tauri-vscode",
9
+ "rust-lang.rust-analyzer",
10
+ "vadimcn.vscode-lldb"
7
11
  ]
8
12
  }
@@ -17,6 +17,17 @@
17
17
  "webRoot": "${workspaceFolder}",
18
18
  "preLaunchTask": "Restart Vite Dev Server"
19
19
  },
20
+ {
21
+ "type": "lldb",
22
+ "request": "launch",
23
+ "name": "Run as Desktop App (Dev)",
24
+ "program": "${workspaceFolder}/src-tauri/target/debug/my-app-package-name",
25
+ "args": [],
26
+ "cwd": "${workspaceFolder}",
27
+ "terminal": "console",
28
+ "preLaunchTask": "Cargo Build (Desktop Dev)",
29
+ "postDebugTask": "Stop Vite Desktop Server"
30
+ },
20
31
  {
21
32
  "name": "Debug Game Preview",
22
33
  "request": "launch",
@@ -55,5 +55,10 @@
55
55
  // does fetch when he does Pull
56
56
  "git.fetchOnPull": true,
57
57
  // move file
58
- "js/ts.updateImportsOnFileMove.enabled": "always"
58
+ "js/ts.updateImportsOnFileMove.enabled": "always",
59
+ // ink
60
+ "ink.mainFile": "start.ink",
61
+ "ink.rootFolder": "ink",
62
+ "ink.markup": "Markdown",
63
+ "ink.engine": "pixi-vn"
59
64
  }
@@ -101,6 +101,53 @@
101
101
  "panel": "dedicated",
102
102
  "close": true
103
103
  }
104
+ },
105
+ {
106
+ "label": "Cargo Build (Desktop Dev)",
107
+ "type": "shell",
108
+ "command": "cargo build --manifest-path=./src-tauri/Cargo.toml --no-default-features",
109
+ "dependsOn": ["Start Vite Desktop Server"],
110
+ "presentation": {
111
+ "reveal": "always",
112
+ "panel": "dedicated",
113
+ "clear": true,
114
+ "close": true
115
+ },
116
+ "problemMatcher": ["$rustc"]
117
+ },
118
+ {
119
+ "label": "Start Vite Desktop Server",
120
+ "type": "shell",
121
+ "command": "npm run dev",
122
+ "isBackground": true,
123
+ "dependsOn": ["Install Dependencies"],
124
+ "problemMatcher": {
125
+ "owner": "vite",
126
+ "pattern": {
127
+ "regexp": "^(?!x)x"
128
+ },
129
+ "background": {
130
+ "activeOnStart": true,
131
+ "beginsPattern": ".",
132
+ "endsPattern": "localhost:5173"
133
+ }
134
+ },
135
+ "presentation": {
136
+ "reveal": "always",
137
+ "panel": "dedicated",
138
+ "clear": false,
139
+ "close": true
140
+ }
141
+ },
142
+ {
143
+ "label": "Stop Vite Desktop Server",
144
+ "type": "shell",
145
+ "command": "pkill -f 'vite' 2>/dev/null; pkill -f 'npm run dev' 2>/dev/null; exit 0",
146
+ "presentation": {
147
+ "reveal": "never",
148
+ "panel": "dedicated",
149
+ "close": true
150
+ }
104
151
  }
105
152
  ]
106
153
  }
@@ -1,3 +1,3 @@
1
- # my-app-project-name
2
-
3
- my-app-description
1
+ # my-app-project-name
2
+
3
+ my-app-description
@@ -0,0 +1,188 @@
1
+ name: 'Build & Publish Desktop App'
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ # ── Create the release exactly once before the matrix starts ────────────────
10
+ create-release:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: write
14
+ outputs:
15
+ release_tag: ${{ github.ref_name }}
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: create release
20
+ run: |
21
+ gh release view "${{ github.ref_name }}" 2>/dev/null || \
22
+ gh release create "${{ github.ref_name }}" \
23
+ --title "App v$(jq -r '.version' src-tauri/tauri.conf.json)" \
24
+ --notes "See the assets to download this version and install." \
25
+ 2>/dev/null || \
26
+ gh release view "${{ github.ref_name }}" > /dev/null
27
+ env:
28
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29
+
30
+ # ── Build and upload per platform ───────────────────────────────────────────
31
+ publish-tauri:
32
+ needs: create-release
33
+ permissions:
34
+ contents: write
35
+ strategy:
36
+ fail-fast: false
37
+ matrix:
38
+ include:
39
+ - platform: 'macos-latest'
40
+ args: '--target aarch64-apple-darwin'
41
+ target: 'aarch64-apple-darwin'
42
+ arch: 'aarch64'
43
+ - platform: 'macos-latest'
44
+ args: '--target x86_64-apple-darwin'
45
+ target: 'x86_64-apple-darwin'
46
+ arch: 'x86_64'
47
+ - platform: 'ubuntu-22.04'
48
+ args: ''
49
+ target: ''
50
+ arch: 'x64'
51
+ - platform: 'windows-latest'
52
+ args: ''
53
+ target: ''
54
+ arch: 'x64'
55
+
56
+ runs-on: ${{ matrix.platform }}
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+
60
+ - name: setup node
61
+ uses: actions/setup-node@v6
62
+ with:
63
+ node-version: lts/*
64
+
65
+ - name: install Rust stable
66
+ uses: dtolnay/rust-toolchain@stable
67
+ with:
68
+ targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
69
+
70
+ - name: install dependencies (ubuntu only)
71
+ if: matrix.platform == 'ubuntu-22.04'
72
+ run: |
73
+ sudo apt-get update
74
+ sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
75
+
76
+ - name: install frontend dependencies
77
+ run: npm i
78
+
79
+ - name: build app
80
+ uses: tauri-apps/tauri-action@v0
81
+ env:
82
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
83
+ with:
84
+ args: ${{ matrix.args }}
85
+
86
+ # ── Linux: .deb + .AppImage (AppImage is already portable) ─────────────
87
+ - name: upload artifacts (Linux)
88
+ if: matrix.platform == 'ubuntu-22.04'
89
+ env:
90
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
91
+ TAG: ${{ needs.create-release.outputs.release_tag }}
92
+ run: |
93
+ upload_file() {
94
+ local file="$1"
95
+ local limit=$((1900 * 1024 * 1024))
96
+ local size; size=$(stat -c%s "$file")
97
+ if [ "$size" -gt "$limit" ]; then
98
+ echo "Splitting $(basename "$file") (${size} bytes) into 1.9 GB parts..."
99
+ split -b 1900m "$file" "${file}.part"
100
+ for part in "${file}.part"*; do
101
+ gh release upload "$TAG" "$part" --clobber
102
+ done
103
+ else
104
+ gh release upload "$TAG" "$file" --clobber
105
+ fi
106
+ }
107
+ find src-tauri/target/release/bundle -type f \
108
+ \( -name "*.deb" -o -name "*.AppImage" -o -name "*.rpm" \) |
109
+ while IFS= read -r f; do upload_file "$f"; done
110
+
111
+ # ── macOS: .dmg installer + portable .app.tar.gz ───────────────────────
112
+ - name: upload artifacts (macOS)
113
+ if: matrix.platform == 'macos-latest'
114
+ env:
115
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
116
+ TAG: ${{ needs.create-release.outputs.release_tag }}
117
+ run: |
118
+ BIN_NAME=$(grep '^name = ' src-tauri/Cargo.toml | head -1 | cut -d'"' -f2)
119
+ VERSION=$(jq -r '.version' src-tauri/tauri.conf.json)
120
+ ARCH="${{ matrix.arch }}"
121
+ BUNDLE_DIR="src-tauri/target/${{ matrix.target }}/release/bundle"
122
+
123
+ upload_file() {
124
+ local file="$1"
125
+ local limit=$((1900 * 1024 * 1024))
126
+ local size; size=$(stat -f%z "$file")
127
+ if [ "$size" -gt "$limit" ]; then
128
+ echo "Splitting $(basename "$file") (${size} bytes) into 1.9 GB parts..."
129
+ split -b 1900m "$file" "${file}.part"
130
+ for part in "${file}.part"*; do
131
+ gh release upload "$TAG" "$part" --clobber
132
+ done
133
+ else
134
+ gh release upload "$TAG" "$file" --clobber
135
+ fi
136
+ }
137
+
138
+ # DMG installer
139
+ find "$BUNDLE_DIR/dmg" -name "*.dmg" |
140
+ while IFS= read -r f; do upload_file "$f"; done
141
+
142
+ # Portable: bundle .app into a tar.gz
143
+ APP_PATH=$(find "$BUNDLE_DIR/macos" -maxdepth 1 -name "*.app" | head -1)
144
+ PORTABLE="${BIN_NAME}_${VERSION}_macos_${ARCH}-portable.tar.gz"
145
+ tar -czf "$PORTABLE" -C "$(dirname "$APP_PATH")" "$(basename "$APP_PATH")"
146
+ upload_file "$PORTABLE"
147
+
148
+ # ── Windows: NSIS/.msi installers + portable .zip ──────────────────────
149
+ - name: upload artifacts (Windows)
150
+ if: matrix.platform == 'windows-latest'
151
+ shell: pwsh
152
+ env:
153
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
154
+ run: |
155
+ $tag = "${{ needs.create-release.outputs.release_tag }}"
156
+ $ver = (Get-Content src-tauri/tauri.conf.json | ConvertFrom-Json).version
157
+ $name = (Select-String -Path src-tauri/Cargo.toml `
158
+ -Pattern '^name = "(.+)"').Matches[0].Groups[1].Value
159
+
160
+ function Upload-File($Path, $Tag) {
161
+ $limitBytes = 1900 * 1MB
162
+ $item = Get-Item $Path
163
+ if ($item.Length -gt $limitBytes) {
164
+ Write-Host "Splitting $($item.Name) ($($item.Length) bytes) into 1.9 GB parts..."
165
+ $stream = [System.IO.File]::OpenRead($Path)
166
+ $buf = New-Object byte[] $limitBytes
167
+ $i = 0
168
+ while (($n = $stream.Read($buf, 0, $buf.Length)) -gt 0) {
169
+ $part = "$Path.part$($i.ToString('D3'))"
170
+ $data = if ($n -eq $buf.Length) { $buf } else { $buf[0..($n - 1)] }
171
+ [System.IO.File]::WriteAllBytes($part, $data)
172
+ gh release upload $Tag $part --clobber
173
+ $i++
174
+ }
175
+ $stream.Dispose()
176
+ } else {
177
+ gh release upload $Tag $Path --clobber
178
+ }
179
+ }
180
+
181
+ # NSIS and MSI installers
182
+ Get-ChildItem -Recurse src-tauri/target/release/bundle -Include "*.exe","*.msi" |
183
+ ForEach-Object { Upload-File $_.FullName $tag }
184
+
185
+ # Portable ZIP (single EXE, no installer)
186
+ $zip = "${name}_${ver}_windows_x64-portable.zip"
187
+ Compress-Archive -Path "src-tauri/target/release/$name.exe" -DestinationPath $zip
188
+ Upload-File $zip $tag