I’m excited to announce Recor.jl, a high-performance ray-triangle intersection engine with bounding volume hierarchy (BVH) acceleration, designed for both CPU and GPU execution in Julia. Raycore will power a new ray tracing backend for Maki, bringing photorealistic rendering to the Maki ecosystem with the familiar Maki API. We considered the ray intersection engine because it can be used in many other areas such as simulating light transport, heat transfer, or acoustic propagation and many other areas.
Why write a new ray intersection engine?
You may wonder: why create another ray tracer? The answer lies in Julia’s unique strengths, the opportunities they create, and the flexibility we get from full control over the rendering implementation.
Benefits of Julia
-
High level language with performance close to C/C++ – Write readable code that runs fast
-
great gpu support – Single codebase runs on CUDA, AMD, Metal, oneAPI and OpenCL through KernelAbstractions.jl
-
Multiple dispatch for different geometries, algorithms and materials – Cleanly extend the system without modifying the core code
-
Pluggable architecture for new features – Add custom content, sampling strategies, or acceleration structures
-
One of the best languages for writing mathematics – Code looks like equations you would write on paper
Honest Assessment: Tradeoffs
Julia isn’t perfect, and there are definitely challenges:
-
Long compilation time for first use – The first run of a function triggers JIT compilation
-
GPU code still has some rough edges – Complex kernels require careful attention to avoid allocations and GPU-unfriendly constructs
-
Not all backends work yet – I have only tested AMDGPU and OpenCL.jl. Metal.jl and OpenCL don’t work on macOS yet, although I think it’s a matter of time to support all backends.
In practice, compile time is not as bad as it sounds. You keep your Julia session running and pay the compilation cost only once. There is also work underway on precompilation that could reduce this time to almost zero in the future and compile most kernels ahead of time. For GPU code, better tooling to detect and fix problems is on the horizon, along with better error messages when problematic LLVM code occurs.
The flexibility to write high-performance ray tracers in a high-level language opens up exciting possibilities:
-
Use automatic resolution Getting gradient for training ML model
-
Plug in new customizations seamlessly Without fighting any kind of system or rewriting the core algorithm
-
Democratize work on high-performance ray tracing – Contribution does not require C++ expertise and the code base is quite small
-
rapid experiment – Test new ideas without long compilation cycles
What is Raycore.jl?
Recore is a focused library that does one thing well: fast ray-triangle intersection with BVH acceleration. It provides building blocks for ray tracing applications without implementing any particular rendering architecture.
Main characteristics
-
Fast BVH creation and traversal
-
CPU and GPU support via KernelAbstractions.jl
-
Analysis tools: centroid calculation, illumination analysis, view factor for radiosity
-
Maki integration for visualization
Display
Thanks to the bounding volume hierarchy, the intersection display matches the scene size relatively well.
using Raycore, GeometryBasics, BenchmarkTools, Markdown, Bonito
ray = Raycore.Ray(o=Point3f(0, 0, -5), d=Vec3f(0, 0, 1))
results = map([1, 1000, 10000]) do n
spheres = [Tesselation(Sphere(randn(Point3f) .* 1000f0, 0.5f0), 32) for _ in 1:n]
bvh = Raycore.BVH(spheres)
tclosest = BenchmarkTools.@belapsed Raycore.closest_hit($bvh, $ray)
ntriangles = length(bvh.primitives)
# use closest hit for time per triangle, since it needs to traverse more triangles
tpt = string(round((tclosest/ntriangles)*1e9, digits=5), "ns")
tcloseststr = string(round(tclosest * 1e6, digits=2), "μs")
(triangles=ntriangles, closest=tcloseststr, time_per_triangle_ns=tpt)
end
DOM.div(Bonito.Table(results))
| 1922 | 0.01μs | 0.0064ns |
| 1922000 | 0.58μs | 0.0003ns |
| 19220000 | 4.01μs | 0.00021ns |
Since you can run thousands of ray intersections in parallel on the GPU, we get very good performance per ray intersection. The benchmark below is from the GPU tutorial, which produces approximately 400x700px * 4 samples x 8 shadow rays per 3 lights + 1 reflection ray that can generate 8 shadow rays, so about 40mio rays, which we can do in an optimized GPU kernel in about 43ms: 
interactive tutorial
The documentation includes several practical tutorials that build from the basics to advanced GPU optimization:
1. BVH HIT TEST AND BASICS
Learn the fundamentals of ray-triangle intersection, BVH construction, and visualization.

Try the tutorial →
2. Ray Tracing in an Hour
Create a complete ray tracer from scratch with shadows, materials, reflections and tone mapping analogous to famous ray tracing in a weekend.

Try the tutorial →
3. Ray Tracing on GPU
Port ray tracers to GPUs and learn optimization techniques: loop unrolling, tiling, and wavefront rendering. Includes comprehensive benchmarks comparing different approaches.
Try the tutorial →
4. View Factors and Analysis
Calculate view factors, illuminance and centroids for radiosity and thermal analysis applications.

Try the tutorial →
launch
Install Raycore.jl from the Julia package manager:
using Pkg
Pkg.add("Raycore")
Then watch the interactive tutorial to get started creating your first ray tracer!
future work
We have some plans to further improve the package in the future:
-
Maki Raytracing Backend – Bringing photorealistic rendering to the Maki ecosystem
-
Advanced Acceleration Structures – Explore alternatives to BVH like kd-trees or octrees for specific use cases
-
gpu memory optimization – Reduce memory footprint for large views
-
better precompilation – Further reduce first-run latency
-
further optimize performance – It would be great if more people worked on optimizing this natively 🙂
Contributions welcome! The codebase is designed to be accessible, and the Julia community is friendly and helpful.
approvals
Raycore.jl was spun off from Trace.jl, which was originally created by Anton Smirnov. It will soon be renamed to Trace.jl Hikari And released as the main ray tracing implementation built on top of Raycore, providing a complete path tracing framework. The project builds on the excellent work of the Julia GPU ecosystem, especially KernelAbstraction.js for portable GPU programming and of course all GPU backend packages. Special thanks to everyone who helped shape Recore. Part of this work was made possible by investment from the Sovereign Tech Agency and most of the optimization and GPU work has been funded by Muon Space.
I’m excited to see what can be built with Raycore.jl and how far we can push performance as a community!