[{"content":"","permalink":"http://localhost:1313/posts/invariant-mechanism-analysis/","summary":"","title":"Invariant Mechanism Analysis"},{"content":"Association vs. Causation Classical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: $$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$This objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$. From a probabilistic objective this is equivalent to optimizing: $$ \\arg \\max_\\theta p_\\theta (Y|X) $$However, not all association is causally grounded!\nExample do-Calculus Rule 1: Insertion/Deletion of Observations $P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\nRule 2: Action/Observation Exchange $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), z, w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\underline{Z}}$\nRule 3: Insertion/Deletion of Interventions $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\overline{Z(W)}}$\nCompeteness The do-calculus has been proven to be complete. This means that if it rules cannot translate the do-operator into pure probabilistic expressions, the causal effect is not identifiable.\nInstrumental Variables ","permalink":"http://localhost:1313/posts/causal-effect-estimation/","summary":"\u003ch2 id=\"association-vs-causation\"\u003eAssociation vs. Causation\u003c/h2\u003e\n\u003cp\u003eClassical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: \u003c/p\u003e\n$$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$\u003cp\u003eThis objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$.\nFrom a probabilistic objective this is equivalent to optimizing: \u003c/p\u003e\n$$ \\arg \\max_\\theta p_\\theta (Y|X) $$\u003cp\u003eHowever, not all association is causally grounded!\u003c/p\u003e\n\u003ch3 id=\"example\"\u003eExample\u003c/h3\u003e\n\u003ch2 id=\"do-calculus\"\u003edo-Calculus\u003c/h2\u003e\n\u003ch3 id=\"rule-1-insertiondeletion-of-observations\"\u003eRule 1: Insertion/Deletion of Observations\u003c/h3\u003e\n\u003cp\u003e$P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\u003c/p\u003e","title":"Causal Effect Estimation"},{"content":" Disclaimer: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\nLive Demo · GitHub Repository\nThe Software Stack With WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed with modern AI tooling:\nGraphics: wgpu (Targeting WebGPU via WebAssembly) Math: glam GUI / Debugging: egui Build Tooling: Trunk Blocks and Chunks At the core of any voxel engine lies a hierarchy: individual voxels aggregate into manageable spatial volumes called Chunks.\nA chunk is represented as a contiguous 3D array of Blocks. Storing millions of empty air voxels naively would quickly exhaust memory, especially within browser constraints. To mitigate this, chunks consisting solely of air are treated as uniform singletons and avoid individual heap allocations:\n#[derive(Copy, Clone, PartialEq, Eq)] pub enum BlockType { Air, Grass, Dirt, Stone, } pub struct Chunk { blocks: [BlockType; N_BLOCKS_PER_CHUNK], } View Distance \u0026amp; The Single-Thread Bottleneck In a traditional native engine, chunk generation and meshing are dispatched to background thread pools (e.g., via rayon). In a standard browser WASM environment, however, we are bound to the main UI and animation thread.\nIf a frame takes longer than 16.6 ms we fall under the holy 60 FPS mark. Because generating 3D Perlin/Simplex noise and extracting surface polygons (meshing) is computationally heavy, we cannot generate all chunks within the player\u0026rsquo;s view distance in a single frame.\nInstead, we need two things:\nPrioritization: Chunks closest to the player must generate first. Time-slicing (Amortization): Bound the number of chunks and meshes generated per frame cycle. 1. Precomputed Spherical Offsets Calculating Euclidean distances on every frame for dozens of surrounding chunk coordinates is wasteful. Since the relative geometric layout never changes, we can precompute the offset coordinates relative to $(0, 0, 0)$ once at startup and sort them spherically:\nfn generate_offsets_in_spherical_order(radius: isize) -\u0026gt; Vec\u0026lt;(ChunkCoord, usize)\u0026gt; { let mut offsets = Vec::new(); for x in 0..radius { for y in 0..radius { for z in 0..radius { let offset_x = x - radius / 2; let offset_y = y - radius / 2; let offset_z = z - radius / 2; // Euclidean distance relative to origin let dist = (offset_x.pow(2) + offset_y.pow(2) + offset_z.pow(2)).isqrt() as usize; offsets.push((ChunkCoord(offset_x, offset_y, offset_z), dist)); } } } // Sort ascending: closest chunks first offsets.sort_unstable_by_key(|(_, dist)| *dist); offsets } 2. The Frame Update Loop In each render tick, the engine slides its active chunk window based on the player\u0026rsquo;s movement, and then consumes a strictly defined compute budget of chunk and mesh builds:\n// Called once per frame pub fn update( \u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, max_chunk_budget: usize, max_mesh_budget: usize ) -\u0026gt; (usize, usize) { // 1. Shift the logical sliding window (O(1) index updates, practically free) self.slide_active_window(player_position); // 2. Process pending generation within budget let n_chunks = self.generate_pending_chunks(player_position, max_chunk_budget); let n_meshes = self.generate_pending_meshes(player_position, device, max_mesh_budget); (n_chunks, n_meshes) } Chunk Management: 3D Toroidal Buffering Rather than reallocating an entire 3D grid whenever the player crosses a chunk boundary, the engine uses a 3D Toroidal Ring Buffer (Sliding Window).\nBecause coordinates wrap around via modulo operations across all three axes, moving through the world requires zero data reallocations. When the player moves along an axis (say, $+X$), only the 2D plane on the opposite, trailing boundary ($-X$) is invalidated and marked for regeneration with the newly entered terrain.\n/// Update loaded chunks based on player movement. /// Only marks the \u0026#34;trailing\u0026#34; surface layer of chunks for clearance. fn slide_active_window(\u0026amp;mut self, new_player_coord: \u0026amp;ChunkCoord) { let deltas = [ new_player_coord.0 - self.previous_player_coord.0, new_player_coord.1 - self.previous_player_coord.1, new_player_coord.2 - self.previous_player_coord.2, ]; for (axis, \u0026amp;movement_delta) in deltas.iter().enumerate() { if movement_delta == 0 { continue; } let step = if movement_delta \u0026gt; 0 { 1 } else { -1 }; let mut working_base = self.previous_player_coord; // Process step-by-step to handle multi-chunk teleports/fast movement for _ in 0..movement_delta.abs() { let half = self.active_size[axis] as isize / 2; let plane_offset = -half * step; // Invalidate the 2D plane perpendicular to the movement direction for i in 0..self.active_size[(axis + 1) % 3] as isize { for j in 0..self.active_size[(axis + 2) % 3] as isize { let chunk_coord = match axis { 0 =\u0026gt; ChunkCoord(working_base.0 + plane_offset, working_base.1 + i - half, working_base.2 + j - half), 1 =\u0026gt; ChunkCoord(working_base.0 + j - half, working_base.1 + plane_offset, working_base.2 + i - half), _ =\u0026gt; ChunkCoord(working_base.0 + i - half, working_base.1 + j - half, working_base.2 + plane_offset), }; self.get_active_entry_mut(\u0026amp;chunk_coord).unset(); } } match axis { 0 =\u0026gt; working_base.0 += step, 1 =\u0026gt; working_base.1 += step, _ =\u0026gt; working_base.2 += step, } } } self.previous_player_coord = *new_player_coord; } Prioritized Chunk \u0026amp; Mesh Generation Generating a chunk is a two-step pipeline:\nVoxel Population: The 3D density noise generates raw voxel data. Mesh Extraction: Once a chunk and all its direct neighbors are populated, faces obscured by adjacent solid blocks are culled, and GPU vertex buffers are created and uploaded. Notice how whenever a non-empty chunk finishes loading, it flags its immediate neighbors (unset_mesh()): a border chunk cannot accurately cull its outer faces until adjacent blocks are known!\nfn generate_pending_chunks(\u0026amp;mut self, player_chunk_position: \u0026amp;ChunkCoord, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, distance) = self.offsets[i]; let chunk_coord = player_chunk_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).is_pending() { // Early out for chunks strictly above terrain generation limit if chunk_coord.1 \u0026lt;= -2 || chunk_coord.1 \u0026gt;= 14 { *self.get_active_entry_mut(\u0026amp;chunk_coord) = ActiveEntry::Empty { coord: chunk_coord }; continue; } let new_chunk = Chunk::new_populated(\u0026amp;self.density_generator, \u0026amp;chunk_coord); used_budget += 1; if new_chunk.is_empty() { self.get_active_entry_mut(\u0026amp;chunk_coord).set_empty(chunk_coord); } else { let required_lod = select_lod(distance); self.get_active_entry_mut(\u0026amp;chunk_coord).set_loaded(chunk_coord, new_chunk, required_lod); // Invalidate neighbor meshes to enforce seamless boundary culling for neighbor_coord in self.get_neighbor_chunk_coords(\u0026amp;chunk_coord) { self.get_active_entry_mut(\u0026amp;neighbor_coord).unset_mesh(); } } } } used_budget } fn generate_pending_meshes(\u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, _) = self.offsets[i]; let chunk_coord = player_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).needs_remesh() { let chunk_borders = self.get_chunk_borders(\u0026amp;chunk_coord); self.get_active_entry_mut(\u0026amp;chunk_coord).generate_and_upload_mesh(device, \u0026amp;chunk_borders); used_budget += 1; } } used_budget } What\u0026rsquo;s Next? While the engine runs at a solid 60 FPS under normal navigation, there are several exciting paths for future improvements:\nGreedy Meshing: Combining adjacent coplanar quad faces into single larger quads to drastically reduce vertex and index buffer sizes. Web Workers via SharedArrayBuffer: Offloading noise sampling to background Web Workers using Rust\u0026rsquo;s wasm-bindgen-rayon to make chunk generation truly asynchronous without stuttering the render thread. Persistent Browser Storage: Currently, all edits vanish on page refresh. The browser provides powerful mechanisms to persist modified worlds: OPFS (Origin Private File System): A modern, sandboxed filesystem API that allows fast, synchronous binary I/O from within Web Workers. It would enable Minecraft-style binary region files (.mca) running purely on the client. IndexedDB: An alternative key-value store to save compressed diffs of player-modified chunks without touching the pristine procedurally generated baseline. Floating Origin (Camera-Relative Rendering): While chunk coordinates can logically span a 32-bit integer space (billions of blocks), GPU rendering relies on 32-bit floating-point numbers (f32). At extreme coordinate distances, IEEE 754 floats lose precision, manifesting as severe vertex jitter, camera stutter, and depth-fighting artifacts (the classic \u0026ldquo;Far Lands\u0026rdquo; effect).\nAn architectural fix is a floating origin: instead of translating the camera through an ever-expanding global space, the camera is pinned statically at $(0, 0, 0)$. Chunks maintain their true logical world coordinates for generation and storage, but are indexed and pushed to the GPU transformed into local camera space. ","permalink":"http://localhost:1313/posts/voxel-engine/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eDisclaimer\u003c/strong\u003e: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ca href=\"https://eliaswendt.github.io/woxel\"\u003eLive Demo\u003c/a\u003e · \u003ca href=\"https://github.com/eliaswendt/woxel\"\u003eGitHub Repository\u003c/a\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-software-stack\"\u003eThe Software Stack\u003c/h2\u003e\n\u003cp\u003eWith WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed with modern AI tooling:\u003c/p\u003e","title":"Building a Browser Voxel Engine in Rust \u0026 WebGPU"},{"content":"Abstract High-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\nLinks ACL Anthology Download PDF GitHub Repo Huggingface Repo 🤗 BibTeX 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @inproceedings{aliJudgingQualityLanguages2025b, title = {Judging {{Quality Across Languages}}: {{A Multilingual Approach}} to {{Pretraining Data Filtering}} with {{Language Models}}}, shorttitle = {Judging {{Quality Across Languages}}}, booktitle = {Proceedings of the 2025 {{Conference}} on {{Empirical Methods}} in {{Natural Language Processing}}}, author = {Ali, Mehdi and Brack, Manuel and L{\\\u0026#34;u}bbering, Max and Wendt, Elias and Khan, Abbas Goher and Rutmann, Richard and Jude, Alex and Kraus, Maurice and Weber, Alexander Arno and Stollenwerk, Felix and Kacz{\\\u0026#39;e}r, David and Mai, Florian and Flek, Lucie and Sifa, Rafet and {Flores-Herr}, Nicolas and Koehler, Joachim and Schramowski, Patrick and Fromm, Michael and Kersting, Kristian}, year = 2025, pages = {8870--8909}, publisher = {Association for Computational Linguistics}, address = {Suzhou, China}, doi = {10.18653/v1/2025.emnlp-main.449}, urldate = {2026-06-27}, langid = {english}, file = {/Users/me/Zotero/storage/5IE6855P/Ali et al. - 2025 - Judging Quality Across Languages A Multilingual Approach to Pretraining Data Filtering with Languag.pdf} } ","permalink":"http://localhost:1313/posts/publication-jql/","summary":"\u003ch2 id=\"abstract\"\u003eAbstract\u003c/h2\u003e\n\u003cp\u003eHigh-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\u003c/p\u003e","title":"Judging Quality Across Languages: A Multilingual Approach to Pretraining Data Filtering with Language Models"},{"content":"The core idea of Bayesian inference is updating an initial belief in light of new evidence.\nStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the prior distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the posterior $p(X|E)$:\n$$ \\underbrace{p(X|E)}_{\\text{posterior}} = \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}} = \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}} = \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]} $$ Prior $p(X)$: What we believe about $X$ (e.g. how it is distributed) before looking at the data Likelihood $p(E|X)$: If the hypothesis $X$ were true, how likely would the observed evidence $E$ be? Posterior $p(X|E)$: What we should believe about $X$ now that we have observed $E$. Marginal Likelihood (Evidence) $p(E)$: The total probability of observing the evidence across all possible states of $X$. Notice: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning: $$ \\text{Posterior} \\propto \\text{Likelihood} \\cdot \\text{Prior} $$ New beliefs are a direct compromise between what you previously thought (Prior) and what the data suggests (Likelihood).\nIterative Learning Bayesian updating is naturally sequential. Assuming independent observations given $X$, the current posterior $p(X|E)$ becomes the starting prior:\n$$ p(X | E_1, E_2) \\propto p(E_2 | X) \\cdot p(X | E_1) $$As you collect more evidence, the likelihood term begins to dominate, and the initial prior gradually washes out.\nExample: The Base Rate Fallacy Why can\u0026rsquo;t we just rely on the likelihood $p(E|X)$? Consider a rare disease:\nPrior: $1$ in $1{,}000$ people has the disease $\\rightarrow p(\\text{Disease}) = 0.001$. Likelihood (Accuracy): A test is $99$% accurate for sick people $\\rightarrow p(\\text{Positive} | \\text{Disease}) = 0.99$. False Positive Rate: The test gives a false positive $5$% of the time for healthy people $\\rightarrow p(\\text{Positive} | \\text{Healthy}) = 0.05$. If a patient tests positive ($E = \\text{Positive}$):\n$$ p(\\text{Disease} | \\text{Positive}) = \\frac{0.99 \\cdot 0.001}{(0.99 \\cdot 0.001) + (0.05 \\cdot 0.999)} \\approx \\frac{0.00099}{0.00099 + 0.04995} \\approx 1.94\\% $$Even with a $99$% accurate test, the probability of being sick is under $2$%. The massive pool of healthy people generates far more false alarms than genuine detections. The prior acts as an anchor that keeps rare events from being drastically overestimated.\n","permalink":"http://localhost:1313/posts/bayes-theorem/","summary":"\u003cp\u003eThe core idea of Bayesian inference is updating an initial belief in light of new evidence.\u003c/p\u003e\n\u003cp\u003eStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the \u003cstrong\u003eprior\u003c/strong\u003e distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the \u003cstrong\u003eposterior\u003c/strong\u003e $p(X|E)$:\u003c/p\u003e\n$$\n\\underbrace{p(X|E)}_{\\text{posterior}}\n= \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}}\n= \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}}\n= \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]}\n$$\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePrior $p(X)$:\u003c/strong\u003e What we believe about $X$ (e.g. how it is distributed) before looking at the data\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLikelihood $p(E|X)$:\u003c/strong\u003e If the hypothesis $X$ were true, how likely would the observed evidence $E$ be?\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePosterior $p(X|E)$:\u003c/strong\u003e What we should believe about $X$ now that we have observed $E$.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMarginal Likelihood (Evidence) $p(E)$:\u003c/strong\u003e The total probability of observing the evidence across \u003cem\u003eall\u003c/em\u003e possible states of $X$.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eNotice\u003c/strong\u003e: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning:\n\u003c/p\u003e","title":"Bayes' Theorem"},{"content":"","permalink":"http://localhost:1313/posts/invariant-mechanism-analysis/","summary":"","title":"Invariant Mechanism Analysis"},{"content":"Association vs. Causation Classical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: $$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$This objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$. From a probabilistic objective this is equivalent to optimizing: $$ \\arg \\max_\\theta p_\\theta (Y|X) $$However, not all association is causally grounded!\nExample do-Calculus Rule 1: Insertion/Deletion of Observations $P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\nRule 2: Action/Observation Exchange $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), z, w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\underline{Z}}$\nRule 3: Insertion/Deletion of Interventions $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\overline{Z(W)}}$\nCompeteness The do-calculus has been proven to be complete. This means that if it rules cannot translate the do-operator into pure probabilistic expressions, the causal effect is not identifiable.\nInstrumental Variables ","permalink":"http://localhost:1313/posts/causal-effect-estimation/","summary":"\u003ch2 id=\"association-vs-causation\"\u003eAssociation vs. Causation\u003c/h2\u003e\n\u003cp\u003eClassical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: \u003c/p\u003e\n$$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$\u003cp\u003eThis objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$.\nFrom a probabilistic objective this is equivalent to optimizing: \u003c/p\u003e\n$$ \\arg \\max_\\theta p_\\theta (Y|X) $$\u003cp\u003eHowever, not all association is causally grounded!\u003c/p\u003e\n\u003ch3 id=\"example\"\u003eExample\u003c/h3\u003e\n\u003ch2 id=\"do-calculus\"\u003edo-Calculus\u003c/h2\u003e\n\u003ch3 id=\"rule-1-insertiondeletion-of-observations\"\u003eRule 1: Insertion/Deletion of Observations\u003c/h3\u003e\n\u003cp\u003e$P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\u003c/p\u003e","title":"Causal Effect Estimation"},{"content":" Disclaimer: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\nLive Demo · GitHub Repository\nThe Software Stack With WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed with modern AI tooling:\nGraphics: wgpu (Targeting WebGPU via WebAssembly) Linear Algebra: glam GUI / Debugging: egui Build Tooling: Trunk Blocks and Chunks At the core of any voxel engine lies a hierarchy: individual voxels aggregate into manageable spatial volumes called Chunks.\nA chunk is represented as a contiguous 3D array of Blocks. Storing millions of empty air voxels naively would quickly exhaust memory, especially within browser constraints. To mitigate this, chunks consisting solely of air are treated as uniform singletons and avoid individual heap allocations:\n#[derive(Copy, Clone, PartialEq, Eq)] pub enum BlockType { Air, Grass, Dirt, Stone, } pub struct Chunk { blocks: [BlockType; N_BLOCKS_PER_CHUNK], } View Distance \u0026amp; The Single-Thread Bottleneck In a traditional native engine, chunk generation and meshing are dispatched to background thread pools (e.g., via rayon). In a standard browser WASM environment, however, we are bound to the main UI and animation thread.\nIf a frame takes longer than 16.6 ms we fall under the holy 60 FPS mark. Because generating 3D Perlin/Simplex noise and extracting surface polygons (meshing) is computationally heavy, we cannot generate all chunks within the player\u0026rsquo;s view distance in a single frame.\nInstead, we need two things:\nPrioritization: Chunks closest to the player must generate first. Time-slicing (Amortization): Bound the number of chunks and meshes generated per frame cycle. 1. Precomputed Spherical Offsets Calculating Euclidean distances on every frame for dozens of surrounding chunk coordinates is wasteful. Since the relative geometric layout never changes, we can precompute the offset coordinates relative to $(0, 0, 0)$ once at startup and sort them spherically:\nfn generate_offsets_in_spherical_order(radius: isize) -\u0026gt; Vec\u0026lt;(ChunkCoord, usize)\u0026gt; { let mut offsets = Vec::new(); for x in 0..radius { for y in 0..radius { for z in 0..radius { let offset_x = x - radius / 2; let offset_y = y - radius / 2; let offset_z = z - radius / 2; // Euclidean distance relative to origin let dist = (offset_x.pow(2) + offset_y.pow(2) + offset_z.pow(2)).isqrt() as usize; offsets.push((ChunkCoord(offset_x, offset_y, offset_z), dist)); } } } // Sort ascending: closest chunks first offsets.sort_unstable_by_key(|(_, dist)| *dist); offsets } 2. The Frame Update Loop In each render tick, the engine slides its active chunk window based on the player\u0026rsquo;s movement, and then consumes a strictly defined compute budget of chunk and mesh builds:\n// Called once per frame pub fn update( \u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, max_chunk_budget: usize, max_mesh_budget: usize ) -\u0026gt; (usize, usize) { // 1. Shift the logical sliding window (O(1) index updates, practically free) self.slide_active_window(player_position); // 2. Process pending generation within budget let n_chunks = self.generate_pending_chunks(player_position, max_chunk_budget); let n_meshes = self.generate_pending_meshes(player_position, device, max_mesh_budget); (n_chunks, n_meshes) } Chunk Management: 3D Toroidal Buffering Rather than reallocating an entire 3D grid whenever the player crosses a chunk boundary, the engine uses a 3D Toroidal Ring Buffer (Sliding Window).\nBecause coordinates wrap around via modulo operations across all three axes, moving through the world requires zero data reallocations. When the player moves along an axis (say, $+X$), only the 2D plane on the opposite, trailing boundary ($-X$) is invalidated and marked for regeneration with the newly entered terrain.\n/// Update loaded chunks based on player movement. /// Only marks the \u0026#34;trailing\u0026#34; surface layer of chunks for clearance. fn slide_active_window(\u0026amp;mut self, new_player_coord: \u0026amp;ChunkCoord) { let deltas = [ new_player_coord.0 - self.previous_player_coord.0, new_player_coord.1 - self.previous_player_coord.1, new_player_coord.2 - self.previous_player_coord.2, ]; for (axis, \u0026amp;movement_delta) in deltas.iter().enumerate() { if movement_delta == 0 { continue; } let step = if movement_delta \u0026gt; 0 { 1 } else { -1 }; let mut working_base = self.previous_player_coord; // Process step-by-step to handle multi-chunk teleports/fast movement for _ in 0..movement_delta.abs() { let half = self.active_size[axis] as isize / 2; let plane_offset = -half * step; // Invalidate the 2D plane perpendicular to the movement direction for i in 0..self.active_size[(axis + 1) % 3] as isize { for j in 0..self.active_size[(axis + 2) % 3] as isize { let chunk_coord = match axis { 0 =\u0026gt; ChunkCoord(working_base.0 + plane_offset, working_base.1 + i - half, working_base.2 + j - half), 1 =\u0026gt; ChunkCoord(working_base.0 + j - half, working_base.1 + plane_offset, working_base.2 + i - half), _ =\u0026gt; ChunkCoord(working_base.0 + i - half, working_base.1 + j - half, working_base.2 + plane_offset), }; self.get_active_entry_mut(\u0026amp;chunk_coord).unset(); } } match axis { 0 =\u0026gt; working_base.0 += step, 1 =\u0026gt; working_base.1 += step, _ =\u0026gt; working_base.2 += step, } } } self.previous_player_coord = *new_player_coord; } Prioritized Chunk \u0026amp; Mesh Generation Generating a chunk is a two-step pipeline:\nVoxel Population: The 3D density noise generates raw voxel data. Mesh Extraction: Once a chunk and all its direct neighbors are populated, faces obscured by adjacent solid blocks are culled, and GPU vertex buffers are created and uploaded. Notice how whenever a non-empty chunk finishes loading, it flags its immediate neighbors (unset_mesh()): a border chunk cannot accurately cull its outer faces until adjacent blocks are known!\nfn generate_pending_chunks(\u0026amp;mut self, player_chunk_position: \u0026amp;ChunkCoord, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, distance) = self.offsets[i]; let chunk_coord = player_chunk_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).is_pending() { // Early out for chunks strictly above terrain generation limit if chunk_coord.1 \u0026lt;= -2 || chunk_coord.1 \u0026gt;= 14 { *self.get_active_entry_mut(\u0026amp;chunk_coord) = ActiveEntry::Empty { coord: chunk_coord }; continue; } let new_chunk = Chunk::new_populated(\u0026amp;self.density_generator, \u0026amp;chunk_coord); used_budget += 1; if new_chunk.is_empty() { self.get_active_entry_mut(\u0026amp;chunk_coord).set_empty(chunk_coord); } else { let required_lod = select_lod(distance); self.get_active_entry_mut(\u0026amp;chunk_coord).set_loaded(chunk_coord, new_chunk, required_lod); // Invalidate neighbor meshes to enforce seamless boundary culling for neighbor_coord in self.get_neighbor_chunk_coords(\u0026amp;chunk_coord) { self.get_active_entry_mut(\u0026amp;neighbor_coord).unset_mesh(); } } } } used_budget } fn generate_pending_meshes(\u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, _) = self.offsets[i]; let chunk_coord = player_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).needs_remesh() { let chunk_borders = self.get_chunk_borders(\u0026amp;chunk_coord); self.get_active_entry_mut(\u0026amp;chunk_coord).generate_and_upload_mesh(device, \u0026amp;chunk_borders); used_budget += 1; } } used_budget } What\u0026rsquo;s Next? While the engine runs at a solid 60 FPS under normal navigation, there are several exciting paths for future improvements:\nGreedy Meshing: Combining adjacent coplanar quad faces into single larger quads to drastically reduce vertex and index buffer sizes. Web Workers via SharedArrayBuffer: Offloading noise sampling to background Web Workers using Rust\u0026rsquo;s wasm-bindgen-rayon to make chunk generation truly asynchronous without stuttering the render thread. Persistent Browser Storage: Currently, all edits vanish on page refresh. The browser provides powerful mechanisms to persist modified worlds: OPFS (Origin Private File System): A modern, sandboxed filesystem API that allows fast, synchronous binary I/O from within Web Workers. It would enable Minecraft-style binary region files (.mca) running purely on the client. IndexedDB: An alternative key-value store to save compressed diffs of player-modified chunks without touching the pristine procedurally generated baseline. Floating Origin (Camera-Relative Rendering): While chunk coordinates can logically span a 32-bit integer space (billions of blocks), GPU rendering relies on 32-bit floating-point numbers (f32). At extreme coordinate distances, IEEE 754 floats lose precision, manifesting as severe vertex jitter, camera stutter, and depth-fighting artifacts (the classic \u0026ldquo;Far Lands\u0026rdquo; effect).\nAn architectural fix is a floating origin: instead of translating the camera through an ever-expanding global space, the camera is pinned statically at $(0, 0, 0)$. Chunks maintain their true logical world coordinates for generation and storage, but are indexed and pushed to the GPU transformed into local camera space. ","permalink":"http://localhost:1313/posts/voxel-engine/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eDisclaimer\u003c/strong\u003e: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ca href=\"https://eliaswendt.github.io/woxel\"\u003eLive Demo\u003c/a\u003e · \u003ca href=\"https://github.com/eliaswendt/woxel\"\u003eGitHub Repository\u003c/a\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-software-stack\"\u003eThe Software Stack\u003c/h2\u003e\n\u003cp\u003eWith WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed with modern AI tooling:\u003c/p\u003e","title":"Building a Browser Voxel Engine in Rust \u0026 WebGPU"},{"content":"Abstract High-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\nLinks ACL Anthology Download PDF GitHub Repo Huggingface Repo 🤗 BibTeX 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @inproceedings{aliJudgingQualityLanguages2025b, title = {Judging {{Quality Across Languages}}: {{A Multilingual Approach}} to {{Pretraining Data Filtering}} with {{Language Models}}}, shorttitle = {Judging {{Quality Across Languages}}}, booktitle = {Proceedings of the 2025 {{Conference}} on {{Empirical Methods}} in {{Natural Language Processing}}}, author = {Ali, Mehdi and Brack, Manuel and L{\\\u0026#34;u}bbering, Max and Wendt, Elias and Khan, Abbas Goher and Rutmann, Richard and Jude, Alex and Kraus, Maurice and Weber, Alexander Arno and Stollenwerk, Felix and Kacz{\\\u0026#39;e}r, David and Mai, Florian and Flek, Lucie and Sifa, Rafet and {Flores-Herr}, Nicolas and Koehler, Joachim and Schramowski, Patrick and Fromm, Michael and Kersting, Kristian}, year = 2025, pages = {8870--8909}, publisher = {Association for Computational Linguistics}, address = {Suzhou, China}, doi = {10.18653/v1/2025.emnlp-main.449}, urldate = {2026-06-27}, langid = {english}, file = {/Users/me/Zotero/storage/5IE6855P/Ali et al. - 2025 - Judging Quality Across Languages A Multilingual Approach to Pretraining Data Filtering with Languag.pdf} } ","permalink":"http://localhost:1313/posts/publication-jql/","summary":"\u003ch2 id=\"abstract\"\u003eAbstract\u003c/h2\u003e\n\u003cp\u003eHigh-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\u003c/p\u003e","title":"Judging Quality Across Languages: A Multilingual Approach to Pretraining Data Filtering with Language Models"},{"content":"The core idea of Bayesian inference is updating an initial belief in light of new evidence.\nStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the prior distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the posterior $p(X|E)$:\n$$ \\underbrace{p(X|E)}_{\\text{posterior}} = \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}} = \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}} = \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]} $$ Prior $p(X)$: What we believe about $X$ (e.g. how it is distributed) before looking at the data Likelihood $p(E|X)$: If the hypothesis $X$ were true, how likely would the observed evidence $E$ be? Posterior $p(X|E)$: What we should believe about $X$ now that we have observed $E$. Marginal Likelihood (Evidence) $p(E)$: The total probability of observing the evidence across all possible states of $X$. Notice: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning: $$ \\text{Posterior} \\propto \\text{Likelihood} \\cdot \\text{Prior} $$ New beliefs are a direct compromise between what you previously thought (Prior) and what the data suggests (Likelihood).\nIterative Learning Bayesian updating is naturally sequential. Assuming independent observations given $X$, the current posterior $p(X|E)$ becomes the starting prior:\n$$ p(X | E_1, E_2) \\propto p(E_2 | X) \\cdot p(X | E_1) $$As you collect more evidence, the likelihood term begins to dominate, and the initial prior gradually washes out.\nExample: The Base Rate Fallacy Why can\u0026rsquo;t we just rely on the likelihood $p(E|X)$? Consider a rare disease:\nPrior: $1$ in $1{,}000$ people has the disease $\\rightarrow p(\\text{Disease}) = 0.001$. Likelihood (Accuracy): A test is $99$% accurate for sick people $\\rightarrow p(\\text{Positive} | \\text{Disease}) = 0.99$. False Positive Rate: The test gives a false positive $5$% of the time for healthy people $\\rightarrow p(\\text{Positive} | \\text{Healthy}) = 0.05$. If a patient tests positive ($E = \\text{Positive}$):\n$$ p(\\text{Disease} | \\text{Positive}) = \\frac{0.99 \\cdot 0.001}{(0.99 \\cdot 0.001) + (0.05 \\cdot 0.999)} \\approx \\frac{0.00099}{0.00099 + 0.04995} \\approx 1.94\\% $$Even with a $99$% accurate test, the probability of being sick is under $2$%. The massive pool of healthy people generates far more false alarms than genuine detections. The prior acts as an anchor that keeps rare events from being drastically overestimated.\n","permalink":"http://localhost:1313/posts/bayes-theorem/","summary":"\u003cp\u003eThe core idea of Bayesian inference is updating an initial belief in light of new evidence.\u003c/p\u003e\n\u003cp\u003eStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the \u003cstrong\u003eprior\u003c/strong\u003e distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the \u003cstrong\u003eposterior\u003c/strong\u003e $p(X|E)$:\u003c/p\u003e\n$$\n\\underbrace{p(X|E)}_{\\text{posterior}}\n= \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}}\n= \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}}\n= \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]}\n$$\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePrior $p(X)$:\u003c/strong\u003e What we believe about $X$ (e.g. how it is distributed) before looking at the data\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLikelihood $p(E|X)$:\u003c/strong\u003e If the hypothesis $X$ were true, how likely would the observed evidence $E$ be?\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePosterior $p(X|E)$:\u003c/strong\u003e What we should believe about $X$ now that we have observed $E$.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMarginal Likelihood (Evidence) $p(E)$:\u003c/strong\u003e The total probability of observing the evidence across \u003cem\u003eall\u003c/em\u003e possible states of $X$.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eNotice\u003c/strong\u003e: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning:\n\u003c/p\u003e","title":"Bayes' Theorem"},{"content":"","permalink":"http://localhost:1313/posts/invariant-mechanism-analysis/","summary":"","title":"Invariant Mechanism Analysis"},{"content":"Association vs. Causation Classical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: $$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$This objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$. From a probabilistic objective this is equivalent to optimizing: $$ \\arg \\max_\\theta p_\\theta (Y|X) $$However, not all association is causally grounded!\nExample do-Calculus Rule 1: Insertion/Deletion of Observations $P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\nRule 2: Action/Observation Exchange $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), z, w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\underline{Z}}$\nRule 3: Insertion/Deletion of Interventions $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\overline{Z(W)}}$\nCompeteness The do-calculus has been proven to be complete. This means that if it rules cannot translate the do-operator into pure probabilistic expressions, the causal effect is not identifiable.\nInstrumental Variables ","permalink":"http://localhost:1313/posts/causal-effect-estimation/","summary":"\u003ch2 id=\"association-vs-causation\"\u003eAssociation vs. Causation\u003c/h2\u003e\n\u003cp\u003eClassical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: \u003c/p\u003e\n$$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$\u003cp\u003eThis objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$.\nFrom a probabilistic objective this is equivalent to optimizing: \u003c/p\u003e\n$$ \\arg \\max_\\theta p_\\theta (Y|X) $$\u003cp\u003eHowever, not all association is causally grounded!\u003c/p\u003e\n\u003ch3 id=\"example\"\u003eExample\u003c/h3\u003e\n\u003ch2 id=\"do-calculus\"\u003edo-Calculus\u003c/h2\u003e\n\u003ch3 id=\"rule-1-insertiondeletion-of-observations\"\u003eRule 1: Insertion/Deletion of Observations\u003c/h3\u003e\n\u003cp\u003e$P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\u003c/p\u003e","title":"Causal Effect Estimation"},{"content":" Disclaimer: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\nLive Demo · GitHub Repository\nThe Software Stack With WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed with modern AI tooling:\nGraphics: wgpu (Targeting WebGPU via WebAssembly) Linear Algebra: glam GUI: egui Build Tooling: Trunk Blocks and Chunks At the core of any voxel engine lies a hierarchy: individual voxels aggregate into manageable spatial volumes called Chunks.\nA chunk is represented as a contiguous 3D array of Blocks. Storing millions of empty air voxels naively would quickly exhaust memory, especially within browser constraints. To mitigate this, chunks consisting solely of air are treated as uniform singletons and avoid individual heap allocations:\n#[derive(Copy, Clone, PartialEq, Eq)] pub enum BlockType { Air, Grass, Dirt, Stone, } pub struct Chunk { blocks: [BlockType; N_BLOCKS_PER_CHUNK], } View Distance \u0026amp; The Single-Thread Bottleneck In a traditional native engine, chunk generation and meshing are dispatched to background thread pools (e.g., via rayon). In a standard browser WASM environment, however, we are bound to the main UI and animation thread.\nIf a frame takes longer than 16.6 ms we fall under the holy 60 FPS mark. Because generating 3D Perlin/Simplex noise and extracting surface polygons (meshing) is computationally heavy, we cannot generate all chunks within the player\u0026rsquo;s view distance in a single frame.\nInstead, we need two things:\nPrioritization: Chunks closest to the player must generate first. Time-slicing (Amortization): Bound the number of chunks and meshes generated per frame cycle. 1. Precomputed Spherical Offsets Calculating Euclidean distances on every frame for dozens of surrounding chunk coordinates is wasteful. Since the relative geometric layout never changes, we can precompute the offset coordinates relative to $(0, 0, 0)$ once at startup and sort them spherically:\nfn generate_offsets_in_spherical_order(radius: isize) -\u0026gt; Vec\u0026lt;(ChunkCoord, usize)\u0026gt; { let mut offsets = Vec::new(); for x in 0..radius { for y in 0..radius { for z in 0..radius { let offset_x = x - radius / 2; let offset_y = y - radius / 2; let offset_z = z - radius / 2; // Euclidean distance relative to origin let dist = (offset_x.pow(2) + offset_y.pow(2) + offset_z.pow(2)).isqrt() as usize; offsets.push((ChunkCoord(offset_x, offset_y, offset_z), dist)); } } } // Sort ascending: closest chunks first offsets.sort_unstable_by_key(|(_, dist)| *dist); offsets } 2. The Frame Update Loop In each render tick, the engine slides its active chunk window based on the player\u0026rsquo;s movement, and then consumes a strictly defined compute budget of chunk and mesh builds:\n// Called once per frame pub fn update( \u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, max_chunk_budget: usize, max_mesh_budget: usize ) -\u0026gt; (usize, usize) { // 1. Shift the logical sliding window (O(1) index updates, practically free) self.slide_active_window(player_position); // 2. Process pending generation within budget let n_chunks = self.generate_pending_chunks(player_position, max_chunk_budget); let n_meshes = self.generate_pending_meshes(player_position, device, max_mesh_budget); (n_chunks, n_meshes) } Chunk Management: 3D Toroidal Buffering Rather than reallocating an entire 3D grid whenever the player crosses a chunk boundary, the engine uses a 3D Toroidal Ring Buffer (Sliding Window).\nBecause coordinates wrap around via modulo operations across all three axes, moving through the world requires zero data reallocations. When the player moves along an axis (say, $+X$), only the 2D plane on the opposite, trailing boundary ($-X$) is invalidated and marked for regeneration with the newly entered terrain.\n/// Update loaded chunks based on player movement. /// Only marks the \u0026#34;trailing\u0026#34; surface layer of chunks for clearance. fn slide_active_window(\u0026amp;mut self, new_player_coord: \u0026amp;ChunkCoord) { let deltas = [ new_player_coord.0 - self.previous_player_coord.0, new_player_coord.1 - self.previous_player_coord.1, new_player_coord.2 - self.previous_player_coord.2, ]; for (axis, \u0026amp;movement_delta) in deltas.iter().enumerate() { if movement_delta == 0 { continue; } let step = if movement_delta \u0026gt; 0 { 1 } else { -1 }; let mut working_base = self.previous_player_coord; // Process step-by-step to handle multi-chunk teleports/fast movement for _ in 0..movement_delta.abs() { let half = self.active_size[axis] as isize / 2; let plane_offset = -half * step; // Invalidate the 2D plane perpendicular to the movement direction for i in 0..self.active_size[(axis + 1) % 3] as isize { for j in 0..self.active_size[(axis + 2) % 3] as isize { let chunk_coord = match axis { 0 =\u0026gt; ChunkCoord(working_base.0 + plane_offset, working_base.1 + i - half, working_base.2 + j - half), 1 =\u0026gt; ChunkCoord(working_base.0 + j - half, working_base.1 + plane_offset, working_base.2 + i - half), _ =\u0026gt; ChunkCoord(working_base.0 + i - half, working_base.1 + j - half, working_base.2 + plane_offset), }; self.get_active_entry_mut(\u0026amp;chunk_coord).unset(); } } match axis { 0 =\u0026gt; working_base.0 += step, 1 =\u0026gt; working_base.1 += step, _ =\u0026gt; working_base.2 += step, } } } self.previous_player_coord = *new_player_coord; } Prioritized Chunk \u0026amp; Mesh Generation Generating a chunk is a two-step pipeline:\nVoxel Population: The 3D density noise generates raw voxel data. Mesh Extraction: Once a chunk and all its direct neighbors are populated, faces obscured by adjacent solid blocks are culled, and GPU vertex buffers are created and uploaded. Notice how whenever a non-empty chunk finishes loading, it flags its immediate neighbors (unset_mesh()): a border chunk cannot accurately cull its outer faces until adjacent blocks are known!\nfn generate_pending_chunks(\u0026amp;mut self, player_chunk_position: \u0026amp;ChunkCoord, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, distance) = self.offsets[i]; let chunk_coord = player_chunk_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).is_pending() { // Early out for chunks strictly above terrain generation limit if chunk_coord.1 \u0026lt;= -2 || chunk_coord.1 \u0026gt;= 14 { *self.get_active_entry_mut(\u0026amp;chunk_coord) = ActiveEntry::Empty { coord: chunk_coord }; continue; } let new_chunk = Chunk::new_populated(\u0026amp;self.density_generator, \u0026amp;chunk_coord); used_budget += 1; if new_chunk.is_empty() { self.get_active_entry_mut(\u0026amp;chunk_coord).set_empty(chunk_coord); } else { let required_lod = select_lod(distance); self.get_active_entry_mut(\u0026amp;chunk_coord).set_loaded(chunk_coord, new_chunk, required_lod); // Invalidate neighbor meshes to enforce seamless boundary culling for neighbor_coord in self.get_neighbor_chunk_coords(\u0026amp;chunk_coord) { self.get_active_entry_mut(\u0026amp;neighbor_coord).unset_mesh(); } } } } used_budget } fn generate_pending_meshes(\u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, _) = self.offsets[i]; let chunk_coord = player_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).needs_remesh() { let chunk_borders = self.get_chunk_borders(\u0026amp;chunk_coord); self.get_active_entry_mut(\u0026amp;chunk_coord).generate_and_upload_mesh(device, \u0026amp;chunk_borders); used_budget += 1; } } used_budget } What\u0026rsquo;s Next? While the engine runs at a solid 60 FPS under normal navigation, there are several exciting paths for future improvements:\nGreedy Meshing: Combining adjacent coplanar quad faces into single larger quads to drastically reduce vertex and index buffer sizes. Web Workers via SharedArrayBuffer: Offloading noise sampling to background Web Workers using Rust\u0026rsquo;s wasm-bindgen-rayon to make chunk generation truly asynchronous without stuttering the render thread. Persistent Browser Storage: Currently, all edits vanish on page refresh. The browser provides powerful mechanisms to persist modified worlds: OPFS (Origin Private File System): A modern, sandboxed filesystem API that allows fast, synchronous binary I/O from within Web Workers. It would enable Minecraft-style binary region files (.mca) running purely on the client. IndexedDB: An alternative key-value store to save compressed diffs of player-modified chunks without touching the pristine procedurally generated baseline. Floating Origin (Camera-Relative Rendering): While chunk coordinates can logically span a 32-bit integer space (billions of blocks), GPU rendering relies on 32-bit floating-point numbers (f32). At extreme coordinate distances, IEEE 754 floats lose precision, manifesting as severe vertex jitter, camera stutter, and depth-fighting artifacts (the classic \u0026ldquo;Far Lands\u0026rdquo; effect).\nAn architectural fix is a floating origin: instead of translating the camera through an ever-expanding global space, the camera is pinned statically at $(0, 0, 0)$. Chunks maintain their true logical world coordinates for generation and storage, but are indexed and pushed to the GPU transformed into local camera space. ","permalink":"http://localhost:1313/posts/voxel-engine/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eDisclaimer\u003c/strong\u003e: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ca href=\"https://eliaswendt.github.io/woxel\"\u003eLive Demo\u003c/a\u003e · \u003ca href=\"https://github.com/eliaswendt/woxel\"\u003eGitHub Repository\u003c/a\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-software-stack\"\u003eThe Software Stack\u003c/h2\u003e\n\u003cp\u003eWith WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed with modern AI tooling:\u003c/p\u003e","title":"Building a Browser Voxel Engine in Rust \u0026 WebGPU"},{"content":"Abstract High-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\nLinks ACL Anthology Download PDF GitHub Repo Huggingface Repo 🤗 BibTeX 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @inproceedings{aliJudgingQualityLanguages2025b, title = {Judging {{Quality Across Languages}}: {{A Multilingual Approach}} to {{Pretraining Data Filtering}} with {{Language Models}}}, shorttitle = {Judging {{Quality Across Languages}}}, booktitle = {Proceedings of the 2025 {{Conference}} on {{Empirical Methods}} in {{Natural Language Processing}}}, author = {Ali, Mehdi and Brack, Manuel and L{\\\u0026#34;u}bbering, Max and Wendt, Elias and Khan, Abbas Goher and Rutmann, Richard and Jude, Alex and Kraus, Maurice and Weber, Alexander Arno and Stollenwerk, Felix and Kacz{\\\u0026#39;e}r, David and Mai, Florian and Flek, Lucie and Sifa, Rafet and {Flores-Herr}, Nicolas and Koehler, Joachim and Schramowski, Patrick and Fromm, Michael and Kersting, Kristian}, year = 2025, pages = {8870--8909}, publisher = {Association for Computational Linguistics}, address = {Suzhou, China}, doi = {10.18653/v1/2025.emnlp-main.449}, urldate = {2026-06-27}, langid = {english}, file = {/Users/me/Zotero/storage/5IE6855P/Ali et al. - 2025 - Judging Quality Across Languages A Multilingual Approach to Pretraining Data Filtering with Languag.pdf} } ","permalink":"http://localhost:1313/posts/publication-jql/","summary":"\u003ch2 id=\"abstract\"\u003eAbstract\u003c/h2\u003e\n\u003cp\u003eHigh-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\u003c/p\u003e","title":"Judging Quality Across Languages: A Multilingual Approach to Pretraining Data Filtering with Language Models"},{"content":"The core idea of Bayesian inference is updating an initial belief in light of new evidence.\nStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the prior distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the posterior $p(X|E)$:\n$$ \\underbrace{p(X|E)}_{\\text{posterior}} = \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}} = \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}} = \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]} $$ Prior $p(X)$: What we believe about $X$ (e.g. how it is distributed) before looking at the data Likelihood $p(E|X)$: If the hypothesis $X$ were true, how likely would the observed evidence $E$ be? Posterior $p(X|E)$: What we should believe about $X$ now that we have observed $E$. Marginal Likelihood (Evidence) $p(E)$: The total probability of observing the evidence across all possible states of $X$. Notice: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning: $$ \\text{Posterior} \\propto \\text{Likelihood} \\cdot \\text{Prior} $$ New beliefs are a direct compromise between what you previously thought (Prior) and what the data suggests (Likelihood).\nIterative Learning Bayesian updating is naturally sequential. Assuming independent observations given $X$, the current posterior $p(X|E)$ becomes the starting prior:\n$$ p(X | E_1, E_2) \\propto p(E_2 | X) \\cdot p(X | E_1) $$As you collect more evidence, the likelihood term begins to dominate, and the initial prior gradually washes out.\nExample: The Base Rate Fallacy Why can\u0026rsquo;t we just rely on the likelihood $p(E|X)$? Consider a rare disease:\nPrior: $1$ in $1{,}000$ people has the disease $\\rightarrow p(\\text{Disease}) = 0.001$. Likelihood (Accuracy): A test is $99$% accurate for sick people $\\rightarrow p(\\text{Positive} | \\text{Disease}) = 0.99$. False Positive Rate: The test gives a false positive $5$% of the time for healthy people $\\rightarrow p(\\text{Positive} | \\text{Healthy}) = 0.05$. If a patient tests positive ($E = \\text{Positive}$):\n$$ p(\\text{Disease} | \\text{Positive}) = \\frac{0.99 \\cdot 0.001}{(0.99 \\cdot 0.001) + (0.05 \\cdot 0.999)} \\approx \\frac{0.00099}{0.00099 + 0.04995} \\approx 1.94\\% $$Even with a $99$% accurate test, the probability of being sick is under $2$%. The massive pool of healthy people generates far more false alarms than genuine detections. The prior acts as an anchor that keeps rare events from being drastically overestimated.\n","permalink":"http://localhost:1313/posts/bayes-theorem/","summary":"\u003cp\u003eThe core idea of Bayesian inference is updating an initial belief in light of new evidence.\u003c/p\u003e\n\u003cp\u003eStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the \u003cstrong\u003eprior\u003c/strong\u003e distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the \u003cstrong\u003eposterior\u003c/strong\u003e $p(X|E)$:\u003c/p\u003e\n$$\n\\underbrace{p(X|E)}_{\\text{posterior}}\n= \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}}\n= \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}}\n= \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]}\n$$\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePrior $p(X)$:\u003c/strong\u003e What we believe about $X$ (e.g. how it is distributed) before looking at the data\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLikelihood $p(E|X)$:\u003c/strong\u003e If the hypothesis $X$ were true, how likely would the observed evidence $E$ be?\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePosterior $p(X|E)$:\u003c/strong\u003e What we should believe about $X$ now that we have observed $E$.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMarginal Likelihood (Evidence) $p(E)$:\u003c/strong\u003e The total probability of observing the evidence across \u003cem\u003eall\u003c/em\u003e possible states of $X$.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eNotice\u003c/strong\u003e: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning:\n\u003c/p\u003e","title":"Bayes' Theorem"},{"content":"","permalink":"http://localhost:1313/posts/invariant-mechanism-analysis/","summary":"","title":"Invariant Mechanism Analysis"},{"content":"Association vs. Causation Classical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: $$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$This objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$. From a probabilistic objective this is equivalent to optimizing: $$ \\arg \\max_\\theta p_\\theta (Y|X) $$However, not all association is causally grounded!\nExample do-Calculus Rule 1: Insertion/Deletion of Observations $P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\nRule 2: Action/Observation Exchange $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), z, w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\underline{Z}}$\nRule 3: Insertion/Deletion of Interventions $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\overline{Z(W)}}$\nCompeteness The do-calculus has been proven to be complete. This means that if it rules cannot translate the do-operator into pure probabilistic expressions, the causal effect is not identifiable.\nInstrumental Variables ","permalink":"http://localhost:1313/posts/causal-effect-estimation/","summary":"\u003ch2 id=\"association-vs-causation\"\u003eAssociation vs. Causation\u003c/h2\u003e\n\u003cp\u003eClassical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: \u003c/p\u003e\n$$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$\u003cp\u003eThis objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$.\nFrom a probabilistic objective this is equivalent to optimizing: \u003c/p\u003e\n$$ \\arg \\max_\\theta p_\\theta (Y|X) $$\u003cp\u003eHowever, not all association is causally grounded!\u003c/p\u003e\n\u003ch3 id=\"example\"\u003eExample\u003c/h3\u003e\n\u003ch2 id=\"do-calculus\"\u003edo-Calculus\u003c/h2\u003e\n\u003ch3 id=\"rule-1-insertiondeletion-of-observations\"\u003eRule 1: Insertion/Deletion of Observations\u003c/h3\u003e\n\u003cp\u003e$P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\u003c/p\u003e","title":"Causal Effect Estimation"},{"content":" Disclaimer: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\nLive Demo · GitHub Repository\nThe Software Stack With WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\nGraphics: wgpu (Targeting WebGPU via WebAssembly) Linear Algebra: glam GUI: egui Build Tooling: Trunk Blocks and Chunks At the core of any voxel engine lies a hierarchy: individual voxels aggregate into manageable spatial volumes called Chunks.\nA chunk is represented as a contiguous 3D array of Blocks. Storing millions of empty air voxels naively would quickly exhaust memory, especially within browser constraints. To mitigate this, chunks consisting solely of air are treated as uniform singletons and avoid individual heap allocations:\n#[derive(Copy, Clone, PartialEq, Eq)] pub enum BlockType { Air, Grass, Dirt, Stone, } pub struct Chunk { blocks: [BlockType; N_BLOCKS_PER_CHUNK], } View Distance \u0026amp; The Single-Thread Bottleneck In a traditional native engine, chunk generation and meshing are dispatched to background thread pools (e.g., via rayon). In a standard browser WASM environment, however, we are bound to the main UI and animation thread.\nIf a frame takes longer than 16.6 ms we fall under the holy 60 FPS mark. Because generating 3D Perlin/Simplex noise and extracting surface polygons (meshing) is computationally heavy, we cannot generate all chunks within the player\u0026rsquo;s view distance in a single frame.\nInstead, we need two things:\nPrioritization: Chunks closest to the player must generate first. Time-slicing (Amortization): Bound the number of chunks and meshes generated per frame cycle. 1. Precomputed Spherical Offsets Calculating Euclidean distances on every frame for dozens of surrounding chunk coordinates is wasteful. Since the relative geometric layout never changes, we can precompute the offset coordinates relative to $(0, 0, 0)$ once at startup and sort them spherically:\nfn generate_offsets_in_spherical_order(radius: isize) -\u0026gt; Vec\u0026lt;(ChunkCoord, usize)\u0026gt; { let mut offsets = Vec::new(); for x in 0..radius { for y in 0..radius { for z in 0..radius { let offset_x = x - radius / 2; let offset_y = y - radius / 2; let offset_z = z - radius / 2; // Euclidean distance relative to origin let dist = (offset_x.pow(2) + offset_y.pow(2) + offset_z.pow(2)).isqrt() as usize; offsets.push((ChunkCoord(offset_x, offset_y, offset_z), dist)); } } } // Sort ascending: closest chunks first offsets.sort_unstable_by_key(|(_, dist)| *dist); offsets } 2. The Frame Update Loop In each render tick, the engine slides its active chunk window based on the player\u0026rsquo;s movement, and then consumes a strictly defined compute budget of chunk and mesh builds:\n// Called once per frame pub fn update( \u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, max_chunk_budget: usize, max_mesh_budget: usize ) -\u0026gt; (usize, usize) { // 1. Shift the logical sliding window (O(1) index updates, practically free) self.slide_active_window(player_position); // 2. Process pending generation within budget let n_chunks = self.generate_pending_chunks(player_position, max_chunk_budget); let n_meshes = self.generate_pending_meshes(player_position, device, max_mesh_budget); (n_chunks, n_meshes) } Chunk Management: 3D Toroidal Buffering Rather than reallocating an entire 3D grid whenever the player crosses a chunk boundary, the engine uses a 3D Toroidal Ring Buffer (Sliding Window).\nBecause coordinates wrap around via modulo operations across all three axes, moving through the world requires zero data reallocations. When the player moves along an axis (say, $+X$), only the 2D plane on the opposite, trailing boundary ($-X$) is invalidated and marked for regeneration with the newly entered terrain.\n/// Update loaded chunks based on player movement. /// Only marks the \u0026#34;trailing\u0026#34; surface layer of chunks for clearance. fn slide_active_window(\u0026amp;mut self, new_player_coord: \u0026amp;ChunkCoord) { let deltas = [ new_player_coord.0 - self.previous_player_coord.0, new_player_coord.1 - self.previous_player_coord.1, new_player_coord.2 - self.previous_player_coord.2, ]; for (axis, \u0026amp;movement_delta) in deltas.iter().enumerate() { if movement_delta == 0 { continue; } let step = if movement_delta \u0026gt; 0 { 1 } else { -1 }; let mut working_base = self.previous_player_coord; // Process step-by-step to handle multi-chunk teleports/fast movement for _ in 0..movement_delta.abs() { let half = self.active_size[axis] as isize / 2; let plane_offset = -half * step; // Invalidate the 2D plane perpendicular to the movement direction for i in 0..self.active_size[(axis + 1) % 3] as isize { for j in 0..self.active_size[(axis + 2) % 3] as isize { let chunk_coord = match axis { 0 =\u0026gt; ChunkCoord(working_base.0 + plane_offset, working_base.1 + i - half, working_base.2 + j - half), 1 =\u0026gt; ChunkCoord(working_base.0 + j - half, working_base.1 + plane_offset, working_base.2 + i - half), _ =\u0026gt; ChunkCoord(working_base.0 + i - half, working_base.1 + j - half, working_base.2 + plane_offset), }; self.get_active_entry_mut(\u0026amp;chunk_coord).unset(); } } match axis { 0 =\u0026gt; working_base.0 += step, 1 =\u0026gt; working_base.1 += step, _ =\u0026gt; working_base.2 += step, } } } self.previous_player_coord = *new_player_coord; } Prioritized Chunk \u0026amp; Mesh Generation Generating a chunk is a two-step pipeline:\nVoxel Population: The 3D density noise generates raw voxel data. Mesh Extraction: Once a chunk and all its direct neighbors are populated, faces obscured by adjacent solid blocks are culled, and GPU vertex buffers are created and uploaded. Notice how whenever a non-empty chunk finishes loading, it flags its immediate neighbors (unset_mesh()): a border chunk cannot accurately cull its outer faces until adjacent blocks are known!\nfn generate_pending_chunks(\u0026amp;mut self, player_chunk_position: \u0026amp;ChunkCoord, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, distance) = self.offsets[i]; let chunk_coord = player_chunk_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).is_pending() { // Early out for chunks strictly above terrain generation limit if chunk_coord.1 \u0026lt;= -2 || chunk_coord.1 \u0026gt;= 14 { *self.get_active_entry_mut(\u0026amp;chunk_coord) = ActiveEntry::Empty { coord: chunk_coord }; continue; } let new_chunk = Chunk::new_populated(\u0026amp;self.density_generator, \u0026amp;chunk_coord); used_budget += 1; if new_chunk.is_empty() { self.get_active_entry_mut(\u0026amp;chunk_coord).set_empty(chunk_coord); } else { let required_lod = select_lod(distance); self.get_active_entry_mut(\u0026amp;chunk_coord).set_loaded(chunk_coord, new_chunk, required_lod); // Invalidate neighbor meshes to enforce seamless boundary culling for neighbor_coord in self.get_neighbor_chunk_coords(\u0026amp;chunk_coord) { self.get_active_entry_mut(\u0026amp;neighbor_coord).unset_mesh(); } } } } used_budget } fn generate_pending_meshes(\u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, _) = self.offsets[i]; let chunk_coord = player_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).needs_remesh() { let chunk_borders = self.get_chunk_borders(\u0026amp;chunk_coord); self.get_active_entry_mut(\u0026amp;chunk_coord).generate_and_upload_mesh(device, \u0026amp;chunk_borders); used_budget += 1; } } used_budget } What\u0026rsquo;s Next? While the engine runs at a solid 60 FPS under normal navigation, there are several exciting paths for future improvements:\nGreedy Meshing: Combining adjacent coplanar quad faces into single larger quads to drastically reduce vertex and index buffer sizes. Web Workers via SharedArrayBuffer: Offloading noise sampling to background Web Workers using Rust\u0026rsquo;s wasm-bindgen-rayon to make chunk generation truly asynchronous without stuttering the render thread. Persistent Browser Storage: Currently, all edits vanish on page refresh. The browser provides powerful mechanisms to persist modified worlds: OPFS (Origin Private File System): A modern, sandboxed filesystem API that allows fast, synchronous binary I/O from within Web Workers. It would enable Minecraft-style binary region files (.mca) running purely on the client. IndexedDB: An alternative key-value store to save compressed diffs of player-modified chunks without touching the pristine procedurally generated baseline. Floating Origin (Camera-Relative Rendering): While chunk coordinates can logically span a 32-bit integer space (billions of blocks), GPU rendering relies on 32-bit floating-point numbers (f32). At extreme coordinate distances, IEEE 754 floats lose precision, manifesting as severe vertex jitter, camera stutter, and depth-fighting artifacts (the classic \u0026ldquo;Far Lands\u0026rdquo; effect).\nAn architectural fix is a floating origin: instead of translating the camera through an ever-expanding global space, the camera is pinned statically at $(0, 0, 0)$. Chunks maintain their true logical world coordinates for generation and storage, but are indexed and pushed to the GPU transformed into local camera space. ","permalink":"http://localhost:1313/posts/voxel-engine/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eDisclaimer\u003c/strong\u003e: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ca href=\"https://eliaswendt.github.io/woxel\"\u003eLive Demo\u003c/a\u003e · \u003ca href=\"https://github.com/eliaswendt/woxel\"\u003eGitHub Repository\u003c/a\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-software-stack\"\u003eThe Software Stack\u003c/h2\u003e\n\u003cp\u003eWith WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\u003c/p\u003e","title":"Building a Browser Voxel Engine in Rust \u0026 WebGPU"},{"content":"Abstract High-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\nLinks ACL Anthology Download PDF GitHub Repo Huggingface Repo 🤗 BibTeX 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @inproceedings{aliJudgingQualityLanguages2025b, title = {Judging {{Quality Across Languages}}: {{A Multilingual Approach}} to {{Pretraining Data Filtering}} with {{Language Models}}}, shorttitle = {Judging {{Quality Across Languages}}}, booktitle = {Proceedings of the 2025 {{Conference}} on {{Empirical Methods}} in {{Natural Language Processing}}}, author = {Ali, Mehdi and Brack, Manuel and L{\\\u0026#34;u}bbering, Max and Wendt, Elias and Khan, Abbas Goher and Rutmann, Richard and Jude, Alex and Kraus, Maurice and Weber, Alexander Arno and Stollenwerk, Felix and Kacz{\\\u0026#39;e}r, David and Mai, Florian and Flek, Lucie and Sifa, Rafet and {Flores-Herr}, Nicolas and Koehler, Joachim and Schramowski, Patrick and Fromm, Michael and Kersting, Kristian}, year = 2025, pages = {8870--8909}, publisher = {Association for Computational Linguistics}, address = {Suzhou, China}, doi = {10.18653/v1/2025.emnlp-main.449}, urldate = {2026-06-27}, langid = {english}, file = {/Users/me/Zotero/storage/5IE6855P/Ali et al. - 2025 - Judging Quality Across Languages A Multilingual Approach to Pretraining Data Filtering with Languag.pdf} } ","permalink":"http://localhost:1313/posts/publication-jql/","summary":"\u003ch2 id=\"abstract\"\u003eAbstract\u003c/h2\u003e\n\u003cp\u003eHigh-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\u003c/p\u003e","title":"Judging Quality Across Languages: A Multilingual Approach to Pretraining Data Filtering with Language Models"},{"content":"The core idea of Bayesian inference is updating an initial belief in light of new evidence.\nStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the prior distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the posterior $p(X|E)$:\n$$ \\underbrace{p(X|E)}_{\\text{posterior}} = \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}} = \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}} = \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]} $$ Prior $p(X)$: What we believe about $X$ (e.g. how it is distributed) before looking at the data Likelihood $p(E|X)$: If the hypothesis $X$ were true, how likely would the observed evidence $E$ be? Posterior $p(X|E)$: What we should believe about $X$ now that we have observed $E$. Marginal Likelihood (Evidence) $p(E)$: The total probability of observing the evidence across all possible states of $X$. Notice: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning: $$ \\text{Posterior} \\propto \\text{Likelihood} \\cdot \\text{Prior} $$ New beliefs are a direct compromise between what you previously thought (Prior) and what the data suggests (Likelihood).\nIterative Learning Bayesian updating is naturally sequential. Assuming independent observations given $X$, the current posterior $p(X|E)$ becomes the starting prior:\n$$ p(X | E_1, E_2) \\propto p(E_2 | X) \\cdot p(X | E_1) $$As you collect more evidence, the likelihood term begins to dominate, and the initial prior gradually washes out.\nExample: The Base Rate Fallacy Why can\u0026rsquo;t we just rely on the likelihood $p(E|X)$? Consider a rare disease:\nPrior: $1$ in $1{,}000$ people has the disease $\\rightarrow p(\\text{Disease}) = 0.001$. Likelihood (Accuracy): A test is $99$% accurate for sick people $\\rightarrow p(\\text{Positive} | \\text{Disease}) = 0.99$. False Positive Rate: The test gives a false positive $5$% of the time for healthy people $\\rightarrow p(\\text{Positive} | \\text{Healthy}) = 0.05$. If a patient tests positive ($E = \\text{Positive}$):\n$$ p(\\text{Disease} | \\text{Positive}) = \\frac{0.99 \\cdot 0.001}{(0.99 \\cdot 0.001) + (0.05 \\cdot 0.999)} \\approx \\frac{0.00099}{0.00099 + 0.04995} \\approx 1.94\\% $$Even with a $99$% accurate test, the probability of being sick is under $2$%. The massive pool of healthy people generates far more false alarms than genuine detections. The prior acts as an anchor that keeps rare events from being drastically overestimated.\n","permalink":"http://localhost:1313/posts/bayes-theorem/","summary":"\u003cp\u003eThe core idea of Bayesian inference is updating an initial belief in light of new evidence.\u003c/p\u003e\n\u003cp\u003eStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the \u003cstrong\u003eprior\u003c/strong\u003e distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the \u003cstrong\u003eposterior\u003c/strong\u003e $p(X|E)$:\u003c/p\u003e\n$$\n\\underbrace{p(X|E)}_{\\text{posterior}}\n= \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}}\n= \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}}\n= \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]}\n$$\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePrior $p(X)$:\u003c/strong\u003e What we believe about $X$ (e.g. how it is distributed) before looking at the data\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLikelihood $p(E|X)$:\u003c/strong\u003e If the hypothesis $X$ were true, how likely would the observed evidence $E$ be?\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePosterior $p(X|E)$:\u003c/strong\u003e What we should believe about $X$ now that we have observed $E$.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMarginal Likelihood (Evidence) $p(E)$:\u003c/strong\u003e The total probability of observing the evidence across \u003cem\u003eall\u003c/em\u003e possible states of $X$.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eNotice\u003c/strong\u003e: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning:\n\u003c/p\u003e","title":"Bayes' Theorem"},{"content":"","permalink":"http://localhost:1313/posts/invariant-mechanism-analysis/","summary":"","title":"Invariant Mechanism Analysis"},{"content":"Association vs. Causation Classical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: $$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$This objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$. From a probabilistic objective this is equivalent to optimizing: $$ \\arg \\max_\\theta p_\\theta (Y|X) $$However, not all association is causally grounded!\nExample do-Calculus Rule 1: Insertion/Deletion of Observations $P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\nRule 2: Action/Observation Exchange $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), z, w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\underline{Z}}$\nRule 3: Insertion/Deletion of Interventions $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\overline{Z(W)}}$\nCompeteness The do-calculus has been proven to be complete. This means that if it rules cannot translate the do-operator into pure probabilistic expressions, the causal effect is not identifiable.\nInstrumental Variables ","permalink":"http://localhost:1313/posts/causal-effect-estimation/","summary":"\u003ch2 id=\"association-vs-causation\"\u003eAssociation vs. Causation\u003c/h2\u003e\n\u003cp\u003eClassical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: \u003c/p\u003e\n$$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$\u003cp\u003eThis objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$.\nFrom a probabilistic objective this is equivalent to optimizing: \u003c/p\u003e\n$$ \\arg \\max_\\theta p_\\theta (Y|X) $$\u003cp\u003eHowever, not all association is causally grounded!\u003c/p\u003e\n\u003ch3 id=\"example\"\u003eExample\u003c/h3\u003e\n\u003ch2 id=\"do-calculus\"\u003edo-Calculus\u003c/h2\u003e\n\u003ch3 id=\"rule-1-insertiondeletion-of-observations\"\u003eRule 1: Insertion/Deletion of Observations\u003c/h3\u003e\n\u003cp\u003e$P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\u003c/p\u003e","title":"Causal Effect Estimation"},{"content":" Disclaimer: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\nLive Demo · GitHub Repository\nThe Software Stack With WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\nGraphics: wgpu (Targeting WebGPU via WebAssembly) Linear Algebra: glam GUI: egui Build Tooling: Trunk Blocks and Chunks At the core of any voxel engine lies a hierarchy: individual voxels aggregate into manageable spatial volumes called Chunks.\nA chunk is represented as a contiguous 3D array of Blocks. Storing millions of empty air voxels naively would quickly exhaust memory, especially within browser constraints. To mitigate this, chunks consisting solely of air are treated as uniform singletons and avoid individual heap allocations:\n#[derive(Copy, Clone, PartialEq, Eq)] pub enum BlockType { Air, Grass, Dirt, Stone, } pub struct Chunk { blocks: [BlockType; N_BLOCKS_PER_CHUNK], } View Distance \u0026amp; The Single-Thread Bottleneck In a traditional native engine, chunk generation and meshing are dispatched to background thread pools (e.g., via rayon). In a standard browser WASM environment, however, we are bound to the main UI and animation thread.\nIf a frame takes longer than 16.6 ms we fall under the holy 60 FPS mark. Because generating 3D Perlin/Simplex noise and extracting surface polygons (meshing) is computationally heavy, we cannot generate all chunks within the player\u0026rsquo;s view distance in a single frame.\nInstead, we need two things:\nPrioritization: Chunks closest to the player must generate first. Time-slicing (Amortization): Bound the number of chunks and meshes generated per frame cycle. 1. Precomputed Spherical Offsets Calculating Euclidean distances on every frame for dozens of surrounding chunk coordinates is wasteful. Since the relative geometric layout never changes, we can precompute the offset coordinates relative to $(0, 0, 0)$ once at startup and sort them spherically:\nfn generate_offsets_in_spherical_order(radius: isize) -\u0026gt; Vec\u0026lt;(ChunkCoord, usize)\u0026gt; { let mut offsets = Vec::new(); for x in 0..radius { for y in 0..radius { for z in 0..radius { let offset_x = x - radius / 2; let offset_y = y - radius / 2; let offset_z = z - radius / 2; // Euclidean distance relative to origin let dist = (offset_x.pow(2) + offset_y.pow(2) + offset_z.pow(2)).isqrt() as usize; offsets.push((ChunkCoord(offset_x, offset_y, offset_z), dist)); } } } // Sort ascending: closest chunks first offsets.sort_unstable_by_key(|(_, dist)| *dist); offsets } 2. The Frame Update Loop In each render tick, the engine slides its active chunk window based on the player\u0026rsquo;s movement, and then consumes a strictly defined compute budget of chunk and mesh builds:\n// Called once per frame pub fn update( \u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, max_chunk_budget: usize, max_mesh_budget: usize ) -\u0026gt; (usize, usize) { // 1. Shift the logical sliding window (O(1) index updates, practically free) self.slide_active_window(player_position); // 2. Process pending generation within budget let n_chunks = self.generate_pending_chunks(player_position, max_chunk_budget); let n_meshes = self.generate_pending_meshes(player_position, device, max_mesh_budget); (n_chunks, n_meshes) } Chunk Management: 3D Toroidal Buffering Rather than reallocating an entire 3D grid whenever the player crosses a chunk boundary, the engine uses a 3D Toroidal Ring Buffer (Sliding Window).\nBecause coordinates wrap around via modulo operations across all three axes, moving through the world requires zero data reallocations. When the player moves along an axis (say, $+X$), only the 2D plane on the opposite, trailing boundary ($-X$) is invalidated and marked for regeneration with the newly entered terrain.\n/// Update loaded chunks based on player movement. /// Only marks the \u0026#34;trailing\u0026#34; surface layer of chunks for clearance. fn slide_active_window(\u0026amp;mut self, new_player_coord: \u0026amp;ChunkCoord) { let deltas = [ new_player_coord.0 - self.previous_player_coord.0, new_player_coord.1 - self.previous_player_coord.1, new_player_coord.2 - self.previous_player_coord.2, ]; for (axis, \u0026amp;movement_delta) in deltas.iter().enumerate() { if movement_delta == 0 { continue; } let step = if movement_delta \u0026gt; 0 { 1 } else { -1 }; let mut working_base = self.previous_player_coord; // Process step-by-step to handle multi-chunk teleports/fast movement for _ in 0..movement_delta.abs() { let half = self.active_size[axis] as isize / 2; let plane_offset = -half * step; // Invalidate the 2D plane perpendicular to the movement direction for i in 0..self.active_size[(axis + 1) % 3] as isize { for j in 0..self.active_size[(axis + 2) % 3] as isize { let chunk_coord = match axis { 0 =\u0026gt; ChunkCoord(working_base.0 + plane_offset, working_base.1 + i - half, working_base.2 + j - half), 1 =\u0026gt; ChunkCoord(working_base.0 + j - half, working_base.1 + plane_offset, working_base.2 + i - half), _ =\u0026gt; ChunkCoord(working_base.0 + i - half, working_base.1 + j - half, working_base.2 + plane_offset), }; self.get_active_entry_mut(\u0026amp;chunk_coord).unset(); } } match axis { 0 =\u0026gt; working_base.0 += step, 1 =\u0026gt; working_base.1 += step, _ =\u0026gt; working_base.2 += step, } } } self.previous_player_coord = *new_player_coord; } Prioritized Chunk \u0026amp; Mesh Generation Generating a chunk is a two-step pipeline:\nVoxel Population: The 3D density noise generates raw voxel data. Mesh Extraction: Once a chunk and all its direct neighbors are populated, faces obscured by adjacent solid blocks are culled, and GPU vertex buffers are created and uploaded. Notice how whenever a non-empty chunk finishes loading, it flags its immediate neighbors (unset_mesh()): a border chunk cannot accurately cull its outer faces until adjacent blocks are known!\nfn generate_pending_chunks(\u0026amp;mut self, player_chunk_position: \u0026amp;ChunkCoord, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, distance) = self.offsets[i]; let chunk_coord = player_chunk_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).is_pending() { // Early out for chunks strictly above terrain generation limit if chunk_coord.1 \u0026lt;= -2 || chunk_coord.1 \u0026gt;= 14 { *self.get_active_entry_mut(\u0026amp;chunk_coord) = ActiveEntry::Empty { coord: chunk_coord }; continue; } let new_chunk = Chunk::new_populated(\u0026amp;self.density_generator, \u0026amp;chunk_coord); used_budget += 1; if new_chunk.is_empty() { self.get_active_entry_mut(\u0026amp;chunk_coord).set_empty(chunk_coord); } else { let required_lod = select_lod(distance); self.get_active_entry_mut(\u0026amp;chunk_coord).set_loaded(chunk_coord, new_chunk, required_lod); // Invalidate neighbor meshes to enforce seamless boundary culling for neighbor_coord in self.get_neighbor_chunk_coords(\u0026amp;chunk_coord) { self.get_active_entry_mut(\u0026amp;neighbor_coord).unset_mesh(); } } } } used_budget } fn generate_pending_meshes(\u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, _) = self.offsets[i]; let chunk_coord = player_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).needs_remesh() { let chunk_borders = self.get_chunk_borders(\u0026amp;chunk_coord); self.get_active_entry_mut(\u0026amp;chunk_coord).generate_and_upload_mesh(device, \u0026amp;chunk_borders); used_budget += 1; } } used_budget } What\u0026rsquo;s Next? While the engine runs at a solid 60 FPS under normal navigation, there are several exciting paths for future improvements:\nGreedy Meshing: Combining adjacent coplanar quad faces into single larger quads to drastically reduce vertex and index buffer sizes. Web Workers via SharedArrayBuffer: Offloading noise sampling to background Web Workers using Rust\u0026rsquo;s wasm-bindgen-rayon to make chunk generation truly asynchronous without stuttering the render thread. Persistent Browser Storage: Currently, all edits vanish on page refresh. The browser provides powerful mechanisms to persist modified worlds: OPFS (Origin Private File System): A modern, sandboxed filesystem API that allows fast, synchronous binary I/O from within Web Workers. It would enable Minecraft-style binary region files (.mca) running purely on the client. IndexedDB: An alternative key-value store to save compressed diffs of player-modified chunks without touching the pristine procedurally generated baseline. Floating Origin (Camera-Relative Rendering): While chunk coordinates can logically span a 32-bit integer space (billions of blocks), GPU rendering relies on 32-bit floating-point numbers (f32). At extreme coordinate distances, IEEE 754 floats lose precision, manifesting as severe vertex jitter, camera stutter, and depth-fighting artifacts (the classic \u0026ldquo;Far Lands\u0026rdquo; effect).\nAn architectural fix is a floating origin: instead of translating the camera through an ever-expanding global space, the camera is pinned statically at $(0, 0, 0)$. Chunks maintain their true logical world coordinates for generation and storage, but are indexed and pushed to the GPU transformed into local camera space. ","permalink":"http://localhost:1313/posts/voxel-engine/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eDisclaimer\u003c/strong\u003e: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ca href=\"https://eliaswendt.github.io/woxel\"\u003eLive Demo\u003c/a\u003e · \u003ca href=\"https://github.com/eliaswendt/woxel\"\u003eGitHub Repository\u003c/a\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-software-stack\"\u003eThe Software Stack\u003c/h2\u003e\n\u003cp\u003eWith WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\u003c/p\u003e","title":"Building a Browser Voxel Engine in Rust \u0026 WebGPU"},{"content":"Abstract High-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\nLinks ACL Anthology Download PDF GitHub Repo Huggingface Repo 🤗 BibTeX 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @inproceedings{aliJudgingQualityLanguages2025b, title = {Judging {{Quality Across Languages}}: {{A Multilingual Approach}} to {{Pretraining Data Filtering}} with {{Language Models}}}, shorttitle = {Judging {{Quality Across Languages}}}, booktitle = {Proceedings of the 2025 {{Conference}} on {{Empirical Methods}} in {{Natural Language Processing}}}, author = {Ali, Mehdi and Brack, Manuel and L{\\\u0026#34;u}bbering, Max and Wendt, Elias and Khan, Abbas Goher and Rutmann, Richard and Jude, Alex and Kraus, Maurice and Weber, Alexander Arno and Stollenwerk, Felix and Kacz{\\\u0026#39;e}r, David and Mai, Florian and Flek, Lucie and Sifa, Rafet and {Flores-Herr}, Nicolas and Koehler, Joachim and Schramowski, Patrick and Fromm, Michael and Kersting, Kristian}, year = 2025, pages = {8870--8909}, publisher = {Association for Computational Linguistics}, address = {Suzhou, China}, doi = {10.18653/v1/2025.emnlp-main.449}, urldate = {2026-06-27}, langid = {english}, file = {/Users/me/Zotero/storage/5IE6855P/Ali et al. - 2025 - Judging Quality Across Languages A Multilingual Approach to Pretraining Data Filtering with Languag.pdf} } ","permalink":"http://localhost:1313/posts/publication-jql/","summary":"\u003ch2 id=\"abstract\"\u003eAbstract\u003c/h2\u003e\n\u003cp\u003eHigh-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\u003c/p\u003e","title":"Judging Quality Across Languages: A Multilingual Approach to Pretraining Data Filtering with Language Models"},{"content":"The core idea of Bayesian inference is updating an initial belief in light of new evidence.\nStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the prior distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the posterior $p(X|E)$:\n$$ \\underbrace{p(X|E)}_{\\text{posterior}} = \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}} = \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}} = \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]} $$ Prior $p(X)$: What we believe about $X$ (e.g. how it is distributed) before looking at the data Likelihood $p(E|X)$: If the hypothesis $X$ were true, how likely would the observed evidence $E$ be? Posterior $p(X|E)$: What we should believe about $X$ now that we have observed $E$. Marginal Likelihood (Evidence) $p(E)$: The total probability of observing the evidence across all possible states of $X$. Notice: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning: $$ \\text{Posterior} \\propto \\text{Likelihood} \\cdot \\text{Prior} $$ New beliefs are a direct compromise between what you previously thought (Prior) and what the data suggests (Likelihood).\nIterative Learning Bayesian updating is naturally sequential. Assuming independent observations given $X$, the current posterior $p(X|E)$ becomes the starting prior:\n$$ p(X | E_1, E_2) \\propto p(E_2 | X) \\cdot p(X | E_1) $$As you collect more evidence, the likelihood term begins to dominate, and the initial prior gradually washes out.\nExample: The Base Rate Fallacy Why can\u0026rsquo;t we just rely on the likelihood $p(E|X)$? Consider a rare disease:\nPrior: $1$ in $1{,}000$ people has the disease $\\rightarrow p(\\text{Disease}) = 0.001$. Likelihood (Accuracy): A test is $99$% accurate for sick people $\\rightarrow p(\\text{Positive} | \\text{Disease}) = 0.99$. False Positive Rate: The test gives a false positive $5$% of the time for healthy people $\\rightarrow p(\\text{Positive} | \\text{Healthy}) = 0.05$. If a patient tests positive ($E = \\text{Positive}$):\n$$ p(\\text{Disease} | \\text{Positive}) = \\frac{0.99 \\cdot 0.001}{(0.99 \\cdot 0.001) + (0.05 \\cdot 0.999)} \\approx \\frac{0.00099}{0.00099 + 0.04995} \\approx 1.94\\% $$Even with a $99$% accurate test, the probability of being sick is under $2$%. The massive pool of healthy people generates far more false alarms than genuine detections. The prior acts as an anchor that keeps rare events from being drastically overestimated.\n","permalink":"http://localhost:1313/posts/bayes-theorem/","summary":"\u003cp\u003eThe core idea of Bayesian inference is updating an initial belief in light of new evidence.\u003c/p\u003e\n\u003cp\u003eStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the \u003cstrong\u003eprior\u003c/strong\u003e distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the \u003cstrong\u003eposterior\u003c/strong\u003e $p(X|E)$:\u003c/p\u003e\n$$\n\\underbrace{p(X|E)}_{\\text{posterior}}\n= \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}}\n= \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}}\n= \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]}\n$$\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePrior $p(X)$:\u003c/strong\u003e What we believe about $X$ (e.g. how it is distributed) before looking at the data\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLikelihood $p(E|X)$:\u003c/strong\u003e If the hypothesis $X$ were true, how likely would the observed evidence $E$ be?\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePosterior $p(X|E)$:\u003c/strong\u003e What we should believe about $X$ now that we have observed $E$.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMarginal Likelihood (Evidence) $p(E)$:\u003c/strong\u003e The total probability of observing the evidence across \u003cem\u003eall\u003c/em\u003e possible states of $X$.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eNotice\u003c/strong\u003e: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning:\n\u003c/p\u003e","title":"Bayes' Theorem"},{"content":"","permalink":"http://localhost:1313/posts/invariant-mechanism-analysis/","summary":"","title":"Invariant Mechanism Analysis"},{"content":"Association vs. Causation Classical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: $$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$This objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$. From a probabilistic objective this is equivalent to optimizing: $$ \\arg \\max_\\theta p_\\theta (Y|X) $$However, not all association is causally grounded!\nExample do-Calculus Rule 1: Insertion/Deletion of Observations $P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\nRule 2: Action/Observation Exchange $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), z, w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\underline{Z}}$\nRule 3: Insertion/Deletion of Interventions $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\overline{Z(W)}}$\nCompeteness The do-calculus has been proven to be complete. This means that if it rules cannot translate the do-operator into pure probabilistic expressions, the causal effect is not identifiable.\nInstrumental Variables ","permalink":"http://localhost:1313/posts/causal-effect-estimation/","summary":"\u003ch2 id=\"association-vs-causation\"\u003eAssociation vs. Causation\u003c/h2\u003e\n\u003cp\u003eClassical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: \u003c/p\u003e\n$$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$\u003cp\u003eThis objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$.\nFrom a probabilistic objective this is equivalent to optimizing: \u003c/p\u003e\n$$ \\arg \\max_\\theta p_\\theta (Y|X) $$\u003cp\u003eHowever, not all association is causally grounded!\u003c/p\u003e\n\u003ch3 id=\"example\"\u003eExample\u003c/h3\u003e\n\u003ch2 id=\"do-calculus\"\u003edo-Calculus\u003c/h2\u003e\n\u003ch3 id=\"rule-1-insertiondeletion-of-observations\"\u003eRule 1: Insertion/Deletion of Observations\u003c/h3\u003e\n\u003cp\u003e$P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\u003c/p\u003e","title":"Causal Effect Estimation"},{"content":" Disclaimer: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\nLive Demo · GitHub Repository\nThe Software Stack With WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\nGraphics: wgpu (Targeting WebGPU via WebAssembly) Linear Algebra: glam GUI: egui Build Tooling: Trunk Blocks and Chunks At the core of any voxel engine lies a hierarchy: individual voxels aggregate into manageable spatial volumes called Chunks.\nA chunk is represented as a contiguous 3D array of Blocks. Storing millions of empty air voxels naively would quickly exhaust memory, especially within browser constraints. To mitigate this, chunks consisting solely of air are treated as uniform singletons and avoid individual heap allocations:\n#[derive(Copy, Clone, PartialEq, Eq)] pub enum BlockType { Air, Grass, Dirt, Stone, } pub struct Chunk { blocks: [BlockType; N_BLOCKS_PER_CHUNK], } View Distance \u0026amp; The Single-Thread Bottleneck In a traditional native engine, chunk generation and meshing are dispatched to background thread pools (e.g., via rayon). In a standard browser WASM environment, however, we are bound to the main UI and animation thread.\nIf a frame takes longer than 16.6 ms we fall under the holy 60 FPS mark. Because generating 3D Perlin/Simplex noise and extracting surface polygons (meshing) is computationally heavy, we cannot generate all chunks within the player\u0026rsquo;s view distance in a single frame.\nInstead, we need two things:\nPrioritization: Chunks closest to the player must generate first. Time-slicing (Amortization): Bound the number of chunks and meshes generated per frame cycle. 1. Precomputed Spherical Offsets Calculating Euclidean distances on every frame for dozens of surrounding chunk coordinates is wasteful. Since the relative geometric layout never changes, we can precompute the offset coordinates relative to $(0, 0, 0)$ once at startup and sort them spherically:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 fn generate_offsets_in_spherical_order(radius: isize) -\u0026gt; Vec\u0026lt;(ChunkCoord, usize)\u0026gt; { let mut offsets = Vec::new(); for x in 0..radius { for y in 0..radius { for z in 0..radius { let offset_x = x - radius / 2; let offset_y = y - radius / 2; let offset_z = z - radius / 2; // Euclidean distance relative to origin let dist = (offset_x.pow(2) + offset_y.pow(2) + offset_z.pow(2)).isqrt() as usize; offsets.push((ChunkCoord(offset_x, offset_y, offset_z), dist)); } } } // Sort ascending: closest chunks first offsets.sort_unstable_by_key(|(_, dist)| *dist); offsets } 2. The Frame Update Loop In each render tick, the engine slides its active chunk window based on the player\u0026rsquo;s movement, and then consumes a strictly defined compute budget of chunk and mesh builds:\n// Called once per frame pub fn update( \u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, max_chunk_budget: usize, max_mesh_budget: usize ) -\u0026gt; (usize, usize) { // 1. Shift the logical sliding window (O(1) index updates, practically free) self.slide_active_window(player_position); // 2. Process pending generation within budget let n_chunks = self.generate_pending_chunks(player_position, max_chunk_budget); let n_meshes = self.generate_pending_meshes(player_position, device, max_mesh_budget); (n_chunks, n_meshes) } Chunk Management: 3D Toroidal Buffering Rather than reallocating an entire 3D grid whenever the player crosses a chunk boundary, the engine uses a 3D Toroidal Ring Buffer (Sliding Window).\nBecause coordinates wrap around via modulo operations across all three axes, moving through the world requires zero data reallocations. When the player moves along an axis (say, $+X$), only the 2D plane on the opposite, trailing boundary ($-X$) is invalidated and marked for regeneration with the newly entered terrain.\n/// Update loaded chunks based on player movement. /// Only marks the \u0026#34;trailing\u0026#34; surface layer of chunks for clearance. fn slide_active_window(\u0026amp;mut self, new_player_coord: \u0026amp;ChunkCoord) { let deltas = [ new_player_coord.0 - self.previous_player_coord.0, new_player_coord.1 - self.previous_player_coord.1, new_player_coord.2 - self.previous_player_coord.2, ]; for (axis, \u0026amp;movement_delta) in deltas.iter().enumerate() { if movement_delta == 0 { continue; } let step = if movement_delta \u0026gt; 0 { 1 } else { -1 }; let mut working_base = self.previous_player_coord; // Process step-by-step to handle multi-chunk teleports/fast movement for _ in 0..movement_delta.abs() { let half = self.active_size[axis] as isize / 2; let plane_offset = -half * step; // Invalidate the 2D plane perpendicular to the movement direction for i in 0..self.active_size[(axis + 1) % 3] as isize { for j in 0..self.active_size[(axis + 2) % 3] as isize { let chunk_coord = match axis { 0 =\u0026gt; ChunkCoord(working_base.0 + plane_offset, working_base.1 + i - half, working_base.2 + j - half), 1 =\u0026gt; ChunkCoord(working_base.0 + j - half, working_base.1 + plane_offset, working_base.2 + i - half), _ =\u0026gt; ChunkCoord(working_base.0 + i - half, working_base.1 + j - half, working_base.2 + plane_offset), }; self.get_active_entry_mut(\u0026amp;chunk_coord).unset(); } } match axis { 0 =\u0026gt; working_base.0 += step, 1 =\u0026gt; working_base.1 += step, _ =\u0026gt; working_base.2 += step, } } } self.previous_player_coord = *new_player_coord; } Prioritized Chunk \u0026amp; Mesh Generation Generating a chunk is a two-step pipeline:\nVoxel Population: The 3D density noise generates raw voxel data. Mesh Extraction: Once a chunk and all its direct neighbors are populated, faces obscured by adjacent solid blocks are culled, and GPU vertex buffers are created and uploaded. Notice how whenever a non-empty chunk finishes loading, it flags its immediate neighbors (unset_mesh()): a border chunk cannot accurately cull its outer faces until adjacent blocks are known!\nfn generate_pending_chunks(\u0026amp;mut self, player_chunk_position: \u0026amp;ChunkCoord, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, distance) = self.offsets[i]; let chunk_coord = player_chunk_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).is_pending() { // Early out for chunks strictly above terrain generation limit if chunk_coord.1 \u0026lt;= -2 || chunk_coord.1 \u0026gt;= 14 { *self.get_active_entry_mut(\u0026amp;chunk_coord) = ActiveEntry::Empty { coord: chunk_coord }; continue; } let new_chunk = Chunk::new_populated(\u0026amp;self.density_generator, \u0026amp;chunk_coord); used_budget += 1; if new_chunk.is_empty() { self.get_active_entry_mut(\u0026amp;chunk_coord).set_empty(chunk_coord); } else { let required_lod = select_lod(distance); self.get_active_entry_mut(\u0026amp;chunk_coord).set_loaded(chunk_coord, new_chunk, required_lod); // Invalidate neighbor meshes to enforce seamless boundary culling for neighbor_coord in self.get_neighbor_chunk_coords(\u0026amp;chunk_coord) { self.get_active_entry_mut(\u0026amp;neighbor_coord).unset_mesh(); } } } } used_budget } fn generate_pending_meshes(\u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, _) = self.offsets[i]; let chunk_coord = player_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).needs_remesh() { let chunk_borders = self.get_chunk_borders(\u0026amp;chunk_coord); self.get_active_entry_mut(\u0026amp;chunk_coord).generate_and_upload_mesh(device, \u0026amp;chunk_borders); used_budget += 1; } } used_budget } What\u0026rsquo;s Next? While the engine runs at a solid 60 FPS under normal navigation, there are several exciting paths for future improvements:\nGreedy Meshing: Combining adjacent coplanar quad faces into single larger quads to drastically reduce vertex and index buffer sizes. Web Workers via SharedArrayBuffer: Offloading noise sampling to background Web Workers using Rust\u0026rsquo;s wasm-bindgen-rayon to make chunk generation truly asynchronous without stuttering the render thread. Persistent Browser Storage: Currently, all edits vanish on page refresh. The browser provides powerful mechanisms to persist modified worlds: OPFS (Origin Private File System): A modern, sandboxed filesystem API that allows fast, synchronous binary I/O from within Web Workers. It would enable Minecraft-style binary region files (.mca) running purely on the client. IndexedDB: An alternative key-value store to save compressed diffs of player-modified chunks without touching the pristine procedurally generated baseline. Floating Origin (Camera-Relative Rendering): While chunk coordinates can logically span a 32-bit integer space (billions of blocks), GPU rendering relies on 32-bit floating-point numbers (f32). At extreme coordinate distances, IEEE 754 floats lose precision, manifesting as severe vertex jitter, camera stutter, and depth-fighting artifacts (the classic \u0026ldquo;Far Lands\u0026rdquo; effect).\nAn architectural fix is a floating origin: instead of translating the camera through an ever-expanding global space, the camera is pinned statically at $(0, 0, 0)$. Chunks maintain their true logical world coordinates for generation and storage, but are indexed and pushed to the GPU transformed into local camera space. ","permalink":"http://localhost:1313/posts/voxel-engine/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eDisclaimer\u003c/strong\u003e: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ca href=\"https://eliaswendt.github.io/woxel\"\u003eLive Demo\u003c/a\u003e · \u003ca href=\"https://github.com/eliaswendt/woxel\"\u003eGitHub Repository\u003c/a\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-software-stack\"\u003eThe Software Stack\u003c/h2\u003e\n\u003cp\u003eWith WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\u003c/p\u003e","title":"Building a Browser Voxel Engine in Rust \u0026 WebGPU"},{"content":"Abstract High-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\nLinks ACL Anthology Download PDF GitHub Repo Huggingface Repo 🤗 BibTeX 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @inproceedings{aliJudgingQualityLanguages2025b, title = {Judging {{Quality Across Languages}}: {{A Multilingual Approach}} to {{Pretraining Data Filtering}} with {{Language Models}}}, shorttitle = {Judging {{Quality Across Languages}}}, booktitle = {Proceedings of the 2025 {{Conference}} on {{Empirical Methods}} in {{Natural Language Processing}}}, author = {Ali, Mehdi and Brack, Manuel and L{\\\u0026#34;u}bbering, Max and Wendt, Elias and Khan, Abbas Goher and Rutmann, Richard and Jude, Alex and Kraus, Maurice and Weber, Alexander Arno and Stollenwerk, Felix and Kacz{\\\u0026#39;e}r, David and Mai, Florian and Flek, Lucie and Sifa, Rafet and {Flores-Herr}, Nicolas and Koehler, Joachim and Schramowski, Patrick and Fromm, Michael and Kersting, Kristian}, year = 2025, pages = {8870--8909}, publisher = {Association for Computational Linguistics}, address = {Suzhou, China}, doi = {10.18653/v1/2025.emnlp-main.449}, urldate = {2026-06-27}, langid = {english}, file = {/Users/me/Zotero/storage/5IE6855P/Ali et al. - 2025 - Judging Quality Across Languages A Multilingual Approach to Pretraining Data Filtering with Languag.pdf} } ","permalink":"http://localhost:1313/posts/publication-jql/","summary":"\u003ch2 id=\"abstract\"\u003eAbstract\u003c/h2\u003e\n\u003cp\u003eHigh-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\u003c/p\u003e","title":"Judging Quality Across Languages: A Multilingual Approach to Pretraining Data Filtering with Language Models"},{"content":"The core idea of Bayesian inference is updating an initial belief in light of new evidence.\nStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the prior distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the posterior $p(X|E)$:\n$$ \\underbrace{p(X|E)}_{\\text{posterior}} = \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}} = \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}} = \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]} $$ Prior $p(X)$: What we believe about $X$ (e.g. how it is distributed) before looking at the data Likelihood $p(E|X)$: If the hypothesis $X$ were true, how likely would the observed evidence $E$ be? Posterior $p(X|E)$: What we should believe about $X$ now that we have observed $E$. Marginal Likelihood (Evidence) $p(E)$: The total probability of observing the evidence across all possible states of $X$. Notice: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning: $$ \\text{Posterior} \\propto \\text{Likelihood} \\cdot \\text{Prior} $$ New beliefs are a direct compromise between what you previously thought (Prior) and what the data suggests (Likelihood).\nIterative Learning Bayesian updating is naturally sequential. Assuming independent observations given $X$, the current posterior $p(X|E)$ becomes the starting prior:\n$$ p(X | E_1, E_2) \\propto p(E_2 | X) \\cdot p(X | E_1) $$As you collect more evidence, the likelihood term begins to dominate, and the initial prior gradually washes out.\nExample: The Base Rate Fallacy Why can\u0026rsquo;t we just rely on the likelihood $p(E|X)$? Consider a rare disease:\nPrior: $1$ in $1{,}000$ people has the disease $\\rightarrow p(\\text{Disease}) = 0.001$. Likelihood (Accuracy): A test is $99$% accurate for sick people $\\rightarrow p(\\text{Positive} | \\text{Disease}) = 0.99$. False Positive Rate: The test gives a false positive $5$% of the time for healthy people $\\rightarrow p(\\text{Positive} | \\text{Healthy}) = 0.05$. If a patient tests positive ($E = \\text{Positive}$):\n$$ p(\\text{Disease} | \\text{Positive}) = \\frac{0.99 \\cdot 0.001}{(0.99 \\cdot 0.001) + (0.05 \\cdot 0.999)} \\approx \\frac{0.00099}{0.00099 + 0.04995} \\approx 1.94\\% $$Even with a $99$% accurate test, the probability of being sick is under $2$%. The massive pool of healthy people generates far more false alarms than genuine detections. The prior acts as an anchor that keeps rare events from being drastically overestimated.\n","permalink":"http://localhost:1313/posts/bayes-theorem/","summary":"\u003cp\u003eThe core idea of Bayesian inference is updating an initial belief in light of new evidence.\u003c/p\u003e\n\u003cp\u003eStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the \u003cstrong\u003eprior\u003c/strong\u003e distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the \u003cstrong\u003eposterior\u003c/strong\u003e $p(X|E)$:\u003c/p\u003e\n$$\n\\underbrace{p(X|E)}_{\\text{posterior}}\n= \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}}\n= \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}}\n= \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]}\n$$\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePrior $p(X)$:\u003c/strong\u003e What we believe about $X$ (e.g. how it is distributed) before looking at the data\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLikelihood $p(E|X)$:\u003c/strong\u003e If the hypothesis $X$ were true, how likely would the observed evidence $E$ be?\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePosterior $p(X|E)$:\u003c/strong\u003e What we should believe about $X$ now that we have observed $E$.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMarginal Likelihood (Evidence) $p(E)$:\u003c/strong\u003e The total probability of observing the evidence across \u003cem\u003eall\u003c/em\u003e possible states of $X$.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eNotice\u003c/strong\u003e: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning:\n\u003c/p\u003e","title":"Bayes' Theorem"},{"content":"","permalink":"http://localhost:1313/posts/invariant-mechanism-analysis/","summary":"","title":"Invariant Mechanism Analysis"},{"content":"Association vs. Causation Classical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: $$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$This objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$. From a probabilistic objective this is equivalent to optimizing: $$ \\arg \\max_\\theta p_\\theta (Y|X) $$However, not all association is causally grounded!\nExample do-Calculus Rule 1: Insertion/Deletion of Observations $P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\nRule 2: Action/Observation Exchange $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), z, w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\underline{Z}}$\nRule 3: Insertion/Deletion of Interventions $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\overline{Z(W)}}$\nCompeteness The do-calculus has been proven to be complete. This means that if it rules cannot translate the do-operator into pure probabilistic expressions, the causal effect is not identifiable.\nInstrumental Variables ","permalink":"http://localhost:1313/posts/causal-effect-estimation/","summary":"\u003ch2 id=\"association-vs-causation\"\u003eAssociation vs. Causation\u003c/h2\u003e\n\u003cp\u003eClassical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: \u003c/p\u003e\n$$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$\u003cp\u003eThis objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$.\nFrom a probabilistic objective this is equivalent to optimizing: \u003c/p\u003e\n$$ \\arg \\max_\\theta p_\\theta (Y|X) $$\u003cp\u003eHowever, not all association is causally grounded!\u003c/p\u003e\n\u003ch3 id=\"example\"\u003eExample\u003c/h3\u003e\n\u003ch2 id=\"do-calculus\"\u003edo-Calculus\u003c/h2\u003e\n\u003ch3 id=\"rule-1-insertiondeletion-of-observations\"\u003eRule 1: Insertion/Deletion of Observations\u003c/h3\u003e\n\u003cp\u003e$P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\u003c/p\u003e","title":"Causal Effect Estimation"},{"content":" Disclaimer: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\nLive Demo · GitHub Repository\nThe Software Stack With WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\nGraphics: wgpu (Targeting WebGPU via WebAssembly) Linear Algebra: glam GUI: egui Build Tooling: Trunk Blocks and Chunks At the core of any voxel engine lies a hierarchy: individual voxels aggregate into manageable spatial volumes called Chunks.\nA chunk is represented as a contiguous 3D array of Blocks. Storing millions of empty air voxels naively would quickly exhaust memory, especially within browser constraints. To mitigate this, chunks consisting solely of air are treated as uniform singletons and avoid individual heap allocations:\n#[derive(Copy, Clone, PartialEq, Eq)] pub enum BlockType { Air, Grass, Dirt, Stone, } pub struct Chunk { blocks: [BlockType; N_BLOCKS_PER_CHUNK], } View Distance \u0026amp; The Single-Thread Bottleneck In a traditional native engine, chunk generation and meshing are dispatched to background thread pools (e.g., via rayon). In a standard browser WASM environment, however, we are bound to the main UI and animation thread.\nIf a frame takes longer than 16.6 ms we fall under the holy 60 FPS mark. Because generating 3D Perlin/Simplex noise and extracting surface polygons (meshing) is computationally heavy, we cannot generate all chunks within the player\u0026rsquo;s view distance in a single frame.\nInstead, we need two things:\nPrioritization: Chunks closest to the player must generate first. Time-slicing (Amortization): Bound the number of chunks and meshes generated per frame cycle. 1. Precomputed Spherical Offsets Calculating Euclidean distances on every frame for dozens of surrounding chunk coordinates is wasteful. Since the relative geometric layout never changes, we can precompute the offset coordinates relative to $(0, 0, 0)$ once at startup and sort them spherically:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 fn generate_offsets_in_spherical_order(radius: isize) -\u0026gt; Vec\u0026lt;(ChunkCoord, usize)\u0026gt; { let mut offsets = Vec::new(); for x in 0..radius { for y in 0..radius { for z in 0..radius { let offset_x = x - radius / 2; let offset_y = y - radius / 2; let offset_z = z - radius / 2; // Euclidean distance relative to origin let dist = (offset_x.pow(2) + offset_y.pow(2) + offset_z.pow(2)).isqrt() as usize; offsets.push((ChunkCoord(offset_x, offset_y, offset_z), dist)); } } } // Sort ascending: closest chunks first offsets.sort_unstable_by_key(|(_, dist)| *dist); offsets } 2. The Frame Update Loop In each render tick, the engine slides its active chunk window based on the player\u0026rsquo;s movement, and then consumes a strictly defined compute budget of chunk and mesh builds:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Called once per frame pub fn update( \u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, max_chunk_budget: usize, max_mesh_budget: usize ) -\u0026gt; (usize, usize) { // 1. Shift the logical sliding window (O(1) index updates, practically free) self.slide_active_window(player_position); // 2. Process pending generation within budget let n_chunks = self.generate_pending_chunks(player_position, max_chunk_budget); let n_meshes = self.generate_pending_meshes(player_position, device, max_mesh_budget); (n_chunks, n_meshes) } Chunk Management: 3D Toroidal Buffering Rather than reallocating an entire 3D grid whenever the player crosses a chunk boundary, the engine uses a 3D Toroidal Ring Buffer (Sliding Window).\nBecause coordinates wrap around via modulo operations across all three axes, moving through the world requires zero data reallocations. When the player moves along an axis (say, $+X$), only the 2D plane on the opposite, trailing boundary ($-X$) is invalidated and marked for regeneration with the newly entered terrain.\n/// Update loaded chunks based on player movement. /// Only marks the \u0026#34;trailing\u0026#34; surface layer of chunks for clearance. fn slide_active_window(\u0026amp;mut self, new_player_coord: \u0026amp;ChunkCoord) { let deltas = [ new_player_coord.0 - self.previous_player_coord.0, new_player_coord.1 - self.previous_player_coord.1, new_player_coord.2 - self.previous_player_coord.2, ]; for (axis, \u0026amp;movement_delta) in deltas.iter().enumerate() { if movement_delta == 0 { continue; } let step = if movement_delta \u0026gt; 0 { 1 } else { -1 }; let mut working_base = self.previous_player_coord; // Process step-by-step to handle multi-chunk teleports/fast movement for _ in 0..movement_delta.abs() { let half = self.active_size[axis] as isize / 2; let plane_offset = -half * step; // Invalidate the 2D plane perpendicular to the movement direction for i in 0..self.active_size[(axis + 1) % 3] as isize { for j in 0..self.active_size[(axis + 2) % 3] as isize { let chunk_coord = match axis { 0 =\u0026gt; ChunkCoord(working_base.0 + plane_offset, working_base.1 + i - half, working_base.2 + j - half), 1 =\u0026gt; ChunkCoord(working_base.0 + j - half, working_base.1 + plane_offset, working_base.2 + i - half), _ =\u0026gt; ChunkCoord(working_base.0 + i - half, working_base.1 + j - half, working_base.2 + plane_offset), }; self.get_active_entry_mut(\u0026amp;chunk_coord).unset(); } } match axis { 0 =\u0026gt; working_base.0 += step, 1 =\u0026gt; working_base.1 += step, _ =\u0026gt; working_base.2 += step, } } } self.previous_player_coord = *new_player_coord; } Prioritized Chunk \u0026amp; Mesh Generation Generating a chunk is a two-step pipeline:\nVoxel Population: The 3D density noise generates raw voxel data. Mesh Extraction: Once a chunk and all its direct neighbors are populated, faces obscured by adjacent solid blocks are culled, and GPU vertex buffers are created and uploaded. Notice how whenever a non-empty chunk finishes loading, it flags its immediate neighbors (unset_mesh()): a border chunk cannot accurately cull its outer faces until adjacent blocks are known!\nfn generate_pending_chunks(\u0026amp;mut self, player_chunk_position: \u0026amp;ChunkCoord, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, distance) = self.offsets[i]; let chunk_coord = player_chunk_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).is_pending() { // Early out for chunks strictly above terrain generation limit if chunk_coord.1 \u0026lt;= -2 || chunk_coord.1 \u0026gt;= 14 { *self.get_active_entry_mut(\u0026amp;chunk_coord) = ActiveEntry::Empty { coord: chunk_coord }; continue; } let new_chunk = Chunk::new_populated(\u0026amp;self.density_generator, \u0026amp;chunk_coord); used_budget += 1; if new_chunk.is_empty() { self.get_active_entry_mut(\u0026amp;chunk_coord).set_empty(chunk_coord); } else { let required_lod = select_lod(distance); self.get_active_entry_mut(\u0026amp;chunk_coord).set_loaded(chunk_coord, new_chunk, required_lod); // Invalidate neighbor meshes to enforce seamless boundary culling for neighbor_coord in self.get_neighbor_chunk_coords(\u0026amp;chunk_coord) { self.get_active_entry_mut(\u0026amp;neighbor_coord).unset_mesh(); } } } } used_budget } fn generate_pending_meshes(\u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, _) = self.offsets[i]; let chunk_coord = player_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).needs_remesh() { let chunk_borders = self.get_chunk_borders(\u0026amp;chunk_coord); self.get_active_entry_mut(\u0026amp;chunk_coord).generate_and_upload_mesh(device, \u0026amp;chunk_borders); used_budget += 1; } } used_budget } What\u0026rsquo;s Next? While the engine runs at a solid 60 FPS under normal navigation, there are several exciting paths for future improvements:\nGreedy Meshing: Combining adjacent coplanar quad faces into single larger quads to drastically reduce vertex and index buffer sizes. Web Workers via SharedArrayBuffer: Offloading noise sampling to background Web Workers using Rust\u0026rsquo;s wasm-bindgen-rayon to make chunk generation truly asynchronous without stuttering the render thread. Persistent Browser Storage: Currently, all edits vanish on page refresh. The browser provides powerful mechanisms to persist modified worlds: OPFS (Origin Private File System): A modern, sandboxed filesystem API that allows fast, synchronous binary I/O from within Web Workers. It would enable Minecraft-style binary region files (.mca) running purely on the client. IndexedDB: An alternative key-value store to save compressed diffs of player-modified chunks without touching the pristine procedurally generated baseline. Floating Origin (Camera-Relative Rendering): While chunk coordinates can logically span a 32-bit integer space (billions of blocks), GPU rendering relies on 32-bit floating-point numbers (f32). At extreme coordinate distances, IEEE 754 floats lose precision, manifesting as severe vertex jitter, camera stutter, and depth-fighting artifacts (the classic \u0026ldquo;Far Lands\u0026rdquo; effect).\nAn architectural fix is a floating origin: instead of translating the camera through an ever-expanding global space, the camera is pinned statically at $(0, 0, 0)$. Chunks maintain their true logical world coordinates for generation and storage, but are indexed and pushed to the GPU transformed into local camera space. ","permalink":"http://localhost:1313/posts/voxel-engine/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eDisclaimer\u003c/strong\u003e: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ca href=\"https://eliaswendt.github.io/woxel\"\u003eLive Demo\u003c/a\u003e · \u003ca href=\"https://github.com/eliaswendt/woxel\"\u003eGitHub Repository\u003c/a\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-software-stack\"\u003eThe Software Stack\u003c/h2\u003e\n\u003cp\u003eWith WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\u003c/p\u003e","title":"Building a Browser Voxel Engine in Rust \u0026 WebGPU"},{"content":"Abstract High-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\nLinks ACL Anthology Download PDF GitHub Repo Huggingface Repo 🤗 BibTeX 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @inproceedings{aliJudgingQualityLanguages2025b, title = {Judging {{Quality Across Languages}}: {{A Multilingual Approach}} to {{Pretraining Data Filtering}} with {{Language Models}}}, shorttitle = {Judging {{Quality Across Languages}}}, booktitle = {Proceedings of the 2025 {{Conference}} on {{Empirical Methods}} in {{Natural Language Processing}}}, author = {Ali, Mehdi and Brack, Manuel and L{\\\u0026#34;u}bbering, Max and Wendt, Elias and Khan, Abbas Goher and Rutmann, Richard and Jude, Alex and Kraus, Maurice and Weber, Alexander Arno and Stollenwerk, Felix and Kacz{\\\u0026#39;e}r, David and Mai, Florian and Flek, Lucie and Sifa, Rafet and {Flores-Herr}, Nicolas and Koehler, Joachim and Schramowski, Patrick and Fromm, Michael and Kersting, Kristian}, year = 2025, pages = {8870--8909}, publisher = {Association for Computational Linguistics}, address = {Suzhou, China}, doi = {10.18653/v1/2025.emnlp-main.449}, urldate = {2026-06-27}, langid = {english}, file = {/Users/me/Zotero/storage/5IE6855P/Ali et al. - 2025 - Judging Quality Across Languages A Multilingual Approach to Pretraining Data Filtering with Languag.pdf} } ","permalink":"http://localhost:1313/posts/publication-jql/","summary":"\u003ch2 id=\"abstract\"\u003eAbstract\u003c/h2\u003e\n\u003cp\u003eHigh-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\u003c/p\u003e","title":"Judging Quality Across Languages: A Multilingual Approach to Pretraining Data Filtering with Language Models"},{"content":"The core idea of Bayesian inference is updating an initial belief in light of new evidence.\nStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the prior distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the posterior $p(X|E)$:\n$$ \\underbrace{p(X|E)}_{\\text{posterior}} = \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}} = \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}} = \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]} $$ Prior $p(X)$: What we believe about $X$ (e.g. how it is distributed) before looking at the data Likelihood $p(E|X)$: If the hypothesis $X$ were true, how likely would the observed evidence $E$ be? Posterior $p(X|E)$: What we should believe about $X$ now that we have observed $E$. Marginal Likelihood (Evidence) $p(E)$: The total probability of observing the evidence across all possible states of $X$. Notice: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning: $$ \\text{Posterior} \\propto \\text{Likelihood} \\cdot \\text{Prior} $$ New beliefs are a direct compromise between what you previously thought (Prior) and what the data suggests (Likelihood).\nIterative Learning Bayesian updating is naturally sequential. Assuming independent observations given $X$, the current posterior $p(X|E)$ becomes the starting prior:\n$$ p(X | E_1, E_2) \\propto p(E_2 | X) \\cdot p(X | E_1) $$As you collect more evidence, the likelihood term begins to dominate, and the initial prior gradually washes out.\nExample: The Base Rate Fallacy Why can\u0026rsquo;t we just rely on the likelihood $p(E|X)$? Consider a rare disease:\nPrior: $1$ in $1{,}000$ people has the disease $\\rightarrow p(\\text{Disease}) = 0.001$. Likelihood (Accuracy): A test is $99$% accurate for sick people $\\rightarrow p(\\text{Positive} | \\text{Disease}) = 0.99$. False Positive Rate: The test gives a false positive $5$% of the time for healthy people $\\rightarrow p(\\text{Positive} | \\text{Healthy}) = 0.05$. If a patient tests positive ($E = \\text{Positive}$):\n$$ p(\\text{Disease} | \\text{Positive}) = \\frac{0.99 \\cdot 0.001}{(0.99 \\cdot 0.001) + (0.05 \\cdot 0.999)} \\approx \\frac{0.00099}{0.00099 + 0.04995} \\approx 1.94\\% $$Even with a $99$% accurate test, the probability of being sick is under $2$%. The massive pool of healthy people generates far more false alarms than genuine detections. The prior acts as an anchor that keeps rare events from being drastically overestimated.\n","permalink":"http://localhost:1313/posts/bayes-theorem/","summary":"\u003cp\u003eThe core idea of Bayesian inference is updating an initial belief in light of new evidence.\u003c/p\u003e\n\u003cp\u003eStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the \u003cstrong\u003eprior\u003c/strong\u003e distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the \u003cstrong\u003eposterior\u003c/strong\u003e $p(X|E)$:\u003c/p\u003e\n$$\n\\underbrace{p(X|E)}_{\\text{posterior}}\n= \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}}\n= \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}}\n= \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]}\n$$\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePrior $p(X)$:\u003c/strong\u003e What we believe about $X$ (e.g. how it is distributed) before looking at the data\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLikelihood $p(E|X)$:\u003c/strong\u003e If the hypothesis $X$ were true, how likely would the observed evidence $E$ be?\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePosterior $p(X|E)$:\u003c/strong\u003e What we should believe about $X$ now that we have observed $E$.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMarginal Likelihood (Evidence) $p(E)$:\u003c/strong\u003e The total probability of observing the evidence across \u003cem\u003eall\u003c/em\u003e possible states of $X$.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eNotice\u003c/strong\u003e: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning:\n\u003c/p\u003e","title":"Bayes' Theorem"},{"content":"","permalink":"http://localhost:1313/posts/invariant-mechanism-analysis/","summary":"","title":"Invariant Mechanism Analysis"},{"content":"Association vs. Causation Classical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: $$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$This objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$. From a probabilistic objective this is equivalent to optimizing: $$ \\arg \\max_\\theta p_\\theta (Y|X) $$However, not all association is causally grounded!\nExample do-Calculus Rule 1: Insertion/Deletion of Observations $P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\nRule 2: Action/Observation Exchange $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), z, w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\underline{Z}}$\nRule 3: Insertion/Deletion of Interventions $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\overline{Z(W)}}$\nCompeteness The do-calculus has been proven to be complete. This means that if it rules cannot translate the do-operator into pure probabilistic expressions, the causal effect is not identifiable.\nInstrumental Variables ","permalink":"http://localhost:1313/posts/causal-effect-estimation/","summary":"\u003ch2 id=\"association-vs-causation\"\u003eAssociation vs. Causation\u003c/h2\u003e\n\u003cp\u003eClassical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: \u003c/p\u003e\n$$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$\u003cp\u003eThis objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$.\nFrom a probabilistic objective this is equivalent to optimizing: \u003c/p\u003e\n$$ \\arg \\max_\\theta p_\\theta (Y|X) $$\u003cp\u003eHowever, not all association is causally grounded!\u003c/p\u003e\n\u003ch3 id=\"example\"\u003eExample\u003c/h3\u003e\n\u003ch2 id=\"do-calculus\"\u003edo-Calculus\u003c/h2\u003e\n\u003ch3 id=\"rule-1-insertiondeletion-of-observations\"\u003eRule 1: Insertion/Deletion of Observations\u003c/h3\u003e\n\u003cp\u003e$P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\u003c/p\u003e","title":"Causal Effect Estimation"},{"content":" Disclaimer: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\nLive Demo · GitHub Repository\nThe Software Stack With WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\nGraphics: wgpu (Targeting WebGPU via WebAssembly) Linear Algebra: glam GUI: egui Build Tooling: Trunk Blocks and Chunks At the core of any voxel engine lies a hierarchy: individual voxels aggregate into manageable spatial volumes called Chunks.\nA chunk is represented as a contiguous 3D array of Blocks. Storing millions of empty air voxels naively would quickly exhaust memory, especially within browser constraints. To mitigate this, chunks consisting solely of air are treated as uniform singletons and avoid individual heap allocations:\n#[derive(Copy, Clone, PartialEq, Eq)] pub enum BlockType { Air, Grass, Dirt, Stone, } pub struct Chunk { blocks: [BlockType; N_BLOCKS_PER_CHUNK], } View Distance \u0026amp; The Single-Thread Bottleneck In a traditional native engine, chunk generation and meshing are dispatched to background thread pools (e.g., via rayon). In a standard browser WASM environment, however, we are bound to the main UI and animation thread.\nIf a frame takes longer than 16.6 ms we fall under the holy 60 FPS mark. Because generating 3D Perlin/Simplex noise and extracting surface polygons (meshing) is computationally heavy, we cannot generate all chunks within the player\u0026rsquo;s view distance in a single frame.\nInstead, we need two things:\nPrioritization: Chunks closest to the player must generate first. Time-slicing (Amortization): Bound the number of chunks and meshes generated per frame cycle. 1. Precomputed Spherical Offsets Calculating Euclidean distances on every frame for dozens of surrounding chunk coordinates is wasteful. Since the relative geometric layout never changes, we can precompute the offset coordinates relative to $(0, 0, 0)$ once at startup and sort them spherically:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 fn generate_offsets_in_spherical_order(radius: isize) -\u0026gt; Vec\u0026lt;(ChunkCoord, usize)\u0026gt; { let mut offsets = Vec::new(); for x in 0..radius { for y in 0..radius { for z in 0..radius { let offset_x = x - radius / 2; let offset_y = y - radius / 2; let offset_z = z - radius / 2; // Euclidean distance relative to origin let dist = (offset_x.pow(2) + offset_y.pow(2) + offset_z.pow(2)).isqrt() as usize; offsets.push((ChunkCoord(offset_x, offset_y, offset_z), dist)); } } } // Sort ascending: closest chunks first offsets.sort_unstable_by_key(|(_, dist)| *dist); offsets } 2. The Frame Update Loop In each render tick, the engine slides its active chunk window based on the player\u0026rsquo;s movement, and then consumes a strictly defined compute budget of chunk and mesh builds:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Called once per frame pub fn update( \u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, max_chunk_budget: usize, max_mesh_budget: usize ) -\u0026gt; (usize, usize) { // 1. Shift the logical sliding window (O(1) index updates, practically free) self.slide_active_window(player_position); // 2. Process pending generation within budget let n_chunks = self.generate_pending_chunks(player_position, max_chunk_budget); let n_meshes = self.generate_pending_meshes(player_position, device, max_mesh_budget); (n_chunks, n_meshes) } Chunk Management: 3D Toroidal Buffering Rather than reallocating an entire 3D grid whenever the player crosses a chunk boundary, the engine uses a 3D Toroidal Ring Buffer (Sliding Window).\nBecause coordinates wrap around via modulo operations across all three axes, moving through the world requires zero data reallocations. When the player moves along an axis (say, $+X$), only the 2D plane on the opposite, trailing boundary ($-X$) is invalidated and marked for regeneration with the newly entered terrain.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 /// Update loaded chunks based on player movement. /// Only marks the \u0026#34;trailing\u0026#34; surface layer of chunks for clearance. fn slide_active_window(\u0026amp;mut self, new_player_coord: \u0026amp;ChunkCoord) { let deltas = [ new_player_coord.0 - self.previous_player_coord.0, new_player_coord.1 - self.previous_player_coord.1, new_player_coord.2 - self.previous_player_coord.2, ]; for (axis, \u0026amp;movement_delta) in deltas.iter().enumerate() { if movement_delta == 0 { continue; } let step = if movement_delta \u0026gt; 0 { 1 } else { -1 }; let mut working_base = self.previous_player_coord; // Process step-by-step to handle multi-chunk teleports/fast movement for _ in 0..movement_delta.abs() { let half = self.active_size[axis] as isize / 2; let plane_offset = -half * step; // Invalidate the 2D plane perpendicular to the movement direction for i in 0..self.active_size[(axis + 1) % 3] as isize { for j in 0..self.active_size[(axis + 2) % 3] as isize { let chunk_coord = match axis { 0 =\u0026gt; ChunkCoord(working_base.0 + plane_offset, working_base.1 + i - half, working_base.2 + j - half), 1 =\u0026gt; ChunkCoord(working_base.0 + j - half, working_base.1 + plane_offset, working_base.2 + i - half), _ =\u0026gt; ChunkCoord(working_base.0 + i - half, working_base.1 + j - half, working_base.2 + plane_offset), }; self.get_active_entry_mut(\u0026amp;chunk_coord).unset(); } } match axis { 0 =\u0026gt; working_base.0 += step, 1 =\u0026gt; working_base.1 += step, _ =\u0026gt; working_base.2 += step, } } } self.previous_player_coord = *new_player_coord; } Prioritized Chunk \u0026amp; Mesh Generation Generating a chunk is a two-step pipeline:\nVoxel Population: The 3D density noise generates raw voxel data. Mesh Extraction: Once a chunk and all its direct neighbors are populated, faces obscured by adjacent solid blocks are culled, and GPU vertex buffers are created and uploaded. Notice how whenever a non-empty chunk finishes loading, it flags its immediate neighbors (unset_mesh()): a border chunk cannot accurately cull its outer faces until adjacent blocks are known!\nfn generate_pending_chunks(\u0026amp;mut self, player_chunk_position: \u0026amp;ChunkCoord, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, distance) = self.offsets[i]; let chunk_coord = player_chunk_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).is_pending() { // Early out for chunks strictly above terrain generation limit if chunk_coord.1 \u0026lt;= -2 || chunk_coord.1 \u0026gt;= 14 { *self.get_active_entry_mut(\u0026amp;chunk_coord) = ActiveEntry::Empty { coord: chunk_coord }; continue; } let new_chunk = Chunk::new_populated(\u0026amp;self.density_generator, \u0026amp;chunk_coord); used_budget += 1; if new_chunk.is_empty() { self.get_active_entry_mut(\u0026amp;chunk_coord).set_empty(chunk_coord); } else { let required_lod = select_lod(distance); self.get_active_entry_mut(\u0026amp;chunk_coord).set_loaded(chunk_coord, new_chunk, required_lod); // Invalidate neighbor meshes to enforce seamless boundary culling for neighbor_coord in self.get_neighbor_chunk_coords(\u0026amp;chunk_coord) { self.get_active_entry_mut(\u0026amp;neighbor_coord).unset_mesh(); } } } } used_budget } fn generate_pending_meshes(\u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, _) = self.offsets[i]; let chunk_coord = player_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).needs_remesh() { let chunk_borders = self.get_chunk_borders(\u0026amp;chunk_coord); self.get_active_entry_mut(\u0026amp;chunk_coord).generate_and_upload_mesh(device, \u0026amp;chunk_borders); used_budget += 1; } } used_budget } What\u0026rsquo;s Next? While the engine runs at a solid 60 FPS under normal navigation, there are several exciting paths for future improvements:\nGreedy Meshing: Combining adjacent coplanar quad faces into single larger quads to drastically reduce vertex and index buffer sizes. Web Workers via SharedArrayBuffer: Offloading noise sampling to background Web Workers using Rust\u0026rsquo;s wasm-bindgen-rayon to make chunk generation truly asynchronous without stuttering the render thread. Persistent Browser Storage: Currently, all edits vanish on page refresh. The browser provides powerful mechanisms to persist modified worlds: OPFS (Origin Private File System): A modern, sandboxed filesystem API that allows fast, synchronous binary I/O from within Web Workers. It would enable Minecraft-style binary region files (.mca) running purely on the client. IndexedDB: An alternative key-value store to save compressed diffs of player-modified chunks without touching the pristine procedurally generated baseline. Floating Origin (Camera-Relative Rendering): While chunk coordinates can logically span a 32-bit integer space (billions of blocks), GPU rendering relies on 32-bit floating-point numbers (f32). At extreme coordinate distances, IEEE 754 floats lose precision, manifesting as severe vertex jitter, camera stutter, and depth-fighting artifacts (the classic \u0026ldquo;Far Lands\u0026rdquo; effect).\nAn architectural fix is a floating origin: instead of translating the camera through an ever-expanding global space, the camera is pinned statically at $(0, 0, 0)$. Chunks maintain their true logical world coordinates for generation and storage, but are indexed and pushed to the GPU transformed into local camera space. ","permalink":"http://localhost:1313/posts/voxel-engine/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eDisclaimer\u003c/strong\u003e: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ca href=\"https://eliaswendt.github.io/woxel\"\u003eLive Demo\u003c/a\u003e · \u003ca href=\"https://github.com/eliaswendt/woxel\"\u003eGitHub Repository\u003c/a\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-software-stack\"\u003eThe Software Stack\u003c/h2\u003e\n\u003cp\u003eWith WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\u003c/p\u003e","title":"Building a Browser Voxel Engine in Rust \u0026 WebGPU"},{"content":"Abstract High-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\nLinks ACL Anthology Download PDF GitHub Repo Huggingface Repo 🤗 BibTeX 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @inproceedings{aliJudgingQualityLanguages2025b, title = {Judging {{Quality Across Languages}}: {{A Multilingual Approach}} to {{Pretraining Data Filtering}} with {{Language Models}}}, shorttitle = {Judging {{Quality Across Languages}}}, booktitle = {Proceedings of the 2025 {{Conference}} on {{Empirical Methods}} in {{Natural Language Processing}}}, author = {Ali, Mehdi and Brack, Manuel and L{\\\u0026#34;u}bbering, Max and Wendt, Elias and Khan, Abbas Goher and Rutmann, Richard and Jude, Alex and Kraus, Maurice and Weber, Alexander Arno and Stollenwerk, Felix and Kacz{\\\u0026#39;e}r, David and Mai, Florian and Flek, Lucie and Sifa, Rafet and {Flores-Herr}, Nicolas and Koehler, Joachim and Schramowski, Patrick and Fromm, Michael and Kersting, Kristian}, year = 2025, pages = {8870--8909}, publisher = {Association for Computational Linguistics}, address = {Suzhou, China}, doi = {10.18653/v1/2025.emnlp-main.449}, urldate = {2026-06-27}, langid = {english}, file = {/Users/me/Zotero/storage/5IE6855P/Ali et al. - 2025 - Judging Quality Across Languages A Multilingual Approach to Pretraining Data Filtering with Languag.pdf} } ","permalink":"http://localhost:1313/posts/publication-jql/","summary":"\u003ch2 id=\"abstract\"\u003eAbstract\u003c/h2\u003e\n\u003cp\u003eHigh-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\u003c/p\u003e","title":"Judging Quality Across Languages: A Multilingual Approach to Pretraining Data Filtering with Language Models"},{"content":"The core idea of Bayesian inference is updating an initial belief in light of new evidence.\nStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the prior distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the posterior $p(X|E)$:\n$$ \\underbrace{p(X|E)}_{\\text{posterior}} = \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}} = \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}} = \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]} $$ Prior $p(X)$: What we believe about $X$ (e.g. how it is distributed) before looking at the data Likelihood $p(E|X)$: If the hypothesis $X$ were true, how likely would the observed evidence $E$ be? Posterior $p(X|E)$: What we should believe about $X$ now that we have observed $E$. Marginal Likelihood (Evidence) $p(E)$: The total probability of observing the evidence across all possible states of $X$. Notice: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning: $$ \\text{Posterior} \\propto \\text{Likelihood} \\cdot \\text{Prior} $$ New beliefs are a direct compromise between what you previously thought (Prior) and what the data suggests (Likelihood).\nIterative Learning Bayesian updating is naturally sequential. Assuming independent observations given $X$, the current posterior $p(X|E)$ becomes the starting prior:\n$$ p(X | E_1, E_2) \\propto p(E_2 | X) \\cdot p(X | E_1) $$As you collect more evidence, the likelihood term begins to dominate, and the initial prior gradually washes out.\nExample: The Base Rate Fallacy Why can\u0026rsquo;t we just rely on the likelihood $p(E|X)$? Consider a rare disease:\nPrior: $1$ in $1{,}000$ people has the disease $\\rightarrow p(\\text{Disease}) = 0.001$. Likelihood (Accuracy): A test is $99$% accurate for sick people $\\rightarrow p(\\text{Positive} | \\text{Disease}) = 0.99$. False Positive Rate: The test gives a false positive $5$% of the time for healthy people $\\rightarrow p(\\text{Positive} | \\text{Healthy}) = 0.05$. If a patient tests positive ($E = \\text{Positive}$):\n$$ p(\\text{Disease} | \\text{Positive}) = \\frac{0.99 \\cdot 0.001}{(0.99 \\cdot 0.001) + (0.05 \\cdot 0.999)} \\approx \\frac{0.00099}{0.00099 + 0.04995} \\approx 1.94\\% $$Even with a $99$% accurate test, the probability of being sick is under $2$%. The massive pool of healthy people generates far more false alarms than genuine detections. The prior acts as an anchor that keeps rare events from being drastically overestimated.\n","permalink":"http://localhost:1313/posts/bayes-theorem/","summary":"\u003cp\u003eThe core idea of Bayesian inference is updating an initial belief in light of new evidence.\u003c/p\u003e\n\u003cp\u003eStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the \u003cstrong\u003eprior\u003c/strong\u003e distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the \u003cstrong\u003eposterior\u003c/strong\u003e $p(X|E)$:\u003c/p\u003e\n$$\n\\underbrace{p(X|E)}_{\\text{posterior}}\n= \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}}\n= \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}}\n= \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]}\n$$\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePrior $p(X)$:\u003c/strong\u003e What we believe about $X$ (e.g. how it is distributed) before looking at the data\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLikelihood $p(E|X)$:\u003c/strong\u003e If the hypothesis $X$ were true, how likely would the observed evidence $E$ be?\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePosterior $p(X|E)$:\u003c/strong\u003e What we should believe about $X$ now that we have observed $E$.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMarginal Likelihood (Evidence) $p(E)$:\u003c/strong\u003e The total probability of observing the evidence across \u003cem\u003eall\u003c/em\u003e possible states of $X$.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eNotice\u003c/strong\u003e: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning:\n\u003c/p\u003e","title":"Bayes' Theorem"},{"content":"","permalink":"http://localhost:1313/posts/invariant-mechanism-analysis/","summary":"","title":"Invariant Mechanism Analysis"},{"content":"Association vs. Causation Classical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: $$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$This objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$. From a probabilistic objective this is equivalent to optimizing: $$ \\arg \\max_\\theta p_\\theta (Y|X) $$However, not all association is causally grounded!\nExample do-Calculus Rule 1: Insertion/Deletion of Observations $P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\nRule 2: Action/Observation Exchange $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), z, w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\underline{Z}}$\nRule 3: Insertion/Deletion of Interventions $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\overline{Z(W)}}$\nCompeteness The do-calculus has been proven to be complete. This means that if it rules cannot translate the do-operator into pure probabilistic expressions, the causal effect is not identifiable.\nInstrumental Variables ","permalink":"http://localhost:1313/posts/causal-effect-estimation/","summary":"\u003ch2 id=\"association-vs-causation\"\u003eAssociation vs. Causation\u003c/h2\u003e\n\u003cp\u003eClassical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: \u003c/p\u003e\n$$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$\u003cp\u003eThis objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$.\nFrom a probabilistic objective this is equivalent to optimizing: \u003c/p\u003e\n$$ \\arg \\max_\\theta p_\\theta (Y|X) $$\u003cp\u003eHowever, not all association is causally grounded!\u003c/p\u003e\n\u003ch3 id=\"example\"\u003eExample\u003c/h3\u003e\n\u003ch2 id=\"do-calculus\"\u003edo-Calculus\u003c/h2\u003e\n\u003ch3 id=\"rule-1-insertiondeletion-of-observations\"\u003eRule 1: Insertion/Deletion of Observations\u003c/h3\u003e\n\u003cp\u003e$P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\u003c/p\u003e","title":"Causal Effect Estimation"},{"content":" Disclaimer: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\nLive Demo · GitHub Repository\nThe Software Stack With WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\nGraphics: wgpu (Targeting WebGPU via WebAssembly) Linear Algebra: glam GUI: egui Build Tooling: Trunk Blocks and Chunks At the core of any voxel engine lies a hierarchy: individual voxels aggregate into manageable spatial volumes called Chunks.\nA chunk is represented as a contiguous 3D array of Blocks. Storing millions of empty air voxels naively would quickly exhaust memory, especially within browser constraints. To mitigate this, chunks consisting solely of air are treated as uniform singletons and avoid individual heap allocations:\n#[derive(Copy, Clone, PartialEq, Eq)] pub enum BlockType { Air, Grass, Dirt, Stone, } pub struct Chunk { blocks: [BlockType; N_BLOCKS_PER_CHUNK], } View Distance \u0026amp; The Single-Thread Bottleneck In a traditional native engine, chunk generation and meshing are dispatched to background thread pools (e.g., via rayon). In a standard browser WASM environment, however, we are bound to the main UI and animation thread.\nIf a frame takes longer than 16.6 ms we fall under the holy 60 FPS mark. Because generating 3D Perlin/Simplex noise and extracting surface polygons (meshing) is computationally heavy, we cannot generate all chunks within the player\u0026rsquo;s view distance in a single frame.\nInstead, we need two things:\nPrioritization: Chunks closest to the player must generate first. Time-slicing (Amortization): Bound the number of chunks and meshes generated per frame cycle. 1. Precomputed Spherical Offsets Calculating Euclidean distances on every frame for dozens of surrounding chunk coordinates is wasteful. Since the relative geometric layout never changes, we can precompute the offset coordinates relative to $(0, 0, 0)$ once at startup and sort them spherically:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 fn generate_offsets_in_spherical_order(radius: isize) -\u0026gt; Vec\u0026lt;(ChunkCoord, usize)\u0026gt; { let mut offsets = Vec::new(); for x in 0..radius { for y in 0..radius { for z in 0..radius { let offset_x = x - radius / 2; let offset_y = y - radius / 2; let offset_z = z - radius / 2; // Euclidean distance relative to origin let dist = (offset_x.pow(2) + offset_y.pow(2) + offset_z.pow(2)).isqrt() as usize; offsets.push((ChunkCoord(offset_x, offset_y, offset_z), dist)); } } } // Sort ascending: closest chunks first offsets.sort_unstable_by_key(|(_, dist)| *dist); offsets } 2. The Frame Update Loop In each render tick, the engine slides its active chunk window based on the player\u0026rsquo;s movement, and then consumes a strictly defined compute budget of chunk and mesh builds:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Called once per frame pub fn update( \u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, max_chunk_budget: usize, max_mesh_budget: usize ) -\u0026gt; (usize, usize) { // 1. Shift the logical sliding window (O(1) index updates, practically free) self.slide_active_window(player_position); // 2. Process pending generation within budget let n_chunks = self.generate_pending_chunks(player_position, max_chunk_budget); let n_meshes = self.generate_pending_meshes(player_position, device, max_mesh_budget); (n_chunks, n_meshes) } Chunk Management: 3D Toroidal Buffering Rather than reallocating an entire 3D grid whenever the player crosses a chunk boundary, the engine uses a 3D Toroidal Ring Buffer (Sliding Window).\nBecause coordinates wrap around via modulo operations across all three axes, moving through the world requires zero data reallocations. When the player moves along an axis (say, $+X$), only the 2D plane on the opposite, trailing boundary ($-X$) is invalidated and marked for regeneration with the newly entered terrain.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 /// Update loaded chunks based on player movement. /// Only marks the \u0026#34;trailing\u0026#34; surface layer of chunks for clearance. fn slide_active_window(\u0026amp;mut self, new_player_coord: \u0026amp;ChunkCoord) { let deltas = [ new_player_coord.0 - self.previous_player_coord.0, new_player_coord.1 - self.previous_player_coord.1, new_player_coord.2 - self.previous_player_coord.2, ]; for (axis, \u0026amp;movement_delta) in deltas.iter().enumerate() { if movement_delta == 0 { continue; } let step = if movement_delta \u0026gt; 0 { 1 } else { -1 }; let mut working_base = self.previous_player_coord; // Process step-by-step to handle multi-chunk teleports/fast movement for _ in 0..movement_delta.abs() { let half = self.active_size[axis] as isize / 2; let plane_offset = -half * step; // Invalidate the 2D plane perpendicular to the movement direction for i in 0..self.active_size[(axis + 1) % 3] as isize { for j in 0..self.active_size[(axis + 2) % 3] as isize { let chunk_coord = match axis { 0 =\u0026gt; ChunkCoord(working_base.0 + plane_offset, working_base.1 + i - half, working_base.2 + j - half), 1 =\u0026gt; ChunkCoord(working_base.0 + j - half, working_base.1 + plane_offset, working_base.2 + i - half), _ =\u0026gt; ChunkCoord(working_base.0 + i - half, working_base.1 + j - half, working_base.2 + plane_offset), }; self.get_active_entry_mut(\u0026amp;chunk_coord).unset(); } } match axis { 0 =\u0026gt; working_base.0 += step, 1 =\u0026gt; working_base.1 += step, _ =\u0026gt; working_base.2 += step, } } } self.previous_player_coord = *new_player_coord; } Prioritized Chunk \u0026amp; Mesh Generation Generating a chunk is a two-step pipeline:\nVoxel Population: The 3D density noise generates raw voxel data. Mesh Extraction: Once a chunk and all its direct neighbors are populated, faces obscured by adjacent solid blocks are culled, and GPU vertex buffers are created and uploaded. Notice how whenever a non-empty chunk finishes loading, it flags its immediate neighbors (unset_mesh()): a border chunk cannot accurately cull its outer faces until adjacent blocks are known!\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 fn generate_pending_chunks(\u0026amp;mut self, player_chunk_position: \u0026amp;ChunkCoord, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, distance) = self.offsets[i]; let chunk_coord = player_chunk_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).is_pending() { // Early out for chunks strictly above terrain generation limit if chunk_coord.1 \u0026lt;= -2 || chunk_coord.1 \u0026gt;= 14 { *self.get_active_entry_mut(\u0026amp;chunk_coord) = ActiveEntry::Empty { coord: chunk_coord }; continue; } let new_chunk = Chunk::new_populated(\u0026amp;self.density_generator, \u0026amp;chunk_coord); used_budget += 1; if new_chunk.is_empty() { self.get_active_entry_mut(\u0026amp;chunk_coord).set_empty(chunk_coord); } else { let required_lod = select_lod(distance); self.get_active_entry_mut(\u0026amp;chunk_coord).set_loaded(chunk_coord, new_chunk, required_lod); // Invalidate neighbor meshes to enforce seamless boundary culling for neighbor_coord in self.get_neighbor_chunk_coords(\u0026amp;chunk_coord) { self.get_active_entry_mut(\u0026amp;neighbor_coord).unset_mesh(); } } } } used_budget } fn generate_pending_meshes(\u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, _) = self.offsets[i]; let chunk_coord = player_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).needs_remesh() { let chunk_borders = self.get_chunk_borders(\u0026amp;chunk_coord); self.get_active_entry_mut(\u0026amp;chunk_coord).generate_and_upload_mesh(device, \u0026amp;chunk_borders); used_budget += 1; } } used_budget } What\u0026rsquo;s Next? While the engine runs at a solid 60 FPS under normal navigation, there are several exciting paths for future improvements:\nGreedy Meshing: Combining adjacent coplanar quad faces into single larger quads to drastically reduce vertex and index buffer sizes. Web Workers via SharedArrayBuffer: Offloading noise sampling to background Web Workers using Rust\u0026rsquo;s wasm-bindgen-rayon to make chunk generation truly asynchronous without stuttering the render thread. Persistent Browser Storage: Currently, all edits vanish on page refresh. The browser provides powerful mechanisms to persist modified worlds: OPFS (Origin Private File System): A modern, sandboxed filesystem API that allows fast, synchronous binary I/O from within Web Workers. It would enable Minecraft-style binary region files (.mca) running purely on the client. IndexedDB: An alternative key-value store to save compressed diffs of player-modified chunks without touching the pristine procedurally generated baseline. Floating Origin (Camera-Relative Rendering): While chunk coordinates can logically span a 32-bit integer space (billions of blocks), GPU rendering relies on 32-bit floating-point numbers (f32). At extreme coordinate distances, IEEE 754 floats lose precision, manifesting as severe vertex jitter, camera stutter, and depth-fighting artifacts (the classic \u0026ldquo;Far Lands\u0026rdquo; effect).\nAn architectural fix is a floating origin: instead of translating the camera through an ever-expanding global space, the camera is pinned statically at $(0, 0, 0)$. Chunks maintain their true logical world coordinates for generation and storage, but are indexed and pushed to the GPU transformed into local camera space. ","permalink":"http://localhost:1313/posts/voxel-engine/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eDisclaimer\u003c/strong\u003e: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ca href=\"https://eliaswendt.github.io/woxel\"\u003eLive Demo\u003c/a\u003e · \u003ca href=\"https://github.com/eliaswendt/woxel\"\u003eGitHub Repository\u003c/a\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-software-stack\"\u003eThe Software Stack\u003c/h2\u003e\n\u003cp\u003eWith WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\u003c/p\u003e","title":"Building a Browser Voxel Engine in Rust \u0026 WebGPU"},{"content":"Abstract High-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\nLinks ACL Anthology Download PDF GitHub Repo Huggingface Repo 🤗 BibTeX 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @inproceedings{aliJudgingQualityLanguages2025b, title = {Judging {{Quality Across Languages}}: {{A Multilingual Approach}} to {{Pretraining Data Filtering}} with {{Language Models}}}, shorttitle = {Judging {{Quality Across Languages}}}, booktitle = {Proceedings of the 2025 {{Conference}} on {{Empirical Methods}} in {{Natural Language Processing}}}, author = {Ali, Mehdi and Brack, Manuel and L{\\\u0026#34;u}bbering, Max and Wendt, Elias and Khan, Abbas Goher and Rutmann, Richard and Jude, Alex and Kraus, Maurice and Weber, Alexander Arno and Stollenwerk, Felix and Kacz{\\\u0026#39;e}r, David and Mai, Florian and Flek, Lucie and Sifa, Rafet and {Flores-Herr}, Nicolas and Koehler, Joachim and Schramowski, Patrick and Fromm, Michael and Kersting, Kristian}, year = 2025, pages = {8870--8909}, publisher = {Association for Computational Linguistics}, address = {Suzhou, China}, doi = {10.18653/v1/2025.emnlp-main.449}, urldate = {2026-06-27}, langid = {english}, file = {/Users/me/Zotero/storage/5IE6855P/Ali et al. - 2025 - Judging Quality Across Languages A Multilingual Approach to Pretraining Data Filtering with Languag.pdf} } ","permalink":"http://localhost:1313/posts/publication-jql/","summary":"\u003ch2 id=\"abstract\"\u003eAbstract\u003c/h2\u003e\n\u003cp\u003eHigh-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\u003c/p\u003e","title":"Judging Quality Across Languages: A Multilingual Approach to Pretraining Data Filtering with Language Models"},{"content":"The core idea of Bayesian inference is updating an initial belief in light of new evidence.\nStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the prior distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the posterior $p(X|E)$:\n$$ \\underbrace{p(X|E)}_{\\text{posterior}} = \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}} = \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}} = \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]} $$ Prior $p(X)$: What we believe about $X$ (e.g. how it is distributed) before looking at the data Likelihood $p(E|X)$: If the hypothesis $X$ were true, how likely would the observed evidence $E$ be? Posterior $p(X|E)$: What we should believe about $X$ now that we have observed $E$. Marginal Likelihood (Evidence) $p(E)$: The total probability of observing the evidence across all possible states of $X$. Notice: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning: $$ \\text{Posterior} \\propto \\text{Likelihood} \\cdot \\text{Prior} $$ New beliefs are a direct compromise between what you previously thought (Prior) and what the data suggests (Likelihood).\nIterative Learning Bayesian updating is naturally sequential. Assuming independent observations given $X$, the current posterior $p(X|E)$ becomes the starting prior:\n$$ p(X | E_1, E_2) \\propto p(E_2 | X) \\cdot p(X | E_1) $$As you collect more evidence, the likelihood term begins to dominate, and the initial prior gradually washes out.\nExample: The Base Rate Fallacy Why can\u0026rsquo;t we just rely on the likelihood $p(E|X)$? Consider a rare disease:\nPrior: $1$ in $1{,}000$ people has the disease $\\rightarrow p(\\text{Disease}) = 0.001$. Likelihood (Accuracy): A test is $99$% accurate for sick people $\\rightarrow p(\\text{Positive} | \\text{Disease}) = 0.99$. False Positive Rate: The test gives a false positive $5$% of the time for healthy people $\\rightarrow p(\\text{Positive} | \\text{Healthy}) = 0.05$. If a patient tests positive ($E = \\text{Positive}$):\n$$ p(\\text{Disease} | \\text{Positive}) = \\frac{0.99 \\cdot 0.001}{(0.99 \\cdot 0.001) + (0.05 \\cdot 0.999)} \\approx \\frac{0.00099}{0.00099 + 0.04995} \\approx 1.94\\% $$Even with a $99$% accurate test, the probability of being sick is under $2$%. The massive pool of healthy people generates far more false alarms than genuine detections. The prior acts as an anchor that keeps rare events from being drastically overestimated.\n","permalink":"http://localhost:1313/posts/bayes-theorem/","summary":"\u003cp\u003eThe core idea of Bayesian inference is updating an initial belief in light of new evidence.\u003c/p\u003e\n\u003cp\u003eStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the \u003cstrong\u003eprior\u003c/strong\u003e distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the \u003cstrong\u003eposterior\u003c/strong\u003e $p(X|E)$:\u003c/p\u003e\n$$\n\\underbrace{p(X|E)}_{\\text{posterior}}\n= \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}}\n= \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}}\n= \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]}\n$$\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePrior $p(X)$:\u003c/strong\u003e What we believe about $X$ (e.g. how it is distributed) before looking at the data\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLikelihood $p(E|X)$:\u003c/strong\u003e If the hypothesis $X$ were true, how likely would the observed evidence $E$ be?\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePosterior $p(X|E)$:\u003c/strong\u003e What we should believe about $X$ now that we have observed $E$.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMarginal Likelihood (Evidence) $p(E)$:\u003c/strong\u003e The total probability of observing the evidence across \u003cem\u003eall\u003c/em\u003e possible states of $X$.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eNotice\u003c/strong\u003e: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning:\n\u003c/p\u003e","title":"Bayes' Theorem"},{"content":"","permalink":"http://localhost:1313/posts/invariant-mechanism-analysis/","summary":"","title":"Invariant Mechanism Analysis"},{"content":"Association vs. Causation Classical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: $$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$This objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$. From a probabilistic objective this is equivalent to optimizing: $$ \\arg \\max_\\theta p_\\theta (Y|X) $$However, not all association is causally grounded!\nExample do-Calculus Rule 1: Insertion/Deletion of Observations $P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\nRule 2: Action/Observation Exchange $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), z, w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\underline{Z}}$\nRule 3: Insertion/Deletion of Interventions $P(y \\mid \\mathrm{do}(x), \\mathrm{do}(z), w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}, \\overline{Z(W)}}$\nCompeteness The do-calculus has been proven to be complete. This means that if it rules cannot translate the do-operator into pure probabilistic expressions, the causal effect is not identifiable.\nInstrumental Variables ","permalink":"http://localhost:1313/posts/causal-effect-estimation/","summary":"\u003ch2 id=\"association-vs-causation\"\u003eAssociation vs. Causation\u003c/h2\u003e\n\u003cp\u003eClassical Machine Learning tries to minimize an Empirical Loss, often chosen to be the Mean-Squared-Error: \u003c/p\u003e\n$$ \\arg \\min_\\theta MSE(x, y, f_\\theta) = \\frac{1}{N} \\sum_{i=1}^N (f_\\theta (x_i) - y_i)^2 $$\u003cp\u003eThis objective tries to find parameters $\\theta$ that best parameterize the model $f_\\theta$.\nFrom a probabilistic objective this is equivalent to optimizing: \u003c/p\u003e\n$$ \\arg \\max_\\theta p_\\theta (Y|X) $$\u003cp\u003eHowever, not all association is causally grounded!\u003c/p\u003e\n\u003ch3 id=\"example\"\u003eExample\u003c/h3\u003e\n\u003ch2 id=\"do-calculus\"\u003edo-Calculus\u003c/h2\u003e\n\u003ch3 id=\"rule-1-insertiondeletion-of-observations\"\u003eRule 1: Insertion/Deletion of Observations\u003c/h3\u003e\n\u003cp\u003e$P(y \\mid \\mathrm{do}(x), z, w) = P(y \\mid \\mathrm{do}(x), w) \\quad \\text{if } Y \\perp Z \\mid X, W \\text{ in } \\mathcal{G}_{\\overline{X}}$\u003c/p\u003e","title":"Causal Effect Estimation"},{"content":" Disclaimer: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\nLive Demo · GitHub Repository\nThe Software Stack With WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\nGraphics: wgpu (Targeting WebGPU via WebAssembly) Linear Algebra: glam GUI: egui Build Tooling: Trunk Blocks and Chunks At the core of any voxel engine lies a hierarchy: individual voxels aggregate into manageable spatial volumes called Chunks.\nA chunk is represented as a contiguous 3D array of Blocks. Storing millions of empty air voxels naively would quickly exhaust memory, especially within browser constraints. To mitigate this, chunks consisting solely of air are treated as uniform singletons and avoid individual heap allocations:\n1 2 3 4 5 6 7 8 9 10 11 #[derive(Copy, Clone, PartialEq, Eq)] pub enum BlockType { Air, Grass, Dirt, Stone, } pub struct Chunk { blocks: [BlockType; N_BLOCKS_PER_CHUNK], } View Distance \u0026amp; The Single-Thread Bottleneck In a traditional native engine, chunk generation and meshing are dispatched to background thread pools (e.g., via rayon). In a standard browser WASM environment, however, we are bound to the main UI and animation thread.\nIf a frame takes longer than 16.6 ms we fall under the holy 60 FPS mark. Because generating 3D Perlin/Simplex noise and extracting surface polygons (meshing) is computationally heavy, we cannot generate all chunks within the player\u0026rsquo;s view distance in a single frame.\nInstead, we need two things:\nPrioritization: Chunks closest to the player must generate first. Time-slicing (Amortization): Bound the number of chunks and meshes generated per frame cycle. 1. Precomputed Spherical Offsets Calculating Euclidean distances on every frame for dozens of surrounding chunk coordinates is wasteful. Since the relative geometric layout never changes, we can precompute the offset coordinates relative to $(0, 0, 0)$ once at startup and sort them spherically:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 fn generate_offsets_in_spherical_order(radius: isize) -\u0026gt; Vec\u0026lt;(ChunkCoord, usize)\u0026gt; { let mut offsets = Vec::new(); for x in 0..radius { for y in 0..radius { for z in 0..radius { let offset_x = x - radius / 2; let offset_y = y - radius / 2; let offset_z = z - radius / 2; // Euclidean distance relative to origin let dist = (offset_x.pow(2) + offset_y.pow(2) + offset_z.pow(2)).isqrt() as usize; offsets.push((ChunkCoord(offset_x, offset_y, offset_z), dist)); } } } // Sort ascending: closest chunks first offsets.sort_unstable_by_key(|(_, dist)| *dist); offsets } 2. The Frame Update Loop In each render tick, the engine slides its active chunk window based on the player\u0026rsquo;s movement, and then consumes a strictly defined compute budget of chunk and mesh builds:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Called once per frame pub fn update( \u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, max_chunk_budget: usize, max_mesh_budget: usize ) -\u0026gt; (usize, usize) { // 1. Shift the logical sliding window (O(1) index updates, practically free) self.slide_active_window(player_position); // 2. Process pending generation within budget let n_chunks = self.generate_pending_chunks(player_position, max_chunk_budget); let n_meshes = self.generate_pending_meshes(player_position, device, max_mesh_budget); (n_chunks, n_meshes) } Chunk Management: 3D Toroidal Buffering Rather than reallocating an entire 3D grid whenever the player crosses a chunk boundary, the engine uses a 3D Toroidal Ring Buffer (Sliding Window).\nBecause coordinates wrap around via modulo operations across all three axes, moving through the world requires zero data reallocations. When the player moves along an axis (say, $+X$), only the 2D plane on the opposite, trailing boundary ($-X$) is invalidated and marked for regeneration with the newly entered terrain.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 /// Update loaded chunks based on player movement. /// Only marks the \u0026#34;trailing\u0026#34; surface layer of chunks for clearance. fn slide_active_window(\u0026amp;mut self, new_player_coord: \u0026amp;ChunkCoord) { let deltas = [ new_player_coord.0 - self.previous_player_coord.0, new_player_coord.1 - self.previous_player_coord.1, new_player_coord.2 - self.previous_player_coord.2, ]; for (axis, \u0026amp;movement_delta) in deltas.iter().enumerate() { if movement_delta == 0 { continue; } let step = if movement_delta \u0026gt; 0 { 1 } else { -1 }; let mut working_base = self.previous_player_coord; // Process step-by-step to handle multi-chunk teleports/fast movement for _ in 0..movement_delta.abs() { let half = self.active_size[axis] as isize / 2; let plane_offset = -half * step; // Invalidate the 2D plane perpendicular to the movement direction for i in 0..self.active_size[(axis + 1) % 3] as isize { for j in 0..self.active_size[(axis + 2) % 3] as isize { let chunk_coord = match axis { 0 =\u0026gt; ChunkCoord(working_base.0 + plane_offset, working_base.1 + i - half, working_base.2 + j - half), 1 =\u0026gt; ChunkCoord(working_base.0 + j - half, working_base.1 + plane_offset, working_base.2 + i - half), _ =\u0026gt; ChunkCoord(working_base.0 + i - half, working_base.1 + j - half, working_base.2 + plane_offset), }; self.get_active_entry_mut(\u0026amp;chunk_coord).unset(); } } match axis { 0 =\u0026gt; working_base.0 += step, 1 =\u0026gt; working_base.1 += step, _ =\u0026gt; working_base.2 += step, } } } self.previous_player_coord = *new_player_coord; } Prioritized Chunk \u0026amp; Mesh Generation Generating a chunk is a two-step pipeline:\nVoxel Population: The 3D density noise generates raw voxel data. Mesh Extraction: Once a chunk and all its direct neighbors are populated, faces obscured by adjacent solid blocks are culled, and GPU vertex buffers are created and uploaded. Notice how whenever a non-empty chunk finishes loading, it flags its immediate neighbors (unset_mesh()): a border chunk cannot accurately cull its outer faces until adjacent blocks are known!\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 fn generate_pending_chunks(\u0026amp;mut self, player_chunk_position: \u0026amp;ChunkCoord, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, distance) = self.offsets[i]; let chunk_coord = player_chunk_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).is_pending() { // Early out for chunks strictly above terrain generation limit if chunk_coord.1 \u0026lt;= -2 || chunk_coord.1 \u0026gt;= 14 { *self.get_active_entry_mut(\u0026amp;chunk_coord) = ActiveEntry::Empty { coord: chunk_coord }; continue; } let new_chunk = Chunk::new_populated(\u0026amp;self.density_generator, \u0026amp;chunk_coord); used_budget += 1; if new_chunk.is_empty() { self.get_active_entry_mut(\u0026amp;chunk_coord).set_empty(chunk_coord); } else { let required_lod = select_lod(distance); self.get_active_entry_mut(\u0026amp;chunk_coord).set_loaded(chunk_coord, new_chunk, required_lod); // Invalidate neighbor meshes to enforce seamless boundary culling for neighbor_coord in self.get_neighbor_chunk_coords(\u0026amp;chunk_coord) { self.get_active_entry_mut(\u0026amp;neighbor_coord).unset_mesh(); } } } } used_budget } fn generate_pending_meshes(\u0026amp;mut self, player_position: \u0026amp;ChunkCoord, device: \u0026amp;wgpu::Device, budget: usize) -\u0026gt; usize { let mut used_budget = 0; for i in 0..self.offsets.len() { if used_budget \u0026gt;= budget { break; } let (offset, _) = self.offsets[i]; let chunk_coord = player_position.add(\u0026amp;offset); if self.get_active_entry(\u0026amp;chunk_coord).needs_remesh() { let chunk_borders = self.get_chunk_borders(\u0026amp;chunk_coord); self.get_active_entry_mut(\u0026amp;chunk_coord).generate_and_upload_mesh(device, \u0026amp;chunk_borders); used_budget += 1; } } used_budget } What\u0026rsquo;s Next? While the engine runs at a solid 60 FPS under normal navigation, there are several exciting paths for future improvements:\nGreedy Meshing: Combining adjacent coplanar quad faces into single larger quads to drastically reduce vertex and index buffer sizes. Web Workers via SharedArrayBuffer: Offloading noise sampling to background Web Workers using Rust\u0026rsquo;s wasm-bindgen-rayon to make chunk generation truly asynchronous without stuttering the render thread. Persistent Browser Storage: Currently, all edits vanish on page refresh. The browser provides powerful mechanisms to persist modified worlds: OPFS (Origin Private File System): A modern, sandboxed filesystem API that allows fast, synchronous binary I/O from within Web Workers. It would enable Minecraft-style binary region files (.mca) running purely on the client. IndexedDB: An alternative key-value store to save compressed diffs of player-modified chunks without touching the pristine procedurally generated baseline. Floating Origin (Camera-Relative Rendering): While chunk coordinates can logically span a 32-bit integer space (billions of blocks), GPU rendering relies on 32-bit floating-point numbers (f32). At extreme coordinate distances, IEEE 754 floats lose precision, manifesting as severe vertex jitter, camera stutter, and depth-fighting artifacts (the classic \u0026ldquo;Far Lands\u0026rdquo; effect).\nAn architectural fix is a floating origin: instead of translating the camera through an ever-expanding global space, the camera is pinned statically at $(0, 0, 0)$. Chunks maintain their true logical world coordinates for generation and storage, but are indexed and pushed to the GPU transformed into local camera space. ","permalink":"http://localhost:1313/posts/voxel-engine/","summary":"\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eDisclaimer\u003c/strong\u003e: This is a vibe-coding project. I used Claude Code for the vast majority of the implementation (especially the wgpu rendering pipeline and noise-based terrain generation). My primary focus was exploring the architecture around chunk management, spatial indexing, and meshing. 😊\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003ca href=\"https://eliaswendt.github.io/woxel\"\u003eLive Demo\u003c/a\u003e · \u003ca href=\"https://github.com/eliaswendt/woxel\"\u003eGitHub Repository\u003c/a\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"the-software-stack\"\u003eThe Software Stack\u003c/h2\u003e\n\u003cp\u003eWith WebGPU maturing and WebAssembly integration in Rust becoming remarkably smooth, I wanted to see how far browser-based 3D engines could be pushed:\u003c/p\u003e","title":"Building a Browser Voxel Engine in Rust \u0026 WebGPU"},{"content":"Abstract High-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\nLinks ACL Anthology Download PDF GitHub Repo Huggingface Repo 🤗 BibTeX 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @inproceedings{aliJudgingQualityLanguages2025b, title = {Judging {{Quality Across Languages}}: {{A Multilingual Approach}} to {{Pretraining Data Filtering}} with {{Language Models}}}, shorttitle = {Judging {{Quality Across Languages}}}, booktitle = {Proceedings of the 2025 {{Conference}} on {{Empirical Methods}} in {{Natural Language Processing}}}, author = {Ali, Mehdi and Brack, Manuel and L{\\\u0026#34;u}bbering, Max and Wendt, Elias and Khan, Abbas Goher and Rutmann, Richard and Jude, Alex and Kraus, Maurice and Weber, Alexander Arno and Stollenwerk, Felix and Kacz{\\\u0026#39;e}r, David and Mai, Florian and Flek, Lucie and Sifa, Rafet and {Flores-Herr}, Nicolas and Koehler, Joachim and Schramowski, Patrick and Fromm, Michael and Kersting, Kristian}, year = 2025, pages = {8870--8909}, publisher = {Association for Computational Linguistics}, address = {Suzhou, China}, doi = {10.18653/v1/2025.emnlp-main.449}, urldate = {2026-06-27}, langid = {english}, file = {/Users/me/Zotero/storage/5IE6855P/Ali et al. - 2025 - Judging Quality Across Languages A Multilingual Approach to Pretraining Data Filtering with Languag.pdf} } ","permalink":"http://localhost:1313/posts/publication-jql/","summary":"\u003ch2 id=\"abstract\"\u003eAbstract\u003c/h2\u003e\n\u003cp\u003eHigh-quality multilingual training data is essential for effectively pretraining large language models (LLMs). Yet, the availability of suitable open-source multilingual datasets remains limited. Existing state-of-the-art datasets mostly rely on heuristic filtering methods, restricting both their cross-lingual transferability and scalability. Here, we introduce JQL, a systematic approach that efficiently curates diverse and high-quality multilingual data at scale while significantly reducing computational demands. JQL distills LLMs’ annotation capabilities into lightweight annotators based on pretrained multilingual embeddings. These models exhibit robust multilingual and cross-lingual performance, even for languages and scripts unseen during training. Evaluated empirically across 35 languages, the resulting annotation pipeline substantially outperforms current heuristic filtering methods like Fineweb2. JQL notably enhances downstream model training quality and increases data retention rates. Our research provides practical insights and valuable resources for multilingual data curation, raising the standards of multilingual dataset development.\u003c/p\u003e","title":"Judging Quality Across Languages: A Multilingual Approach to Pretraining Data Filtering with Language Models"},{"content":"The core idea of Bayesian inference is updating an initial belief in light of new evidence.\nStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the prior distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the posterior $p(X|E)$:\n$$ \\underbrace{p(X|E)}_{\\text{posterior}} = \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}} = \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}} = \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]} $$ Prior $p(X)$: What we believe about $X$ (e.g. how it is distributed) before looking at the data Likelihood $p(E|X)$: If the hypothesis $X$ were true, how likely would the observed evidence $E$ be? Posterior $p(X|E)$: What we should believe about $X$ now that we have observed $E$. Marginal Likelihood (Evidence) $p(E)$: The total probability of observing the evidence across all possible states of $X$. Notice: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning: $$ \\text{Posterior} \\propto \\text{Likelihood} \\cdot \\text{Prior} $$ New beliefs are a direct compromise between what you previously thought (Prior) and what the data suggests (Likelihood).\nIterative Learning Bayesian updating is naturally sequential. Assuming independent observations given $X$, the current posterior $p(X|E)$ becomes the starting prior:\n$$ p(X | E_1, E_2) \\propto p(E_2 | X) \\cdot p(X | E_1) $$As you collect more evidence, the likelihood term begins to dominate, and the initial prior gradually washes out.\nExample: The Base Rate Fallacy Why can\u0026rsquo;t we just rely on the likelihood $p(E|X)$? Consider a rare disease:\nPrior: $1$ in $1{,}000$ people has the disease $\\rightarrow p(\\text{Disease}) = 0.001$. Likelihood (Accuracy): A test is $99$% accurate for sick people $\\rightarrow p(\\text{Positive} | \\text{Disease}) = 0.99$. False Positive Rate: The test gives a false positive $5$% of the time for healthy people $\\rightarrow p(\\text{Positive} | \\text{Healthy}) = 0.05$. If a patient tests positive ($E = \\text{Positive}$):\n$$ p(\\text{Disease} | \\text{Positive}) = \\frac{0.99 \\cdot 0.001}{(0.99 \\cdot 0.001) + (0.05 \\cdot 0.999)} \\approx \\frac{0.00099}{0.00099 + 0.04995} \\approx 1.94\\% $$Even with a $99$% accurate test, the probability of being sick is under $2$%. The massive pool of healthy people generates far more false alarms than genuine detections. The prior acts as an anchor that keeps rare events from being drastically overestimated.\n","permalink":"http://localhost:1313/posts/bayes-theorem/","summary":"\u003cp\u003eThe core idea of Bayesian inference is updating an initial belief in light of new evidence.\u003c/p\u003e\n\u003cp\u003eStarting with an initial belief over an unobserved hypothesis or latent state $X$, represented by the \u003cstrong\u003eprior\u003c/strong\u003e distribution $p(X)$, we incorporate the observation of new evidence $E$ (the observed data) to compute an updated belief, known as the \u003cstrong\u003eposterior\u003c/strong\u003e $p(X|E)$:\u003c/p\u003e\n$$\n\\underbrace{p(X|E)}_{\\text{posterior}}\n= \\frac{\\overbrace{p(E|X)}^{\\text{likelihood}} \\cdot \\overbrace{p(X)}^{\\text{prior}}}{\\underbrace{p(E)}_{\\text{evidence / marginal likelihood}}}\n= \\frac{p(E|X) \\, p(X)}{\\underbrace{\\int p(E|x) \\, p(x) \\, dx}_{\\text{normalizing constant}}}\n= \\frac{p(E, X)}{\\mathbb{E}_{x \\sim p(X)} [p(E|x)]}\n$$\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePrior $p(X)$:\u003c/strong\u003e What we believe about $X$ (e.g. how it is distributed) before looking at the data\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLikelihood $p(E|X)$:\u003c/strong\u003e If the hypothesis $X$ were true, how likely would the observed evidence $E$ be?\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePosterior $p(X|E)$:\u003c/strong\u003e What we should believe about $X$ now that we have observed $E$.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eMarginal Likelihood (Evidence) $p(E)$:\u003c/strong\u003e The total probability of observing the evidence across \u003cem\u003eall\u003c/em\u003e possible states of $X$.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003eNotice\u003c/strong\u003e: The denominator $p(E)$ does not depend on a specific hypothesis $X$. It is simply a constant sum (or integral) over all possibilities. Because of this, it functions purely as a normalizing constant to ensure the posterior integrates to $1$ (making it a probability). Stripping away the denominator leaves the core mechanism of Bayesian reasoning:\n\u003c/p\u003e","title":"Bayes' Theorem"}]