Skip to content

Repository files navigation

Rdot (JavaScript Signals for Godot! 🥳)

logo

What is Rdot?

Rdot is inspired by most modern Web Frameworks that use a reactive programming model. It enables you to write GDScript with syntax similar to Vue / Solid / Qwik and many other Frameworks... but in Godot!

example

The most common use case for Rdot is to synchronize the state of your game with the UI, although it can be used for other things as well.

⚠️ Disclaimer ⚠️

This should be seen as a proof of concept and not ready for production. While most logic was ported over, there still needs to be more testing to be done.

Logic was sourced from proposal-signals and translated to GDScript. Big shoutout to everyone who contributed to the proposal or worked on the demo in said proposal. ❤️

Usage

varcounter=R.state(0)
vardisplayText=R.computed(func(_ignore):
return"Counter: "+str(counter.value)
)
$AddButton.button_down.connect(func(): counter.value+=1)
$SubtractButton.button_down.connect(func(): counter.value-=1)
R.effect(func(_ignore):
$CounterLabel.text=displayText.value
)

See Explanation for a walkthrough of the code. More examples can be found in the demo folder.

Stores

Stores offer the ability to quickly create many reactive states at once. They are useful for managing the state of your game.

varstore=R.store({ # or R.state({ ... })"counter": 0,
"name": "John Doe"
})
R.effect(func(_ignore):
$CounterLabel.text="Counter: "+str(store.counter)
)

The benefit of this is that you can avoid having to access the value via the value property. Stores support also nested objects, allowing you to create more complex states.

R.state automatically creates a store when an object is passed as an argument.

Binding

Binding is a way to synchronize the state of a reactive value with the UI. It can be used to create 1-way or 2-way bindings.

varnumber=R.state(0)
varmessage=R.state("Hello World")
# 1-way bindingR.bind($Label, "text", message)
# 2-way bindingR.bind($Slider, "value", number, $Slider.value_changed)

There is an edge-case for bindings using Stores. When binding to a store, you have to pass the store as well as the key you want to bind to.

varstore=R.store({
"counter": 0,
"name": "John Doe"
})
R.bind($Label, "text", store, "name")
R.bind($Slider, "value", store, "counter", $Slider.value_changed)

Explanation

R. (R-dot) is the namespace for all Rdot functions.

R.state is a function that creates a reactive state. It returns an object with a value property that you can read and write to. The methods do_get and do_set(value) are also available but behave the same as value.

varcounter=R.state(0)

R.computed recalculated it's value each time a reactive value in the function changes. It returns an object with a value property that you can read. The first argument can be ignored but has to be there for Godot to not complain.

vardouble=R.computed(func(_ignore):
returncounter.value*2
)

R.effect can be used to synchronize the reactive state with the UI. It its rerun each time a reactive value in the function changes.

R.effect(func(_ignore):
print("Double changed: ", double.value)
)

API

## Creates a reactive stateR.state(initialValue: Variant) ->R.RdotState|RdotStore## Creates a computed state based on the returned value of the functionR.computed(func: Callable) ->R.RdotComputed## Runs the function each time a reactive value in the function changes## Returns a function to stop the effectR.effect(func: Callable) ->Callable## Creates a Store based off of a DictionaryR.store(initialValue: Dictionary) ->RdotStore## Updates the target property when the value changes## When a watch_signal is provided, the value will be updated when the signal is emitted (2 way binding)## Returns a function to stop the bindingR.bind(target: Object, property: String, value: R.RdotState|R.RdotComputed, watch_signal: Signal=null) ->Callable## For binding to a storeR.bind(target: Object, property: String, store: RdotStore, key: String, watch_signal: Signal=null) ->Callable

About

JavaScript Signals for Godot!

Topics

Resources

Stars

87 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - Nitwel/Rdot: JavaScript Signals for Godot! · GitHub
Skip to content

Repository files navigation

Rdot (JavaScript Signals for Godot! 🥳)

logo

What is Rdot?

Rdot is inspired by most modern Web Frameworks that use a reactive programming model. It enables you to write GDScript with syntax similar to Vue / Solid / Qwik and many other Frameworks... but in Godot!

example

The most common use case for Rdot is to synchronize the state of your game with the UI, although it can be used for other things as well.

⚠️ Disclaimer ⚠️

This should be seen as a proof of concept and not ready for production. While most logic was ported over, there still needs to be more testing to be done.

Logic was sourced from proposal-signals and translated to GDScript. Big shoutout to everyone who contributed to the proposal or worked on the demo in said proposal. ❤️

Usage

varcounter=R.state(0)
vardisplayText=R.computed(func(_ignore):
return"Counter: "+str(counter.value)
)
$AddButton.button_down.connect(func(): counter.value+=1)
$SubtractButton.button_down.connect(func(): counter.value-=1)
R.effect(func(_ignore):
$CounterLabel.text=displayText.value
)

See Explanation for a walkthrough of the code. More examples can be found in the demo folder.

Stores

Stores offer the ability to quickly create many reactive states at once. They are useful for managing the state of your game.

varstore=R.store({ # or R.state({ ... })"counter": 0,
"name": "John Doe"
})
R.effect(func(_ignore):
$CounterLabel.text="Counter: "+str(store.counter)
)

The benefit of this is that you can avoid having to access the value via the value property. Stores support also nested objects, allowing you to create more complex states.

R.state automatically creates a store when an object is passed as an argument.

Binding

Binding is a way to synchronize the state of a reactive value with the UI. It can be used to create 1-way or 2-way bindings.

varnumber=R.state(0)
varmessage=R.state("Hello World")
# 1-way bindingR.bind($Label, "text", message)
# 2-way bindingR.bind($Slider, "value", number, $Slider.value_changed)

There is an edge-case for bindings using Stores. When binding to a store, you have to pass the store as well as the key you want to bind to.

varstore=R.store({
"counter": 0,
"name": "John Doe"
})
R.bind($Label, "text", store, "name")
R.bind($Slider, "value", store, "counter", $Slider.value_changed)

Explanation

R. (R-dot) is the namespace for all Rdot functions.

R.state is a function that creates a reactive state. It returns an object with a value property that you can read and write to. The methods do_get and do_set(value) are also available but behave the same as value.

varcounter=R.state(0)

R.computed recalculated it's value each time a reactive value in the function changes. It returns an object with a value property that you can read. The first argument can be ignored but has to be there for Godot to not complain.

vardouble=R.computed(func(_ignore):
returncounter.value*2
)

R.effect can be used to synchronize the reactive state with the UI. It its rerun each time a reactive value in the function changes.

R.effect(func(_ignore):
print("Double changed: ", double.value)
)

API

## Creates a reactive stateR.state(initialValue: Variant) ->R.RdotState|RdotStore## Creates a computed state based on the returned value of the functionR.computed(func: Callable) ->R.RdotComputed## Runs the function each time a reactive value in the function changes## Returns a function to stop the effectR.effect(func: Callable) ->Callable## Creates a Store based off of a DictionaryR.store(initialValue: Dictionary) ->RdotStore## Updates the target property when the value changes## When a watch_signal is provided, the value will be updated when the signal is emitted (2 way binding)## Returns a function to stop the bindingR.bind(target: Object, property: String, value: R.RdotState|R.RdotComputed, watch_signal: Signal=null) ->Callable## For binding to a storeR.bind(target: Object, property: String, store: RdotStore, key: String, watch_signal: Signal=null) ->Callable

About

JavaScript Signals for Godot!

Topics

Resources

Stars

87 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Nitwel/Rdot: JavaScript Signals for Godot! · GitHub
Skip to content

Repository files navigation

Rdot (JavaScript Signals for Godot! 🥳)

logo

What is Rdot?

Rdot is inspired by most modern Web Frameworks that use a reactive programming model. It enables you to write GDScript with syntax similar to Vue / Solid / Qwik and many other Frameworks... but in Godot!

example

The most common use case for Rdot is to synchronize the state of your game with the UI, although it can be used for other things as well.

⚠️ Disclaimer ⚠️

This should be seen as a proof of concept and not ready for production. While most logic was ported over, there still needs to be more testing to be done.

Logic was sourced from proposal-signals and translated to GDScript. Big shoutout to everyone who contributed to the proposal or worked on the demo in said proposal. ❤️

Usage

varcounter=R.state(0)
vardisplayText=R.computed(func(_ignore):
return"Counter: "+str(counter.value)
)
$AddButton.button_down.connect(func(): counter.value+=1)
$SubtractButton.button_down.connect(func(): counter.value-=1)
R.effect(func(_ignore):
$CounterLabel.text=displayText.value
)

See Explanation for a walkthrough of the code. More examples can be found in the demo folder.

Stores

Stores offer the ability to quickly create many reactive states at once. They are useful for managing the state of your game.

varstore=R.store({ # or R.state({ ... })"counter": 0,
"name": "John Doe"
})
R.effect(func(_ignore):
$CounterLabel.text="Counter: "+str(store.counter)
)

The benefit of this is that you can avoid having to access the value via the value property. Stores support also nested objects, allowing you to create more complex states.

R.state automatically creates a store when an object is passed as an argument.

Binding

Binding is a way to synchronize the state of a reactive value with the UI. It can be used to create 1-way or 2-way bindings.

varnumber=R.state(0)
varmessage=R.state("Hello World")
# 1-way bindingR.bind($Label, "text", message)
# 2-way bindingR.bind($Slider, "value", number, $Slider.value_changed)

There is an edge-case for bindings using Stores. When binding to a store, you have to pass the store as well as the key you want to bind to.

varstore=R.store({
"counter": 0,
"name": "John Doe"
})
R.bind($Label, "text", store, "name")
R.bind($Slider, "value", store, "counter", $Slider.value_changed)

Explanation

R. (R-dot) is the namespace for all Rdot functions.

R.state is a function that creates a reactive state. It returns an object with a value property that you can read and write to. The methods do_get and do_set(value) are also available but behave the same as value.

varcounter=R.state(0)

R.computed recalculated it's value each time a reactive value in the function changes. It returns an object with a value property that you can read. The first argument can be ignored but has to be there for Godot to not complain.

vardouble=R.computed(func(_ignore):
returncounter.value*2
)

R.effect can be used to synchronize the reactive state with the UI. It its rerun each time a reactive value in the function changes.

R.effect(func(_ignore):
print("Double changed: ", double.value)
)

API

## Creates a reactive stateR.state(initialValue: Variant) ->R.RdotState|RdotStore## Creates a computed state based on the returned value of the functionR.computed(func: Callable) ->R.RdotComputed## Runs the function each time a reactive value in the function changes## Returns a function to stop the effectR.effect(func: Callable) ->Callable## Creates a Store based off of a DictionaryR.store(initialValue: Dictionary) ->RdotStore## Updates the target property when the value changes## When a watch_signal is provided, the value will be updated when the signal is emitted (2 way binding)## Returns a function to stop the bindingR.bind(target: Object, property: String, value: R.RdotState|R.RdotComputed, watch_signal: Signal=null) ->Callable## For binding to a storeR.bind(target: Object, property: String, store: RdotStore, key: String, watch_signal: Signal=null) ->Callable

About

JavaScript Signals for Godot!

Topics

Resources

Stars

87 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Nitwel/Rdot: JavaScript Signals for Godot! · GitHub
Skip to content

Repository files navigation

Rdot (JavaScript Signals for Godot! 🥳)

logo

What is Rdot?

Rdot is inspired by most modern Web Frameworks that use a reactive programming model. It enables you to write GDScript with syntax similar to Vue / Solid / Qwik and many other Frameworks... but in Godot!

example

The most common use case for Rdot is to synchronize the state of your game with the UI, although it can be used for other things as well.

⚠️ Disclaimer ⚠️

This should be seen as a proof of concept and not ready for production. While most logic was ported over, there still needs to be more testing to be done.

Logic was sourced from proposal-signals and translated to GDScript. Big shoutout to everyone who contributed to the proposal or worked on the demo in said proposal. ❤️

Usage

varcounter=R.state(0)
vardisplayText=R.computed(func(_ignore):
return"Counter: "+str(counter.value)
)
$AddButton.button_down.connect(func(): counter.value+=1)
$SubtractButton.button_down.connect(func(): counter.value-=1)
R.effect(func(_ignore):
$CounterLabel.text=displayText.value
)

See Explanation for a walkthrough of the code. More examples can be found in the demo folder.

Stores

Stores offer the ability to quickly create many reactive states at once. They are useful for managing the state of your game.

varstore=R.store({ # or R.state({ ... })"counter": 0,
"name": "John Doe"
})
R.effect(func(_ignore):
$CounterLabel.text="Counter: "+str(store.counter)
)

The benefit of this is that you can avoid having to access the value via the value property. Stores support also nested objects, allowing you to create more complex states.

R.state automatically creates a store when an object is passed as an argument.

Binding

Binding is a way to synchronize the state of a reactive value with the UI. It can be used to create 1-way or 2-way bindings.

varnumber=R.state(0)
varmessage=R.state("Hello World")
# 1-way bindingR.bind($Label, "text", message)
# 2-way bindingR.bind($Slider, "value", number, $Slider.value_changed)

There is an edge-case for bindings using Stores. When binding to a store, you have to pass the store as well as the key you want to bind to.

varstore=R.store({
"counter": 0,
"name": "John Doe"
})
R.bind($Label, "text", store, "name")
R.bind($Slider, "value", store, "counter", $Slider.value_changed)

Explanation

R. (R-dot) is the namespace for all Rdot functions.

R.state is a function that creates a reactive state. It returns an object with a value property that you can read and write to. The methods do_get and do_set(value) are also available but behave the same as value.

varcounter=R.state(0)

R.computed recalculated it's value each time a reactive value in the function changes. It returns an object with a value property that you can read. The first argument can be ignored but has to be there for Godot to not complain.

vardouble=R.computed(func(_ignore):
returncounter.value*2
)

R.effect can be used to synchronize the reactive state with the UI. It its rerun each time a reactive value in the function changes.

R.effect(func(_ignore):
print("Double changed: ", double.value)
)

API

## Creates a reactive stateR.state(initialValue: Variant) ->R.RdotState|RdotStore## Creates a computed state based on the returned value of the functionR.computed(func: Callable) ->R.RdotComputed## Runs the function each time a reactive value in the function changes## Returns a function to stop the effectR.effect(func: Callable) ->Callable## Creates a Store based off of a DictionaryR.store(initialValue: Dictionary) ->RdotStore## Updates the target property when the value changes## When a watch_signal is provided, the value will be updated when the signal is emitted (2 way binding)## Returns a function to stop the bindingR.bind(target: Object, property: String, value: R.RdotState|R.RdotComputed, watch_signal: Signal=null) ->Callable## For binding to a storeR.bind(target: Object, property: String, store: RdotStore, key: String, watch_signal: Signal=null) ->Callable

About

JavaScript Signals for Godot!

Topics

Resources

Stars

87 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - Nitwel/Rdot: JavaScript Signals for Godot! · GitHub
Skip to content

Repository files navigation

Rdot (JavaScript Signals for Godot! 🥳)

logo

What is Rdot?

Rdot is inspired by most modern Web Frameworks that use a reactive programming model. It enables you to write GDScript with syntax similar to Vue / Solid / Qwik and many other Frameworks... but in Godot!

example

The most common use case for Rdot is to synchronize the state of your game with the UI, although it can be used for other things as well.

⚠️ Disclaimer ⚠️

This should be seen as a proof of concept and not ready for production. While most logic was ported over, there still needs to be more testing to be done.

Logic was sourced from proposal-signals and translated to GDScript. Big shoutout to everyone who contributed to the proposal or worked on the demo in said proposal. ❤️

Usage

varcounter=R.state(0)
vardisplayText=R.computed(func(_ignore):
return"Counter: "+str(counter.value)
)
$AddButton.button_down.connect(func(): counter.value+=1)
$SubtractButton.button_down.connect(func(): counter.value-=1)
R.effect(func(_ignore):
$CounterLabel.text=displayText.value
)

See Explanation for a walkthrough of the code. More examples can be found in the demo folder.

Stores

Stores offer the ability to quickly create many reactive states at once. They are useful for managing the state of your game.

varstore=R.store({ # or R.state({ ... })"counter": 0,
"name": "John Doe"
})
R.effect(func(_ignore):
$CounterLabel.text="Counter: "+str(store.counter)
)

The benefit of this is that you can avoid having to access the value via the value property. Stores support also nested objects, allowing you to create more complex states.

R.state automatically creates a store when an object is passed as an argument.

Binding

Binding is a way to synchronize the state of a reactive value with the UI. It can be used to create 1-way or 2-way bindings.

varnumber=R.state(0)
varmessage=R.state("Hello World")
# 1-way bindingR.bind($Label, "text", message)
# 2-way bindingR.bind($Slider, "value", number, $Slider.value_changed)

There is an edge-case for bindings using Stores. When binding to a store, you have to pass the store as well as the key you want to bind to.

varstore=R.store({
"counter": 0,
"name": "John Doe"
})
R.bind($Label, "text", store, "name")
R.bind($Slider, "value", store, "counter", $Slider.value_changed)

Explanation

R. (R-dot) is the namespace for all Rdot functions.

R.state is a function that creates a reactive state. It returns an object with a value property that you can read and write to. The methods do_get and do_set(value) are also available but behave the same as value.

varcounter=R.state(0)

R.computed recalculated it's value each time a reactive value in the function changes. It returns an object with a value property that you can read. The first argument can be ignored but has to be there for Godot to not complain.

vardouble=R.computed(func(_ignore):
returncounter.value*2
)

R.effect can be used to synchronize the reactive state with the UI. It its rerun each time a reactive value in the function changes.

R.effect(func(_ignore):
print("Double changed: ", double.value)
)

API

## Creates a reactive stateR.state(initialValue: Variant) ->R.RdotState|RdotStore## Creates a computed state based on the returned value of the functionR.computed(func: Callable) ->R.RdotComputed## Runs the function each time a reactive value in the function changes## Returns a function to stop the effectR.effect(func: Callable) ->Callable## Creates a Store based off of a DictionaryR.store(initialValue: Dictionary) ->RdotStore## Updates the target property when the value changes## When a watch_signal is provided, the value will be updated when the signal is emitted (2 way binding)## Returns a function to stop the bindingR.bind(target: Object, property: String, value: R.RdotState|R.RdotComputed, watch_signal: Signal=null) ->Callable## For binding to a storeR.bind(target: Object, property: String, store: RdotStore, key: String, watch_signal: Signal=null) ->Callable

About

JavaScript Signals for Godot!

Topics

Resources

Stars

87 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Nitwel/Rdot: JavaScript Signals for Godot! · GitHub
Skip to content

Repository files navigation

Rdot (JavaScript Signals for Godot! 🥳)

logo

What is Rdot?

Rdot is inspired by most modern Web Frameworks that use a reactive programming model. It enables you to write GDScript with syntax similar to Vue / Solid / Qwik and many other Frameworks... but in Godot!

example

The most common use case for Rdot is to synchronize the state of your game with the UI, although it can be used for other things as well.

⚠️ Disclaimer ⚠️

This should be seen as a proof of concept and not ready for production. While most logic was ported over, there still needs to be more testing to be done.

Logic was sourced from proposal-signals and translated to GDScript. Big shoutout to everyone who contributed to the proposal or worked on the demo in said proposal. ❤️

Usage

varcounter=R.state(0)
vardisplayText=R.computed(func(_ignore):
return"Counter: "+str(counter.value)
)
$AddButton.button_down.connect(func(): counter.value+=1)
$SubtractButton.button_down.connect(func(): counter.value-=1)
R.effect(func(_ignore):
$CounterLabel.text=displayText.value
)

See Explanation for a walkthrough of the code. More examples can be found in the demo folder.

Stores

Stores offer the ability to quickly create many reactive states at once. They are useful for managing the state of your game.

varstore=R.store({ # or R.state({ ... })"counter": 0,
"name": "John Doe"
})
R.effect(func(_ignore):
$CounterLabel.text="Counter: "+str(store.counter)
)

The benefit of this is that you can avoid having to access the value via the value property. Stores support also nested objects, allowing you to create more complex states.

R.state automatically creates a store when an object is passed as an argument.

Binding

Binding is a way to synchronize the state of a reactive value with the UI. It can be used to create 1-way or 2-way bindings.

varnumber=R.state(0)
varmessage=R.state("Hello World")
# 1-way bindingR.bind($Label, "text", message)
# 2-way bindingR.bind($Slider, "value", number, $Slider.value_changed)

There is an edge-case for bindings using Stores. When binding to a store, you have to pass the store as well as the key you want to bind to.

varstore=R.store({
"counter": 0,
"name": "John Doe"
})
R.bind($Label, "text", store, "name")
R.bind($Slider, "value", store, "counter", $Slider.value_changed)

Explanation

R. (R-dot) is the namespace for all Rdot functions.

R.state is a function that creates a reactive state. It returns an object with a value property that you can read and write to. The methods do_get and do_set(value) are also available but behave the same as value.

varcounter=R.state(0)

R.computed recalculated it's value each time a reactive value in the function changes. It returns an object with a value property that you can read. The first argument can be ignored but has to be there for Godot to not complain.

vardouble=R.computed(func(_ignore):
returncounter.value*2
)

R.effect can be used to synchronize the reactive state with the UI. It its rerun each time a reactive value in the function changes.

R.effect(func(_ignore):
print("Double changed: ", double.value)
)

API

## Creates a reactive stateR.state(initialValue: Variant) ->R.RdotState|RdotStore## Creates a computed state based on the returned value of the functionR.computed(func: Callable) ->R.RdotComputed## Runs the function each time a reactive value in the function changes## Returns a function to stop the effectR.effect(func: Callable) ->Callable## Creates a Store based off of a DictionaryR.store(initialValue: Dictionary) ->RdotStore## Updates the target property when the value changes## When a watch_signal is provided, the value will be updated when the signal is emitted (2 way binding)## Returns a function to stop the bindingR.bind(target: Object, property: String, value: R.RdotState|R.RdotComputed, watch_signal: Signal=null) ->Callable## For binding to a storeR.bind(target: Object, property: String, store: RdotStore, key: String, watch_signal: Signal=null) ->Callable

About

JavaScript Signals for Godot!

Topics

Resources

Stars

87 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - Nitwel/Rdot: JavaScript Signals for Godot! · GitHub
Skip to content

Repository files navigation

Rdot (JavaScript Signals for Godot! 🥳)

logo

What is Rdot?

Rdot is inspired by most modern Web Frameworks that use a reactive programming model. It enables you to write GDScript with syntax similar to Vue / Solid / Qwik and many other Frameworks... but in Godot!

example

The most common use case for Rdot is to synchronize the state of your game with the UI, although it can be used for other things as well.

⚠️ Disclaimer ⚠️

This should be seen as a proof of concept and not ready for production. While most logic was ported over, there still needs to be more testing to be done.

Logic was sourced from proposal-signals and translated to GDScript. Big shoutout to everyone who contributed to the proposal or worked on the demo in said proposal. ❤️

Usage

varcounter=R.state(0)
vardisplayText=R.computed(func(_ignore):
return"Counter: "+str(counter.value)
)
$AddButton.button_down.connect(func(): counter.value+=1)
$SubtractButton.button_down.connect(func(): counter.value-=1)
R.effect(func(_ignore):
$CounterLabel.text=displayText.value
)

See Explanation for a walkthrough of the code. More examples can be found in the demo folder.

Stores

Stores offer the ability to quickly create many reactive states at once. They are useful for managing the state of your game.

varstore=R.store({ # or R.state({ ... })"counter": 0,
"name": "John Doe"
})
R.effect(func(_ignore):
$CounterLabel.text="Counter: "+str(store.counter)
)

The benefit of this is that you can avoid having to access the value via the value property. Stores support also nested objects, allowing you to create more complex states.

R.state automatically creates a store when an object is passed as an argument.

Binding

Binding is a way to synchronize the state of a reactive value with the UI. It can be used to create 1-way or 2-way bindings.

varnumber=R.state(0)
varmessage=R.state("Hello World")
# 1-way bindingR.bind($Label, "text", message)
# 2-way bindingR.bind($Slider, "value", number, $Slider.value_changed)

There is an edge-case for bindings using Stores. When binding to a store, you have to pass the store as well as the key you want to bind to.

varstore=R.store({
"counter": 0,
"name": "John Doe"
})
R.bind($Label, "text", store, "name")
R.bind($Slider, "value", store, "counter", $Slider.value_changed)

Explanation

R. (R-dot) is the namespace for all Rdot functions.

R.state is a function that creates a reactive state. It returns an object with a value property that you can read and write to. The methods do_get and do_set(value) are also available but behave the same as value.

varcounter=R.state(0)

R.computed recalculated it's value each time a reactive value in the function changes. It returns an object with a value property that you can read. The first argument can be ignored but has to be there for Godot to not complain.

vardouble=R.computed(func(_ignore):
returncounter.value*2
)

R.effect can be used to synchronize the reactive state with the UI. It its rerun each time a reactive value in the function changes.

R.effect(func(_ignore):
print("Double changed: ", double.value)
)

API

## Creates a reactive stateR.state(initialValue: Variant) ->R.RdotState|RdotStore## Creates a computed state based on the returned value of the functionR.computed(func: Callable) ->R.RdotComputed## Runs the function each time a reactive value in the function changes## Returns a function to stop the effectR.effect(func: Callable) ->Callable## Creates a Store based off of a DictionaryR.store(initialValue: Dictionary) ->RdotStore## Updates the target property when the value changes## When a watch_signal is provided, the value will be updated when the signal is emitted (2 way binding)## Returns a function to stop the bindingR.bind(target: Object, property: String, value: R.RdotState|R.RdotComputed, watch_signal: Signal=null) ->Callable## For binding to a storeR.bind(target: Object, property: String, store: RdotStore, key: String, watch_signal: Signal=null) ->Callable

About

JavaScript Signals for Godot!

Topics

Resources

Stars

87 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - Nitwel/Rdot: JavaScript Signals for Godot! · GitHub
Skip to content

Repository files navigation

Rdot (JavaScript Signals for Godot! 🥳)

logo

What is Rdot?

Rdot is inspired by most modern Web Frameworks that use a reactive programming model. It enables you to write GDScript with syntax similar to Vue / Solid / Qwik and many other Frameworks... but in Godot!

example

The most common use case for Rdot is to synchronize the state of your game with the UI, although it can be used for other things as well.

⚠️ Disclaimer ⚠️

This should be seen as a proof of concept and not ready for production. While most logic was ported over, there still needs to be more testing to be done.

Logic was sourced from proposal-signals and translated to GDScript. Big shoutout to everyone who contributed to the proposal or worked on the demo in said proposal. ❤️

Usage

varcounter=R.state(0)
vardisplayText=R.computed(func(_ignore):
return"Counter: "+str(counter.value)
)
$AddButton.button_down.connect(func(): counter.value+=1)
$SubtractButton.button_down.connect(func(): counter.value-=1)
R.effect(func(_ignore):
$CounterLabel.text=displayText.value
)

See Explanation for a walkthrough of the code. More examples can be found in the demo folder.

Stores

Stores offer the ability to quickly create many reactive states at once. They are useful for managing the state of your game.

varstore=R.store({ # or R.state({ ... })"counter": 0,
"name": "John Doe"
})
R.effect(func(_ignore):
$CounterLabel.text="Counter: "+str(store.counter)
)

The benefit of this is that you can avoid having to access the value via the value property. Stores support also nested objects, allowing you to create more complex states.

R.state automatically creates a store when an object is passed as an argument.

Binding

Binding is a way to synchronize the state of a reactive value with the UI. It can be used to create 1-way or 2-way bindings.

varnumber=R.state(0)
varmessage=R.state("Hello World")
# 1-way bindingR.bind($Label, "text", message)
# 2-way bindingR.bind($Slider, "value", number, $Slider.value_changed)

There is an edge-case for bindings using Stores. When binding to a store, you have to pass the store as well as the key you want to bind to.

varstore=R.store({
"counter": 0,
"name": "John Doe"
})
R.bind($Label, "text", store, "name")
R.bind($Slider, "value", store, "counter", $Slider.value_changed)

Explanation

R. (R-dot) is the namespace for all Rdot functions.

R.state is a function that creates a reactive state. It returns an object with a value property that you can read and write to. The methods do_get and do_set(value) are also available but behave the same as value.

varcounter=R.state(0)

R.computed recalculated it's value each time a reactive value in the function changes. It returns an object with a value property that you can read. The first argument can be ignored but has to be there for Godot to not complain.

vardouble=R.computed(func(_ignore):
returncounter.value*2
)

R.effect can be used to synchronize the reactive state with the UI. It its rerun each time a reactive value in the function changes.

R.effect(func(_ignore):
print("Double changed: ", double.value)
)

API

## Creates a reactive stateR.state(initialValue: Variant) ->R.RdotState|RdotStore## Creates a computed state based on the returned value of the functionR.computed(func: Callable) ->R.RdotComputed## Runs the function each time a reactive value in the function changes## Returns a function to stop the effectR.effect(func: Callable) ->Callable## Creates a Store based off of a DictionaryR.store(initialValue: Dictionary) ->RdotStore## Updates the target property when the value changes## When a watch_signal is provided, the value will be updated when the signal is emitted (2 way binding)## Returns a function to stop the bindingR.bind(target: Object, property: String, value: R.RdotState|R.RdotComputed, watch_signal: Signal=null) ->Callable## For binding to a storeR.bind(target: Object, property: String, store: RdotStore, key: String, watch_signal: Signal=null) ->Callable

About

JavaScript Signals for Godot!

Topics

Resources

Stars

87 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages