Skip to content

Latest commit

 

History

History
722 lines (584 loc) · 14 KB

File metadata and controls

722 lines (584 loc) · 14 KB

File Structure Specification

Overview

Projects generated by the visual builder use standard Vite/React structure with an additional .lowcode/ metadata folder. This approach ensures:

  • ✅ Works with any IDE (VSCode, WebStorm, etc.)
  • ✅ Compatible with standard build tools
  • ✅ Can be committed to version control
  • ✅ Deployable to any hosting platform
  • ✅ Visual editor state persisted separately

Project Structure

my-app/
├── .lowcode/                    # Visual editor metadata
│   ├── manifest.json            # Component architecture
│   ├── connections.json         # Data flow connections
│   ├── variables.json           # Global reactive variables
│   ├── config.json              # Project configuration
│   ├── debug-snapshots/         # Saved debugger states
│   └── plugins/                 # Custom plugins
│       └── framework-custom.js
│
├── src/                         # Standard source directory
│   ├── components/              # Generated components
│   │   ├── UserCard.jsx
│   │   ├── UserList.jsx
│   │   └── Button.jsx
│   │
│   ├── scripts/                 # Custom script nodes
│   │   ├── validateUser.js
│   │   └── formatData.js
│   │
│   ├── runtime/                 # Tool runtime (auto-generated)
│   │   ├── globalState.js       # Reactive variables system
│   │   ├── debugger.js          # Debug wrapper (in debug mode)
│   │   └── connections.js       # Component wiring helpers
│   │
│   ├── styles/                  # Global styles
│   │   └── globals.css
│   │
│   ├── App.jsx                  # Main app component
│   └── main.jsx                 # Entry point
│
├── public/                      # Static assets
│   └── favicon.ico
│
├── node_modules/                # Dependencies
│
├── .gitignore
├── package.json
├── vite.config.js
├── tsconfig.json               # If TypeScript enabled
└── README.md

Metadata Files

.lowcode/manifest.json

Purpose: Complete component architecture and configuration

Structure:

{
  "version": "0.1.0",
  "metadata": {
    "projectName": "My Dashboard",
    "framework": "react",
    "createdAt": "2025-10-25T10:00:00Z",
    "updatedAt": "2025-10-25T15:30:00Z",
    "author": "john@example.com"
  },
  "components": {
    "root": {
      "id": "root",
      "type": "App",
      "children": ["header", "main", "footer"]
    },
    "header": {
      "id": "header",
      "type": "Header",
      "props": {...},
      "state": {...},
      "children": ["logo", "nav"]
    }
  },
  "routes": [...],
  "theme": {...}
}

Git: ✅ Commit this - it's the source of truth


.lowcode/connections.json

Purpose: Visual representation of data flow between components

Structure:

{
  "connections": [
    {
      "id": "conn-1",
      "source": {
        "componentId": "userList",
        "output": "selectedUser"
      },
      "target": {
        "componentId": "userDetail",
        "input": "user"
      },
      "type": "binding"
    },
    {
      "id": "conn-2",
      "source": {
        "componentId": "submitButton",
        "output": "onClick"
      },
      "target": {
        "componentId": "formContainer",
        "input": "handleSubmit"
      },
      "type": "event"
    }
  ],
  "layout": {
    "userList": { "x": 100, "y": 200 },
    "userDetail": { "x": 400, "y": 200 }
  }
}

Git: ⚠️ Optional - visual editor layout, not essential for build


.lowcode/variables.json

Purpose: Global reactive state definitions

Structure:

{
  "currentUser": {
    "type": "object",
    "reactive": true,
    "default": null,
    "schema": {
      "id": "string",
      "name": "string",
      "email": "string",
      "role": "string"
    },
    "description": "Currently authenticated user"
  },
  "theme": {
    "type": "string",
    "reactive": true,
    "default": "light",
    "options": ["light", "dark"],
    "description": "Application theme"
  },
  "isAuthenticated": {
    "type": "boolean",
    "reactive": true,
    "default": false,
    "description": "User authentication status"
  }
}

Git: ✅ Commit this - defines app state


.lowcode/config.json

Purpose: Tool-specific configuration

Structure:

{
  "framework": "react",
  "typescript": false,
  "formatting": {
    "style": "prettier",
    "config": {
      "semi": true,
      "singleQuote": true,
      "tabWidth": 2
    }
  },
  "plugins": {
    "react": {
      "version": "18.2.0"
    }
  },
  "debugger": {
    "enabled": true,
    "autoCapture": true
  },
  "sync": {
    "mode": "review-required",
    "autoSync": false
  }
}

Git: ✅ Commit this - project settings


.lowcode/debug-snapshots/

Purpose: Saved debugger states for later review

Structure:

debug-snapshots/
├── 2025-10-25-150023.json      # Timestamp-based
├── 2025-10-25-151245.json
└── bug-form-submit.json         # Named snapshots

Content:

{
  "timestamp": "2025-10-25T15:00:23Z",
  "event": "onClick",
  "component": "submitButton",
  "state": {
    "components": {...},
    "globals": {...}
  },
  "description": "Form submission bug"
}

Git: ❌ Don't commit - local debugging data


Generated Code Structure

Component Files

Location: src/components/{ComponentName}.jsx

Template:

import React, { useState } from 'react';

/**
 * @lowcode:generated
 * @lowcode:component-id: userCard
 * @lowcode:last-generated: 2025-10-25T10:00:00Z
 * DO NOT EDIT: This file is auto-generated. Changes will be overwritten.
 * To customize, edit in the visual editor or mark regions as @lowcode:preserve
 */

export default function UserCard({ user, onClick }) {
  const [isHovered, setIsHovered] = useState(false);

  return (
    <div 
      className="card"
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)}
      onClick={onClick}
    >
      <h2>{user.name}</h2>
      <p>{user.email}</p>
    </div>
  );
}

Comment Markers:

  • @lowcode:generated - Flag as tool-generated
  • @lowcode:component-id - Link to manifest entry
  • @lowcode:last-generated - Timestamp for change detection
  • @lowcode:preserve - Protect regions from regeneration

Script Nodes

Location: src/scripts/{scriptName}.js

Template:

/**
 * @lowcode:script-node
 * @lowcode:id: validateUser
 * This file can be freely edited. It will not be overwritten.
 */

export function validateUser(inputs) {
  const { userData } = inputs;
  const errors = [];

  if (!userData.email?.includes('@')) {
    errors.push('Invalid email format');
  }

  if (userData.password?.length < 8) {
    errors.push('Password must be at least 8 characters');
  }

  return {
    isValid: errors.length === 0,
    errors
  };
}

// Metadata for visual editor
export const metadata = {
  name: 'Validate User',
  description: 'Validates user input data',
  inputs: {
    userData: {
      type: 'object',
      required: true,
      schema: {
        email: 'string',
        password: 'string'
      }
    }
  },
  outputs: {
    isValid: { type: 'boolean' },
    errors: { type: 'array', items: 'string' }
  }
};

User Editable: ✅ Yes - Script nodes are meant to be customized


Runtime Files

src/runtime/globalState.js

Purpose: Reactive global variables system

Auto-generated from .lowcode/variables.json:

/**
 * @lowcode:generated
 * Global state management - Auto-generated from .lowcode/variables.json
 */
import { create } from 'zustand';

export const useGlobalState = create((set) => ({
  // State
  currentUser: null,
  theme: 'light',
  isAuthenticated: false,

  // Actions
  setCurrentUser: (user) => set({ currentUser: user }),
  setTheme: (theme) => set({ theme }),
  setIsAuthenticated: (isAuth) => set({ isAuthenticated: isAuth }),
  
  // Reset
  reset: () => set({
    currentUser: null,
    theme: 'light',
    isAuthenticated: false
  })
}));

User Editable: ❌ No - Regenerated when variables.json changes


src/runtime/debugger.js

Purpose: Debug instrumentation (only in debug mode)

/**
 * @lowcode:generated
 * Debug runtime - Only included in debug builds
 */

class DebugRuntime {
  constructor() {
    this.isPaused = false;
    this.snapshots = [];
  }

  __debugWrap(name, handler, metadata) {
    return async (...args) => {
      if (this.isPaused) {
        await this.waitForContinue();
      }
      
      const preState = this.captureState();
      const result = await handler(...args);
      const postState = this.captureState();
      
      this.notifyElectron({
        type: 'EVENT',
        name,
        preState,
        postState,
        metadata
      });
      
      return result;
    };
  }

  captureState() {
    // Capture component states, globals, etc.
    return {...};
  }
}

export const debugRuntime = new DebugRuntime();
export const __debugWrap = debugRuntime.__debugWrap.bind(debugRuntime);

User Editable: ❌ No - Tool-managed


App Entry Point

src/App.jsx

/**
 * @lowcode:generated
 * Main application component
 */
import React from 'react';
import Header from './components/Header';
import Main from './components/Main';
import Footer from './components/Footer';

export default function App() {
  return (
    <div className="app">
      <Header />
      <Main />
      <Footer />
    </div>
  );
}

src/main.jsx

/**
 * @lowcode:generated
 * Application entry point
 */
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './styles/globals.css';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Configuration Files

package.json

{
  "name": "my-dashboard",
  "private": true,
  "version": "0.1.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "zustand": "^4.4.1"
  },
  "devDependencies": {
    "@types/react": "^18.2.37",
    "@types/react-dom": "^18.2.15",
    "@vitejs/plugin-react": "^4.2.0",
    "eslint": "^8.53.0",
    "eslint-plugin-react": "^7.33.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.4",
    "vite": "^5.0.0"
  },
  "lowcode": {
    "version": "0.1.0",
    "framework": "react"
  }
}

vite.config.js

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  server: {
    port: 3000,
    open: false,
    cors: true
  },
  build: {
    outDir: 'dist',
    sourcemap: true
  }
});

.gitignore

# Dependencies
node_modules

# Build output
dist
*.local

# Debug snapshots (don't commit)
.lowcode/debug-snapshots/

# Editor files
.vscode
.idea
*.swp
*.swo

# OS files
.DS_Store
Thumbs.db

# Logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*

File Naming Conventions

Components

  • Format: PascalCase
  • Extension: .jsx (or .tsx for TypeScript)
  • Examples: UserCard.jsx, NavigationBar.jsx, Button.jsx

Scripts

  • Format: camelCase
  • Extension: .js (or .ts for TypeScript)
  • Examples: validateUser.js, formatData.js, calculateTotal.js

Styles

  • Format: kebab-case or camelCase
  • Extension: .css, .scss, .module.css
  • Examples: globals.css, button.module.css

Directory Guidelines

src/components/

  • ✅ All visual components
  • ✅ One component per file
  • ✅ Co-located styles if using CSS modules

src/scripts/

  • ✅ Non-visual logic components
  • ✅ Reusable functions
  • ✅ Data transformations

src/runtime/

  • ❌ Don't edit manually
  • ❌ Auto-generated by tool
  • ⚠️ Regenerated on config changes

src/styles/

  • ✅ Global styles
  • ✅ Theme configuration
  • ✅ CSS variables

Migration from Other Tools

From Bubble

  1. Export Bubble app structure
  2. Map pages → components
  3. Map workflows → script nodes
  4. Convert database schemas → API integration

From Webflow

  1. Export Webflow HTML/CSS
  2. Parse HTML → component tree
  3. Convert classes → Tailwind utilities
  4. Map interactions → React event handlers

From Figma

  1. Export Figma components
  2. Convert frames → div structure
  3. Map styles → Tailwind classes
  4. Add interactivity manually

Deployment

Standard Deployment (No Changes Needed)

# Build for production
npm run build

# Deploy to Vercel
vercel

# Deploy to Netlify
netlify deploy --prod

# Deploy to AWS Amplify
amplify publish

What Gets Deployed

dist/
├── index.html
├── assets/
│   ├── index-a1b2c3d4.js
│   └── index-e5f6g7h8.css
└── favicon.ico

Note: .lowcode/ directory is NOT deployed (development only)


Backup & Restore

Backup Project

# Backup metadata only
cp -r .lowcode/ .lowcode.backup/

# Full project backup
tar -czf my-app-backup.tar.gz .

Restore Project

# Restore metadata
cp -r .lowcode.backup/ .lowcode/

# Regenerate code from manifest
npm run lowcode:regenerate

Best Practices

✅ DO:

  • Commit .lowcode/manifest.json, variables.json, config.json
  • Keep components small and focused
  • Use script nodes for complex logic
  • Document custom code in comments

❌ DON'T:

  • Edit src/runtime/ files manually
  • Commit debug-snapshots/
  • Remove @lowcode: comment markers
  • Modify generated code without @lowcode:preserve markers

See Also: