Changelog
All notable changes are documented here. The format roughly follows Keep a Changelog and the gem versioning is described in the README β first three segments mirror the targeted CSFML release, fourth segment is ruby-sfmlβs own patch level.
HTML API docs: ruby-sfml-doc.netlify.app/
[Unreleased]
[3.0.0.8] β 2026-05-12
Continued documentation pass. RDoc coverage went from 68% β 87% on top of 3.0.0.7βs first pass β every public class, module, and attribute is now documented, plus all the simple setter/getter/predicate methods. Docs site: ruby-sfml-doc.netlify.app/.
Changed β documentation
-
All 63
attr_reader/attr_accessordeclarations now carry a one-line description (62 β 0 undocumented). -
72 of 97 module-level constants now documented (was 23) β every
CODES/INDEXtable,STATUSESenum,DEFAULT_*sentinel, and named-color singleton has a sentence. -
Hand-written docstrings on
Assets,Clock,Window(bare),Sprite,View,Transform,SocketSelector,Http,IpAddress,Eventβ the methods that survived the previous pass without docs. -
Final aggressive auto-doc pass fills setter / getter / predicate / accessor patterns the conservative pass skipped.
[3.0.0.7] β 2026-05-12
Documentation pass. RDoc coverage went from 36% β 68% βevery public class, module, and the high-traffic methods now carry at least a one-line description. Pair this release with the new docs site at ruby-sfml-doc.netlify.app/.
Changed β documentation
-
Hand-written, context-aware docstrings on the value classes (
Vector2,Vector3,Color,Rect,Time): every operator, every helper, every pattern-match hook. -
Audio API surface (
Sound,Music,SoundStream,Listener): every playback method, every property setter/getter, every 3D- audio knob has a real description. -
Graphics β
Transformablemixin (position / rotation / scale / origin / move / rotate / scale_by), thenCircleShape/RectangleShape/ConvexShape/Text/VertexArray/RenderWindow. Color named-accessors, geometric introspection, fill / outline / texture binding. -
Network β typed
Packetreader / writer methods, full FTP surface (download / upload / directory_listing / β¦). -
The autodoc pass fills in trivial setter / getter / predicate pairs everywhere else, so the docs site has at least an identifiable signature line on every public method.
Changed β infra
-
documentation_uriin the gemspec now points to ruby-sfml-doc.netlify.app/ (was rubydoc.info). rubydoc.info still works as an archive of older releases. -
.rdoc_optionsships inside the gem (gem unpackexposes it), so the docs-site repo canrdocan unpacked release without re-supplying title / template / markup / exclude config. -
Added
script/build-docs.shβ local-only build that renders../ruby-sfml-doc/public/. Optional--checkmode catches βdocs out of date with sourceβ in a pre-push hook.
[3.0.0.6] β 2026-05-12
Quality-of-life release: the CSFML 3.0 surface was already covered; this round adds the helpers and tooling you reach for when building on top of it.
Added β system
-
Vector2 / Vector3 math β distance, distance_sq, lerp, project_on, reflect, clamp_length, zero?, abs, plus
Vector2#angle, angle_to(other), rotated(degrees) / rotated_rad(radians), perpendicular, andVector3#angle_between. Both classes gain to_v3 / to_v2 for cross-dimension promotion + scalar coercion (2 * vec).
Added β graphics
-
RenderWindow#screenshot(path)β capture the current back-buffer to disk (PNG / JPG / BMP / TGA inferred by extension). -
RenderWindow#capture_imageβ same capture, returns an in-memorySFML::Imagefor further processing. -
SFML::SpriteSheetβ slice a uniformly-gridded image into numbered frames..load(path, frame_size:, padding:, margin:), region(i), region_at(col, row), sprite(i),#animation(fps:, ...). -
SFML::TextureAtlasβ load Aseprite / TexturePacker JSON descriptors..load(json_path), region(name), sprite(name),#animation(names, fps:)(auto-derives fps from Aseprite per-frame durations when present). -
SFML::Animationβ frame-based animation that drives a Spriteβs texture_rect over time. Loop / one-shot, update(dt), reset, done?. Sprite-style transform setters (position=,rotation=,scale=,origin=,color=) for ergonomic use. -
SFML::ParticleSystemβ VertexArray-backed particle pool.#spawn(position:, velocity:, lifetime:, color:, size:), optionalgravity:,update_particlesubclass hook for drag / attractors / colour curves.
Added β game-loop
-
Fixed timestep β
fixed_timestep Nclass macro onSFML::Appcallsupdate(dt)exactly N times per second with a fixed dt (semi-implicit Euler accumulator, capped at 5 catch-up steps to prevent the βspiral of deathβ). Readinterpolation_alphafrom draw to smoothly render between fixed updates. -
Input actions DSL β
action :jump, keys: [...], scancodes: [...], mouse_buttons: [...], joy_buttons: [...]onSFML::AppandSFML::Scene. Poll withaction_pressed? (:name)fromupdate/draw; build digital axes withaxis(negative:, positive:). Scene actions inherit from the host Appβs actions.
Added β errors
-
Domain-specific exception hierarchy:
-
SFML::LoadErrorβ asset load failures (file, memory, stream) -
SFML::AudioErrorβ capture / OpenAL / channel-map -
SFML::NetworkErrorβ sockets / packet framing -
SFML::ShaderErrorβ GLSL compile / link -
SFML::GraphicsErrorβ generic graphics-side failures -
SFML::WindowErrorβ window / context creation All inherit fromSFML::Error, so existingrescue SFML::Errorblocks keep catching everything.
Added β CI / tooling
-
CI badge in README.md.
[3.0.0.5] β 2026-05-11
Round-trip release: closes every remaining CSFML 3.0 gap thatβs useful from Ruby. The library now covers the surface area youβd expect for porting a CSFML application straight across.
Added β graphics
-
Color#+,Color#-,Color#*(aliasmodulate),Color#to_integer/Color.from_integer(value)β channel-wise saturating arithmetic, plus packed 0xRRGGBBAA round-trips. -
Texture binding + geometric introspection on the three concrete shapes via the new
Graphics::ShapeInspectablemixin:CircleShape/RectangleShape/ConvexShapeall gaintexture/texture=/set_texture(tex, reset_rect:),texture_rect/texture_rect=,point(i),geometric_center,local_bounds,global_bounds,transform,inverse_transform,dup/clone.RectangleShapeadditionally exposespoint_count. -
SFML::Shapeβ callback-driven abstract shape. Subclass and override point_count / point(i) to drive geometry from live Ruby data; call update after the source data changes. -
SFML::TransformableObjectβ standalone transform container (CSFMLβssfTransformable*). Useful as a base for custom drawables that combine a transform with their own rendering. -
VertexArray#dup/ clone β independent deep copy. -
VertexBuffer#bind/VertexBuffer.unbindβ bind a VBO as the active GL vertex buffer (for mixing raw GL withSFMLrendering). -
Texture sRGB variants via the
srgb:kwarg onTexture.load,Texture.create,Texture.from_memory,Texture.from_image, andTexture#resize. -
Shader#set_mat3/ set_mat4 / set_mat3_array / set_mat4_array andShader#set_bvec(name, *components)β matrix and bool-vector uniforms. -
Shader.from_stream(vertex:, geometry:, fragment:),Font.from_stream(io),Image.from_stream(io),Texture.from_stream(io, srgb:, ...)β load any of these from a Ruby IO-like object (File, StringIO, network reader). Backed by the newSFML::InputStreamadapter that wraps a Ruby IO as CSFMLβssfInputStream*.
Added β audio
-
Full 3D-audio surface on
SoundStream(mirror of Sound / Music):pan,min_gain/max_gain,max_distance,spatialization_enabled?,direction,cone,velocity,doppler_factor,directional_attenuation_factor,effect_processor=(real-time DSP filter),channel_mapβ and the=setters. -
SoundRecorder#channel_mapβ read the channel layout the recorder is producing. -
SFML::SoundRecorderβ callback-based mic capture. Subclass and override on_start / on_process_samples(samples, channels) / on_stop. The pre-existing module-level helpers (SoundRecorder.available?/.devices/.default_device) are preserved as class methods. -
Music.from_stream(io, **opts)andSoundBuffer.from_stream(io)β stream-backed audio loaders.
Added β network
-
SFML::Network::Packetβ wire-compatible withsf::Packet. Typed read / write forBool,Int8βInt64,Uint8βUint64,Float,Double,String; data / size / read_position / end_of_packet? / ok? / clear / dup. -
TcpSocket#send_packet/ receive_packet andUdpSocket#send_packet(packet, to:, port:)/ receive_packet β structured framing on top of the existing raw byte send/receive.
Added β window
-
Keyboard::SCAN_CODESβ full layout-independent scancode table (146 entries matchingsfScancode). -
Keyboard.scancode_pressed?(:scan_w)β query the physical key regardless of keyboard layout (the standard for WASD-style games). -
Keyboard.localize(scancode)/.delocalize(key)/.description(scancode)β convert between physical scancodes and logical keys under the current OS layout, plus the human-readable description string. -
Keyboard.virtual_keyboard_visible=β on-screen keyboard toggle for touchscreen / mobile builds (no-op on desktop). -
VideoMode.fullscreen_modesβ all video modes the display supports for true-fullscreen window creation, sorted from most to least pixels. -
VideoMode#valid?β does the display actually support this mode at fullscreen? -
SFML::Contextβ headless GL context. Activate it on a thread to compile shaders / make raw GL calls without a window. StaticContext.active_context_id,.extension_available?(name),.gl_function(name).
Added β system
-
SFML::InputStream(io)β wraps a Ruby IO-like object (anything answeringread/seek/pos/size) as thesfInputStream*argument CSFML loader functions take. Used internally by every*.from_streamfactory.
[3.0.0.4] β 2026-05-09
Added β graphics
-
Sprite#dup/ clone,Sprite#texture(borrowed reference),Sprite#transform,Sprite#inverse_transform. -
View#scissor/View#scissor=β normalised [0..1] clip rect applied at render time (paired with the existingviewportAPI). -
Texture.from_memory(bytes, smooth:, repeated:)β decode + upload a Ruby String of bytes (PNG / JPG / BMP / TGA / β¦) as a texture. Bypasses the disk for embedded assets / network blobs. -
Texture#resize(w, h)β reallocate GPU memory in place. -
Texture#swap(other)β atomically swap GPU memory between two textures (cheap double-buffer pattern). -
Texture#native_handleβ the OpenGL texture-object name for raw GL interop. -
Texture#update_from_texture(source, offset:),Texture#update_from_render_window(window, offset:),Texture#update_from_window(window, offset:)β copy pixels from another GPU texture / from a windowβs back-buffer / from a bare-Windowβs framebuffer into this texture atoffset. -
RenderWindow#viewport(view = self.view)andRenderWindow#scissor(view = self.view)β pixel-spaceSFML::Rects the view actually covers / clips. Same onRenderTexture. -
Shader#set_int_color(name, color)β uploads aSFML::Coloras avec4uniform (CSFML normalises 0β255 β 0.0β1.0 for you).
Added β audio
-
Sound#dup/ clone,Sound#bufferreader. -
Sound#pan/ pan=,Sound#min_gain/max_gain (and=),Sound#max_distance(and=),Sound#spatialization_enabled?/ spatialization_enabled=,Sound#directional_attenuation_factor(and=) β the full remaining 3D-audio surface from CSFMLβs SoundSource. -
Same set on
Music:pan, gain clamps, max-distance, spatialisation, directional-attenuation. -
Music#channel_count,Music#sample_rateβ stream introspection. -
Music#loop_points/ loop_points= β set the looping window inside a track ([offset_time, length_time] pair ofSFML::Times). -
Music.from_memory(bytes, **opts)β stream from a Ruby String of bytes (in-memory MP3 / OGG / FLAC). Callerβs bytes must outlive theMusic(we pin the Ruby buffer). -
SoundBuffer.from_memory(bytes)β decode.wav/.ogg/.flacfrom RAM. -
SoundBuffer.from_samples(samples, sample_rate:, channel_count:, channel_map:)β build a buffer from a Ruby Array of int16 samples. Default channel maps for 1- and 2-channel content. -
SoundBuffer#dup,SoundBuffer#sample_count,SoundBuffer#samplesβ sample-level introspection.
[3.0.0.3] β 2026-05-09
Added β typography
-
Font#familyβ human-readable family name fromsfFont_getInfo. -
Font#has_glyph?(codepoint)β accepts an Integer codepoint or a single-character String. -
Font#kerning(a, b, character_size:, bold: false)β wrapssfFont_getKerning/getBoldKerningfor accurate glyph pairing. Used in advanced text layout. -
Font#line_spacing(size),Font#underline_position(size),Font#underline_thickness(size)β typography metrics for the given character size. -
Font#texture(size)β borrowedSFML::Textureof the glyph atlas (handy for debug visualisations of whatβs been rasterised). -
Font#dup/ clone β independent deep copy. -
Font.from_memory(bytes)β load from a Ruby String (embedded assets, network responses,data:URLs). -
Text#find_character_pos(index)β exactVector2position of the character at the given byte index. Critical for caret / selection rendering in text inputs. -
Text#letter_spacing/ line_spacing getters (the setters were already there). -
Text#dup/ clone β independent copy with the same string and font reference. -
Text#transform/ inverse_transform β theSFML::Transformthe renderer applies when drawing this Text.
Added β Image / Texture / RenderTexture
-
Image.from_memory(bytes)β decode PNG / JPG / BMP / TGA / GIF / HDR / PSD from a Ruby String. Mirror ofImage#save_to_memory. -
Image#copy_from(source, at:, source_rect: nil, apply_alpha: false)β stamp a region ofsourceinto self. Useful for hand-built texture atlases or composite images. -
Texture.create(width, height)β allocate a blank GPU texture; pair withTexture#update(image)to stream pixels. -
Texture.maximum_size/Texture.unbindβ class-level helpers. -
Texture#bind(coord:)β manually bind for raw OpenGL interop. -
Texture#srgb?,Texture#generate_mipmap,Texture#dup. -
RenderTexture.maximum_anti_aliasing_level,RenderTexture#srgb?,RenderTexture#generate_mipmap. -
RenderTexture#active=, push_gl_states, pop_gl_states, reset_gl_states β same GL-state machinery as RenderWindow.
Added β Window / RenderWindow polish
-
RenderWindow#focused?/ request_focus / position / position= / srgb?. -
RenderWindow#visible=, key_repeat_enabled=, joystick_threshold=. -
RenderWindow#active=, push_gl_states, pop_gl_states, reset_gl_states β for mixing raw OpenGL calls withSFMLrendering. Surround custom GL with push/pop so SFMLβs internal state survives. -
RenderWindow#wait_event(timeout:)β block until the next event ortimeoutelapses (aSFML::Time). For low-power / event-driven apps that donβt need a 60Hz update loop. -
Window#cursor=, cursor_visible=, cursor_grabbed= β parity with the same setters that already existed onRenderWindow. -
Window#joystick_threshold=,Window#context_settings,Window#wait_event(timeout:).
Added β Shader
-
Shader#bind,Shader.unbind,Shader#native_handleβ for raw GL interop and debug introspection.
Fixed
-
SFML::App._dispatchnow forwards:resizedevents to bothon_resize(width, height)andon_event(event). The 3.0.0.2 refactor accidentally routed:resizedonly through the structured hook, which broke any app that forwardedon_eventto a sub-system (e.g.def on_event(e) = @gui.on_event(e)) β the GUI never got told to refresh its view + reflow on resize. Both hooks now receive the event; apps that already useon_resizeare unaffected.
[3.0.0.2] β 2026-05-09
Added
-
SFML::Appβ subclass-friendly main loop. Removes the boilerplate of window creation, event pumping, dt management, and clear/display so a small app fits in a few methods. -
Class-level configuration DSL for
SFML::App. Defaults that used to be passed to.newcan now be declared in the class body and inherited:ruby class MyApp < SFML::App width 800 height 600 title "Smooth" framerate 120 antialiasing 4 background SFML::Color["#1a1a1a"] endPer-instance kwargs to.newstill override on a case-by-case basis. Available macros:width,height,title,framerate,vsync,background,style,fullscreen,antialiasing,context. -
SFML::ContextSettingsβ configures the OpenGL context the window backs onto: anti-aliasing level, depth/stencil bits, GL version. The fifth argument tosfRenderWindow_createis no longerNULLby default; passantialiasing: 4(orcontext: SFML::ContextSettings.new(...)) toRenderWindow.new/SFML::App.newto turn on MSAA. Read back what the driver actually gave you withwindow.context_settings. WrapssfContextSettingsandsfRenderWindow_getSettings. -
on_keyβ class-level keybinding DSL. Bind a key to an instance method, a Proc, or a block; bindings inherit through subclasses with later definitions shadowing earlier ones:ruby class MyApp < SFML::App on_key :escape, :quit on_key :f11, :toggle_fullscreen on_key :p do |app| app.toggle_pause end endBindings live as the classβskey_handlersHash; the same DSL is also available onSFML::Scene, where scene-level bindings shadow app-level ones for the active scene. -
pause/resume/toggle_pause/paused?onSFML::Appβ while paused,update(dt)is skipped butdrawcontinues, so a pause overlay can be drawn on top of a frozen scene. -
on_resize(width, height)hook onSFML::AppandSFML::Sceneβ replaces thecase event in {type: :resized, size: {x:, y:}}boilerplate that used to live insideon_event. Default forwards to the active scene. -
SFML::Sceneβ base class for stateful screens (menu, gameplay, results screen, settings overlay, etc.). Lifecycle hooks (setup/update/draw/on_event/on_resize/teardown), its ownon_keyDSL, and aswitch_to(other)shortcut that delegates to the host app. The host app picks a starting scene with theinitial_scene SomeSceneclass macro;App.switch_totears down the previous scene before callingsetupon the new one. -
New example 24_scenes β title β play scene pair built on
SFML::Scene+initial_scene. -
New example 04_app_class β bouncing ball on top of
SFML::Appwith class-level config andon_keybindings (replaces the old04_game_classexample).
Changed
-
SFML::App._dispatchno longer auto-quits on Esc. Apps that want it bind it explicitly withon_key :escape, :quit. The window-close button (:closed) still always quits. -
Audio specs (anything under
spec/sfml/audio/) are now auto-tagged:audioand skipped by default on macOS, where CoreAudio + the CSFML OpenAL backend occasionally hang the test group. Opt-in withbundle exec rspec --tag audio. Linux runs the full suite as before.
[3.0.0.1] β 2026-05-07
Added
-
Window#icon=andRenderWindow#icon=β set the windowβs title-bar / taskbar icon from anySFML::Image. WrapssfWindow_setIcon/sfRenderWindow_setIcon. New example 21_window_icon builds a procedural 32Γ32 ruby-style icon to demo the API. -
Image#save_to_memory(format)β encode an image to a Ruby String of bytes in the given format ("png","jpg","bmp","tga"), without touching the disk. Useful for screenshots over the network, data: URLs, or piping into other image-processing libraries. WrapssfImage_saveToMemoryplus thesfBuffer_*helpers in libcsfml-system. -
Shader array uniforms β
shader[:positions] = [[x, y], ...]and similar for vec3 / vec4 arrays; also acceptsVector2/Vector3elements interchangeably. New explicitShader#set_float_arrayforuniform float arr[N];(which canβt be inferred via[]=because itβd collide with the vec3 case). Wraps thesfShader_set{Float,Vec2,Vec3,Vec4}UniformArrayfamily. -
Window#minimum_size=/ maximum_size= and the same onRenderWindowβ clamp how small or large the OS lets the user drag the window. Accepts[w, h],Vector2, ornil(clears the limit). WrapssfWindow_setMinimumSize/setMaximumSizeand the RenderWindow equivalents. -
Listener.velocityandListener.coneβ finish the 3D-audio surface on the listener side. Velocity feeds the Doppler effect for sources whosedoppler_factoris non-zero; cone (aSoundCone, or a Hash convertible to one) attenuates sources outside a directional pickup pattern. -
3D-audio polish for
SoundandMusicβ now exposevelocity,doppler_factor,direction, andcone(via the newSFML::SoundConevalue class βinner_angle,outer_angle,outer_gain). Cone setter accepts both aSoundConeand a Hash. Pluseffect_processor=for installing a real-time DSP Ruby callable on the audio thread (->(samples, channels) { ... }); passnilto remove it. The DSP path is documented as Ruby+GVL-limited and best for very light effects only. Wraps the correspondingsfSound_*andsfMusic_*setters/getters plussetEffectProcessor. -
SFML::VertexBufferβ GPU-resident vertex buffer (VBO). Same shape asVertexArraybut vertices live on the GPU, so a draw call ships only an OpenGL handle instead of re-uploading every frame.new(vertices, primitive_type:, usage:)(one of:stream/:dynamic/:static),update(vertices, offset:)for partial uploads,draw_range_on(target, first, count)to draw a slice.VertexBuffer.available?reports whether the GPU supports VBOs at all (fall back toVertexArrayif it doesnβt). Wraps thesfVertexBuffer_*family plus thesfRender{Window,Texture}_drawVertexBuffer{,Range}draw paths. -
Window.from_handle/RenderWindow.from_handleβ wrap an existing OS-level window (HWND, NSView*, X11 Window xid). The outside framework owns the windowβs lifecycle;SFMLjust renders into it. Pair with native_handle to interop in the other direction. WrapssfWindow_createFromHandle/sfRenderWindow_createFromHandleand the matchinggetNativeHandlegetters. -
SFML::SoundStreamβ procedural audio source. Subclass it and override on_get_data to return an Array ofInt16PCM samples (ornilto stop); optionally override on_seek(time) to supportplaying_offset=. Same playback / 3D-positional API asSoundandMusic(volume, pitch, looping, position, attenuation, min_distance, relative_to_listener). Wraps the fullsfSoundStream_*family. Includes example 23_sound_stream β a real-time sine synth with arrow-key pitch / volume control. -
SFML::Network::SocketSelectorβ multiplex many sockets onto one blockingwait.add/remove/clear/wait(timeout:)/ready?(socket). Polymorphic acrossTcpListener,TcpSocket,UdpSocket. Thewaitcall releases the GVL, so other Ruby threads keep running during the syscall. Wraps thesfSocketSelector_*family. -
SFML::Network::Ftpβ CSFMLβs FTP client wrapped as idiomatic Ruby:connect,login/login_anonymous,working_directory,directory_listing,change_directory,parent_directory,create_directory,delete_directory,rename_file,delete_file,download,upload,send_command,keep_alive,disconnect. Each call returns aResponse(orDirectoryResponse/ListingResponse) with ok?, status, status_symbol, message, plus directory or names where applicable. Network calls release the GVL. Same caveat as Http β Ruby stdlibNet::FTPis the better choice in production. -
SFML::Network::Httpβ CSFMLβs HTTP/1.x client in idiomatic Ruby form.Http.new(host, port:)plus#send_request(method:, uri:, fields:, body:, http_version:, timeout:)returns anHttp::Responsewith status (Integer) / status_symbol (:ok,:not_found,:connection_failed, β¦), body, field(name), http_version. Markedblocking: trueso the GVL is released during the network round-trip and concurrent Ruby threads can run. WrapssfHttp_*,sfHttpRequest_*,sfHttpResponse_*. Note: for any non-trivial use (TLS, redirects, JSON, retries), Rubyβs stdlibNet::HTTPis the better tool β this binding exists for parity with CSFML, not because we recommend it. -
SFML::Sensorpolling module βavailable?(type),enable(type),disable(type),value(type)for the six sensor types (:accelerometer,:gyroscope,:magnetometer,:gravity,:user_acceleration,:orientation). The:sensor_changedevent variant now decodes itssensor:andvalue:payloads. WrapssfSensor_isAvailable/sfSensor_setEnabled/sfSensor_getValue. -
SFML::Touchpolling module βdown?(finger)andposition(finger, relative_to: window). Touch event variants (:touch_began,:touch_moved,:touch_ended) now decode theirfinger:andposition:payloads (previously fell through to empty data). WrapssfTouch_isDown/sfTouch_getPosition/sfTouch_getPositionRenderWindow. -
Sound#playing_offset/playing_offset=andMusic#playing_offset/playing_offset=β read or seek the playback head as aSFML::Time. Setter also accepts a Numeric (interpreted as seconds). WrapssfSound_setPlayingOffset/sfMusic_setPlayingOffsetand the matching getters. -
Stencil buffer support β new
SFML::StencilModevalue class with symbolic comparisons (:equal,:always, etc.) and update operations (:replace,:keep, etc.). Pass it viastencil_mode:toRenderTarget#drawfor two-pass mask/clip effects, and clear the stencil withtarget.clear(color, stencil: N)ortarget.clear(stencil: N). WrapssfRenderWindow_clearStencil/clearColorAndStencil(and the RenderTexture twins) plus the existing stencil_mode slot insfRenderStates. New example 22_stencil_mask demonstrates a cursor-following spotlight that clips an animated rainbow background.
Fixed
-
at_exithook now writes the unhandled exception (message, class, backtrace) to stderr before callingexit!. Previouslyexit!short-circuited Rubyβs terminal exception reporter, so an error insetupor any other top-level user code looked like a silent exit.
[3.0.0.0] β initial release
First public cut. Targets CSFML 3.0.0 (released March 2025) and Ruby β₯ 3.2. API surface complete for the SFML 3.0 spec; some engineering polish still pending (gem build end-to-end verification, RBS signatures, hosted RDoc).
System
-
Vector2,Vector3β operator-friendly value classes withcoerce(2 * vec), pattern-matchdeconstruct,length,normalize,dot/cross, conversion helpers -
Rectβ single class for float / int rectangles withcontains?,intersects?, deconstruction -
Time,Clockβ monotonic timer, immutable Time arithmetic
Window
-
RenderWindowβ main 2D drawing surface -
Windowβ bare GL-only window for raw-OpenGL apps -
Eventβ pattern-matchable hash-like value (case event in {type: :key_pressed, code: :escape}) -
Keyboard,Mouse,Joystickβ polling APIs with symbol-named keys / buttons / axes -
Cursorβ 21 system cursor types +from_pixelsfor custom shapes -
Clipboardβ UTF-8 in / UTF-8 out via the unicode-string CSFML path -
VideoMode
Graphics
-
Color,Image,Texture,RenderTexture -
Sprite,CircleShape,RectangleShape,ConvexShapeβ share aTransformablemixin (position, rotation, scale, origin, move) -
Vertex,VertexArrayβ batched geometry; six primitive types -
Font,Textβ UTF-8 strings,local_bounds/global_bounds, Font.find searches common system paths plus a bundled DejaVu Sans -
Viewβ 2D camera, includingfrom_rectand viewport for split-screen / minimap -
RenderStates,BlendModeβ full blend mode catalogue, kwargs shortcut onwindow.draw(thing, blend_mode: SFML::BlendMode::ADD) -
Shaderβ load from file or memory, uniform setter that dispatches by Ruby type (shader[:time] = 1.5,shader[:tex] = my_texture,shader[:tint] = SFML::Color.red) -
Transformβ standalone 4Γ3 matrix value class, chainable -
RenderTarget#drawacceptstexture:,blend_mode:,shader:,coordinate_type:,render_states:kwargs -
RenderTarget#draw_primitives(vertices, type)β one-shot batch rendering without aVertexArrayobject
Audio
-
SoundBuffer,Sound,Music -
3D positional audio on Sound and Music (position=, attenuation=, min_distance=, relative_to_listener=)
-
Listenerβ global βearβ withposition,direction,up_vector,global_volume -
SoundBufferRecorder+SoundRecorderstatic helpers β record audio from the system mic into a SoundBuffer
Network
-
Network::IpAddressβ value class withfrom_string,from_bytes,LOCALHOST/ANY/BROADCASTconstants,local,public -
Network::TcpSocket,Network::TcpListenerβ TCP client + server, blocking and non-blocking modes -
Network::UdpSocketβ connectionless datagrams -
SocketStatusreturned as symbols (:done,:not_ready,:disconnected,:error,:partial) -
Intentionally not wrapped:
Http,Ftp(use Ruby stdlibβsNet::HTTP/Net::FTPβ theyβre nicer)
Helpers
-
Appβ subclass-friendly main loop withsetup/update(dt)/draw/on_eventhooks. -
Assetsβ cached, search-path-driven loader.SFML::Assets.font("DejaVuSans"),.texture(name),.sound(name),.music(name). Default search root is<dir of $0>/assets/. -
Bundled DejaVu Sans (Bitstream Vera license) β
SFML::Font.defaultworks without a system font install
Engineering
-
Two-tier API:
SFML::C::*thin FFI bindings,SFML::*idiomatic Ruby on top. Most user-facing classes are ~50β150 LOC each -
RenderTargetmixin βRenderWindowandRenderTextureshare every drawing method through CSFML_PREFIX dispatch -
287 RSpec examples, all hitting real CSFML
-
20 self-contained example folders under examples/
-
CI matrix: Ubuntu + macOS Γ Ruby 3.2 / 3.3 / 3.4
-
Linux CI builds CSFML 3 from source (cached) and runs specs under
xvfb-run -
extconf.rbchecks every requiredlibcsfml-*plus probessfClock_isRunning(CSFML 3.0+ only) βgem installaborts with a helpful message on CSFML 2.x -
Same probe re-runs at
require "sfml"time as a runtime sanity check -
at_exithook stops liveSound/Musicand bypasses Rubyβs finalizer pass viaexit!β eliminates a class of GL/OpenAL-teardown segfaults that plagued every non-trivial example -
RDoc 7 (Aliki theme) generated via
rake rdoc