Wunderframe Applications
A Wunderframe Application is a full-stack web application built using LUAT templating, modern frontend tooling, and a content management system. Applications use a convention-based structure with zero configuration for common tools like TailwindCSS and esbuild.
What is a Wunderframe Application?
Wunderframe Applications combine:
- 🎨 LUAT Templating - Server-side rendering with Svelte-like syntax
- ⚡ Zero Config - Pre-configured TailwindCSS, esbuild, and TypeScript
- 📱 Modern Frontend - Alpine.js, HTMX, and component-based architecture
- 🗃️ Content Management - Built-in node-based content system
- 🔧 Live Development - Hot reloading and real-time updates
Project Structure
Every Wunderframe application follows a standard structure:
my-app/
├── app.lua # Application entry point and routing
├── app.js # Frontend JavaScript entry point
├── app.css # Global styles with TailwindCSS
├── wunder.toml # Project configuration
├── package.json # Frontend dependencies
├── lib/ # Application logic and templates
│ ├── components/ # Reusable LUAT components
│ ├── pages/ # Page templates
│ └── utils/ # Utility modules and helpers
└── src/ # Frontend source files
├── directives/ # Alpine.js directives
└── components/ # Web components
Core Files
app.lua
- Application Entry Point
The main Lua file that handles routing and renders the appropriate templates:
-- app.lua
local json = require("json")
local getMatchingContentType = require("lib/utils/content_types")
local function render(pageContext, runtime)
local helpers = createContextHelpers(runtime)
helpers.createContext()
local currentNode = pageContext.current_node
-- Handle root path routing
if pageContext.full_path == "/" then
currentNode = get_node("stories/" .. pageContext.story_node.path .. "/site/homepage")
end
-- Set up context for templates
helpers.setContext("currentNode", currentNode)
helpers.setContext("pageContext", pageContext)
-- Find and render the appropriate component
local renderComponent = getMatchingContentType(currentNode.content_type)
if renderComponent then
return renderComponent(currentNode, runtime)
else
error("No matching content type found for: " .. currentNode.content_type)
end
end
return {
render = render
}
app.js
- Frontend Entry Point
Configures the client-side JavaScript with Alpine.js, HTMX, and custom components:
// app.js
import "@phosphor-icons/web/light";
import Alpine from 'alpinejs';
import htmx from "htmx.org";
import loopVideo from "./src/directives/loopvideo.js";
import { initializeDev } from './src/helper.js';
// Register Alpine directives
loopVideo(Alpine);
Alpine.start();
// Set up HTMX and development features
document.addEventListener('htmx:load', () => {
// Live editing integration
if(window.raisin) {
const editor = window.raisin.editor;
editor.onMessage("UPDATE", (newData) => {
htmx.ajax('POST', location.href, {
target: '#app',
swap: 'outerHTML',
values: { properties: JSON.stringify(newData.properties) }
});
});
}
// Initialize development mode
initializeDev();
});
app.css
- Global Styles
TailwindCSS configuration with custom fonts and animations:
/* app.css */
@import url('https://fonts.googleapis.com/css2?family=Inter...');
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@custom-variant dark (&:where(.dark, .dark *));
@theme {
--font-sans: "Inter", "sans-serif";
--font-playful: "Sour Gummy", sans-serif;
}
/* Custom animations */
@keyframes fade-in-up {
0% { opacity: 0; transform: translateY(32px);}
100% { opacity: 1; transform: translateY(0);}
}
.animate-fade-in-up {
animation: fade-in-up 1s cubic-bezier(.23,1.01,.32,1) both;
}
wunder.toml
- Project Configuration
# wunder.toml
name = "my-app"
target = "/"
[sync]
status = "unsynced"
workspaces = []
[frontend_tools]
enabled = ["tailwindcss", "typescript"]
Zero Configuration
Wunderframe applications come with pre-configured tooling:
TailwindCSS
- ✅ Auto-configured with sensible defaults
- ✅ Typography plugin included
- ✅ Custom theme and variant support
- ✅ Dark mode support built-in
esbuild
- ✅ Fast JavaScript/TypeScript bundling
- ✅ ES modules and CommonJS support
- ✅ Development and production builds
- ✅ Hot reloading in development
TypeScript
- ✅ Optional TypeScript support
- ✅ Pre-configured for Alpine.js and HTMX
- ✅ Type checking and IntelliSense
Built-in Frontend Stack
Alpine.js
Interactive frontend framework for reactive components:
<div x-data="{ open: false }">
<button @click="open = !open">Toggle</button>
<div x-show="open">Content</div>
</div>
HTMX
Enables server-side rendering with dynamic updates:
<button hx-post="/api/action" hx-target="#result">
Click me
</button>
<div id="result"></div>
Phosphor Icons
Beautiful icon library included by default:
<i class="ph ph-heart"></i>
<i class="ph ph-star-fill"></i>
What's Next?
- Project Structure - Detailed look at file organization
- Built-in Functions - Lua functions available in your app
- Content Types - Managing different page types
- Development Workflow - Building and deploying your app