Direction (RTL)
The platform renders your generator inside a document whose dir follows the user's language. Mirroring is not optional, and there is no second stylesheet — the layout has to flip on its own.
Compare side by side with the LTR / RTL toggle above the demo below. Written the modern way this is almost free: use logical properties for every one-sided value — margin-inline-start, padding-inline-end, inset-inline-start, text-align: start. Symmetric shorthands need no attention at all, and flex and grid mirror themselves; adding flex-row-reverse for RTL flips a layout that has already been flipped.
Hit the toggle and watch what flips and what does not. Flips: the rail changes sides, label and value swap, the slider fills from the other end, the switch knob travels the other way — all of it done by logical properties and flex on their own, without a single flex-row-reverse. Does not flip: the ruler's zero point, the tick direction, the board's position. The Arabic label on the first row (عرض اللوح, board width) is the text itself running right to left: in LTR عرض sits on the left and اللوح on the right, and RTL swaps the two words. The Latin row below it only moves as a block — its letters still run left to right, and 200 is never 002. Direction changes the arrangement, not the writing direction inside a word. The board, the ruler and the artifact never mirror — lock that layer to direction: ltr and the logical properties inside it always resolve to the left, so the artifact's orientation is independent of the interface around it. But the overlays on the canvas are interface, not artifact, so they do flip: in RTL, Regenerate lands on the mirrored side.
Pitfalls this system actually hit
| Symptom | Cause and fix |
|---|---|
| The slider knob moves the wrong way | The webkit fill uses linear-gradient(to right …), which has to become to left |
| Scrubbing changes the value in the wrong direction | Read direction and flip the sign of the delta |
| The select popover is misaligned | When positioning in JS, RTL must align with the trigger's right edge, not blindly reuse left |
| A centred floating chip sits half off | Don't use inset-inline-start:50% + translateX(-50%); use inset-inline:0; margin-inline:auto |
| The progress bar grows from the wrong end | transform-origin has to switch sides with the direction |
| The switch knob slides outside its track | The knob starts from inset-inline-start but travels with translateX(16px) — transform is physical, so RTL needs -16px. Any transform that means "move forward" has to decide its own direction |
| Labels collide with inputs | One-sided padding didn't flip. Use logical properties throughout |