nanoshell 1.2.3 → 1.7.2

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.
package/README.md CHANGED
@@ -14,44 +14,80 @@
14
14
  - **Executable Size**: **3.00 MB** Self-Contained Binary
15
15
  - **IPC Latency**: **0.00 ms** Zero-Copy Shared Memory Matrix across Python/C++/Rust
16
16
  - **CSS Engine**: Universal Dynamic CSS Flex/Grid Gap Engine (0 hardcoded class names)
17
- - **Display Scaling**: Native 200% High-DPI Monitor Scale Auto-Detection
17
+ # NanoShell (v1.5.0)
18
18
 
19
- ---
19
+ > **Created by Suman Biswas**
20
+ > *Hyper-lightweight 17MB RAM, 120 FPS Native WebKit Desktop Application Framework & Runtime Engine*
20
21
 
21
- ## 📦 Quick Start
22
+ NanoShell is an ultra-fast, zero-overhead desktop application engine built with **Zig** and **Ultralight GPU-Accelerated WebKit C++**. It allows web developers to build native desktop applications using HTML, CSS, and Vanilla JavaScript with **17MB RSS RAM footprint**, **120 FPS performance**, and **zero-copy C-level OS bindings**.
22
23
 
23
- ### Create App from Template
24
+ ---
24
25
 
25
- To scaffold a new native desktop app from template:
26
+ ## 🚀 Quick Start
26
27
 
27
28
  ```bash
29
+ # 1. Scaffold a new application project
28
30
  npx nanoshell my-awesome-app
29
- ```
30
31
 
31
- ### Run Application
32
-
33
- ```bash
32
+ # 2. Start Development Mode (In-Window Hot Reloading on Ctrl+S)
34
33
  cd my-awesome-app
35
- npm start
36
- ```
34
+ npx nanoshell start
37
35
 
38
- ### Build Production Binary
39
-
40
- ```bash
36
+ # 3. Build Standalone Production Binary (.exe)
41
37
  npx nanoshell build
38
+
39
+ # 4. Package Windows Installer (.exe + Setup.exe via Inno Setup)
40
+ npx nanoshell package
42
41
  ```
43
42
 
44
- Build production release binary only. Generates `dist/my-awesome-app.exe` (3.00 MB, 17.0 MB RAM native executable)!
43
+ ---
45
44
 
46
- ### Generate Setup Installer (.exe)
45
+ ## 📖 Master JavaScript API Reference (`window.NanoShell`)
47
46
 
48
- ```bash
49
- npx nanoshell package
50
- ```
47
+ ### 📁 File System (`NanoShell.fs`)
48
+ - `NanoShell.fs.readFile(path)`: Read text file contents.
49
+ - `NanoShell.fs.writeFile(path, content)`: Write text file to disk.
50
+ - `NanoShell.fs.exists(path)`: Check file/directory existence.
51
+ - `NanoShell.fs.readDir(path)`: List directory folder contents.
52
+ - `NanoShell.fs.mkdir(path)`: Create directory folder.
53
+ - `NanoShell.fs.remove(path)`: Delete file or directory.
54
+
55
+ ### 💻 System & OS (`NanoShell.os`)
56
+ - `NanoShell.os.getInfo()`: Get platform, arch (`x64`), core count, and RAM telemetry.
57
+
58
+ ### ⚙️ Shell & Execution (`NanoShell.shell` & `NanoShell.process`)
59
+ - `NanoShell.shell.openExternal(urlOrPath)`: Open URL or file in default OS application.
60
+ - `NanoShell.shell.exec(command)`: Execute CLI command (PowerShell/CMD).
61
+ - `NanoShell.process.list()`: Task Manager process list.
62
+
63
+ ### 🪟 Window & Screen Controls (`NanoShell.window` & `NanoShell.screen`)
64
+ - `NanoShell.window.minimize()`, `maximize()`, `restore()`, `close()`, `center()`, `setTitle()`, `setFullscreen()`.
65
+ - `NanoShell.screen.getMonitors()`: List connected monitors, resolutions, and refresh rates.
66
+ - `NanoShell.screen.getCursorPosition()`: Global mouse desktop coordinates `(x, y)`.
67
+
68
+ ### 📋 Clipboard (`NanoShell.clipboard`)
69
+ - `NanoShell.clipboard.writeText(text)`: Copy text to system clipboard.
70
+ - `NanoShell.clipboard.readText()`: Paste text from system clipboard.
71
+
72
+ ### 💬 OS Dialogs (`NanoShell.dialog`)
73
+ - `NanoShell.dialog.showOpen()`: Native Open File Picker dialog.
74
+ - `NanoShell.dialog.showSave()`: Native Save File Picker dialog.
75
+ - `NanoShell.dialog.showMessage(title, message)`: Native OS Alert message box.
76
+
77
+ ### 🔔 Toast Notifications (`NanoShell.notification`)
78
+ - `NanoShell.notification.show(title, body)`: Trigger native OS Toast notification.
79
+
80
+ ### 🔋 Power & Battery (`NanoShell.power`)
81
+ - `NanoShell.power.getBatteryStatus()`: Battery %, charging status, AC power.
82
+
83
+ ### ⚡ Shared Memory & Snapshot (`NanoShell.shm` & `NanoShell.snapshot`)
84
+ - `NanoShell.shm.createRegion(name, size)`: Zero-copy C RAM allocation (< 0.01ms IPC).
85
+ - `NanoShell.snapshot.thawState()`: < 1ms instant cold-start thaw engine.
86
+
87
+ ---
51
88
 
52
- Build binary and generate Windows installer (`dist/MyApp-Setup.exe` powered by **Inno Setup**)!
53
- - Provides user choice: **"Install for all users (Admin)"** vs **"Install for me only (Per-User, No Admin)"**
54
- - High-ratio LZMA2 compression for ultra-compact setup installers
89
+ ## 📦 100% Portable Bundle
90
+ Every scaffolded NanoShell app includes portable Visual C++ runtime DLLs (`vcruntime140.dll`, `msvcp140.dll`, `vcruntime140_1.dll`) and is compiled against `x86_64-windows-gnu` baseline CPU targets — ensuring **100% portable out-of-the-box execution on any Windows laptop without admin rights or external installers**.
55
91
  - Automatic Start Menu & Desktop shortcuts
56
92
 
57
93
 
package/cli/bundler.zig CHANGED
@@ -34,31 +34,73 @@ pub const SingleBinaryBundler = struct {
34
34
 
35
35
  const cwd = std.Io.Dir.cwd();
36
36
 
37
- // Copy Main Executable bin/<app_name>.exe -> dist/<app_name>.exe
38
- const src_exe_path = try std.fmt.allocPrint(self.allocator, "bin/{s}.exe", .{self.config.app_name});
39
- defer self.allocator.free(src_exe_path);
37
+ // Copy Main Executable (search zig-out/bin, bin, root, example_app.exe)
38
+ const possible_srcs = [_][]const u8{
39
+ "zig-out/bin/example_app.exe",
40
+ "example_app.exe",
41
+ "bin/example_app.exe",
42
+ try std.fmt.allocPrint(self.allocator, "bin/{s}.exe", .{self.config.app_name}),
43
+ try std.fmt.allocPrint(self.allocator, "{s}.exe", .{self.config.app_name}),
44
+ };
45
+ const dst_exe_name = try std.fmt.allocPrint(self.allocator, "{s}.exe", .{self.config.app_name});
46
+ defer self.allocator.free(dst_exe_name);
40
47
  const dst_exe_path = try std.fmt.allocPrint(self.allocator, "{s}/{s}.exe", .{ self.config.output_dir, self.config.app_name });
41
48
  defer self.allocator.free(dst_exe_path);
42
49
 
43
- _ = cwd.copyFile(src_exe_path, dist_dir, try std.fmt.allocPrint(self.allocator, "{s}.exe", .{self.config.app_name}), io, .{}) catch |err| {
44
- std.log.warn("Executable copy warning: {s}", .{@errorName(err)});
45
- };
50
+ var copied = false;
51
+ for (possible_srcs) |src| {
52
+ if (cwd.copyFile(src, dist_dir, dst_exe_name, io, .{})) |_| {
53
+ copied = true;
54
+ break;
55
+ } else |_| {}
56
+ }
57
+ if (!copied) {
58
+ std.log.warn("Executable copy warning: Could not locate baseline executable binary", .{});
59
+ }
46
60
 
47
- // Copy DLLs
61
+ // Copy DLLs to dist/ (search vendor/lib, zig-out/bin, and root)
48
62
  const dlls = [_][]const u8{ "AppCore.dll", "Ultralight.dll", "UltralightCore.dll", "WebCore.dll", "vcruntime140.dll", "msvcp140.dll", "vcruntime140_1.dll" };
49
63
  for (dlls) |dll| {
50
- const src_dll = try std.fmt.allocPrint(self.allocator, "bin/{s}", .{dll});
51
- defer self.allocator.free(src_dll);
52
- _ = cwd.copyFile(src_dll, dist_dir, dll, io, .{}) catch {};
64
+ const possible_dll_srcs = [_][]const u8{
65
+ try std.fmt.allocPrint(self.allocator, "vendor/lib/{s}", .{dll}),
66
+ try std.fmt.allocPrint(self.allocator, "zig-out/bin/{s}", .{dll}),
67
+ try std.fmt.allocPrint(self.allocator, "bin/{s}", .{dll}),
68
+ dll,
69
+ };
70
+ defer for (possible_dll_srcs) |p| self.allocator.free(p);
71
+
72
+ const dst_dll = try std.fmt.allocPrint(self.allocator, "{s}/{s}", .{ self.config.output_dir, dll });
73
+ defer self.allocator.free(dst_dll);
74
+
75
+ for (possible_dll_srcs) |src_dll| {
76
+ if (copyFileSimple(src_dll, dst_dll)) {
77
+ break;
78
+ }
79
+ }
53
80
  }
54
81
 
55
- // Copy Resource Files
82
+ // Copy Resource Files to dist/ and dist/resources/
56
83
  const res_files = [_][]const u8{ "icudt67l.dat", "cacert.pem" };
57
84
  for (res_files) |file| {
58
- const src_res = try std.fmt.allocPrint(self.allocator, "bin/{s}", .{file});
59
- defer self.allocator.free(src_res);
60
- _ = cwd.copyFile(src_res, dist_dir, file, io, .{}) catch {};
61
- _ = cwd.copyFile(src_res, dist_dir, try std.fmt.allocPrint(self.allocator, "resources/{s}", .{file}), io, .{}) catch {};
85
+ const possible_res_srcs = [_][]const u8{
86
+ try std.fmt.allocPrint(self.allocator, "vendor/resources/{s}", .{file}),
87
+ try std.fmt.allocPrint(self.allocator, "resources/{s}", .{file}),
88
+ try std.fmt.allocPrint(self.allocator, "zig-out/bin/resources/{s}", .{file}),
89
+ try std.fmt.allocPrint(self.allocator, "bin/{s}", .{file}),
90
+ };
91
+ defer for (possible_res_srcs) |p| self.allocator.free(p);
92
+
93
+ const dst_res1 = try std.fmt.allocPrint(self.allocator, "{s}/{s}", .{ self.config.output_dir, file });
94
+ defer self.allocator.free(dst_res1);
95
+ const dst_res2 = try std.fmt.allocPrint(self.allocator, "{s}/resources/{s}", .{ self.config.output_dir, file });
96
+ defer self.allocator.free(dst_res2);
97
+
98
+ for (possible_res_srcs) |src_res| {
99
+ if (copyFileSimple(src_res, dst_res1)) {
100
+ _ = copyFileSimple(src_res, dst_res2);
101
+ break;
102
+ }
103
+ }
62
104
  }
63
105
 
64
106
  // Copy app/* files to dist/app/*
@@ -78,3 +120,9 @@ pub const SingleBinaryBundler = struct {
78
120
  std.log.info("Built Custom Named Executable -> '{s}' (Self-contained release package)", .{dst_exe_path});
79
121
  }
80
122
  };
123
+
124
+ fn copyFileSimple(src: []const u8, dst: []const u8) bool {
125
+ const io = std.Io.Threaded.global_single_threaded.io();
126
+ std.Io.Dir.cwd().copyFile(src, std.Io.Dir.cwd(), dst, io, .{}) catch return false;
127
+ return true;
128
+ }
@@ -1,4 +1,5 @@
1
1
  const std = @import("std");
2
+ const installer = @import("installer.zig");
2
3
 
3
4
  pub const DevServer = struct {
4
5
  allocator: std.mem.Allocator,
@@ -8,14 +9,184 @@ pub const DevServer = struct {
8
9
  }
9
10
 
10
11
  pub fn runDevMode(self: *DevServer, app_dir_name: []const u8) !void {
12
+ _ = app_dir_name;
11
13
  std.log.info("=================================================================", .{});
12
- std.log.info(" ⚡ NanoShell Hot-Reload Dev Engine Started for: {s}", .{app_dir_name});
13
- std.log.info(" Watching app/ directory for UI changes...", .{});
14
+ std.log.info(" ⚡ NanoShell Dev Server Started", .{});
15
+ std.log.info(" Watching app/ directory & nanoshell.json for live changes...", .{});
14
16
  std.log.info("=================================================================", .{});
15
17
 
16
- const exe_path = try std.fmt.allocPrint(self.allocator, "{s}/bin/{s}.exe", .{ app_dir_name, app_dir_name });
17
- defer self.allocator.free(exe_path);
18
+ var config = installer.loadConfig(self.allocator) catch installer.AppConfig{};
19
+ defer config.deinit(self.allocator);
18
20
 
19
- std.log.info("Dev Server active for '{s}'. File watcher operational.", .{exe_path});
21
+ // Find executable inside bin/ or zig-out/bin/
22
+ const io = std.Io.Threaded.global_single_threaded.io();
23
+ const cwd = std.Io.Dir.cwd();
24
+
25
+ var found_exe: ?[]const u8 = null;
26
+
27
+ const candidate_paths = [_][]const u8{
28
+ "zig-out/bin/example_app.exe",
29
+ "bin/example_app.exe",
30
+ "zig-out/bin/nanoshell.exe",
31
+ };
32
+
33
+ for (candidate_paths) |p| {
34
+ if (cwd.openFile(io, p, .{})) |f| {
35
+ f.close(io);
36
+ found_exe = p;
37
+ break;
38
+ } else |_| {}
39
+ }
40
+
41
+ if (found_exe == null) {
42
+ // Search bin/ for any .exe
43
+ var bin_dir = cwd.openDir(io, "bin", .{ .iterate = true }) catch null;
44
+ if (bin_dir) |*d| {
45
+ defer d.close(io);
46
+ var iter = d.iterate();
47
+ while (iter.next(io) catch null) |entry| {
48
+ if (entry.kind == .file and std.mem.endsWith(u8, entry.name, ".exe")) {
49
+ found_exe = try std.fmt.allocPrint(self.allocator, "bin/{s}", .{entry.name});
50
+ break;
51
+ }
52
+ }
53
+ }
54
+ }
55
+
56
+ var win_exe_buf: [256]u8 = undefined;
57
+ const exe_to_run = found_exe orelse "bin\\app.exe";
58
+ var pos: usize = 0;
59
+ for (exe_to_run) |ch| {
60
+ if (ch == '/') {
61
+ win_exe_buf[pos] = '\\';
62
+ } else {
63
+ win_exe_buf[pos] = ch;
64
+ }
65
+ pos += 1;
66
+ }
67
+ win_exe_buf[pos] = 0;
68
+ const win_path = win_exe_buf[0..pos];
69
+
70
+ var dev_cmd_buf: [300]u8 = undefined;
71
+ const dev_cmd = std.fmt.bufPrintZ(&dev_cmd_buf, "{s} --dev", .{win_path}) catch win_path;
72
+
73
+ std.log.info("Launching NanoShell runtime in DEV mode: {s}", .{dev_cmd});
74
+
75
+ // Launch app process once - native engine handles smooth in-window hot reload in dev mode
76
+ var child = try self.spawnChildProcess(dev_cmd);
77
+ defer _ = child.kill();
78
+
79
+ std.log.info("App running! In-window hot reload active for app/index.html, styles.css, app.js.", .{});
80
+
81
+ const WinApi = struct {
82
+ pub extern "kernel32" fn Sleep(dwMilliseconds: u32) callconv(.winapi) void;
83
+ pub extern "kernel32" fn GetExitCodeProcess(hProcess: std.os.windows.HANDLE, lpExitCode: *u32) callconv(.winapi) i32;
84
+ };
85
+
86
+ var exit_code: u32 = 259; // STILL_ACTIVE
87
+ while (exit_code == 259) {
88
+ WinApi.Sleep(500);
89
+ _ = WinApi.GetExitCodeProcess(child.hProcess, &exit_code);
90
+ }
91
+ }
92
+
93
+ fn spawnChildProcess(self: *DevServer, exe_path: []const u8) !ChildProcess {
94
+ _ = self;
95
+ var cmd_utf16: [1024]u16 = undefined;
96
+ const len = try std.unicode.utf8ToUtf16Le(&cmd_utf16, exe_path);
97
+ cmd_utf16[len] = 0;
98
+
99
+ const STARTUPINFOW = extern struct {
100
+ cb: u32 = 104,
101
+ lpReserved: ?[*:0]u16 = null,
102
+ lpDesktop: ?[*:0]u16 = null,
103
+ lpTitle: ?[*:0]u16 = null,
104
+ dwX: u32 = 0,
105
+ dwY: u32 = 0,
106
+ dwXSize: u32 = 0,
107
+ dwYSize: u32 = 0,
108
+ dwXCountChars: u32 = 0,
109
+ dwYCountChars: u32 = 0,
110
+ dwFillAttribute: u32 = 0,
111
+ dwFlags: u32 = 0,
112
+ wShowWindow: u16 = 0,
113
+ cbReserved2: u16 = 0,
114
+ lpReserved2: ?*u8 = null,
115
+ hStdInput: ?std.os.windows.HANDLE = null,
116
+ hStdOutput: ?std.os.windows.HANDLE = null,
117
+ hStdError: ?std.os.windows.HANDLE = null,
118
+ };
119
+
120
+ const PROCESS_INFORMATION = extern struct {
121
+ hProcess: std.os.windows.HANDLE,
122
+ hThread: std.os.windows.HANDLE,
123
+ dwProcessId: u32,
124
+ dwThreadId: u32,
125
+ };
126
+
127
+ const WinApi = struct {
128
+ pub extern "kernel32" fn CreateProcessW(
129
+ lpApplicationName: ?[*:0]const u16,
130
+ lpCommandLine: ?[*:0]u16,
131
+ lpProcessAttributes: ?*anyopaque,
132
+ lpThreadAttributes: ?*anyopaque,
133
+ bInheritHandles: i32,
134
+ dwCreationFlags: u32,
135
+ lpEnvironment: ?*anyopaque,
136
+ lpCurrentDirectory: ?[*:0]const u16,
137
+ lpStartupInfo: *const STARTUPINFOW,
138
+ lpProcessInformation: *PROCESS_INFORMATION,
139
+ ) callconv(.winapi) i32;
140
+
141
+ pub extern "kernel32" fn TerminateProcess(hProcess: std.os.windows.HANDLE, uExitCode: u32) callconv(.winapi) i32;
142
+ pub extern "kernel32" fn CloseHandle(hObject: std.os.windows.HANDLE) callconv(.winapi) i32;
143
+ };
144
+
145
+ var si = STARTUPINFOW{};
146
+ var pi: PROCESS_INFORMATION = undefined;
147
+
148
+ const res = WinApi.CreateProcessW(null, @ptrCast(&cmd_utf16), null, null, 0, 0, null, null, &si, &pi);
149
+ if (res == 0) return error.ProcessCreationFailed;
150
+
151
+ return ChildProcess{
152
+ .hProcess = pi.hProcess,
153
+ .hThread = pi.hThread,
154
+ };
155
+ }
156
+
157
+ fn getAppModTime(self: *DevServer) i128 {
158
+ _ = self;
159
+ const io = std.Io.Threaded.global_single_threaded.io();
160
+ const cwd = std.Io.Dir.cwd();
161
+ var max_mtime: i128 = 0;
162
+
163
+ var app_dir = cwd.openDir(io, "app", .{ .iterate = true }) catch return 0;
164
+ defer app_dir.close(io);
165
+
166
+ var iter = app_dir.iterate();
167
+ while (iter.next(io) catch null) |entry| {
168
+ if (entry.kind == .file) {
169
+ if (app_dir.statFile(io, entry.name, .{})) |st| {
170
+ const ns = st.mtime.toNanoseconds();
171
+ if (ns > max_mtime) max_mtime = ns;
172
+ } else |_| {}
173
+ }
174
+ }
175
+ return max_mtime;
176
+ }
177
+ };
178
+
179
+ pub const ChildProcess = struct {
180
+ hProcess: std.os.windows.HANDLE,
181
+ hThread: std.os.windows.HANDLE,
182
+
183
+ pub fn kill(self: *ChildProcess) void {
184
+ const WinApi = struct {
185
+ pub extern "kernel32" fn TerminateProcess(hProcess: std.os.windows.HANDLE, uExitCode: u32) callconv(.winapi) i32;
186
+ pub extern "kernel32" fn CloseHandle(hObject: std.os.windows.HANDLE) callconv(.winapi) i32;
187
+ };
188
+ _ = WinApi.TerminateProcess(self.hProcess, 1);
189
+ _ = WinApi.CloseHandle(self.hProcess);
190
+ _ = WinApi.CloseHandle(self.hThread);
20
191
  }
21
192
  };
package/cli/installer.zig CHANGED
@@ -185,25 +185,35 @@ pub fn generateIss(allocator: std.mem.Allocator, config: AppConfig) ![]const u8
185
185
  \\Name: "desktopicon"; Description: "{{cm:CreateDesktopIcon}}"; GroupDescription: "{{cm:AdditionalIcons}}"; Flags: unchecked
186
186
  \\
187
187
  \\[Files]
188
- \\; Main executable
189
- \\Source: "bin\{{#AppExeName}}"; DestDir: "{{app}}"; Flags: ignoreversion
188
+ \\; Main executable (searches dist, root, zig-out\bin, and bin)
189
+ \\Source: "dist\{{#AppName}}.exe"; DestDir: "{{app}}"; DestName: "{{#AppExeName}}"; Flags: ignoreversion skipifsourcedoesntexist
190
+ \\Source: "example_app.exe"; DestDir: "{{app}}"; DestName: "{{#AppExeName}}"; Flags: ignoreversion skipifsourcedoesntexist
191
+ \\Source: "zig-out\bin\example_app.exe"; DestDir: "{{app}}"; DestName: "{{#AppExeName}}"; Flags: ignoreversion skipifsourcedoesntexist
192
+ \\Source: "bin\{{#AppExeName}}"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
190
193
  \\
191
- \\; NanoShell Runtime DLLs & Portable C++ Runtimes
192
- \\Source: "bin\AppCore.dll"; DestDir: "{{app}}"; Flags: ignoreversion
193
- \\Source: "bin\Ultralight.dll"; DestDir: "{{app}}"; Flags: ignoreversion
194
- \\Source: "bin\UltralightCore.dll"; DestDir: "{{app}}"; Flags: ignoreversion
195
- \\Source: "bin\WebCore.dll"; DestDir: "{{app}}"; Flags: ignoreversion
196
- \\Source: "bin\vcruntime140.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
197
- \\Source: "bin\msvcp140.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
198
- \\Source: "bin\vcruntime140_1.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
194
+ \\; NanoShell Runtime DLLs & Portable C++ Runtimes (vendor\lib and bin)
195
+ \\Source: "vendor\lib\AppCore.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
196
+ \\Source: "vendor\lib\Ultralight.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
197
+ \\Source: "vendor\lib\UltralightCore.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
198
+ \\Source: "vendor\lib\WebCore.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
199
+ \\Source: "vendor\lib\icudt67l.dat"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
200
+ \\Source: "vendor\lib\cacert.pem"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
201
+ \\Source: "vendor\lib\resources\*"; DestDir: "{{app}}\resources"; Flags: ignoreversion recursesubdirs createallsubdirs skipifsourcedoesntexist
199
202
  \\
200
- \\; ICU Unicode data and TLS certs
201
- \\Source: "bin\icudt67l.dat"; DestDir: "{{app}}"; Flags: ignoreversion
202
- \\Source: "bin\cacert.pem"; DestDir: "{{app}}"; Flags: ignoreversion
203
- \\Source: "bin\resources\*"; DestDir: "{{app}}\resources"; Flags: ignoreversion recursesubdirs createallsubdirs
203
+ \\Source: "bin\AppCore.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
204
+ \\Source: "bin\Ultralight.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
205
+ \\Source: "bin\UltralightCore.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
206
+ \\Source: "bin\WebCore.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
207
+ \\Source: "bin\vcruntime140.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
208
+ \\Source: "bin\msvcp140.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
209
+ \\Source: "bin\vcruntime140_1.dll"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
210
+ \\Source: "bin\icudt67l.dat"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
211
+ \\Source: "bin\cacert.pem"; DestDir: "{{app}}"; Flags: ignoreversion skipifsourcedoesntexist
212
+ \\Source: "bin\resources\*"; DestDir: "{{app}}\resources"; Flags: ignoreversion recursesubdirs createallsubdirs skipifsourcedoesntexist
204
213
  \\
205
214
  \\; App HTML / CSS / JS assets
206
- \\Source: "app\*"; DestDir: "{{app}}\app"; Flags: ignoreversion recursesubdirs createallsubdirs
215
+ \\Source: "example_app\*"; DestDir: "{{app}}\app"; Flags: ignoreversion recursesubdirs createallsubdirs skipifsourcedoesntexist
216
+ \\Source: "app\*"; DestDir: "{{app}}\app"; Flags: ignoreversion recursesubdirs createallsubdirs skipifsourcedoesntexist
207
217
  \\
208
218
  \\[Icons]
209
219
  \\Name: "{{group}}\\{{#AppName}}"; Filename: "{{app}}\\{{#AppExeName}}"; WorkingDir: "{{app}}"
package/cli/main.zig CHANGED
@@ -129,12 +129,12 @@ pub fn main() !void {
129
129
  \\</head>
130
130
  \\<body>
131
131
  \\ <div class="container">
132
- \\ <div class="fps-badge"><span id="fps-val">60</span> FPS Realtime</div>
132
+ \\ <div class="fps-badge"><span id="fps-val">120</span> FPS Locked</div>
133
133
  \\ <h1>⚡ NanoShell Desktop App</h1>
134
134
  \\ <p>Ultra-lightweight WebKit desktop runtime</p>
135
135
  \\ <button id="btn">Click Me</button>
136
136
  \\ </div>
137
- \\ <script src="app.js"></script>
137
+ \\ <!-- app.js is injected inline by the NanoShell engine at load time -->
138
138
  \\</body>
139
139
  \\</html>
140
140
  ;
@@ -184,26 +184,15 @@ pub fn main() !void {
184
184
  try app_dir.writeFile(io, .{ .sub_path = "app/styles.css", .data = css_content });
185
185
 
186
186
  const js_content =
187
- \\let lastTime = performance.now();
188
- \\let frames = 0;
189
- \\function calcFps() {
190
- \\ const now = performance.now();
191
- \\ frames++;
192
- \\ const delta = now - lastTime;
193
- \\ if (delta >= 500) {
194
- \\ const fps = Math.round((frames * 1000) / delta);
195
- \\ const el = document.getElementById('fps-val');
196
- \\ if (el) el.innerText = fps;
197
- \\ frames = 0;
198
- \\ lastTime = now;
199
- \\ }
200
- \\ requestAnimationFrame(calcFps);
201
- \\}
202
- \\requestAnimationFrame(calcFps);
187
+ \\// NanoShell Application JavaScript (0% Idle CPU Overhead)
188
+ \\console.log('⚡ [NanoShell] App loaded successfully');
203
189
  \\
204
- \\document.getElementById('btn').addEventListener('click', () => {
205
- \\ alert('Hello from NanoShell!');
206
- \\});
190
+ \\const btn = document.getElementById('btn');
191
+ \\if (btn) {
192
+ \\ btn.addEventListener('click', () => {
193
+ \\ alert('Hello from NanoShell!');
194
+ \\ });
195
+ \\}
207
196
  ;
208
197
  try app_dir.writeFile(io, .{ .sub_path = "app/app.js", .data = js_content });
209
198