Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
3c6a149
fix: present the canvas opaque so a browser does not composite the pa…
Ughuuu Sep 4, 2026
a556d84
add screen buffer. Add ime events. Add safe area support
Ughuuu Sep 5, 2026
25602cd
remove/simplify comments
Ughuuu Sep 5, 2026
2b0a969
web: a supplied canvas keeps its page's scrolling; ⌘ chords and keyup…
Ughuuu Sep 5, 2026
db8ad10
Update events.rs
Ughuuu Sep 5, 2026
890aaab
update egui renderer
Ughuuu Sep 5, 2026
f4f389b
egui: a frame that draws no UI shows the last pass again
Ughuuu Sep 5, 2026
2fac4f3
mesh3d: carry per-vertex colors
Ughuuu Sep 6, 2026
f714dc8
Update wgpu_canvas.rs
Ughuuu Sep 6, 2026
b64bd0a
Add launch url support
Ughuuu Sep 7, 2026
bbee2f5
postprocessing
Ughuuu Sep 7, 2026
02fa7bd
rustfmt tidies the launch-url imports and binding
Ughuuu Sep 7, 2026
fb942b8
Set the pointer to the shape egui asked for
Ughuuu Sep 10, 2026
1af51c7
Let a caller state a texture's whole sampler
Ughuuu Sep 10, 2026
1f7d425
get keyboard height for android and ios.
Ughuuu Sep 11, 2026
e90b8d8
Update texture_manager.rs
Ughuuu Sep 11, 2026
dce5aec
add support for exclusive full screen and maximized mode.
Ughuuu Sep 11, 2026
cc0bd8c
Re-export wgpu so an implementor cannot drift to another version
Ughuuu Sep 12, 2026
775b688
fix egui hotkeys
Ughuuu Sep 13, 2026
b80fa33
fix(build): clippy chunk lint and the serde feature over wgpu's types
sebcrozet Sep 10, 2026
179489c
fix(egui): make retained UI shapes opt-in rather than the default
sebcrozet Sep 10, 2026
d85164a
feat(post-processing): build effect pipelines per output format so bo…
sebcrozet Sep 10, 2026
423c961
refactor(scene2d): one traversal behind both 2D render paths
sebcrozet Sep 10, 2026
13ef752
fix(input): keep a cmd-held key pressed on web and take IME cursors o…
sebcrozet Sep 10, 2026
284ea24
feat(mesh3d): render per-vertex colors through the default material a…
sebcrozet Sep 10, 2026
3e0e94f
docs(examples): a 2D material that refracts the screen copy it reads
sebcrozet Sep 10, 2026
9aac618
docs(examples): a film-stage post-processing effect, and OffscreenSur…
sebcrozet Sep 10, 2026
62f77df
docs(changelog): record everything on this branch
sebcrozet Sep 10, 2026
253d556
fix(mobile,window): one UIKit view lookup, a pinned Android keyboard …
sebcrozet Sep 13, 2026
1f0cc01
ci: run the tests that only exist with the egui feature
sebcrozet Sep 13, 2026
30d3deb
docs(changelog): the keyboard height, fullscreen and egui hotkey changes
sebcrozet Sep 13, 2026
061d95f
fix(egui): follow egui's own rule for the command modifier
sebcrozet Sep 13, 2026
945d745
change rendering to use instead pixel per point.
Ughuuu Sep 13, 2026
cab7b43
make zoom configurable
Ughuuu Sep 13, 2026
4a45b95
text scale
Ughuuu Sep 13, 2026
16bf4bb
ios: fix text_scale for objc2-ui-kit 0.3 and rustfmt import order
Ughuuu Sep 13, 2026
5fb037a
fixes to ssao
Ughuuu Sep 15, 2026
bb3591f
Move to wesl 0.5: VirtualResolver lives in wesl::resolver, Compiler r…
Ughuuu Sep 19, 2026
c1ee9da
make bloom and other stuff optional
Ughuuu Sep 20, 2026
9ab3d5f
add prepare to pre-enable hdr if needed and post processing
Ughuuu Sep 20, 2026
ec7acb7
Update hdr.rs
Ughuuu Sep 20, 2026
8d2df95
fix clippy: the bloom layout is already a reference, and the lazy pip…
Ughuuu Sep 20, 2026
c2446d5
a surface-less render takes a software adapter where there is no driver
Ughuuu Sep 20, 2026
0acb496
add sprite batching
Ughuuu Sep 21, 2026
d5a1104
The whole-image rectangle is public beside the instance that takes it
Ughuuu Sep 21, 2026
4f0eb8f
The instance example and the re-export catch up with the UV rectangle
Ughuuu Sep 21, 2026
ca5cecf
Every key with a W3C code reaches the app, and Back and Forward are t…
Ughuuu Sep 26, 2026
035cac6
A window can sleep until an event, and another thread can wake it
Ughuuu Sep 26, 2026
3fcc9a8
A window says when it gains or loses focus and when it goes out of sight
Ughuuu Sep 26, 2026
5498f39
An app sent back, brought back or short of memory says so
Ughuuu Sep 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,18 @@ jobs:
run: cargo build --verbose -p kiss3d;
- name: Build kiss3d (+ egui)
run: cargo build --verbose -p kiss3d --features egui;
# `serde` derives over types the graphics crates own, so it only builds
# while their own serde features are pulled in with it.
- name: Build kiss3d (+ serde)
run: cargo build --verbose -p kiss3d --features serde;
- name: Build examples (+ egui)
run: cargo build --verbose --examples --features egui;
- name: Run tests
run: cargo test
# The egui integration (key translation, the command modifier) is behind
# the feature, so its tests only exist in a build that enables it.
- name: Run tests (+ egui)
run: cargo test --features egui
build-wasm:
runs-on: ubuntu-latest
env:
Expand Down
19 changes: 19 additions & 0 deletions .run/film_chain (web).run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="film_chain (web)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="command" value="run --package kiss3d --example film_chain --features rt_switcher --target wasm32-unknown-unknown" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<option name="emulateTerminal" value="true" />
<option name="channel" value="DEFAULT" />
<option name="requiredFeatures" value="true" />
<option name="allFeatures" value="false" />
<option name="withSudo" value="false" />
<option name="buildTarget" value="REMOTE" />
<option name="backtrace" value="SHORT" />
<envs />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>
19 changes: 19 additions & 0 deletions .run/film_chain.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="film_chain" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="command" value="run --package kiss3d --example film_chain --features rt_switcher" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<option name="emulateTerminal" value="true" />
<option name="channel" value="DEFAULT" />
<option name="requiredFeatures" value="true" />
<option name="allFeatures" value="false" />
<option name="withSudo" value="false" />
<option name="buildTarget" value="REMOTE" />
<option name="backtrace" value="SHORT" />
<envs />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>
19 changes: 19 additions & 0 deletions .run/screen_read2d (web).run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="screen_read2d (web)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="command" value="run --package kiss3d --example screen_read2d --features rt_switcher --target wasm32-unknown-unknown" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<option name="emulateTerminal" value="true" />
<option name="channel" value="DEFAULT" />
<option name="requiredFeatures" value="true" />
<option name="allFeatures" value="false" />
<option name="withSudo" value="false" />
<option name="buildTarget" value="REMOTE" />
<option name="backtrace" value="SHORT" />
<envs />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>
20 changes: 20 additions & 0 deletions .run/screen_read2d.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="screen_read2d" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="buildProfileId" value="dev" />
<option name="command" value="run --package kiss3d --example screen_read2d --features rt_switcher" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<envs />
<option name="emulateTerminal" value="true" />
<option name="channel" value="DEFAULT" />
<option name="requiredFeatures" value="true" />
<option name="allFeatures" value="false" />
<option name="withSudo" value="false" />
<option name="buildTarget" value="REMOTE" />
<option name="backtrace" value="SHORT" />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>
19 changes: 19 additions & 0 deletions .run/vertex_colors (web).run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="vertex_colors (web)" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="command" value="run --package kiss3d --example vertex_colors --features rt_switcher --target wasm32-unknown-unknown" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<option name="emulateTerminal" value="true" />
<option name="channel" value="DEFAULT" />
<option name="requiredFeatures" value="true" />
<option name="allFeatures" value="false" />
<option name="withSudo" value="false" />
<option name="buildTarget" value="REMOTE" />
<option name="backtrace" value="SHORT" />
<envs />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>
19 changes: 19 additions & 0 deletions .run/vertex_colors.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="vertex_colors" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="command" value="run --package kiss3d --example vertex_colors --features rt_switcher" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<option name="emulateTerminal" value="true" />
<option name="channel" value="DEFAULT" />
<option name="requiredFeatures" value="true" />
<option name="allFeatures" value="false" />
<option name="withSudo" value="false" />
<option name="buildTarget" value="REMOTE" />
<option name="backtrace" value="SHORT" />
<envs />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>
77 changes: 77 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,80 @@
# Unreleased

## Breaking Changes

- `Window::draw_ui` (and `OffscreenSurface::draw_ui`) takes an `FnMut` rather than an `FnOnce`, and
may run it more than once per frame: egui discards and re-runs a pass that only measured
something, so a closure that mutates state has to tolerate being replayed.
- `PostProcessingContext` gained an `output_format` field, and the built-in effects now build their
pipelines per format. A custom effect that constructs the context itself, or that built one
pipeline against the surface format, has to follow; `FormatPipelines` does the caching.
- `RenderContext2d` gained `screen` and `screen_generation` fields, and `OffscreenBuffers` a
`format` field.
- The `serde` feature now also enables `wgpu/serde`, which `TextureSampling` needs to derive over
wgpu's own types.

## New Features

- `Window::render_chains` (and `OffscreenSurface::render_chains`) runs a second post-processing
chain on the HDR film, before bloom and the tonemap, so an effect works in linear light and what
it writes is what blooms. `PostProcessingContext::output_format` says which format an effect
draws into, and `FormatPipelines` keeps one pipeline per format, so the same effect can be handed
to either chain. Added the `film_chain` example.
- `Material2d::reads_screen`: a 2D material can sample the frame drawn so far. The 2D pass is split
around each object that asks, with the film copied into `RenderContext2d::screen` first;
`screen_generation` changes when that copy is a new texture, so a bind group over it is rebuilt.
Added the `screen_read2d` example.
- Per-vertex colours: `GpuMesh3d::set_colors` / `colors` / `has_colors`, which the default material
multiplies into its base colour and the glTF loader fills in from `COLOR_0`. A mesh that carries
none is unaffected and allocates no buffer. Added the `vertex_colors` example.
- `TextureSampling`, with `TextureManager::add_image_sampled` and `Texture::sampled`, states a
texture's whole sampler at once: wrapping per axis, the magnification, minification and mip
filters, anisotropy, the colour space and premultiplied alpha. `TextureSampling::sane` drops what
the device would refuse rather than aborting the process, and `Texture::premultiplied` says which
blend mode the result wants.
- Input-method text: `ImeEvent`, `Window::ime_events` and `Window::set_ime_allowed`. egui's text
fields consume the same events on their own.
- `Window::safe_area` reports the display's insets in pixels, non-zero on iOS.
- `kiss3d::window::take_launch_url` (iOS) returns the URL the app was opened from, once.
- `Window::set_ui_retained` / `ui_retained` / `clear_ui` redraw the last egui pass on the frames
that build none, so a host can run its widgets only when something changed. Off by default: an
app that draws its UI conditionally expects a frame that draws none to show none.
- egui's pointer shape is applied to the window, and a pass egui asks to discard (a new `Area`, a
`Grid`, a `Resize`) is re-run before the frame is shown rather than showing the gap.
- `Canvas::set_cursor_icon` and `HdrPipeline::scene_texture`.
- `Window::keyboard_height` reports how many pixels of the window the on-screen keyboard covers,
from the bottom. Non-zero on Android and iOS, so a mobile app can lift what the keyboard would
bury.
- `Window::set_exclusive_fullscreen` takes the current monitor's largest video mode at its highest
refresh rate, and `set_maximized` / `is_maximized` join the existing `set_fullscreen` /
`is_fullscreen`.
- `kiss3d::wgpu` re-exports the wgpu the crate itself was built against. The material traits are
written in wgpu types, so an implementor naming them through this cannot drift to another
version.
- egui now hears punctuation, digits, the numpad, the function keys and the clipboard keys, not
only the letters and the navigation keys, so an app can bind a chord to any of them.

## Bug Fixes

- On the web, the surface is presented opaque wherever the platform offers it: a WebGPU canvas
lists premultiplied alpha first, and the page showed through every pixel left at alpha 0.
- A canvas the page supplies keeps the layout and the scrolling the page gave it; only a canvas
kiss3d had to create still sizes the document around itself.
- egui reads an event's own modifiers rather than the polled key states, so a chord tapped and
released inside one frame is no longer seen unmodified. ⌘ is the command modifier on an Apple
platform reached through a browser too, not only on native macOS.
- On the web on macOS, a key pressed while ⌘ is held is released when ⌘ is, rather than staying
pressed for good: macOS sends no keyup of its own for it.
- A render target reused at another colour format is remade rather than only resized.
- Auto-exposure meters what the film-stage chain wrote, not the film it started from.

## Performance

- The screenshot read-back texture is built on the first capture instead of with every window, and
a resize drops it rather than rebuilding one nothing has asked for.
- The film-stage render targets are allocated on the first frame a film chain is passed, so a run
that never passes one costs nothing.

# v0.46.0

## Breaking Changes
Expand Down
10 changes: 6 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ path = "src/lib.rs"
# falls back to a path text field).
egui = ["dep:egui", "dep:egui-wgpu", "dep:rfd"]
recording = ["dep:ffmpeg-the-third"]
serde = ["dep:serde", "glamx/serde", "bitflags/serde", "rgb/serde"]
serde = ["dep:serde", "glamx/serde", "bitflags/serde", "rgb/serde", "wgpu/serde"]
# If enabled, switching between the ray-tracer and the rasterizer is possible while kipping
# only the `.render_3d` call (instead of having to manually switch between `.render_3d` and
# `.raytrace_3d`. This is mainly for debugging and experiments comparing the rasterizer and
Expand All @@ -59,7 +59,7 @@ rusttype = { version = "0.9", features = ["gpu_cache"] }
serde = { version = "1", features = ["derive"], optional = true }
wgpu = "30"
winit = "0.30"
wesl = "0.4"
wesl = "0.5"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
pollster = "1"
Expand All @@ -83,8 +83,9 @@ android-activity = "0.6.1"
# summons UIKit's keyboard itself through a hidden UIKeyInput view (window/ios.rs).
[target.'cfg(target_os = "ios")'.dependencies]
objc2 = "0.6"
objc2-foundation = "0.3"
objc2-ui-kit = { version = "0.3", features = ["UIResponder", "UIView", "UITextInput"] }
objc2-core-foundation = { version = "0.3", features = ["CFCGTypes"] }
objc2-foundation = { version = "0.3", features = ["NSValue"] }
objc2-ui-kit = { version = "0.3", features = ["UIApplication", "UIGeometry", "UIResponder", "UIView", "UITextInput", "UIWindow", "objc2-core-foundation"] }

[target.wasm32-unknown-unknown.dependencies]
oneshot = { version = "0.2.0", features = ["async"] }
Expand All @@ -105,6 +106,7 @@ web-sys = { version = "0.3", features = [
"TouchList",
"HtmlCanvasElement",
"HtmlElement",
"Navigator",
"Window",
"UiEvent",
"Event",
Expand Down
Loading
Loading