Skip to content

Commit a8b6d29

Browse files
committed
doc: add website live example
1 parent 8e575e7 commit a8b6d29

23 files changed

Lines changed: 1580 additions & 19 deletions

File tree

.github/workflows/pages.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: GitHub Pages
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
workflow_dispatch:
9+
10+
jobs:
11+
build:
12+
name: Build Web Site
13+
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/master'
14+
runs-on: ubuntu-22.04
15+
concurrency:
16+
group: ${{ github.workflow }}-${{ github.ref }}
17+
steps:
18+
- uses: actions/checkout@v5
19+
with:
20+
submodules: recursive
21+
fetch-depth: 0
22+
23+
- name: Build Soluna (WASM)
24+
uses: ./.github/actions/soluna
25+
id: build
26+
with:
27+
soluna_path: "."
28+
29+
- name: Install web build tools
30+
run: |
31+
sudo apt-get update
32+
sudo apt-get install -y lua5.4 zip
33+
34+
- name: Prepare web assets
35+
run: |
36+
lua5.4 script/build_web.lua \
37+
--soluna . \
38+
--site web \
39+
--wasm "${{ steps.build.outputs.SOLUNA_WASM_PATH }}" \
40+
--js "${{ steps.build.outputs.SOLUNA_JS_PATH }}"
41+
42+
- name: Setup Hugo
43+
uses: peaceiris/actions-hugo@v3
44+
with:
45+
hugo-version: "0.119.0"
46+
47+
- name: Build
48+
run: hugo --source web --minify
49+
50+
- name: Upload static files as artifact
51+
id: deployment
52+
uses: actions/upload-pages-artifact@v3
53+
with:
54+
path: web/public
55+
56+
deploy:
57+
name: Deploy to GitHub Pages
58+
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/master'
59+
needs: [build]
60+
runs-on: ubuntu-22.04
61+
permissions:
62+
pages: write
63+
id-token: write
64+
environment:
65+
name: github-pages
66+
url: ${{ steps.deployment.outputs.page_url }}
67+
steps:
68+
- name: Deploy to GitHub Pages
69+
id: deployment
70+
uses: actions/deploy-pages@v4

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ bin/macos
55
bin/mingw
66
bin/msvc
77
bin/emcc
8+
web/public
9+
web/data
10+
web/static/runtime
11+
web/static/data

script/build_web.lua

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
local function trim(s)
2+
return (s:gsub("^%s+", ""):gsub("%s+$", ""))
3+
end
4+
5+
local function shell_quote(value)
6+
return "'" .. value:gsub("'", "'\\''") .. "'"
7+
end
8+
9+
local function run(cmd)
10+
local ok = os.execute(cmd)
11+
if ok ~= true and ok ~= 0 then
12+
error("command failed: " .. cmd)
13+
end
14+
end
15+
16+
local function read_file(path)
17+
local f = assert(io.open(path, "rb"))
18+
local data = f:read("*a")
19+
f:close()
20+
return data
21+
end
22+
23+
local function write_file(path, data)
24+
local f = assert(io.open(path, "wb"))
25+
f:write(data)
26+
f:close()
27+
end
28+
29+
local function read_lines(path)
30+
local f = assert(io.open(path, "r"))
31+
local lines = {}
32+
for line in f:lines() do
33+
lines[#lines + 1] = line
34+
end
35+
f:close()
36+
return lines
37+
end
38+
39+
local function exec_lines(cmd)
40+
local p = assert(io.popen(cmd, "r"))
41+
local lines = {}
42+
for line in p:lines() do
43+
if line ~= "" then
44+
lines[#lines + 1] = line
45+
end
46+
end
47+
p:close()
48+
return lines
49+
end
50+
51+
local function is_array(tbl)
52+
local count = 0
53+
for k, _ in pairs(tbl) do
54+
if type(k) ~= "number" then
55+
return false
56+
end
57+
count = count + 1
58+
end
59+
for i = 1, count do
60+
if tbl[i] == nil then
61+
return false
62+
end
63+
end
64+
return true
65+
end
66+
67+
local function json_escape(value)
68+
return value
69+
:gsub("\\", "\\\\")
70+
:gsub("\"", "\\\"")
71+
:gsub("\b", "\\b")
72+
:gsub("\f", "\\f")
73+
:gsub("\n", "\\n")
74+
:gsub("\r", "\\r")
75+
:gsub("\t", "\\t")
76+
end
77+
78+
local function json_encode(value)
79+
local t = type(value)
80+
if t == "nil" then
81+
return "null"
82+
elseif t == "boolean" then
83+
return value and "true" or "false"
84+
elseif t == "number" then
85+
return tostring(value)
86+
elseif t == "string" then
87+
return "\"" .. json_escape(value) .. "\""
88+
elseif t == "table" then
89+
if is_array(value) then
90+
local parts = {}
91+
for i = 1, #value do
92+
parts[#parts + 1] = json_encode(value[i])
93+
end
94+
return "[" .. table.concat(parts, ",") .. "]"
95+
end
96+
local parts = {}
97+
for k, v in pairs(value) do
98+
parts[#parts + 1] = json_encode(k) .. ":" .. json_encode(v)
99+
end
100+
table.sort(parts)
101+
return "{" .. table.concat(parts, ",") .. "}"
102+
else
103+
error("unsupported json type: " .. t)
104+
end
105+
end
106+
107+
local function titleize(name)
108+
local parts = {}
109+
for part in name:gmatch("[^_%-%s]+") do
110+
parts[#parts + 1] = part:sub(1, 1):upper() .. part:sub(2)
111+
end
112+
return table.concat(parts, " ")
113+
end
114+
115+
local function parse_doc_file(path)
116+
local blocks = {}
117+
local doc_lines = {}
118+
local annos = {}
119+
120+
local function flush(signature)
121+
if #doc_lines == 0 and #annos == 0 then
122+
return
123+
end
124+
blocks[#blocks + 1] = {
125+
signature = signature,
126+
docs = doc_lines,
127+
annos = annos,
128+
}
129+
doc_lines = {}
130+
annos = {}
131+
end
132+
133+
for _, line in ipairs(read_lines(path)) do
134+
if line:match("^%-%-%-@") then
135+
annos[#annos + 1] = trim(line:gsub("^%-%-%-@", ""))
136+
elseif line:match("^%-%-%-") then
137+
doc_lines[#doc_lines + 1] = trim(line:gsub("^%-%-%-%s?", ""))
138+
else
139+
local trimmed = trim(line)
140+
if trimmed ~= "" and (#doc_lines > 0 or #annos > 0) then
141+
flush(trimmed)
142+
end
143+
end
144+
end
145+
flush(nil)
146+
return blocks
147+
end
148+
149+
local function parse_args(argv)
150+
local opts = {
151+
soluna = ".",
152+
site = "web",
153+
wasm = nil,
154+
js = nil,
155+
}
156+
local i = 1
157+
while i <= #argv do
158+
local arg = argv[i]
159+
if arg == "--soluna" then
160+
opts.soluna = argv[i + 1]
161+
i = i + 2
162+
elseif arg == "--site" then
163+
opts.site = argv[i + 1]
164+
i = i + 2
165+
elseif arg == "--wasm" then
166+
opts.wasm = argv[i + 1]
167+
i = i + 2
168+
elseif arg == "--js" then
169+
opts.js = argv[i + 1]
170+
i = i + 2
171+
else
172+
error("unknown argument: " .. arg)
173+
end
174+
end
175+
if not opts.wasm or not opts.js then
176+
error("missing --wasm or --js argument")
177+
end
178+
return opts
179+
end
180+
181+
local opts = parse_args(arg)
182+
local soluna_dir = opts.soluna
183+
local site_dir = opts.site
184+
local runtime_dir = site_dir .. "/static/runtime"
185+
local data_dir = site_dir .. "/data"
186+
local static_data_dir = site_dir .. "/static/data"
187+
188+
run("mkdir -p " .. shell_quote(runtime_dir))
189+
run("mkdir -p " .. shell_quote(runtime_dir .. "/test"))
190+
run("mkdir -p " .. shell_quote(data_dir))
191+
run("mkdir -p " .. shell_quote(static_data_dir))
192+
193+
run("cp " .. shell_quote(opts.wasm) .. " " .. shell_quote(runtime_dir .. "/soluna.wasm"))
194+
run("cp " .. shell_quote(opts.js) .. " " .. shell_quote(runtime_dir .. "/soluna.js"))
195+
196+
run("cd " .. shell_quote(soluna_dir) .. " && zip -r " .. shell_quote(runtime_dir .. "/asset.zip") .. " asset")
197+
run("cp -R " .. shell_quote(soluna_dir .. "/test/.") .. " " .. shell_quote(runtime_dir .. "/test"))
198+
199+
local examples = {}
200+
local example_paths = exec_lines("find " .. shell_quote(soluna_dir .. "/test") .. " -maxdepth 1 -type f -name '*.lua' -print")
201+
table.sort(example_paths)
202+
for _, path in ipairs(example_paths) do
203+
local name = path:match("([^/]+)%.lua$")
204+
if name then
205+
local content = read_file(path)
206+
if not content:find("font%.system") then
207+
examples[#examples + 1] = {
208+
id = name,
209+
title = titleize(name),
210+
entry = "test/" .. name .. ".lua",
211+
}
212+
end
213+
end
214+
end
215+
216+
local docs = {}
217+
local doc_paths = exec_lines("find " .. shell_quote(soluna_dir .. "/docs") .. " -maxdepth 1 -type f -name '*.lua' -print")
218+
table.sort(doc_paths)
219+
for _, path in ipairs(doc_paths) do
220+
local name = path:match("([^/]+)%.lua$")
221+
if name then
222+
docs[#docs + 1] = {
223+
module = name,
224+
title = titleize(name),
225+
blocks = parse_doc_file(path),
226+
}
227+
end
228+
end
229+
230+
local examples_payload = json_encode({
231+
generated_at = os.date("!%Y-%m-%dT%H:%M:%SZ"),
232+
examples = examples,
233+
})
234+
write_file(data_dir .. "/examples.json", examples_payload)
235+
write_file(static_data_dir .. "/examples.json", examples_payload)
236+
237+
local docs_payload = json_encode({
238+
generated_at = os.date("!%Y-%m-%dT%H:%M:%SZ"),
239+
modules = docs,
240+
})
241+
write_file(data_dir .. "/docs.json", docs_payload)
242+
write_file(static_data_dir .. "/docs.json", docs_payload)

test/imageloader.lua

Lines changed: 0 additions & 7 deletions
This file was deleted.

test/setting.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
local setting = require "soluna.setting"
1+
local soluna = require "soluna"
22

3-
print_r(setting)
3+
print_r(soluna.settings())

test/spritepack.lua

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,10 @@ local spritemgr = require "soluna.spritemgr"
33
-- texture size = 128
44
local bank = spritemgr.newbank(65536, 128)
55

6-
local ids = {
7-
bank:add(32, 16),
8-
bank:add(64, 32),
9-
bank:add(96, 96),
10-
bank:add(96, 96),
11-
}
12-
13-
for _, id in ipairs(ids) do
14-
bank:touch(id)
15-
end
6+
bank:add(32, 16)
7+
bank:add(64, 32)
8+
bank:add(96, 96)
9+
bank:add(96, 96)
1610

1711
local texid, n = bank:pack()
1812
print("Pack",n,"from",texid)

web/config.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
baseURL = "/"
2+
title = "Soluna Web Lab"
3+
languageCode = "en-us"
4+
paginate = 12
5+
relativeURLs = true
6+
canonifyURLs = true
7+
8+
[params]
9+
description = "Soluna documentation and live examples running in the browser."

web/content/_index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
title: "Soluna Web Lab"
3+
description: "Live docs and examples for the Soluna engine."
4+
---

web/content/docs/_index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
title: "Docs"
3+
description: "Soluna API reference."
4+
---

web/content/examples/_index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
title: "Examples"
3+
description: "Gallery of Soluna test entries."
4+
---

0 commit comments

Comments
 (0)