Welcome, weary internet traveller. You’ve stumbled onto a great slice of the internet.

Keyframes is a creative community. Share your #wip, get #feedback, find inspiration, and chat with people who make things. It is a bunker from the rest of the garbage internet. No popularity contests here. No circle jerks. No regular jerks. Just a wholesome place to shoot the shit and be real about what you’re making.

You can post in public, or private (with a Plus account). Use it to improve your work, or just feel good about creating things again.

Come on in! We hope you enjoy your stay.

Register here for a very fun time ✨️

Or log in if you’re returning. (Welcome back!)

All code posts

Neat code for a ripple animation of SVG lines
// postcss.config.js module.exports = { plugins: [ require('postcss-cssnext'), require('postcss-for'), require('postcss-math'), require('postcss-simple-vars'), ] } // style.css @keyframes bump { 8%, 11% { transform: translate(0, 0); } 10% { transform: translate(-.333em, -.333em); } } @for $i from 1 to 30 { .line-$i { transform-origin: bottom left; animation: bump 10s cubic-bezier(.67,-0.13,.47,1.22) infinite; animation-delay: resolve(0.1s * $i / 3); } }
Scrolling Waveform Visualizer Using Web Audio API
const targetLength = this.analyser.fftSize * 8 // or however long // if you want 4 bars at x bpm (4/4): // 60 / bpm * 4 * 4 * this.audioCtx.sampleRate let displayArray = new Uint8Array(targetLength).fill(128) let prevTime = 0 const updateData = (t) => { this.requestAnimId = requestAnimationFrame(updateData) const frameOffset = Math.floor( (this.audioCtx.currentTime - prevTime) * this.audioCtx.sampleRate ) prevTime = this.audioCtx.currentTime displayArray = concatenate( Uint8Array, displayArray, this.getAnalyserData().slice(-frameOffset) ).slice(-targetLength) canvasCtx.fillStyle = 'rgba(255, 255, 255, 1)' canvasCtx.fillRect(0, 0, this.state.width, this.state.height) canvasCtx.lineWidth = 1 canvasCtx.strokeStyle = defaultColors.paleVioletRed canvasCtx.beginPath() const sliceWidth = this.state.width * 1.0 / targetLength let x = 0 for (let i = 0; i < targetLength; i++) { const v = displayArray[i] / 128.0 const y = v * this.state.height / 2 if (i === 0) { canvasCtx.moveTo(x, y) } else { canvasCtx.lineTo(x, y) } x += sliceWidth } canvasCtx.lineTo(this.state.width, this.state.height / 2) canvasCtx.stroke() } updateData()

Trying to build a smooth waveform visualizer Γ  la Traktor using the Web Audio API that shows a longer section of the waveform than the FFT size of the analyzer node. Normally you can't do that by default as the buffer length is tied to the FFT, it's more suitable for oscilloscopes and such. So far I've got it working with an approach of concatenating Uint8Arrays into a bigger target, but it's a real CPU killer (chrome task manager shows 99-102% πŸ˜„). This code is embedded within a React component lifecycle method. Here's how it looks like in action:

https://cdn.haywirez.com/file/haywirez-cdn/temp/songsling_io_scrolling_waveform.mp4

Performance improvement suggestions very welcome πŸ˜„

Need help manipulating a component in FramerX
import * as React from "react"; import { PropertyControls, ControlType } from "framer"; import { Chat } from "./canvas"; const style: React.CSSProperties = { height: "100%", display: "flex", alignItems: "center", justifyContent: "center", textAlign: "center", color: "#8855FF", background: "rgba(136, 85, 255, 0.1)", overflow: "hidden", }; // Define type of property interface Props { text: string; } export class embedTest extends React.Component<Props> { // Set default properties static defaultProps = { text: "Hello World!" } // Items shown in property panel static propertyControls: PropertyControls = { text: { type: ControlType.String, title: "Text" }, } render() { return <div style={style}> {this.props.text} <Chat /> </div>; } }

I'm trying to manipulate the properties of Chat , a "design" component in FramerX. I've imported it, and it renders.

What's the best way to position it inside my embedTest component? I can pass props to it, but not all of them seem to work predictably?

Should I be positioning it inside a wrapper and manipulating that?

I wanna pin it to the left of the parent container, and have its position animatable.

Bit confused about how you're supposed to mix design & code components.

FramerX Source: https://cl.ly/79dbf10ab6b8
FramerX docs: https://framer.gitbook.io/framer/

A tiny library I'm working on that allows declarative interaction patterns
document.addEventListener('DOMContentLoaded', function() { ariaAutopilot.instruct({ '[role=tab]': { 'activate': 'context -> select', 'select': 'siblings -> deselect, set-script-focusable; context -> set-focusable; target -> show, set-focusable; target -> update-location', 'deselect': 'target -> hide, set-script-focusable', 'key_down': 'target -> focus', 'key_left': 'previous-sibling -> select', 'key_right': 'next-sibling -> select' }, '[role=tabpanel]': { 'target': 'origin -> select; context -> focus', 'key_up': 'origin -> focus' } }); });

This recipe automatically adds accessible tab interaction to the page. You simply define the correct HTML with the correct ARIA roles and the library handles it from there.

Wrap videos in a Figure (with a caption!) in Jekyll
module Jekyll module Converters class Markdown < Converter alias process convert # RegEx for Vimeo and YouTube URLs VIMEO_URL = /@\[(.*)\]\(.+vimeo\.com\/([0-9]+)\)/ YOUTUBE_URL = /@\[(.*)\]\([^\=]+youtube[^\=]+=([^&"\)]+[^\&)])[^\)]*\)/ YOUTUBE_SHORT_URL = /@\[(.*)\]\([^\=]+youtu\.be\/([^&"\)]+[^\&)])[^\)]*\)/ # RegEx for Markdown images IMAGE = /!\[(.*)\]\(([^\)]+)\)(?:{:([^}]+)})*/ # RegEx for Markdown styles LINK = /<figcaption>(.*)\[([^\]]+)\]\(([^)]+)\)(.*)<\/figcaption>/ ITALIC = /<figcaption>(.*)([\-\β€” ])\*(.*)\*([\.\-?!:\β€” \n])(.*)<\/figcaption>/i ITALIC_ALT = /<figcaption>(.*)([\-\β€” ])_(.*)_([\.\-?!:\β€” \n])(.*)<\/figcaption>/i BOLD = /<figcaption>(.*)([\-\β€” ])\*\*(.*)\*\*([\.\-?!:\β€” \n])(.*)<\/figcaption>/i BOLD_ALT = /<figcaption>(.*)([\-\β€” ])__(.*)__([\.\-?!:\β€” \n])(.*)<\/figcaption>/i # Substitutes for Vimeo and YouTube URLs VIMEO_EMBED = '<figure>' + '<div class="embed">' + '<iframe src="https://player.vimeo.com/video/' + '\2' + '?color=FFFFFF&title=0&byline=0&portrait=0" ' + 'width="1280" height="720" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>' + '</div>' + '<figcaption>' + '\1' + '</figcaption>' + '</figure>' YOUTUBE_EMBED = '<figure>' + '<div class="embed">' + '<iframe width="1280" height="720" src="https://www.youtube-nocookie.com/embed/'+ '\2' + '?rel=0&amp;showinfo=0" frameborder="0" allowfullscreen></iframe>' + '</div>' + '<figcaption>' + '\1' + '</figcaption>' + '</figure>' # Substitutes for images IMG = '<figure>' + '<img src="' + '\2' + '" ' + '\3' + '/>' + '<figcaption>' + '\1' + '</figcaption>' + '</figure>' # Substitutes for styles EM = '<figcaption>\1\2<em>\3</em>\4\5</figcaption>' URL = '<figcaption>\1<a href="\3">\2</a>\4</figcaption>' STRONG = '<figcaption>\1\2<strong>\3</strong>\4\5</figcaption>' def convert(content) # Convert videos and images to their substitutes content = content.gsub(VIMEO_URL,VIMEO_EMBED) content = content.gsub(YOUTUBE_URL,YOUTUBE_EMBED) content = content.gsub(YOUTUBE_SHORT_URL,YOUTUBE_EMBED) content = content.gsub(IMAGE, IMG) # Get Kramdown to process the raw content as Markdown html = process(content) # Process the leftover Markdown within <figcaption>s html = html.gsub(BOLD, STRONG) html = html.gsub(BOLD_ALT, STRONG) html = html.gsub(ITALIC, EM) html = html.gsub(ITALIC_ALT, EM) html = html.gsub(LINK, URL) # Hand over the processed content back to Jekyll content = html end end end end

Call it figure.rb and slap it onto your _plugins folder! Then, if you want to include a video in your Markdown content, use it like so:

<code>@[Your video caption goes here!](https://link-to-video.com/)</code>
minimal prompt for zsh
function git_prompt() { local dirty="" if [[ -n $(git ls-files --other --exclude-standard 2> /dev/null) ]]; then dirty="*" fi if ! git diff --quiet 2> /dev/null; then dirty="*" fi local ref ref=$(git symbolic-ref --quiet HEAD 2> /dev/null) local ret=$? if [[ $ret != 0 ]]; then [[ $ret == 128 ]] && return ref=$(git rev-parse --short HEAD 2> /dev/null) || return fi echo " %F{cyan}${ref#refs/heads/}%f%F{red}${dirty}%f" } setopt PROMPT_SUBST export PROMPT='[%[email protected]%F{yellow}%m%f:%F{blue}%~%f$(git_prompt)]%# ' export RPROMPT='[%D %*]'

because i hate plugins

docker image for rails deployment
FROM ruby:2.5.1 ARG DEBIAN_FRONTEND="noninteractive" ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE="true" RUN echo $TZ | tee /etc/timezone && rm /etc/localtime && ln -s /usr/share/zoneinfo/$TZ /etc/localtime && \ curl -sSL https://deb.nodesource.com/setup_10.x | bash - && \ curl -sSL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get -y update && apt-get -y install iproute2 tzdata nodejs yarn ADD app /home/app WORKDIR /home/app VOLUME /home/app/files RUN bin/bundle config --local build.nokogiri "--use-system-libraries" && \ bin/bundle config --local deployment 1 && \ bin/bundle install --without=development:test && \ bin/rails yarn:install RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* EXPOSE 3000 CMD ["bin/rails", "server", "--no-daemon"]
swift mutexes
final class NoStarveMutex { private final let _semaphoreA = DispatchSemaphore(value: 1) private final let _semaphoreB = DispatchSemaphore(value: 0) private final var _countA = Int64(0) private final var _countB = Int64(0) final func lockAndWait() { lock() waitForLock() } final func lock() { OSAtomicIncrement64(&_countA) _semaphoreA.wait(timeout: DispatchTime.distantFuture) _countB += 1 if OSAtomicDecrement64(&_countA) == 0 { _semaphoreB.signal() } else { _semaphoreA.signal() } } final func waitForLock() { _semaphoreB.wait(timeout: DispatchTime.distantFuture) _countB -= 1 } final func unlock() { if _countB == 0 { _semaphoreA.signal() } else { _semaphoreB.signal() } } } final class ReadWriteMutex { private final let _readMutex = NoStarveMutex() private final let _writeMutex = NoStarveMutex() private final var _count = Int64(0) final func lock() { _readMutex.lock() } final func lockForReadingAndWait() { lock() waitForReadLock() } final func waitForReadLock() { _readMutex.waitForLock() if OSAtomicIncrement64(&_count) == 1 { _writeMutex.lockAndWait() } _readMutex.unlock() } final func unlockForReading() { if OSAtomicDecrement64(&_count) == 1 { _writeMutex.unlock() } } final func lockForWritingAndWait() { lock() waitForWriteLock() } final func waitForWriteLock() { _readMutex.waitForLock() _writeMutex.lockAndWait() } final func unlockForWriting() { _writeMutex.unlock() _readMutex.unlock() } }

popping and locking

TSV parser
class TSVFile attr_reader :rows def initialize(path) return unless File.exists? path @rows = Array.new f = File.read(path, mode: "r") lines = f.encode(universal_newline: true).split("\n") headers = lines.first.split("\t").collect(&:strip) lines.drop(1).each do |line| cols = line.split("\t").collect(&:strip) @rows << Hash[headers.zip(cols)] end end end

kinda crazy that ruby doesn't provide its own

Pepper phrases throughout text
def pepper_in_text(text, pepper) body = text.split(' ') pepper.each { |value| body.insert(rand(0..body.length), value) } body = body.join(' ') end

Here's a method I wrote to help generate seed data for testing mentions. It takes a block of text and randomly intersperses an array of strings throughout it, preserving word breaks.

Here's an example of how you use it:

pepper_in_text(some_paragraph, ['jacob', 'pasquale'])