diff --git a/demos/manifest.toml b/demos/manifest.toml deleted file mode 100644 index e91fac6..0000000 --- a/demos/manifest.toml +++ /dev/null @@ -1,49 +0,0 @@ -# This file was generated by Gleam -# You typically do not need to edit this file - -packages = [ - { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, - { name = "booklet", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "booklet", source = "hex", outer_checksum = "08E0FDB78DC4D8A5D3C80295B021505C7D2A2E7B6C6D5EAB7286C36F4A53C851" }, - { name = "directories", version = "1.2.0", build_tools = ["gleam"], requirements = ["envoy", "gleam_stdlib", "platform", "simplifile"], otp_app = "directories", source = "hex", outer_checksum = "D13090CFCDF6759B87217E8DDD73A75903A700148A82C1D33799F333E249BF9E" }, - { name = "envoy", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "9C6FBB6BFA02A52798BEEC5977A738CAD6E4A057F4B67FD0C8061AD2502C191A" }, - { name = "exception", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "329D269D5C2A314F7364BD2711372B6F2C58FA6F39981572E5CA68624D291F8C" }, - { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" }, - { name = "gleam_community_ansi", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "B5AA433AF84313E23FDF90CCFF752B9380FE9FFCE02B2949D49B7AACCC77B16D" }, - { name = "gleam_community_colour", version = "2.0.4", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "6DB4665555D7D2B27F0EA32EF47E8BEBC4303821765F9C73D483F38EE24894F0" }, - { name = "gleam_crypto", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "2DE9E4EF53CF6FEE049D4F765731F7178F7A11AEFAE00EEE63BF7536B354AD3F" }, - { name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" }, - { name = "gleam_http", version = "4.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "82EA6A717C842456188C190AFB372665EA56CE13D8559BF3B1DD9E40F619EE0C" }, - { name = "gleam_httpc", version = "5.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "C545172618D07811494E97AAA4A0FB34DA6F6D0061FDC8041C2F8E3BE2B2E48F" }, - { name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" }, - { name = "gleam_otp", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "BA6A294E295E428EC1562DC1C11EA7530DCB981E8359134BEABC8493B7B2258E" }, - { name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" }, - { name = "gleam_stdlib", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "960090C2FB391784BB34267B099DC9315CC1B1F6013E7415BC763CEF1905D7D3" }, - { name = "gleam_time", version = "1.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "533D8723774D61AD4998324F5DD1DABDCDBFABAFB9E87CB5D03C6955448FC97D" }, - { name = "glint", version = "1.2.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "2214C7CEFDE457CEE62140C3D4899B964E05236DA74E4243DFADF4AF29C382BB" }, - { name = "glisten", version = "9.0.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging"], otp_app = "glisten", source = "hex", outer_checksum = "7795AA50830656F3A0316A6B26595F893C83272DA901B3405E31339CAA31A10B" }, - { name = "gramps", version = "6.0.1", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "D55636072DEE173F6586A5679D3C02EC7A0DE3F8646B78C351B72908FF223DF7" }, - { name = "group_registry", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "group_registry", source = "hex", outer_checksum = "BC798A53D6F2406DB94E27CB45C57052CB56B32ACF7CC16EA20F6BAEC7E36B90" }, - { name = "houdini", version = "1.2.1", build_tools = ["gleam"], requirements = [], otp_app = "houdini", source = "hex", outer_checksum = "6F8AC2F12974567FB744BEA66AC93CEB76AAEA19AD28564623F76CDA9BC26A85" }, - { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, - { name = "justin", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "8B1C62269E8607D0A0ED698B7903984CE0BF7B6B3C0DEA3C6C8302B39402837B" }, - { name = "logging", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "BC5F18CE5DD9686100229FE5409BDC3DD5C46D5A7DF2F804AD2D8F0DD6C5060E" }, - { name = "lustre", version = "5.6.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "houdini"], otp_app = "lustre", source = "hex", outer_checksum = "EE558CD4DB9F09FCC16417ADF0183A3C2DAC3E4B21ED3AC0CAE859792AB810CA" }, - { name = "lustre_dev_tools", version = "2.3.6", build_tools = ["gleam"], requirements = ["argv", "booklet", "filepath", "gleam_community_ansi", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_httpc", "gleam_json", "gleam_otp", "gleam_regexp", "gleam_stdlib", "glint", "group_registry", "justin", "lustre", "mist", "polly", "simplifile", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "7A650A107C7E767D902A8CB608460B927DE0CDD47D5BA04DED71F9F622FE6AD9" }, - { name = "marceau", version = "1.3.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "2D1C27504BEF45005F5DFB18591F8610FB4BFA91744878210BDC464412EC44E9" }, - { name = "mist", version = "6.0.3", build_tools = ["gleam"], requirements = ["exception", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "1B07F321D5FA0CB162D81496F2DE96AEB6EF8980F4F38230A4CC3F849497E020" }, - { name = "off_topic", version = "1.0.0-rc2", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib", "gleam_time", "lustre"], source = "local", path = ".." }, - { name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" }, - { name = "polly", version = "3.1.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_erlang", "gleam_otp", "gleam_stdlib", "simplifile"], otp_app = "polly", source = "hex", outer_checksum = "51FB565D81FF6212FDF3306D44419601F2A7C4EDD1F00FC9DA5C376A00AED4FE" }, - { name = "simplifile", version = "2.4.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "7C18AFA4FED0B4CE1FA5B0B4BAC1FA1744427054EA993565F6F3F82E5453170D" }, - { name = "snag", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "274F41D6C3ECF99F7686FDCE54183333E41D2C1CA5A3A673F9A8B2C7A4401077" }, - { name = "tom", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "tom", source = "hex", outer_checksum = "DCF04CB7AB35D58CFC598C66EA2E1816D160759802C89B2BA6238780D59BC256" }, - { name = "wisp", version = "2.2.2", build_tools = ["gleam"], requirements = ["directories", "exception", "filepath", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "houdini", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "5FF5F1E288C3437252ABB93D8F9CF42FF652CE7AD54480CFE736038DC09C4F22" }, -] - -[requirements] -gleam_stdlib = { version = ">= 1.0.0 and < 2.0.0" } -gleam_time = { version = ">= 1.8.0 and < 2.0.0" } -justin = { version = ">= 1.0.0 and < 2.0.0" } -lustre = { version = ">= 5.6.0 and < 6.0.0" } -lustre_dev_tools = { version = ">= 2.3.6 and < 3.0.0" } -off_topic = { path = ".." } diff --git a/demos/src/component.css b/demos/src/component.css index 154ec62..f4a2d37 100644 --- a/demos/src/component.css +++ b/demos/src/component.css @@ -2,19 +2,19 @@ @source "./src/**/*.gleam"; @theme { - --color-card-bg: var(--background, #ffffff); - --color-card-border: var(--code-border, #ffaff3); - --color-card-text: var(--text, #2a2020); - --color-link: var(--links, #d900b8); + --color-card-bg: var(--background, #ffffff); + --color-card-border: var(--code-border, #ffaff3); + --color-card-text: var(--text, #2a2020); + --color-link: var(--links, #d900b8); } .theme-dark { - --bg: #292d3e; - --taupe-mono-1: #fdf1d4; + --bg: #292d3e; + --taupe-mono-1: #fdf1d4; - --background: var(--bg); - --code-background: #202431; - --text: var(--taupe-mono-1); - --links: var(--pink, #ffaff3); - --code-border: var(--pink, #ffaff3); + --background: var(--bg); + --code-background: #202431; + --text: var(--taupe-mono-1); + --links: var(--pink, #ffaff3); + --code-border: var(--pink, #ffaff3); } diff --git a/demos/src/component.gleam b/demos/src/component.gleam index c79a2ea..536128a 100644 --- a/demos/src/component.gleam +++ b/demos/src/component.gleam @@ -19,6 +19,7 @@ import demos/page_state import demos/pointer import demos/prevent_unload import demos/reduced_motion +import demos/request_animation_frame import demos/screen_orientation import demos/scroll_into_view import demos/session_storage @@ -51,6 +52,7 @@ pub fn register() -> Nil { language.register() breakpoints.register() local_storage.register() + request_animation_frame.register() session_storage.register() every.register() after.register() diff --git a/demos/src/demos.gleam b/demos/src/demos.gleam index 10c99de..c83f000 100644 --- a/demos/src/demos.gleam +++ b/demos/src/demos.gleam @@ -36,6 +36,8 @@ const demos = [ "focus", "blur", "on", + "on_animation_frame", + "on_animation_frame_delta", "colour_scheme", "reduced_motion", "contrast", diff --git a/demos/src/demos/request_animation_frame.gleam b/demos/src/demos/request_animation_frame.gleam new file mode 100644 index 0000000..1088f6f --- /dev/null +++ b/demos/src/demos/request_animation_frame.gleam @@ -0,0 +1,165 @@ +import demo +import gleam/float +import gleam/list +import gleam/string +import gleam/time/duration.{type Duration} +import lustre/attribute +import lustre/effect.{type Effect} +import lustre/element.{type Element} +import lustre/element/html +import lustre/element/svg +import off_topic.{type PageState} + +pub fn register() -> Nil { + demo.register(component(), ["on_animation_frame", "on_animation_frame_delta"]) +} + +fn component() { + demo.application(init:, update:, view:, subscriptions:) +} + +type Model { + Model( + visible: Bool, + page_state: PageState, + x: Float, + y: Float, + r: Float, + s: Float, + dx: Float, + dy: Float, + w: Float, + h: Float, + ) +} + +type Message { + VisibilityChanged(Bool) + PageStateChanged(PageState) + GotCanvasSize(Float, Float) + Tick(Duration) + Clicked +} + +fn init(_flags: Nil) -> #(Model, Effect(Message)) { + let model = + Model( + visible: False, + page_state: off_topic.Active, + x: 0.0, + y: 0.0, + r: random_radius(), + s: random_speed(), + dx: random_direction(), + dy: random_direction(), + w: 0.0, + h: 0.0, + ) + + #(model, effect.none()) +} + +fn random_radius() -> Float { + float.random() *. 12.0 +. 4.0 +} + +fn random_speed() -> Float { + float.random() *. 200.0 +. 80.0 +} + +fn random_direction() -> Float { + let mag = float.random() *. 0.6 +. 0.4 + case float.random() >. 0.5 { + True -> mag + False -> mag *. -1.0 + } +} + +fn subscriptions(model: Model) -> off_topic.Subscription(Message) { + off_topic.batch([ + off_topic.page_state(PageStateChanged), + off_topic.element_visible("#canvas", VisibilityChanged), + off_topic.element_size("#canvas", GotCanvasSize), + off_topic.on_click(fn(_) { Clicked }), + case model.visible, model.page_state { + True, off_topic.Active -> off_topic.on_animation_frame_delta(Tick) + _, _ -> off_topic.none() + }, + ]) +} + +fn update(model: Model, message: Message) -> #(Model, Effect(Message)) { + let model = case message { + VisibilityChanged(visible) -> Model(..model, visible:) + PageStateChanged(page_state) -> Model(..model, page_state:) + GotCanvasSize(w, h) -> Model(..model, w:, h:) + Clicked -> + Model( + ..model, + r: random_radius(), + s: random_speed(), + dx: random_direction(), + dy: random_direction(), + ) + Tick(dt) -> tick(model, dt) + } + + #(model, effect.none()) +} + +fn tick(model: Model, dt: Duration) -> Model { + let Model(x:, y:, dx:, dy:, w:, h:, r:, s:, ..) = model + let dt = duration.to_seconds(dt) + + let lx = w /. -2.0 +. r + let hx = w /. 2.0 -. r + let ly = h /. -2.0 +. r + let hy = h /. 2.0 -. r + + let x = float.clamp(x +. dx *. dt *. s, min: lx, max: hx) + let y = float.clamp(y +. dy *. dt *. s, min: ly, max: hy) + + let dx = case x <=. lx || x >=. hx { + True -> -1.0 *. dx + False -> dx + } + + let dy = case y <=. ly || y >=. hy { + True -> -1.0 *. dy + False -> dy + } + + Model(..model, x:, y:, dx:, dy:) +} + +fn view(model: Model) -> Element(Message) { + let Model(x:, y:, w:, h:, r:, ..) = model + + let animation = + svg.svg( + [ + attribute.class("text-card-border"), + attribute.attribute( + "viewBox", + [w /. -2.0, h /. -2.0, w, h] + |> list.map(float.to_string) + |> string.join(" "), + ), + ], + [ + svg.circle([ + attribute.attribute("cx", float.to_string(x)), + attribute.attribute("cy", float.to_string(y)), + attribute.attribute("r", float.to_string(r)), + attribute.attribute("fill", "#ffaff3"), + ]), + ], + ) + + demo.card( + "request_animation_frame", + html.div([attribute.id("canvas"), attribute.class("w-full h-20")], [ + animation, + ]), + ) +} diff --git a/src/off_topic.gleam b/src/off_topic.gleam index 5297252..13182da 100644 --- a/src/off_topic.gleam +++ b/src/off_topic.gleam @@ -1732,7 +1732,7 @@ pub fn on_idle( pub fn on_animation_frame( send message: fn(Timestamp) -> message, ) -> Subscription(message) { - no_erlang() + let _ = no_erlang() runtime.animation(fn() { message(timestamp.system_time()) }) } diff --git a/src/off_topic/internal/runtime.gleam b/src/off_topic/internal/runtime.gleam index d126dd3..9664529 100644 --- a/src/off_topic/internal/runtime.gleam +++ b/src/off_topic/internal/runtime.gleam @@ -754,8 +754,8 @@ fn diff(tick, path, left, right, effects) { if n1 == n2 && p1 == p2 && c1.dependencies == c2.dependencies -> #(left, effects) - Animating(tick:, ..), RequestAnimationFrame(callback:) -> { - #(Animating(tick:, callback:), effects) + Animating(..), RequestAnimationFrame(..) -> { + #(left, effects) } Group(olds), Batch(news) ->