@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@*- - * = . *@
@@*++-::-::-:::::---::.:.:::::::::::-:::::-::::-:---:-:. .@@@@@@@. ::::::---:-:::::::::---::::::--:--:-:::::---:: %@
@@ .::---::::::-::::::::::-:::::::::::::::-:::::::::. -@@@@@: -@@@@@+ :::------:-::-::-:::.:::::::::::-::---::-:: #@
@@*-::::.:::-::::::::-----::::::::-::::::::-:-:::. *@@@@@ -*+-+@@@@@* .::::-::::--:::::-:::::-:-::::-:-::::::: %@
@@.----:--::::::::::::::::-:::::::::.::::--::. .%@@@@% .::.-%***+-+@@@@@%. ::::----:::::::::::::-::::::::::::-: %@
@@ ------:-:::-::::::-::::-:-::::::-::-::.. +@@@@@@ .-:::::-%*%*%**: %@@@@@+ :::-:---::-::::::::::.:::::::-::- *@
@@ .:-:-::-:-::::::-:::-::::::::::::::: *@@@@@*@@@-.-:-::::.-%%*%**%-.: +@@@@@* .--::::::-::::::::::::::::::.: %@
@@.:.-:---:::::::-::-::::::::::::::. @@@@@%+. +@@@-:-::-::.:+**%*%%**.-::. @@@@@@@@% .::::-:::::::::::::::-::.:: %@
@@:-----::-::::::::-::.:::::::::. -@@@@@*-- +@@@-.:::-:+*.+=%%**%%+::--: @@@@@@@@@@@@ .:.::::::.:--::-::-:---- %@
@@ .:::.-:::::::::::---:::::: -@@@@@.:-. . +@@@-.---:. *-+*=*%%%%-.:-::.@@@@@@@@@%@@@@@ ::::::-:::::--:::::: %@
@@ ::::::::-::::::--:::::. %@@@@@ :+-: .-%%@ =@@@+.::..*%:-@*#*+%*%+.::::.@@@@@@*@@@@@#@@@@@. .::-:-:-::::::::: %@
@@:::::::::::::::-::-:. -@@@@@* -++ +@%@**%@ *@@@-.-:*%*+#%+*+*%%%%+.:-::.@@@@@@@@@@@@@@@@@@@@@+ .:--:::::::::: %@
@@ .::::::-::.::::.. *@@@@@*.--- . -@@@*%*- *@@@-.:.. +*%**%#***##+.---:.@@@@@@@@+ -@@@@@@#@@@@% .:::::::::: %@
@@ ::::-:::::::. #@@@@#- :-*@@ .+@%.@%:-. *@@@. .. -*+%##@#@=.-:-:.@@@@@@% ::.***@@@@ %@@@@#. .::--:: %@
@@ :::-:-:::. .@@@@@@ ::: . #@@ %@@++ -@--:*@@@%@@@@ .:*=**-*%%#@+.:--..@@@@@@: ::..%%*@@@@ ... :@@@@@- .::: %@
@@ .:::-:: -@@@@@@@@@ ::--- . @@@- -##-+@*- *@@@@@@@@: - - *%%%#+.--:::@@@@@@:.-:- %%*@@@@...-+- **+@@@@@+ . %@
@@ ::: +@@@@#@@@@@@@ -----.. %@@+ *@@+ % *@@@ #= @@%.- *%*@@=.::::.@@@@@@: :-:.%%%@@@@ ..-=* #***+-@@@@@= *@
@@ . %@@@@%%@@@@@@@@@ -----.... .-@@**- -@: =@@@. @@@@+ . -@@@::-=+-:..@@@@@@@ .:: %*%@@@@ :.+=+ #%*%*%+* #@@@@@@
@@ *@@@@@* @@@@@@@@@@ ::--+ ...%@@: *@%+ @+#@@@%@@@ @@@@@@@@@----+----%+:@@@@@@@@ . %%%@@@@...++*.%*%*%*%%- *@
@@ -%@- :--:@@@@@@@@@@ ----- . + *@@.+@@@@@@@%*+ @@@@@@@@@@@@ -+*%*@@*@#%#@@@@@@@* %*%@@@@ ..-**.%*%*%*%%+.:.- %@
@@ : ---+-+--@@@@@@@@@@ ---:-.. .@% %@#++:...+*+ #@@@@@@@@@@@@@ :. .@%-*%@@@%%%%#@@@@@ +**@@@@...=*% %%*%%%-+-:::: *@
@@ -.-*+-+-+:@@@@@@@@@@ ::-*- . @**-+-++- :@@@@@@@@@@@@@@@@@#+ %+ ..-+*@@##%%*@@@@@#+%@@@...=%*.%%%%+-=+--::- %@
@@ -.++---+::@@@%@@@@@@ ::. .+-*-+ @@@@@@@@@@#@@@@*:*%#@@@@%%%%**++ .--*@@@#%%%*@@@@@@@...+*% %*%%:-::-::-- %@
@@ -.+-+--+-:#@@@@@@@@@ . %@@@@* %@@@@@@@@@@@@@@@@@@% :-+*%%***+#@@@@@- ..:--@@@##%%%@@@@...*%%.#*-*@%:+-:::- %@
@@ :.-+:-+---@@@@@@@@@@ :@@@@@@@@@@@@@@@@@@@@@@@@@@@@***% ....:%- %@@@+ @@@@-. .--+#@@%...-@:. +*% -::-+-.-+.::- %@
@@ ::+-+-----@@@@@@@@@@ .%==*@@@@@@@@@@@*@@@@@@@@***%%%%*:-.:.- +@@@@#*@@@@@*%%*- :--**+--=+*:*%%.%-:.---+-:::- %@
@@ :.*-+-+--:@@@@@@@@@@ .@@@@@%+#@@@@@@@@@@@@@@@@@%**%%%*.=:..+ :*-** -@@@@%. *%*%*%%*-. . +*%-+. *%%.#+:+.:---:-:- %@
@@ ::+----+--@@@@@@@@@@ + .%@@@@%*#@@@@@@@@@@@@@@@@@***#%=- : :+%% -##@@%%%%%%%+. . ...: *##::.*#* %%:::-- %@
@@ :.+++-----@@@@@@@@@.@@@@@ -@@@@* #@@@@@@@@@@@%@@@@**%%#%*%%%%*=. .. -=-- -%%%*%%%- :::: *%#.-*%%%*@*:..-- %@
@@ :.+:-++--:@@@@@@@@@@ *@@@@% *@@@@@@@@@@@@@@@@%+*%%%*%##%******%%%:. +#%%*%**%***:+-.:.*%%-*+. #@**@%--- %@
@@ ::=+------@@@@@@* %@@@@+ @@@*-....--: -@@@@@@@@+ @@@@@%+*%*%%%##@##%%%% . :****%*%*+=-#*.:: *% :-#@%%*@%.:-- *@
@@ ::-+-+-+--@@@@@@@@+ -@@@@@+ :-....-----:. .@% . @@@@@@***%%%%%%%*%*+-+*%*#**=*%@@@@% ::.*@%-+:-:-%+-:.::-.%@
@@ .:+-------@@@@ .@@@@@- @%----+ ...---+----:.. .::.---:: #@@@@@%+**%*%*%*++-=**+%#@@@@@@@% :: *@@@@***-#-*%*-:- %@
@@ :.+--+-+-:@@%@@@@: %@@@@- :--:- .-+--+------::.::--=+---: *@@@@@#+-+*%*%-+=@@@@@@@@@@@@+ .*@@@#: :+**- -:- %@
@@ ..*-------@@: *@@@@% . -:-:..:-%%+**+--+-+-+-:::::-- -+--::: -@@@@@@*--@@@@@@@@@@@% *##%*****%*#%:.. + .::-:- %@
@@ ::*+-+--. *@@@@% -@@@#--:...#@%: --+++--+--+.-:::-:.@- :---:-: :@@@@@@@@@@@@@%- - :.-%%%%*%#@%% . + . %*- %@
@@ :-*+---+@@% .@@@@@ @@*:.: ...+:-----.-+-::-::-:-@ %%. ---:::: @@@@@@@.- -+-* --: ..%###%*%*+. - -%*-.: %@
@@ .:*--. :@@@@@ @@- .*@@@@@ :-+ ...-+-.:%@%::+:::::::+%.@@@%+**--+----:. * .:*.-*+-*:% .::..:*##%**%*@*:...:: %@
@@ .-*:-@@@@* @@@@@+:#@@@@@@@@ ---....--:%@@@@@#-.:::.-. -+ + --* .-------::..++% +*+-% @@@%:.:---:.*@%-. ..::::: %@
@@ .:***. -@@@@% .@@@@@@@@@@@@@ -:+ ...+-:%@@@@@@-:::..-: @*#- -+:*%@ .. -+ ....+-%.-*+-* @@@@@@:-+----: ..:::::::: %@
@@ ..*@@@@@- :@@@@@@@@@@@*:@@@@ ---.. .---:%@@@*--..:..--.%#@@ %% -@.+: . *@@@- ++% +**+* @@@@@@.--+-+---::::-:-::- %@
@@ :.@+ *@@@@@@@@@@@%=--=-@@@@ --+ ...-+-- :--.-++-::-. +=-@@@@+ --.. *@@@@@%++% +*+-% @@@@@% *=+-+-+:::::-:::-- %@
@@...+%@@@@#@@@@@@*---==**+@@@@ ---....---------**%%+-@@-.:--- +%@*-..: . *@@@@@@*+% +**-* @@@@@# -::+=---::--:----- %@
@@ ::. -@@@@@@@ :.:++****+@@@@ --- .-::-++**%*- :@@@@@:**=+- -%.-- . *@@@@@@--%.-*+-* @@@@@# : -**::--------- %@
@@ ::-: *@@@@@@@+@@@#+****+@@@@ :---+++-*+-%** *@@@@: ..-****+. -: . %@@@@@@-*%.+=-**-@@@@@%*@@@@@ .--::-:-:--- *@
@@ ::-:.*@@@@@@@-@@@@#****-@@@@ *%%+=**##%.%* .+#@%*=*@+ . .-*****+++:.*@@@@@-=*.:*+-*-%@@@@%@@%#@@@*.+--:---:-- %@
@@ .--:.*@@@@@@@-@@@@@***%-@@@@-=+-*@@@@@+ += +*@@@@##@#%%%##*- ..-=**+--++:.-@@-=**:*%=**@#%@@%@@@@@@##- :+:::---- %@
@@ :--:.%@@@@@@@-@@@@@****-@@@@++++-+. *@#@%%@@%*: +%@######%- ..:-%*******-*+**%****+*@@@@*.@@@@@@@@@ ---::-- #@
@@ ::-:.*@@@@@@@-@@@@@****+@@@@-**%.-. -=@@@@#+. .*. +%@@@#@#@%+ -*%-: ***-*%**#+@%%@@% *@@@@#%@@@= -+-::- %@
@@ ::-:.%@@@@@@@-@@@@*****+@@@@:%%%*- .: .=*%%****. -#@@@%%%@#%#@@+. . ****-*%***@%--@% #@@@@@@@@ -+.- %@
@@ .-+:.*@@@@@@@-@@@%+++-*@@ ---.*%**+: . :%***+. +*****. .%@@#@%@@%--*-... **%+-#++%+@%@@@% :. +@#@@@@@@@-..=- *@
@@ :.--:*@@@@@@@-@@::+%@@@.- -=++@#%%%%**#%***-:+@@#+--*%**%*. :#@#%*- .: .. *** -+-=+.@@@@@% -:: %@@@@@#@@* :- %@
@@ ::--:%@@@@@@@::*@@@%..-.-*.-#* @@*-+%###**--+:@@@@@@%::.+***%**: -%%...:: :%-*.:+--*--.*@@* . .=##@@@@@@@ - %@
@@ .:+:.*@@@@@@@@@@*::--+-.*@@@@% @@%+++***++*+-- :*@*---=*%*%**- . -+**=***+.---*-+- .@* -#@@@%. @@@#@@@@@* %@
@@ ::--.*@@@@%%*::-+-+-:%@@@@@@@* @@%*%*#%* -+*=+--@@@@%*#*+++++%*%*%++.-=++++=*%*%=*%=.+: :@@@@@+ =*--@@@@@@@@*- %@
@@ .-+.:%@@#+ -***+-@@@@@@@@@@@* @::*%%*%*=- .=**%@@@+*+*+: :%*%%*%%***#%**+-+********:+@@@@+. -+.-**@@#@. . %@
@@ ::-:.**:+=. *#%%@@@@@@@@@@@@% ---%%*%%%%%*+- .-+-+*+ +%%**=++-*#**%=##++**#%%*@@@@@- :+**:****+-+%+.::: *@
@@ ::---#+ *@* @@@@@@@@@. ::*%*#%%**%**%%%*=- . :+*@%=+*%**%*@%#@##**%###%*#*. @@@@@= +###%**%: ..:.: %@
@@ --+--#* .. ... @@@@@@ .:-=+-*+-**%%%%%%*%%%%%**- . -%%%%+-=*%%%*%*%**%**=-%%%%%%%%*--: @@@@@* -**+. .::::: %@
@@ ::::.** .::...:@@* --+***==+#*%++=+*%%*%*%*%%%%%%%%@%**==%%%%**%%%+--++-*+--:+%%%%%%.:---: @@@@%+=@**%=-. ..- %@
@@.--*%@#*+:. ..-- .-*%@*****%**%*+***%*=*%%%%%*%*%%***-*%%%%*: +**-. :-++= ++++---:+*@%*+-::---.:@@@: .+- .%#*+.- #@
@@ ..-*@#%**+-..:-*%#@@##%*%%**++*****%*%*%+*=*%%%%-***%%%**+ .---: *#*..-* ++++=*=++ +%++=**-...-@@@- .-.. .*##@%: %@
@@@# .:%###%*%#%@@@##@#**++=****+**%**%%*****+++*%%%#* *#*=+++++-@@@@@@@-+ -++**+ *%*-@-+-+-***:-@@@*. . -*@*: . %@
@@@@@@@ -%@##%*##@@#@#*=*-++***#%***%**%%*%**%%%*: :--+--+-++- *@@@* +***% -#*@%-@+*++-*+=**@@@*%*###-. .@@
@@@@@@@@@* :##@%%%%#%%%++*=*%*****#%*#%***%%*%*%%-**=++-+++-++++- -** .. :%%%-@*:@**%++++=%*%%#@#%. ... +@@@@@
@@@@@@@@@@@@* :#####%#*****=+******%%%#@%%*%*%==++++-+++++++++-+=**%*+ -**%*+#%**+#*+@*%****++%%@#+ :@@@@@@@@@
@@@@@@@@@@@@@@@% =%@##%%%*+****%**%%%#####%%%+ ::+=+++++++++++=**+: :*%*-%@@:%+-+ #*-%*%*%*%*%*- .*@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@* +%#%*%%%****%%%*%###@%%%%*.@# -***++-=+*+:- +*%*: ..:--.:= ++=#%%##%*:.. -@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@* .-@#%*##%****%*#@#%%*%%*.@%-@*: -***-:.-**+%%%%**-:-::-++*% %%*@@*+. *@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@* +#@#%%%%**####%%@%#* @#.*%#*++.+%#+%@@*+%*%-.*+--.:-+*%*@#*- . @@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@: +@##%#@@%%%%%%%#*.%*=#%*--- -**.: -*=-:++ =-+++.***#- ... -@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ *@@#@#@#%*%%%*+@%-***--+ -++:+-..++=+-.*-+=*%#-... %@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@- %@@@#@#%*%*+%+-**=--+ *%*----.+--++-%%**: .. -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+ .%@@#@##%:***+-****.+*****+.:-+=**+ :. .*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@. -%@@#%%%%++*****-***+-+=*%%+-:: +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# -%##%*%**+-=+-***%***+. . %@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@% -#@%*%*%++*%%#*-:.. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* +##%*%%#*... .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@- .%#-. . *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@- -#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-------------------------------------------------- StickyFlow.js----------------------------------------------------------
SFL parser, scene builder, SVG renderer, interactive viewer and editing runtime in one package. No runtime dependencies, no React, no Konva. The static tier is DOM-free and runs in Node.
npm install stickyflowNode 18 or newer. The package ships ESM, CJS and TypeScript types.
import { render } from 'stickyflow'
const { svg, width, height, diagnostics } = render(sfl)
// A complete, deterministic SVG string. render() never touches the DOM.| Import | What it is |
|---|---|
stickyflow |
Static tier. SFL text in, SVG string out. Node, SSR, CLI. |
stickyflow/viewer |
Viewer in the DOM: select, hover, pan, zoom, typed events, and live input for components such as a switch or a button. |
stickyflow/interaction |
Editing gestures on a viewer. Reports what changed; the host applies the patch to the SFL text. |
stickyflow/binding |
Data sources, bindings and handlers. createDataSource, createBindingRuntime, renderBound. No DOM. |
stickyflow/web-component |
<stickyflow-diagram> custom element in Shadow DOM, no build step. |
Each entry only depends on the ones below it; test/architecture enforces that.
import { createViewer } from 'stickyflow/viewer'
import { bindEditing, applyMoveChange } from 'stickyflow/interaction'
const viewer = createViewer({ container, source: sfl, interactive: true })
const editing = bindEditing(viewer)
editing.on('moveChange', (event) => {
sfl = applyMoveChange(sfl, event) // the text changes, nothing else does
viewer.update({ source: sfl })
})A component is an interface element with a value, a look and a behavior. Seven are built in. RollingNumber, TickScale and Ruler show a value. Switch, Checkbox, ToggleButton and Button are operated by the user. An application adds its own type with defineComponent().
A document declares a data source and binds to it. <- makes a property follow the data. <-> also writes the data when the user changes a component value, and onChange runs for each change by the user.
DataSource lamp {
mode: record
fields {
on: boolean
}
}
Model demo {
Component power {
type: switch
value: <-> lamp.on
layout {
position: 0, 0
size: 104, 60
}
}
}
import { createBindingRuntime, createDataSource } from 'stickyflow/binding'
import { connectInteraction, createViewer } from 'stickyflow/viewer'
const viewer = createViewer({ container, source: sfl, interactive: true })
const runtime = createBindingRuntime(sfl)
const lamp = createDataSource({ on: false })
runtime.registerSource('lamp', lamp)
runtime.attach(viewer)
connectInteraction(viewer, runtime)
lamp.set({ on: true }) // the switch followsBinding and live input need only stickyflow/binding and stickyflow/viewer. Editing with stickyflow/interaction is separate.
Shapes, links, frames, swimlanes, paths and text. Fifteen chart types. Isometric objects. Shader surfaces and components. Data sources with bindings, and events with handlers, so a document can react to data and input.
- Deterministic. The same SFL gives the same SVG, byte for byte.
- Text stays the source. Edits patch the SFL text; comments and order survive.
- Layered. Language, semantic, render input, scene, SVG, runtime, each with one job and one direction.
src/
model/ types and registries for shapes, charts, components
sflLanguage/ AST, lexer, parser, canonical emitter
sflSemantic/ SFL AST to canvas state
renderInput/ renderer contract and style decoding
renderScene/ deterministic scene construction
svg/ SVG serialization and the DOM contract
binding/ data sources, bindings and handlers
runtime/ viewer, interaction, web component
npm run ci # lint, typecheck, tests, build, smoke
npm run build # tsupHow the package and its neighbours fit together: docs/ARCHITECTURE.md. Adding a new placeable object: docs/ADDING_CANVAS_OBJECT.md. Adding a component: docs/ADDING_COMPONENT.md. Changes: CHANGELOG.md.
- Docs and examples: stickyflow.org/docs
- The language: stickyflow.org/sfl-language
- Playground: stickyflow.org/playground