Repository navigation
v0.1.3
A timeline for cutscenes; a glTF character of your own in the hero's place - auto-rigged,
weight-painted in Crystal, drawn by the client with smooth weights or with its own
animations; a weapon fitted in its hand; a free camera and a modding guide. The notes:
- A timeline for cutscenes. The
Cutscenecomponent plays a Timeline - tracks of clips
on a time axis, as Unity's Timeline lays one out - edited in a dock under Crystal's 3D
view: object tracks walk, glide, turn, pose, show, fade and scale the scene's objects (or
the hero), a camera track glides the camera and hands it back, dialogue lines hold the
playhead until dismissed, screen fades and flashes, sounds and music, flags, warps,
battles, items and signals to code. Clips are dragged and resized on the lanes, the ruler
scrubs with a live preview in the 3D view (objects move, the camera clip moves the view),
Space plays; every edit autosaves and undoes. It starts on talking to the object, on
entering the map, or from code, with If flags, Once and Then flags; B skips it; the
hero stands still while the player can still advance the lines. Play in OpenFF starts
the client on the map with the cutscene playing (--cutscene=PATH). The whole thing is
plain data in the scene file, so a cutscene can also be written by hand or generated. - A weapon on a character, in the model viewer. The viewer's on a character toggle
puts one of the party's models (j101…) under a viewed weapon or shield, plays its battle
motions (b_b01: the idle, the swings) through the transport, and poses the weapon from the
hand joint each frame as the game does -R_te/L_tefor a weapon, the forearm for a
shield, then the game's grip turn and offset (btl.BattlePlayer.haveWeapon). For a glTF an
item definition names, the fit fields (scale, rotation, offset - what the client applies in
battle) move the model live and save to the definition, so an export is fitted to the attack
animations by eye; the Look card's On a character… opens the viewer that way. The game's
ownw###models take the toggle too, for comparison. Off, the viewer shows the model alone
as before. Under it:/api/model/joint(a node's matrix per frame of a motion, from the same
SBC walk the viewer's poses come from), a second model and an attach matrix in the viewer,
and a transport that can be pointed at another model. The Look card now shows for a shield
(armour with a model of its own) as well as a weapon. - The modding guide.
Guide\index.htmlin the release (the repository'sDocs/Guide):
short HTML tutorials with pictures - getting started, the map editor, a map of your own,
items and weapons, cutscenes, models/sounds/fonts, C# code, Steam mods - and a reference
of every component, timeline clip, file, setting and shortcut. Crystal opens it with
Help ▸ Guide (a Help menu is new: the guide's pages, the API reference, the samples). - Sample projects. The three sample mods ship in the release (
Samples\; the Showcase
also as a ready mod inmods\), and File ▸ Sample projects… copies one into a project
of your own - laid out as any project, the C# undercode/with a csproj against the
client's engine - to read, change and Run in OpenFF. - The project panel's two sides. The game's libraries and the mod's own folders were one
list, too tall for the panel with the mod's rows below the fold. A Mod tab now sits
beside FF3 / FF4: the tree shows one side at a time and each tab remembers the library
last browsed on it. The Behaviours section of the inspector no longer asks for C# code
first: the built-in behaviours attach on a project without any (they always could in the
client; the editor hid them). Game.Camera.MoveTodid nothing. In the game's free camera mode a set position is
rebuilt every frame from the target, an angle pair and a distance, so the position the
API wrote was overwritten before it was seen and the camera parked 16 units behind its
target. MoveTo/LookAt now set the angles and the distance from the line target -> position,
so a camera glide lands where it is told.Game.Hero.Freeze(keepInput: true)holds the hero still with the pad left on, for a
cutscene's lines; the plain Freeze() still takes the pad too.- Export .glb: a real skeleton, all motions, and no project needed. The export's skin
used to be one joint per matrix instance, all at the origin, animated with delta matrices:
playback was right, but in Blender the bones were dots scattered around the character and
no use for weighting a mesh. The skin is now the model's own node tree - bones parented
and placed as the game's SBC builds them, inverse binds from the same walk - and vertices
carry the game's weights, including the DS's envelope blends (several bones per vertex at
the knees, elbows and hips), checked against the viewer's matrices to 1e-2 over every
frame. + all motions exports every motion of the pack on the transport as separate
animations of one file. With a project open the file goes into the project'sexports/
as before, now with the textures as PNGs beside it; with no project - which used to
write somewhere unasked and then say "no project is open" - the browser's Save As takes
it where you like (/api/model/glb). - A character remade from Blender. The way back in for a mesh modelled over the export:
the model viewer's Remake from glTF… writes a skinned glTF over a model of the game's
(j101, a monster) in the game's own format, keeping its skeleton, envelope blends and
the SBC that builds them, so every.ncapmotion plays on the new mesh - in the OpenFF
client and the Steam game alike. Vertices go through the game's matrix stack slots by
nearest weights (one bone, or one of the blends the original had); a node drawn without a
slot gets its shape inline as the original does; runs are split at the game's 20,480-vertex
buffer and a model over its 32,768 is refused with the number to aim for. Undo remake
reverts;crystal mdl-reskin file.glb j101does the same at the command line. Checked by
round trip: the game'sj101exported, re-exported by Blender 5.1 and written back lands
on the original to 1/4096 through the idle and a swing; a 10,320-triangle subdivision of
it fights a goblin in the client. The staticmdl-importobserves the same limits now. - On OpenFF, the glTF itself - smooth weights and all. A model definition
(defs/models/j101.json:{ "model": "j101", "gltf": "assets/luneth-hd.glb" }, which
Remake writes on an OpenFF project) has the client draw the file in the game model's place
wherever it is drawn - field, battle, menus. The game's model still loads and animates;
the stand-in walks its SBC for the frame's joint matrices (shapes masked off, a NODEDESC
callback, the battle's own hand-joint callback still called) and skins the glTF through
them on the CPU with the weights as Blender painted them, the file's inverse binds times
the game's node matrices. Vertex colours are the game's own for the part - the scene's
light times the original material's diffuse and ambient plus emission - so it is as bright
as the native model beside it (measured 131.4 against 131.8) and dims with the scene.
Undo remake removes the definition with the overrides. The OpenFF client'sDrawModel
buffers, the Steam port's fixed 20,480 vertices a run / 32,768 a model / 256 shapes, now
grow to fit, so a dense game-format model draws too; on an OpenFF target the writers note
a model over the Steam limit rather than refuse it. - A mesh with no rig, rigged to the character. Remake with a plain glTF binds it to the
model's skeleton first (AutoRig,crystal mdl-autorig): fitted to the character's height
and feet, weighted from the nearest point of the original mesh's surface - the game's own
skinning, blends included - after the original is posed like the file (a modelled
character stands arms-down, the game's bind is a T; matched by proportions, the file
taken back into the bind pose through its new weights), then smoothed. The rigged copy
is written beside the file as<name>-rigged.glb. - The viewer skins a glTF with the game's motions. A skinned glTF whose joints are a
game model's bones (a remade export, an auto-rigged mesh) gets the model's transport:
its packs and motions, skinned in the browser from the model's node matrices per frame
(/api/model/rig-pose). Orbit and scrub to check the weights. - Weight painting in the viewer. weights on a skinned file of the project's: one
bone's weight as a heat map with the skeleton over it, a brush (add / erase / smooth,
radius, strength, mirror to the L_/R_ counterpart) on the mesh as posed, Alt+click to pick
the bone under the cursor, undo, and Save weights writing the four-bone weights into the
.glbin place and remaking the game model from it. The auto-rig's second pass (in the
bind pose, where the arms stand clear of the body) and its outlier vote take most of the
need away; the brush is for the rest. The brush is a ring on the surface under the cursor
and paints that surface - out along the mesh's edges to the radius, not a ball about the
point - so a sleeve is painted without the chest beneath it. The hierarchy lists a skinned file's bones as a
folding tree (click to pick the paint bone); bones and wireframe toggles draw the
skeleton and the mesh's edges over the shaded model, weights mode or not, and the heat
map can be turned off to paint on the textured model. - The auto-rig knows a chin from a chest. Two more steps for a mesh of other
proportions: each arm limb is turned about its joint onto the game's posed bone before the
carry into the bind pose (the matched pose is alike as a whole, not limb by limb, and the
difference would otherwise stay as a permanent bend of the forearm off its bone); and the
file is cut by its own shape into head (above the narrowest slice under the head), arms
(outside the torso's width in a slice) and the rest, each taking weights only from the
like part of the original. On the chibi that tookmuneoff the face,kubioff the eyes,
haraoff the sleeves andR_sakotuoff the hair in one go. Legs and a skirt are regions
too (a tunic follows the hips, never the legs), and the cuts - neck, hips, arm floor, torso
width, skirt - are sliders on the unrigged file with the found values shown and the frames
drawn on the model, saved beside the file and used by every rig of it after. - A fitted skeleton. The game's skeleton with its joints moved to where the file has them
(markers first - chin, wrists, elbows, knees, groin, placed by clicking the model - the
mesh's own rings for the rest), weights by distance to those bones within the regions, the
file carried into the T-pose about them;"fitted": truein the definition and the client
retargets the game's motions onto it, every bone its own name. Limbs of the file's own
lengths bend where the file bends. OpenFF only. - A model's own animations. A glTF look with animation clips plays them in the game's
motions' place, for the motions the definition names ("clips": roles like idle, walk, run,
attack, damage, magic, victory, or a motion's id or pack name), in step with the game's
motion or at their own pace; the rest stay the game's.Game.Hero.PlayClip/Npc.PlayClip
play a clip from C#. Crystal's transport plays a file's own clips, and own clips under the
viewer edits the map. - Weights you can reason about. assign paints a part onto a bone outright; the vertex
under the brush reads out its bones and weights; all bones colours the mesh by heaviest
bone with the hierarchy's rows in the same colours. Weights are kept as Blender keeps them- each bone's its own, no sum held to one while painting - so erase takes only that
bone's weight off and nothing is handed to a parent or a stray bone; a vertex may carry
nothing (it stays as the file has it; the readout says so) and the sum is made one on save.
- each bone's its own, no sum held to one while painting - so erase takes only that
- The model view's toolbox. The tools are icon buttons floating at the view's left -
look, bones, wireframe, heat map, all bones, the four brushes, the auto-rig's cuts and
markers, own clips - and the active tool's properties sit in the inspector as a card, so
the view never resizes as a tool comes and goes; the readout of the vertex under the cursor
floats over the view's bottom right. The middle button (or Shift with the right) drags the
view, in the model viewer as in the map editor. With a bone picked in the hierarchy, Up and
Down step to the next bone - from the 3D view too, so the bone under the brush is swapped
without leaving it. Every tool has a key on its button (Q look, B, W, H, C, 1-4 the
brushes, X, M, L), [ ] and { } step the brush, Ctrl+Z and Ctrl+S undo and save; painting,
Ctrl held erases and Shift smooths for the stroke, the right button dragged sets radius
(sideways) and strength (up) with the ring and the numbers following, Alt + drag orbits
and Alt + click picks the bone. Mirror is off unless ticked; G cycles the backdrop
(dark, grey, light, sand). - Normals, an importer's way. A
.glbasset in the project panel has a Normals card in
the inspector: from the file, or calculated from the triangles at a smoothing angle (across
the seams where the file split a vertex), applied into the file with the file's own kept
inside it for an exact Revert. For a model exported faceted. - A file's kind, and a weapon in your character's hand. A
.glbasset's Kind card in
the inspector flags it as a character, prop, weapon, shield, map or battle map when its name
and shape do not say (written into the file). A weapon's on a character preview now
offers the project's own characters as the body - a rigged export, an auto-rigged file -
skinned by the viewer and the weapon hung from its own hand joint, so equipment is fitted
on the character it will be worn by. - Which model a file plays as, in plain sight. A character file's In play card in the
inspector says which game model the client draws it in place of (the whole binding is one
file,defs/models/<model>.json, a click away), and switches or clears it by hand; the
Models list tags both tiles (→ j101on the file,← luneth-chibi-riggedon the model). - A free camera in the client. F7 on the debug overlay (F1): the mouse looks, WASD fly,
E/Q up and down, Shift and Ctrl the pace, the wheel too, R back to the game's eye, F7 or
Esc off. The game runs on with the player's input held off - a close look at what is drawn.
A drive'scamera x y z yaw pitchplaces it for a screenshot. - Textures at any size in OpenFF. The DS format's 64 × 64 (or 8 to 1024) is the Steam
game's ceiling, not the client's: on an OpenFF project Replace with a PNG… keeps a larger
picture at its own size astextures/<name>.png, exported with the mod, and the client
draws that in the texture's place - filtered smooth, mapped as before - while the package
keeps the downsized copy for Steam. - One character in a glTF: the Look. Picking a glTF as a game character's model in the
map editor no longer goes nowhere - a.hichrow can only name a game model - but puts a
Lookbehaviour on that one character (Path,Fitted): the game's model still loads,
walks and talks, the client draws the file in its place, skinned by that character's own
motions.Npc.SetLook/Game.Hero.SetLookdo the same from C#. A definition
(defs/models) stays the way to dress every instance of a model. - Save weights writes the geometry too. The bind pose re-carried through the painted
weights - what the viewer showed all along - now goes into the file with them, so the
preview and the game stop showing sleeves stretched to where the first auto-rig left them. - The retarget carries a node's move. The game's motions move nodes as well as turn them
(transin a hop, a knockback, the fall); a retargeted glTF now follows those moves as the
viewer always did - a felled character lies on the ground rather than at standing height,
a sleeve is not stretched to where its shoulder had been. Drive verbsmotion <id> [loop] [all] [end]andhp <member> <hp>for looking at a pose in play. - Another rig's model, retargeted by the client. A definition may name a glTF rigged
another way (Mixamo, Tripo, Rigify): bones matched by a table of the usual names and the
definition's"bones", the file scaled and stood on its feet with its up and facing found
from the rig, limb bones turned into the game's bind directions, the game's motion applied
as world rotations down the file's own hierarchy.scale,rotation,offsetoverride
the fit. Proportions still tell; the auto-rig is the better road for a chibi. - glTF textures get mipmaps in the client (they had none: a 2048-square texture on a
character a hundred pixels tall shimmered), capped at 2048 a side; JPEG textures decode
for the game-format remake too. Then taken off again by default: an atlas of many small
islands packed tight (a generated model's - 1189 on the chibi) cannot be mipmapped without
mixing two islands into one texel, and those were the grey lines along the hair and face
from afar, gone up close. The client now draws level 0 alone (at most 2048 a side, the
islands' rims repainted from their insides, as Crystal's viewer does);--gltf-mips=auto
builds a chain from the UVs' coverage where they leave room,fullregardless.