aduros / wasm4 Goto Github PK
View Code? Open in Web Editor NEWBuild retro games using WebAssembly for a fantasy console.
Home Page: https://wasm4.org
License: ISC License
Build retro games using WebAssembly for a fantasy console.
Home Page: https://wasm4.org
License: ISC License
For audio sequence should be provided a timecode.
We can use a tick of update, but how i know it depend of RAF frequency, and we can't sync a APU with update for sequencing.
I know that WASM export a seed
function that really is Date.now, and this already can be used, but is hacky.
maybe we can provide a time
function same way?
UPD, i see that now we use a clamped update, and it should runs about 60 frames on any screens, exclude a iOS in power-save mode (it ticks 30 FPS)
https://github.com/aduros/wasm4/blob/main/runtimes/web/src/index.js#L343
It definitely require install wasm32-unknown-unknown
toolchain before trying to compile any of rust code. It either require installation of wasm-pack
or installing it manually via rustup
. Does it installs wasm-pack when we install w4?
Hi,
I'm having trouble allocating a String
, am I missing something?
// lib.rs
#[no_mangle]
fn update() {
let mut my_string = String::new();
my_string.push('#');
text(&my_string.clone(), 20, 20);
}
Uncaught (in promise) RuntimeError: unreachable
at update (<anonymous>:wasm-function[11]:0x20fb)
at p.update (wasm4.js:1)
at t (wasm4.js:1)
at wasm4.js:1
```
Example:
(Note: dist
currently does not exists)
$ w4 bundle build/cart.wasm --html dist/index.html
OK! Bundled dist/index.html.
It's better to check if dist
exists (and create if it does not) than just attempting to write the file to the HTML file.
The program crashes after a while when different objects are being rendered.
To reproduce this, follow the Setup for a HelloWorld AS application and make this little change in main.ts:
// ... as in the template
let counter: i32 = 0;
export function update (): void {
store<u16>(w4.DRAW_COLORS, 2);
w4.text("Counter: " + (counter++).toString(), 10, 10);
// ... as in the template
Same behavior in Chrome and Firefox.
I spotted this when developing a game but the code above is a minimal example.
FaberVitale was kind enough to explain how to do this at the browser level in #24 (comment), but I was thinking that a simple FPS counter on a hotkey would be nice.
Starting playing off the go hello world, noticed my KEYS and Framebuffer were getting overwritten with variables in memory. Looks like this link from the rust linker options
"--global-base=6560"
in target.json in the go hello world cleared things up
Problem:
Hard to play when Arrows Up / Left/Right is used in same time because any wrong finger movements produce false input.
I think that corner input should be registered only when a finger in those zone:
What is problem, looks video (focus on joy):
https://youtu.be/dk0RV5x2Bz4?t=16
You can figure out, that when a left/right is pressed , sometimes UP/DOWN is detected too, that produce a wrong movement.
For Snake game this extremely increasing a difficulty.
I think it's better to split the CLI, runtime, website and example into different repositories. It'll be easier to manage it.
The Rust stub in the default uses the following declaration for tone
:
pub fn tone (frequency: u32, volume: u32, duration: u32, flags: u32) {
unsafe { extern_tone(frequency, volume, duration, flags) }
}
extern {
#[link_name = "tone"]
fn extern_tone (frequency: u32, volume: u32, duration: u32, flags: u32);
}
However, the APU in the javascript source code uses the following parameter order:
tone (frequency, duration, volume, flags)
The same seems to be the case for AssemblyScript, Go and C.
This doesn't cause any problems in practice, but causes editor hints to be wrong.
I think this issue related that iPAD have a layout as in MacOS but has touchscreen.
I know that a lot of sites not preventing a zoom in/out by double tap or pinch (mapped on wheel) and this produce bugs like this.
But why a virtual joypad is missaligned and stacking?
This reproduced in Safari and Chrome (because it use Safari).
Then a Safari not support 'pixelated' on WebGL context, i think we should use internal scale by bliting a framebuffer into canvas with 'nearest' filter mode, because anyway we should try to round pixel for avoiding canvas pixel stretching when a viewport little bit smaller or greater that 160.
Patch exist, but not working in Safari
https://bugs.webkit.org/show_bug.cgi?id=193895
Complement #85
Similar to w4 new
but instead initialize the project in the current directory. Shouldn't be hard to implement
Adding this to start()
will hook all panic messages (probably), unless it panics during a panic in which case it just crashes. If memory problems are present it will crash on alloc so we can't rely on .to_string()
.
#[no_mangle]
fn start() {
#[cfg(debug_assertions)]
panic::set_hook(Box::new(|info| {
if let Some(s) = info.payload().downcast_ref::<&str>() {
trace(s);
} else {
trace("A panic occurred somewhere...")
}
/* // I am unsure of what wizardry wasmbindgen uses but backtraces don't seem to work independently.
trace("Stack:\n");
let backtrace = Backtrace::force_capture();
match backtrace.status() {
std::backtrace::BacktraceStatus::Unsupported => trace("No backtrace support"),
std::backtrace::BacktraceStatus::Disabled => {
trace("Something disabled the backtracing")
}
std::backtrace::BacktraceStatus::Captured => {
for frame in backtrace.frames() {
trace(&format!("{:?}", frame));
}
}
_ => trace("The compiler demanded I add this. If you see this assume everything has gone wrong."),
};
*/
//trace(&info.to_string())
// .to_string() will just crash if allocations are not working
}));
}
An error(&str)
function could be added so that stack logs could be passed to the console as errors.
I begun implement new feature but see that we have a lot of bug in oval
import * as w4 from "./wasm4";
let time: f32 = 0.0;
export function update (): void {
time += 0.01;
store<u16>(w4.DRAW_COLORS, 2);
const sx = u32((1. + Mathf.sin(time)) * 50);
const sy = u32((1. + Mathf.sin(time)) * 50);
w4.text ("New Rect", 4, 4);
w4.rect (20, 20, 31, 31);
w4.text ("New Oval", 84, 4);
w4.oval (80 + 20, 20, 31, 31);
}
Follow: #13
Unhandled Promise Rejection: ReferenceError: Can't find variable: AudioContext
Tested on simulator with iphone 11Max and iOS14.0 .
It seems that before 14.1 AudioContext was behind a vendor prefix.
source: https://developer.mozilla.org/en-US/docs/Web/API/AudioContext#browser_compatibility
The FRAMEBUFFER
memory region can be directly written to for drawing, but that's not very well explained in the docs. Let's add a section to the graphics documentation showing how to write a single pixel for example.
Context loss happens on some devices when coming out of sleep/suspend.
The screen only appears on gray-and-white, and the mobile gamepad is also shown.
Snake on Pale Moon 29.4.0.2
Sound Demo on Pale Moon 29.1.1 and 29.4.0.2
I have also been doubting if I should even post this issue as Pale Moon isn't really a popular browser, so this will probably be marked as wontfix, but let's see...
Would this be useful for anyone? Lua seems to be the lingua franca of fantasy consoles, so it might help drive adoption?
Implementation-wise it would be a little different since it's interpreted. We could provide a prebuilt cart.wasm written in C containing the Lua runtime. The *.lua files would then be injected into this cart.wasm somehow to produce the final cart.
The nice thing about this approach is that Lua carts would require no compiler toolchain to setup.
When following the Getting started tutorial I spotted several problems:
npx
. See https://www.assemblyscript.org/quick-start.html for inspiration.Cannot GET /
for http://localhost:4444/src
- wasm4.ts is a library source, I would expect it to be referenced in package.json as a devDependencies, not in the src directory as it is not supposed to be edited by the user.Music can be implemented right now by games calling tone() at the right times. It involves writing a bunch of code to handle the time sequencing... but it's a lot of work.
Let's build a music sequencer and a music authoring format into the runtime. The goal is a new music()
method which takes something as a parameter to play music using the 4 channel audio system.
There are some approaches here for that something:
w4
command similar to png2src that generates the blob in source code.The music format should be usable for short sound effects too and not only background music. Maybe the function should be called something like track()
or sequence()
instead of music()
to reflect that.
Right now I'm leaning towards BeepBox, and a w4 beepbox2src
command that takes a beepbox.co URL or json export and spits out binary data in source code.
I see palette uses texture2D texture now. What about change it to texture1D? While wasm4 support only 4 palette slots (2-bit palette) I guess it could be even simpler approach and pass this four colours via 4 uniforms and use something like this:
// palette
uniform vec2 p0;
uniform vec2 p1;
uniform vec2 p2;
uniform vec2 p3;
uniform sampler2D framebuffer;
varying vec2 framebufferCoord;
vec4 lookup(float img, vec4 p0, vec4 p1, vec4 p2, vec4 p3) {
// not sure about implementation. Just basic idea
// instead "mix" it could be "step"
vec4 p;
p = mix(p0, p1, mix(0.0, 1.0 / 3.0, img));
p = mix(p, p2, mix(1.0 / 3.0, 2.0 / 3.0, img));
p = mix(p, p3, mix(2.0 / 3.0, 1.0, img));
return p;
}
void main() {
gl_FragColor = lookup(texture2D(framebuffer, framebufferCoord).r, p0, p1, p2, p3);
}
Docs show example which uses 0x42
store<u16>(w4.DRAW_COLORS, 0x42);
w4.rect(10, 10, 32, 32);
But template uses store<u16>(w4.DRAW_COLORS, 2)
for this.
Will be great explain what 0x42
mean and how it created. For example: 0x04 << 4 | 0x02
. Even better have some util function like:
function encodeColors(xx: u32, yy: u32, zz: u32, ww: u32): u16 {
return ((xx & 0x3) | (yy & 0x3) << 4 | (zz & 0x3) << 8 | (ww & 0x3) << 12) as u16;
}
When attempting to draw dynamic text to the screen in rust, the runtime aborts entirely.
// lib.rs
mod wasm4;
use wasm4::*;
#[no_mangle]
fn update() {
unsafe {
*DRAW_COLORS = 2;
}
text(format!("{:02x}", unsafe {CT}).as_str(), 10, 10);
unsafe { CT += CT.wrapping_add(1) }
}
Error in the console:
Uncaught (in promise) RuntimeError: unreachable executed
update http://localhost:4444/wasm4.js:1
t http://localhost:4444/wasm4.js:1
<anonymous> http://localhost:4444/wasm4.js:1
async* http://localhost:4444/wasm4.js:1
<anonymous> http://localhost:4444/wasm4.js:1
wasm4.js line 1 > WebAssembly.instantiate:15530:1
<anonymous> http://localhost:4444/wasm4.js:1
AsyncFunctionNext self-hosted:692
(Async: async)
<anonymous> http://localhost:4444/wasm4.js:1
<anonymous> http://localhost:4444/wasm4.js:1
oval()
supports outlines but not fill yet.
Provide wrapped native executables for users without node/npm installed. Probably using something like pkg.
When running w4 new --assemblyscript hello-world
the project name is always cart
.
I would expect hello-world
here.
As an enhancement, a wizard with more parameters would be useful (like npm init
)... :-)
Similar to PICO-8, use the least significant bits of an image to encode carts in an image for easier sharing.
Consider this AS code:
import * as w4 from "./wasm4";
store<u32>(w4.PALETTE, 0xe0f8cf, 0); // light
store<u32>(w4.PALETTE, 0xe30000, 1); // red
store<u32>(w4.PALETTE, 0x306850, 2); // green
store<u32>(w4.PALETTE, 0x000000, 3); // black
export function update (): void {
// nothing here
}
I would expect the background colored in light green, but some kind of violet appears:
Works fine when the other three colors are not set.
If you request more linear memory, then the emulator's this.memory
is not actually the one in use by the WASM instance anymore and the whole thing starts crashing and / or not displaying anything anymore.
Oh unless the idea is that allocating memory isn't even allowed. Though that doesn't seem to be enforced anywhere. For example Rust by default allocates 1MiB for the stack alone on startup, almost definitely true for C and C++ as well.
Looks like partially offscreen blits with flipping (and maybe also rotation?) are drawn incorrectly.
It would be great to have the ability to save scores in the global leaderboard, which would be available for all cartridges. Such a table could then be accessed either from the game itself or/and as a link on the cartridge web page. You could even add GitHub account registration as an option.
wdyt?
After my PR #53 we have a template support for png2src.
And site saids about this https://wasm4.org/docs/guides/sprites#custom-template
But current NPM version is still 1.0.3 that not have this feature.
@aduros can you up pathc version and sync NPM and github?
An issue has come up in [email protected] not present in 1.0.2. The types for non-array constants are not being rendered when running w4 png2src
. I believe this only affects the Rust variant since the other supported languages don't require this type signature on constant variables.
This is the output from [email protected]
const spritesheetWidth: u32 = 16;
const spritesheetHeight: u32 = 32;
const spritesheetFlags: u32 = 1; // BLIT_2BPP
const spritesheet: [u8; 128] = [
// ...
];
This is the output from [email protected]. I do appreciate the variable naming update to match Rust style. ❤️
const SPRITESHEET_WIDTH = 16;
const SPRITESHEET_HEIGHT = 32;
const SPRITESHEET_FLAGS = 1; // BLIT_2BPP
const SPRITESHEET: [u8; 128] = [
// ...
];
I think it probably makes sense to automatically install the dependencies on a new project after creating it. It would remove a manual step in the quickstart guide.
It does require that npm
be in the $PATH though, maybe that's a problem in some cases. Also there are folks that prefer yarn over npm?
@ttulka How would you feel about this?
For large carts that less that 64kb, bundle emit invalid HTML.
I have a cart size 16kb and 44kb of HTML, but browser was crash with Unexpected identifier
Cart:
https://github.com/eXponenta/wasm4-game/tree/main/build
Page:
https://exponenta.github.io/wasm4-game/build/my-super-game.html
This reproduced on 1.0.3 version and on 1.0.4 version of wasm4.
Lang is AsemblyScript.
The playable demos have a bad UX on non-EN keyboard layouts.
Please add a few alternative keys, e.g., for Watris:
And, I guess there are also other smart choices for the other demos, for good UX worldwide, and for one handed control.
With Bulk Memory Operations becoming universally supported as of iOS 15, I think these functions could be removed.
FPS now not synced at 60 FPS.
b6e8b44#commitcomment-56199734
For me it always a 30, because elapsed time prcission is 1ms
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
It would be handy to set FPS from the game code. This would save developers some boilerplate code.
export function update(): void {
// next update will be called in 0.5 sec
w4.setFPS(30);
// ...
What do you think?
hline - horizontal line only
vline - vertical line only
Will be good to intorudce a Gamepad support in game and menu.
This allow to use this platform like Steam Big Screen in AndroidTV, Tablet or Real Consoles with WebGL/Canvas support (like Xbox, PS5).
For runtime this will be easy, and because site have grid, looks like that Gamepad navigation can be implemented and on it.
I wanted to debug some stuff and print some integers to the console. I wrote some integer printing code.
func printInt(r int) {
var bytes [6]byte
bytesIndex := 5
byteLen := 0
const MAXX = 1000_000
for i := 10; i < MAXX; i *= 10 {
rem := r % i
bytes[bytesIndex] = digitToByte(rem * 10 / i)
r -= rem
bytesIndex--
byteLen++
if r < 1 || bytesIndex < 0 {
break
}
}
trace(string(bytes[:]), byteLen)
}
But after few prints the colors in game started changing. The problem were hidden memory allocations during string operations. The problem is strings in golang allocate on the heap on creation. It seems that this heap allocation doesn't care where it allocates memory and my color pallete got overwritten by string data! I think it would be better if the trace function in golang was like c++ version so it takes array of bytes so we avoid allocating memory with string type. Like this:
func trace (str []byte, byteLength int);
Creating template Rust project and modifying string literal in the first text
call to contain non-ASCII UTF-8 bytes makes the game output garbled text, as if it were interpreting the bytes it as CP1252 instead of UTF-8.
This contradicts with the name of function textUtf8
.
Inspecting the cartridge with wasm2wat
shows that the string inside is indeed UTF-8.
If drawing outside the screen 1 pixel to the right or 1 pixel below the SCREEN_SIZE, the border pixels within the screen boundary are overwritten. Doing so in the top or left of the screen does not exhibit the issue.
Example:
#include "wasm4.h"
void start()
{
PALETTE[0]=0x000000;
PALETTE[1]=0xFF0000;
PALETTE[2]=0x00FF00;
PALETTE[3]=0x0000FF;
}
void update()
{
*DRAW_COLORS=0x03;
rect(SCREEN_SIZE-16,SCREEN_SIZE-16,16,16);
*DRAW_COLORS=0x22;
rect(SCREEN_SIZE,SCREEN_SIZE-16,16,16);
rect(SCREEN_SIZE-16,SCREEN_SIZE,16,16);
*DRAW_COLORS=0x03;
rect(0,0,16,16);
*DRAW_COLORS=0x22;
rect(-16,0,16,16);
rect(0,-16,16,16);
}
Hi, Thanks for WASM-4! ❤️
In fact WebAssembly have been supported by wide list of languages which can be found here: https://github.com/appcypher/awesome-wasm-langs
The only problem here that if dev would like to add support or definitions for a language from the list, By myself looked into docs but this isn't mentioned...
Is there a guide or someway to add more languages?
With a brief look at the source code, I see that the implementation (rendering, ...) is provided by the platform. This means, it is relatively easy to add support for a new language, but it is difficult to add a new platform (the whole runtime must be re-implemented).
Is the goal of the project to be extendable for language creators, or to write Wasm games that run easily on any new/exotic platform? The current implementation tends to the former.
I wonder if this was really the motivation as I would expect the opposite: Support of just a few popular languages (AS, Rust, C/C++) with ease of integration to my platform. This could be achieved by implementing the rendering in the Wasm module and provide just the update
function, output bytes (the rendered scene) and user input interface. The platform would then need just to copy the bytes to whatever screen it has and call update.
What are your thoughts? :-)
It would be neat to have an easily accessible editor for live coding. Something like the TypeScript Playground with the code on the left and the game on the right, with the ability to inspect the WAT and download the cart.wasm
.
AssemblyScript seems like it would be a perfect fit for this! @MaxGraey 👀 Maybe the existing AS editor could be repurposed?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.