onejs-core 2.0.19 → 2.0.21
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/definitions/augments.d.ts +1 -0
- package/dist/index.js +6 -3
- package/dist/utils/color-parser.d.ts +1 -1
- package/dist/utils/color-parser.js +1 -1
- package/index.ts +15 -12
- package/package.json +1 -1
- package/scripts/switch.cjs +92 -81
- package/utils/color-parser.ts +1 -1
|
@@ -26,6 +26,7 @@ declare global {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const document: DocumentWrapper
|
|
29
|
+
const onejsDocument: DocumentWrapper
|
|
29
30
|
const setTimeout: (callback: () => void, delay?: number) => number
|
|
30
31
|
const clearTimeout: (id: number) => void
|
|
31
32
|
const setInterval: (callback: () => void, delay?: number) => number
|
package/dist/index.js
CHANGED
|
@@ -33,9 +33,12 @@ export function h(type, props, ...children) {
|
|
|
33
33
|
return element;
|
|
34
34
|
}
|
|
35
35
|
export { emo } from "./styling/index";
|
|
36
|
-
|
|
37
|
-
if (typeof ___document != "undefined") {
|
|
36
|
+
if (typeof globalThis.___document != "undefined") {
|
|
38
37
|
// @ts-ignore
|
|
39
|
-
globalThis.
|
|
38
|
+
globalThis.onejsDocument = new DocumentWrapper(globalThis.___document);
|
|
39
|
+
if (!globalThis.ONEJS_WEBGL) {
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
globalThis.document = globalThis.onejsDocument;
|
|
42
|
+
}
|
|
40
43
|
}
|
|
41
44
|
// puer.$extension(CS.UnityEngine.UIElements.VisualElement, CS.UnityEngine.UIElements.VisualElementExtensions)
|
|
@@ -27,7 +27,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
27
27
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
28
28
|
IN THE SOFTWARE.
|
|
29
29
|
*/
|
|
30
|
-
|
|
30
|
+
const kCSSColorTable = {
|
|
31
31
|
"transparent": [0, 0, 0, 0], "aliceblue": [240, 248, 255, 1],
|
|
32
32
|
"antiquewhite": [250, 235, 215, 1], "aqua": [0, 255, 255, 1],
|
|
33
33
|
"aquamarine": [127, 255, 212, 1], "azure": [240, 255, 255, 1],
|
package/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference path="./definitions/index.d.ts" />
|
|
2
|
-
import { DocumentWrapper } from "./dom/document"
|
|
3
|
-
import { DomWrapper } from "./dom/dom"
|
|
2
|
+
import { DocumentWrapper } from "./dom/document"
|
|
3
|
+
import { DomWrapper } from "./dom/dom"
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* OneJS's own h function. Use this to quickly create elements in jsx-like syntax
|
|
@@ -10,29 +10,29 @@ import { DomWrapper } from "./dom/dom";
|
|
|
10
10
|
* @returns
|
|
11
11
|
*/
|
|
12
12
|
export function h(type: any, props: any, ...children: any[]): any {
|
|
13
|
-
const element = typeof type === "string" ? document.createElement(type) : type
|
|
13
|
+
const element = typeof type === "string" ? document.createElement(type) : type
|
|
14
14
|
|
|
15
15
|
// Assign properties to the element
|
|
16
16
|
for (const [key, value] of Object.entries(props || {})) {
|
|
17
17
|
if (key.startsWith("on") && typeof value === "function") {
|
|
18
|
-
element.addEventListener(key.substring(2).toLowerCase(), value)
|
|
18
|
+
element.addEventListener(key.substring(2).toLowerCase(), value)
|
|
19
19
|
} else if (key === "style" && typeof value === "object") {
|
|
20
|
-
Object.assign(element.style, value)
|
|
20
|
+
Object.assign(element.style, value)
|
|
21
21
|
} else {
|
|
22
|
-
element.setAttribute(key, value)
|
|
22
|
+
element.setAttribute(key, value)
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// Append children
|
|
27
27
|
for (const child of children) {
|
|
28
28
|
if (typeof child === "string") {
|
|
29
|
-
element.appendChild(document.createTextNode(child))
|
|
29
|
+
element.appendChild(document.createTextNode(child))
|
|
30
30
|
} else {
|
|
31
|
-
element.appendChild(child)
|
|
31
|
+
element.appendChild(child)
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
return element
|
|
35
|
+
return element
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
export { emo } from "./styling/index"
|
|
@@ -46,10 +46,13 @@ declare global {
|
|
|
46
46
|
const toJsArray: <T>(csArr: CS.System.Array) => T[]
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
if (typeof ___document != "undefined") {
|
|
49
|
+
if (typeof globalThis.___document != "undefined") {
|
|
51
50
|
// @ts-ignore
|
|
52
|
-
globalThis.
|
|
51
|
+
globalThis.onejsDocument = new DocumentWrapper(globalThis.___document)
|
|
52
|
+
if (!globalThis.ONEJS_WEBGL) {
|
|
53
|
+
// @ts-ignore
|
|
54
|
+
globalThis.document = globalThis.onejsDocument
|
|
55
|
+
}
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
// puer.$extension(CS.UnityEngine.UIElements.VisualElement, CS.UnityEngine.UIElements.VisualElementExtensions)
|
package/package.json
CHANGED
package/scripts/switch.cjs
CHANGED
|
@@ -13,9 +13,9 @@ const projectDir = path.resolve(process.cwd(), '..')
|
|
|
13
13
|
const manifestPath = path.join(projectDir, 'Packages', 'manifest.json')
|
|
14
14
|
|
|
15
15
|
const backends = [
|
|
16
|
-
{ name: "QuickJS", tgzUrl: "https://github.com/Tencent/puerts/releases/download/Unity_v2.2.
|
|
17
|
-
{ name: "V8", tgzUrl: "https://github.com/Tencent/puerts/releases/download/Unity_v2.2.
|
|
18
|
-
{ name: "NodeJS", tgzUrl: "https://github.com/Tencent/puerts/releases/download/Unity_v2.2.
|
|
16
|
+
{ name: "QuickJS", tgzUrl: "https://github.com/Tencent/puerts/releases/download/Unity_v2.2.2/PuerTS_Quickjs_2.2.2.tgz" },
|
|
17
|
+
{ name: "V8", tgzUrl: "https://github.com/Tencent/puerts/releases/download/Unity_v2.2.2/PuerTS_V8_2.2.2.tgz" },
|
|
18
|
+
{ name: "NodeJS", tgzUrl: "https://github.com/Tencent/puerts/releases/download/Unity_v2.2.2/PuerTS_Nodejs_2.2.2.tgz" }
|
|
19
19
|
]
|
|
20
20
|
|
|
21
21
|
const args = process.argv.slice(2)
|
|
@@ -33,16 +33,16 @@ if (args.length > 0 && args[0].toLowerCase() == "clear") {
|
|
|
33
33
|
} else if (
|
|
34
34
|
args.length > 0 &&
|
|
35
35
|
(["quickjs", "v8", "nodejs"].includes(args[0].toLowerCase()) ||
|
|
36
|
-
|
|
36
|
+
(args[0].toLowerCase().endsWith('.tgz') || /^https?:\/\/.+\.tgz$/i.test(args[0])))
|
|
37
37
|
) {
|
|
38
|
-
let backend
|
|
39
|
-
const outputDir = "./tmp"
|
|
38
|
+
let backend
|
|
39
|
+
const outputDir = "./tmp"
|
|
40
40
|
if (["quickjs", "v8", "nodejs"].includes(args[0].toLowerCase())) {
|
|
41
|
-
backend = backends.find(b => b.name.toLowerCase() === args[0])
|
|
41
|
+
backend = backends.find(b => b.name.toLowerCase() === args[0])
|
|
42
42
|
} else {
|
|
43
|
-
backend = { name: "Custom", tgzUrl: args[0] }
|
|
43
|
+
backend = { name: "Custom", tgzUrl: args[0] }
|
|
44
44
|
}
|
|
45
|
-
Process(backend, outputDir)
|
|
45
|
+
Process(backend, outputDir)
|
|
46
46
|
} else {
|
|
47
47
|
console.log("Usage: npm run switch <quickjs|v8|nodejs|clear|tgz-url>\n")
|
|
48
48
|
console.log(" quickjs: Switch to QuickJS backend")
|
|
@@ -64,7 +64,7 @@ async function Process(backend, outputDir) {
|
|
|
64
64
|
}
|
|
65
65
|
await extractTgz(downloadedPath, outputDir)
|
|
66
66
|
|
|
67
|
-
// Safe keep asmdef files
|
|
67
|
+
// Safe keep asmdef files, et al.
|
|
68
68
|
const onejsDir = await getOneJSUnityDir()
|
|
69
69
|
const a = path.join(onejsDir, 'Puerts/Editor/com.tencent.puerts.core.Editor.asmdef')
|
|
70
70
|
const b = path.join(upmDir, 'Editor/com.tencent.puerts.core.Editor.asmdef')
|
|
@@ -72,6 +72,9 @@ async function Process(backend, outputDir) {
|
|
|
72
72
|
const d = path.join(upmDir, 'Runtime/com.tencent.puerts.core.asmdef')
|
|
73
73
|
await fse.copy(a, b)
|
|
74
74
|
await fse.copy(c, d)
|
|
75
|
+
const e = path.join(onejsDir, 'Puerts/Runtime/Src/Default/JsEnv.cs')
|
|
76
|
+
const f = path.join(upmDir, 'Runtime/Src/Default/JsEnv.cs')
|
|
77
|
+
await fse.copy(e, f)
|
|
75
78
|
|
|
76
79
|
// Replace OneJS/Puerts with the new one
|
|
77
80
|
const puertsDir = path.join(onejsDir, "Puerts")
|
|
@@ -95,130 +98,138 @@ async function Process(backend, outputDir) {
|
|
|
95
98
|
// }
|
|
96
99
|
|
|
97
100
|
async function getOneJSUnityDir() {
|
|
98
|
-
let oneJSPath = null
|
|
101
|
+
let oneJSPath = null
|
|
99
102
|
|
|
100
103
|
// Step 1: Check manifest.json
|
|
101
104
|
if (fs.existsSync(manifestPath)) {
|
|
102
|
-
const manifestContent = fs.readFileSync(manifestPath,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
105
|
+
const manifestContent = fs.readFileSync(manifestPath, "utf8")
|
|
106
|
+
let manifestJson
|
|
107
|
+
try { manifestJson = JSON.parse(manifestContent) } catch {
|
|
108
|
+
console.error('Could not parse manifest.json at ' + manifestPath)
|
|
109
|
+
return null
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const dependencies = manifestJson && manifestJson.dependencies
|
|
113
|
+
const oneJSKeys = ["com.dragonground.onejs", "com.singtaa.onejs"]
|
|
114
|
+
|
|
115
|
+
if (dependencies) {
|
|
116
|
+
for (const key of oneJSKeys) {
|
|
117
|
+
const packagePath = dependencies[key]
|
|
118
|
+
if (typeof packagePath === "string") {
|
|
119
|
+
const v = packagePath.trim() // e.g., "file:PATH/TO/OneJS"
|
|
120
|
+
if (v.startsWith("file:")) {
|
|
121
|
+
oneJSPath = path.resolve(projectDir, v.substring(5)) // strip "file:"
|
|
122
|
+
return oneJSPath
|
|
123
|
+
}
|
|
124
|
+
}
|
|
114
125
|
}
|
|
115
126
|
}
|
|
116
127
|
}
|
|
117
128
|
|
|
118
129
|
// Step 2: If not found, parse OneJS.Runtime.csproj
|
|
119
130
|
if (!oneJSPath) {
|
|
120
|
-
const csprojPath = path.join(projectDir, 'OneJS.Runtime.csproj')
|
|
131
|
+
const csprojPath = path.join(projectDir, 'OneJS.Runtime.csproj')
|
|
121
132
|
|
|
122
133
|
if (fs.existsSync(csprojPath)) {
|
|
123
|
-
const csprojContent = fs.readFileSync(csprojPath, 'utf8')
|
|
124
|
-
const parser = new xml2js.Parser()
|
|
134
|
+
const csprojContent = fs.readFileSync(csprojPath, 'utf8')
|
|
135
|
+
const parser = new xml2js.Parser()
|
|
125
136
|
|
|
126
137
|
try {
|
|
127
|
-
const result = await parser.parseStringPromise(csprojContent)
|
|
138
|
+
const result = await parser.parseStringPromise(csprojContent)
|
|
128
139
|
|
|
129
|
-
const project = result.Project
|
|
130
|
-
const itemGroups = project.ItemGroup
|
|
140
|
+
const project = result.Project
|
|
141
|
+
const itemGroups = project.ItemGroup
|
|
131
142
|
|
|
132
143
|
if (itemGroups && itemGroups.length > 0) {
|
|
133
144
|
for (const itemGroup of itemGroups) {
|
|
134
145
|
if (itemGroup.Compile) {
|
|
135
146
|
for (const compileItem of itemGroup.Compile) {
|
|
136
|
-
const includePath = compileItem.$.Include
|
|
147
|
+
const includePath = compileItem.$.Include
|
|
137
148
|
|
|
138
149
|
// Normalize path separators for cross-platform compatibility
|
|
139
|
-
const normalizedIncludePath = includePath.replace(/\\/g, '/')
|
|
140
|
-
const searchIndex = normalizedIncludePath.indexOf('OneJS/Runtime/Engine/ScriptEngine.cs')
|
|
150
|
+
const normalizedIncludePath = includePath.replace(/\\/g, '/')
|
|
151
|
+
const searchIndex = normalizedIncludePath.indexOf('OneJS/Runtime/Engine/ScriptEngine.cs')
|
|
141
152
|
|
|
142
153
|
if (searchIndex !== -1) {
|
|
143
|
-
oneJSPath = normalizedIncludePath.substring(0, searchIndex + 'OneJS'.length)
|
|
144
|
-
oneJSPath = path.resolve(projectDir, oneJSPath)
|
|
145
|
-
return oneJSPath
|
|
154
|
+
oneJSPath = normalizedIncludePath.substring(0, searchIndex + 'OneJS'.length)
|
|
155
|
+
oneJSPath = path.resolve(projectDir, oneJSPath)
|
|
156
|
+
return oneJSPath
|
|
146
157
|
}
|
|
147
158
|
}
|
|
148
159
|
}
|
|
149
160
|
}
|
|
150
161
|
}
|
|
151
162
|
|
|
152
|
-
console.error('Could not find OneJS path in csproj file.')
|
|
153
|
-
return null
|
|
163
|
+
console.error('Could not find OneJS path in csproj file.')
|
|
164
|
+
return null
|
|
154
165
|
} catch (err) {
|
|
155
|
-
console.error('Error parsing csproj file:', err)
|
|
156
|
-
return null
|
|
166
|
+
console.error('Error parsing csproj file:', err)
|
|
167
|
+
return null
|
|
157
168
|
}
|
|
158
169
|
} else {
|
|
159
|
-
console.error('OneJS.Runtime.csproj file does not exist.')
|
|
160
|
-
return null
|
|
170
|
+
console.error('OneJS.Runtime.csproj file does not exist.')
|
|
171
|
+
return null
|
|
161
172
|
}
|
|
162
173
|
}
|
|
163
174
|
|
|
164
|
-
return oneJSPath
|
|
175
|
+
return oneJSPath
|
|
165
176
|
}
|
|
166
177
|
|
|
167
178
|
function ensureDirectoryExistence(filePath) {
|
|
168
|
-
const dirname = path.dirname(filePath)
|
|
179
|
+
const dirname = path.dirname(filePath)
|
|
169
180
|
if (fs.existsSync(dirname)) {
|
|
170
|
-
return true
|
|
181
|
+
return true
|
|
171
182
|
}
|
|
172
|
-
fs.mkdirSync(dirname, { recursive: true })
|
|
183
|
+
fs.mkdirSync(dirname, { recursive: true })
|
|
173
184
|
}
|
|
174
185
|
|
|
175
186
|
function getFilenameFromUrl(fileUrl) {
|
|
176
|
-
const parsedUrl = url.parse(fileUrl)
|
|
177
|
-
return path.basename(parsedUrl.pathname)
|
|
187
|
+
const parsedUrl = url.parse(fileUrl)
|
|
188
|
+
return path.basename(parsedUrl.pathname)
|
|
178
189
|
}
|
|
179
190
|
|
|
180
191
|
async function downloadFile(fileUrl, outputDir) {
|
|
181
|
-
const filename = getFilenameFromUrl(fileUrl)
|
|
182
|
-
const outputLocationPath = path.join(outputDir, filename)
|
|
192
|
+
const filename = getFilenameFromUrl(fileUrl)
|
|
193
|
+
const outputLocationPath = path.join(outputDir, filename)
|
|
183
194
|
|
|
184
|
-
ensureDirectoryExistence(outputLocationPath)
|
|
195
|
+
ensureDirectoryExistence(outputLocationPath)
|
|
185
196
|
|
|
186
197
|
// Check if file exists (keep existing code)
|
|
187
198
|
if (fs.existsSync(outputLocationPath)) {
|
|
188
|
-
console.log(`Local .tgz found: ${outputLocationPath}`)
|
|
189
|
-
return outputLocationPath
|
|
199
|
+
console.log(`Local .tgz found: ${outputLocationPath}`)
|
|
200
|
+
return outputLocationPath
|
|
190
201
|
}
|
|
191
202
|
|
|
192
|
-
console.log(`Downloading ${filename}`)
|
|
193
|
-
const response = await fetch(fileUrl)
|
|
203
|
+
console.log(`Downloading ${filename}`)
|
|
204
|
+
const response = await fetch(fileUrl)
|
|
194
205
|
|
|
195
206
|
if (!response.ok) {
|
|
196
|
-
throw new Error(`Failed to fetch ${fileUrl}: ${response.statusText}`)
|
|
207
|
+
throw new Error(`Failed to fetch ${fileUrl}: ${response.statusText}`)
|
|
197
208
|
}
|
|
198
209
|
|
|
199
210
|
// Get the total size for the progress bar
|
|
200
|
-
const totalSize = parseInt(response.headers.get('content-length'), 10)
|
|
201
|
-
|
|
211
|
+
const totalSize = parseInt(response.headers.get('content-length'), 10)
|
|
212
|
+
|
|
202
213
|
// Create progress bar
|
|
203
214
|
const progressBar = new ProgressBar('[:bar] :percent ETA: :etas', {
|
|
204
215
|
complete: '=',
|
|
205
216
|
incomplete: ' ',
|
|
206
217
|
width: 40,
|
|
207
218
|
total: totalSize
|
|
208
|
-
})
|
|
219
|
+
})
|
|
209
220
|
|
|
210
|
-
const fileStream = fs.createWriteStream(outputLocationPath)
|
|
221
|
+
const fileStream = fs.createWriteStream(outputLocationPath)
|
|
211
222
|
for await (const chunk of response.body) {
|
|
212
|
-
fileStream.write(chunk)
|
|
213
|
-
progressBar.tick(chunk.length)
|
|
223
|
+
fileStream.write(chunk)
|
|
224
|
+
progressBar.tick(chunk.length)
|
|
214
225
|
}
|
|
215
226
|
|
|
216
|
-
fileStream.end()
|
|
227
|
+
fileStream.end()
|
|
217
228
|
|
|
218
229
|
return new Promise((resolve, reject) => {
|
|
219
|
-
fileStream.on('close', () => resolve(outputLocationPath))
|
|
220
|
-
fileStream.on('error', reject)
|
|
221
|
-
})
|
|
230
|
+
fileStream.on('close', () => resolve(outputLocationPath))
|
|
231
|
+
fileStream.on('error', reject)
|
|
232
|
+
})
|
|
222
233
|
}
|
|
223
234
|
|
|
224
235
|
async function extractTgz(filePath, outputDir) {
|
|
@@ -226,47 +237,47 @@ async function extractTgz(filePath, outputDir) {
|
|
|
226
237
|
file: filePath,
|
|
227
238
|
cwd: outputDir,
|
|
228
239
|
})
|
|
229
|
-
console.log(`Extraction completed.`)
|
|
240
|
+
console.log(`Extraction completed.`)
|
|
230
241
|
}
|
|
231
242
|
|
|
232
243
|
|
|
233
244
|
|
|
234
245
|
async function checkFileInUse(file) {
|
|
235
246
|
try {
|
|
236
|
-
const handle = await fsp.open(file, 'r+')
|
|
237
|
-
await handle.close()
|
|
247
|
+
const handle = await fsp.open(file, 'r+')
|
|
248
|
+
await handle.close()
|
|
238
249
|
} catch (err) {
|
|
239
250
|
if (err.code === 'EBUSY' || err.code === 'EPERM' || err.code === 'EACCES') {
|
|
240
|
-
console.error('File is in use by another program or access is denied:', err)
|
|
241
|
-
return false
|
|
251
|
+
console.error('File is in use by another program or access is denied:', err)
|
|
252
|
+
return false
|
|
242
253
|
} else {
|
|
243
|
-
console.error('Cannot access file:', err)
|
|
244
|
-
return false
|
|
254
|
+
console.error('Cannot access file:', err)
|
|
255
|
+
return false
|
|
245
256
|
}
|
|
246
257
|
}
|
|
247
|
-
return true
|
|
258
|
+
return true
|
|
248
259
|
}
|
|
249
260
|
|
|
250
261
|
async function checkAllDeletable(currentPath) {
|
|
251
262
|
try {
|
|
252
|
-
const stats = await fsp.stat(currentPath)
|
|
263
|
+
const stats = await fsp.stat(currentPath)
|
|
253
264
|
|
|
254
265
|
if (stats.isDirectory()) {
|
|
255
|
-
const files = await fsp.readdir(currentPath)
|
|
266
|
+
const files = await fsp.readdir(currentPath)
|
|
256
267
|
|
|
257
268
|
for (const file of files) {
|
|
258
|
-
const deletable = await checkAllDeletable(path.join(currentPath, file))
|
|
269
|
+
const deletable = await checkAllDeletable(path.join(currentPath, file))
|
|
259
270
|
if (!deletable) {
|
|
260
|
-
return false
|
|
271
|
+
return false
|
|
261
272
|
}
|
|
262
273
|
}
|
|
263
|
-
return true
|
|
274
|
+
return true
|
|
264
275
|
} else {
|
|
265
|
-
return await checkFileInUse(currentPath)
|
|
276
|
+
return await checkFileInUse(currentPath)
|
|
266
277
|
}
|
|
267
278
|
} catch (err) {
|
|
268
|
-
console.log(`Error accessing: ${currentPath}, ${err}`)
|
|
269
|
-
return false
|
|
279
|
+
console.log(`Error accessing: ${currentPath}, ${err}`)
|
|
280
|
+
return false
|
|
270
281
|
}
|
|
271
282
|
}
|
|
272
283
|
|
package/utils/color-parser.ts
CHANGED
|
@@ -31,7 +31,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
31
31
|
IN THE SOFTWARE.
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
const kCSSColorTable = {
|
|
35
35
|
"transparent": [0, 0, 0, 0], "aliceblue": [240, 248, 255, 1],
|
|
36
36
|
"antiquewhite": [250, 235, 215, 1], "aqua": [0, 255, 255, 1],
|
|
37
37
|
"aquamarine": [127, 255, 212, 1], "azure": [240, 255, 255, 1],
|