implement brush cost gauges

they're a little ugly at the moment, and can be a little useless for most simple brushes, but whatever we'll make them better later
This commit is contained in:
liquidex 2024-10-25 21:38:18 +02:00
parent 43e6951f7d
commit 913d65b0a8
19 changed files with 378 additions and 65 deletions

View file

@ -279,11 +279,24 @@ extern "C" fn haku_status_string(code: StatusCode) -> *const i8 {
.as_ptr() .as_ptr()
} }
#[derive(Debug)]
struct CompileStats {
ast_size: usize,
}
#[derive(Debug)]
struct RunnableBrush {
chunk_id: ChunkId,
closure_spec: ClosureSpec,
compile_stats: CompileStats,
}
#[derive(Debug, Default)] #[derive(Debug, Default)]
enum BrushState { enum BrushState {
#[default] #[default]
Default, Default,
Ready(ChunkId, ClosureSpec), Ready(RunnableBrush),
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -431,7 +444,13 @@ unsafe extern "C" fn haku_compile_brush(
Ok(chunk_id) => chunk_id, Ok(chunk_id) => chunk_id,
Err(_) => return StatusCode::TooManyChunks, Err(_) => return StatusCode::TooManyChunks,
}; };
brush.state = BrushState::Ready(chunk_id, closure_spec); brush.state = BrushState::Ready(RunnableBrush {
chunk_id,
closure_spec,
compile_stats: CompileStats {
ast_size: ast.len(),
},
});
info!("brush compiled into {chunk_id:?}"); info!("brush compiled into {chunk_id:?}");
@ -470,7 +489,7 @@ unsafe extern "C" fn haku_begin_brush(instance: *mut Instance, brush: *const Bru
let instance = &mut *instance; let instance = &mut *instance;
let brush = &*brush; let brush = &*brush;
let BrushState::Ready(chunk_id, closure_spec) = brush.state else { let BrushState::Ready(runnable) = &brush.state else {
panic!("brush is not compiled and ready to be used"); panic!("brush is not compiled and ready to be used");
}; };
@ -479,10 +498,10 @@ unsafe extern "C" fn haku_begin_brush(instance: *mut Instance, brush: *const Bru
instance.reset_exception(); instance.reset_exception();
instance.trampoline = None; instance.trampoline = None;
let Ok(closure_id) = instance let Ok(closure_id) = instance.vm.create_ref(Ref::Closure(Closure::chunk(
.vm runnable.chunk_id,
.create_ref(Ref::Closure(Closure::chunk(chunk_id, closure_spec))) runnable.closure_spec,
else { ))) else {
return StatusCode::OutOfRefSlots; return StatusCode::OutOfRefSlots;
}; };
@ -574,3 +593,26 @@ unsafe extern "C" fn haku_cont_dotter(
) )
}) })
} }
#[unsafe(no_mangle)]
unsafe extern "C" fn haku_stat_ast_size(brush: *const Brush) -> usize {
match &(*brush).state {
BrushState::Default => 0,
BrushState::Ready(runnable) => runnable.compile_stats.ast_size,
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn haku_stat_num_refs(instance: *const Instance) -> usize {
(*instance).vm.num_refs()
}
#[unsafe(no_mangle)]
unsafe extern "C" fn haku_stat_remaining_fuel(instance: *const Instance) -> usize {
(*instance).vm.remaining_fuel()
}
#[unsafe(no_mangle)]
unsafe extern "C" fn haku_stat_remaining_memory(instance: *const Instance) -> usize {
(*instance).vm.remaining_memory()
}

View file

@ -73,10 +73,18 @@ impl Vm {
} }
} }
pub fn num_refs(&self) -> usize {
self.refs.len()
}
pub fn remaining_fuel(&self) -> usize { pub fn remaining_fuel(&self) -> usize {
self.fuel self.fuel
} }
pub fn remaining_memory(&self) -> usize {
self.memory
}
pub fn set_fuel(&mut self, fuel: usize) { pub fn set_fuel(&mut self, fuel: usize) {
self.fuel = fuel; self.fuel = fuel;
} }

View file

@ -1,7 +1,13 @@
#!/usr/bin/env fish #!/usr/bin/env fish
set filename $argv[1] function mkicon
set icon_name (basename $filename .svg) set -l filename $argv[1]
set icon_base64 (svgcleaner --stdout $filename 2>/dev/null | base64 -w0) set -l icon_name (basename $filename .svg)
set -l icon_base64 (svgcleaner --stdout $filename 2>/dev/null | base64 -w0)
printf "--icon-%s: url('data:image/svg+xml;base64,%s');" "$icon_name" "$icon_base64" printf "--icon-%s: url('data:image/svg+xml;base64,%s');\n" "$icon_name" "$icon_base64"
end
for arg in $argv
mkicon $arg
end

View file

@ -166,12 +166,20 @@ pre:has(code) {
/* Icons */ /* Icons */
:root { :root {
--icon-rkgk-grayscale: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHdpZHRoPSIxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBkPSJtMCAwaDE2djE2aC0xNnoiLz48L2NsaXBQYXRoPjxnIGNsaXAtcGF0aD0idXJsKCNhKSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjIiPjxwYXRoIGQ9Im0xMiAxNy00LjU1Mjc5LTkuMTA1NTdjLS42NjQ5LTEuMzI5ODEuMzAyMDktMi44OTQ0MyAxLjc4ODg2LTIuODk0NDNoOC43NjM5MyIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxnIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PHBhdGggZD0ibTUuNSAxMi0yLjUgNSIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLW9wYWNpdHk9Ii41Ii8+PHBhdGggZD0ibTMgNWgxIi8+PC9nPjwvZz48L3N2Zz4="); --icon-brackets: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHdpZHRoPSIxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNyA0aC0zdjhoM20yLThoM3Y4aC0zIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMiIvPjwvc3ZnPg==");
--icon-droplet: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHdpZHRoPSIxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNSAxMGMwLTEuNjM0NzIgMS4wMDIxMi00LjI3MTU2IDIuMTg3MjYtNi41NDUzNy4zNDg5My0uNjY5NDQgMS4yNzY1NS0uNjY5NDQgMS42MjU0OCAwIDEuMTg1MTQgMi4yNzM4MSAyLjE4NzI2IDQuOTEwNjUgMi4xODcyNiA2LjU0NTM3IDAgMi0xLjUgMy0zIDNzLTMtMS0zLTN6IiBmaWxsPSIjMDAwIi8+PC9zdmc+");
--icon-external-link: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHdpZHRoPSIxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBzdHJva2U9IiMwMDAiPjxwYXRoIGQ9Im0xMC41IDl2Mi41aC02di02aDIuNSIvPjxwYXRoIGQ9Im03IDkgNC41LTQuNW0wIDBoLTMuNW0zLjUgMHYzLjUiLz48L2c+PC9zdmc+"); --icon-external-link: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHdpZHRoPSIxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBzdHJva2U9IiMwMDAiPjxwYXRoIGQ9Im0xMC41IDl2Mi41aC02di02aDIuNSIvPjxwYXRoIGQ9Im03IDkgNC41LTQuNW0wIDBoLTMuNW0zLjUgMHYzLjUiLz48L2c+PC9zdmc+");
--icon-memory: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHdpZHRoPSIxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjMDAwIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iLjEiPjxwYXRoIGQ9Im01LjA1IDMuMDVoNS45djkuOWgtNS45eiIvPjxwYXRoIGQ9Im0zLjA1IDQuMDVoMS45djEuOWgtMS45eiIvPjxwYXRoIGQ9Im0xMS4wNSA0LjA1aDEuOXYxLjloLTEuOXoiLz48cGF0aCBkPSJtMy4wNSA3LjA1aDEuOXYxLjloLTEuOXoiLz48cGF0aCBkPSJtMTEuMDUgNy4wNWgxLjl2MS45aC0xLjl6Ii8+PHBhdGggZD0ibTMuMDUgMTAuMDVoMS45djEuOWgtMS45eiIvPjxwYXRoIGQ9Im0xMS4wNSAxMC4wNWgxLjl2MS45aC0xLjl6Ii8+PC9nPjwvc3ZnPg==");
--icon-object: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHdpZHRoPSIxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Im0xMiA2YzAgMS4xMDQ1Ny0uODk1NCAyLTIgMnYyYzIuMjA5MSAwIDQtMS43OTA4NiA0LTRzLTEuNzkwOS00LTQtNGMtMi4yMDkxNCAwLTQgMS43OTA4Ni00IDRoMmMwLTEuMTA0NTcuODk1NDMtMiAyLTIgMS4xMDQ2IDAgMiAuODk1NDMgMiAyeiIgZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0ibTMgN2g2djZoLTZ6IiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMiIvPjwvc3ZnPg==");
--icon-rkgk-grayscale: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHdpZHRoPSIxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBkPSJtMCAwaDE2djE2aC0xNnoiLz48L2NsaXBQYXRoPjxnIGNsaXAtcGF0aD0idXJsKCNhKSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjIiPjxwYXRoIGQ9Im0xMiAxNy00LjU1Mjc5LTkuMTA1NTdjLS42NjQ5LTEuMzI5ODEuMzAyMDktMi44OTQ0MyAxLjc4ODg2LTIuODk0NDNoOC43NjM5MyIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxnIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PHBhdGggZD0ibTUuNSAxMi0yLjUgNSIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLW9wYWNpdHk9Ii41Ii8+PHBhdGggZD0ibTMgNWgxIi8+PC9nPjwvZz48L3N2Zz4=");
--icon-brackets-white: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHdpZHRoPSIxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNyA0aC0zdjhoM20yLThoM3Y4aC0zIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIvPjwvc3ZnPg==");
--icon-droplet-white: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHdpZHRoPSIxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNSAxMGMwLTEuNjM0NzIgMS4wMDIxMi00LjI3MTU2IDIuMTg3MjYtNi41NDUzNy4zNDg5My0uNjY5NDQgMS4yNzY1NS0uNjY5NDQgMS42MjU0OCAwIDEuMTg1MTQgMi4yNzM4MSAyLjE4NzI2IDQuOTEwNjUgMi4xODcyNiA2LjU0NTM3IDAgMi0xLjUgMy0zIDNzLTMtMS0zLTN6IiBmaWxsPSIjZmZmIi8+PC9zdmc+");
--icon-object-white: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHdpZHRoPSIxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Im0xMiA2YzAgMS4xMDQ1Ny0uODk1NCAyLTIgMnYyYzIuMjA5MSAwIDQtMS43OTA4NiA0LTRzLTEuNzkwOS00LTQtNGMtMi4yMDkxNCAwLTQgMS43OTA4Ni00IDRoMmMwLTEuMTA0NTcuODk1NDMtMiAyLTIgMS4xMDQ2IDAgMiAuODk1NDMgMiAyeiIgZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIi8+PHBhdGggZD0ibTMgN2g2djZoLTZ6IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIvPjwvc3ZnPg==");
--icon-memory-white: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjE2IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHdpZHRoPSIxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjZmZmIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iLjEiPjxwYXRoIGQ9Im01LjA1IDMuMDVoNS45djkuOWgtNS45eiIvPjxwYXRoIGQ9Im0zLjA1IDQuMDVoMS45djEuOWgtMS45eiIvPjxwYXRoIGQ9Im0xMS4wNSA0LjA1aDEuOXYxLjloLTEuOXoiLz48cGF0aCBkPSJtMy4wNSA3LjA1aDEuOXYxLjloLTEuOXoiLz48cGF0aCBkPSJtMTEuMDUgNy4wNWgxLjl2MS45aC0xLjl6Ii8+PHBhdGggZD0ibTMuMDUgMTAuMDVoMS45djEuOWgtMS45eiIvPjxwYXRoIGQ9Im0xMS4wNSAxMC4wNWgxLjl2MS45aC0xLjl6Ii8+PC9nPjwvc3ZnPg==");
} }
.icon { .icon {
display: inline-block;
vertical-align: middle; vertical-align: middle;
width: 16px; width: 16px;
height: 16px; height: 16px;
@ -179,10 +187,35 @@ pre:has(code) {
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: 50% 50%; background-position: 50% 50%;
&.icon-rkgk-grayscale { &.icon-brackets {
background-image: var(--icon-rkgk-grayscale); background-image: var(--icon-brackets);
}
&.icon-droplet {
background-image: var(--icon-droplet);
} }
&.icon-external-link { &.icon-external-link {
background-image: var(--icon-external-link); background-image: var(--icon-external-link);
} }
&.icon-memory {
background-image: var(--icon-memory);
}
&.icon-object {
background-image: var(--icon-object);
}
&.icon-rkgk-grayscale {
background-image: var(--icon-rkgk-grayscale);
}
&.icon-brackets-white {
background-image: var(--icon-brackets-white);
}
&.icon-droplet-white {
background-image: var(--icon-droplet-white);
}
&.icon-memory-white {
background-image: var(--icon-memory-white);
}
&.icon-object-white {
background-image: var(--icon-object-white);
}
} }

81
static/brush-cost.js Normal file
View file

@ -0,0 +1,81 @@
class Gauge extends HTMLElement {
constructor(iconName, label) {
super();
this.iconName = iconName;
this.label = label;
}
connectedCallback() {
this.role = "progressbar";
this.classList.add("icon", `icon-${this.iconName}`);
this.full = this.appendChild(document.createElement("div"));
this.full.classList.add("full", "icon", `icon-${this.iconName}-white`);
}
setValue(value, valueMax) {
let clampedNormalized = Math.max(0, Math.min(1, value / valueMax));
this.style.setProperty("--progress", `${clampedNormalized * 100}%`);
this.title = `${this.label}: ${value} / ${valueMax} (${Math.ceil((value / valueMax) * 100)}%)`;
}
}
customElements.define("rkgk-brush-cost-gauge", Gauge);
export class BrushCostGauges extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.codeSizeGauge = this.appendChild(
createGauge({
className: "code-size",
iconName: "brackets",
label: "Code size",
}),
);
this.fuelGauge = this.appendChild(
createGauge({
className: "fuel",
iconName: "droplet",
label: "Fuel",
}),
);
this.objectsGauge = this.appendChild(
createGauge({
className: "objects",
iconName: "object",
label: "Objects",
}),
);
this.memoryGauge = this.appendChild(
createGauge({
className: "memory",
iconName: "memory",
label: "Bulk memory",
}),
);
this.codeSizeGauge.setValue(0);
this.fuelGauge.setValue(0);
this.objectsGauge.setValue(0);
this.memoryGauge.setValue(0);
}
update(stats) {
this.codeSizeGauge.setValue(stats.astSize, stats.astSizeMax);
this.fuelGauge.setValue(stats.fuel, stats.fuelMax);
this.objectsGauge.setValue(stats.numRefs, stats.numRefsMax);
this.memoryGauge.setValue(stats.memory, stats.memoryMax);
}
}
customElements.define("rkgk-brush-cost-gauges", BrushCostGauges);
function createGauge({ className, iconName, label }) {
let gauge = new Gauge(iconName, label);
gauge.classList.add(className);
return gauge;
}

View file

@ -257,4 +257,24 @@ export class Haku {
return { status: "ok" }; return { status: "ok" };
} }
get astSize() {
if (this.#pBrush != 0) {
return w.haku_stat_ast_size(this.#pBrush);
} else {
return 0;
}
}
get numRefs() {
return w.haku_stat_num_refs(this.#pInstance);
}
get remainingFuel() {
return w.haku_stat_remaining_fuel(this.#pInstance);
}
get remainingMemory() {
return w.haku_stat_remaining_memory(this.#pInstance);
}
} }

View file

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 4H4V12H7M9 4H12V12H9" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 171 B

3
static/icon/brackets.svg Normal file
View file

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 4H4V12H7M9 4H12V12H9" stroke="black" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 171 B

View file

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 10C5 8.36528 6.00212 5.72844 7.18726 3.45463C7.53619 2.78519 8.46381 2.78519 8.81274 3.45463C9.99788 5.72844 11 8.36528 11 10C11 12 9.5 13 8 13C6.5 13 5 12 5 10Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 293 B

3
static/icon/droplet.svg Normal file
View file

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 10C5 8.36528 6.00212 5.72844 7.18726 3.45463C7.53619 2.78519 8.46381 2.78519 8.81274 3.45463C9.99788 5.72844 11 8.36528 11 10C11 12 9.5 13 8 13C6.5 13 5 12 5 10Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 293 B

View file

@ -0,0 +1,9 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5.05" y="3.05" width="5.9" height="9.9" fill="white" stroke="white" stroke-width="0.1"/>
<rect x="3.05" y="4.05" width="1.9" height="1.9" fill="white" stroke="white" stroke-width="0.1"/>
<rect x="11.05" y="4.05" width="1.9" height="1.9" fill="white" stroke="white" stroke-width="0.1"/>
<rect x="3.05" y="7.05" width="1.9" height="1.9" fill="white" stroke="white" stroke-width="0.1"/>
<rect x="11.05" y="7.05" width="1.9" height="1.9" fill="white" stroke="white" stroke-width="0.1"/>
<rect x="3.05" y="10.05" width="1.9" height="1.9" fill="white" stroke="white" stroke-width="0.1"/>
<rect x="11.05" y="10.05" width="1.9" height="1.9" fill="white" stroke="white" stroke-width="0.1"/>
</svg>

After

Width:  |  Height:  |  Size: 794 B

9
static/icon/memory.svg Normal file
View file

@ -0,0 +1,9 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5.05" y="3.05" width="5.9" height="9.9" fill="black" stroke="black" stroke-width="0.1"/>
<rect x="3.05" y="4.05" width="1.9" height="1.9" fill="black" stroke="black" stroke-width="0.1"/>
<rect x="11.05" y="4.05" width="1.9" height="1.9" fill="black" stroke="black" stroke-width="0.1"/>
<rect x="3.05" y="7.05" width="1.9" height="1.9" fill="black" stroke="black" stroke-width="0.1"/>
<rect x="11.05" y="7.05" width="1.9" height="1.9" fill="black" stroke="black" stroke-width="0.1"/>
<rect x="3.05" y="10.05" width="1.9" height="1.9" fill="black" stroke="black" stroke-width="0.1"/>
<rect x="11.05" y="10.05" width="1.9" height="1.9" fill="black" stroke="black" stroke-width="0.1"/>
</svg>

After

Width:  |  Height:  |  Size: 794 B

View file

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 6C12 7.10457 11.1046 8 10 8V10C12.2091 10 14 8.20914 14 6C14 3.79086 12.2091 2 10 2C7.79086 2 6 3.79086 6 6H8C8 4.89543 8.89543 4 10 4C11.1046 4 12 4.89543 12 6Z" fill="white"/>
<rect x="3" y="7" width="6" height="6" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 407 B

4
static/icon/object.svg Normal file
View file

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 6C12 7.10457 11.1046 8 10 8V10C12.2091 10 14 8.20914 14 6C14 3.79086 12.2091 2 10 2C7.79086 2 6 3.79086 6 6H8C8 4.89543 8.89543 4 10 4C11.1046 4 12 4.89543 12 6Z" fill="black"/>
<rect x="3" y="7" width="6" height="6" stroke="black" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 407 B

BIN
static/icon/rkgk design.zip Normal file

Binary file not shown.

View file

@ -15,7 +15,7 @@ main {
height: 100%; height: 100%;
position: relative; position: relative;
&>.fullscreen { & > .fullscreen {
width: 100%; width: 100%;
height: 100%; height: 100%;
max-width: 100%; max-width: 100%;
@ -25,23 +25,26 @@ main {
top: 0; top: 0;
} }
&>.panels { & > .panels {
--right-width: 384px; /* Overridden by JavaScript */ --right-width: 384px; /* Overridden by JavaScript */
box-sizing: border-box; box-sizing: border-box;
padding: 16px; padding: 16px;
display: grid; display: grid;
grid-template-columns: [left] 1fr [right-resize] auto [right] minmax(0, var(--right-width)); grid-template-columns: [left] 1fr [right-resize] auto [right] minmax(
0,
var(--right-width)
);
/* Pass all events through. Children may receive events as normal. */ /* Pass all events through. Children may receive events as normal. */
pointer-events: none; pointer-events: none;
&>* { & > * {
pointer-events: all; pointer-events: all;
} }
&>.right { & > .right {
grid-column: right / right; grid-column: right / right;
min-height: 0; min-height: 0;
@ -53,29 +56,41 @@ main {
pointer-events: none; pointer-events: none;
&>* { & > * {
min-width: 0; min-width: 0;
min-height: 0; min-height: 0;
} }
&>rkgk-resize-handle { & > rkgk-resize-handle {
pointer-events: auto; pointer-events: auto;
} }
&>.docked>rkgk-brush-editor { & > .docked > rkgk-brush-editor {
max-height: 100%; max-height: 100%;
pointer-events: auto; pointer-events: auto;
} }
&>.floating>rkgk-brush-preview { & > .floating {
width: 128px; display: flex;
height: 128px; flex-direction: column;
pointer-events: auto;
gap: 12px;
& > rkgk-brush-preview {
width: 128px;
height: 128px;
pointer-events: auto;
}
& > rkgk-brush-cost-gauges {
width: 100%;
pointer-events: auto;
}
} }
} }
} }
&>rkgk-canvas-renderer { & > rkgk-canvas-renderer {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: absolute; position: absolute;
@ -83,7 +98,7 @@ main {
top: 0; top: 0;
} }
&>rkgk-reticle-renderer { & > rkgk-reticle-renderer {
width: 100%; width: 100%;
height: 100%; height: 100%;
position: absolute; position: absolute;
@ -92,7 +107,7 @@ main {
overflow: hidden; overflow: hidden;
} }
&>#js-loading { & > #js-loading {
background-color: var(--color-panel-background); background-color: var(--color-panel-background);
display: flex; display: flex;
@ -111,7 +126,7 @@ rkgk-resize-handle {
cursor: col-resize; cursor: col-resize;
&>.visual { & > .visual {
width: 2px; width: 2px;
height: 100%; height: 100%;
background-color: var(--color-brand-blue); background-color: var(--color-brand-blue);
@ -119,7 +134,8 @@ rkgk-resize-handle {
opacity: 0%; opacity: 0%;
} }
&:hover>.visual, &.dragging>.visual { &:hover > .visual,
&.dragging > .visual {
opacity: 100%; opacity: 100%;
} }
} }
@ -130,7 +146,7 @@ rkgk-resize-handle {
rkgk-canvas-renderer { rkgk-canvas-renderer {
display: block; display: block;
&>canvas { & > canvas {
display: block; display: block;
} }
} }
@ -142,7 +158,7 @@ rkgk-reticle-renderer {
pointer-events: none; pointer-events: none;
&>.reticles { & > .reticles {
position: relative; position: relative;
} }
} }
@ -153,15 +169,15 @@ rkgk-reticle-cursor {
position: absolute; position: absolute;
display: block; display: block;
&>.container { & > .container {
&>.arrow { & > .arrow {
width: 24px; width: 24px;
height: 24px; height: 24px;
background-color: var(--color); background-color: var(--color);
clip-path: path("M 0,0 L 13,13 L 6,13 L 0,19 Z"); clip-path: path("M 0,0 L 13,13 L 6,13 L 0,19 Z");
} }
&>.nickname { & > .nickname {
position: absolute; position: absolute;
top: 20px; top: 20px;
left: 8px; left: 8px;
@ -188,7 +204,7 @@ rkgk-code-editor {
overflow: auto; overflow: auto;
&>.layer { & > .layer {
position: absolute; position: absolute;
left: 0; left: 0;
top: 0; top: 0;
@ -203,7 +219,7 @@ rkgk-code-editor {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
&>.line { & > .line {
flex-shrink: 0; flex-shrink: 0;
white-space: pre-wrap; white-space: pre-wrap;
@ -211,14 +227,14 @@ rkgk-code-editor {
} }
} }
&>.layer-gutter { & > .layer-gutter {
user-select: none; user-select: none;
counter-reset: line; counter-reset: line;
color: transparent; color: transparent;
&>.line { & > .line {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -241,27 +257,27 @@ rkgk-code-editor {
} }
} }
&>.layer:not(.layer-gutter) { & > .layer:not(.layer-gutter) {
margin-left: var(--gutter-width); margin-left: var(--gutter-width);
width: calc(100% - var(--gutter-width)); width: calc(100% - var(--gutter-width));
} }
&>.layer-error-squiggles { & > .layer-error-squiggles {
color: transparent; color: transparent;
&>.line { & > .line {
&>.squiggle { & > .squiggle {
text-decoration: underline wavy black; text-decoration: underline wavy black;
text-decoration-skip-ink: none; text-decoration-skip-ink: none;
} }
&>.squiggle-error { & > .squiggle-error {
text-decoration-color: var(--color-error); text-decoration-color: var(--color-error);
} }
} }
} }
&>textarea { & > textarea {
display: block; display: block;
width: calc(100% - var(--gutter-width)); width: calc(100% - var(--gutter-width));
margin: 0; margin: 0;
@ -294,8 +310,8 @@ rkgk-brush-editor.rkgk-panel {
gap: 4px; gap: 4px;
position: relative; position: relative;
&>.text-area { & > .text-area {
display: block; display: block;
width: 100%; width: 100%;
margin: 0; margin: 0;
@ -306,18 +322,19 @@ rkgk-brush-editor.rkgk-panel {
box-sizing: border-box; box-sizing: border-box;
} }
&>.errors:empty, &>.error-header:empty { & > .errors:empty,
& > .error-header:empty {
display: none; display: none;
} }
&>.error-header { & > .error-header {
margin: 0; margin: 0;
margin-top: 0.5em; margin-top: 0.5em;
font-size: 1rem; font-size: 1rem;
color: var(--color-error); color: var(--color-error);
} }
&>.errors { & > .errors {
margin: 0; margin: 0;
color: var(--color-error); color: var(--color-error);
white-space: pre-wrap; white-space: pre-wrap;
@ -334,13 +351,19 @@ rkgk-brush-preview {
display: block; display: block;
position: relative; position: relative;
background: background: repeating-conic-gradient(
repeating-conic-gradient(var(--checkerboard-light) 0% 25%, var(--checkerboard-dark) 0% 50%) var(--checkerboard-light) 0% 25%,
var(--checkerboard-dark) 0% 50%
)
50% 50% / var(--checkerboard-size) var(--checkerboard-size); 50% 50% / var(--checkerboard-size) var(--checkerboard-size);
border-radius: 4px; border-radius: 4px;
& > canvas {
border-radius: 4px;
}
&.error { &.error {
&>canvas { & > canvas {
display: none; display: none;
} }
@ -354,10 +377,53 @@ rkgk-brush-preview {
} }
} }
/* Brush cost gauges */
rkgk-brush-cost-gauges,
rkgk-brush-cost-gauges.rkgk-panel {
--gauge-size: 20px;
height: var(--gauge-size);
border-radius: 4px;
display: flex;
flex-direction: row;
overflow: clip; /* clip corners */
& > rkgk-brush-cost-gauge {
display: block;
height: var(--gauge-size);
flex-grow: 1;
& > .full {
width: 100%;
height: 100%;
clip-path: xywh(0 0 var(--progress) 100%);
background-color: var(--gauge-color);
}
&.code-size {
--gauge-color: var(--color-brand-blue);
}
&.fuel {
--gauge-color: #f44096;
}
&.objects {
--gauge-color: #fd9916;
}
&.memory {
--gauge-color: #5aca40;
}
}
}
/* Welcome screen */ /* Welcome screen */
rkgk-welcome { rkgk-welcome {
&>dialog { & > dialog {
h3 { h3 {
margin: 0.5rem 0; margin: 0.5rem 0;
font-size: 2rem; font-size: 2rem;
@ -369,7 +435,8 @@ rkgk-welcome {
/* Connection status dialogs */ /* Connection status dialogs */
rkgk-connection-status { rkgk-connection-status {
&>dialog[name='logging-in-dialog'][open], &>dialog[name='disconnected-dialog'][open] { & > dialog[name="logging-in-dialog"][open],
& > dialog[name="disconnected-dialog"][open] {
border: none; border: none;
outline: none; outline: none;
background: none; background: none;
@ -379,8 +446,8 @@ rkgk-connection-status {
align-items: center; align-items: center;
} }
&>dialog[name='error-dialog'][open] { & > dialog[name="error-dialog"][open] {
& textarea[name='error-text'] { & textarea[name="error-text"] {
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
resize: none; resize: none;
@ -394,7 +461,7 @@ rkgk-connection-status {
.menu-bar { .menu-bar {
--border-radius: 4px; --border-radius: 4px;
display: flex; display: flex;
align-items: center; align-items: center;
box-sizing: border-box; box-sizing: border-box;
@ -403,9 +470,9 @@ rkgk-connection-status {
height: 24px; height: 24px;
border-radius: var(--border-radius); border-radius: var(--border-radius);
&>a { & > a {
display: block; display: block;
color: var(--color-text); color: var(--color-text);
padding: 4px 8px; padding: 4px 8px;
text-decoration: none; text-decoration: none;
@ -432,11 +499,10 @@ rkgk-connection-status {
} }
} }
&>hr { & > hr {
height: 100%; height: 100%;
margin: 0; margin: 0;
border: none; border: none;
border-right: 1px solid var(--color-panel-border); border-right: 1px solid var(--color-panel-border);
} }
} }

View file

@ -18,6 +18,7 @@ let canvasRenderer = main.querySelector("rkgk-canvas-renderer");
let reticleRenderer = main.querySelector("rkgk-reticle-renderer"); let reticleRenderer = main.querySelector("rkgk-reticle-renderer");
let brushEditor = main.querySelector("rkgk-brush-editor"); let brushEditor = main.querySelector("rkgk-brush-editor");
let brushPreview = main.querySelector("rkgk-brush-preview"); let brushPreview = main.querySelector("rkgk-brush-preview");
let brushCostGauges = main.querySelector("rkgk-brush-cost-gauges");
let welcome = main.querySelector("rkgk-welcome"); let welcome = main.querySelector("rkgk-welcome");
let connectionStatus = main.querySelector("rkgk-connection-status"); let connectionStatus = main.querySelector("rkgk-connection-status");
@ -251,12 +252,15 @@ function readUrl(urlString) {
let compileResult = currentUser.setBrush(brushEditor.code); let compileResult = currentUser.setBrush(brushEditor.code);
brushEditor.renderHakuResult("Compilation", compileResult); brushEditor.renderHakuResult("Compilation", compileResult);
brushCostGauges.update(currentUser.getStats(session.wallInfo));
if (compileResult.status != "ok") { if (compileResult.status != "ok") {
brushPreview.setErrorFlag(); brushPreview.setErrorFlag();
return; return;
} }
brushPreview.renderBrush(currentUser.haku).then((previewResult) => { brushPreview.renderBrush(currentUser.haku).then((previewResult) => {
brushCostGauges.update(currentUser.getStats(session.wallInfo));
if (previewResult.status == "error") { if (previewResult.status == "error") {
brushEditor.renderHakuResult( brushEditor.renderHakuResult(
previewResult.phase == "eval" ? "Evaluation" : "Rendering", previewResult.phase == "eval" ? "Evaluation" : "Rendering",

View file

@ -89,6 +89,19 @@ export class User {
return false; return false;
} }
} }
getStats(wallInfo) {
return {
astSize: this.haku.astSize,
astSizeMax: wallInfo.hakuLimits.ast_capacity,
numRefs: this.haku.numRefs,
numRefsMax: wallInfo.hakuLimits.ref_capacity,
fuel: wallInfo.hakuLimits.fuel - this.haku.remainingFuel,
fuelMax: wallInfo.hakuLimits.fuel,
memory: wallInfo.hakuLimits.memory - this.haku.remainingMemory,
memoryMax: wallInfo.hakuLimits.memory,
};
}
} }
export class OnlineUsers extends EventTarget { export class OnlineUsers extends EventTarget {

View file

@ -21,6 +21,7 @@
<script type="module"> <script type="module">
import "rkgk/live-reload.js"; import "rkgk/live-reload.js";
import "rkgk/brush-cost.js";
import "rkgk/brush-editor.js"; import "rkgk/brush-editor.js";
import "rkgk/brush-preview.js"; import "rkgk/brush-preview.js";
import "rkgk/canvas-renderer.js"; import "rkgk/canvas-renderer.js";
@ -64,6 +65,7 @@
<div class="right"> <div class="right">
<div class="floating"> <div class="floating">
<rkgk-brush-preview></rkgk-brush-preview> <rkgk-brush-preview></rkgk-brush-preview>
<rkgk-brush-cost-gauges class="rkgk-panel"></rkgk-brush-cost-gauges>
</div> </div>
<rkgk-resize-handle <rkgk-resize-handle
data-direction="vertical" data-direction="vertical"