This document provides context and guidelines for AI coding assistants working with the Valdi codebase.
Valdi is a cross-platform UI framework that compiles declarative TypeScript components to native views on iOS, Android, and macOS. Write your UI once, and it runs natively on multiple platforms without web views or JavaScript bridges.
Valdi has been used in production at Snap for 8 years and is now available as open source under the MIT license.
The Valdi compiler takes TypeScript source files (using TSX/JSX syntax) and compiles them into .valdimodule files. These compiled modules are read by the Valdi runtime on each platform to render native views. This is not TypeScript rendered in a WebView - Valdi generates true native UI components.
- Valdi: TypeScript-based declarative UI framework that compiles to native code
- TSX/JSX: React-like syntax for declarative UI (but this is not React - Valdi compiles to native)
- Bazel: Primary build system for reproducible builds
- TypeScript/JavaScript: Application and UI layer
- C++: Cross-platform runtime and layout engine
- Swift: Compiler implementation
- Kotlin/Java: Android runtime
- Objective-C/C++: iOS runtime
- Flexbox: Layout system with automatic RTL support
Example applications demonstrating Valdi features:
helloworld/- Basic getting started examplevaldi_gpt/- More complex demo applicationbenchmark/- Performance testing app*_example/- Various feature demonstrations (navigation, managed context, etc.)
The Valdi compiler and companion tools:
compiler/- Swift-based main compiler that transforms TypeScript to native codecompanion/- TypeScript-based companion tools for the build process
Core Valdi runtime implementations:
- Platform-specific implementations (iOS, Android, macOS)
- Cross-platform C++ core with layout engine
- Protobuf integration for efficient serialization
- Generated code from Djinni interfaces for cross-language bindings
Core Valdi TypeScript modules and standard library:
valdi_core/- Core component and runtime APIs (Component, Provider, etc.)valdi_protobuf/- Protobuf serialization supportvaldi_http/- HTTP client module (promise-based network requests)valdi_navigation/- Navigation utilitiesvaldi_rxjs/- RxJS integration for reactive programmingpersistence/- Key-value storage with encryption and TTL supportdrawing/- Managed context for graphics and drawing operationsfile_system/- Low-level file I/O operationsvaldi_web/,web_renderer/- Web runtime implementationsfoundation/,coreutils/- Common utilities (arrays, Base64, LRU cache, UUID, etc.)worker/- Worker service support for background JavaScript execution- Other standard library modules
Node.js packages:
cli/- Command-line interface for Valdi development (valdicommand)eslint-plugin-valdi/- ESLint rules for Valdi code
Bazel build rules and macros for the Valdi build system
Comprehensive documentation:
- Codelabs for learning
- API documentation
- Setup and installation guides
External dependencies and their Bazel build configurations
- Bazel is the primary build system - Use
bazel build,bazel test, etc.- Note:
bzlis an alias forbazel- both commands work interchangeably - The CLI looks for
bazel,bzl, orbazeliskexecutables
- Note:
- MODULE.bazel and WORKSPACE - Bazel module system is in use
- Cross-platform builds - Code must work on iOS, Android, Linux, and macOS
- Platform transitions - Build rules handle platform-specific compilation automatically
- C++: Follow the project's C++ style conventions
- TypeScript: Use ESLint with Valdi-specific rules
- Swift: Follow Swift conventions for compiler code
- Kotlin: Follow Kotlin conventions for Android runtime
- Indentation: Always match existing file conventions
- Test files are typically in
test/subdirectories - Run tests with
bazel test //path/to:target - All changes should include appropriate tests
- Use the built-in Valdi testing framework for component tests
- Djinni interfaces - Some code is generated from
.djinnifiles for cross-language bindings - Don't modify generated code - Change the source
.djinnifile instead - Generated files are typically in
generated-src/directories
# Build the compiler
bazel build //compiler/compiler:valdi-compiler
# After building, move the binary to bin/ directory for use by the toolchain
# The exact path depends on your platform (macos/linux and architecture)
# Example for macOS ARM64:
cp bazel-bin/compiler/compiler/valdi-compiler bin/compiler/macos/arm64/Note: Pre-built compiler binaries are checked in to /bin/compiler/ for convenience, but you can build and use your own version during development.
# Run all tests
bazel test //...
# Run specific test
bazel test //valdi/test:some_testcd npm_modules/cli
# Install the valdi command-line tool globally
npm run cli:install
# After installation, use the CLI
valdi --helpUse existing apps in /apps/ as templates. Each app needs:
BUILD.bazelfile defining build targetspackage.jsonfor npm dependencies- Entry point file (typically
.tsxfor TypeScript JSX) - Source files in
src/directory
/README.md- Main project documentation/docs/INSTALL.md- Installation and setup instructions/docs/DEV_SETUP.md- Developer environment setup/CONTRIBUTING.md- Contribution guidelines/CODE_OF_CONDUCT.md- Community standards/LICENSE.md- MIT License information
Pre-built binaries are stored in /bin/:
- Compiler binaries for Linux/macOS
- SQLite compiler for data persistence
- Other build tools
- Uses Objective-C++ bridge layer for TypeScript-native communication
- Metal for GPU-accelerated rendering
- See
/valdi/src/ios/for platform implementations
- Kotlin/Java implementations
- Uses Android NDK for C++ integration
- See
/valdi/src/android/for platform implementations
- TypeScript runtime for web targets
- See
/src/valdi_modules/src/valdi/web_renderer/for web implementation
- Native macOS implementation
- See
/valdi/src/valdi/macos/for desktop implementations
- Setup environment - Follow
/docs/DEV_SETUP.md - Make changes in appropriate directory
- Build locally with Bazel
- Run tests to verify changes
- Run linters with appropriate tools
- Test on multiple platforms - Changes may affect iOS, Android, and web
- Update documentation if adding features
Valdi components follow a class-based pattern with lifecycle methods:
import { Component } from 'valdi_core/src/Component';
class MyComponent extends Component {
// Required: Render the component's UI
onRender() {
<view>
<label value="Hello" />
</view>;
}
// Optional lifecycle methods:
// onMount() - Called when component is first mounted
// onUnmount() - Called before component is removed
// onUpdate(prevProps) - Called when component updates
}Key Valdi Concepts:
- Components use TSX/JSX syntax (similar to React but compiles to native)
- State management via component properties
- Event handlers for user interactions
- Flexbox layout system for positioning
For performance-critical code, write native implementations with TypeScript bindings:
- Define interfaces in TypeScript
- Specify polyglot modules in build files (BUILD.bazel)
- Implement in C++, Swift, Kotlin, or Objective-C
- Compiler generates type-safe bindings
For background processing:
- Create worker services that run in separate JavaScript contexts
- Communicate via message passing
- See
/docs/docs/advanced-worker-service.md
Pass data and services between native code and Valdi:
- Component Context: Pass native data to Valdi components when instantiating them
- Native Annotations: Use TypeScript comments to export components to native platforms
- Example:
@Componentand@ExportModelannotations define how components are exposed - See
/docs/docs/native-annotations.mdand/docs/docs/native-context.md
Dependency injection for Valdi components:
- Use
Providerto pass services and data down the component tree - Similar to React Context but Valdi-specific
- Enables loose coupling and testability
- See
/docs/docs/advanced-provider.md
String management for multi-language support:
- String resources defined in JSON files
- Automatic locale switching based on device settings
- See
/docs/docs/advanced-localization.md
- Don't skip cross-platform testing - Changes affect multiple platforms
- Don't modify generated code - Change the source instead
- Don't ignore Bazel cache - Use
bazel cleansparingly - Don't hardcode platform assumptions - Use appropriate abstractions
- Performance matters - Valdi is a UI framework where rendering performance is critical
- TypeScript source → Valdi compiler (Swift)
- Compiler output → Platform-specific code generation
- Native builds → iOS/Android/macOS apps
- Runtime → C++ layout engine + platform-specific renderers
- Valdi includes instant hot reload during development
- Changes to TypeScript components are reflected in milliseconds
- No need to recompile native code for UI changes
- Use
valdi hotreloadcommand
- View recycling - Global view pooling reuses native views
- Viewport-aware rendering - Only visible views are inflated
- Independent component rendering - Components update without parent re-renders
- Optimized layout - C++ layout engine with minimal marshalling
- Cross-platform compatibility is critical - Test implications across iOS, Android, and web
- Bazel is non-negotiable - Don't suggest alternative build systems
- Generated code exists - Some files are auto-generated from Djinni interfaces
- Performance is paramount - This is a production UI framework used at scale
- Follow existing patterns - This is a mature codebase with established conventions
- TypeScript is compiled - Unlike React Native, this doesn't run JavaScript at runtime
- Native integration is deep - Direct access to platform APIs via polyglot modules
# Install Valdi CLI (first time)
cd npm_modules/cli && npm run cli:install
# Setup development environment
valdi dev_setup
# Bootstrap a new project
mkdir my_project && cd my_project
valdi bootstrap
# Install dependencies and build
valdi install ios # or android
# Start hot reload
valdi hotreload# Setup development environment (first time)
scripts/dev_setup.sh
# Build everything
bazel build //...
# Run all tests
bazel test //...
# Build and run example app
cd apps/helloworld
valdi install ios # or androidValdi includes a built-in testing framework:
- Component-level unit tests
- Mock services and dependencies
- See
/docs/docs/workflow-testing.md
import { TestRunner } from 'valdi_core/src/TestRunner';
TestRunner.test('component renders correctly', () => {
const component = new MyComponent();
// Test assertions
});- VSCode integration - Full debugging support with breakpoints
- Hermes debugger - For JavaScript debugging
- Native debugging - Xcode/Android Studio for platform-specific issues
- See
/docs/docs/workflow-hermes-debugger.md
For more details on specific topics, see the /docs/ directory:
- Architecture overview
- API reference
- Codelabs for hands-on learning
- Advanced features (animations, gestures, protobuf)
- Native bindings and custom views
This is an open-source project. When contributing:
- Follow the style guides
- Include tests for new features
- Update documentation
- Ensure cross-platform compatibility
- See
CONTRIBUTING.mdfor full guidelines
- Discord: Join the Valdi Discord community for support and discussions
- Documentation: Comprehensive docs in
/docs/directory - Examples: Working examples in
/apps/directory - Issues: Report bugs and request features via GitHub issues
- Discussions: Ask questions and share ideas in GitHub Discussions
This document is intended for AI coding assistants to quickly understand the structure and conventions of the Valdi codebase. For human developers, please refer to the main README.md and comprehensive documentation in /docs/.