├── sc
├── .gdignore
├── letters-test.scd
├── sequence-test.scd
├── sound-test.scd
├── config-test.scd
├── salonLetters.txt
├── walkers.scd
├── setup.scd
├── cube-routines.scd
├── Animatron
│ └── Animatron.sc
├── dot.sc
├── dots.scd
├── midi-test.scd
├── cube-routines-mod.scd
└── osc-test.scd
├── commands
├── .gdignore
├── init_example.osc
├── tutorial-cmds.osc
└── init.osc
├── config
├── .gdignore
└── config_example.osc
├── docs
├── .gdignore
├── help
│ ├── help-bg.osc
│ ├── help-flipv.osc
│ ├── help-post.osc
│ ├── help-fliph.osc
│ ├── help-selected.osc
│ ├── help-tutorial.osc
│ ├── help-editor-append.osc
│ ├── help-free.osc
│ ├── help-stop.osc
│ ├── help-at.osc
│ ├── help-iter.osc
│ ├── help-letter-scale.osc
│ ├── help-list-commands.osc
│ ├── help-routine-stop.osc
│ ├── help-ungroup.osc
│ ├── help-window-center.osc
│ ├── help-editor-clear.osc
│ ├── help-list-midi.osc
│ ├── help-parent-free.osc
│ ├── help-routine-free-all.osc
│ ├── help-routine-free.osc
│ ├── help-routine-start.osc
│ ├── help-write.osc
│ ├── help-error-reply.osc
│ ├── help-list-children.osc
│ ├── help-list-states.osc
│ ├── help-midi-free.osc
│ ├── help-play.osc
│ ├── help-editor-font-size.osc
│ ├── help-post-font-decrease.osc
│ ├── help-post-font-increase.osc
│ ├── help-post-font-size.osc
│ ├── help-status-reply.osc
│ ├── help-editor-font-decrease.osc
│ ├── help-editor-font-increase.osc
│ ├── help-frame-next.osc
│ ├── help-oneshot.osc
│ ├── help-osc-remote.osc
│ ├── help-state-free.osc
│ ├── help-frame-prev.osc
│ ├── help-help.osc
│ ├── help-midi-debug.osc
│ ├── help-play-rand.osc
│ ├── help-window-fullscreen.osc
│ ├── help-parent.osc
│ ├── help-window-position.osc
│ ├── help-list-sequence.osc
│ ├── help-slow.osc
│ ├── help-speed.osc
│ ├── help-window-screen.osc
│ ├── help-osc-send.osc
│ ├── help-window-top.osc
│ ├── help-createordestroy.osc
│ ├── help-editor-open.osc
│ ├── help-letter.osc
│ ├── help-list.osc
│ ├── help-app-remote.osc
│ ├── help-editor-save.osc
│ ├── help-letter-spacing.osc
│ ├── help-load-alphabet.osc
│ ├── help-onfinish.osc
│ ├── help-rand.osc
│ ├── help-list-actors-reply.osc
│ ├── help-say.osc
│ ├── help-list-anims.osc
│ ├── help-play-range.osc
│ ├── help-select.osc
│ ├── help-list-anims-reply.osc
│ ├── help-load-defs.osc
│ ├── help-list-assets.osc
│ ├── help-routine.osc
│ ├── help-sound-free.osc
│ ├── help-behind.osc
│ ├── help-choose-arg.osc
│ ├── help-front.osc
│ ├── help-assets-path.osc
│ ├── help-size.osc
│ ├── help-deselect.osc
│ ├── help-angle.osc
│ ├── help-size-x.osc
│ ├── help-size-y.osc
│ ├── help-sound.osc
│ ├── help-color-b.osc
│ ├── help-color-r.osc
│ ├── help-rotate.osc
│ ├── help-color-g.osc
│ ├── help-scale.osc
│ ├── help-state-add.osc
│ ├── help-size-xy.osc
│ ├── help-color.osc
│ ├── help-scale-x.osc
│ ├── help-scale-xy.osc
│ ├── help-scale-y.osc
│ ├── help-window-size.osc
│ ├── help-create-group.osc
│ ├── help-frame.osc
│ ├── help-onframe-free.osc
│ ├── help-ysort.osc
│ ├── help-choose.osc
│ ├── help-fade.osc
│ ├── help-list-assets-reply.osc
│ ├── help-wait.osc
│ ├── help-alpha.osc
│ ├── help-load-config.osc
│ ├── help-onfinish-free.osc
│ ├── help-position-x.osc
│ ├── help-position-y.osc
│ ├── help-position.osc
│ ├── help-create.osc
│ ├── help-loop.osc
│ ├── help-move.osc
│ ├── help-move-x.osc
│ ├── help-move-y.osc
│ ├── help-load.osc
│ ├── help-pivot.osc
│ ├── help-group.osc
│ ├── help-onframe.osc
│ ├── help-debug.osc
│ ├── help-action.osc
│ ├── help-midi.osc
│ └── help-def.osc
├── help-actor-free.osc
├── tutorial.osc
├── help-create.osc
├── tutorial-index.osc
├── tutorial-utils-rand.osc
├── tutorial-controls.osc
├── KeyboardShortcuts.md.html
├── tutorial-actor-animation.osc
├── tutorial-commands.osc
├── tutorial-utils-custom-cmds.osc
├── tutorial-actor-multi.osc
├── tutorial-actor-attributes.osc
├── tutorial-actors.osc
└── markdeep
│ ├── slides.css
│ └── apidoc.css
├── animations
└── .gdignore
├── icon.png
├── icons
├── ull-16.png
├── ull-32.png
├── ull-48.png
├── ull-64.png
├── animatron.ico
├── ull-128.png
├── ull-256.png
├── ull.svg.import
├── action.svg.import
├── ull-16.png.import
├── ull-32.png.import
├── ull-48.png.import
├── ull-64.png.import
├── ull-128.png.import
├── ull-256.png.import
├── action.svg
└── ull.svg
├── fonts
├── WalterTurncoat.ttf
└── mononoki_Bold.ttf
├── addons
└── gdosc
│ ├── bin
│ ├── x11
│ │ └── libgdosc.so
│ ├── osx
│ │ └── libgdosc.dylib
│ └── win64
│ │ ├── libgdosc.dll
│ │ ├── libgdosc.exp
│ │ └── libgdosc.lib
│ ├── gdoscmsg.gdns
│ ├── gdoscsender.gdns
│ ├── gdoscreceiver.gdns
│ ├── gdosc.gdnlib
│ ├── gdscript_oscsender_template.gd
│ └── gdscript_oscreceiver_template.gd
├── transparent_bg.tres
├── RoutineNode.tscn
├── default_env.tres
├── actions
├── Action.gd
├── wander.gd
├── oscillate.gd
└── wrap.gd
├── .gitignore
├── OscSender.gd
├── icon.png.import
├── RoutineNode.gd
├── SpeechBubble.tscn
├── MetaNode.tscn
├── Logger.gd
├── SpeechBubble.gd
├── Letters.gd
├── CustomCommands.gd
├── PostTextEdit.gd
├── Animation.gd
├── Helper.gd
├── AudioInputPlayer.gd
├── Config.gd
├── Main.tscn
├── MetaNode.gd
├── Midi.gd
├── OscTextEdit.gd
├── project.godot
├── README.md
└── Main.gd
/sc/.gdignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/commands/.gdignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/config/.gdignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/.gdignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/animations/.gdignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icon.png
--------------------------------------------------------------------------------
/docs/help/help-bg.osc:
--------------------------------------------------------------------------------
1 | /bg r:f
2 |
3 | /description Set the background color.
4 |
--------------------------------------------------------------------------------
/docs/help-actor-free.osc:
--------------------------------------------------------------------------------
1 | /free actor:s
2 |
3 | Delete the ACTOR removing its instance.
4 |
--------------------------------------------------------------------------------
/docs/help/help-flipv.osc:
--------------------------------------------------------------------------------
1 | /flipv actor:s
2 |
3 | /description Flip the actor vertically.
4 |
--------------------------------------------------------------------------------
/docs/help/help-post.osc:
--------------------------------------------------------------------------------
1 | /post msg:s
2 |
3 | /description Print MSG in the post window.
4 |
--------------------------------------------------------------------------------
/icons/ull-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/ull-16.png
--------------------------------------------------------------------------------
/icons/ull-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/ull-32.png
--------------------------------------------------------------------------------
/icons/ull-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/ull-48.png
--------------------------------------------------------------------------------
/icons/ull-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/ull-64.png
--------------------------------------------------------------------------------
/docs/help/help-fliph.osc:
--------------------------------------------------------------------------------
1 | /fliph actor:s
2 |
3 | /description Flip the actor horizontally.
4 |
--------------------------------------------------------------------------------
/docs/help/help-selected.osc:
--------------------------------------------------------------------------------
1 | /selected
2 |
3 | /description Get the list of selected actors.
4 |
--------------------------------------------------------------------------------
/docs/help/help-tutorial.osc:
--------------------------------------------------------------------------------
1 | /tutorial
2 |
3 | /description Load the tutorial in the editor.
4 |
--------------------------------------------------------------------------------
/icons/animatron.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/animatron.ico
--------------------------------------------------------------------------------
/icons/ull-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/ull-128.png
--------------------------------------------------------------------------------
/icons/ull-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/icons/ull-256.png
--------------------------------------------------------------------------------
/docs/help/help-editor-append.osc:
--------------------------------------------------------------------------------
1 | /editor/append msg:s
2 |
3 | /description Append MSG to editor.
4 |
--------------------------------------------------------------------------------
/docs/help/help-free.osc:
--------------------------------------------------------------------------------
1 | /free actor:s
2 |
3 | /description Delete the actor (remove its instance).
4 |
--------------------------------------------------------------------------------
/docs/help/help-stop.osc:
--------------------------------------------------------------------------------
1 | /stop actor:s
2 |
3 | /description Stop playing the actor's animation.
4 |
--------------------------------------------------------------------------------
/docs/help/help-at.osc:
--------------------------------------------------------------------------------
1 | /at index:i
2 |
3 | /description Perform a CMD on the actor at the GROUP INDEX.
4 |
--------------------------------------------------------------------------------
/docs/help/help-iter.osc:
--------------------------------------------------------------------------------
1 | /iter cmd:s
2 |
3 | /description Perform a CMD on every actor in the GROUP.
4 |
--------------------------------------------------------------------------------
/docs/help/help-letter-scale.osc:
--------------------------------------------------------------------------------
1 | /letter/scale scale
2 |
3 | /description Set the scale of the letters.
4 |
--------------------------------------------------------------------------------
/docs/help/help-list-commands.osc:
--------------------------------------------------------------------------------
1 | /list/commands
2 |
3 | /description Get list of available commands.
4 |
--------------------------------------------------------------------------------
/docs/help/help-routine-stop.osc:
--------------------------------------------------------------------------------
1 | /routine/stop name:s
2 |
3 | /description Stop the routine named NAME.
4 |
--------------------------------------------------------------------------------
/docs/help/help-ungroup.osc:
--------------------------------------------------------------------------------
1 | /ungroup group:s
2 |
3 | /description Remove the actor from a named group.
4 |
--------------------------------------------------------------------------------
/docs/help/help-window-center.osc:
--------------------------------------------------------------------------------
1 | /window/center
2 |
3 | /description Center window in main display.
4 |
--------------------------------------------------------------------------------
/fonts/WalterTurncoat.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/fonts/WalterTurncoat.ttf
--------------------------------------------------------------------------------
/fonts/mononoki_Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/fonts/mononoki_Bold.ttf
--------------------------------------------------------------------------------
/config/config_example.osc:
--------------------------------------------------------------------------------
1 | def /config
2 | /window/screen 1
3 | /window/center
4 | /window/top
5 |
--------------------------------------------------------------------------------
/docs/help/help-editor-clear.osc:
--------------------------------------------------------------------------------
1 | /editor/clear
2 |
3 | /description Clears the editor. **CANNOT BE UNDONE.**
4 |
--------------------------------------------------------------------------------
/docs/help/help-list-midi.osc:
--------------------------------------------------------------------------------
1 | /list/midi
2 |
3 | /description Get list of commands mapped to MIDI events.
4 |
--------------------------------------------------------------------------------
/docs/help/help-parent-free.osc:
--------------------------------------------------------------------------------
1 | /parent/free child:s
2 |
3 | /description Free the CHILD from any parent.
4 |
--------------------------------------------------------------------------------
/docs/help/help-routine-free-all.osc:
--------------------------------------------------------------------------------
1 | /routine/free/all
2 |
3 | /description Remove all existing routines.
4 |
--------------------------------------------------------------------------------
/docs/help/help-routine-free.osc:
--------------------------------------------------------------------------------
1 | /routine/free name:s
2 |
3 | /description Remove the routine named NAME.
4 |
--------------------------------------------------------------------------------
/docs/help/help-routine-start.osc:
--------------------------------------------------------------------------------
1 | /routine/start name:s
2 |
3 | /description Start the routine named NAME.
4 |
--------------------------------------------------------------------------------
/docs/help/help-write.osc:
--------------------------------------------------------------------------------
1 | /write msg:s
2 |
3 | /description Write MSG string with assets mapped to letters.
4 |
--------------------------------------------------------------------------------
/docs/help/help-error-reply.osc:
--------------------------------------------------------------------------------
1 | /error/reply error:s
2 |
3 | /description Return an error message to the client.
4 |
--------------------------------------------------------------------------------
/docs/help/help-list-children.osc:
--------------------------------------------------------------------------------
1 | /list/children actor:s
2 |
3 | /description List the ACTOR's children (if any).
4 |
--------------------------------------------------------------------------------
/docs/help/help-list-states.osc:
--------------------------------------------------------------------------------
1 | /list/states actor
2 |
3 | /description Get a list of states for the given ACTOR.
4 |
--------------------------------------------------------------------------------
/docs/help/help-midi-free.osc:
--------------------------------------------------------------------------------
1 | /midi/free
2 |
3 | /description Unmap MIDI MIDIMSG for MIDINUM in channel MIDICH.
4 |
--------------------------------------------------------------------------------
/docs/help/help-play.osc:
--------------------------------------------------------------------------------
1 | /play actor:s
2 |
3 | /description Play the actor's animation from the current frame.
4 |
--------------------------------------------------------------------------------
/docs/help/help-editor-font-size.osc:
--------------------------------------------------------------------------------
1 | /editor/font/size size:i
2 |
3 | /description Set the font size of the editor.
4 |
--------------------------------------------------------------------------------
/docs/help/help-post-font-decrease.osc:
--------------------------------------------------------------------------------
1 | /post/font/decrease
2 |
3 | /description Decrease the font size of the post.
4 |
--------------------------------------------------------------------------------
/docs/help/help-post-font-increase.osc:
--------------------------------------------------------------------------------
1 | /post/font/increase
2 |
3 | /description Increase the font size of the post.
4 |
--------------------------------------------------------------------------------
/docs/help/help-post-font-size.osc:
--------------------------------------------------------------------------------
1 | /post/font/size size:i
2 |
3 | /description Set the font size of the post window.
4 |
--------------------------------------------------------------------------------
/docs/help/help-status-reply.osc:
--------------------------------------------------------------------------------
1 | /status/reply status:s
2 |
3 | /description Return a status message to the client.
4 |
--------------------------------------------------------------------------------
/addons/gdosc/bin/x11/libgdosc.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/addons/gdosc/bin/x11/libgdosc.so
--------------------------------------------------------------------------------
/docs/help/help-editor-font-decrease.osc:
--------------------------------------------------------------------------------
1 | /editor/font/decrease
2 |
3 | /description Decrease the font size of the editor.
4 |
--------------------------------------------------------------------------------
/docs/help/help-editor-font-increase.osc:
--------------------------------------------------------------------------------
1 | /editor/font/increase
2 |
3 | /description Increase the font size of the editor.
4 |
--------------------------------------------------------------------------------
/docs/help/help-frame-next.osc:
--------------------------------------------------------------------------------
1 | /frame/next actor:s
2 |
3 | /description Jump to the next frame of the ACTOR's' animation.
4 |
--------------------------------------------------------------------------------
/docs/help/help-oneshot.osc:
--------------------------------------------------------------------------------
1 | /oneshot actor:s
2 |
3 | /description Play the ACTOR to the end, and stop. Then set VISIBILITY.
4 |
--------------------------------------------------------------------------------
/docs/help/help-osc-remote.osc:
--------------------------------------------------------------------------------
1 | /osc/remote ip:s
2 |
3 | /description Register a remote OSC client at IP address on PORT.
4 |
--------------------------------------------------------------------------------
/docs/help/help-state-free.osc:
--------------------------------------------------------------------------------
1 | /state/free actor state
2 |
3 | /description Remove the STATE from the ACTOR's state machine.
4 |
--------------------------------------------------------------------------------
/addons/gdosc/bin/osx/libgdosc.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/addons/gdosc/bin/osx/libgdosc.dylib
--------------------------------------------------------------------------------
/addons/gdosc/bin/win64/libgdosc.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/addons/gdosc/bin/win64/libgdosc.dll
--------------------------------------------------------------------------------
/addons/gdosc/bin/win64/libgdosc.exp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/addons/gdosc/bin/win64/libgdosc.exp
--------------------------------------------------------------------------------
/addons/gdosc/bin/win64/libgdosc.lib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/loopier/animatron-godot3/HEAD/addons/gdosc/bin/win64/libgdosc.lib
--------------------------------------------------------------------------------
/docs/help/help-frame-prev.osc:
--------------------------------------------------------------------------------
1 | /frame/prev actor:s
2 |
3 | /description Jump to the previous frame of the ACTOR's' animation.
4 |
--------------------------------------------------------------------------------
/docs/help/help-help.osc:
--------------------------------------------------------------------------------
1 | /help
2 |
3 | /description Open this file in a browser and print the keyboard shortcuts and commands.
4 |
--------------------------------------------------------------------------------
/docs/help/help-midi-debug.osc:
--------------------------------------------------------------------------------
1 | /midi/debug [enable:b]
2 |
3 | /description Enable (or disable) reporting of MIDI input events.
4 |
--------------------------------------------------------------------------------
/docs/help/help-play-rand.osc:
--------------------------------------------------------------------------------
1 | /play/rand actor:s
2 |
3 | /description Play the ACTOR frames in a random order. Defaults to TRUE.
4 |
--------------------------------------------------------------------------------
/docs/help/help-window-fullscreen.osc:
--------------------------------------------------------------------------------
1 | /window/fullscreen [enable:b]
2 |
3 | /description Set fullscreen mode (defaults to true).
4 |
--------------------------------------------------------------------------------
/docs/help/help-parent.osc:
--------------------------------------------------------------------------------
1 | /parent child:s
2 |
3 | /description Set the CHILD as child of PARENT. Will inherit all transformations.
4 |
--------------------------------------------------------------------------------
/docs/help/help-window-position.osc:
--------------------------------------------------------------------------------
1 | /window/position x:i
2 |
3 | /description Move window to the specified position given in pixels.
4 |
--------------------------------------------------------------------------------
/docs/help/help-list-sequence.osc:
--------------------------------------------------------------------------------
1 | /list/sequence actor:s
2 |
3 | /description Print the list of commands triggered on all ACTOR frames.
4 |
--------------------------------------------------------------------------------
/docs/help/help-slow.osc:
--------------------------------------------------------------------------------
1 | /slow actor amount
2 |
3 | /description Devide the speed by a specific AMOUNT. Negative values play in reverse.
4 |
--------------------------------------------------------------------------------
/docs/help/help-speed.osc:
--------------------------------------------------------------------------------
1 | /speed actor:s
2 |
3 | /description Set the playback speed (1 is normal speed). Negative values play in reverse.
4 |
--------------------------------------------------------------------------------
/docs/help/help-window-screen.osc:
--------------------------------------------------------------------------------
1 | /window/screen screenIndex:i
2 |
3 | /description Move the window between displays (0 = main display).
4 |
--------------------------------------------------------------------------------
/docs/help/help-osc-send.osc:
--------------------------------------------------------------------------------
1 | /osc/send addr:s
2 |
3 | /description Send an OSC message with an arbitrary number of arguments to a remote client.
4 |
--------------------------------------------------------------------------------
/docs/help/help-window-top.osc:
--------------------------------------------------------------------------------
1 | /window/top [enable:b]
2 |
3 | /description Set window to be always on top of other windows (defaults to true).
4 |
--------------------------------------------------------------------------------
/docs/help/help-createordestroy.osc:
--------------------------------------------------------------------------------
1 | /createordestroy actor:s
2 |
3 | /description Like `/create`, but if the actor already exists, it removes it.
4 |
--------------------------------------------------------------------------------
/docs/help/help-editor-open.osc:
--------------------------------------------------------------------------------
1 | /editor/open [path:s]
2 |
3 | /description Open an OSC file in the editor. Opens a dialog if no PATH is provided.
4 |
--------------------------------------------------------------------------------
/docs/help/help-letter.osc:
--------------------------------------------------------------------------------
1 | /letter letter:c
2 |
3 | /description Map a single letter to an asset. Creates an actor named after LETTER with ASSET.
4 |
--------------------------------------------------------------------------------
/docs/help/help-list.osc:
--------------------------------------------------------------------------------
1 | /list
2 |
3 | /description Get list of current actor instances. Returned in the form of a `/list/actors/reply` OSC message.
4 |
--------------------------------------------------------------------------------
/docs/help/help-app-remote.osc:
--------------------------------------------------------------------------------
1 | /app/remote [allow:b]
2 |
3 | /description Allow (or prevent) executing OSC commands from remote (non-localhost) clients.
4 |
--------------------------------------------------------------------------------
/docs/help/help-editor-save.osc:
--------------------------------------------------------------------------------
1 | /editor/save [path:s]
2 |
3 | /description Save the editor contents into a file. Opens a dialog if no PATH is provided.
4 |
--------------------------------------------------------------------------------
/docs/help/help-letter-spacing.osc:
--------------------------------------------------------------------------------
1 | /letter/spacing amount
2 |
3 | /description Set the spacing between letters. It's a multiplier of the actors' size.
4 |
--------------------------------------------------------------------------------
/docs/help/help-load-alphabet.osc:
--------------------------------------------------------------------------------
1 | /load/alphabet
2 |
3 | /description Load the alphabet (default letters load from folders named `letter-[ASCII_CHAR]`)
4 |
--------------------------------------------------------------------------------
/transparent_bg.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="StyleBoxFlat" format=2]
2 |
3 | [resource]
4 | content_margin_left = 10.0
5 | bg_color = Color( 0.6, 0.6, 0.6, 0 )
6 |
--------------------------------------------------------------------------------
/docs/help/help-onfinish.osc:
--------------------------------------------------------------------------------
1 | /onfinish actor:s
2 |
3 | /description Add SUBCOMMAND to be triggered on the last frame. The SUBCOMMAND can be any valid command.
4 |
--------------------------------------------------------------------------------
/docs/help/help-rand.osc:
--------------------------------------------------------------------------------
1 | /rand cmd:s
2 |
3 | /description Send a CMD with a random value between MIN and `max.`**This only works with single-value commands.**
4 |
--------------------------------------------------------------------------------
/docs/help/help-list-actors-reply.osc:
--------------------------------------------------------------------------------
1 | /list/actors/reply [actor:s]
2 |
3 | /description Return the list of instanced actors to the client (one name per argument).
4 |
--------------------------------------------------------------------------------
/docs/help/help-say.osc:
--------------------------------------------------------------------------------
1 | /say actor:s
2 |
3 | /description Have the actor "say" something via a speech bubble, with an optional duration (defaults to three seconds).
4 |
--------------------------------------------------------------------------------
/docs/help/help-list-anims.osc:
--------------------------------------------------------------------------------
1 | /list/anims
2 |
3 | /description Get list of available (loaded) animations. Returned in the form of a `/list/anims/reply` OSC message.
4 |
--------------------------------------------------------------------------------
/docs/help/help-play-range.osc:
--------------------------------------------------------------------------------
1 | /play/range actor:s
2 |
3 | /description Play an ACTOR range of frames, begining on the START frame up to (and including) the END frame.
4 |
--------------------------------------------------------------------------------
/docs/help/help-select.osc:
--------------------------------------------------------------------------------
1 | /select [actor:s]
2 |
3 | /description Add the actor to the selected set. If run without ACTOR it will return the list of selected actors.
4 |
--------------------------------------------------------------------------------
/docs/help/help-list-anims-reply.osc:
--------------------------------------------------------------------------------
1 | /list/anims/reply [anim:s]
2 |
3 | /description Return the list of available (loaded) animations to the client (one name per argument).
4 |
--------------------------------------------------------------------------------
/docs/help/help-load-defs.osc:
--------------------------------------------------------------------------------
1 | /load/defs filename
2 |
3 | /description Load a custom command definitions file, which should have the format [described below](#def-files).
4 |
--------------------------------------------------------------------------------
/docs/help/help-list-assets.osc:
--------------------------------------------------------------------------------
1 | /list/assets
2 |
3 | /description Get list of available (unloaded) assets on disk. Returned in the form of a `/list/assets/reply` OSC message.
4 |
--------------------------------------------------------------------------------
/docs/help/help-routine.osc:
--------------------------------------------------------------------------------
1 | /routine name:s
2 |
3 | /description Start a routine named NAME that sends CMD every INTERVAL of time (in seconds) for an arbitrary number of REPEATS.
4 |
--------------------------------------------------------------------------------
/docs/help/help-sound-free.osc:
--------------------------------------------------------------------------------
1 | /sound/free band:i
2 |
3 | /description Unmap sound for the given BAND. If COMMAND and ACTOR are specified, remove only that COMMAND for the actor.
4 |
--------------------------------------------------------------------------------
/sc/letters-test.scd:
--------------------------------------------------------------------------------
1 | "setup.scd".loadRelative.first;
2 | (
3 | x.("/load/alphabet");
4 | x.("/write", "alo");
5 | x.("/letters/spacing", 0.25);
6 | x.("/letters/scale", 0.25);
7 | )
--------------------------------------------------------------------------------
/docs/help/help-behind.osc:
--------------------------------------------------------------------------------
1 | /behind actor:s
2 |
3 | /description Change the draw order for an actor to be behind a reference actor. To move to the background, use `/behind actor *`.
4 |
--------------------------------------------------------------------------------
/docs/help/help-choose-arg.osc:
--------------------------------------------------------------------------------
1 | /choose/arg cmd:s
2 |
3 | /description Send a CMD with a value randomly chosen from any of the arguments. **This only works with single-value commands.**
4 |
--------------------------------------------------------------------------------
/docs/help/help-front.osc:
--------------------------------------------------------------------------------
1 | /front actor:s
2 |
3 | /description Change the draw order for an actor to be in front of a reference actor. To move to the foreground, use `/front actor *`.
4 |
--------------------------------------------------------------------------------
/docs/help/help-assets-path.osc:
--------------------------------------------------------------------------------
1 | /assets/path [path:s]
2 |
3 | /description Sets the path to the assets root directory. If no argument is provided, it returns the current value of the path.
4 |
--------------------------------------------------------------------------------
/docs/help/help-size.osc:
--------------------------------------------------------------------------------
1 | /size actor:s
2 |
3 | /description Set the actor's uniform size. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/RoutineNode.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=2]
2 |
3 | [ext_resource path="res://RoutineNode.gd" type="Script" id=1]
4 |
5 | [node name="TimerNode" type="Timer"]
6 | script = ExtResource( 1 )
7 |
--------------------------------------------------------------------------------
/docs/tutorial.osc:
--------------------------------------------------------------------------------
1 | # ANIMATRON TUTORIAL
2 | # ------------------
3 | # Welcome to the Animatron Tutorial.
4 |
5 | # Put the cursor on the next line and press SHIFT + ENTER
6 |
7 | /tutorial/controls
8 |
--------------------------------------------------------------------------------
/default_env.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Environment" load_steps=2 format=2]
2 |
3 | [sub_resource type="ProceduralSky" id=1]
4 |
5 | [resource]
6 | background_mode = 2
7 | background_sky = SubResource( 1 )
8 |
--------------------------------------------------------------------------------
/docs/help/help-deselect.osc:
--------------------------------------------------------------------------------
1 | /deselect [actor:s]
2 |
3 | /description Remove the actor from the selected set. If run without ACTOR it will deselect all (equivalent to `/deselect "*"` or `/deselect "!"`).
4 |
--------------------------------------------------------------------------------
/docs/help/help-angle.osc:
--------------------------------------------------------------------------------
1 | /angle actor:s
2 |
3 | /description Set the actor's rotation angle to DEGREES. If DUR is set, interpolate the rotation over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-size-x.osc:
--------------------------------------------------------------------------------
1 | /size/x actor:s
2 |
3 | /description Set the actor's uniform size on the x axis. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-size-y.osc:
--------------------------------------------------------------------------------
1 | /size/y actor:s
2 |
3 | /description Set the actor's uniform size on the y axis. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-sound.osc:
--------------------------------------------------------------------------------
1 | /sound band:i
2 |
3 | /description Map the amplitude of the sound input at the frequency BAND to any COMMAND within the range MIN and MAX (if ommited they default to `[0.0..1.0]`)
4 |
--------------------------------------------------------------------------------
/docs/help/help-color-b.osc:
--------------------------------------------------------------------------------
1 | /color/b actor:s
2 |
3 | /description Add a Blue value to the actor. Should be in the 0-1 range (can be negative to subtract colour). Set to black (0,0,0) to restore its original colour.
4 |
--------------------------------------------------------------------------------
/docs/help/help-color-r.osc:
--------------------------------------------------------------------------------
1 | /color/r actor:s
2 |
3 | /description Add a Red value to the actor. Should be in the 0-1 range (can be negative to subtract colour). Set to black (0,0,0) to restore its original colour.
4 |
--------------------------------------------------------------------------------
/docs/help/help-rotate.osc:
--------------------------------------------------------------------------------
1 | /rotate actor:s
2 |
3 | /description Add DEGREE'S to the actor's rotation angle. If DUR is set, interpolate the rotation over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-color-g.osc:
--------------------------------------------------------------------------------
1 | /color/g actor:s
2 |
3 | /description Add a Green value to the actor. Should be in the 0-1 range (can be negative to subtract colour). Set to black (0,0,0) to restore its original colour.
4 |
--------------------------------------------------------------------------------
/docs/help/help-scale.osc:
--------------------------------------------------------------------------------
1 | /scale actor:s
2 |
3 | /description Set the actor's relative uniform scale to the current size. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-state-add.osc:
--------------------------------------------------------------------------------
1 | /state/add actor new_state ... next_states
2 |
3 | /description Add a NEW_STATE to the ACTOR's state machine. NEXT_STATES is an arbitrary number of next possible states. States are asset names.
4 |
--------------------------------------------------------------------------------
/docs/help/help-size-xy.osc:
--------------------------------------------------------------------------------
1 | /size/xy actor:s
2 |
3 | /description Set the actor's size for the X and Y axis (may be different). If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-color.osc:
--------------------------------------------------------------------------------
1 | /color actor:s
2 |
3 | /description Add an RGB colour to the actor. Red, green and blue should be in the 0-1 range (can be negative to subtract colour). Set to black (0,0,0) to restore its original colour.
4 |
--------------------------------------------------------------------------------
/docs/help/help-scale-x.osc:
--------------------------------------------------------------------------------
1 | /scale/x actor:s
2 |
3 | /description Set the actor's relative scale to the current size on the x axis. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-scale-xy.osc:
--------------------------------------------------------------------------------
1 | /scale/xy actor:s
2 |
3 | /description Set the actor's relative scale to the current size on both axis. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-scale-y.osc:
--------------------------------------------------------------------------------
1 | /scale/y actor:s
2 |
3 | /description Set the actor's relative scale to the current size on the y axis. If DUR is set, interpolate the scale over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-window-size.osc:
--------------------------------------------------------------------------------
1 | /window/size sx:i
2 |
3 | /description Set window to the specified size in pixels. -1 may be specified for either SX or SY, in which case it will be computed using the project viewport aspect ratio.
4 |
--------------------------------------------------------------------------------
/docs/help/help-create-group.osc:
--------------------------------------------------------------------------------
1 | /create/group group:s
2 |
3 | /description Create a batch of actors with a given (loaded) animation. A group will be created with this name and each actor will be named after the group with an index sufix.
4 |
--------------------------------------------------------------------------------
/docs/help/help-frame.osc:
--------------------------------------------------------------------------------
1 | /frame actor:s
2 |
3 | /description Jump to the given frame number (with wrapping). If a FLOAT from 0-1 is passed, it will jump to the frame corresponding to that position (0 being the first frame and 1 the last).
4 |
--------------------------------------------------------------------------------
/docs/help/help-onframe-free.osc:
--------------------------------------------------------------------------------
1 | /onframe/free actor:s
2 |
3 | /description Remove SUBCOMMAND trigger from FRAME. The SUBCOMMAND only needs the command address (with leading `/`) and the actor name -- don't any the command parameter value.
4 |
--------------------------------------------------------------------------------
/docs/help/help-ysort.osc:
--------------------------------------------------------------------------------
1 | /ysort [sort:b]
2 |
3 | /description Force actors to be sorted based on y position (lower on screen drawn later, i.e. "on top"). SORT argument defaults to TRUE, but initial state of y-sorting at startup is FALSE.
4 |
--------------------------------------------------------------------------------
/docs/help/help-choose.osc:
--------------------------------------------------------------------------------
1 | /choose cmd1
2 |
3 | /description Randomly choose one of the **comma separated** commands and send it. Commands are fully formed commands with the regular OSC syntax. **NOTE: commas need to be SURROUNDED by SPACES.**
4 |
--------------------------------------------------------------------------------
/docs/help/help-fade.osc:
--------------------------------------------------------------------------------
1 | /fade actor:s
2 |
3 | /description Set the actor's opacity realtive to the current value (where 1 is keep as it is). If DUR is set, interpolate the fade over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-list-assets-reply.osc:
--------------------------------------------------------------------------------
1 | /list/assets/reply [asset:s]
2 |
3 | /description return the list of available (unloaded) assets to the client (one name per argument). assets must be loaded as anims in order to create actor instances.
4 |
--------------------------------------------------------------------------------
/docs/help/help-wait.osc:
--------------------------------------------------------------------------------
1 | /wait duration
2 |
3 | /description Wait for DURATION seconds before executing the next command. Only relevant within a list of commands being executed together at once, such as inside a custom DEFined command list.
4 |
--------------------------------------------------------------------------------
/docs/help/help-alpha.osc:
--------------------------------------------------------------------------------
1 | /alpha actor:s
2 |
3 | /description Set the actor's opacity, where 1 is fully opaque/visible and 0 is transparent/invisible). If DUR is set, interpolate the alpha over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-load-config.osc:
--------------------------------------------------------------------------------
1 | /load/config filename:s
2 |
3 | /description Load a config file following the DEF syntax (**WARNING** This might change in the futre). After loading the file, the method defined with DEF needs to be explicitly called.
4 |
--------------------------------------------------------------------------------
/docs/help/help-onfinish-free.osc:
--------------------------------------------------------------------------------
1 | /onfinish/free actor:s
2 |
3 | /description Remove SUBCOMMAND trigger from the last frame. The SUBCOMMAND only needs the command address (with leading `/`) and the actor name -- don't any the command parameter value.
4 |
--------------------------------------------------------------------------------
/docs/help/help-position-x.osc:
--------------------------------------------------------------------------------
1 | /position/x actor:s
2 |
3 | /description Set the actor to the x coordinate (specified as fractions of the viewport from 0-1). If DUR is set, interpolate the movement over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-position-y.osc:
--------------------------------------------------------------------------------
1 | /position/y actor:s
2 |
3 | /description Set the actor to the y coordinate (specified as fractions of the viewport from 0-1). If DUR is set, interpolate the movement over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-position.osc:
--------------------------------------------------------------------------------
1 | /position actor:s
2 |
3 | /description Set the actor to the x,y coordinates (specified as fractions of the viewport from 0-1). If DUR is set, interpolate the movement over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-create.osc:
--------------------------------------------------------------------------------
1 | /create actor:s
2 |
3 | /description Create a new actor with a given (loaded) animation. If the named actor already exists, change its animation to the one specified. The initial position of a new actor will be at (0.5,0.5), the centre of the viewport.
4 |
--------------------------------------------------------------------------------
/docs/help-create.osc:
--------------------------------------------------------------------------------
1 | /create actor animation
2 |
3 | /despcription Create a new ACTOR with a given (loaded) ANIMATION. If the named actor already exists, change its animation to the one specified. The initial position of a new actor will be at (0.5,0.5), the centre of the viewport.
4 |
--------------------------------------------------------------------------------
/docs/help/help-loop.osc:
--------------------------------------------------------------------------------
1 | /loop actor:s
2 |
3 | /description Set the ACTOR's animation to loop.
4 | /loop actor:s
5 |
6 | /description Enable or disable looped animation playback. ENABLE argument defaults to TRUE, and initial state of animation looping for new actors is also TRUE.
7 |
--------------------------------------------------------------------------------
/docs/help/help-move.osc:
--------------------------------------------------------------------------------
1 | /move actor:s
2 |
3 | /description Move the actor to the x,y coordinates relative to the current position (specified as fractions of the viewport from 0-1). If DUR is set, interpolate the movement over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-move-x.osc:
--------------------------------------------------------------------------------
1 | /move/x actor:s
2 |
3 | /description Move the actor to the x coordinate relative to the current position (specified as fractions of the viewport from 0-1). If DUR is set, interpolate the move/xment over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-move-y.osc:
--------------------------------------------------------------------------------
1 | /move/y actor:s
2 |
3 | /description Move the actor to the y coordinate relative to the current position (specified as fractions of the viewport from 0-1). If DUR is set, interpolate the move/xment over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-load.osc:
--------------------------------------------------------------------------------
1 | /load asset:s
2 |
3 | /description Load an (animation) asset from disk. It will create an ANIM with the same name as the asset. Wildcards are supported, so several animations can be loaded at once. The list of assets available to load can be found by calling `/list/assets`.
4 |
--------------------------------------------------------------------------------
/actions/Action.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 | class_name Action, "res://icons/action.svg"
3 |
4 | onready var actor = get_parent()
5 | onready var offsetNode = actor.get_node("Offset")
6 | var curTime : float = 0.0
7 |
8 | func _init():
9 | pass
10 |
11 |
12 | func updateTime(delta : float):
13 | curTime += delta
14 |
15 |
--------------------------------------------------------------------------------
/docs/help/help-pivot.osc:
--------------------------------------------------------------------------------
1 | /pivot actor:s
2 |
3 | /description Set the actor's animation pivot to the specified point. PX and PY should be in the normalized range 0-1, with 0 being left/top of the frame and 1 being right/bottom. If DUR is set, interpolate the pivot over that number of seconds, otherwise change instantaneously.
4 |
--------------------------------------------------------------------------------
/docs/help/help-group.osc:
--------------------------------------------------------------------------------
1 | /group group:s
2 |
3 | /description Add the actor to a named group. If run without ACTOR it will return the list of actors in the group. Note that `/group "myGroup" "!"` may be used to add the current selection to a group. Use the group name as an actor name in all commands to apply it to all it's members.
4 |
--------------------------------------------------------------------------------
/addons/gdosc/gdoscmsg.gdns:
--------------------------------------------------------------------------------
1 | [gd_resource type="NativeScript" load_steps=2 format=2]
2 |
3 | [ext_resource path="res://addons/gdosc/gdosc.gdnlib" type="GDNativeLibrary" id=1]
4 |
5 | [resource]
6 |
7 | resource_name = "oscmsg"
8 | class_name = "oscmsg"
9 | library = ExtResource( 1 )
10 | _sections_unfolded = [ "Resource" ]
11 |
--------------------------------------------------------------------------------
/docs/help/help-onframe.osc:
--------------------------------------------------------------------------------
1 | /onframe actor:s
2 |
3 | /description Add SUBCOMMAND to be triggered on FRAME. The SUBCOMMAND can be any valid command. For example, to create an animation sequence, the animation asset can be changed on the desired FRAME: `/create actorA animA` `/onframe actorA 8 /create actorA animB`.
4 |
--------------------------------------------------------------------------------
/addons/gdosc/gdoscsender.gdns:
--------------------------------------------------------------------------------
1 | [gd_resource type="NativeScript" load_steps=2 format=2]
2 |
3 | [ext_resource path="res://addons/gdosc/gdosc.gdnlib" type="GDNativeLibrary" id=1]
4 |
5 | [resource]
6 |
7 | resource_name = "oscsender"
8 | class_name = "oscsender"
9 | library = ExtResource( 1 )
10 | _sections_unfolded = [ "Resource" ]
11 |
--------------------------------------------------------------------------------
/docs/help/help-debug.osc:
--------------------------------------------------------------------------------
1 | /debug [enable:b]
2 |
3 | /description Enable (or disable) reporting of informative status messages (via OSC and to the debug window). By default, this is disabled when running in exported builds, but enabled when running in the Godot editor. This flag does not affect error reporting (errors are always reported).
4 |
--------------------------------------------------------------------------------
/addons/gdosc/gdoscreceiver.gdns:
--------------------------------------------------------------------------------
1 | [gd_resource type="NativeScript" load_steps=2 format=2]
2 |
3 | [ext_resource path="res://addons/gdosc/gdosc.gdnlib" type="GDNativeLibrary" id=1]
4 |
5 | [resource]
6 |
7 | resource_name = "oscreceiver"
8 | class_name = "oscreceiver"
9 | library = ExtResource( 1 )
10 | _sections_unfolded = [ "Resource" ]
11 |
--------------------------------------------------------------------------------
/docs/help/help-action.osc:
--------------------------------------------------------------------------------
1 | /action actor:s
2 |
3 | /description Apply an action (behaviour) to the actor. Actions are script classes that define custom behaviours, such as "wander". Each action type will have its own unique list of arguments. You can see the [built-in actions here](#actions). Calling it without any ACTION will remove any existing actions.
4 |
--------------------------------------------------------------------------------
/docs/tutorial-index.osc:
--------------------------------------------------------------------------------
1 | # INDEX
2 | # -----
3 | # put the cursor on a line and press SHIFT + ENTER
4 |
5 | /tutorial/welcome
6 | /tutorial/controls
7 | /tutorial/commands
8 |
9 | # actors
10 |
11 | /tutorial/actors
12 | /tutorial/actor-attributes
13 | /tutorial/actor-animation
14 | /tutorial/actor-multi
15 |
16 | # utils
17 |
18 | /tutorial/utils-rand
19 |
--------------------------------------------------------------------------------
/addons/gdosc/gdosc.gdnlib:
--------------------------------------------------------------------------------
1 | [general]
2 |
3 | singleton=false
4 | load_once=true
5 | symbol_prefix="godot_"
6 | reloadable=true
7 |
8 | [entry]
9 |
10 | X11.64="res://addons/gdosc/bin/x11/libgdosc.so"
11 | Windows.64="res://addons/gdosc/bin/win64/libgdosc.dll"
12 | OSX.64="res://addons/gdosc/bin/osx/libgdosc.dylib"
13 |
14 | [dependencies]
15 |
16 | X11.64=[ ]
17 | Windows.64=[ ]
18 | OSX.64=[ ]
19 |
--------------------------------------------------------------------------------
/docs/help/help-midi.osc:
--------------------------------------------------------------------------------
1 | /midi
2 |
3 | /description Map the MIDIMSG (NOTEON, NOTEOFF, CC, VELOCITY) received in channel MIDICH to a COMMAND within a range between MIN and MAX. For `noteon/noteoff` events, a `*` wildcard can be passed as MIDINUM to use the note number as value (ignoring the velocity). The VELOCITY midimsg maps the velocity of all notes to COMMAND, passing it as an argument (ignoring the note number).
4 |
--------------------------------------------------------------------------------
/docs/help/help-def.osc:
--------------------------------------------------------------------------------
1 | /def cmdName
2 |
3 | /description Define a custom OSC command that is a list of other OSC commands. This may be recursive, so each SUBCOMMAND may reference one of the built-in commands, or another custom-defined command. Another way to define custom commands is via the file `commands/init.osc`. The CMDNAME string (first argument) may include argument names, which may be referenced as SUBCOMMAND arguments using $NAME. Example: `/def "/addsel actor anim" "/create $actor $anim" "/select $actor"`.
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Godot-specific
2 | .import/
3 | *.translation
4 | export.cfg
5 | export_presets.cfg
6 | .mono/
7 |
8 | # For now, keep animations out of git by default (can be added explicitly when desired)
9 | animations/
10 | runtime_data/
11 | commands/
12 | config/
13 |
14 | # Generated by MacOS
15 | .DS_Store
16 |
17 | # Generated by Windows
18 | Thumbs.db
19 |
20 | # Applications
21 | *.app
22 | *.exe
23 | *.war
24 |
25 | # Large media files
26 | *.mp4
27 | *.tiff
28 | *.avi
29 | *.flv
30 | *.mov
31 | *.wmv
32 |
33 |
--------------------------------------------------------------------------------
/commands/init_example.osc:
--------------------------------------------------------------------------------
1 | def /startup
2 | /load om-walk-*
3 | /wait 2
4 | /create walker om-walk-s
5 | /color walker 0.7 0.2 0.1
6 | /crowd
7 | /wait 3
8 | /say walker "Hi everybody!"
9 |
10 | def /createsel actor anim
11 | /create $actor $anim
12 | /select $actor
13 |
14 | def /crowd
15 | /deselect
16 | /createsel om1 om-walk-w
17 | /createsel om2 om-walk-w
18 | /createsel om3 om-walk-w
19 | /createsel om4 om-walk-w
20 | /createsel om5 om-walk-w
21 | /group crowd om?
22 |
23 |
--------------------------------------------------------------------------------
/docs/tutorial-utils-rand.osc:
--------------------------------------------------------------------------------
1 | # RANDOM
2 | # ------
3 | # single-value commands (commands with only one value as
4 | # agrument besides the TARGET), can be randomized with
5 | # the '/rand' command, which takes has a somewhat confusing
6 | # syntax, but which is consistent with the actor command syntax:
7 | # /rand /CMD TARGET MIN MAX
8 |
9 | # firts let's create something
10 |
11 | /free *
12 | /new box box
13 |
14 | # to randomize it's size we would use
15 |
16 | /rand /scale box 0.1 2
17 |
18 | # randomizing rotation would be done with
19 |
20 | /rand /rotate box 0 360
21 |
22 | /tutorial/index
23 |
--------------------------------------------------------------------------------
/OscSender.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | var oscsndr
4 |
5 | func _ready():
6 |
7 | oscsndr = load("res://addons/gdosc/gdoscsender.gdns").new()
8 | # [mandatory] will send messages to ip:port
9 |
10 | func connectRemote(args):
11 | var ip = args[0]
12 | var port = args[1]
13 | oscsndr.stop()
14 | oscsndr.setup( ip, port )
15 | # [mandatory] enabling emission
16 | oscsndr.start()
17 | print("connected to %s:%s" % [ip, port])
18 |
19 | func send(args):
20 | # address
21 | oscsndr.msg(args[0])
22 | # args
23 | if len(args) > 1:
24 | for arg in args.slice(1,-1):
25 | oscsndr.add(arg)
26 | # sending the message
27 | oscsndr.send()
28 | print("sent OSC message: %s" % [args])
29 |
30 | func _exit_tree ( ):
31 | # disable the sender, highly recommended!
32 | oscsndr.stop()
33 |
--------------------------------------------------------------------------------
/sc/sequence-test.scd:
--------------------------------------------------------------------------------
1 | a = Animatron();
2 |
3 | a.sendMsg("/free", "*");
4 | (
5 | a.sendMsg("/new", "na", "numbers");
6 | a.sendMsg("/load", "square");
7 | a.sendMsg("/speed", "na", 2/12);
8 | a.sendMsg("/scale", "na", 0.25);
9 |
10 | a.sendMsg("/onframe", "na", 4, "/position/x", "na", 0.2);
11 | a.sendMsg("/onframe", "na", 7, "/position/x", "na", 0.7);
12 | a.sendMsg("/onframe", "na", 2, "/scale", "na", 0.4);
13 | a.sendMsg("/onframe", "na", 8, "/scale", "na", 0.2);
14 | a.sendMsg("/onframe", "na", 9, "/create", "na", "square");
15 | a.sendMsg("/onframe", "na", 3, "/create", "na", "numbers");
16 | )
17 | a.sendMsg("/onframe/free", "na", 4, "/position/x", "na");
18 | a.sendMsg("/onframe/free", "na", 7, "/position/x", "na");
19 | a.sendMsg("/create", "la", "letter-a")
20 | a.sendMsg("/list/assets");
--------------------------------------------------------------------------------
/actions/wander.gd:
--------------------------------------------------------------------------------
1 | extends Action
2 |
3 | var noise := OpenSimplexNoise.new()
4 | var wanderRange : float = 0.1 # as a fraction of the screen
5 | var wanderSpeed : float = 1
6 |
7 |
8 | func _init(args : Array):
9 | if args.size() > 0:
10 | wanderRange = float(args[0])
11 | if args.size() > 1:
12 | wanderSpeed = float(args[1])
13 | noise.seed = randi()
14 | noise.octaves = 2
15 | noise.period = 4.0
16 | noise.persistence = 0.5
17 | noise.lacunarity = 2
18 |
19 |
20 | func _physics_process(delta : float):
21 | updateTime(delta * wanderSpeed)
22 | var pos = Vector2(noise.get_noise_1d(curTime), 0)
23 | pos = pos.rotated(PI * noise.get_noise_2d(-5.37, curTime))
24 | offsetNode.position = (pos * wanderRange * OS.window_size.y).linear_interpolate(Vector2(0,0), 1.0 - clamp(curTime*2.0, 0, 1))
25 |
--------------------------------------------------------------------------------
/docs/tutorial-controls.osc:
--------------------------------------------------------------------------------
1 | # CONTROLS
2 | # --------
3 | # Congrats! You already know how to use Animatron!
4 |
5 | # What you just did by pressing SHIFT + ENTER is EVALUATE A LINE
6 |
7 | # You can also EVALUATE A BLOCK by pressing CTRL + ENTER
8 | # A BLOCK is a group of lines that are not separated by empty lines. For example:
9 |
10 | /editor/append Line1 added to the end of this file
11 | /editor/append Line2 added to the end of this file
12 |
13 | # Try putting the cursor on either of the previous lines and evaluating the block
14 |
15 | # Now do it again but only evaluating one line (SHIFT + ENTER)
16 |
17 | # To go to the next section, evaluate the next line. If you prefer to see the
18 | # the index, evaluate the last one.
19 |
20 | # next
21 |
22 | /tutorial/commands
23 |
24 | # up
25 |
26 | /tutorial/index
27 |
--------------------------------------------------------------------------------
/icon.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://icon.png"
13 | dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/sc/sound-test.scd:
--------------------------------------------------------------------------------
1 | (
2 | a = Animatron();
3 | s.waitForBoot{
4 | Pdef(\a, Pbind(\amp, Pwhite(), \degree, Pwhite(0,7))).play;
5 | }
6 | )
7 |
8 | a.sendMsg("/debug", true);
9 | a.sendMsg("/debug", false);
10 | a.sendMsg("/load", "circle");
11 | a.sendMsg("/load", "canon-man");
12 | a.sendMsg("/list/assets");
13 | a.sendMsg("/free", "*");
14 | (
15 | a.sendMsg("/new", "ca", "circle");
16 | a.sendMsg("/new", "mac", "canon-man");
17 | // a.sendMsg("/color", "mac", 1,1,1);
18 | a.sendMsg("/frame", "mac", 300);
19 | a.sendMsg("/stop", "mac");
20 | a.sendMsg("/sound", 1, "/scale", "ca", 0.0,1.0);
21 | a.sendMsg("/sound", 1, "/frame", "mac", 300.0,400.0);
22 | )
23 | a.sendMsg("/sound/free", 1, "/scale", "ca");
24 | a.sendMsg("/sound", 1, "/scale", "ca", 0.0,1.0);
25 | a.sendMsg("/sound/free", 1, "/frame", "mac");
26 | a.sendMsg("/sound/free", 1);
27 |
--------------------------------------------------------------------------------
/icons/ull.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/ull.svg-37c61327b2d32f8ed5f3a8adb33fc72d.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://icons/ull.svg"
13 | dest_files=[ "res://.import/ull.svg-37c61327b2d32f8ed5f3a8adb33fc72d.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/icons/action.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/action.svg-deb8721e73a858622be9f72858aff2fe.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://icons/action.svg"
13 | dest_files=[ "res://.import/action.svg-deb8721e73a858622be9f72858aff2fe.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/icons/ull-16.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/ull-16.png-71fa0dc090ddf935f1cd59124836de4b.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://icons/ull-16.png"
13 | dest_files=[ "res://.import/ull-16.png-71fa0dc090ddf935f1cd59124836de4b.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/icons/ull-32.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/ull-32.png-b7e5ec678285ad754fc36dcef1e1ee70.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://icons/ull-32.png"
13 | dest_files=[ "res://.import/ull-32.png-b7e5ec678285ad754fc36dcef1e1ee70.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/icons/ull-48.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/ull-48.png-3078c5a5eaa642339e4ec588ceb335d0.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://icons/ull-48.png"
13 | dest_files=[ "res://.import/ull-48.png-3078c5a5eaa642339e4ec588ceb335d0.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/icons/ull-64.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/ull-64.png-80adc4edcdb1fd7e99ae24e7c78a4b89.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://icons/ull-64.png"
13 | dest_files=[ "res://.import/ull-64.png-80adc4edcdb1fd7e99ae24e7c78a4b89.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/icons/ull-128.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/ull-128.png-0865dd289f1bea08db13d18ce0600ac5.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://icons/ull-128.png"
13 | dest_files=[ "res://.import/ull-128.png-0865dd289f1bea08db13d18ce0600ac5.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/icons/ull-256.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/ull-256.png-9a0313a3dfac9419d880614fd03a5b5e.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://icons/ull-256.png"
13 | dest_files=[ "res://.import/ull-256.png-9a0313a3dfac9419d880614fd03a5b5e.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/gdosc/gdscript_oscsender_template.gd:
--------------------------------------------------------------------------------
1 | extends Object
2 |
3 | var oscsndr
4 |
5 | func _ready():
6 |
7 | oscsndr = load("res://addons/gdosc/gdoscsender.gdns").new()
8 | # [mandatory] will send messages to ip:port
9 | oscsndr.setup( "127.0.0.1", 12000 )
10 | # [mandatory] enabling emission
11 | oscsndr.start()
12 |
13 | func _process(delta):
14 | # creation of new message
15 | oscsndr.msg("/hello")
16 | # adding an object, will send its name
17 | oscsndr.add( self )
18 | # adding a float
19 | oscsndr.add( delta )
20 | # adding a Vector2
21 | oscsndr.add( Vector2( randf(), randf() ) )
22 | # adding a Vector3 (position, scale, rotation, etc)
23 | oscsndr.add( Vector3( randf(), randf(), randf() ) )
24 | # sending the message
25 | oscsndr.send()
26 | pass
27 |
28 | func _exit_tree ( ):
29 | # disable the sender, highly recommended!
30 | oscsndr.stop()
31 |
--------------------------------------------------------------------------------
/commands/tutorial-cmds.osc:
--------------------------------------------------------------------------------
1 | def /tutorial/welcome
2 | /tutorial
3 |
4 | def /tutorial/index
5 | /editor/open docs/tutorial-index.osc
6 |
7 | def /tutorial/controls
8 | /editor/open docs/tutorial-controls.osc
9 |
10 | def /tutorial/commands
11 | /editor/open docs/tutorial-commands.osc
12 |
13 | # actors
14 |
15 | def /tutorial/actors
16 | /editor/open docs/tutorial-actors.osc
17 |
18 | def /tutorial/actor-attributes
19 | /editor/open docs/tutorial-actor-attributes.osc
20 |
21 | def /tutorial/actor-animation
22 | /editor/open docs/tutorial-actor-animation.osc
23 |
24 | def /tutorial/actor-multi
25 | /editor/open docs/tutorial-actor-multi.osc
26 |
27 | # utils
28 |
29 | def /tutorial/utils-rand
30 | /editor/open docs/tutorial-utils-rand.osc
31 |
32 | def /tutorial/utils-custom-cmds
33 | /editor/open docs/tutorial-utils-custom-cmds.osc
34 |
--------------------------------------------------------------------------------
/docs/KeyboardShortcuts.md.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Keyboard Shortcuts
4 |
5 | ## Editor
6 |
7 | Keys | Description
8 | --------|------
9 | `CTRL + H` | show this help and OSC commands.
10 | `CTRL + ENTER` | evaluate current block.
11 | `SHIFT + ENTER` | evaluate current line.
12 | `CTRL + E` | toggle editor and post window.
13 | `CTRL + SHIFT + E` | toggle editor.
14 | `CTRL + P` | toggle post window.
15 | `CTRL + SHIFT + P` | clear post window.
16 | `CTRL + O` | open a file in the text editor.
17 | `CTRL + S` | save the contents of the text editor to a file.
18 | `CTRL + D` | duplicate line.
19 | `CTRL + +` | increase font
20 | `CTRL + -` | increase font
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/sc/config-test.scd:
--------------------------------------------------------------------------------
1 | (
2 | ////////////////////////////////////////////////////////////
3 | // Setup
4 | ////////////////////////////////////////////////////////////
5 | "setup.scd".loadRelative.first;
6 | )
7 |
8 | n.sendMsg("/list/assets")
9 | n.sendMsg("/load/config", "res://config/config.osc");
10 | n.sendMsg("/config");
11 | n.sendMsg("/assets/path"); // report the current path
12 | n.sendMsg("/assets/path", "myanimations/");
13 | n.sendMsg("/assets/path", "animations/");
14 | n.sendMsg("/assets/path", "res://animations/"); // should do same as previous line
15 | n.sendMsg("/window/screen", 1);
16 | n.sendMsg("/window/position", 1500, 200);
17 | n.sendMsg("/window/center"); // works only on display 1 (?)
18 | n.sendMsg("/window/fullscreen", 1);
19 | n.sendMsg("/window/fullscreen", 0);
20 | n.sendMsg("/window/size", 640, -1);
21 | n.sendMsg("/window/top");
22 | n.sendMsg("/window/top", false);
23 | n.sendMsg("/window/top", true);
24 | n.sendMsg("/window/top", 0);
25 | n.sendMsg("/window/top", 1);
26 |
--------------------------------------------------------------------------------
/docs/tutorial-actor-animation.osc:
--------------------------------------------------------------------------------
1 | # ACTOR ANIMATION
2 | # ---------------
3 | # Some commands manage animation parameters.
4 |
5 | /free *
6 | /new box box-spitneat
7 |
8 | # For example, we can change the animation speed (1 being normal)
9 |
10 | /speed box 0.5
11 |
12 | /speed box 2
13 |
14 | /speed box 1
15 |
16 | # stop
17 |
18 | /stop box
19 |
20 | # set a frame (if the number is greater than the number for frames
21 | # it will wrap around 0)
22 |
23 | /frame box 8
24 |
25 | # play again
26 |
27 | /play box
28 |
29 | # play backwards
30 |
31 | /play/reverse box
32 |
33 | # play forwards
34 |
35 | /play box
36 |
37 | # stop the looping
38 |
39 | /noloop box
40 |
41 | # play once and vanish (it only hides the animation -- try evaluating it
42 | # multiple times
43 |
44 | /once box
45 |
46 | # in the next section we'll deal with multiple actors
47 |
48 |
49 |
50 | # next
51 |
52 | /tutorial/actor-multi
53 |
54 | # previous
55 |
56 | /tutorial/actor-attributes
57 |
58 | # up
59 |
60 | /tutorial/index
61 |
--------------------------------------------------------------------------------
/RoutineNode.gd:
--------------------------------------------------------------------------------
1 | extends Timer
2 |
3 | # This is not the code for the Main.Routines node.
4 | # Main.Routines holds different instances of this script, which is a
5 | # single routine.
6 |
7 | var cmd : Array
8 | onready var main = get_parent().get_parent()
9 | onready var repeats = 0 setget setRepeats
10 | onready var iteration = 0
11 |
12 | func _ready():
13 | wait_time = 1.0
14 | connect("timeout", self, "next")
15 |
16 | func setRepeats( inRepeats ):
17 | if inRepeats == "inf":
18 | repeats = 0
19 | return
20 | repeats = int(inRepeats)
21 |
22 | func next():
23 | if len(cmd) <= 0:
24 | print("routine without commands: %s %s" % [name, cmd])
25 | return
26 |
27 | # print("routine:%s iteration:%s/%s cmd:%s" % [name, iteration+1, repeats, cmd])
28 | main.evalCommandList([cmd], null)
29 |
30 | if repeats != 0 and iteration >= (repeats - 1):
31 | print("routine ended after %s times: %s" % [iteration + 1, name])
32 | iteration = 0
33 | remove_and_skip()
34 | return
35 |
36 | iteration = (iteration + 1) % max(repeats, 1)
37 |
--------------------------------------------------------------------------------
/docs/tutorial-commands.osc:
--------------------------------------------------------------------------------
1 | # COMMANDS
2 | # --------
3 | # The lines that you've been evaluating are called COMMANDS.
4 |
5 | # Everything in Animatron is controlled with commands.
6 | # The syntax for ALL commands is:
7 |
8 | /CMD TARGET ARGS...
9 |
10 | # the CMD is any string with a leading slash '/'
11 | # the TARGET is who are you commanding to do something
12 | # the ARGS is any number of parameters that we need to pass to the command (there
13 | # can be none)
14 |
15 | # to see a list of all the commands in the POST WINDOW (to the right of this text) evaluate
16 |
17 | /list/commands
18 |
19 | # see docs/Reference.md.html for descriptions.
20 |
21 | # We use commands to create and modify ACTORS, print info on the POST WINDOW,
22 | # and interact with the APPLICATION.
23 | # The list of commands is too long to cover them all, so we'll just show you some basic ones
24 |
25 | # For example, let's change de background color by passing it RGB values
26 |
27 | /bg 0.2 0.2 0.2
28 |
29 | # next
30 |
31 | /tutorial/actors
32 |
33 | # previous
34 |
35 | /tutorial/controls
36 |
37 | # up
38 |
39 | /tutorial/index
40 |
--------------------------------------------------------------------------------
/sc/salonLetters.txt:
--------------------------------------------------------------------------------
1 | /load/alphabet
2 |
3 | /letters/spacing 0.2
4 | /letters/scale 1.2
5 |
6 | /write salon
7 | /create s letter-s
8 |
9 | /front l *
10 | /free *
11 | /list
12 |
13 | /rotate * 90 2
14 |
15 | /move * 0 -0.5 4
16 |
17 |
18 | //////////
19 |
20 | /load/alphabet
21 |
22 | /create s letter-s
23 | /state/add s letter-s letter-a
24 | /state/add s letter-a letter-l
25 | /state/add s letter-l letter-o letter-a
26 | /state/add s letter-o letter-n
27 | /state/add s letter-n letter-s
28 |
29 | /load boomBig
30 |
31 | /def /let actor
32 | /create $actor letter-s
33 | /size $actor 0.333
34 | /rand /color/r $actor -0.6 -0.1
35 | /rand /color/g $actor -0.6 -0.1
36 | /rand /color/b $actor -0.6 -0.1
37 | /rand /position/x $actor 0.2 0.8
38 | /rand /position/y $actor 0.1 0.9
39 | /state/add $actor letter-s letter-s letter-a
40 | /state/add $actor letter-a letter-a letter-l
41 | /state/add $actor letter-l letter-l letter-o
42 | /state/add $actor letter-o letter-o letter-n
43 | /state/add $actor letter-n letter-n letter-s boomBig
44 | /state/add $actor boomBig letter-s
45 |
46 | /let a0
47 |
48 | /fade * 0 5
49 | /free *
50 |
--------------------------------------------------------------------------------
/addons/gdosc/gdscript_oscreceiver_template.gd:
--------------------------------------------------------------------------------
1 | extends Object
2 |
3 | var oscrcv
4 |
5 | func _ready():
6 |
7 | oscrcv = load("res://addons/gdosc/gdoscreceiver.gdns").new()
8 | # [optional] maximum number of messages in the buffer, default is 100
9 | oscrcv.max_queue( 20 )
10 | # [optional] receiver will only keeps the "latest" message for each address
11 | oscrcv.avoid_duplicate( true )
12 | # [mandatory] listening to port 14000
13 | oscrcv.setup( 14000 )
14 | # [mandatory] starting the reception of messages
15 | oscrcv.start()
16 |
17 | func _process(delta):
18 |
19 | # check if there are pending messages
20 | while( oscrcv.has_message() ):
21 | # retrieval of the messages as a dictionary
22 | var msg = oscrcv.get_next()
23 | # printing the values, check console
24 | print( "address:", msg["address"] )
25 | print( "typetag:", msg["typetag"] )
26 | print( "from:" + str( msg["ip"] ) + ":" + str( msg["port"] ) )
27 | print( "arguments: ")
28 | for i in range( 0, msg["arg_num"] ):
29 | print( "\t", i, " = ", msg["args"][i] )
30 | pass
31 |
32 | func _exit_tree ( ):
33 | # disable the receiver, highly recommended!
34 | oscrcv.stop()
35 |
--------------------------------------------------------------------------------
/docs/tutorial-utils-custom-cmds.osc:
--------------------------------------------------------------------------------
1 | # CUSTOM COMMANDS (DEFS)
2 | # -----------
3 | # We can define custom commands with '/def'.
4 | # This is useful to combine simple commands into complex instructions.
5 |
6 | # The syntax for '/def' is
7 |
8 | /def /NEWCMD VARS...
9 | /CMD TARGET ARGS | $VARS ...
10 | /CMD TARGET ARGS | $VARS ...
11 | ...
12 |
13 | # NEWCMD: is the new command name - must include a leading slash '/'
14 | # VARS: (optional) are any number of strings that we can use in the embedded commands
15 | # CMD, TARGET and ARGS: any valid commands, including previously defined DEFs
16 | # they need to be tabluated (press tab on every new line)
17 | # VARS can be used in the commands with a leading $
18 |
19 | # for exmaple, we can create an actor at a random position with a random
20 | # size and a random color
21 |
22 | /def /randactor actor anim
23 | /new $actor anim
24 | /rand /position/x $actor 0.1 0.9
25 | /rand /position/y $actor 0.1 0.9
26 | /rand /scale $actor 0.3 0.7
27 | /rand /color/r $actor 0 1
28 | /rand /color/g $actor 0 1
29 | /rand /color/b $actor 0 1
30 |
--------------------------------------------------------------------------------
/docs/tutorial-actor-multi.osc:
--------------------------------------------------------------------------------
1 | # ACTOR MULTI
2 | # -----------
3 | # Let's create a few squares
4 |
5 | /free *
6 | /new sq-red square
7 | /create sq-green square
8 | /create sq-white square
9 |
10 | # now let's randomize their scale, color and position (evaluate
11 | # the block as many times as needed until you see the 3 squares
12 | # overlapping each-other)
13 |
14 | /rand /scale sq* 0.3 0.7
15 | /rand /position/x sq* 0.3 0.7
16 | /rand /position/y sq* 0.3 0.7
17 | /rand /color/r sq-red 0.4 0.7
18 | /rand /color/g sq-green 0.4 0.7
19 | /color sq-white 1 1 1
20 |
21 | # using a WILDCARD '*' we can tell Animatron to send any
22 | # command to all actors who's name begin with 'sq'.
23 |
24 | # we can rearrange the order in which the actors are stacked
25 | # by choosing which one we want on top or below any other one
26 |
27 | # for example, let's put 'sqe' in front of 'sqi'
28 |
29 | /front sq-red sq-green
30 |
31 | # and back behind it
32 |
33 | /behind sq-red sq-green
34 |
35 | # or put 'sqe' on top of all
36 |
37 | /front sq-red *
38 |
39 | # or at the background
40 |
41 | /behind sq-red *
42 |
43 |
44 |
45 |
46 | # related
47 |
48 | /tutorial/utils-rand
49 |
50 | # previous
51 |
52 | /tutorial/actor-attributes
53 |
54 | # up
55 |
56 | /tutorial/index
57 |
--------------------------------------------------------------------------------
/actions/oscillate.gd:
--------------------------------------------------------------------------------
1 | extends Action
2 |
3 | var oscPeriod := 1.0 # the period of one oscillation in seconds
4 | var oscRotRange : = 0.0 # between +/- this number of degrees
5 | var oscPosRange := Vector2(0.05, 0.05) # between +/- this (normalized) offset
6 | var oscPosFreq := Vector2(1, 2) # lissajous normalized frequencies (a, b)
7 | var oscPosPhase := 0.125 # the normalized phase (0-1 == 0-2pi) of the x component
8 |
9 |
10 | func _init(args : Array):
11 | if args.size() > 0:
12 | oscPeriod = float(args[0])
13 | if args.size() > 1:
14 | oscRotRange = float(args[1])
15 | if args.size() > 2:
16 | oscPosRange = Vector2(float(args[2]), float(args[2]))
17 | if args.size() > 3:
18 | oscPosRange.y = float(args[3])
19 | if args.size() > 4:
20 | oscPosFreq = Vector2(float(args[4]), float(args[4]))
21 | if args.size() > 5:
22 | oscPosFreq.y = float(args[5])
23 | if args.size() > 6:
24 | oscPosPhase = float(args[6])
25 |
26 |
27 | func _physics_process(delta : float):
28 | var deltaRadians = TAU * delta / oscPeriod
29 | updateTime(deltaRadians)
30 | var pos = Vector2(sin(oscPosFreq.x * curTime + oscPosPhase * TAU), sin(oscPosFreq.y * curTime)) * oscPosRange
31 | offsetNode.position = pos * OS.window_size.y
32 | offsetNode.rotation = deg2rad(oscRotRange * sin(curTime))
33 |
--------------------------------------------------------------------------------
/SpeechBubble.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=2]
2 |
3 | [ext_resource path="res://SpeechBubble.gd" type="Script" id=1]
4 |
5 | [sub_resource type="DynamicFontData" id=1]
6 | font_path = "res://fonts/WalterTurncoat.ttf"
7 |
8 | [sub_resource type="DynamicFont" id=2]
9 | size = 18
10 | extra_spacing_bottom = -11
11 | font_data = SubResource( 1 )
12 |
13 | [node name="SpeechBubble" type="Node2D"]
14 | script = ExtResource( 1 )
15 |
16 | [node name="Anchor" type="Node2D" parent="."]
17 |
18 | [node name="ColorRect" type="ColorRect" parent="Anchor"]
19 | margin_bottom = 24.0
20 | __meta__ = {
21 | "_edit_use_anchors_": false
22 | }
23 |
24 | [node name="RichTextLabel" type="RichTextLabel" parent="Anchor"]
25 | margin_bottom = 24.0
26 | custom_colors/default_color = Color( 0, 0, 0, 1 )
27 | custom_fonts/normal_font = SubResource( 2 )
28 | bbcode_enabled = true
29 | fit_content_height = true
30 | scroll_active = false
31 |
32 | [node name="Timer" type="Timer" parent="."]
33 | one_shot = true
34 |
35 | [node name="Tween" type="Tween" parent="."]
36 |
37 | [connection signal="resized" from="Anchor/RichTextLabel" to="." method="_on_RichTextLabel_resized"]
38 | [connection signal="timeout" from="Timer" to="." method="_on_Timer_timeout"]
39 | [connection signal="tween_all_completed" from="Tween" to="." method="_on_Tween_tween_all_completed"]
40 |
--------------------------------------------------------------------------------
/MetaNode.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=2]
2 |
3 | [ext_resource path="res://Animation.gd" type="Script" id=1]
4 | [ext_resource path="res://MetaNode.gd" type="Script" id=2]
5 |
6 | [sub_resource type="Shader" id=4]
7 | code = "shader_type canvas_item;
8 |
9 | uniform vec3 uAddColor = vec3(0, 0, 0);
10 | uniform bool uSelected = false;
11 |
12 | void fragment() {
13 |
14 | COLOR = texture(TEXTURE, UV);
15 | COLOR.rgb += uAddColor;
16 | if (uSelected) {
17 | if (COLOR.a < 1.0) COLOR.rgb = vec3(1);
18 | }
19 | }"
20 |
21 | [sub_resource type="ShaderMaterial" id=2]
22 | resource_local_to_scene = true
23 | shader = SubResource( 4 )
24 | shader_param/uAddColor = Vector3( 0, 0, 0 )
25 | shader_param/uSelected = false
26 |
27 | [sub_resource type="SpriteFrames" id=3]
28 | animations = [ ]
29 |
30 | [node name="MetaNode" type="KinematicBody2D"]
31 | position = Vector2( 500, 300 )
32 | script = ExtResource( 2 )
33 |
34 | [node name="Offset" type="Node2D" parent="."]
35 |
36 | [node name="Animation" type="AnimatedSprite" parent="Offset"]
37 | material = SubResource( 2 )
38 | frames = SubResource( 3 )
39 | script = ExtResource( 1 )
40 |
41 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
42 |
43 | [node name="Tween" type="Tween" parent="."]
44 |
45 | [connection signal="animation_finished" from="Offset/Animation" to="Offset/Animation" method="_on_Animation_animation_finished"]
46 |
--------------------------------------------------------------------------------
/sc/walkers.scd:
--------------------------------------------------------------------------------
1 | (
2 | ////////////////////////////////////////////////////////////
3 | // Setup
4 | ////////////////////////////////////////////////////////////
5 | "setup.scd".loadRelative.first;
6 | )
7 |
8 | x.("/load om-walk-e")
9 |
10 | (
11 | x.("/new bg bg-black");
12 | x.("/size bg 2");
13 | x.("/color bg 0.5 0.5 0.5");
14 | x.("/behind bg *");
15 | )
16 |
17 | (
18 | ~numActors = 20;
19 | ~numActors.do{ arg i;
20 | x.("/create om% om-walk-e".format(i));
21 | x.("/frame om% %".format(i, 50.rand));
22 | x.("/position om% % %".format(i, 1.0.rand, rrand(0.2,1)));
23 | x.("/color om% % % %".format(i, rrand(0, 0.5), rrand(0, 0.5), rrand(0, 0.5)));
24 | };
25 | )
26 |
27 | (
28 | n.sendMsg("/def", "/update actor speed size rate",
29 | "/fade $actor 0 2",
30 | "/wait 2",
31 | "/fade $actor 1 2",
32 | "/speed $actor $speed",
33 | "/size $actor $size", // add time argument (2) at the end
34 | "/action $actor wrap 0 $rate 0")
35 | )
36 | x.("/update om5 2 0.5 3")
37 |
38 | (
39 | Tdef(\anim, {
40 | 16.do{ arg outer;
41 | ~numActors.do{ arg i;
42 | var size = exprand(0.5,6) * 1;
43 | var speed = size.linexp(0.5,8, 2, 0.25) * 1;
44 | x.("/update om% % % %".format(i, speed, size, speed * size * 0.15));
45 | exprand(0.2,0.5).wait;
46 | };
47 | 1.wait;
48 | };
49 | }).play
50 | )
51 |
52 | Tdef(\anim).stop
53 | x.("/fade om* 0 4")
54 | x.("/free *")
55 |
56 | x.("/list/assets")
57 |
58 |
--------------------------------------------------------------------------------
/actions/wrap.gd:
--------------------------------------------------------------------------------
1 | extends Action
2 |
3 | var moveDir := 0.0 # the normalized direction of motion (angle in degrees)
4 | var moveSpeed := 1.0 # the speed of movement
5 | var rotSpeed := 0.0 # the speed of rotation
6 | const margin := 0.1 # extra "safety" zone around the viewport for wrapping
7 |
8 |
9 | func _init(args : Array):
10 | if args.size() > 0:
11 | moveDir = float(args[0])
12 | if args.size() > 1:
13 | moveSpeed = float(args[1])
14 | if args.size() > 2:
15 | rotSpeed = float(args[2])
16 |
17 |
18 | func _physics_process(delta : float):
19 | updateTime(delta)
20 | var offset = Vector2(moveSpeed, 0).rotated(deg2rad(moveDir)) * delta
21 | var newPos : Vector2 = actor.position + offset * OS.window_size.y
22 | actor.rotation_degrees = wrapf(actor.rotation_degrees + rotSpeed * delta, -180, 180)
23 | var animNode = offsetNode.get_node("Animation")
24 | var animName = animNode.animation
25 | var halfSize = animNode.frames.get_frame(animName, 0).get_size() / 2 * actor.scale
26 | halfSize = halfSize.rotated(deg2rad(actor.rotation_degrees)).abs()
27 | var animPos : Vector2 = animNode.position * actor.scale;
28 | animPos = animPos.rotated(deg2rad(actor.rotation_degrees))
29 | var extra : float = OS.window_size.y * margin
30 |
31 | actor.position = Vector2(
32 | wrapf(newPos.x,
33 | -halfSize.x - animPos.x - extra,
34 | OS.window_size.x + halfSize.x - animPos.x + extra),
35 | wrapf(newPos.y,
36 | -halfSize.y - animPos.y - extra,
37 | OS.window_size.y + halfSize.y - animPos.y + extra))
38 |
--------------------------------------------------------------------------------
/sc/setup.scd:
--------------------------------------------------------------------------------
1 | (
2 | ////////////////////////////////////////////////////////////
3 | // Setup
4 | ////////////////////////////////////////////////////////////
5 | var separateBySpaces;
6 | OSCdef(\listActorsReply, { arg msg;
7 | "Actors: %".format(msg[1..]).postln;
8 | }, "/list/actors/reply");
9 | OSCdef(\listAnimsReply, { arg msg;
10 | "Available animations:\n\t%".format(join(msg[1..], "\n\t")).postln;
11 | }, "/list/anims/reply");
12 | OSCdef(\listAssetsReply, { arg msg;
13 | "Available assets:\n\t%".format(join(msg[1..], "\n\t")).postln;
14 | }, "/list/assets/reply");
15 | OSCdef(\errorReply, { arg msg;
16 | "Error: %".format(msg[1]).postln;
17 | }, "/error/reply");
18 | OSCdef(\statusReply, { arg msg;
19 | "Status: %".format(msg[1]).postln;
20 | }, "/status/reply");
21 | n = NetAddr("localhost", 56101);
22 | separateBySpaces = { arg str;
23 | // This regex isn't perfect, but works
24 | // reasonably well for most of my cases...
25 | var regex = '"(.+?)"|(?:([^"]+?)(?=\\s))|(?:(?<=\\s)([^"]+))'.asString;
26 | var arr = str.asString.findRegexp(regex).flop.last.clump(4).collect{ |x|
27 | x.drop(1).collect(_.stripWhiteSpace)
28 | }.flatten.reject(_.isEmpty);
29 | if (arr.isEmpty) { arr = [ str ] };
30 | arr
31 | };
32 |
33 | x = { arg ...args;
34 | if (args.notEmpty) {
35 | var arr = separateBySpaces.(args[0]);
36 | if (arr.notEmpty) {
37 | arr = arr ++ args[1..];
38 | n.sendMsg(*arr);
39 | arr
40 | };
41 | }
42 | };
43 |
44 | "Animatron ready.\nUse:\n\tn.sendMsg(\"/load\", \"asset\")\nor:\n\tx.(\"/load asset\")"
45 | )
46 |
--------------------------------------------------------------------------------
/docs/tutorial-actor-attributes.osc:
--------------------------------------------------------------------------------
1 | # CHANGING ACTOR ATTRIBUTES
2 | # ---------------------------
3 | # Actors can be manipulated to change their appearance an behaviour.
4 | # For a list of commands to change them, see the 'ACTOR' section in
5 |
6 | /list/commands
7 |
8 | # we'll show just a few of them and let you explore the rest
9 |
10 | # first, create a couple of actors
11 |
12 | /create box box-spitneat
13 |
14 | # POSITION
15 | # --------
16 | # We can change the position of any actor with
17 |
18 | /position/x box 0.2
19 |
20 | # or
21 | /position/y box 0.8
22 |
23 | #or
24 | /position box 0.5 0.2
25 |
26 | # the center of the screen is at x:0.5 y:0.5, 0 being left and top, and
27 | # 1 being bottom and right
28 |
29 | /position box 0.5 0.5
30 |
31 | # SCALE
32 | # ----
33 | # let's shrink it to half its size (1 is normal)
34 |
35 | /scale box 0.5
36 |
37 | # or make it bigger
38 |
39 | /scale box 1.5
40 |
41 | # ROTATION
42 | # --------
43 | # we rotate the actor along it's pivot point by degrees
44 |
45 | /rotate box 90
46 |
47 | /rotate box -90
48 |
49 | # COLOR
50 | # -----
51 | # the color is changed by specifying 3 color values (RED, GREEN and BLUE)
52 |
53 | /color/r box 1
54 |
55 | /color/g box 0.5
56 |
57 | /color/b box 0.7
58 |
59 | /color box 0.1 0.7 0.3
60 |
61 | /color box 0.3 0.2 0.6
62 |
63 | # back to the original color
64 |
65 | /color box 0 0 0
66 |
67 | # in the next section we'll cover animation manipulation
68 |
69 |
70 |
71 | # next
72 |
73 | /tutorial/actor-animation
74 |
75 | # previous
76 |
77 | /tutorial/actors
78 |
79 | # up
80 |
81 | /tutorial/index
82 |
--------------------------------------------------------------------------------
/docs/tutorial-actors.osc:
--------------------------------------------------------------------------------
1 | # ACTORS
2 | # ------
3 | # An ACTOR plays an image sequence (ANIM).
4 |
5 | # First we need to load the ANIM into memory with the '/load' command.
6 | # The argument is the ASSET (file) name.
7 |
8 | /load box-spitneat
9 |
10 | # to see a list of all the assets use
11 |
12 | /list/assets
13 |
14 | # now we can create an actor that plays the animation we just loaded.
15 | # 'box' is the actor NAME, and 'box-spitneat' the name of the ASSET that
16 | # we want it to play
17 |
18 | /create box box-spitneat
19 |
20 | # we can do both steps (load an create) at once with
21 |
22 | /new box box-spitneat
23 |
24 | # or by evaluating a block
25 |
26 | /load box-spitneat
27 | /create box box-spitneat
28 |
29 | # WARINING: long image sequences take a while to load, and the application
30 | # will freeze while loading, so it's better to pre-load the assets first, then
31 | # they'll be available without having to reload them, even if no actors
32 | # are using them.
33 |
34 | # to remove an actor from the stage
35 |
36 | /free box
37 |
38 | # more than one actor can use the same animation
39 |
40 | /create box-1 box-spitneat
41 |
42 | /create box-2 box-spitneat
43 |
44 | # You probably won't see it very well because they are one on top of the other.
45 | # We would need to move the one on top to see both of them.
46 | # In the next section we cover how to do this -- and other things.
47 |
48 | # but first, let's clear the stage using a wildcard '*', which is a way to
49 | # quickly access all actors on stage
50 |
51 | /free *
52 |
53 |
54 | # next
55 |
56 | /tutorial/actor-attributes
57 |
58 | # previous
59 |
60 | /tutorial/commands
61 |
62 | # up
63 |
64 | /tutorial/index
65 |
--------------------------------------------------------------------------------
/Logger.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | enum {
4 | LOG_LEVEL_FATAL,
5 | LOG_LEVEL_ERROR,
6 | LOG_LEVEL_WARNING,
7 | LOG_LEVEL_INFO,
8 | LOG_LEVEL_DEBUG,
9 | LOG_LEVEL_VERBOSE,
10 | }
11 |
12 | const levelNames = ["FATAL", "ERROR", "WARNING", "INFO", "DEBUG", "VERBOSE"]
13 |
14 | onready var level = LOG_LEVEL_INFO setget setLevel, getLevel
15 | var target : TextEdit
16 |
17 |
18 | func setTarget( inTarget ):
19 | target = inTarget
20 |
21 | func setLevel( inLevel ):
22 | level = inLevel
23 | logMsg("Log level set to: %s" % [levelNames[level]])
24 |
25 | func getLevel():
26 | return level
27 |
28 | func setLevelFatal():
29 | setLevel(LOG_LEVEL_FATAL)
30 |
31 | func setLevelError():
32 | setLevel(LOG_LEVEL_ERROR)
33 |
34 | func setLevelWarning():
35 | setLevel(LOG_LEVEL_WARNING)
36 |
37 | func setLevelInfo():
38 | setLevel(LOG_LEVEL_INFO)
39 |
40 | func setLevelDebug():
41 | setLevel(LOG_LEVEL_DEBUG)
42 |
43 | func setLevelVerbose():
44 | setLevel(LOG_LEVEL_VERBOSE)
45 |
46 | func fatal( msg ):
47 | logMsg("[FATAL]: %s" % [msg], true)
48 |
49 | func error( msg ):
50 | if level < LOG_LEVEL_ERROR:
51 | return
52 | logMsg("[ERROR]: %s" % [msg], true)
53 |
54 | func warn( msg ):
55 | if level < LOG_LEVEL_WARNING:
56 | return
57 | logMsg("[WARNING]: %s" % [msg], true)
58 |
59 | func info( msg ):
60 | if level < LOG_LEVEL_INFO:
61 | return
62 | logMsg("[INFO]: %s" % [msg], true)
63 |
64 | func debug( msg ):
65 | if level < LOG_LEVEL_DEBUG:
66 | return
67 | logMsg("[DEBUG]: %s" % [msg])
68 |
69 | func verbose( msg ):
70 | if level < LOG_LEVEL_VERBOSE:
71 | return
72 | logMsg("[VERBOSE]: %s" % [msg])
73 |
74 | func logMsg( msg, post=false ):
75 | print(msg)
76 | if target != null and post:
77 | target.append(msg)
78 |
79 | func logDict( dict, post=false ):
80 | for key in dict:
81 | logMsg("%s:%s" % [key, dict[key]], post)
82 |
--------------------------------------------------------------------------------
/SpeechBubble.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | onready var textNode = $Anchor/RichTextLabel
4 | onready var textBg = $Anchor/ColorRect
5 | onready var padding = 16
6 | onready var fadetime = 0
7 | onready var offset = Vector2(0, -96)
8 |
9 | # Called when the node enters the scene tree for the first time.
10 | func _ready():
11 | visible = false
12 | # setText("ALO Blah\nBLAH alO")
13 |
14 |
15 | func setText(text, wait = 3):
16 | visible = true
17 | $Timer.wait_time = wait
18 | $Timer.stop()
19 | text = "[center]" + text
20 | textNode.bbcode_text = text
21 | resizeBubble()
22 |
23 | $Tween.remove_all()
24 | # $Tween.interpolate_property(textNode, "modulate", Color(0,0,0,1), Color(0,0,0,0), fadetime, Tween.TRANS_EXPO)
25 | # $Tween.interpolate_property(textBg, "modulate", textBg.color, Color(0,0,0,0), fadetime)
26 | $Tween.start()
27 |
28 |
29 | # distribute text on even lines
30 | func formatText():
31 | print("TODO: format text in even lines")
32 | print("TODO: multiline")
33 | var words = textNode.text.count(" ") + 1
34 | # print("words: ", words)
35 |
36 |
37 | func resizeBubble():
38 | formatText()
39 | var textSize = textNode.get_font("normal_font").get_string_size(textNode.text)
40 | textNode.margin_right = textSize.x + padding
41 | textNode.margin_bottom = textSize.y * textNode.get_line_count() + padding
42 |
43 |
44 | func _on_Timer_timeout():
45 | queue_free()
46 | visible = false
47 |
48 |
49 | func _on_Tween_tween_all_completed():
50 | $Timer.start()
51 |
52 |
53 | func _on_RichTextLabel_resized():
54 | textBg.margin_right = textNode.margin_right
55 | textBg.margin_bottom = textNode.margin_bottom
56 | offset.x = textBg.margin_right / (-2)
57 |
58 | var animNode = get_node("../Offset/Animation")
59 | if animNode:
60 | var texSize = animNode.frames.get_frame(animNode.get_animation(), 0).get_size()
61 | offset.y = texSize.y * -0.55 - textNode.margin_bottom + animNode.position.y
62 |
63 | $Anchor.set_position(offset)
64 |
--------------------------------------------------------------------------------
/Letters.gd:
--------------------------------------------------------------------------------
1 | # A class to manage typing with images
2 | class_name Letters
3 | extends Node
4 |
5 |
6 | onready var main = get_parent()
7 | # spacing is a multiplier of actor width
8 | var spacing = 1
9 | var scale = 1
10 | var msg = ""
11 | var alphabet := {
12 | "a": "letter-a",
13 | "b": "letter-b",
14 | "c": "letter-c",
15 | "d": "letter-d",
16 | "e": "letter-e",
17 | "f": "letter-f",
18 | "g": "letter-g",
19 | "h": "letter-h",
20 | "i": "letter-i",
21 | "j": "letter-j",
22 | "k": "letter-k",
23 | "l": "letter-l",
24 | "m": "letter-m",
25 | "n": "letter-n",
26 | "o": "letter-o",
27 | "p": "letter-p",
28 | "q": "letter-q",
29 | "r": "letter-r",
30 | "s": "letter-s",
31 | "t": "letter-t",
32 | "u": "letter-u",
33 | "v": "letter-v",
34 | "w": "letter-w",
35 | "x": "letter-x",
36 | "y": "letter-y",
37 | "z": "letter-z",
38 | }
39 |
40 |
41 | # Called when the node enters the scene tree for the first time.
42 | func _ready():
43 | # loadAlphabet()
44 | pass # Replace with function body.
45 |
46 |
47 | # Called every frame. 'delta' is the elapsed time since the previous frame.
48 | #func _process(delta):
49 | # pass
50 |
51 |
52 | func loadAlphabet(inArgs, sender=null):
53 | for letter in alphabet.keys():
54 | main.evalOscCommand("/load", [alphabet[letter]], null)
55 |
56 |
57 | func setLetter(inArgs, sender=null):
58 | var letter = inArgs[0]
59 | var source = inArgs[1]
60 | alphabet[letter] = source
61 |
62 |
63 | func write(inArgs, sender=null):
64 | msg = inArgs[0]
65 | for i in msg.length():
66 | var letter = msg[i]
67 | var pos = i * spacing
68 | print(letter + ": " + alphabet[letter])
69 | main.evalOscCommand("/create", [letter, alphabet[letter]], null)
70 | main.evalOscCommand("/position", [letter, pos, 0.5], null)
71 |
72 |
73 | func setSpacing(inArgs, sender=null):
74 | spacing = inArgs[0] as float
75 | write([msg], null)
76 |
77 |
78 | func setScale(inArgs, sender=null):
79 | print("TODO SCALE " + str(inArgs[0]))
80 | for x in msg:
81 | main.evalOscCommand("/scale", [x, inArgs[0]], null)
82 |
--------------------------------------------------------------------------------
/CustomCommands.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 | class_name CustomCommands
3 |
4 | var commands = {}
5 |
6 |
7 | func defineCommand(defCommand : String, defArgs : Array, commandList : Array):
8 | commands[defCommand] = { args = defArgs, cmds = commandList }
9 |
10 |
11 | func loadCommandFile(path):
12 | var file = File.new()
13 | file.open(path, File.READ)
14 | if not file.is_open():
15 | print("Unable to open command defs file: " + path)
16 | return false
17 | var lineNum = 1
18 | var defCommand
19 | var defArgs = []
20 | var commandList = []
21 | while file.is_open() && !file.eof_reached():
22 | var filteredLine = []
23 | # @todo Replace when Godot Array gets a filter() function (4.0)
24 | for elem in file.get_csv_line(" "):
25 | if !elem.empty():
26 | filteredLine.append(elem.strip_edges())
27 | if !file.eof_reached() && !filteredLine.empty():
28 | if filteredLine[0][0] == '#':
29 | # Ignore comment lines that start with '#'
30 | continue
31 | if filteredLine[0] == "def" && filteredLine.size() > 1:
32 | if defCommand && !commandList.empty():
33 | defineCommand(defCommand, defArgs, commandList)
34 | defCommand = filteredLine[1]
35 | defArgs = filteredLine.slice(2, -1)
36 | commandList = []
37 | print("%d: Defining '%s' with args: %s" % [lineNum, defCommand, defArgs])
38 | else:
39 | print("%d: [%s] %s" % [lineNum, defCommand, filteredLine])
40 | commandList.append(filteredLine)
41 | lineNum += 1
42 | file.close()
43 | if defCommand && !commandList.empty():
44 | defineCommand(defCommand, defArgs, commandList)
45 |
46 | for k in commands:
47 | print("Command: ", k, "\n", commands[k])
48 | return true
49 |
50 |
51 | func hasCommand(address):
52 | return commands.has(address)
53 |
54 |
55 | func getCommand(address):
56 | return commands[address]
57 |
58 |
59 | func getCommandSummary() -> String:
60 | var cmdList := []
61 | for k in commands:
62 | cmdList.push_back("%-12s\t%s" % [k, (commands[k].args as PoolStringArray).join(' ')])
63 | return (cmdList as PoolStringArray).join('\n')
64 |
65 |
--------------------------------------------------------------------------------
/PostTextEdit.gd:
--------------------------------------------------------------------------------
1 | extends TextEdit
2 |
3 | var main
4 |
5 | var shortcutsHelp = "\nKeyboard shortcuts:\n" \
6 | + "\t CTRL + H - show this Help and OSC commands.\n" \
7 | + "\t CTRL + ENTER - evaluate block.\n" \
8 | + "\t SHIFT + ENTER - evaluate line.\n" \
9 | + "\t CTRL + E - toggle editor and post window.\n" \
10 | + "\t CTRL + SHIFT + E - toggle editor.\n" \
11 | + "\t CTRL + P - toggle post window.\n" \
12 | + "\t CTRL + SHIFT + P - clear post window.\n" \
13 | + "\t CTRL + O - open a file in the text editor.\n" \
14 | + "\t CTRL + S - save text editor contents to a file.\n" \
15 | + "\t CTRL + D - duplicate line.\n" \
16 | + "\t CTRL + + - Increase font.\n" \
17 | + "\t CTRL + - - Decrease font.\n"
18 |
19 | var help = "================================================================\n" \
20 | + "To see the tutorial type:\n" \
21 | + "\n" \
22 | + "/tutorial\n" \
23 | + "\n" \
24 | + "and evaluate by hitting CTRL + ENTER while the cursor is on that line.\n" \
25 | + "\n" \
26 | + "See the docs by evaluating:\n" \
27 | + "\n" \
28 | + "/help\n" \
29 | + shortcutsHelp \
30 | + "================================================================\n\n"
31 |
32 | # Called when the node enters the scene tree for the first time.
33 | func _ready():
34 | main = get_parent()
35 | set_text(help)
36 |
37 | func _on_PostTextEdit_gui_input(event):
38 | if event.is_action_pressed("increase_editor_font", true):
39 | increaseFont()
40 | elif event.is_action_pressed("decrease_editor_font", true):
41 | decreaseFont()
42 |
43 | func append( msg ):
44 | set_text("%s\n%s" % [get_text(), msg])
45 | scroll_vertical = INF
46 |
47 | func printDict( dict ):
48 | for key in dict.keys():
49 | append("%s: %s" % [key, dict[key]])
50 |
51 | func clear():
52 | set_text("")
53 |
54 | func help():
55 | append(shortcutsHelp)
56 |
57 | func increaseFont():
58 | var font = get("custom_fonts/font")
59 | font.set_size(font.get_size() + 1)
60 | main.post("font size: %d" % [font.get_size()])
61 |
62 | func decreaseFont():
63 | var font = get("custom_fonts/font")
64 | font.set_size(font.get_size() - 1)
65 | main.post("font size: %d" % [font.get_size()])
66 |
67 | func setFontSize( size ):
68 | get("custom_fonts/font").set_size(size)
69 |
--------------------------------------------------------------------------------
/sc/cube-routines.scd:
--------------------------------------------------------------------------------
1 | (
2 | ////////////////////////////////////////////////////////////
3 | // Setup
4 | ////////////////////////////////////////////////////////////
5 | "setup.scd".loadRelative.first;
6 | )
7 |
8 | (
9 | // Create the actor setup commands
10 | n.sendMsg("/def", "/updown actor holdTime",
11 | "/speed $actor 1",
12 | "/frame $actor 0",
13 | "/noloop $actor",
14 | "/wait $holdTime",
15 | "/speed $actor -1",
16 | "/noloop $actor",
17 | );
18 | n.sendMsg("/def", "/make-c actor red green blue offsetx offsety period holdTime",
19 | "/create $actor cube-unshrink-h",
20 | "/noloop $actor",
21 | "/color $actor $red $green $blue",
22 | "/size $actor 0.5",
23 | "/position $actor $offsetx $offsety",
24 | "/routine $actor inf $period /updown $actor $holdTime"
25 | );
26 | x.("/load cube-unshrink-h");
27 | )
28 |
29 | (
30 | // Algorithmically create and animate a bunch of cubes
31 | ~num = 15;
32 | x.("/routine/free/all");
33 | x.("/free *");
34 | ~num.do{ arg i;
35 | var rgb = rrand(-0.3, 0.3 ! 3);
36 | var row = (i % 3) - 1;
37 | var col = 1 - (i div: 3 - 1);
38 | var posx = 0.12 * col + 0.5;
39 | var posy = 0.25 * row + 0.5 + (0.105 * col);
40 | // Try different modulus, from 2 to ~num
41 | var period = (i % ~num).linexp(0, ~num-1, 0.5, 8);
42 | x.("/make-c c% % % % % % % %".format(i, rgb[0], rgb[1], rgb[2], posx, posy, period, period / 2).debug("cmd"));
43 | }
44 | )
45 |
46 |
47 |
48 | x.("/action c* wander 0.2 0.5")
49 | x.("/rotate c* 90 1")
50 | { ~num.do{ arg i; x.("/size c% 0.5 2".format(i)); 0.25.wait; } }.fork
51 | { ~num.do{ arg i; x.("/rotate c% 90 2".format(i)); 0.25.wait; } }.fork
52 | { ~num.do{ arg i; x.("/fade c% 0 8".format(i)); 0.25.wait; } }.fork
53 |
54 |
55 |
56 |
57 |
58 | (
59 | // An explicit version
60 | n.sendMsg("/def", "/make-cubes",
61 | "/make-c c1 0.2 0.2 0.2 0.62 0.355 12 6",
62 | "/make-c c2 -0.2 -0.2 -0.2 0.62 0.605 6 3",
63 | "/make-c c3 0.0 0.0 0.0 0.62 0.855 4 2",
64 | "/make-c c4 0.2 -0.2 -0.2 0.5 0.25 3 2",
65 | "/make-c c5 -0.2 0.2 -0.2 0.5 0.5 2 1",
66 | "/make-c c6 0.2 0.2 -0.2 0.5 0.75 1 0.5",
67 | "/make-c c7 -0.2 -0.2 0.2 0.38 0.145 0.666667 0.3333",
68 | "/make-c c8 0.2 -0.2 0.2 0.38 0.395 0.5 0.25",
69 | "/make-c c9 -0.2 0.2 0.2 0.38 0.645 0.333333 0.1666667"
70 | );
71 | )
72 |
73 | x.("/make-cubes")
74 |
--------------------------------------------------------------------------------
/sc/Animatron/Animatron.sc:
--------------------------------------------------------------------------------
1 | Animatron {
2 | var <>osc;
3 | var <>oscReply;
4 | var <>config;
5 | var <>actors;
6 | var <>assets;
7 |
8 | *new { | addr="localhost", port=56101 |
9 | ^super.new.init(addr, port)
10 | }
11 |
12 | init { | addr="localhost", port=56101 |
13 | var separateBySpaces;
14 |
15 | this.osc = NetAddr(addr, port);
16 |
17 | OSCdef(\listActorsReply, { arg msg;
18 | "Actors: %".format(msg[1..]).postln;
19 | oscReply = msg.debug("oscdef");
20 | }, "/list/actors/reply");
21 | OSCdef(\listAnimsReply, { arg msg;
22 | "Available animations:\n\t%".format(join(msg[1..], "\n\t")).postln;
23 | }, "/list/anims/reply");
24 | OSCdef(\listAssetsReply, { arg msg;
25 | "Available assets:\n\t%".format(join(msg[1..], "\n\t")).postln;
26 | }, "/list/assets/reply");
27 | OSCdef(\errorReply, { arg msg;
28 | "Error: %".format(msg[1]).postln;
29 | oscReply = msg;
30 | }, "/error/reply");
31 | OSCdef(\statusReply, { arg msg;
32 | "Status: %".format(msg[1]).postln;
33 | }, "/status/reply");
34 | // OSCdef(\oscReply, { arg msg;
35 | // msg.debug("oscreply");
36 | // }, "/error/reply");
37 |
38 | // n = NetAddr("localhost", 56101);
39 | // separateBySpaces = { arg str;
40 | // // This regex isn't perfect, but works
41 | // // reasonably well for most of my cases...
42 | // var regex = '"(.+?)"|(?:([^"]+?)(?=\\s))|(?:(?<=\\s)([^"]+))'.asString;
43 | // var arr = str.asString.findRegexp(regex).flop.last.clump(4).collect{ |x|
44 | // x.drop(1).collect(_.stripWhiteSpace)
45 | // }.flatten.reject(_.isEmpty);
46 | // if (arr.isEmpty) { arr = [ str ] };
47 | // arr
48 | // };
49 |
50 | // x = { arg ...args;
51 | // if (args.notEmpty) {
52 | // var arr = separateBySpaces.(args[0]);
53 | // if (arr.notEmpty) {
54 | // arr = arr ++ args[1..];
55 | // n.sendMsg(*arr);
56 | // arr
57 | // };
58 | // }
59 | // };
60 |
61 | // "Animatron ready.\nUse:\n\tn.sendMsg(\"/load\", \"asset\")\nor:\n\tx.(\"/load asset\")".postln;
62 |
63 | // x.("/load/config", Platform.userHomeDir++"/work/toplap-20221005-asturies/asturies-config.osc");
64 | ^this.osc;
65 | }
66 |
67 | // doesNotUnderstand { |selector ...args|
68 | // // super.findRespondingMethodFor(selector);
69 |
70 | // }
71 | }
--------------------------------------------------------------------------------
/sc/dot.sc:
--------------------------------------------------------------------------------
1 | (
2 | ////////////////////////////////////////////////////////////
3 | // Setup
4 | ////////////////////////////////////////////////////////////
5 | "setup.scd".loadRelative.first;
6 | )
7 |
8 | n.sendMsg("/help");
9 | n.sendMsg("/list/assets");
10 | n.sendMsg("/load", "dot-p-front");
11 | n.sendMsg("/load", "dot-p-back");
12 | n.sendMsg("/load", "dot-p-speak");
13 | n.sendMsg("/load", "dot-p-speak-front");
14 | n.sendMsg("/load", "dot-p-speak-right");
15 | n.sendMsg("/load", "dot-p-01");
16 | n.sendMsg("/load", "dot-p-02");
17 | n.sendMsg("/load", "dot-p-03");
18 | n.sendMsg("/load", "dot-p-04");
19 | n.sendMsg("/load", "dot-p-07");
20 | n.sendMsg("/load", "dot-p-08");
21 | n.sendMsg("/load", "dot-p-09");
22 | n.sendMsg("/load", "dot-p-10");
23 | n.sendMsg("/load", "dot-p-11");
24 | n.sendMsg("/load", "dot-p-12");
25 | n.sendMsg("/load", "dot-p-13");
26 | n.sendMsg("/load", "dot-p-14");
27 | n.sendMsg("/load", "dot-p-15");
28 | n.sendMsg("/load", "dot-p-16");
29 | n.sendMsg("/load", "dot-p-17");
30 | n.sendMsg("/load", "dot-p-18");
31 | n.sendMsg("/load", "dot-p-20");
32 | n.sendMsg("/create", "dot", "dot-p-01");
33 | n.sendMsg("/create", "dot", "dot-p-02");
34 | n.sendMsg("/create", "dot", "dot-p-03");
35 | n.sendMsg("/create", "dot", "dot-p-04");
36 | n.sendMsg("/create", "dot", "dot-p-07");
37 | n.sendMsg("/create", "dot", "dot-p-08");
38 | n.sendMsg("/create", "dot", "dot-p-10");
39 | n.sendMsg("/create", "dot", "dot-p-11");
40 | n.sendMsg("/create", "dot", "dot-p-12");
41 | n.sendMsg("/create", "dot", "dot-p-13");
42 | n.sendMsg("/create", "dot", "dot-p-14");
43 | n.sendMsg("/create", "dot", "dot-p-15");
44 | n.sendMsg("/create", "dot", "dot-p-16");
45 | n.sendMsg("/create", "dot", "dot-p-17");
46 | n.sendMsg("/create", "dot", "dot-p-18");
47 | n.sendMsg("/create", "dot", "dot-p-20");
48 | n.sendMsg("/create", "dot", "dot-p-speak-front");
49 | (
50 | n.sendMsg("/create", "dot", "dot-p-02");
51 | n.sendMsg("/create", "dot", "dot-p-04");
52 | n.sendMsg("/speed", "dot", 12/30);
53 | n.sendMsg("/speed", "dot", 0.40);
54 | n.sendMsg("/scale", "dot", 4.0);
55 | )
56 |
57 | n.sendMsg("/color", "dot", 0.5,0.1,0);
58 | n.sendMsg("/stop", "dot");
59 | n.sendMsg("/play", "dot");
60 | n.sendMsg("/frame", "dot", 0);
61 | n.sendMsg("/position", "dot", 0.25, 0.5, 6);
62 | n.sendMsg("/position", "dat", 0.5, 0.6);
63 | n.sendMsg("/fliph", "dot");
--------------------------------------------------------------------------------
/Animation.gd:
--------------------------------------------------------------------------------
1 | extends AnimatedSprite
2 |
3 | var random = false setget setRandom
4 | var loopStart := 0 setget setStart
5 | var loopEnd := -1 setget setEnd
6 | var reverse := false
7 | var nextAnim := 0
8 |
9 | func _ready():
10 | connect("frame_changed", self, "_on_Animation_frame_changed")
11 |
12 | func _on_Animation_animation_finished():
13 | if not reverse:
14 | frame = loopStart
15 | else:
16 | frame = loopEnd
17 |
18 | # we need to manually stop the animation if the last frame of the range is
19 | # not the last frame the animation (loopEnd != last frame)
20 | if not frames.get_animation_loop(animation):
21 | stop()
22 | frame = loopEnd if not reverse else loopStart
23 |
24 | func _on_Animation_frame_changed():
25 | # Logger.debug("play:%s frame:%s loop:%s start:%s end:%s speed:%s" % [is_playing(), frame, loop, loopStart, loopEnd, frames.get_animation_speed(animation)])
26 | if random:
27 | set_frame( randi() % frames.get_frame_count( animation ) )
28 |
29 | if loopEnd < 0:
30 | loopEnd = frames.get_frame_count(animation) - 1
31 |
32 | # Logger.debug("loop end: %s" % [reverse])
33 | if not reverse and frame > loopEnd:
34 | emit_signal("animation_finished")
35 | if reverse and frame < loopStart or frame > loopEnd:
36 | emit_signal("animation_finished")
37 |
38 | func setSpeed(speed):
39 | if float(speed) < 0:
40 | reverse = true
41 | else:
42 | reverse = false
43 | play("", reverse)
44 | set_speed_scale(abs(float(speed)))
45 |
46 | func loop(loop):
47 | frames.set_animation_loop(animation, loop)
48 | play("", reverse)
49 |
50 | func setRandom(newRandom):
51 | random = newRandom
52 | if random and not is_playing():
53 | play()
54 |
55 | func setRange(startFrame, endFrame):
56 | loopStart = int(startFrame)
57 | loopEnd = int(endFrame)
58 | reset()
59 |
60 | func setStart(startFrame):
61 | loopStart = int(startFrame)
62 |
63 | func setEnd(endFrame):
64 | loopEnd = int(endFrame)
65 |
66 | func reset():
67 | Logger.debug("frame: %d st:%s end:%s rev:%s" % [frame, loopStart, loopEnd, reverse])
68 | if frame < loopStart and not reverse:
69 | frame = loopStart
70 | elif frame >= loopEnd and not reverse:
71 | frame = loopStart
72 | elif frame > loopEnd and reverse:
73 | frame = loopEnd
74 | elif frame <= loopStart and reverse:
75 | frame = loopEnd
76 | Logger.debug("frame: %s" % [frame])
77 |
--------------------------------------------------------------------------------
/commands/init.osc:
--------------------------------------------------------------------------------
1 | def /init
2 | /load/defs midi
3 |
4 | # create and select an actor
5 | def /createsel actor anim
6 | /create $actor $anim
7 | /select $actor
8 |
9 | # load and create an actor
10 | def /new actor anim
11 | /load $anim
12 | /create $actor $anim
13 |
14 | # load, create and select an actor
15 | def /newsel actor anim
16 | /deselect
17 | /new $actor $anim
18 | /select $actor
19 |
20 | def /fast actor amount
21 | /speed $actor $amount
22 |
23 | def /center actor
24 | /position $actor 0.5 0.5
25 |
26 | def /left actor amout
27 | /move/x $actor -$amount
28 |
29 | def /right actor amout
30 | /move/x $actor $amount 0
31 |
32 | # play actor in reverse
33 | def /play/rev actor
34 | /play $actor true
35 |
36 | # play the animation once and vanish
37 | def /once actor
38 | /oneshot $actor 0
39 |
40 | # play the animation once and stop on the last frame
41 | def /noloop actor
42 | /oneshot $actor 1
43 |
44 | # visibility envelope
45 | def /adsr actor atk dec sus sust rel
46 | /fade $actor 0
47 | /fade $actor 1 $atk
48 | /wait $atk
49 | /fade $actor $sus $dec
50 | /wait $dec
51 | /wait $sust
52 | /fade $actor 0 $rel
53 |
54 | # visibility envelope
55 | def /ar actor atk rel
56 | /fade $actor 0
57 | /fade $actor 1 $atk
58 | /wait $atk
59 | /fade $actor 0 $rel
60 |
61 | ################################################################################
62 | # colors
63 | ################################################################################
64 | def /black actor
65 | /color $actor 0 0 0
66 |
67 | def /white actor
68 | /color $actor 1 1 1
69 |
70 | def /color/gray actor value
71 | /color $actor $value $value $value
72 |
73 | def /gray actor value
74 | /color $actor $value $value $value
75 |
76 | def /red actor value
77 | /color/r $actor $value
78 |
79 | def /green actor value
80 | /color/g $actor $value
81 |
82 | def /blue actor value
83 | /color/b $actor $value
84 |
85 | ################################################################################
86 | # random
87 | ################################################################################
88 | def /rand/pos actor
89 | /rand /position/x $actor 0 1
90 | /rand /position/y $actor 0 1
91 |
92 | # FIX: not working with wildcards -- dunno why
93 | def /rand/gray actor min max
94 | /rand /color/gray $actor $min $max
95 |
--------------------------------------------------------------------------------
/icons/action.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/sc/dots.scd:
--------------------------------------------------------------------------------
1 | (
2 | ////////////////////////////////////////////////////////////
3 | // Setup
4 | ////////////////////////////////////////////////////////////
5 | "setup.scd".loadRelative.first;
6 | )
7 |
8 | x.("/load dot-explode")
9 |
10 | (
11 | x.("/new bg bg-black");
12 | x.("/size bg 2");
13 | x.("/color bg 0.5 0.5 0.5");
14 | x.("/behind bg *");
15 | )
16 |
17 | (
18 | n.sendMsg("/def", "/createDot actor startFrame rate size posx posy",
19 | "/create $actor dot-explode",
20 | "/frame $actor $startFrame",
21 | "/speed $actor $rate",
22 | "/size $actor $size",
23 | "/onframe/free $actor 2 /frame $actor",
24 | "/onframe $actor 2 /frame $actor 0",
25 | "/position $actor $posx $posy"
26 | );
27 | )
28 |
29 | (
30 | ~numActors = 30;
31 | ~numActors.do{ arg i;
32 | var t = i * 2pi / ~numActors;
33 | var posx = cos(t) * 0.4 + 0.5;
34 | var posy = sin(t) * 0.4 + 0.5;
35 | var size = i.linexp(0, ~numActors-1, 0.25, 2).debug("size");
36 | x.("/createDot dot% % % % % %".format(i, 2.rand, rrand(0.75,1.333) * 0.25, size, posx, posy));
37 | };
38 | )
39 |
40 | (
41 | n.sendMsg("/def", "/update actor posx posy fadeTime",
42 | "/position $actor $posx $posy $fadeTime",
43 | );
44 | )
45 | x.("/update dot5 0.2 0.4 2")
46 |
47 | (
48 | Tdef(\anim, {
49 | inf.do{ arg outer;
50 | var freq = rrand(0.5, 3);
51 | var offset = 2pi.rand;
52 | var fadeTime = rrand(1.0, 3);
53 | var elapsedTime = 0;
54 | ~numActors.do{ arg i;
55 | var t = i * 2pi / ~numActors * freq;
56 | var posx = cos(t + offset) * i.linexp(0, ~numActors-1, 0.02, 0.4) + 0.5;
57 | var posy = sin(t + offset) * i.linexp(0, ~numActors-1, 0.02, 0.4) + 0.5;
58 | var size = rrand(0.75,1.333) * 0.25;
59 | var fadeTime = i.linexp(0, ~numActors-1, 2, 0.5);
60 | // posx = (1 - posx).wrap(0.25, 0.75);
61 | // posy = (1 - posy).wrap(0.25, 0.75);
62 | x.("/update dot% % % % %".format(i, posx, posy, fadeTime));
63 | elapsedTime = elapsedTime + 0.025;
64 | 0.025.wait;
65 | };
66 | (fadeTime - elapsedTime).max(0).wait;
67 | };
68 | }).play
69 | )
70 |
71 | (
72 | ~numActors.do{ arg i;
73 | var startFrame = 0;
74 | var oldEndFrame = 3;
75 | var endFrame = 2;
76 | var actor = "dot" ++ i;
77 | var numFrames = endFrame - startFrame + 1;
78 | x.("/frame % %".format(actor, rrand(startFrame, endFrame - 1)));
79 | x.("/onframe/free % % /frame %".format(actor, oldEndFrame, actor));
80 | x.("/onframe/free % % /frame %".format(actor, endFrame, actor));
81 | x.("/onframe % % /frame % %".format(actor, endFrame, actor, startFrame));
82 | };
83 | )
84 |
85 | Tdef(\anim).stop
86 | x.("/free dot*")
87 |
88 | x.("/list/assets")
89 | x.("/list/anims")
90 | x.("/list")
91 |
--------------------------------------------------------------------------------
/icons/ull.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
36 |
38 |
43 |
51 |
56 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/Helper.gd:
--------------------------------------------------------------------------------
1 | extends Object
2 | class_name Helper
3 |
4 |
5 | ############################################################
6 | # Global (static) helper functions
7 | ############################################################
8 |
9 | static func getGlobalPath(projectPath : String) -> String:
10 | var path = ""
11 | if OS.has_feature("editor"):
12 | # Running from an editor binary.
13 | # `path` will contain the absolute path to `hello.txt` located in the project root.
14 | if not projectPath.is_abs_path():
15 | projectPath = "res://".plus_file(projectPath)
16 | path = ProjectSettings.globalize_path(projectPath)
17 | else:
18 | # Running from an exported project.
19 | # `path` will contain the absolute path to `hello.txt` next to the executable.
20 | # This is *not* identical to using `ProjectSettings.globalize_path()` with a `res://` path,
21 | # but is close enough in spirit.
22 | if projectPath.begins_with("res://"):
23 | projectPath = projectPath.substr("res://".length())
24 | path = (
25 | OS.get_executable_path().get_base_dir().plus_file(projectPath)
26 | if projectPath.is_rel_path()
27 | else projectPath
28 | )
29 | return path
30 |
31 |
32 | # Return a path relative to a default directory, if you provide
33 | # a simple filename without any other path elements
34 | # getPathWithDefaultDir("hello.txt", "test") -> "test/hello.txt"
35 | # getPathWithDefaultDir("another/hello.txt", "test") -> "another/hello.txt"
36 | static func getPathWithDefaultDir(path : String, defaultDir : String) -> String:
37 | if path.get_file() == path:
38 | path = defaultDir.plus_file(path)
39 | return getGlobalPath(path)
40 |
41 |
42 | # Get a bool argument
43 | static func getBool(arg) -> bool:
44 | if typeof(arg) == TYPE_STRING:
45 | return arg.to_lower() == "true" or bool(int(arg))
46 | else:
47 | return bool(arg)
48 |
49 |
50 | # Get a Vector2 argument from a single float/int value,
51 | # an array, or a string of two floats separated by a comma
52 | static func getVector2(arg) -> Vector2:
53 | var value : Vector2
54 | if typeof(arg) == TYPE_STRING:
55 | var parts = arg.split_floats(',')
56 | if not parts.empty():
57 | value = Vector2(parts[0], parts[0])
58 | if parts.size() > 1:
59 | value.y = parts[1]
60 | elif typeof(arg) == TYPE_ARRAY:
61 | if not arg.empty():
62 | value = Vector2(arg[0], arg[0])
63 | if arg.size() > 1:
64 | value.y = arg[1] as float
65 | else:
66 | value = Vector2(float(arg), float(arg))
67 | return value
68 |
69 | static func linlin(val, inmin, inmax, outmin, outmax):
70 | return (float(val - inmin) / float(inmax - inmin)) * float(outmax - outmin) + outmin
71 |
72 | static func getViewSize() -> Vector2:
73 | return Vector2(
74 | ProjectSettings.get_setting("display/window/size/width"),
75 | ProjectSettings.get_setting("display/window/size/height")
76 | )
77 |
--------------------------------------------------------------------------------
/AudioInputPlayer.gd:
--------------------------------------------------------------------------------
1 | extends AudioStreamPlayer
2 |
3 | signal sound_changed(band, amp)
4 |
5 | const VU_COUNT = 4
6 | const FREQ_MAX = 11050.0
7 |
8 | const WIDTH = 400
9 | const HEIGHT = 100
10 |
11 | const MIN_DB = 60
12 |
13 | var spectrum
14 | var band
15 | var amp
16 |
17 | var cmds : Array
18 |
19 | func update():
20 | #warning-ignore:integer_division
21 | # print("---")
22 | var w = WIDTH / VU_COUNT
23 | var prev_hz = 0
24 | for i in range(1, VU_COUNT+1):
25 | var hz = i * FREQ_MAX / VU_COUNT;
26 | var magnitude: float = spectrum.get_magnitude_for_frequency_range(prev_hz, hz).length() if spectrum else 0
27 | var amp = clamp((MIN_DB + linear2db(magnitude)) / MIN_DB, 0, 1)
28 | var height = amp * HEIGHT
29 | prev_hz = hz
30 | if amp > 0:
31 | emit_signal("sound_changed", i, amp)
32 | # print(i, ":", amp)
33 |
34 |
35 | func _process(_delta):
36 | update()
37 |
38 | func _on_AudioInputPlayer_sound_changed(band, amp):
39 | if not get_parent():
40 | return
41 | var main = get_parent()
42 | Logger.verbose("band:%s amp:%s" % [band, amp])
43 | for cmd in cmds:
44 | for key in cmd.keys():
45 | # need for a check to avoid crash on removing cmds from band dictionaries
46 | if not cmd[key].has("addr"): return
47 | var addr = cmd[key]["addr"]
48 | var actor = cmd[key]["actor"].name
49 | var rangemin = cmd[key]["range"][0]
50 | var rangemax = cmd[key]["range"][1]
51 | var value = Helper.linlin(amp, 0.0, 1.0, rangemin, rangemax)
52 | main.evalOscCommand(addr, [actor, value], null)
53 |
54 | func _ready():
55 | spectrum = AudioServer.get_bus_effect_instance(0,0)
56 | for i in range(VU_COUNT):
57 | cmds.append({})
58 | connect("sound_changed", self, "_on_AudioInputPlayer_sound_changed")
59 |
60 | func addSoundCmd( band, cmd, actor, minVal, maxVal ):
61 | var key = getKey(cmd, actor)
62 | cmds[min(int(band), len(cmds)-1)][key] = {"addr": cmd, "actor": actor, "range": [float(minVal), float(maxVal)]}
63 | print(cmds)
64 |
65 | # removes all commands for BAND
66 | func removeAllSoundCmds( band ):
67 | cmds[min(band, len(cmds)-1)] = {}
68 | print(cmds)
69 |
70 | # removes only the CMD for ACTOR in BAND
71 | func removeSoundCmd( band, cmd, actor ):
72 | var key = getKey(cmd, actor)
73 | cmds[min(int(band), len(cmds)-1)].erase(key)
74 | print(cmds)
75 |
76 | func getKey(cmd, actor):
77 | return "%s/%s" % [cmd, actor.name]
78 |
79 | func eventToOsc(cmdsList, value, inmin, inmax):
80 | if not get_parent():
81 | return
82 | var main = get_parent()
83 | for addr in cmdsList.keys():
84 | if not addr.begins_with("/"):
85 | addr = "/" + addr
86 | var minval = cmdsList[addr][0]
87 | var maxval = cmdsList[addr][1]
88 | value = $Helper.linlin(value, inmin, inmax, minval, maxval)
89 | Logger.verbose("sending msg from MIDI: %s %f" % [addr, value])
90 | main.evalOscCommand(addr, [name, value], null)
91 |
--------------------------------------------------------------------------------
/Config.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 | class_name Config
3 |
4 | onready var cmds : CustomCommands = get_parent().find_node("CustomCommands")
5 | onready var osc = get_parent().find_node("OscInterface")
6 | const defaultConfigDir := "config/"
7 | var defaultMidiFile := "commands/midi.osc"
8 | var animationAssetPath := Helper.getGlobalPath("animations/") setget animPathSet
9 | var allowRemoteClients := true
10 |
11 | # Called when the node enters the scene tree for the first time.
12 | func _ready():
13 | Logger.info("User data dir: %s" % [OS.get_user_data_dir()])
14 |
15 |
16 | ############################################################
17 | # Helpers
18 | ############################################################
19 | func animPathSet(path):
20 | animationAssetPath = Helper.getGlobalPath(path)
21 |
22 |
23 | ############################################################
24 | # OSC config commands
25 | ############################################################
26 | func loadConfig(args, sender):
27 | # print(cmds)
28 | if args.size() != 1:
29 | osc.reportError("loadConfig expects one argument", sender)
30 | return
31 | var configFile = Helper.getPathWithDefaultDir(args[0], defaultConfigDir)
32 | if cmds.loadCommandFile(configFile):
33 | osc.reportStatus("Loaded config from '%s'" % configFile, sender)
34 | else:
35 | osc.reportError("Couldn't open config file: '%s'" % [configFile], sender)
36 |
37 |
38 | func moveWindowToScreen(screen, sender):
39 | OS.set_current_screen(int(screen[0]))
40 |
41 |
42 | func setWindowPosition(pos, sender):
43 | Logger.debug("window position: %s" % [pos])
44 | OS.set_window_position(Vector2(pos[0], pos[1]))
45 |
46 |
47 | func setWindowSize(args, sender):
48 | Logger.debug("window size: %s" % [args])
49 | var size = Vector2(args[0], args[1])
50 | var vp = get_viewport()
51 | var aspect = vp.size.x / vp.size.y
52 | if size.y < 0:
53 | size.y = size.x / aspect
54 | elif size.x < 0:
55 | size.x = size.y * aspect
56 | OS.set_window_size(size)
57 |
58 |
59 | func centerWindow(args, sender):
60 | if not args.empty():
61 | osc.reportError("centerWindow expects no arguments", sender)
62 | return
63 | OS.set_window_position((OS.get_screen_size(OS.get_current_screen()) * 0.5) - (OS.get_window_size() * 0.5))
64 |
65 |
66 | func fullscreen(args, sender):
67 | var fs = true if args.empty() else Helper.getBool(args[0])
68 | OS.set_window_fullscreen(fs)
69 |
70 |
71 | func windowAlwaysOnTop(args, sender):
72 | var ot = true if args.empty() else Helper.getBool(args[0])
73 | OS.set_window_always_on_top(ot)
74 |
75 |
76 | # This method sets the path, but also reports it back if run without args
77 | func setAnimationAssetPath(args, sender):
78 | var msg = "Asset path: "
79 | if args.size() == 1:
80 | msg = "Set " + msg
81 | self.animationAssetPath = args[0]
82 | if Directory.new().dir_exists(animationAssetPath):
83 | osc.reportStatus(msg + animationAssetPath, sender)
84 | else:
85 | osc.reportError("Invalid animation path: '%s'" % animationAssetPath, sender)
86 |
87 |
88 | func setAppRemote(args, sender):
89 | allowRemoteClients = true if args.empty() else Helper.getBool(args[0])
90 |
91 |
--------------------------------------------------------------------------------
/docs/markdeep/slides.css:
--------------------------------------------------------------------------------
1 | /* Request lanscape from the printer/browser */
2 | @page {
3 | size: landscape;
4 | margin-bottom: 100px;
5 | }
6 |
7 | .md div.title {
8 | margin-top: 250px;
9 | margin-bottom: 40px;
10 | font-size: 50px;
11 | font-weight: bold;
12 | counter-increment: page;
13 | }
14 |
15 | .md div.subtitle {
16 | font-size: 30px;
17 | }
18 |
19 | .md hr {
20 | page-break-before: always;
21 | }
22 |
23 | body#md {
24 | width: 900px;
25 | max-width: 100%;
26 | font-size: 25px;
27 | padding: 40px;
28 | counter-reset: page;
29 | --accent-color: #39C; /* #F61;*/
30 | }
31 |
32 | /* Disable section numbering */
33 | .md h1:before {content: ""}
34 | .md h2:before {content: ""}
35 |
36 | .md svg.diagram {
37 | zoom: 150%;
38 | }
39 |
40 | /* Sections become presentation sections */
41 | .md h1, .md .nonumberh1 {
42 | page-break-before: always;
43 | width: 1100px;
44 | text-align: center;
45 | margin-top: 20px;
46 | margin-bottom: 20px;
47 | padding-top: 300px;
48 | padding-bottom: 20px;
49 | border: none;
50 | color: var(--accent-color);
51 | margin-left: -100px;
52 | margin-right:-100px;
53 | font-size: 50px;
54 | counter-increment: page;
55 | }
56 |
57 | /* Subsections become slides */
58 | .md h2, .md .nonumberh2 {
59 | page-break-before: always;
60 | width: 1100px;
61 | text-align: center;
62 | background: var(--accent-color);
63 | color: #FFF;
64 | margin-top: 100px;
65 | margin-bottom: 50px;
66 | padding-top: 20px;
67 | padding-bottom: 20px;
68 | border: none;
69 | margin-left: -100px;
70 | margin-right:-100px;
71 | font-size: 34px;
72 | counter-increment: page;
73 | }
74 |
75 | @media print{
76 | footer {
77 | position: fixed;
78 | bottom: 0;
79 | right: 0;
80 | color: #AAA;
81 | font-size: 50%;
82 | }
83 | }
84 |
85 | @media screen {
86 | footer { display: none }
87 |
88 | .md h1, .md .nonumberh1 {
89 | /* Show slide divisions */
90 | border-top: 1px solid black;
91 | }
92 | }
93 |
94 | /* Hide HR in printing */
95 | @media print {
96 | .md hr {
97 | visibility: hidden;
98 | }
99 | }
100 |
101 | .md hr {
102 | counter-increment: page;
103 | }
104 |
105 | .md code {
106 | font-size: 100%;
107 | }
108 |
109 | .md pre.listing {
110 | font-size: 80%;
111 | border: 1px solid #CCC;
112 | }
113 |
114 | .md strong, .md b {
115 | color: var(--accent-color);
116 | }
117 |
118 | .md table {
119 | font-size: 100%;
120 | background-color: #eee;
121 | }
122 |
123 | .md table.table td {
124 | border: none;
125 | }
126 |
127 | .md table.table th {
128 | background-color: black;
129 | color: white;
130 | border: none;
131 | font-family: Verdana,Helvetica,Arial,sans-serif;
132 | }
133 |
134 | .md table.table th + th {
135 | border-left: 3px solid white;
136 | }
137 |
138 | .md table.table td + td {
139 | border-left: 3px solid white;
140 | }
141 |
142 | .md table.table tr:nth-child(n) {
143 | background-color: none;
144 | }
145 |
146 |
--------------------------------------------------------------------------------
/Main.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=16 format=2]
2 |
3 | [ext_resource path="res://OscInterface.gd" type="Script" id=1]
4 | [ext_resource path="res://CustomCommands.gd" type="Script" id=2]
5 | [ext_resource path="res://Config.gd" type="Script" id=3]
6 | [ext_resource path="res://Midi.gd" type="Script" id=4]
7 | [ext_resource path="res://Letters.gd" type="Script" id=5]
8 | [ext_resource path="res://AudioInputPlayer.gd" type="Script" id=6]
9 | [ext_resource path="res://OscTextEdit.gd" type="Script" id=7]
10 | [ext_resource path="res://fonts/mononoki_Bold.ttf" type="DynamicFontData" id=8]
11 | [ext_resource path="res://transparent_bg.tres" type="StyleBox" id=9]
12 | [ext_resource path="res://PostTextEdit.gd" type="Script" id=10]
13 | [ext_resource path="res://OscSender.gd" type="Script" id=11]
14 | [ext_resource path="res://Main.gd" type="Script" id=13]
15 |
16 | [sub_resource type="AudioStreamMicrophone" id=1]
17 |
18 | [sub_resource type="DynamicFont" id=2]
19 | size = 22
20 | outline_color = Color( 0, 0, 0, 1 )
21 | font_data = ExtResource( 8 )
22 |
23 | [sub_resource type="DynamicFont" id=3]
24 | font_data = ExtResource( 8 )
25 |
26 | [node name="Main" type="Node2D"]
27 | script = ExtResource( 13 )
28 |
29 | [node name="OscInterface" type="Node" parent="."]
30 | script = ExtResource( 1 )
31 |
32 | [node name="CustomCommands" type="Node" parent="."]
33 | script = ExtResource( 2 )
34 |
35 | [node name="Config" type="Node" parent="."]
36 | script = ExtResource( 3 )
37 |
38 | [node name="Actors" type="YSort" parent="."]
39 | sort_enabled = false
40 |
41 | [node name="Midi" type="Node" parent="."]
42 | script = ExtResource( 4 )
43 |
44 | [node name="Letters" type="Node" parent="."]
45 | script = ExtResource( 5 )
46 |
47 | [node name="AudioInputPlayer" type="AudioStreamPlayer" parent="."]
48 | stream = SubResource( 1 )
49 | script = ExtResource( 6 )
50 |
51 | [node name="OscTextEdit" type="TextEdit" parent="."]
52 | visible = false
53 | margin_right = 40.0
54 | margin_bottom = 40.0
55 | grow_horizontal = 0
56 | grow_vertical = 0
57 | size_flags_horizontal = 10
58 | size_flags_vertical = 10
59 | custom_colors/current_line_color = Color( 0, 0, 0, 0.0784314 )
60 | custom_fonts/font = SubResource( 2 )
61 | custom_styles/normal = ExtResource( 9 )
62 | highlight_current_line = true
63 | syntax_highlighting = true
64 | show_line_numbers = true
65 | wrap_enabled = true
66 | caret_block_mode = true
67 | caret_blink = true
68 | script = ExtResource( 7 )
69 |
70 | [node name="PostTextEdit" type="TextEdit" parent="."]
71 | margin_right = 40.0
72 | margin_bottom = 40.0
73 | size_flags_horizontal = 10
74 | size_flags_vertical = 10
75 | custom_fonts/font = SubResource( 3 )
76 | custom_styles/read_only = ExtResource( 9 )
77 | custom_styles/normal = ExtResource( 9 )
78 | readonly = true
79 | wrap_enabled = true
80 | script = ExtResource( 10 )
81 |
82 | [node name="OpenFileDialog" type="FileDialog" parent="."]
83 | margin_left = 203.0
84 | margin_top = 92.0
85 | margin_right = 803.0
86 | margin_bottom = 492.0
87 | window_title = "Open a File"
88 | mode = 0
89 |
90 | [node name="SaveFileDialog" type="FileDialog" parent="."]
91 | margin_left = 203.0
92 | margin_top = 92.0
93 | margin_right = 803.0
94 | margin_bottom = 492.0
95 |
96 | [node name="OscSender" type="Node" parent="."]
97 | script = ExtResource( 11 )
98 |
99 | [node name="Routines" type="Node" parent="."]
100 |
101 | [connection signal="gui_input" from="OscTextEdit" to="OscTextEdit" method="_on_OscTextEdit_gui_input"]
102 | [connection signal="visibility_changed" from="OscTextEdit" to="OscTextEdit" method="_on_OscTextEdit_visibility_changed"]
103 | [connection signal="gui_input" from="PostTextEdit" to="PostTextEdit" method="_on_PostTextEdit_gui_input"]
104 | [connection signal="text_changed" from="PostTextEdit" to="PostTextEdit" method="_on_PostTextEdit_text_changed"]
105 | [connection signal="file_selected" from="OpenFileDialog" to="." method="_on_OpenFileDialog_file_selected"]
106 | [connection signal="file_selected" from="SaveFileDialog" to="." method="_on_SaveFileDialog_file_selected"]
107 |
--------------------------------------------------------------------------------
/MetaNode.gd:
--------------------------------------------------------------------------------
1 | extends KinematicBody2D
2 |
3 | var stateMachine : Dictionary
4 | var frameCmds : Dictionary
5 | var finishCmds : Dictionary
6 | var isVisibleEnd := true setget setVisibleEnd
7 | var frameCmdsIndex = 0
8 | # frame that triggers the next command in the frameCmds
9 | var trigFrame = 0
10 | var main
11 |
12 |
13 | func _ready():
14 | var animNode = get_node("Offset/Animation")
15 | animNode.connect("frame_changed", self, "_on_Animation_frame_changed")
16 | animNode.connect("animation_finished", self, "_on_Animation_animation_finished")
17 |
18 | func _on_Animation_frame_changed():
19 | main = get_parent()
20 | if main == null:
21 | return
22 | main = main.get_parent()
23 | var anim = get_node("Offset/Animation").get_animation()
24 | var frame = get_node("Offset/Animation").get_frame()
25 | if frameCmds.has(frame):
26 | sendCmds(frame)
27 |
28 | func _on_Animation_animation_finished():
29 | for cmd in finishCmds:
30 | main.evalOscCommand(finishCmds[cmd][0], finishCmds[cmd].slice(1,-1), null)
31 |
32 | set_visible(isVisibleEnd)
33 | nextState()
34 |
35 | func resetFrameCmds():
36 | frameCmdsIndex = 0
37 |
38 | func addCmdToFrameCmds( inframe, cmd ):
39 | var anim = get_node("Offset/Animation").get_animation()
40 | # print("%s:%s %s:%s" % [typeof frame, frame, typeof cmd, cmd])
41 | var numframes = get_node("Offset/Animation").get_sprite_frames().get_frame_count(anim)
42 | # print("%s/%s: %s %s" % [inframe, numframes, cmd, anim])
43 | trigFrame = int(inframe) % numframes
44 |
45 | var key = getKey(cmd)
46 | if frameCmds.has(trigFrame):
47 | frameCmds[trigFrame][key] = cmd
48 | else:
49 | frameCmds[trigFrame] = {key: cmd}
50 |
51 | print("add cmd to frameCmds on frame %d: %s" % [trigFrame, cmd])
52 | print(frameCmds)
53 | return frameCmds
54 |
55 | func removeCmdFromFrameCmds( inframe, cmd ):
56 | print("remove cmd for frame %s: %s" % [inframe, cmd])
57 | var reply
58 | var key = getKey(cmd)
59 | inframe = int(inframe)
60 |
61 | if frameCmds.has(inframe):
62 | frameCmds[inframe].erase(key)
63 | reply = frameCmds[inframe]
64 | if len(frameCmds[inframe]) == 0:
65 | frameCmds.erase(inframe)
66 | else:
67 | # TODO: change to send '/report/error'
68 | reply = "Command not found in trigger frame %d: %s" % [inframe, cmd]
69 | print(reply)
70 | return reply
71 |
72 | func addFinishCmd( cmd ):
73 | var key = getKey(cmd)
74 | finishCmds[key] = cmd
75 | print("add onfinish cmd: %s : %s" % [key, cmd])
76 | print("on finish: ", finishCmds)
77 |
78 | func removeFinishCmd( cmd ):
79 | print(cmd)
80 | var key = getKey(cmd)
81 | if finishCmds.has(key):
82 | finishCmds.erase(key)
83 | print("remove cmd: %s : %s" % [key, cmd])
84 | print("on finish: ", finishCmds)
85 |
86 | func getFrameCmds():
87 | return frameCmds
88 |
89 | func getKey( cmd ):
90 | if len(cmd) > 1:
91 | return "%s/%s" % [cmd[0], cmd[1]]
92 | return cmd[0]
93 |
94 | func sendCmds( inframe ):
95 | for cmd in frameCmds[inframe]:
96 | var addr = frameCmds[inframe][cmd][0]
97 | var args = frameCmds[inframe][cmd].slice(1,-1)
98 | main.evalOscCommand(addr, args, null)
99 |
100 | func listFrameCmds():
101 | print("frame commands for %s:\n%s" % [name,frameCmds])
102 | print("finish commands for %s:\n%s" % [name,finishCmds])
103 |
104 | func setVisibleEnd(visible):
105 | isVisibleEnd = visible
106 |
107 | func listStates():
108 | Logger.info("State machine: %s" % [name])
109 | for state in stateMachine:
110 | Logger.info("%s : %s" % [state, stateMachine[state]])
111 |
112 | func addState(newState, nextStates):
113 | stateMachine[newState] = nextStates if nextStates is Array else [nextStates]
114 |
115 | func removeState(state):
116 | stateMachine.erase(state)
117 |
118 | func nextState():
119 | var animNode = get_node("Offset/Animation")
120 | var anim = animNode.get_animation()
121 | if not stateMachine.has(anim):
122 | return
123 | var nextPossibleStates = stateMachine[anim]
124 | var nextState = nextPossibleStates[ randi() % nextPossibleStates.size() ]
125 | animNode.set_animation(nextState)
126 | Logger.verbose("changing '%s' state from: %s to: %s" % [name, anim, nextState])
127 |
--------------------------------------------------------------------------------
/docs/markdeep/apidoc.css:
--------------------------------------------------------------------------------
1 | /* Custom stylesheet for API documentation by Aras Pranckevičius, http://aras-p.info/
2 | and tweaked by Morgan McGuire.
3 | Licensed as public domain or BSD 2-clause, whichever is more convenient for you.
4 | Originally from https://github.com/aras-p/markdeep-docs-style */
5 | body#md {
6 | max-width: 50em;
7 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
8 | text-align: left;
9 | margin: 1.5em;
10 | padding: 0 1em;
11 | }
12 |
13 | /* if screen is wide enough, put table of contents on the right side */
14 | @media screen and (min-width: 64em) {
15 | .md .longTOC, .md .mediumTOC, .md .shortTOC {
16 | max-width: 20em;
17 | left: 54em;
18 | display:block;
19 | position: fixed;
20 | top:0;
21 | bottom:0;
22 | overflow-y:scroll;
23 | margin-top:0;
24 | margin-bottom:0;
25 | padding-top:1em;
26 | }
27 | }
28 |
29 | /* for narrow screens or print, hide table of contents */
30 | @media screen and (max-width: 64em) {
31 | .md .longTOC, .md .mediumTOC, .md .shortTOC { display: none; }
32 | }
33 |
34 | @media print {
35 | .md .longTOC, .md .mediumTOC, .md .shortTOC { display: none; }
36 | body { max-width: 100%; }
37 | }
38 |
39 | /* reset heading/link fonts to that of body */
40 | .md a,
41 | .md div.title, contents, .md .tocHeader,
42 | .md h1, .md h2, .md h3, .md h4, .md h5, .md h6,
43 | .md .nonumberh1, .md .nonumberh2, .md .nonumberh3, .md .nonumberh4, .md .nonumberh5, .md .nonumberh6,
44 | .md .shortTOC, .md .mediumTOC, .md .longTOC {
45 | font-family: inherit;
46 | }
47 |
48 | @media screen {.md .tocTop {
49 | display: inline;
50 | }}
51 |
52 | .md div.title {
53 | margin: 0.4em 0 0 0;
54 | padding: 0;
55 | text-align: inherit;
56 | }
57 |
58 | .md div.subtitle {
59 | text-align: inherit;
60 | }
61 |
62 | /* faint border below headings */
63 | .md h1, .md h2, .md h3, .md h4,
64 | .md .nonumberh1, .md .nonumberh2, .md .nonumberh3, .md .nonumberh4 {
65 | border-bottom: 1px solid rgba(0,0,0,.1);
66 | }
67 | /* heading font styles */
68 | .md h1, .md .nonumberh1, .md div.title {
69 | font-size: 150%;
70 | font-weight: 600;
71 | color: rgba(0,0,0,.7);
72 | }
73 | .md h2, .md .nonumberh2 {
74 | font-size: 120%;
75 | font-weight: 400;
76 | color: rgba(0,0,0,.9);
77 | }
78 | .md h3, .md .nonumberh3 {
79 | font-size: 110%;
80 | font-weight: 400;
81 | color: rgba(0,0,0,.7);
82 | }
83 | /* no numbering of headings */
84 | .md h1:before, .md h2:before, .md h3:before, .md h4:before { content: none; }
85 |
86 | /* link styling */
87 | .md a:link, .md a:visited {
88 | color: #3f51b5;
89 | }
90 |
91 | /* inline and block code */
92 | .md code, .md pre.listing {
93 | background-color: rgba(0,0,0,.05);
94 | padding: 0.1em 0.2em;
95 | border-radius: 0.15em;
96 | }
97 | .md pre.listing code {
98 | background-color: transparent;
99 | padding: 0;
100 | border: none;
101 | }
102 |
103 | /* table of contents styling; make all 3 forms of it look the same */
104 | .md .longTOC, .md .mediumTOC, .md .shortTOC {
105 | font-size: inherit;
106 | line-height: 120%;
107 | margin: 1em 0;
108 | padding: .4rem;
109 | border-left: .1rem solid #3f51b5;
110 | }
111 |
112 | .md .tocHeader {
113 | margin: 0;
114 | padding: 0;
115 | border: none;
116 | font-size: inherit;
117 | }
118 |
119 | .md .tocNumber {
120 | display: none;
121 | }
122 |
123 | .md .longTOC .level1, .md .mediumTOC .level1, .md .shortTOC .level1 {
124 | font-weight: inherit;
125 | padding: 0;
126 | margin: 0;
127 | }
128 |
129 | .md .longTOC p, .md .mediumTOC p, .md .shortTOC p {
130 | overflow: hidden;
131 | text-overflow: ellipsis;
132 | }
133 |
134 | .md .longTOC center, .md .mediumTOC center, .md .shortTOC center, .md .tocHeader {
135 | text-align: left;
136 | }
137 |
138 | .md .longTOC b, .md .mediumTOC b, .md .shortTOC b {
139 | font-weight: 400;
140 | }
141 |
142 | .md .longTOC center b, .md .mediumTOC center b, .md .shortTOC center b {
143 | font-weight: bold;
144 | }
145 |
146 | .md .longTOC a, .md .mediumTOC a, .md .shortTOC a {
147 | color: black;
148 | }
149 |
150 | .md .longTOC .level1, .md .mediumTOC .level1, .md .shortTOC .level1,
151 | .md .longTOC .level2, .md .mediumTOC .level2, .md .shortTOC .level2,
152 | .md .longTOC .level3, .md .mediumTOC .level3, .md .shortTOC .level3 {
153 | white-space: nowrap;
154 | margin: 0;
155 | padding: 0;
156 | font-size: 90%;
157 | }
158 |
159 | /* tables; use fainter colors than regular markdeep style */
160 | .md table.table {
161 | font-size: 90%;
162 | }
163 |
164 | .md table.table th {
165 | border: none;
166 | background-color: #ccc;
167 | color: rgba(0,0,0,.6);
168 | }
169 | .md table.table tr, .md table.table td {
170 | border-color: #eee;
171 | }
172 | .md table.table tr:nth-child(even) {
173 | background-color: #f4f4f4;
174 | }
175 |
176 |
--------------------------------------------------------------------------------
/Midi.gd:
--------------------------------------------------------------------------------
1 | class_name Midi
2 | extends Node
3 |
4 | signal note_on_received(num, velocity, ch)
5 | signal note_off_received(num, velocity, ch)
6 | signal cc_received(num, value, ch)
7 |
8 | var debug = true
9 | var midiCmds : Dictionary
10 |
11 | # Called when the node enters the scene tree for the first time.
12 | func _ready():
13 | OS.open_midi_inputs()
14 | print("MIDI devices: ",OS.get_connected_midi_inputs())
15 | set_process_unhandled_input(true)
16 |
17 | func enableDebug(enable):
18 | debug = enable
19 |
20 | func _unhandled_input(event):
21 | if(event is InputEventMIDI):
22 | var signalMsg = ""
23 | var ch = event.get_channel()
24 | var num = 0
25 | var value = 0
26 | # print("MIDI: ", event.as_text())
27 | # print("MIDI:", event.message)
28 | # print("MSG:", MIDI_MESSAGE_CONTROL_CHANGE)
29 | # var msg = "ch:" + str(ch) + " note:" + str(event.get_pitch()) + " vel:" + str(event.get_velocity()) + " inst:" + str(event.get_instrument()) + " pres:" + str(event.get_pressure()) + " cc#:" + str(event.get_controller_number()) + " ccv:" + str(event.get_controller_value())
30 | # print(msg)
31 | if event.message == MIDI_MESSAGE_NOTE_ON:
32 | signalMsg = "noteon"
33 | num = event.get_pitch()
34 | value = event.get_velocity()
35 | elif event.message == MIDI_MESSAGE_NOTE_OFF:
36 | signalMsg = "noteoff"
37 | num = event.get_pitch()
38 | value = event.get_velocity()
39 | elif event.message == MIDI_MESSAGE_CONTROL_CHANGE:
40 | signalMsg = "cc"
41 | num = event.get_controller_number()
42 | value = event.get_controller_value()
43 |
44 | if debug:
45 | print("MIDI msg: %s - ch: %d - num:%d - val:%d - ch:%d" % [signalMsg, ch, num, value, event.get_channel()])
46 |
47 | if signalMsg == "":
48 | return
49 |
50 | processMidiCmd(signalMsg, ch, num, value)
51 |
52 | func addMidiCmd( event, ch, num, cmd, actor, minVal, maxVal ):
53 | if String(num) == "*":
54 | for i in range(128):
55 | # to map any note midievent to a command, we need to
56 | # use note number as velocity value, so we pass
57 | # the same value for both min and max. If they are null
58 | # we give them a midi number
59 | if minVal == null: minVal = i + 1
60 | if maxVal == null: maxVal = i + 1
61 | var newMinVal = Helper.linlin(i, 0,127, minVal, maxVal)
62 | var newMaxVal = newMinVal
63 | addMidiCmd(event, ch, i, cmd, actor, newMinVal, newMaxVal)
64 | return
65 | var key = "%s/ch%s/%s" % [event, ch, num]
66 | midiCmds[key] = {"addr":cmd, "actor":actor.name, "value":[minVal, maxVal]}
67 | # print(midiCmds)
68 | Logger.info("added midi cmd %s: %s" % [key, midiCmds[key]])
69 |
70 | func removeMidiCmd( event, ch, num, cmd, actor ):
71 | if String(num) == "*":
72 | for i in range(128):
73 | removeMidiCmd(event, ch, i, cmd, actor)
74 | return
75 |
76 | var key = "%s/ch%s/%s" % [event, ch, num]
77 |
78 | if not midiCmds.has(key):
79 | Logger.info("trying to erase non-existing MIDI cmd: %s" % [key])
80 | return
81 |
82 | midiCmds.erase(key)
83 | Logger.info("midi cmds: %s" % [midiCmds])
84 |
85 | func processMidiCmd( event, ch, num, val ):
86 | var key = getKey(event, ch, num)
87 | if not midiCmds.has(key):
88 | return
89 |
90 | eventToOsc(midiCmds[key], val)
91 | #
92 | if debug:
93 | Logger.debug("key: %s cmd: %s" % [key, midiCmds[key]] )
94 | # print(midiCmds.keys())
95 |
96 | func eventToOsc(cmd, value):
97 | print("event to osc: ", cmd, value)
98 | if not get_parent():
99 | return
100 |
101 | var main = get_parent()
102 | var addr = cmd["addr"]
103 | if not addr.begins_with("/"):
104 | addr = "/" + addr
105 | var actor = cmd["actor"]
106 | var minval = cmd["value"][0]
107 | var maxval = cmd["value"][1]
108 | if actor == null:
109 | main.evalCommandList([[addr]], null)
110 | return
111 | elif minval == null or maxval == null:
112 | main.evalCommandList([[addr, actor]], null)
113 | return
114 | var args
115 | print("%s(%s) %s(%s)" % [minval, typeof(minval), maxval, typeof(maxval)])
116 | if minval is String and minval.is_valid_float() and maxval is String and maxval.is_valid_float():
117 | args = Helper.linlin(value, 0, 127, float(minval), float(maxval))
118 | elif (minval is float or minval is int) and (maxval is float or maxval is int):
119 | args = Helper.linlin(value, 0, 127, float(minval), float(maxval))
120 | else:
121 | args = minval
122 |
123 | Logger.verbose("MIDI PARSE: original:%s scaled:%s" % [value, args])
124 | Logger.verbose("sending msg from MIDI: %s %s %f" % [addr, actor, value])
125 | main.evalCommandList([[addr, actor, args]], null)
126 |
127 | func getKey(event, ch, num):
128 | return "%s/ch%s/%s" % [event, ch, num]
129 |
130 | func listCmds():
131 | var cmds : String
132 | for key in midiCmds:
133 | var cmd = midiCmds[key]["addr"]
134 | var actor = midiCmds[key]["actor"]
135 | var args = midiCmds[key]["value"]
136 | cmds = "%s\n%s: %s %s %s" % [cmds, key, cmd, actor, args]
137 | # print(cmd, midiCmds[cmd])
138 | # Logger.info(cmds)
139 | return cmds
140 |
--------------------------------------------------------------------------------
/OscTextEdit.gd:
--------------------------------------------------------------------------------
1 | extends TextEdit
2 |
3 | const defaultTextEditorFile := "docs/tutorial.osc"
4 | const tutorialCmdsFile = "commands/tutorial-cmds.osc"
5 | var regex
6 | var main
7 |
8 | func _ready():
9 | regex = RegEx.new()
10 | main = get_parent()
11 | set_visible(true)
12 |
13 | add_color_region("/", " ", Color(1, 0.439216, 0.521569))
14 | add_color_region("#", "", Color(0.447059, 0.462745, 0.498039))
15 |
16 | main.get_node("OscInterface").loadDefsFile([tutorialCmdsFile], null)
17 |
18 |
19 | func _on_OscTextEdit_gui_input(event):
20 | # Logger.verbose(event)
21 | # accept_event()
22 | if event.is_action_pressed("eval_line", true):
23 | undo() # FIX: this is a hack to remove the inserted line on pressing ENTER
24 | evalLine()
25 | elif event.is_action_pressed("eval_block", true):
26 | undo() # FIX: this is a hack to remove the inserted line on pressing ENTER
27 | evalBlock()
28 | elif event.is_action_pressed("open_file", true):
29 | main.get_node("OpenFileDialog").popup()
30 | elif event.is_action_pressed("save_file", true):
31 | main.get_node("SaveFileDialog").popup()
32 | elif event.is_action_pressed("duplicate_line", true):
33 | duplicateLine()
34 | elif event.is_action_pressed("increase_editor_font", true):
35 | increaseFont()
36 | elif event.is_action_pressed("decrease_editor_font", true):
37 | decreaseFont()
38 |
39 | func evalRegion():
40 | textToOsc(get_selection_text())
41 |
42 | func findPrevLinebreak( fromLine ):
43 | var ln = fromLine
44 | while ln > 0:
45 | ln = ln - 1
46 | if get_line(ln) == "":
47 | ln = ln + 1
48 | break
49 | return ln
50 |
51 | func findNextLinebreak( fromLine ):
52 | if get_line(fromLine) == "":
53 | return fromLine
54 | var ln = fromLine
55 | while ln < get_line_count():
56 | ln = ln + 1
57 | if get_line(ln) == "":
58 | ln = ln - 1
59 | break
60 | return ln
61 |
62 | func evalBlock():
63 | var line = cursor_get_line()
64 | var from = findPrevLinebreak(line) - 1
65 | var to = findNextLinebreak(line)
66 | cursor_set_column(len(get_line(line)))
67 | select(from, 0, to + 1, cursor_get_column())
68 | var text = get_selection_text().strip_edges()
69 | Logger.debug("text: %s" % [text])
70 | Logger.debug("def: %s" % [text.begins_with("/def")])
71 | if text.begins_with("/def"):
72 | evalDefs(text)
73 | return
74 | Logger.debug("AFTER DEFS")
75 | textToOsc(text)
76 | deselect()
77 |
78 |
79 | func evalLine():
80 | var ln = cursor_get_line()
81 | var col = cursor_get_column()
82 | selectLine()
83 | textToOsc(get_selection_text())
84 | deselect()
85 | cursor_set_line(ln)
86 | cursor_set_column(col)
87 |
88 | func evalDefs(text):
89 | # group tabs with first non-indented line
90 | # FIX: 'defs' are already parsed in file, but doesn't work with this
91 | # This is a hack converting each line into a string so the parser
92 | # can reconvert it to a command.
93 | var def := Array(text.split("\n")[0].split(" "))
94 | def.remove(0)
95 | var defCmd = def.pop_front()
96 | var defArgs = def
97 | var cmds : Array
98 | var regex = RegEx.new()
99 | regex.compile("\\n\\t(.*)")
100 | for result in regex.search_all(text):
101 | Logger.debug("def subcmd: %s" % [result.get_string()])
102 | cmds.push_back(result.get_string().strip_edges().split(" "))
103 | Logger.debug("def: %s args: %s" % [defCmd, defArgs])
104 | Logger.debug("sub cmds: %s" % [cmds])
105 | main.get_node("CustomCommands").defineCommand(defCmd, defArgs, cmds)
106 |
107 | func textToOsc( msgString ):
108 | var cmds = []
109 | var lines = msgString.split("\n")
110 | for line in lines:
111 | var cmd = Array(line.strip_edges().split(" ")) # convert PoolStringArray to Array
112 | if len(cmd[0].strip_edges()) > 0:
113 | cmds.append(cmd)
114 | main.evalCommandList(cmds, null)
115 | Logger.debug(cmds)
116 |
117 | func selectLine():
118 | var line = cursor_get_line()
119 | cursor_set_column(len(get_line(line)))
120 | select(line, 0, line, cursor_get_column())
121 |
122 | func duplicateLine():
123 | var col = cursor_get_column()
124 | cut()
125 | paste()
126 | paste()
127 | cursor_set_line(cursor_get_line() - 1)
128 | cursor_set_column(col)
129 |
130 | func loadTutorial():
131 | # this is not an optimal way to do it, but we are using a method in
132 | # the Helper class
133 | var dirname = defaultTextEditorFile.split("/")[0]
134 | var filename = defaultTextEditorFile.split("/")[1]
135 | var file = File.new()
136 | var path = Helper.getPathWithDefaultDir(filename, dirname)
137 | file.open(path, File.READ)
138 | set_text(file.get_as_text())
139 |
140 | func append( msg ):
141 | set_text("%s\n%s" % [get_text(), msg])
142 | scroll_vertical = INF
143 |
144 | func increaseFont():
145 | var font = get("custom_fonts/font")
146 | font.set_size(font.get_size() + 1)
147 | Logger.verbose("font size: %d" % [font.get_size()])
148 |
149 | func decreaseFont():
150 | var font = get("custom_fonts/font")
151 | font.set_size(font.get_size() - 1)
152 | Logger.verbose("font size: %d" % [font.get_size()])
153 |
154 | func setFontSize( size ):
155 | get("custom_fonts/font").set_size(size)
156 |
157 | func clear():
158 | set_text("")
159 |
--------------------------------------------------------------------------------
/sc/midi-test.scd:
--------------------------------------------------------------------------------
1 | a = Animatron()
2 | MIDIClient.init;
3 | m = MIDIOut(0);
4 | a.sendMsg("/debug", false);
5 | a.sendMsg("/debug", true);
6 | a.sendMsg("/free", "*");
7 |
8 | // ------------------------------------------------------------
9 | // basic
10 | // ------------------------------------------------------------
11 | (
12 | a.sendMsg("/load", "numbers");
13 | a.sendMsg("/create", "n", "numbers");
14 | a.sendMsg("/create", "n2", "numbers");
15 | a.sendMsg("/speed", "n", 1/12);
16 | a.sendMsg("/speed", "n2", 1/12);
17 | a.sendMsg("/scale", "n2", 1/2);
18 | a.sendMsg("/position/x", "n2", 1/4);
19 | )
20 | // add/remove MIDI cmds
21 | a.sendMsg("/midi", "noteon", 0, 60, "/frame", "n", 0, 10);
22 | a.sendMsg("/midi", "noteon", 0, 60, "/frame", "n2", 0, 10);
23 | a.sendMsg("/midi/free", "noteon", 0, 60, "/frame", "n");
24 | a.sendMsg("/midi/free", "noteon", 0, 60, "/frame", "n2");
25 | a.sendMsg("/midi/free", "noteon", 0, 60, "/frame", "x2");
26 | a.sendMsg("/midi/free", "noteon", 0, 61, "/frame", "n2");
27 |
28 | // test MIDI cmds
29 | a.sendMsg("/midi", "noteon", 0, 60, "/frame", "n", 0, 10);
30 | a.sendMsg("/list/midi");
31 | m.noteOn(0, 60,0);
32 | m.noteOff(0,60,0);
33 | a.sendMsg("/midi/free", "noteon", 0, 60, "/frame", "n");
34 |
35 | // test 2 different MIDI channels
36 | a.sendMsg("/midi", "noteon", 0, 60, "/frame", "n", 0, 10);
37 | a.sendMsg("/midi", "noteon", 1, 60, "/scale", "n", 0.1, 2.0);
38 | a.sendMsg("/list/midi");
39 | m.noteOn(0, 60, 127);m.allNotesOff(0);
40 | m.noteOn(1, 60, 127.rand);m.allNotesOff(1);
41 | a.sendMsg("/midi/free", "noteon", 0, 60, "/frame", "n");
42 | a.sendMsg("/midi/free", "noteon", 1, 60, "/scale", "n");
43 |
44 | a.sendMsg("/midi", "noteon", 0, "*", "/frame", "n", 0, 10);
45 | a.sendMsg("/midi/free", "noteon", 0, "*", "/frame", "n");
46 | a.sendMsg("/list/midi");
47 | // ------------------------------------------------------------
48 | // matrix
49 | // ------------------------------------------------------------
50 | (
51 | 16.do{|i|
52 | var n = "n"++(i.mod(16).asInteger);
53 | a.sendMsg("/create", n, "numbers");
54 | a.sendMsg("/stop", n);
55 | a.sendMsg("/scale", n, 0.2);
56 | a.sendMsg("/frame", n, i);
57 | a.sendMsg("/position/x", n, (i / 4).linlin(0,4, 0.2,0.8));
58 | a.sendMsg("/position/y", n, (i.mod(4)).linlin(0,4, 0.2,0.8));
59 | };
60 | a.sendMsg("/midi", "noteon", 0, "*", "/frame", "n0", 0.0, 10.0);
61 | )
62 | (
63 | Tdef(\midi, {
64 | inf.do{ |i|
65 | // var ch = 16.rand;
66 | var ch = 0;
67 | // var note = 127.rand;
68 | // var vel = 127.rand;
69 | var note = 60;
70 | var vel = 10;
71 | m.noteOn(ch, note, vel);
72 | 0.1.wait;
73 | m.noteOff(ch, note, vel);
74 | 1.wait;
75 | };
76 | }).play;
77 | )
78 | Tdef(\midi).stop;
79 |
80 | // ------------------------------------------------------------
81 | // complex
82 | // ------------------------------------------------------------
83 | a.sendMsg("/load", "canon-man");
84 | (
85 | a.sendMsg("/create", "ha", "canon-man");
86 | a.sendMsg("/create", "he", "canon-man");
87 | a.sendMsg("/stop", "h*");
88 | a.sendMsg("/frame", "ha", rrand(50,500));
89 | a.sendMsg("/frame", "he", rrand(50,500));
90 | a.sendMsg("/color", "he", 1,0,0);
91 | a.sendMsg("/position/x", "he", 0.2);
92 | a.sendMsg("/scale", "he", 0.5);
93 | )
94 | a.sendMsg("/midi/debug", false);
95 | a.sendMsg("/new", "sqa", "square");
96 | a.sendMsg("/midi", "noteon", 0, "*", "/rotate", "sqa", 0, 360);
97 |
98 | a.sendMsg("/midi/free", "noteon", 0, "*", "/rotate", "sqa");
99 | a.sendMsg("/midi/debug", true);
100 |
101 | // all notes on
102 | a.sendMsg("/midi", "noteon", "*", "/frame", "ha", 50,360);
103 | m.noteOn(0, 127.rand, 127.rand.debug);
104 | a.sendMsg("/midi/free", "noteon", "*", "/frame", "ha");
105 | // all notes off
106 | a.sendMsg("/midi", "noteoff", "*", "/frame", "ha", 50,360);
107 | m.noteOn(0, 127.rand, 127.rand.debug);
108 | a.sendMsg("/midi/free", "noteoff", "*", "/frame", "ha");
109 | // all velocity
110 | a.sendMsg("/midi", "velocity", "*", "/scale", "ha", 0.1, 4);
111 | m.noteOn(0, 127.rand, 127.rand.debug);
112 | a.sendMsg("/midi/free", "velocity", "*", "/scale", "ha");
113 | // note on -- using velocity as parameter
114 | a.sendMsg("/midi", "noteon", 60, "/frame", "ha", 50,360);
115 | a.sendMsg("/midi", "noteon", 60, "/scale", "ha", 0.1, 2.0);
116 | m.noteOn(0, 60, 127.rand.debug);
117 | a.sendMsg("/midi/free", "noteon", 60, "/frame", "ha");
118 | a.sendMsg("/midi/free", "noteon", 60, "/scale", "ha");
119 | // note off -- using velocity as parameter
120 | a.sendMsg("/midi", "noteoff", 60, "/frame", "ha", 50,360);
121 | m.noteOff(0, 60, 127.rand.debug);
122 | a.sendMsg("/midi/free", "noteoff", 60, "/frame", "ha");
123 | // cc
124 | a.sendMsg("/midi", "cc", 1, "/frame", "he", 50,360);
125 | m.control(0, 1, 127.rand.debug);
126 | m.noteOn(0, 1, 127.rand.debug);
127 | a.sendMsg("/midi/free", "cc", 1, "/frame", "ha");
128 |
129 | a.sendMsg("/stop", "h*");
130 |
131 | Ziva.boot;
132 | ~m = Pmidi(MIDIOut(0));
133 | (
134 | [
135 | ~m.fast.amp(Pwhite()).midinote(Pwhite(0,127)),
136 | ~m.faster.deg([0,17].pseq),
137 | ~m.deg([0,17].pseq).chan(1),
138 | ~m.faster.deg([0,17].pseq),
139 | ~m.bla([40,60].pseq.linlin(0,127,0.1,1.27).trace),
140 | nil
141 | ].ziva;
142 | )
143 | Pdef(\ziva).remove
144 |
145 | /midi event ch
146 | a.sendMsg("/midi", "noteon", x, "/frame", a, min, max);
147 | noteon/chx/a cmd:[{addr:"/frame", actor:a, value:n.linlin(0,127,min,max)}]
--------------------------------------------------------------------------------
/sc/cube-routines-mod.scd:
--------------------------------------------------------------------------------
1 | (
2 | ////////////////////////////////////////////////////////////
3 | // Setup
4 | ////////////////////////////////////////////////////////////
5 | "setup.scd".loadRelative.first;
6 | )
7 |
8 | (
9 | // Create the actor setup commands
10 | // n.sendMsg("/def", "/updown actor holdTime",
11 | // "/speed $actor 1",
12 | // "/frame $actor 0",
13 | // "/noloop $actor",
14 | // "/wait $holdTime",
15 | // "/speed $actor -1",
16 | // "/noloop $actor",
17 | // );
18 | // n.sendMsg("/def", "/make-c actor red green blue offsetx offsety period holdTime",
19 | // // "/create $actor cube-unshrink-h",
20 | // // "/create $actor cube",
21 | // // "/noloop $actor",
22 | // "/color $actor $red $green $blue",
23 | // "/size $actor 0.5",
24 | // "/position $actor $offsetx $offsety",
25 | // // "/routine $actor inf $period /updown $actor $holdTime"
26 | // );
27 | n.sendMsg("/def", "/make actor red green blue offsetx offsety",
28 | "/color $actor $red $green $blue",
29 | "/size $actor 0.5",
30 | "/speed $actor 0.5",
31 | "/position $actor $offsetx $offsety",
32 | );
33 | n.sendMsg("/def", "/make/states actor",
34 | "/state/add $actor cube cube cube-bubble",
35 | "/state/add $actor cube-tongue cube-open-eye cube-close",
36 | "/state/add $actor cube-close cube-open cube-bubble",
37 | "/state/add $actor cube-bubble cube-open cube-bubble",
38 | "/state/add $actor cube-open cube-open-eye cube-tongue cube-close",
39 | "/state/add $actor cube-open-eye cube-close cube-tongue",
40 | "/state/add $actor cube-shrink-v cube-unshrink-v",
41 | "/state/add $actor cube-shrink-h cube-unshrink-h",
42 | "/state/add $actor cube-unshrink-v cube-shrink-v cube-open",
43 | "/state/add $actor cube-unshrink-h cube-shrink-h cube-bubble",
44 | );
45 | n.sendMsg("/def", "/free/states actor",
46 | "/state/free $actor cube",
47 | "/state/free $actor cube-tongue",
48 | "/state/free $actor cube-close",
49 | "/state/free $actor cube-bubble",
50 | "/state/free $actor cube-open",
51 | "/state/free $actor cube-open-eye",
52 | "/state/free $actor cube-shrink-v",
53 | "/state/free $actor cube-shrink-h",
54 | "/state/free $actor cube-unshrink-v",
55 | "/state/free $actor cube-unshrink-h",
56 | );
57 | x.("/load cube*");
58 | x.("/load cit-step");
59 | x.("/free *");
60 | ~num = 28;
61 | x.("/routine/free/all");
62 | x.("/create/group c cube %".format(~num));
63 | )
64 | (
65 | ~num.do{ arg i;
66 | // x.("/make/states c%".format(i));
67 | // x.("/free/states c%".format(i));
68 | // x.("/anim c% cube".format(i));
69 | // x.("/state/add c% cube cube-open".format(i));
70 | // x.("/state/add c% cube-bubble cube".format(i));
71 | if( i%2 == 1, {
72 | x.("/state/add c% cube cube-bubble".format(i));
73 | // x.("/state/add c% cube-open cube-open-eye".format(i));
74 | // x.("/state/add c% cube-open-eye cube-close".format(i));
75 | // x.("/state/add c% cube-close cube".format(i));
76 | // x.("/state/add c% cube-bubble cube-shrink-v".format(i));
77 | // x.("/state/add c% cube-shrink-v cube-unshrink-v".format(i));
78 | // x.("/state/add c% cube-unshrink-v cube-bubble".format(i));
79 | });
80 | if( i%2 == 0, {
81 | x.("/state/add c% cube cube-open".format(i));
82 | x.("/state/add c% cube-open cube-close".format(i));
83 | x.("/state/add c% cube-close cube-open".format(i));
84 | // x.("/state/add c% cube-bubble cube-open".format(i));
85 | // x.("/state/add c% cube-open cube-tongue".format(i));
86 | // x.("/state/add c% cube-tongue cube-close".format(i));
87 | // x.("/state/add c% cube-close cube".format(i));
88 | // x.("/state/add c% cube-shrink-h cube-unshrink-h".format(i));
89 | // x.("/state/add c% cube-unshrink-h cube-bubble".format(i));
90 | });
91 | x.("/free/states c%".format(i));
92 | x.("/anim c% cube".format(i));
93 | };
94 | )
95 |
96 | (
97 | // Algorithmically create and animate a bunch of cubes
98 | ~num.do{ arg i;
99 | var row = (i % 4) - 1;
100 | var col = 1 - (i div: 4 - 1);
101 | var posx = 0.12 * col + 0.5;
102 | var posy = 0.25 * row + 0.5 + (0.105 * col);
103 | var rgb = rrand(-0.3, 0.3 ! 3);
104 | // var rgb = col mod: 2 / 2 ! 3 * [1,1,-1];
105 | // Try different modulus, from 2 to ~num
106 | // var period = (i % ~num).linexp(0, ~num-1, 0.5, 8);
107 | // x.("/make-c c% % % % % % % %".format(i, rgb[0], rgb[1], rgb[2], posx, posy, period, period / 2).debug("cmd"));
108 | x.("/make c% % % % % %".format(i, rgb[0], rgb[1], rgb[2], posx, posy).debug("cmd"));
109 | }
110 | )
111 |
112 |
113 | x.("/list/routines")
114 | x.("/free *")
115 | x.("/free/states")
116 | x.("/speed * 0.75")
117 | x.("/list/states c0")
118 | x.("/list/anims")
119 | x.("/list/assets")
120 | x.("/list")
121 | x.("/load cit")
122 | x.("/action c* wander 0.2 0.5")
123 | x.("/rotate c* 90 1")
124 | { ~num.do{ arg i; x.("/size c% 0.5 0".format(i)); 0.0625.wait; } }.fork
125 | { ~num.do{ arg i; x.("/rotate c% 90 0".format(i)); 0.25.wait; } }.fork
126 | { ~num.do{ arg i; x.("/fade c% 0 8".format(i)); 0.25.wait; } }.fork
127 | )
128 |
129 | x.("/flipv c7")
130 | x.("/state/add c7 cube-bubble cube-bubble cit")
131 | x.("/state/add c7 cit cube-shrink-v cube-bubble")
132 |
133 |
134 |
135 | (
136 | // An explicit version
137 | n.sendMsg("/def", "/make-cubes",
138 | "/make-c c1 0.2 0.2 0.2 0.62 0.355 12 6",
139 | "/make-c c2 -0.2 -0.2 -0.2 0.62 0.605 6 3",
140 | "/make-c c3 0.0 0.0 0.0 0.62 0.855 4 2",
141 | "/make-c c4 0.2 -0.2 -0.2 0.5 0.25 3 2",
142 | "/make-c c5 -0.2 0.2 -0.2 0.5 0.5 2 1",
143 | "/make-c c6 0.2 0.2 -0.2 0.5 0.75 1 0.5",
144 | "/make-c c7 -0.2 -0.2 0.2 0.38 0.145 0.666667 0.3333",
145 | "/make-c c8 0.2 -0.2 0.2 0.38 0.395 0.5 0.25",
146 | "/make-c c9 -0.2 0.2 0.2 0.38 0.645 0.333333 0.1666667"
147 | );
148 | )
149 |
150 | x.("/make-cubes")
151 | x.("/make/states c7")
152 |
153 | x.("/load cube-*")
154 | x.("/free *")
155 | x.("/create c cube-open-eye")
156 | x.("/make/states c")
157 | x.("/speed c 0.5")
158 | x.("/stop c")
159 | x.("/frame c 10")
160 | x.("/anim c cube-open-eye");
161 | x.("/stop c");
162 | x.("/state/add c cube-open-eye cube-tongue")
163 | x.("/state/add c cube-tongue cube-open-eye cube-tongue")
164 | x.("/state/add c cube-open cube-close cube-open-eye")
165 | x.("/state/add c cube-open-eye cube-close")
166 | x.("/state/add c cube-close cube-open")
167 | x.("/state/add c cube cube-shrink-h cube-shrink-v cube-bubble")
168 | x.("/state/add c cube-shrink-h cube-unshrink-h")
169 | x.("/state/add c cube-shrink-v cube-unshrink-v")
170 | x.("/state/add c cube-unshrink-v cube-shrink-v cube-shrink-h cube-bubble")
171 | x.("/state/add c cube-unshrink-h cube-shrink-h cube-shrink-v cube-bubble")
172 | x.("/state/add c cube-bubble cube-shrink-v cube-shrink-h")
173 | x.("/list/assets")
174 | x.("/color c 0.2 0.1 0")
--------------------------------------------------------------------------------
/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=4
10 |
11 | _global_script_classes=[ {
12 | "base": "Node",
13 | "class": "Action",
14 | "language": "GDScript",
15 | "path": "res://actions/Action.gd"
16 | }, {
17 | "base": "Node",
18 | "class": "Config",
19 | "language": "GDScript",
20 | "path": "res://Config.gd"
21 | }, {
22 | "base": "Node",
23 | "class": "CustomCommands",
24 | "language": "GDScript",
25 | "path": "res://CustomCommands.gd"
26 | }, {
27 | "base": "Object",
28 | "class": "Helper",
29 | "language": "GDScript",
30 | "path": "res://Helper.gd"
31 | }, {
32 | "base": "Node",
33 | "class": "Letters",
34 | "language": "GDScript",
35 | "path": "res://Letters.gd"
36 | }, {
37 | "base": "Node",
38 | "class": "Midi",
39 | "language": "GDScript",
40 | "path": "res://Midi.gd"
41 | } ]
42 | _global_script_class_icons={
43 | "Action": "res://icons/action.svg",
44 | "Config": "",
45 | "CustomCommands": "",
46 | "Helper": "",
47 | "Letters": "",
48 | "Midi": ""
49 | }
50 |
51 | [application]
52 |
53 | config/name="Animatron"
54 | config/description="A live coding framework for 2D animation."
55 | run/main_scene="res://Main.tscn"
56 | config/use_custom_user_dir=true
57 | config/icon="res://icon.png"
58 |
59 | [audio]
60 |
61 | enable_audio_input=true
62 |
63 | [autoload]
64 |
65 | Logger="*res://Logger.gd"
66 |
67 | [display]
68 |
69 | window/size/width=1920
70 | window/size/height=1080
71 | window/stretch/mode="2d"
72 | window/stretch/aspect="keep"
73 |
74 | [global]
75 |
76 | frame=false
77 | audio=false
78 | memor=false
79 | memory=false
80 |
81 | [input]
82 |
83 | ui_accept={
84 | "deadzone": 0.5,
85 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777222,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
86 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
87 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
88 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777221,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
89 | ]
90 | }
91 | eval_block={
92 | "deadzone": 0.5,
93 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":16777221,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
94 | ]
95 | }
96 | toggle_editor={
97 | "deadzone": 0.5,
98 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":true,"control":true,"meta":false,"command":true,"pressed":false,"scancode":69,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
99 | ]
100 | }
101 | toggle_post={
102 | "deadzone": 0.5,
103 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":80,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
104 | ]
105 | }
106 | toggle_editor_and_post={
107 | "deadzone": 0.5,
108 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":69,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
109 | ]
110 | }
111 | clear_post={
112 | "deadzone": 0.5,
113 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":true,"control":true,"meta":false,"command":true,"pressed":false,"scancode":80,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
114 | ]
115 | }
116 | post_commands={
117 | "deadzone": 0.5,
118 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":72,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
119 | ]
120 | }
121 | eval_line={
122 | "deadzone": 0.5,
123 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":true,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777221,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
124 | ]
125 | }
126 | open_file={
127 | "deadzone": 0.5,
128 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":79,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
129 | ]
130 | }
131 | save_file={
132 | "deadzone": 0.5,
133 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":83,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
134 | ]
135 | }
136 | duplicate_line={
137 | "deadzone": 0.5,
138 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":68,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
139 | ]
140 | }
141 | increase_editor_font={
142 | "deadzone": 0.5,
143 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":43,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
144 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":61,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
145 | ]
146 | }
147 | decrease_editor_font={
148 | "deadzone": 0.5,
149 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":45,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
150 | ]
151 | }
152 | pedal_input={
153 | "deadzone": 0.5,
154 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":true,"shift":true,"control":true,"meta":true,"command":true,"pressed":false,"scancode":0,"physical_scancode":70,"unicode":0,"echo":false,"script":null)
155 | ]
156 | }
157 |
158 | [memory]
159 |
160 | limits/message_queue/max_size_kb=8192
161 |
162 | [physics]
163 |
164 | common/enable_pause_aware_picking=true
165 |
166 | [rendering]
167 |
168 | environment/default_environment="res://default_env.tres"
169 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Animatron
2 |
3 | A tool for real-time visual poetry.
4 |
5 | ## What is it?
6 |
7 | **Animatron** is an experimental environment (very much "work in
8 | progress") that enables creation of "visual poetry," in the form of
9 | animations and images, created in real-time through live coding. It
10 | implemented using the open-source [Godot
11 | engine](https://godotengine.org/), and communicates with any "client"
12 | application or live coding language — such as
13 | [SuperCollider](https://supercollider.github.io/) — via the
14 | network, using the Open Sound Control (OSC) protocol.
15 |
16 | # Installation
17 |
18 | - Download `animatron-YOUR_PLATFORM-vX.X.X_X.zip` from the [latest release](https://github.com/loopier/animatron-godot3/releases).
19 | - Download `animatron-assets-vX.X.X_X.zip` from the [latest release](https://github.com/loopier/animatron-godot3/releases)
20 |
21 | ## Linux
22 | - Uncompress `animatron-linux-vX.X.X_X.zip`
23 | - Uncompress `animatron-assets-vX.X.X_X.zip`
24 | - Move the **CONTENTS** of the `animatron-assets-vX.X.X_X` directory (not the directory itself) into `animatron-linux-vX.X.X_X`. You should end up with a structure similar to this:
25 |
26 | ```
27 | animatron-linux-vX.X.X_X/
28 | ├── animations/
29 | ├── commands/
30 | ├── config/
31 | ├── docs/
32 | ├── fonts/
33 | ├── icons/
34 | ├── scripts/
35 | ├── ...
36 | ├── Animatron.pck
37 | ├── Animatron.x86_64
38 | ├── libgdosc.so
39 | ```
40 | Run `Animatron.x86_64` executable by double-clicking it.
41 | Alternatively: open a terminal and run the command:
42 |
43 | ```
44 | $ path/to/animatron/Animatron.x86_64
45 | ```
46 |
47 | ## Windows
48 | - Uncompress `animatron-windows-vX.X.X_X.zip`
49 | - Uncompress `animatron-assets-vX.X.X_X.zip`
50 | - Move the **CONTENTS** of the `animatron-assets-vX.X.X_X` folder (not the folder itself) into `animatron-windows-vX.X.X_X`. You should end up with a structure similar to this:
51 |
52 | ```
53 | animatron-windows-vX.X.X_X/
54 | ├── animations/
55 | ├── commands/
56 | ├── config/
57 | ├── docs/
58 | ├── fonts/
59 | ├── icons/
60 | ├── scripts/
61 | ├── ...
62 | ├── Animatron.pck
63 | ├── Animatron.exe
64 | ├── libgdosc.dll
65 | ```
66 |
67 | Run `Animatron.exe` by double-clicking it.
68 |
69 | If you see an error like "Can't open dynamic library ... The specified module could not be found", you may need to install the [MSVC Redistributable package](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170).
70 |
71 | ## MacOS
72 |
73 | - Uncompress the `animatron-macos-vX.X.X.zip` file. This should unpack an `Animatron.app` bundle.
74 | - CTRL + CLICK (or RIGHT-CLICK) on `Animatron.app` and select `Show package contents` from the popup menu.
75 | - Navigate to `Contents/MacOS`
76 | - Uncompress the `animatron-assets-VX.X.X.zip` file.
77 | - Move the **CONTENTS** of the assets folder (not the folder itself) into `Animatron.app/Contents/MacOs`. You should end up with a structure similar to this:
78 |
79 | ```
80 | Animatron.app
81 | └── Contents
82 | ├── ...
83 | ├── MacOS
84 | │ └── Animatron
85 | ├── animations/
86 | ├── commands/
87 | ├── config/
88 | ├── docs/
89 | ├── fonts/
90 | ├── icons/
91 | ├── scripts/
92 | ```
93 |
94 | Run `Animatron.app` by double-clicking it. The first time you run it, it may be prevented from opening by the macOS Gatekeeper. In this case, you should right-click (or Control-click) the app and select *Open*. If a security warning dialog appears, click the *Open* button to explicitly give permission to run it (only do this if you're sure you've downloaded Animatron from a reliable source). Once you've given your permission, it will remember it for future runs.
95 |
96 | If `Animatron.app` fails to run even after following the above steps, it may have the "quarantine" extended attribute set. This can happen if the program you used to download it (e.g. Safari, Chrome, Telegram) is not trusted. If you are sure it's from a safe place, you may remove the quarantine flag by opening the *Terminal* app and changing to the directory where you have `Animatron.app`. From that directory, run the following command:
97 |
98 | ```
99 | $ cd ~/Downloads # change to wherever you have the app installed
100 | $ xattr -d -r com.apple.quarantine Animatron.app
101 | ```
102 |
103 | # Compile from source
104 |
105 | Clone or download this repository.
106 |
107 | 1. Install [Godot](https://godotengine.org/download) (currently Animatron only works with Godot v3.X).
108 |
109 | 1. Clone or download [this
110 | repository](https://github.com/loopier/animatron).
111 |
112 | 1. Copy some image files (`.jpg` or `.png`) into the `animations/`
113 | directory in the repository. These will be available to use as
114 | animation sources.
115 |
116 | 1. Run Godot, choose *Scan* from the Project Manager and navigate to
117 | the location of the downloaded/cloned `animatron` project. Click
118 | "Select Current Folder," then open the Animatron project from the
119 | list of available projects.
120 |
121 | 1. Run it using the *Play* button in the upper-right corner of the
122 | Godot window (on Windows, press F5).
123 |
124 | 1. Using an external program (such as the
125 | [SuperCollider](https://supercollider.github.io/) language), send
126 | OSC messages to the program, by default on port 56101). You can
127 | find some examples in [osc-test.scd](sc/osc-test.scd).
128 |
129 | Refer to the [OSC command reference](docs/Reference.md.html) —
130 | note that this file can be opened on your local machine in any web
131 | browser and it will appear correctly formatted.
132 |
133 | # Usage
134 |
135 | The best way to learn how it works is running through the tutorial. Type `/tutorial` and press `CTRL + ENTER`. Follow the instructions and you'll get the hang of it pretty quickly.
136 |
137 | See also the [OSC Reference](docs/Reference.md.html) for a list of commands and their usage.
138 |
139 | # Remote
140 |
141 | Animatron can also be used remotely via OSC messages. The commands are the same. The exact syntax of the message depends on the software you're using to send the messages.
142 |
143 | But first, we need to set up the communication system. Animatron is listening for OSC messages on port `56101`. Following is an example for SuperCollider running on the same machine as Animatron.
144 |
145 | ```
146 | a = NetAdress("localhost", 56101);
147 | a.sendMsg("/bg", 0, 0, 0.2);
148 | a.sendMsg("/new", "sq", "square");
149 | a.sendMsg("/color", "sq", 1,0,0);
150 | // ... etc
151 | ```
152 |
153 | To get replies, an OSC listener needs to be set up on the client side:
154 |
155 | ```
156 | a = NetAdress("localhost", 56101);
157 |
158 | OSCdef(\listActorsReply, { arg msg;
159 | "Actors: %".format(msg[1..]).postln;
160 | oscReply = msg.debug("oscdef");
161 | }, "/list/actors/reply");
162 | OSCdef(\listAnimsReply, { arg msg;
163 | "Available animations:\n\t%".format(join(msg[1..], "\n\t")).postln;
164 | }, "/list/anims/reply");
165 | OSCdef(\listAssetsReply, { arg msg;
166 | "Available assets:\n\t%".format(join(msg[1..], "\n\t")).postln;
167 | }, "/list/assets/reply");
168 | OSCdef(\errorReply, { arg msg;
169 | "Error: %".format(msg[1]).postln;
170 | oscReply = msg;
171 | }, "/error/reply");
172 | OSCdef(\statusReply, { arg msg;
173 | "Status: %".format(msg[1]).postln;
174 | }, "/status/reply");
175 | ```
176 |
177 | If you're going to use SuperCollider often, you can copy the `Animatron/` folder you'll find in the `sc/` directory to your SuperCollider `Extensions/` folder. When creating an instance, a listener for the replies is automatically set up:
178 |
179 | ```
180 | a = Animatron();
181 | a.sendMsg("/list/assets"); // see the post window
182 | ```
183 |
184 | # License
185 |
186 | Animatron is Copyright © 2021 by Glen Fraser, Roger Pibernat and
187 | contributors.
188 |
189 | Animatron is distributed under the terms of the GNU Public license version 3 (or
190 | later). See [LICENSE](LICENSE) for all the details.
191 |
192 |
--------------------------------------------------------------------------------
/Main.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | var oscrcv
4 | # Actor commands:
5 | # The first argument for all these commands is the target actor(s).
6 | # It may be "!" (selection), an actor instance name or a wildcard string.
7 | onready var actorCmds = {
8 | "/free": funcref($OscInterface, "freeActor"),
9 | "/anim": funcref($OscInterface, "setActorAnim"),
10 | # play
11 | "/play": funcref($OscInterface, "playActor"),
12 | "/play/range": funcref($OscInterface, "playActorRange"),
13 | "/oneshot": funcref($OscInterface, "playActorOneshot"),
14 | "/loop": funcref($OscInterface, "playActorLoop"),
15 | "/play/rand": funcref($OscInterface, "playActorRandom"),
16 | "/stop": funcref($OscInterface, "stopActor"),
17 | "/frame": funcref($OscInterface, "setActorFrame"),
18 | "/frame/next": funcref($OscInterface, "nextActorFrame"),
19 | "/frame/prev": funcref($OscInterface, "previousActorFrame"),
20 | # absolute position
21 | "/position": funcref($OscInterface, "setActorPosition"),
22 | "/position/x": funcref($OscInterface, "setActorPositionX"),
23 | "/position/y": funcref($OscInterface, "setActorPositionY"),
24 | # relative position
25 | "/move": funcref($OscInterface, "moveActor"),
26 | "/move/x": funcref($OscInterface, "moveActorX"),
27 | "/move/y": funcref($OscInterface, "moveActorY"),
28 | # absolute angle
29 | "/angle": funcref($OscInterface, "setActorAngle"),
30 | # relative angle
31 | "/rotate": funcref($OscInterface, "rotateActor"),
32 | # absolute size
33 | "/size": funcref($OscInterface, "setActorSize"),
34 | "/size/xy": funcref($OscInterface, "setActorSizeXY"),
35 | "/size/x": funcref($OscInterface, "setActorSizeX"),
36 | "/size/y": funcref($OscInterface, "setActorSizeY"),
37 | # relative size
38 | "/scale": funcref($OscInterface, "scaleActor"),
39 | "/scale/xy": funcref($OscInterface, "scaleActorXY"),
40 | "/scale/x": funcref($OscInterface, "scaleActorX"),
41 | "/scale/y": funcref($OscInterface, "scaleActorY"),
42 |
43 | "/pivot": funcref($OscInterface, "setActorPivot"),
44 | "/alpha": funcref($OscInterface, "setActorAlpha"),
45 | "/fade": funcref($OscInterface, "setActorFade"),
46 | "/fade/toggle": funcref($OscInterface, "toggleActorFade"),
47 | "/speed": funcref($OscInterface, "setActorSpeed"),
48 | "/slow": funcref($OscInterface, "setActorSpeedSlow"), # /fast is an alias of /speed
49 | "/fliph": funcref($OscInterface, "flipActorH"),
50 | "/flipv": funcref($OscInterface, "flipActorV"),
51 | "/color": funcref($OscInterface, "colorActor"),
52 | "/color/r": funcref($OscInterface, "colorRedActor"),
53 | "/color/g": funcref($OscInterface, "colorGreenActor"),
54 | "/color/b": funcref($OscInterface, "colorBlueActor"),
55 | "/say": funcref($OscInterface, "sayActor"),
56 | "/action": funcref($OscInterface, "actionActor"),
57 | "/behind": funcref($OscInterface, "behindActor"),
58 | "/front": funcref($OscInterface, "frontActor"),
59 | "/sound": funcref($OscInterface, "soundActor"),
60 | "/sound/free": funcref($OscInterface, "soundFreeActor"),
61 | "/midi": funcref($OscInterface, "midiActor"),
62 | "/midi/free": funcref($OscInterface, "midiFreeActor"),
63 | "/midi/free/all": funcref($OscInterface, "midiFreeAll"),
64 | "/onframe": funcref($OscInterface, "onFrameActor"),
65 | "/onfinish": funcref($OscInterface, "onFinishActor"),
66 | "/onframe/free": funcref($OscInterface, "onFrameFreeActor"),
67 | "/onfinish/free": funcref($OscInterface, "onFinishFreeActor"),
68 | "/list/sequence": funcref($OscInterface, "getActorFrameCmds"),
69 | "/state/add": funcref($OscInterface, "addActorState"),
70 | "/state/free": funcref($OscInterface, "freeActorState"),
71 | "/list/states": funcref($OscInterface, "listActorStates"),
72 | }
73 |
74 | onready var otherCmds = {
75 | "/load": funcref($OscInterface, "loadAsset"),
76 | "/create": funcref($OscInterface, "createActor"),
77 | "/create/group": funcref($OscInterface, "createActorGroup"),
78 | "/createordestroy": funcref($OscInterface, "createOrDestroyActor"),
79 | "/parent": funcref($OscInterface, "parentActor"),
80 | "/parent/free": funcref($OscInterface, "parentFreeActor"),
81 | "/list/children": funcref($OscInterface, "listActorChildren"),
82 | "/ysort": funcref($OscInterface, "ySortActors"),
83 | "/list": funcref($OscInterface, "listActors"), # shortcut for /list/actors
84 | "/list/actors": funcref($OscInterface, "listActors"),
85 | "/list/anims": funcref($OscInterface, "listAnims"),
86 | "/list/assets": funcref($OscInterface, "listAssets"),
87 | "/group": funcref($OscInterface, "groupActor"),
88 | "/ungroup": funcref($OscInterface, "ungroupActor"),
89 | "/iter": funcref($OscInterface, "iterateGroup"),
90 | "/at": funcref($OscInterface, "atGroupItem"),
91 | "/select": funcref($OscInterface, "selectActor"),
92 | "/deselect": funcref($OscInterface, "deselectActor"),
93 | "/selected": funcref($OscInterface, "listSelectedActors"),
94 | "/def": funcref($OscInterface, "defCommand"),
95 | "/load/defs": funcref($OscInterface, "loadDefsFile"),
96 | "/debug": funcref($OscInterface, "enableStatusMessages"),
97 | "/midi/debug": funcref($OscInterface, "midiEnableStatusMessages"),
98 | "/list/midi": funcref($OscInterface, "listMidiCmds"),
99 |
100 | #rand
101 | "/rand": funcref($OscInterface, "randCmdArg"),
102 | "/choose": funcref($OscInterface, "chooseCmd"),
103 | "/choose/arg": funcref($OscInterface, "chooseArg"),
104 |
105 | # time
106 | # "/wait" command is handled specially
107 | "/routine": funcref($OscInterface, "newRoutine"),
108 | "/routine/start": funcref($OscInterface, "startRoutine"),
109 | "/routine/stop": funcref($OscInterface, "stopRoutine"),
110 | "/routine/free": funcref($OscInterface, "freeRoutine"),
111 | "/routine/free/all": funcref($OscInterface, "routineFreeAll"),
112 | "/list/routines": funcref($OscInterface, "listRoutines"),
113 |
114 | # write
115 | "/load/alphabet": funcref($Letters, "loadAlphabet"),
116 | "/write": funcref($Letters, "write"),
117 | "/letter": funcref($Letters, "setLetter"),
118 | "/letters/spacing": funcref($Letters, "setSpacing"),
119 | "/letters/scale": funcref($Letters, "setScale"),
120 |
121 | # app
122 | "/bg": funcref($OscInterface, "setBackgroundColor"),
123 | "/list/commands": funcref($OscInterface, "listCommands"),
124 | "/help": funcref($OscInterface, "openHelp"),
125 | "/user/datapath": funcref($OscInterface, "postUserDataPath"),
126 |
127 | # editor
128 | "/tutorial": funcref($OscInterface, "loadTutorial"),
129 | "/editor/open": funcref($OscInterface, "openFile"),
130 | "/editor/save": funcref($OscInterface, "saveFile"),
131 | "/editor/append": funcref($OscInterface, "editorAppend"),
132 | "/editor/font/size": funcref($OscInterface, "editorFontSize"),
133 | "/editor/font/increase": funcref($OscInterface, "editorIncreaseFont"),
134 | "/editor/font/decrease": funcref($OscInterface, "editorDecreaseFont"),
135 | "/editor/clear": funcref($OscInterface, "editorClear"),
136 | "/post": funcref($OscInterface, "postMsg"),
137 | "/post/font/size": funcref($OscInterface, "postFontSize"),
138 | "/post/font/increase": funcref($OscInterface, "postIncreaseFont"),
139 | "/post/font/decrease": funcref($OscInterface, "postDecreaseFont"),
140 | "/post/open": funcref($OscInterface, "postFile"),
141 | "/post/clear": funcref($OscInterface, "postClear"),
142 |
143 | # logger
144 | "/log": funcref($OscInterface, "logMsg"),
145 | "/log/level": funcref($OscInterface, "setLogLevel"),
146 |
147 | # osc
148 | "/osc/remote": funcref($OscInterface, "connectOscRemote"),
149 | "/osc/send": funcref($OscInterface, "sendOsc"),
150 |
151 | # config commands
152 | "/load/config": funcref($Config, "loadConfig"),
153 | "/assets/path": funcref($Config, "setAnimationAssetPath"),
154 | "/app/remote": funcref($Config, "setAppRemote"),
155 |
156 | # app window
157 | "/window/screen": funcref($Config, "moveWindowToScreen"),
158 | "/window/position": funcref($Config, "setWindowPosition"),
159 | "/window/size": funcref($Config, "setWindowSize"),
160 | "/window/center": funcref($Config, "centerWindow"),
161 | "/window/fullscreen": funcref($Config, "fullscreen"),
162 | "/window/top": funcref($Config, "windowAlwaysOnTop"),
163 | }
164 |
165 |
166 | func getActorCommandSummary() -> String:
167 | return (actorCmds.keys() as PoolStringArray).join('\n')
168 |
169 |
170 | func getOtherCommandSummary() -> String:
171 | return (otherCmds.keys() as PoolStringArray).join('\n')
172 |
173 |
174 | func _ready():
175 | Logger.setLevel(Logger.LOG_LEVEL_INFO)
176 | # Logger.setLevel(Logger.LOG_LEVEL_VERBOSE)
177 | Logger.setTarget(get_node("PostTextEdit"))
178 | Logger.info("version 0.1.0_17")
179 | randomize()
180 |
181 | # See: https://gitlab.com/frankiezafe/gdosc
182 | oscrcv = load("res://addons/gdosc/gdoscreceiver.gdns").new()
183 | # [optional] maximum number of messages in the buffer, default is 100
184 | oscrcv.max_queue( 256 )
185 | # [optional] receiver will only keeps the "latest" message for each address
186 | oscrcv.avoid_duplicate( false )
187 | # [mandatory] listening to port 14000
188 | oscrcv.setup( 56101 )
189 | # [mandatory] starting the reception of messages
190 | oscrcv.start()
191 |
192 | # Load initial set of custom command definitions (if it exists)
193 | $OscInterface.loadDefsFile(["init.osc"], null)
194 |
195 | # Load default config file (if it exists) and call config command
196 | $Config.loadConfig(["config.osc"], null)
197 | evalCommandList([["/config"]], null)
198 |
199 | var w = OS.get_window_size().x
200 | var h = OS.get_window_size().y
201 | var gap = 10
202 | $OscTextEdit._set_size(Vector2(w*2/3, h))
203 | $PostTextEdit._set_size(Vector2(w*1/3 - gap, h))
204 | $PostTextEdit._set_position(Vector2(w*2/3 + gap, 0))
205 |
206 | # $Letters.loadAlphabet([])
207 |
208 |
209 | func evalCommandList(commands : Array, sender):
210 | while !commands.empty():
211 | var cmd = commands.pop_front()
212 | var addr : String = cmd[0]
213 | if addr[0] != '/':
214 | # Allow addresses missing the slash at start
215 | addr = addr.insert(0, '/')
216 | var args = cmd.slice(1, -1) if cmd.size() > 1 else []
217 | if addr == "/wait":
218 | var waitTime = $OscInterface.wait(args, sender)
219 | if waitTime:
220 | Logger.debug("Starting wait of %f seconds..." % [waitTime])
221 | yield(get_tree().create_timer(waitTime), "timeout")
222 | Logger.debug("...done waiting %f seconds" % [waitTime])
223 | else:
224 | var subCmds = evalOscCommand(addr, args, sender)
225 | if typeof(subCmds) == TYPE_ARRAY:
226 | commands = subCmds + commands
227 |
228 |
229 | func evalOscCommand(address : String, args, sender):
230 | Logger.debug("+++ evalOscCommand(%s, %s" % [address, args])
231 | var applyToSelection = address.ends_with("!")
232 | if applyToSelection:
233 | address = address.trim_suffix("!")
234 | args.insert(0, "!")
235 |
236 | if actorCmds.has(address):
237 | actorCmds[address].call_func(args, sender)
238 | elif otherCmds.has(address):
239 | otherCmds[address].call_func(args, sender)
240 | elif $CustomCommands.hasCommand(address):
241 | var cmd = $CustomCommands.getCommand(address)
242 | if args.size() != cmd.args.size():
243 | $OscInterface.reportError("Custom command '%s' expects %d arguments"
244 | % [address, cmd.args.size()], sender)
245 | return
246 | var subCmds = []
247 | for subCmd in cmd.cmds:
248 | var subAddr = subCmd[0]
249 | Logger.debug("subCmd: (%s)%s" % [typeof(subCmd), subCmd])
250 | # Logger.logDict($CustomCommands.commands)
251 | var subArgs = Array(subCmd).slice(1, -1) if subCmd.size() > 1 else []
252 | for i in range(subArgs.size()):
253 | if subArgs[i].begins_with("$"):
254 | var idx = cmd.args.find(subArgs[i].substr(1))
255 | if idx >= 0: subArgs[i] = args[idx]
256 | subCmds.push_back([subAddr] + subArgs)
257 | # Evaluation happens later, in the caller
258 | return subCmds
259 | else:
260 | $OscInterface.reportError("OSC command not found: " + address, sender)
261 |
262 |
263 | func processOscMsg(address : String, args : Array, sender):
264 | evalCommandList([[address] + args], sender)
265 |
266 |
267 | func _process(_delta):
268 | # check if there are pending messages
269 | while( oscrcv.has_message() ):
270 | # retrieval of the messages as a dictionary
271 | var msg = oscrcv.get_next()
272 | var sender = [msg["ip"], msg["port"]]
273 | if not $Config.allowRemoteClients and sender[0] != "127.0.0.1":
274 | Logger.warn("Skipping non-local OSC message from %s" % [sender])
275 | continue
276 | var address = msg["address"]
277 | var args = msg["args"]
278 | # printing the values, check console
279 | if false:
280 | Logger.debug( "address: %s" % [address] )
281 | Logger.debug( "typetag: %s" % [msg["typetag"]] )
282 | Logger.debug( "from: %s:%s" % [msg["ip"], msg["port"]] )
283 | Logger.debug( "arguments: ")
284 | for i in range( 0, msg["arg_num"] ):
285 | Logger.debug( "\t%s = %s" % [i, args[i]] )
286 |
287 | processOscMsg(address, args, sender)
288 |
289 |
290 | func _exit_tree ( ):
291 | # disable the receiver, highly recommended!
292 | oscrcv.stop()
293 |
294 | func _input(event):
295 | # Logger.debug(event.as_text())
296 | if event.is_action_pressed("toggle_editor", true):
297 | $OscTextEdit.set_visible(not($OscTextEdit.is_visible()))
298 | elif event.is_action_pressed("toggle_editor_and_post", true):
299 | $OscTextEdit.set_visible(not($OscTextEdit.is_visible()))
300 | $PostTextEdit.set_visible($OscTextEdit.is_visible())
301 | elif event.is_action_pressed("clear_post", true):
302 | $PostTextEdit.clear()
303 | elif event.is_action_pressed("toggle_post", true):
304 | $PostTextEdit.set_visible(not($PostTextEdit.is_visible()))
305 | elif event.is_action_pressed("post_commands", true):
306 | $OscTextEdit.set_visible(true)
307 | $PostTextEdit.set_visible($OscTextEdit.is_visible())
308 | $PostTextEdit.help()
309 | evalOscCommand("/list/commands", [], null)
310 | elif event.is_action_pressed("pedal_input", true):
311 | processOscMsg("/pedal/pressed", [], null)
312 |
313 | func _on_OpenFileDialog_file_selected(path):
314 | openFile(path)
315 |
316 | func openFile(path):
317 | $OscTextEdit.text = getTextFromFile(path)
318 |
319 | func getTextFromFile(path) -> String:
320 | var file = File.new()
321 | var text : String
322 | var err = file.open(path, File.READ)
323 | if err:
324 | if path.is_rel_path():
325 | var tryPath = OS.get_executable_path().get_base_dir() + "/" + path
326 | err = file.open(tryPath, File.READ)
327 | if err:
328 | Logger.error("can't open relative path as resource, or relative to executable (%s)" % [ProjectSettings.globalize_path(tryPath)])
329 | else:
330 | Logger.error("can't open absolute path: %s" % [ProjectSettings.globalize_path(path)])
331 | if !err:
332 | Logger.verbose("opened file: %s" % [path])
333 | text = file.get_as_text()
334 | file.close()
335 | return text
336 |
337 | func _on_SaveFileDialog_file_selected(path):
338 | saveFile(path)
339 |
340 | func saveFile(path):
341 | Logger.info("save file to: %s" % [path])
342 | var file = File.new()
343 | file.open(path, File.WRITE)
344 | file.store_string($OscTextEdit.text)
345 | file.close()
346 |
347 | func post(msg):
348 | $PostTextEdit.append(msg)
349 |
350 |
351 |
--------------------------------------------------------------------------------
/sc/osc-test.scd:
--------------------------------------------------------------------------------
1 | (
2 | ////////////////////////////////////////////////////////////
3 | // Setup
4 | ////////////////////////////////////////////////////////////
5 | "setup.scd".loadRelative.first;
6 | )
7 |
8 | (
9 | Tdef(\a, {
10 | 100.do{|x|
11 | // "om"++x.postln;
12 | n.sendMsg("/create", "om"++x, "om-walk-sw");
13 | n.sendMsg("/speed", "om"++x, rrand(0.7,2.0));
14 | 0.1.wait;
15 | }
16 | }).play
17 | )
18 |
19 | (
20 | ////////////////////////////////////////////////////////////
21 | // Comprehensive unit tests
22 | ////////////////////////////////////////////////////////////
23 | var test = { |description, msg, waittime=0.5|
24 | ("-- " ++ description).postln;
25 | msg.();
26 | waittime.wait;
27 | };
28 | var create = {
29 | test.("empty list", {
30 | n.sendMsg("/list"); // or /list/actors
31 | });
32 | test.("create one instance with animation", {
33 | n.sendMsg("/create", "omo", "om-walk-SW");
34 | n.sendMsg("/list");
35 | });
36 | };
37 | var transform = {
38 | test.("transform", {
39 | n.sendMsg("/position", "omo", 0.5, 0.5);
40 | 1.0.wait;
41 | n.sendMsg("/fliph", "omo");
42 | 1.0.wait;
43 | n.sendMsg("/fliph", "omo");
44 | n.sendMsg("/flipv", "omo");
45 | 1.0.wait;
46 | n.sendMsg("/flipv", "omo");
47 | });
48 | };
49 | var walkcycle = {
50 | test.("turn-around test", {
51 | n.sendMsg("/create", "omo", "om-walk-W");
52 | 1.0.wait;
53 | n.sendMsg("/create", "omo", "om-walk-NW");
54 | 1.0.wait;
55 | n.sendMsg("/create", "omo", "om-walk-N");
56 | 1.0.wait;
57 | n.sendMsg("/create", "omo", "om-walk-NE");
58 | 1.0.wait;
59 | n.sendMsg("/create", "omo", "om-walk-E");
60 | 1.0.wait;
61 | n.sendMsg("/create", "omo", "om-walk-SE");
62 | 1.0.wait;
63 | n.sendMsg("/create", "omo", "om-walk-S");
64 | 1.0.wait;
65 | n.sendMsg("/create", "omo", "om-to-idle-S");
66 | 1.0.wait;
67 | n.sendMsg("/create", "omo", "om-to-idle-SW");
68 | 1.0.wait;
69 | n.sendMsg("/create", "omo", "om-to-idle-SE");
70 | });
71 | };
72 | var transport = {
73 | test.("transport", {
74 | n.sendMsg("/create", "omo", "om-walk-SW");
75 | n.sendMsg("/stop", "omo");
76 | 1.0.wait;
77 | n.sendMsg("/play", "omo");
78 | });
79 | test.("speed", {
80 | n.sendMsg("/speed", "omo", 2.0);
81 | 1.0.wait;
82 | n.sendMsg("/speed", "omo", 0.5);
83 | 1.0.wait;
84 | n.sendMsg("/speed", "omo", 1.0);
85 | });
86 | test.("frame navigation", {
87 | n.sendMsg("/stop", "omo");
88 | });
89 | test.("wraps frame number", {
90 | n.sendMsg("/frame", "omo", 100);
91 | 1.0.wait;
92 | n.sendMsg("/frame", "omo", 4);
93 | });
94 | };
95 | var free = {
96 | test.("free", {n.sendMsg("/free", "omo", 4);});
97 | };
98 | var wildcards = {
99 | 10.do { |x|
100 | test.("wildcards",
101 | {
102 | n.sendMsg("/create", "om"++x, "om-walk-SW");
103 | n.sendMsg("/speed", "om"++x, rrand(0.7,2.0));
104 | }, 0.1);
105 | };
106 | };
107 | var wildcardsfree = {
108 | test.("wildcards free", {n.sendMsg("/free", "om*");})
109 | };
110 | var color = {
111 | test.("change color", {n.sendMsg("/color", "om*", 1,1,1);})
112 | };
113 | var select = {
114 | test.("none selected", {n.sendMsg("/selected")});
115 | test.("select one", {
116 | n.sendMsg("/create", "omo", "om-walk-SW");
117 | n.sendMsg("/position", "omo", 0.5, 0.5);
118 | n.sendMsg("/select", "omo");
119 | n.sendMsg("/selected");
120 | });
121 | test.("select non-existent", {
122 | n.sendMsg("/select", "blu");
123 | n.sendMsg("/selected".postln);
124 | });
125 | test.("select with '?'", {
126 | n.sendMsg("/create", "oma", "om-walk-SE");
127 | n.sendMsg("/position", "oma", 0.25, 0.5);
128 | n.sendMsg("/select", "om?");
129 | n.sendMsg("/selected".postln);
130 | });
131 | test.("deselect one", {
132 | n.sendMsg("/deselect", "omo");
133 | });
134 | test.("list selected", {
135 | n.sendMsg("/selected".postln);
136 | });
137 | };
138 | var group = {
139 | test.("add omo and oma to 'walkers' group", {
140 | n.sendMsg("/group", "walkers", "om?");
141 | });
142 | test.("list group members", {
143 | n.sendMsg("/group", "walkers");
144 | });
145 | test.("remove oma from 'walkers'", {
146 | n.sendMsg("/ungroup", "walkers", "omo");
147 | });
148 | test.("list group members", {
149 | n.sendMsg("/group", "walkers");
150 | });
151 | };
152 | var say = {
153 | test.("say something", {
154 | n.sendMsg("/create", "omo", "om-idle-SW");
155 | n.sendMsg("/position", "omo", 0.5, 0.5);
156 | n.sendMsg("/say", "omo", "something");
157 | 4.wait;
158 | // n.sendMsg("/say", "omo", "something else\nin two lines");
159 | n.sendMsg("/say", "omo", "something else in two lines");
160 | 4.wait;
161 | // n.sendMsg("/say", "omo", "something\nvertical\nin many\nlines");
162 | n.sendMsg("/say", "omo", "something vertical in many lines");
163 | 4.wait;
164 | // n.sendMsg("/say", "omo", "something during\na given time", 4);
165 | n.sendMsg("/say", "omo", "something during a given time", 4);
166 |
167 | })
168 | };
169 | var manysay = {
170 | test.("many say something",{
171 | 10.do{|x|
172 | n.sendMsg("/create", "om"++x, "om-idle-"++["SW","S"].choose);
173 | if(0.5.coin, {n.sendMsg("/fliph", "om"++x)});
174 | n.sendMsg("/color", "om"++x, 1.0.rand, 0.2.rand, 0.2.rand);
175 | n.sendMsg("/position", "om"++x, rrand(0.1,0.9), rrand(0.2,0.8));
176 | rrand(0.2,3.0).wait;
177 | n.sendMsg("/say", "om"++x, "I'm om"++x, rrand(3,6));
178 | rrand(0.1,2.0).wait;
179 | };
180 | });
181 | };
182 | var listruntimedata = {
183 | test.("files/assets available to load at runtime", {
184 | n.sendMsg("/list/assets");
185 | });
186 | test.("anims loaded at runtime", {
187 | n.sendMsg("/list/anims");
188 | });
189 | };
190 | var loadruntime = {
191 | test.("load file at runtime", {
192 | 100.do{|x|
193 | n.sendMsg("/create", "om"++x, "om-idle-"++["e","n","w","s","nw","ne","sw","se"].choose);
194 | n.sendMsg("/position", "om"++x, rrand(0.1,0.9), rrand(0.2,0.8));
195 | n.sendMsg("/speed", "om"++x, rrand(0.5,2.0));
196 | 0.1.wait;
197 | };
198 | });
199 | };
200 | // syntax for a new test:
201 | // var testname = {
202 | // test.("a description", {
203 | // n.sendMsg(...);
204 | // // ...
205 | // },
206 | // waittime: defaults-to-1.0);
207 | // };
208 | //
209 | // then add it to the task with:
210 | //
211 | // testname.();
212 | //
213 | // comment to disble tests
214 | t = Task {
215 | // create.();
216 | // transform.();
217 | // walkcycle.();
218 | // transport.();
219 | // 2.0.wait;
220 | // free.();
221 | // wildcards.();
222 | // color.();
223 | // select.();
224 | // 1.0.wait;
225 | // group.();
226 | // 2.wait;
227 | // say.();
228 | // manysay.();
229 | listruntimedata.();
230 | loadruntime.();
231 | 4.wait;
232 | wildcardsfree.();
233 | };
234 | t.start;
235 | )
236 |
237 | n.sendMsg("/list/anims");
238 |
239 | (
240 | ////////////////////////////////////////////////////////////
241 | // Alternative OSC interface testing (run OSCdef setup first)
242 | ////////////////////////////////////////////////////////////
243 | Tdef(\test, {
244 | n.sendMsg("/list/assets");
245 | ["run", "om-walk-sw", "om-walk-nw", "om-walk-s", "fox-walk", "frog-jump"].do{ |name| n.sendMsg("/load", name) };
246 | n.sendMsg("/list/anims");
247 | n.sendMsg("/invalid", "frog");
248 | n.sendMsg("/free", "*");
249 | n.sendMsg("/list");
250 | n.sendMsg("/create", "runner", "run");
251 | n.sendMsg("/create", "omo", "om-walk-sw");
252 | n.sendMsg("/create", "oma", "om-walk-nw");
253 | n.sendMsg("/select", "om*");
254 | n.sendMsg("/select");
255 | n.sendMsg("/deselect", "omo");
256 | n.sendMsg("/selected");
257 | n.sendMsg("/stop!");
258 | n.sendMsg("/stop", "omo");
259 | n.sendMsg("/frame!", 3);
260 | n.sendMsg("/frame", "omo", 3);
261 | n.sendMsg("/play!");
262 | n.sendMsg("/play", "om?");
263 | n.sendMsg("/position!", 0.25, 0.25);
264 | n.sendMsg("/position", "omo", 0.75, 0.5, 2);
265 | n.sendMsg("/speed!", 0.5);
266 | n.sendMsg("/speed", "omo", 1.5);
267 | n.sendMsg("/fliph!");
268 | n.sendMsg("/fliph", "omo");
269 | n.sendMsg("/flipv!");
270 | n.sendMsg("/flipv", "omo");
271 | n.sendMsg("/create", "omi", "om-walk-s");
272 | n.sendMsg("/position", "omi", 0.5, 0.5);
273 | n.sendMsg("/group", "inverted", "om*");
274 | n.sendMsg("/group", "inverted");
275 | n.sendMsg("/ungroup", "inverted", "omi");
276 | n.sendMsg("/group", "inverted");
277 | n.sendMsg("/color!", 0.8, 0.5, 0);
278 | n.sendMsg("/color", "omi", 0, 0.5, 0.8);
279 | n.sendMsg("/deselect", "*");
280 | n.sendMsg("/list");
281 | n.sendMsg("/free!");
282 | n.sendMsg("/create", "fox", "fox-walk");
283 | n.sendMsg("/create", "frog", "frog-jump");
284 | n.sendMsg("/group", "others", "f*");
285 | n.sendMsg("/group", "others");
286 | n.sendMsg("/speed", "others", 4);
287 | n.sendMsg("/select", "others");
288 | n.sendMsg("/list");
289 | n.sendMsg("/free!");
290 | n.sendMsg("/list");
291 | n.sendMsg("/say", "omo", "something");
292 | n.sendMsg("/say", "omi", "something else", 8);
293 | n.sendMsg("/select", "oma");
294 | n.sendMsg("/say!", "I'm oma", 4);
295 | n.sendMsg("/deselect");
296 | }).play
297 |
298 | // The expected output is:
299 | /*
300 | Available assets:
301 | default
302 | fox-walk
303 | ...
304 | om-walk-w
305 | pickaxe
306 | march
307 | run
308 | Status: loaded sequences: [res://animations/run_12fps]
309 | Status: loaded sprites: [res://animations/om-walk-sw.png]
310 | Status: loaded sprites: [res://animations/om-walk-nw.png]
311 | Status: loaded sprites: [res://animations/om-walk-s.png]
312 | Status: loaded sprites: [res://animations/fox-walk_6x1_8fps.png]
313 | Status: loaded sprites: [res://animations/frog-jump_4x2_8fps.png]
314 | Available animations:
315 | fox-walk
316 | frog-jump
317 | om-walk-nw
318 | om-walk-s
319 | om-walk-sw
320 | run
321 | Error: OSC command not found: /invalid
322 | Error: No matches found for: *
323 | Status: Freed: []
324 | Anims: [ ]
325 | Status: Created node 'runner' with 'run'
326 | Status: Created node 'omo' with 'om-walk-sw'
327 | Status: Created node 'oma' with 'om-walk-nw'
328 | Status: selected: [omo, oma]
329 | Status: selected: [oma]
330 | Status: Created node 'omi' with 'om-walk-s'
331 | Status: 'inverted' members: [omo, oma, omi]
332 | Status: 'inverted' members: [omo, oma]
333 | Anims: [ runner, omo, oma, omi ]
334 | Status: Freed: []
335 | Status: Created node 'fox' with 'fox-walk'
336 | Status: Created node 'frog' with 'frog-jump'
337 | Status: 'others' members: [fox, frog]
338 | Anims: [ runner, omo, oma, omi, fox, frog ]
339 | Status: Freed: [fox, frog]
340 | Anims: [ runner, omo, oma, omi ]
341 | */
342 |
343 | // And you should see a slow orange upside-down om at
344 | // the upper-left, a blue om facing you in the
345 | // centre, and a fast black upside-down om at the right.
346 | // They'll have some speech bubbles that last a short while.
347 | )
348 |
349 | // If you have a commands/init.osc file installed that defines
350 | // /createsel and /startup, you can run these custom commands
351 | // (like macros).
352 | n.sendMsg("/wait", 2)
353 | n.sendMsg("/startup");
354 | n.sendMsg("/createsel", "frog", "frog-jump")
355 | n.sendMsg("/deselect")
356 |
357 | n.sendMsg("/def", "/waitasset", "/wait 1", "/list/assets")
358 | n.sendMsg("/def", "/waitanim", "/wait 2", "/list/anims")
359 | n.sendMsg("/def", "/waitlist", "/waitasset", "/waitanim")
360 | n.sendMsg("/waitasset")
361 | n.sendMsg("/waitlist")
362 |
363 | n.sendMsg("/def", "/waitlist", "/wait 2", "/list/assets", "/wait 2", "/list/anims")
364 | n.sendMsg("/waitlist")
365 |
366 | n.sendMsg("/def", "/hello", "/list/assets", "/group bob")
367 | n.sendMsg("/hello")
368 | n.sendMsg("/def", "/test arg1 b", "/create $arg1 $b")
369 | n.sendMsg("/test", "fred", "steve")
370 |
371 | n.sendMsg("/list/anims")
372 | (
373 | n.sendMsg("/def", "/square actor",
374 | "/new $actor om-walk-e",
375 | "/position $actor 0.9 0.25 2",
376 | "/wait 4",
377 | "/new $actor om-walk-s",
378 | "/position $actor 0.8 0.9 2",
379 | "/wait 3",
380 | "/new $actor om-walk-w",
381 | "/position $actor 0.2 0.9 1",
382 | "/wait 2",
383 | "/new $actor om-walk-n",
384 | "/position $actor 0.1 0.25 1")
385 | )
386 | n.sendMsg("/square", "om5")
387 | n.sendMsg("/load/defs", "test.osc")
388 | n.sendMsg("/startup")
389 |
390 | n.sendMsg("/list/assets");
391 | n.sendMsg("/load", "march");
392 | n.sendMsg("/create", "m1", "march")
393 | n.sendMsg("/select", "m?")
394 | (1..5).do{|i| n.sendMsg("/position", "m" ++ i, i.linlin(1,5,0,1), 1, 4) }
395 | n.sendMsg("/rotate!", 90, 12)
396 | n.sendMsg("/scale!", "0.25,4", 1)
397 | n.sendMsg("/fade!", 0, 4)
398 |
399 | n.sendMsg("/load", "om-jump-up")
400 | n.sendMsg("/load", "pickaxe")
401 | n.sendMsg("/list/anims")
402 | n.sendMsg("/create", "om", "om-jump-up-nw")
403 | n.sendMsg("/create", "axe", "pickaxe")
404 |
405 | n.sendMsg("/def", "/go", "/free *", "/create axe pickaxe", "/position axe 0.25 0.5", "/scale axe 2 2")
406 | n.sendMsg("/go") // call repeatedly quickly and check for flicker (fixed tweening with 0 duration)
407 |
408 | // If you have a 1024x600 image, you should name it bg-black_1x1_1fps.png
409 | // and can set it as the background (covering the whole view) like this:
410 | n.sendMsg("/load", "bg-black")
411 | n.sendMsg("/create", "bg", "bg-black")
412 | n.sendMsg("/position", "bg", 0.5,0.5)
413 | n.sendMsg("/window/fullscreen", false)
414 | n.sendMsg("/position", "axe", 0.5, 0.5)
415 | n.sendMsg("/position", "om", 0.5, 0.5)
416 | n.sendMsg("/free", "bg")
417 | n.sendMsg("/list")
418 |
419 | (
420 | n.sendMsg("/load", "pickaxe");
421 | n.sendMsg("/create", "bigger", "pickaxe");
422 | n.sendMsg("/create", "axe1", "pickaxe");
423 | n.sendMsg("/create", "axe2", "pickaxe");
424 | n.sendMsg("/create", "axe3", "pickaxe");
425 | n.sendMsg("/scale", "bigger", 2, 2);
426 | n.sendMsg("/position", "bigger", 0.4, 1);
427 | n.sendMsg("/position", "axe1", 0.5, 0.5);
428 | n.sendMsg("/position", "axe2", 0.55, 0.55);
429 | n.sendMsg("/position", "axe3", 0.525, 0.6);
430 | n.sendMsg("/color", "axe1", 0.7, 0, 0);
431 | n.sendMsg("/color", "axe2", 0, 0.7, 0);
432 | n.sendMsg("/color", "axe3", 0, 0, 0.7);
433 | )
434 |
435 | x.("/list");
436 | x.("/behind bigger axe*");
437 | x.("/behind axe* bigger");
438 | x.("/front bigger axe*");
439 | x.("/front axe* bigger");
440 |
441 | x.("/select axe1");
442 | x.("/select axe2");
443 |
444 | x.("/behind! axe3");
445 | x.("/front! axe3");
446 | x.("/behind! bigger");
447 | x.("/front! bigger");
448 |
449 | (
450 | ////////// Wander action
451 | {
452 | x.("/free *");
453 | x.("/load pickaxe");
454 | 100.do{ |i|
455 | var name = "axe" ++ i;
456 | var scl = i.linexp(0,99,0.1,3);
457 | x.("/create % pickaxe".format(name));
458 | x.("/position % % 0.5".format(name, i.linlin(0,99, 0,0.9)));
459 | x.("/rotate % 360 20".format(name));
460 | x.("/pivot % 0 1 10".format(name));
461 | x.("/action % wander 0.2 2".format(name));
462 | x.("/fade % 0.5".format(name));
463 | x.("/scale % % %".format(name, scl, scl));
464 | 0.05.wait;
465 | }
466 | }.forkIfNeeded
467 | )
468 |
469 | (
470 | ////////// Oscillate action
471 | // "Cartoon walking" character
472 | x.("/free *");
473 | x.("/load cube");
474 | x.("/create cube cube");
475 | x.("/position cube 0.2 0.2");
476 | x.("/action cube oscillate 1 15 0.05 0.1 1 2 0.125");
477 | x.("/position cube 0.8 0.5 4");
478 | )
479 |
480 | x.("/load/defs init_example.osc")
481 | x.("/load/defs commands/init_example.osc")
482 | x.("/load/config config_example.osc")
483 | x.("/load/config config/config_example.osc")
484 | x.("/config")
485 | x.("/something")
486 |
487 | x.("/list/assets")
488 | x.("/assets/path animations")
489 | x.("/assets/path C:/Users/holag/Documents/Programming/gitreps/animatron/animations")
490 |
491 | x.("/load letter-a")
492 | x.("/load letter-b")
493 | x.("/load letter-c")
494 | x.("/list/anims")
495 | x.("/new a letter-a")
496 | x.("/new b letter-b")
497 | x.("/new c letter-c")
498 | x.("/scale", "a", 0.5")
499 | x.("/scale", "b", 0.5")
500 | x.("/position", "a", 0.25, 0.5);
501 | x.("/position", "b", 0.75, 0.5);
502 | x.("/group", "ltrs", "a", "b");
503 | x.("/group", "ltrs", "b");
504 | x.("/group", "ltrs");
505 | x.("/stop", "ltrs");
506 | x.("/play", "ltrs");
507 | x.("/stop", "b");
508 | x.("/list/actors")
509 |
510 | (
511 | x.("/new", "n", "numbers");
512 | x.("/speed", "n", 1/12);
513 | // x.("/play/rand", "n");
514 | // x.("/play/rand", "n", 0);
515 | x.("/play/reverse", "n");
516 | // x.("/play/reverse", "n", 0);
517 | // x.("/stop", "n");
518 | // x.("/scale", "n", 0.1, 15);
519 | // x.("/scale", "n", 1, 0);
520 | // x.("/scale", "n", 1.1, 10);
521 | // x.("/scale", "n", 0.7, 2);
522 | // x.("/scale/xy", "n", 0.2, 0.3, 0.2);
523 | // x.("/scale/x", "n", 0.5, 2.0);
524 | // x.("/scale/y", "n", 0.4, 2.0);
525 | // x.("/position/x", "n", 0.2);
526 | // x.("/position/x", "n", 0.3, 0.7);
527 | // x.("/position/y", "n", 0.2);
528 | // x.("/position/y", "n", 0.7, 0.2);
529 | )
530 | (
531 | x.("/new", "na", "square");
532 | x.("/new", "ne", "square");
533 | x.("/new", "ni", "square");
534 | x.("/scale/x", "n*", 0.5);
535 | x.("/pivot", "n*", 0.5, 1.0);
536 | x.("/position/y", "n*", 0.9);
537 | x.("/position/x", "na", 0.2);
538 | x.("/position/x", "ni", 0.8);
539 | x.("/sound", "na", 1, "/scale/y");
540 | x.("/sound", "na", 1, "/position/y");
541 | x.("/sound", "ne", 2, "/scale/y");
542 | x.("/sound", "ni", 3, "/scale/y");
543 | )
544 | x.("/free", "*")
545 | x.("/sound/free", "na", 1)
546 | x.("/sound", "na", 1, "play")
547 |
548 | (
549 | x.("/new", "sqa", "square");
550 | // x.("/color", "sqa", 1,0,0);
551 | x.("/color/r", "sqa", 0.0);
552 | x.("/color/g", "sqa", 0.0);
553 | x.("/color/b", "sqa", 0.0);
554 | x.("/sound", "sqa", 1, "/color/r");
555 | )
556 | x.("/load/config", Platform.userHomeDir++"/work/animatron/config/asturies-config.osc");
557 | (
558 | x.("/full", "bg");
559 | x.("/new", "m", "mouth");
560 | x.("/behind", "bg", "*")
561 | x.("/stop", "m");
562 | x.("/stop", "bg");
563 | x.("/color/orange", "bg");
564 | x.("/speed", "bg", rrand(0.3,0.7));
565 | x.("/speed", "m", 0.2);
566 | x.("/play/rand", "m");
567 | x.("/scale", "m", 0.25);
568 | )
569 | (
570 | x.("/load", "spiral-1");
571 | x.("/load", "square");
572 | x.("/new", "sp", "spiral-1");
573 | x.("/new", "spa", "spiral-1");
574 | x.("/new", "spi", "spiral-1");
575 | x.("/new", "sq", "square");
576 | x.("/pivot", "spa", 0.47, 0.51);
577 | x.("/speed", "sp", rrand(0.3,0.6));
578 | x.("/speed", "spa", rrand(0.4,0.6));
579 | x.("/speed", "spi", rrand(0.4,0.6));
580 | x.("/rotate", "spa", 360.rand);
581 | x.("/color", "sq", 0.3,0.05,0.02);
582 | x.("/color", "spa", 0.3,0.05,0.02);
583 | x.("/color", "sp", 0.7,0.55,0.02);
584 | x.("/color", "spa", 0.7,0.60,0.02);
585 | x.("/behind", "sq", "*");
586 | x.("/scale", "sq", 2, 1.2, 0);
587 | x.("/")
588 | )
589 | (
590 | x.("/load", "square");
591 | x.("/load", "canon-man");
592 | x.("/new", "bg", "square");
593 | x.("/scale", "bg", 2,1.2);
594 | x.("/behind", "bg", "*");
595 | x.("/stop", "bg");
596 | x.("/new", "man", "canon-man");
597 | x.("/new", "mana", "canon-man");
598 | x.("/speed", "man", 1.5);
599 | x.("/play", "man", 0);
600 | x.("/color", "man", 1,0,0);
601 | )
602 | a = Animatron.new;
603 | a.sendMsg("/load/config", "config-abstract.osc")
604 | a.sendMsg("/list");
605 | a.sendMsg("/list/assets");
606 | a.sendMsg("/list/anims");
607 | a.sendMsg("/load", "bg");
608 | a.sendMsg("/load", "square");
609 | a.sendMsg("/load", "rect-long");
610 | a.sendMsg("/new", "bg", "bg");
611 | a.sendMsg("/new", "lna", "rect-long");
612 | a.sendMsg("/color/white", "lna");
613 | a.sendMsg("/scale/y", "lna", 0.25);
614 | a.sendMsg("/speed", "lna", 0.4);
--------------------------------------------------------------------------------