kireji 0.10.0 → 0.12.0

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 (70) hide show
  1. package/package.json +1 -1
  2. package/src/app/kireji/editor/sections/type.d.ts +1 -0
  3. package/src/app/kireji/editor/tab-group/routeID-distribute.js +3 -0
  4. package/src/app/kireji/issue-tracker/sections/issues/1776208910/description +7 -1
  5. package/src/app/kireji/issue-tracker/sections/issues/1776212294/links_.js +1 -0
  6. package/src/app/kireji/issue-tracker/sections/issues/1776316907/affects_.js +3 -0
  7. package/src/app/kireji/issue-tracker/sections/issues/1776316907/description +5 -0
  8. package/src/app/kireji/issue-tracker/sections/issues/1776316907/part.json +3 -0
  9. package/src/app/kireji/issue-tracker/sections/issues/1776316907/priority +1 -0
  10. package/src/app/kireji/issue-tracker/sections/issues/1776316907/status +1 -0
  11. package/src/app/kireji/issue-tracker/sections/issues/1776316907/title +1 -0
  12. package/src/app/kireji/issue-tracker/sections/issues/1776319745/affects_.js +3 -0
  13. package/src/app/kireji/issue-tracker/sections/issues/1776319745/description +7 -0
  14. package/src/app/kireji/issue-tracker/sections/issues/1776319745/part.json +3 -0
  15. package/src/app/kireji/issue-tracker/sections/issues/1776319745/priority +1 -0
  16. package/src/app/kireji/issue-tracker/sections/issues/1776319745/status +1 -0
  17. package/src/app/kireji/issue-tracker/sections/issues/1776319745/title +1 -0
  18. package/src/app/kireji/issue-tracker/sections/issues/1776320694/affects_.js +3 -0
  19. package/src/app/kireji/issue-tracker/sections/issues/1776320694/description +3 -0
  20. package/src/app/kireji/issue-tracker/sections/issues/1776320694/links_.js +3 -0
  21. package/src/app/kireji/issue-tracker/sections/issues/1776320694/part.json +3 -0
  22. package/src/app/kireji/issue-tracker/sections/issues/1776320694/priority +1 -0
  23. package/src/app/kireji/issue-tracker/sections/issues/1776320694/status +1 -0
  24. package/src/app/kireji/issue-tracker/sections/issues/1776320694/title +1 -0
  25. package/src/app/kireji/issue-tracker/sections/issues/1776321398/affects_.js +3 -0
  26. package/src/app/kireji/issue-tracker/sections/issues/1776321398/description +1 -0
  27. package/src/app/kireji/issue-tracker/sections/issues/1776321398/links_.js +3 -0
  28. package/src/app/kireji/issue-tracker/sections/issues/1776321398/part.json +3 -0
  29. package/src/app/kireji/issue-tracker/sections/issues/1776321398/priority +1 -0
  30. package/src/app/kireji/issue-tracker/sections/issues/1776321398/status +1 -0
  31. package/src/app/kireji/issue-tracker/sections/issues/1776321398/title +1 -0
  32. package/src/app/kireji/issue-tracker/sections/issues/1776321594/affects_.js +4 -0
  33. package/src/app/kireji/issue-tracker/sections/issues/1776321594/description +8 -0
  34. package/src/app/kireji/issue-tracker/sections/issues/1776321594/part.json +3 -0
  35. package/src/app/kireji/issue-tracker/sections/issues/1776321594/priority +1 -0
  36. package/src/app/kireji/issue-tracker/sections/issues/1776321594/status +1 -0
  37. package/src/app/kireji/issue-tracker/sections/issues/1776321594/title +1 -0
  38. package/src/app/kireji/issue-tracker/sections/issues/1776323037/affects_.js +3 -0
  39. package/src/app/kireji/issue-tracker/sections/issues/1776323037/description +1 -0
  40. package/src/app/kireji/issue-tracker/sections/issues/1776323037/part.json +3 -0
  41. package/src/app/kireji/issue-tracker/sections/issues/1776323037/priority +1 -0
  42. package/src/app/kireji/issue-tracker/sections/issues/1776323037/status +1 -0
  43. package/src/app/kireji/issue-tracker/sections/issues/1776323037/title +1 -0
  44. package/src/build.js +6 -3
  45. package/src/parts/abstract/match/routeID-collect.js +1 -1
  46. package/src/parts/abstract/match/routeID-distribute.js +3 -3
  47. package/src/parts/abstract/mesh/build.js +7 -2
  48. package/src/parts/abstract/mesh/data-get.js +4 -3
  49. package/src/parts/abstract/mesh/ray-cast.js +2 -2
  50. package/src/parts/abstract/mesh/routeID-distribute.js +3 -0
  51. package/src/parts/abstract/mesh/type.d.ts +5 -1
  52. package/src/parts/abstract/mix/model_.js +2 -2
  53. package/src/parts/abstract/mix/routeID-distribute.js +2 -2
  54. package/src/parts/abstract/part/part.json +6 -3
  55. package/src/parts/abstract/part/routeID-set.js +1 -1
  56. package/src/parts/abstract/part/type.d.ts +8 -4
  57. package/src/parts/abstract/part-mask/routeID-distribute.js +3 -0
  58. package/src/parts/abstract/permutation/routeID-distribute.js +3 -0
  59. package/src/parts/core/gpu/buffer-create.js +12 -0
  60. package/src/parts/core/gpu/part.json +7 -1
  61. package/src/parts/core/gpu/type.d.ts +4 -0
  62. package/src/parts/core/hot-keys/combo_.js +2 -0
  63. package/src/parts/desktop/about/part.html_.js +21 -0
  64. package/src/parts/desktop/about/part.json +3 -0
  65. package/src/parts/desktop/about/title +1 -0
  66. package/src/parts/desktop/era/vintage/part.css_.js +1 -1
  67. package/src/parts/desktop/task-bar/menu/menu.html_.js +2 -2
  68. package/src/type.d.ts +2 -0
  69. package/src/app/kireji/issue-tracker/menu-appear-on +0 -1
  70. package/src/parts/core/gpu/webgpu.d.ts +0 -251
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kireji",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "A web framework for stateful, entropy-perfect, multi-origin web applications. Currently in alpha. Expect breaking changes for version 0. Use with caution!",
5
5
  "files": [
6
6
  "src/",
@@ -3,6 +3,7 @@ declare interface IKirejiAppEditorSections
3
3
 
4
4
  // Subparts.
5
5
  readonly about: IKirejiAppEditorSection
6
+ readonly issues: IKirejiAppEditorSection
6
7
  readonly state: IKirejiAppEditorSection
7
8
  readonly stateSpace: IKirejiAppEditorSection
8
9
  readonly properties: IKirejiAppEditorSection
@@ -1,5 +1,8 @@
1
1
  tabGroup.updateRouteID(ROUTE_ID)
2
2
 
3
+ if (SKIP_RUNTIME_STATE_DISTRIBUTION)
4
+ return
5
+
3
6
  // Extract the number of open tabs.
4
7
  const numberOfTabsOpen = (() => {
5
8
  let estimate = tabGroup.tabBitDepths[ROUTE_ID.toString(2).length]
@@ -1 +1,7 @@
1
- Add alt attributes for all images. Allow deep zoom for low-vision users. Headings shouldn't skip levels (for example, an h4 appearing after an h1 with no h2 or h3 in-between).
1
+ Add alt attributes for all images. Allow deep zoom for low-vision users. Headings shouldn't skip levels (for example, an h4 appearing after an h1 with no h2 or h3 in-between).
2
+
3
+ Do a full pass on all apps examining their tab behavior. Consider assigning tabindex=0 to all and only the first primary element of each region that the user should be able to tab between. For example, having only the first item of a list of icons be tabbable. Then, perhaps try "moving" that tabindex attribute to other items in the same set when other keyboard keys are used (such as arrow keys).
4
+
5
+ Can the keyboard be used to control each app? What is it like to work with apps without a pointing device?
6
+
7
+ What do apps sound like when spoken aloud by a screen reader?
@@ -1,3 +1,4 @@
1
1
  return [
2
2
  kirejiIssues[1776262432],
3
+ kirejiIssues[1776320694],
3
4
  ]
@@ -0,0 +1,3 @@
1
+ return [
2
+ _.parts.abstract.part
3
+ ]
@@ -0,0 +1,5 @@
1
+ Right now, there is sometimes visible FOUC when loading server-rendered pages because of missing early-load artwork.
2
+
3
+ All .png and .gif files should have a corresponding, maximally compressed early-load png preview.
4
+
5
+ The problem is especially noticable on glowstick.click.
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "issue.."
3
+ }
@@ -0,0 +1,3 @@
1
+ return [
2
+ _.app.kireji.issueTracker
3
+ ]
@@ -0,0 +1,7 @@
1
+ Right now, the project-specific issues are mixed directly with the project's own issues.
2
+
3
+ We know which issues are which thanks to a pass that detects the origin of all parts during the packing stage of the build process. This can be used to separate the two.
4
+
5
+ Syncronize the name of the project using the repo name, which is also known during the build process. The framework project is always called kireji. Consider renaming all generic "ecosystem" items (such as the root of the domain outliner) with the project name.
6
+
7
+ In the issue tracker, let the user filter by project and see at a glance whether the issue belongs to the repo project or the framework.
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "issue.."
3
+ }
@@ -0,0 +1 @@
1
+ Add Projects to Issue Tracker
@@ -0,0 +1,3 @@
1
+ return [
2
+ _.parts.desktop.taskBar.tray.stats
3
+ ]
@@ -0,0 +1,3 @@
1
+ The FPS meter doesn't look complete. A better idea might be to have a diagnostics/debug overlay which can be toggled using a switch in the properties app.
2
+
3
+ It can then be set to enabled in the landing model for debugging and that landing model change can be left uncommitted.
@@ -0,0 +1,3 @@
1
+ return [
2
+ kirejiIssues[1776212294],
3
+ ]
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "issue.."
3
+ }
@@ -0,0 +1 @@
1
+ Improve FPS Meter
@@ -0,0 +1,3 @@
1
+ return [
2
+ _.app.kireji.editor.sections.issues
3
+ ]
@@ -0,0 +1 @@
1
+ At build time (or at selection time, whichever is optimal), establish the relationship between parts and the issues that affect them. Then, render the list of issue links (visually consistent with the issue tracker summary) in the Issues section of the part's Kireji editor summary.
@@ -0,0 +1,3 @@
1
+ return [
2
+ kirejiIssues[1776212294],
3
+ ]
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "issue.."
3
+ }
@@ -0,0 +1 @@
1
+ Improve FPS Meter
@@ -0,0 +1,4 @@
1
+ return [
2
+ _,
3
+ _.parts.abstract.part
4
+ ]
@@ -0,0 +1,8 @@
1
+ Currently, the project is read-only. The following problems need to be solved in order to implement the full IDE:
2
+
3
+ 1. How will modifications be stored so that they are not quickly lost? The user's local storage?
4
+ 2. How will modifications be made portable? JSON object export? Full git integration?
5
+ 3. How will the user be shown that the version of the project they are currently working in cannot be shared as a link (for example, a warning bar across the top of the screen)?
6
+ 4. How will the system know when and how to rebuild parts and hydrate views and states when parts are added, edited, moved or removed in real-time? Is there a mathematical way to structure this nicely? Do we start with obvious things (like CSS and HTML snippets) and expand upon the logic from there? Do we build an cause-effect network at build time for propagating an update signal?
7
+ 5. What should happen if the user breaks the entire framework by editing the framework parts? Will there be some sort of fallback? What if the ability to fallback is also borked? Will the editable framework actually be a second running copy of the read-only framework inside of a frame or something so that the preview can be cancelled? How can we enable recovery of a broken instance of the framework so that users don't lose work?
8
+ 6. Should the framework parts and the project parts be held separately (i.e. user can override framework parts from the project to augment the framework but cannot delete the framework's original parts)? If so, this would require keeping a copy of both the framework's versions of files and the project's versions which I don't really prefer.
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "issue.."
3
+ }
@@ -0,0 +1 @@
1
+ Kireji Part Editor (IDE)
@@ -0,0 +1,3 @@
1
+ return [
2
+ _.app.kireji.issueTracker.filters
3
+ ]
@@ -0,0 +1 @@
1
+ The current order of statuses seems is ["doing", "done", "to-do"] (alphabetic). Instead, it should use the same explicit order as the filters do; to-do should come at the beginning.
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "issue.."
3
+ }
@@ -0,0 +1 @@
1
+ Fix Issue Tracker Status Sort Order
package/src/build.js CHANGED
@@ -76,7 +76,8 @@ function ƒ(_, compressedSubjectOrigins) {
76
76
  camelCase = (words, delimiter = "-") => (typeof words === "string" ? words.split(delimiter) : words).map((word, i) => (i ? word[0].toUpperCase() + word.slice(1) : word)).join(""),
77
77
  serialize = value => JSON.stringify(value, (k, v) => (typeof v === "bigint" ? v.toString() + "n" : v), 1),
78
78
  scientific = (x, html = false) => { x = x.toString(10); const log10 = x.length - 1; x = Math.round((x[0] ?? 0) + (x[1] ?? 0) + (x[2] ?? 0) + (x[3] ?? "0") + "." + (x[4] ?? "0")).toString(); const factor = `${x.slice(0, 1)}.${x.slice(1)}`; return html ? `<math><mn>${factor}</mn><mo>&sdot;</mo><msup><mn>10</mn><mn>${log10}</mn></msup></math>` : `${factor} × 10` + [...log10.toString()].map(n => '⁰¹²³⁴⁵⁶⁷⁸⁹'[n]).join("") },
79
- btoaUnicode = string => btoa(new TextEncoder("utf-8").encode(string).reduce((data, byte) => data + String.fromCharCode(byte), "")),
79
+ btoaBuffer = b => (Uint8Array.fromBase64?.(b) ?? ([...b = atob(b)].reduce((A, c, i) => (A[i] = c.charCodeAt(0), A), new Uint8Array(b.length)))).buffer,
80
+ btoaUnicode = b => btoa(new TextEncoder("utf-8").encode(b).reduce((data, byte) => data + String.fromCharCode(byte), "")),
80
81
  sanitizeAttr = string => string.replaceAll(/&/g, '&amp;').replaceAll(/"/g, '&quot;').replaceAll(/'/g, '&#39;').replaceAll(/</g, '&lt;').replaceAll(/>/g, '&gt;')
81
82
 
82
83
  // Math Utilities
@@ -427,7 +428,7 @@ function ƒ(_, compressedSubjectOrigins) {
427
428
  part[itemName] = readRecursive([...domains, itemName])
428
429
  } else if (subject.isFile()) {
429
430
  stats.fileCount++
430
- const isBinary = itemName.endsWith(".png") || itemName.endsWith(".gif")
431
+ const isBinary = itemName.endsWith(".png") || itemName.endsWith(".gif") || itemName.endsWith(".bin")
431
432
  bufferLog(3, "".padEnd(domains.length, " ") + `${isBinary ? "▣" : "≡"} ${itemName}`)
432
433
  subjectOrigins.set(host + "/" + itemName, path === projectPath)
433
434
  part[itemName] = readFile(resolve(path, itemName), isBinary ? "base64" : "utf-8")
@@ -655,6 +656,8 @@ function ƒ(_, compressedSubjectOrigins) {
655
656
  // Resolve late-bound properties in the order they were added to the descriptor map.
656
657
  for (const propertyKey of Reflect.ownKeys(descriptorMap)) {
657
658
  const propertyDescriptor = descriptorMap[propertyKey]
659
+ if (typeof propertyDescriptor !== "object")
660
+ throw new TypeError(`Part Define Error: property definition for "${propertyKey}" on part ${this.host} must be an object, not a primitive value (got ${typeof propertyDescriptor}).`)
658
661
  if ("resolve" in propertyDescriptor) {
659
662
  propertyDescriptor.value = propertyDescriptor.resolve.call(this)
660
663
  delete propertyDescriptor.resolve
@@ -1061,7 +1064,7 @@ function ƒ(_, compressedSubjectOrigins) {
1061
1064
  includeColor: "full",
1062
1065
  includeEra: "full",
1063
1066
  includeMenuApps: "full",
1064
- includeUpdates: "full",
1067
+ // includeUpdates: "full",
1065
1068
  includeKirejiApp: "full",
1066
1069
  includeDesktop: "full"
1067
1070
  })
@@ -30,7 +30,7 @@ if (!newArm)
30
30
  throw new Error("An arm to enable could not be found.")
31
31
 
32
32
  if (oldArm && newArm !== oldArm && !disabledArm)
33
- oldArm.distributeRouteID(-1n)
33
+ oldArm.distributeRouteID(-1n, SKIP_RUNTIME_STATE_DISTRIBUTION)
34
34
 
35
35
  match.updateRouteID(match.offsets.get(newArm) + newArm.routeID)
36
36
 
@@ -4,7 +4,7 @@ const arms = [...match]
4
4
 
5
5
  if (ROUTE_ID === -1n) {
6
6
  if (match.arm !== null)
7
- match.arm.distributeRouteID(-1n)
7
+ match.arm.distributeRouteID(-1n, SKIP_RUNTIME_STATE_DISTRIBUTION)
8
8
  match.arm = null
9
9
  } else for (let index = 0; index < arms.length; index++) {
10
10
  const nextIndex = index + 1
@@ -15,9 +15,9 @@ if (ROUTE_ID === -1n) {
15
15
  const armRouteID = ROUTE_ID - match.offsets.get(newArm)
16
16
 
17
17
  if (oldArm && oldArm !== newArm)
18
- oldArm.distributeRouteID(-1n)
18
+ oldArm.distributeRouteID(-1n, SKIP_RUNTIME_STATE_DISTRIBUTION)
19
19
 
20
- newArm.distributeRouteID(armRouteID)
20
+ newArm.distributeRouteID(armRouteID, SKIP_RUNTIME_STATE_DISTRIBUTION)
21
21
  match.arm = newArm
22
22
  break
23
23
  }
@@ -2,12 +2,17 @@ mesh.define({
2
2
  triTable: { value: [] },
3
3
  triIndex: { value: -1, writable: true },
4
4
  position: { value: { x: null, y: null } },
5
+ data: {
6
+ resolve() {
7
+ return mesh.getData()
8
+ }
9
+ },
5
10
  cardinality: {
6
11
  resolve() {
7
12
  let meshCardinality = 0n
8
13
 
9
- // Obtain the raw data for this mesh.
10
- const [pointList, tris] = mesh.getData()
14
+ // Obtain the raw data for this collision mesh.
15
+ const [pointList, tris] = this.data.collision
11
16
 
12
17
  // Iterate over each tri (array of three point indices) in the data.
13
18
  for (const tri of tris) {
@@ -1,11 +1,12 @@
1
1
  const { points, tris } = mesh.manifest
2
2
 
3
- const data = [[], []]
3
+ const data = { collision: [[], []] }
4
4
 
5
+ // TODO: add a y coordinate use a default 0 for 2D meshes.
5
6
  for (let index = 0; index < points.length; index += 2)
6
- data[0].push([points[index], points[index + 1]])
7
+ data.collision[0].push([Math.round(points[index]), Math.round(points[index + 1])])
7
8
 
8
9
  for (let index = 0; index < tris.length; index += 3)
9
- data[1].push([tris[index], tris[index + 1], tris[index + 2]])
10
+ data.collision[1].push([tris[index], tris[index + 1], tris[index + 2]])
10
11
 
11
12
  return data
@@ -9,7 +9,7 @@ const safeIterationResult = {
9
9
  // Obtain the speed of the force vector, which will be used later if we need to slide along the boundary.
10
10
  const speed = Vector.magnitude(FORCE_VECTOR)
11
11
 
12
- // If there's no motion, nothing will happen; return the safe result.
12
+ // If there's no motion, nothing will happen. Return the safe result.
13
13
  if (speed === 0)
14
14
  return safeIterationResult
15
15
 
@@ -236,7 +236,7 @@ while (true) {
236
236
 
237
237
  } else {
238
238
 
239
- // Discard the unsafe point and return the safe result data.
239
+ // Discard the unsafe point. Return the safe result data.
240
240
  safeIterationResult.hit = true
241
241
  return safeIterationResult
242
242
  }
@@ -1,5 +1,8 @@
1
1
  mesh.updateRouteID(ROUTE_ID)
2
2
 
3
+ if (SKIP_RUNTIME_STATE_DISTRIBUTION)
4
+ return
5
+
3
6
  // Binary search better than embedded match.
4
7
  mesh.triIndex = (() => {
5
8
 
@@ -27,6 +27,8 @@ declare interface IMesh<TOwner>
27
27
  /** The current position of the state in the mesh. */
28
28
  readonly position: IVector2
29
29
  readonly manifest: IMeshManifest
30
+ /** A cache of the pre-processed geometry data obtained by running the getData method. */
31
+ readonly data: IMeshData
30
32
  }
31
33
 
32
34
  declare interface IMeshTriData {
@@ -70,7 +72,9 @@ declare interface IMeshManifest
70
72
  readonly tris: number[]
71
73
  }
72
74
 
73
- declare type IMeshData = [IMeshPoint[], IMeshTri[]]
75
+ declare type IMeshData = {
76
+ readonly collision: [IMeshPoint[], IMeshTri[]]
77
+ }
74
78
 
75
79
  declare type IMeshTri =
76
80
  [IMeshPointIndex, IMeshPointIndex, IMeshPointIndex]
@@ -1,7 +1,7 @@
1
1
  const model = {}
2
2
 
3
3
  for (const factor of mix)
4
- if (factor.cardinality !== 1n)
5
- model[factor.key] = factor.model
4
+ // if (factor.cardinality !== 1n)
5
+ model[factor.key] = factor.model
6
6
 
7
7
  return model
@@ -2,7 +2,7 @@ mix.updateRouteID(ROUTE_ID)
2
2
 
3
3
  if (ROUTE_ID === -1n) {
4
4
  for (const factor of mix)
5
- factor.distributeRouteID(-1n)
5
+ factor.distributeRouteID(-1n, SKIP_RUNTIME_STATE_DISTRIBUTION)
6
6
  } else {
7
7
  const factors = [...mix]
8
8
 
@@ -12,7 +12,7 @@ if (ROUTE_ID === -1n) {
12
12
  const routeID = ROUTE_ID / placeValue
13
13
 
14
14
  if (factor.routeID !== routeID)
15
- factor.distributeRouteID(routeID)
15
+ factor.distributeRouteID(routeID, SKIP_RUNTIME_STATE_DISTRIBUTION)
16
16
 
17
17
  ROUTE_ID %= placeValue
18
18
  }
@@ -6,17 +6,20 @@
6
6
  "symbol-iterator": [],
7
7
  "routeID-set": [
8
8
  "ROUTE_ID",
9
- "DELTA = false"
9
+ "DELTA = false",
10
+ "SKIP_RUNTIME_STATE_DISTRIBUTION = false"
10
11
  ],
11
12
  "model-set": [
12
- "MODEL"
13
+ "MODEL",
14
+ "SKIP_RUNTIME_STATE_DISTRIBUTION = false"
13
15
  ],
14
16
  "routeID-collect": [
15
17
  "SUBPARTS",
16
18
  "DEPTH"
17
19
  ],
18
20
  "routeID-distribute": [
19
- "ROUTE_ID"
21
+ "ROUTE_ID",
22
+ "SKIP_RUNTIME_STATE_DISTRIBUTION = false"
20
23
  ],
21
24
  "routeID-update": [
22
25
  "ROUTE_ID"
@@ -1,7 +1,7 @@
1
1
  if (DELTA)
2
2
  ROUTE_ID = (ROUTE_ID + part.routeID) % part.cardinality
3
3
 
4
- part.distributeRouteID(ROUTE_ID)
4
+ part.distributeRouteID(ROUTE_ID, SKIP_RUNTIME_STATE_DISTRIBUTION)
5
5
  part[".."]?.collectRouteID([part])
6
6
 
7
7
  if (environment === "client") {
@@ -65,9 +65,13 @@ declare interface IPart<TOwner, TSubpart>
65
65
  /** Collects every build function in the part's prototype chain and then calls them all on the part itself. */
66
66
  readonly startBuild(): void
67
67
  /** Performs `part.modelToRouteID()` on MODEL and then performs `part.setRouteID()` on the resulting route ID. */
68
- readonly setModel(MODEL: any)
69
- /** Sets the part's routeID, propagating it leafward and rootward and updating all views. If DELTA is true, then ROUTE_ID is added to the part's current route ID. */
70
- readonly setRouteID(ROUTE_ID: bigint, DELTA: boolean = false): void
68
+ readonly setModel(MODEL: any, SKIP_RUNTIME_STATE_DISTRIBUTION: boolean = false)
69
+ /** Sets the part's routeID, propagating it leafward and rootward and updating all views.
70
+ *
71
+ * If DELTA is true, ROUTE_ID is added to the part's current route ID.
72
+ *
73
+ * If SKIP_RUNTIME_STATE_DISTRIBUTION is true, the distribution flow will skip setting certain properties. It is assumed that these properties are being managed elsewhere. This is useful when a part's runtime state precision is greater than it's cardinality ("lossy" parts). */
74
+ readonly setRouteID(ROUTE_ID: bigint, DELTA: boolean = false, SKIP_RUNTIME_STATE_DISTRIBUTION: boolean = false): void
71
75
  /** Recomputes and then updates the part's routeID in response to a change in the the given subpart's routeID.
72
76
  *
73
77
  * If the part has a parent, it calls collectRoute on that parent, passing the signal rootward.
@@ -79,7 +83,7 @@ declare interface IPart<TOwner, TSubpart>
79
83
  * For any active subparts, it calls distributeRoute on them, passing the signal leafward.
80
84
  *
81
85
  * To avoid redistributing the same route, **check for route ID changes *before* calling distributeRoute**. */
82
- readonly distributeRouteID(ROUTE_ID: bigint): void
86
+ readonly distributeRouteID(ROUTE_ID: bigint, SKIP_RUNTIME_STATE_DISTRIBUTION: boolean = false): void
83
87
  /** If ROUTE_ID is in the part's range, sets the part to that routeID while caching information about the previous routeID. Otherwise, throws an error.
84
88
  *
85
89
  * This method is called by both collectRoute and distributeRoute. It does not propagate the routeID or update any views. */
@@ -1,5 +1,8 @@
1
1
  partMask.updateRouteID(ROUTE_ID)
2
2
 
3
+ if (SKIP_RUNTIME_STATE_DISTRIBUTION)
4
+ return
5
+
3
6
  let chosenParts = 0
4
7
 
5
8
  partMask.chosenParts.clear()
@@ -1,5 +1,8 @@
1
1
  permutation.updateRouteID(ROUTE_ID)
2
2
 
3
+ if (SKIP_RUNTIME_STATE_DISTRIBUTION)
4
+ return
5
+
3
6
  // Extract the number of instances.
4
7
  const instanceCount = (() => {
5
8
  let estimate = permutation.instanceBitDepths[ROUTE_ID.toString(2).length]
@@ -0,0 +1,12 @@
1
+ let size = (TYPED_ARRAY.byteLength + 3) & ~3
2
+
3
+ if (USAGE == (GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST))
4
+ size = Math.ceil(size / 16) * 16
5
+
6
+ const buffer = gpu.device.createBuffer({ size, usage: USAGE, mappedAtCreation: true })
7
+
8
+ new TYPED_ARRAY.constructor(buffer.getMappedRange()).set(TYPED_ARRAY)
9
+
10
+ buffer.unmap()
11
+
12
+ return buffer
@@ -1,3 +1,9 @@
1
1
  {
2
- "extends": "facet"
2
+ "extends": "facet",
3
+ "methods": {
4
+ "buffer-create": [
5
+ "TYPED_ARRAY",
6
+ "USAGE = GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST"
7
+ ]
8
+ }
3
9
  }
@@ -4,6 +4,10 @@ interface IGpu
4
4
  // Runtime Properties.
5
5
  readonly adapter: GPUAdapter
6
6
  readonly device: GPUDevice
7
+
8
+ // Serialized Properties.
9
+ /** Creates and maps a new buffer on the GPU with the given array contents. */
10
+ readonly createBuffer(TYPED_ARRAY: ArrayBuffer, USAGE: GPUBufferUsageFlags): GPUBuffer
7
11
  }
8
12
 
9
13
  declare const gpu: IGpu
@@ -17,6 +17,8 @@ for (const code of hotKeys.pressed)
17
17
  terminalKeys.add(code.toLowerCase())
18
18
  else if (!production && code === "F8")
19
19
  debugger
20
+ else if (!production && code === "F5")
21
+ location.reload()
20
22
  else debug("Unhandled Key Code: " + code)
21
23
 
22
24
  const combo = [...terminalKeys].sort()
@@ -0,0 +1,21 @@
1
+ const scriptCharCount = new TextEncoder().encode(_["build.js"]).length
2
+ const sizeInMB = scriptCharCount / 10 ** 6
3
+ const sizeInKB = scriptCharCount / 10 ** 3
4
+ const maxSizeInMB = 5
5
+ const appNames = Object.keys(_.applications)
6
+ const longestHost = appNames.reduce((a, b) => (a.length >= b.length ? a : b))
7
+ const worstCaseURL = `https://${longestHost}/${_.version}/${encodeSegment(_.cardinality - 1n)}/`
8
+ const maxURLLength = 2000
9
+ const stateSizeInBits = toBits(_.cardinality - 1n, false)
10
+
11
+ return /* html */`
12
+ <h1>Demo Ecosystem</h1>
13
+ ${_.parts.core.update["part.html"]}
14
+ <ul>
15
+ <li>Apps: ${appNames.length}</li>
16
+ <li>JS Size: ${sizeInMB} MB (${sizeInKB} KB)</li>
17
+ <li>JS Usage: ${sizeInMB / maxSizeInMB * 100}%</li>
18
+ <li>State Size: ${stateSizeInBits} bits (${stateSizeInBits / 8000} KB)</li>
19
+ <li>Worst URL: ${worstCaseURL.length} characters</li>
20
+ <li>URL Usage: ${worstCaseURL.length / maxURLLength * 100}%</li>
21
+ </ul>`
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "application"
3
+ }
@@ -0,0 +1 @@
1
+ About Ecosystem
@@ -1,5 +1,5 @@
1
1
  const menuApplicationsCount = Object.keys(_.menuApplications).length
2
- const controlLinesCount = 4
2
+ const controlLinesCount = 2
3
3
  const separatorCount = 2
4
4
  return part["static.css"] + `
5
5
  task-menu::after {
@@ -2,8 +2,8 @@ const
2
2
  controls = [],
3
3
  sections = []
4
4
 
5
- if (_.includeUpdates === "full" || (!production && _.includeUpdates === "local-only"))
6
- controls.push(update["part.html"])
5
+ // if (_.includeUpdates === "full" || (!production && _.includeUpdates === "local-only"))
6
+ // controls.push(update["part.html"])
7
7
 
8
8
  if (_.includeColor === "full" || (!production && _.includeColor.startsWith("debug-")))
9
9
  controls.push(color["part.html"])
package/src/type.d.ts CHANGED
@@ -230,6 +230,8 @@ class SourceMappedFile {
230
230
  declare const environment: "client" | "worker" | "node-main" | "node-module"
231
231
  /** True if the framework was built on the cloud from the main branch. */
232
232
  declare const production: boolean
233
+ /** Converts a base64-encoded string to an ArrayBuffer. */
234
+ declare function btoaBuffer(BODY: string): string
233
235
  /** A unicode-safe replacement for btoa. */
234
236
  declare function btoaUnicode(BODY: string): string
235
237
  declare function warn(...DATA: any[]): void
@@ -1,251 +0,0 @@
1
- /** An alias for the `navigator` object which was created for better control over linting. */
2
- declare const nav: Navigator & {
3
- readonly gpu: {
4
- requestAdapter(options?: GPURequestAdapterOptions): Promise<GPUAdapter | null>
5
- }
6
- }
7
-
8
- // These type definitions are provided for environments that don't have it.
9
- // Everything below was output by Gemini.
10
-
11
- interface GPUAdapter {
12
- requestDevice(descriptor?: GPUDeviceDescriptor): Promise<GPUDevice>;
13
- features: GPUSupportedFeatures;
14
- limits: GPUSupportedLimits;
15
- isFallbackAdapter: boolean;
16
- name: string;
17
- // Add other GPUAdapter properties and methods as needed
18
- }
19
-
20
- interface GPUDevice {
21
- destroy(): void;
22
- createBuffer(descriptor: GPUBufferDescriptor): GPUBuffer;
23
- createTexture(descriptor: GPUTextureDescriptor): GPUTexture;
24
- createSampler(descriptor?: GPUSamplerDescriptor): GPUSampler;
25
- createBindGroupLayout(descriptor: GPUBindGroupLayoutDescriptor): GPUBindGroupLayout;
26
- createBindGroup(descriptor: GPUBindGroupDescriptor): GPUBindGroup;
27
- createShaderModule(descriptor: GPUShaderModuleDescriptor): GPUShaderModule;
28
- createComputePipeline(descriptor: GPUComputePipelineDescriptor): GPUComputePipeline;
29
- createRenderPipeline(descriptor: GPURenderPipelineDescriptor): GPURenderPipeline;
30
- createCommandEncoder(descriptor?: GPUCommandEncoderDescriptor): GPUCommandEncoder;
31
- createQuerySet(descriptor: GPUQuerySetDescriptor): GPUQuerySet;
32
- importExternalTexture(descriptor: GPUExternalTextureDescriptor): GPUExternalTexture;
33
- popErrorScope(): Promise<GPUError | null>;
34
- pushErrorScope(filter: GPUErrorFilter): void;
35
- queue: GPUQueue;
36
- lost: GPUDeviceLostReason;
37
- // Add GPUDevice properties and methods as needed
38
- }
39
-
40
- interface GPUDeviceDescriptor {
41
- requiredFeatures?: GPUFeatureName[];
42
- requiredLimits?: GPULimits;
43
- defaultQueue?: GPUQueueDescriptor;
44
- }
45
-
46
- interface GPURequestAdapterOptions {
47
- powerPreference?: GPUPowerPreference;
48
- }
49
-
50
- type GPUPowerPreference = "low-power" | "high-performance";
51
-
52
- // other interfaces and types
53
- type GPUFeatureName =
54
- | "depth-clip-control"
55
- | "depth32float-stencil8"
56
- | "timestamp-query"
57
- | "indirect-first-instance"
58
- | "shader-f16"
59
- | "rg11b10ufloat-renderable"
60
- | "bgra8unorm-storage"
61
- | "float32-filterable";
62
-
63
- interface GPUSupportedFeatures extends Set<GPUFeatureName> { }
64
-
65
- interface GPULimits {
66
- maxTextureDimension1D: number;
67
- maxTextureDimension2D: number;
68
- maxTextureDimension3D: number;
69
- maxTextureArrayLayers: number;
70
- maxBindGroups: number;
71
- maxBindGroupsPlusVertexBuffers: number;
72
- maxBindingsPerBindGroup: number;
73
- maxDynamicUniformBuffersPerPipelineLayout: number;
74
- maxDynamicStorageBuffersPerPipelineLayout: number;
75
- maxSampledTexturesPerShaderStage: number;
76
- maxSamplersPerShaderStage: number;
77
- maxStorageBuffersPerShaderStage: number;
78
- maxStorageTexturesPerShaderStage: number;
79
- maxUniformBuffersPerShaderStage: number;
80
- maxUniformBufferBindingSize: number;
81
- maxStorageBufferBindingSize: number;
82
- minUniformBufferOffsetAlignment: number;
83
- minStorageBufferOffsetAlignment: number;
84
- maxVertexBuffers: number;
85
- maxVertexAttributes: number;
86
- maxVertexBufferArrayStride: number;
87
- maxInterStageShaderComponents: number;
88
- maxComputeWorkgroupStorageSize: number;
89
- maxComputeInvocationsPerWorkgroup: number;
90
- maxComputeWorkgroupSizeX: number;
91
- maxComputeWorkgroupSizeY: number;
92
- maxComputeWorkgroupSizeZ: number;
93
- maxComputeWorkgroupsPerDimension: number;
94
- }
95
-
96
- interface GPUSupportedLimits extends GPULimits { }
97
-
98
- interface GPUBufferDescriptor {
99
- size: GPUSize64;
100
- usage: GPUBufferUsageFlags;
101
- mappedAtCreation?: boolean;
102
- }
103
-
104
- type GPUBufferUsageFlags = number;
105
-
106
- type GPUSize64 = number;
107
-
108
- interface GPUTextureDescriptor {
109
- size: GPUExtent3D;
110
- format: GPUTextureFormat;
111
- usage: GPUTextureUsageFlags;
112
- dimension?: GPUTextureDimension;
113
- mipLevelCount?: GPUIntegerCoordinate;
114
- sampleCount?: GPUIntegerCoordinate;
115
- viewFormats?: GPUTextureFormat[];
116
- }
117
-
118
- type GPUTextureFormat = string;
119
- type GPUTextureUsageFlags = number;
120
- type GPUTextureDimension = "1d" | "2d" | "3d";
121
- type GPUIntegerCoordinate = number;
122
-
123
- interface GPUExtent3D {
124
- width: GPUIntegerCoordinate;
125
- height?: GPUIntegerCoordinate;
126
- depthOrArrayLayers?: GPUIntegerCoordinate;
127
- }
128
-
129
- interface GPUSamplerDescriptor {
130
- addressModeU?: GPUAddressMode;
131
- addressModeV?: GPUAddressMode;
132
- addressModeW?: GPUAddressMode;
133
- magFilter?: GPUFilterMode;
134
- minFilter?: GPUFilterMode;
135
- mipmapFilter?: GPUMipmapFilterMode;
136
- lodMinClamp?: number;
137
- lodMaxClamp?: number;
138
- compare?: GPUCompareFunction;
139
- maxAnisotropy?: number;
140
- }
141
-
142
- type GPUAddressMode = "clamp-to-edge" | "repeat" | "mirror-repeat";
143
- type GPUFilterMode = "nearest" | "linear";
144
- type GPUMipmapFilterMode = "nearest" | "linear";
145
- type GPUCompareFunction = string;
146
-
147
- interface GPUBindGroupLayoutDescriptor {
148
- entries: GPUBindGroupLayoutEntry[];
149
- }
150
-
151
- interface GPUBindGroupLayoutEntry {
152
- binding: GPUIndex32;
153
- visibility: GPUShaderStageFlags;
154
- buffer?: GPUBufferBindingLayout;
155
- sampler?: GPUSamplerBindingLayout;
156
- texture?: GPUTextureBindingLayout;
157
- storageTexture?: GPUStorageTextureBindingLayout;
158
- externalTexture?: GPUExternalTextureBindingLayout;
159
- }
160
-
161
- type GPUIndex32 = number;
162
- type GPUShaderStageFlags = number;
163
-
164
- interface GPUBufferBindingLayout {
165
- type?: GPUBufferBindingType;
166
- hasDynamicOffset?: boolean;
167
- minBindingSize?: GPUSize64;
168
- }
169
-
170
- type GPUBufferBindingType = "uniform" | "storage" | "read-only-storage";
171
-
172
- interface GPUSamplerBindingLayout {
173
- type?: GPUSamplerBindingType;
174
- }
175
-
176
- type GPUSamplerBindingType = "filtering" | "non-filtering" | "comparison";
177
-
178
- interface GPUTextureBindingLayout {
179
- sampleType?: GPUTextureSampleType;
180
- viewDimension?: GPUTextureViewDimension;
181
- multisampled?: boolean;
182
- }
183
-
184
- type GPUTextureSampleType = "float" | "unfilterable-float" | "depth" | "sint" | "uint";
185
- type GPUTextureViewDimension = "1d" | "2d" | "2d-array" | "cube" | "cube-array" | "3d";
186
-
187
- interface GPUStorageTextureBindingLayout {
188
- access?: GPUStorageTextureAccess;
189
- format: GPUTextureFormat;
190
- viewDimension?: GPUTextureViewDimension;
191
- }
192
-
193
- type GPUStorageTextureAccess = "read-only" | "write-only" | "read-write";
194
-
195
- interface GPUExternalTextureBindingLayout { }
196
-
197
- interface GPUBindGroupDescriptor {
198
- layout: GPUBindGroupLayout;
199
- entries: GPUBindGroupEntry[];
200
- }
201
-
202
- interface GPUBindGroupEntry {
203
- binding: GPUIndex32;
204
- buffer?: GPUBuffer;
205
- offset?: GPUSize64;
206
- size?: GPUSize64;
207
- sampler?: GPUSampler;
208
- textureView?: GPUTextureView;
209
- externalTexture?: GPUExternalTexture;
210
- }
211
-
212
- interface GPUShaderModuleDescriptor {
213
- code: string;
214
- label?: string;
215
- }
216
-
217
- interface GPUComputePipelineDescriptor {
218
- layout?: GPUPipelineLayout;
219
- compute: GPUComputePipelineStage;
220
- }
221
-
222
- interface GPURenderPipelineDescriptor {
223
- layout?: GPUPipelineLayout;
224
- vertex: GPUVertexState;
225
- primitive?: GPUPrimitiveState;
226
- depthStencil?: GPUDepthStencilState;
227
- multisample?: GPUMultisampleState;
228
- fragment?: GPUFragmentState;
229
- }
230
-
231
- interface GPUPipelineLayout { }
232
- interface GPUComputePipelineStage { }
233
- interface GPUVertexState { }
234
- interface GPUPrimitiveState { }
235
- interface GPUDepthStencilState { }
236
- interface GPUMultisampleState { }
237
- interface GPUFragmentState { }
238
- interface GPUCommandEncoderDescriptor { }
239
- interface GPUQuerySetDescriptor { }
240
- interface GPUExternalTextureDescriptor { }
241
- interface GPUQueueDescriptor { }
242
- interface GPUTextureView { }
243
- interface GPUExternalTexture { }
244
- interface GPUQueue { }
245
- interface GPUError { }
246
- type GPUErrorFilter = "out-of-memory" | "validation";
247
- type GPUDeviceLostReason = "destroyed" | "unknown";
248
- interface GPUComputePipeline { }
249
- interface GPURenderPipeline { }
250
- interface GPUCommandEncoder { }
251
- interface GPUQuerySet { }