PR 343's Filmer becomes a Luau plugin mod (kept in contrib/plugins/filmer) on general APIs instead of
its own C++:
- reskate.skater.carry: something held out in one or both hands and aimed, the body crouched (feet
kept) and hunched over it, turned on the spot after it (Extension/Skater/carry.cpp, from the PR's
filmer_hold.cpp, with tests)
- shown = "everyone" | "others" | "me" on skater.pose, reach and carry: the pose sent to the other
players and the one drawn here are split when asked
- reskate.camera.cycle and the camera_cycle event: a plugin's camera as the last step of the camera
height button's cycle, after first person
- reskate.session.nametags(false) holds the names over the other players off
- board.hide(bone, {others = true}) hides it in the board the others are sent too (a sent-pose filter)
- outfit.set takes hand wear slots; input.bind takes an action with no key of its own
A dedicated server's park mods could only be spawned from its console, an admin's chat or a vote,
so a server plugin could not bring out the park its game is played in. A new permission,
server.parks, gives a server copy reskate.server.parks(), which lists the park mods set up with
whether each fits the map running now and is spawned (its objects and minutes left), and
reskate.server.park_spawn(name, minutes?) and park_remove(name), which return ok or false and why.
They go through park-mod add and remove, so the park limits, the map check and the chat lines stay
the server's. Their "[parks]" lines are logged "by plugin <id>". A name is a park mod's own (1 to 16
of a-z 0-9 - _) and minutes are 1 to 1440, or none for until removed. Reading the park files is not
part of this: a plugin brings what it needs to know about a park in its own package.
dingosdk_server_plugin_tests spawns and removes a park mod through a plugin and checks what it is
refused; dingosdk_plugin_tests checks the API on a server copy, and that a player's copy and a
plugin without server.parks cannot use it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hs7xxJDf6SDcQUaXnzmtL5
- reskate.entities.blueprints lists the game's object blueprints (meshes only if asked),
and reskate.entities.bounds gives a blueprint's box, so a mod can pick a prop by list or at random
- Attached objects take upright, turn and ground (a floor found within reach below), the "root"
joint, and a 6th options argument with solid; spawned props' bodies are found and ghosted
- reskate.skater.hide, reskate.world.pick, and skater.get gives right and switch
- reskate.console.command takes an optional 4th table of subcommands; the console lookup
suggests plugin commands word by word, and plugin commands lists the subcommands
- objbody: a test command for finding which body setter takes a prop out of collision
The SDK knew grind exits: reskate.skater.grind_exit took a toe/heel/left/right wish, and C++ worked
out the rail's direction, toe and heel from the stance and facing, the 1.8 m/s and the strength.
That logic is now the grind-exits mod's own Lua (plugin/exits.lua, kept on this machine). What has
to run on the physics thread is general:
- Extension/Skater/launches: every launch of the local skater (ollie, grind, no_comply, boneless),
classified by its call site and the state before it, with the board's direction of travel; the
`launch` event for plugins with events.skater; reskate.skater.shape_launch(from, {across, along,
up}) sets those speeds against the travel, one plugin a kind.
- reskate.skater.get() gains `right` (the root's right axis) and `switch` (the game's stance flag).
- Extension/Skater/pad_hide: reskate.input.hide's pad filter, out of the old grind exit file.
Removed: reskate.skater.grind_exit, the grind_exit event, GrindExitWish and GrindPop.
Physics state 701 is a grind too (the game checks it with 400 in about a dozen places; the
2026-10-11 measurement only reached the 400s): pops out of it were dropped, and skater_state called
it "other". Launches, skater_state ("grinding") and the trainer's grind pop all count it now.
Tests: the grind-exits plugin test drives the new path (11 checks of its own).
- reskate.animation.mirror makes a clip for the other stance (Left and Right trade across the board's
length, each joint from its rest; the board mirrored as itself), and info gives a clip's stance. The
game's trick clips stand goofy: the studio mirrors one for a regular skater, which played half a
turn round in game.
- The studio no longer holds the skater with noclip: he left his board and the flight pose showed
through. His board is stopped once instead; while drawn in the room No Bail guards him, and the
game's own placement goes back into the pose before its physics.
- The whole board is held rigid while a clip moves it, deck mount included.
- The room closes when the game's menu leaves the Skaters page, and the studio closes with it.
- The studio's first camera angle is the PR's, taken once the room's joints are read.
- A log line every 2 s while a clip plays (Clip pose: updates, renders, scale, heights, the joints
that change most), kept while the room's pose is still checked in game.
- A clip marks the joints it only turns (Clip::turned_only, kept in the clip file): those keep the
skater's own position, as the game does; a game trick no longer changed his size.
- While a clip moves the board, its trucks and wheels are held as they were on the deck: the board
physics shook them.
- The character room's facing is taken once: the Skaters page turned its skater on a right drag, and
ours turned with it and sprang back.
- A plugin's cursor reads the middle button from Windows and raw input as well: it did not reach
ImGui in game.
- reskate.animation.game_clips lists the game's animations and "game:<name>" plays one: the
skater's Eclipse clips decoded from its data (Extension/AnimationStudio/game_clips, ported from
ReSkate Studio's animation export), matching make_trick_library.py's clips.
- reskate.animation.play's floor stands a clip on the floor where the skater is, its board's lowest
point on it, as the pull request's studio did; the game's trick clips no longer sink.
- Animator Studio lists the game's tricks from its data; the Python tools are gone.
reskate.session.touch, touching, hide, hidden and raycast, and the touch and touch_end events.
The session publishes every skater's body as capsules while a plugin reads them; a hidden
player goes through the same path a throwdown's hidden players do.
- reskate.room.open, leave and state, with the room permission: ReSkate walks the game's menu to the Skaters page (its navigation events and RB on an internal scripted pad, as PR 297 and PR 230 did), draws the local skater on the room's floor and hides the room's own skater and board; other players are not sent the room. Extension/World/character_room, the room placement and hiding in skater_animation, and post_native_ui_event made general.
- reskate.input.text: what is typed while the plugin's screen is open; while it types, Esc is the plugin's.
- Animator Studio opens in its room (the Studio room setting, as the PR's), under its loading screen, or where the skater is when the walk fails; its card's name, trick and numbers are typed into in place.
- The studio plugin draws PR 297's screen itself: skate.'s Trick List menu and card, the joint timeline with key rows, dragging joints on the skater, keyboard and pad controls with their prompts, the unsaved-changes card, the recording strip and the loading screen. It lists a trick library made with tools/make_trick_library.py (the PR's, here beside it), and checks itself with studio test.
- Drawing: d:rough_rect, d:halftone, d:scribble, d:clip, d:measure, a text wrap width, the title_large font, text up to 400, and the loading screen's kickflipping board as d:game_image("loading_board") with a frame.
- reskate.ui.screen with panel = false: input taken, nothing drawn, the plugin draws it.
- reskate.skater.joint gives each joint's parent; reskate.skater.pose takes an offset.
- reskate.animation: play's at and paused, seek, pause and time; info, sample, joints, trim, edit (keys baked onto a clip) and save; clips named "data:<path>" from the plugin's data folder, "clip:<n>" and "edit:<name>".
- reskate.ui.screen's dock and width: a panel down one side, the game showing beside it.
- reskate.input.cursor: the mouse over the game while the plugin's screen is open.
- contrib/plugins/animator-studio: the Animator Studio of PR 297 (22sh, Fourth Studio, Norms) as a plugin: record a trick, key joints on a timeline, save it, and the trick plays it in game.
- reskate.skater.joint and reskate.session.joint: where any joint of your skater or another player's is.
- reskate.physics.tuning, find and tune: the trainer's tuning values, a plugin's set over the player's own and never saved.
- reskate.skater.set_velocity: the board's velocity set or added to at the next on-board physics step, in the air too.
- reskate.settings.set and the settings.write permission: a game setting held while the plugin keeps it, then put back; gameplay settings stay locked in multiplayer.
- reskate.skater.pose: joints turned and scaled on top of the animation, in the pose drawn and sent.
- The mesh tests build anim_core, which the session's joint publishing now uses.
- reskate.input.hide hides the right stick and the stick clicks, and reskate.input.mouse reads the mouse's movement and wheel.
- reskate.skater.cruise: cruise control up to a speed, optionally easing down to it.
- reskate.skater.reach and hand: an arm reaching for a point (two-bone IK, Extension/Skater/arm_reach), in the pose drawn and sent, and where a hand joint is.
- reskate.entities.set's attach: an object kept on a joint of your skater or another player's, moved every frame.
- reskate.screen.look and slap: the Filmer branch's VX1000 post-process as a fixed-parameter camcorder look drawn by the overlay.
- match.teleports lets through only the publishing plugin's own teleports, and only while its
match runs (its HUD is active, or the native flag is one of its modes); it was merged across
every plugin and checked no match.
- A mode's timer of 0 or past an hour no longer makes its card do nothing: the native flag takes
it as 1 to 3600 s. flag.begin's seconds are checked as 1 to 3600, as the flag takes them.
- skater.push and hold(true) return false with a reason without the stock physics, where they
were dropped unseen.
- telemetry's slam and struck are news since each plugin's own last read; reading them cleared
them for every plugin.
- A banner or callout of a new match shows whatever serial it starts from, and a document without
the slot no longer resets its serial.
- SmokeyDawg58's placement no longer divides input.wheel's whole notches by WHEEL_DELTA again.
The new services and throwdown kit API files use add_functions and the shared
helpers; add_functions opens a read-only parent for reskate.throwdowns.flag.
throwdowns.release_flag stays removed, as plugins has it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A lock tool like noclip and boosts. The player's game enforces it: the roster
carries guest_ollies (protocol 53), and the jump hook gives a locked ollie no
upward speed. Plugins get player.permissions.ollies.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The shared API helpers (plugin_of, need, checked_text, position_of) are in
plugin_api.h, defined once. The API plugins see is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A mod's reskate-plugin.json can declare "variants" {folder, order, displaces}: each <folder>/<name>/
is a variant, the one chosen (else the first of its order) loads, and every other mod whose layout
lists a displaced bundle is set aside for the run. Choices are kept in
%LOCALAPPDATA%\ReSkate\variants.json. Plugins read and choose their own mod's variants with
reskate.package.variants and reskate.package.choose (permission "variants"), and fit every board
for a deck that is not the game's own with reskate.board.fit {plates, axle}.
The board-break plugin, which ships inside the Board Break deck pack, declares the pack's decks as
variants, picks the deck on its own page and with `boardbreak deck`, reads each deck.ini and fits
the boards. Gone from the SDK: breakable_deck, the deck catalog, the MODS page's deck card, the
boarddeck command and the Board_Break_<Name> folder naming.
Plugins register modes (card, replaces, order, flag, players) and publish documents through
reskate.throwdowns.ui: the setup page, the waiting card, HUD slots themed on the game's HUD_<theme>_*
widgets, the match panel, flags and match restrictions. SmokeyDawg58's native plumbing
(throwdown_menu.cpp and its .inl files) renders them and posts throwdown_ui events back. kit::flag
is the one native flag registration. General services added for it: reskate.files, reskate.ui.dialog,
reskate.skater push/hold/bone_cam, reskate.camera.pad_flight, reskate.physics competition,
reskate.session.world, reskate.tricks feed/gesture, and world entities.
His ten modes are now Lua in his plugin: the rules, referee and wire (td/rules, referee, wire), and
every page and HUD document (td/ui*.lua). Extension/Modes and reskate.modes are gone, along with
every race and 1-UP branch in the SDK. The plugin test drives each mode through kit events.
A native setup page is never written to while it closes into flag placement: its rows are not
republished, the stock page is put back once the exit is over, and the stock Players slider is left
alone while a plugin flag is out. This fixes the crashes on the Deathrace button and on 1-UP's
Confirm.
When a plugin mode's flag goes down in a session, the relay offers it to the other players
as that mode's: a new mode message (kind 17) names it, its flag and its player count, and
its offer's series is one older versions do not show. A player whose plugin has the same
mode gets a copy with the mode's own flag mesh and joins it natively; the copies are held
at ten players so none fills and starts a Spot Battle, and the mode's player count decides
who may still join. throwdown_mode events now carry host, leader, player and players: the
host hears joined and left, a player in another's flag hears joined, left, closed and
start, and start names who plays, the leader first. The plugins run the match from there.
A mode can take a stock throwdown's place on the picker (replaces = "skate", "spot_battle"
or "jam"), so his R.E.S.K.A.T.E. sits where S.K.A.T.E. does.
reskate.throwdowns.mode{...} adds a mode to the game's own Throwdowns page: a card on
the picker, the real Spot Battle setup page relabelled with the mode's name, logo,
description, players, timer and rows (sliders, choices, buttons), and the native start
flag. The plugin hears throwdown_mode events (opened, setting, button, placed with the
flag's position and heading, start, leave, cancelled) and runs the mode itself;
release_flag takes the flag down. The flag's queue never starts a Spot Battle: its
waiting card's Start goes to the plugin, MaxPlayers is held at 10 and it is never
relayed as a drop. After SmokeyDawg58's one_up_menu and one_up_placement
(reskate-custom-mods), generalised over a mode registry.
The page is his 4-column logo grid whether or not a plugin has a mode. Its widgets and
grid records, and the game assets it uses that only some levels load, ship in
ReSkate.dll as the throwdown_menu built-in pack, taken from his asset mod's FBMOD
(dingosdk_ebx_pick trims the asset list in place). A mode's logo is a texture path in
its own mod, so no mod edits the shared list. The FPV drone is no longer a built-in pack.
Native menu data: text initialization, change-only writes, retained array publication,
owned-model rollback. Tests: registry and setup helpers, the plugin API, a test plugin
with two modes.
Hall of Meat (contrib/plugins/hall-of-meat) and grind exit triggers
(contrib/plugins/grind-exits) are Lua plugins: the bail model, its Meat card,
each map's best, the trigger rules, settings, console commands and menu panels
are theirs, with their own checks that dingosdk_plugin_tests runs.
What has to run in the game stays in core as plugin services:
- every physics step of the skater (skater_physics, the physics_step event,
permission events.physics);
- the skater's x-ray (xray, xray_render, xray_skeleton; reskate.skater.xray and
the draw handler's d:skeleton);
- skate.'s bottom left HUD corner (hud_corner; reskate.hud.corner);
- the game's slow motion, never in a session (game_speed; reskate.time.slow and
speed, permission game.speed);
- the side of the next pop out of a grind and pad controls kept from the game
(grind_exit; reskate.skater.grind_exit, the grind_exit event, reskate.input.hide);
- skate.'s own pictures by name (game_images; d:game_image), d:gradient and a
font for drawn text.
Removed: Extension/HallOfMeat, grind_exit_control and its commands, the HALL OF
MEAT and GRIND EXITS add-on pages, home tile, hub and native menu rows, their
menu models, and the hallofmeat and grindexit built-in commands.
The three features are Lua plugins in contrib/plugins (fpv-drone, board-break,
road-rash), built on what this adds to the plugin API: flight input, gamepad and
joystick reads with input capture, a rolled camera, a package's own sounds and a
synthesised motor (plugin_sound, plugin_wave, motor_synth), the skater's physics
events (skater_events), items worn over the outfit (outfit_overlay, skater_items),
the board's bones (board_pose), skater animation (anim_core), plugin images,
throwdowns started for chosen players, and server copies of plugins on a lobby
host and the dedicated server (server_plugins).
Removed from core: Extension/RoadRash, Extension/BoardBreak, the drone's flight,
radio, follow, OSD, beacon, outfit and sound code, its prop models (native_prop),
the DRONE, BOARD BREAK and ROAD RASH menu pages, home tiles and native menu rows,
their console commands, the drone follow debug action, the drone marker packet
(kind 36 stays unused; the roster keeps its byte) and the server's drones setting.
Kept in core, since every board needs it whichever plugins run: the breakable
deck packs (breakable_deck: which deck, its label and wheel spacing, the
boarddeck command and the BREAKABLE DECK card on the Mods page), and board_pose
keeping a deck pack's stretches out of sight, the baseplates on the deck and the
wheels at the deck's spacing on every board.
- Skater: skater.state() and the skater_state and bail events (events.skater); noclip and boosts
through the console's own queue, under the host's rules (skater.control); a save point of the
plugin's own (trainer); the game's HUD hidden while any plugin asks (hud).
- World: park editor objects listed, placed, moved and removed through the editor's own edits and
the session's object rules (world.objects); time of day, world controls and park rotation as
the World menu sets them, refused where the host chooses (world.environment); fast travel and
levels, refused for guests (travel); AI skaters, outside sessions only (world.ai).
- Session: other players' skaters as last heard (session.skaters, a feed the session publishes
each frame, plugin_session_feed.h); a plugin's tag above a player's nametag (session.nametags);
voice volume (voice.control); chat lines as events (chat.read) and sending one, one every 3 s
(chat.send); throwdown state and events (throwdowns).
- Music from outside players (music), progress (progression.read) and game settings
(settings.read), read only; named actions on keys or pad combos, pressed while the game has the
input (input); full-screen screens with the input, closed by Esc (ui.screen).
- Libraries and events between plugins: expose, require_plugin, emit, on_plugin; plain data is
copied across VMs and a plugin in a call cannot be called back into.
- net.http: HTTPS to the hosts reskate-plugin.json's new "domains" lists; no redirects, cookies
or Windows sign-in; private and local addresses refused; 10 a minute, 4 waiting, 1 MB back.
- Left for engine work (listed in the design doc): respawn and freeze, manuals, the camera, trick
animations, replays, starting throwdowns, the game's own soundtrack, overlay images, rebinding
plugin keys in the Binds page, local-only chat lines.
- reskate-test has a wider module (ptest noclip, boost, hidehud, object, night, day, ai, screen,
bind, music, chat, web by hand); reskate-hostile has chat-spam, edit-spam, travel-spam,
web-elsewhere, bind-spam and screen-loop.
All host tests pass; not yet tried in game.