Welcome to Velocity

Velocity is an application and component framework built on Hiraeth that makes rapidly developing site and application prototypes a breeze. Using lightweight alternatives to heavy front-end frameworks, Velocity provides a server-side rendered component system capable of building modern and dynamic front-ends with the speed, efficiency, and power of PHP and Twig. Other components include:

HTMX

For application and user data state transfer and requesting content from the server and DOM replacement.

AlpineJS

For no-build dynamic front-end interactivity and reactivity that won't turn your computer into a plane.

Tailwind

For robust locality of component styling with the perfect blend of consistency, flexibility, and ease of use.

Want to try it?
mkdir <path>
cd <path>
composer create-project hiraeth/app:^3.0 ./ -s dev
composer require hiraeth/velocity

How It Works

Define your Twig layout structure as you normally would using extends, block, and the built-in proxy() filter to align your HTMX Boosted Targets and Twig Blocks:


{% extends '@layouts/velocity/main.html' | proxy('body') %}

{% block body %}
    <x:: hx-target:="#main">
        <header>
            <!-- Common Header/Navigation/Etc -->
        </header>
        <main id="main">
            {% block main %}

            {% endblock %}
        </main>
        <footer>
            <!-- Common Footer -->
        </footer>
    </x::>
{% endblock %}

Create a page simply by adding it to a file, e.g. resources/pages/@index.html. When a boosted HTMX Request is made to / with an HX-Target of main this will only render the main block (not the full layout).


{% extends '@layouts/main.html' | proxy('main') %}

{% block main %}
    <p>
        This is my first page!  Will automatically resolve which blocks
        to render based on the type and target of the HTMX request.
    </p>
{% endblock %}

Create custom components by adding them to resources/tags, e.g. resources/tags/hero.html:


{% do require(['image']) %}

<div
    class="
        flex flex-col items-center justify-center
        min-h-64 w-full
        bg-[image:url('{{ image }}')]
    "
>
    <hgroup>
        {{ children|raw }}
    </hgroup>
</div>

Use the compoonents in your other templates:


<x::hero image="/images/waterfall.jpg">
    <h1>How To Build Bullet-Proof MVPs</h1>
    <h2>Matthew J. Sahagian</h2>
</x::hero>

Use fragments (<x::>) and merge attributes (:=) to apply place-of-use customizations and pass in rich/native types with the {% v: ... %} tag:


<x::hero
    image={% v: app.get('WebImageGenerator').fromText('shamrocks wallpaper') %}
    hx-get:="/api/v1/articles/2/readStart"
    hx-trigger:="revealed"
    hx-swap:="none"
>
    <x:: class:="text-emerald-300">
        <h1>Happy St. Patrick's Day!</h1>
        <h2>Matthew J. Sahagian</h2>
    </x::>
</x::hero>

Create dynamic stateful-components by defining AlpineJS scripts local to your components:


<script>
    function myCounter() {
        return {
            value: 0
        }
    }
</script>
<button x-data="myCounter" x-on:click="value++">
    Count: <span x-text="value"></span>
</button>