Create a complete, interactive p5.js sketch based on these detailed specifications:

```json
{
  "SIMULATION": "Interactive Fractal Tree Generation",
  "CONTROLS": [
    {
      "type": "Slider",
      "label": "Branch Angle (Degrees)",
      "parameter": "branchAngle",
      "min": 0,
      "max": 90,
      "default": 30,
      "step": 1,
      "description": "Controls the angle between the two sub-branches at each branching point. Expressed in degrees."
    },
    {
      "type": "Slider",
      "label": "Branch Length Ratio",
      "parameter": "branchLengthRatio",
      "min": 0.5,
      "max": 0.9,
      "default": 0.7,
      "step": 0.01,
      "description": "Determines the length of the new branch relative to the parent branch.  Values less than 1 result in progressively smaller branches."
    },
    {
      "type": "Slider",
      "label": "Branch Thickness",
      "parameter": "branchThickness",
      "min": 1,
      "max": 10,
      "default": 4,
      "step": 1,
      "description": "Controls the thickness of the branches.  Consider reducing this for deeply branching trees to maintain performance."
    },
    {
      "type": "Slider",
      "label": "Recursion Depth",
      "parameter": "recursionDepth",
      "min": 1,
      "max": 12,
      "default": 6,
      "step": 1,
      "description": "Controls how many times the branching process is repeated. Higher values create more detailed trees, but increase computation time."
    },
    {
      "type": "Slider",
      "label": "Starting Length",
      "parameter": "startLength",
      "min": 50,
      "max": 200,
      "default": 120,
      "step": 1,
      "description": "The length of the initial trunk/branch."
    },
    {
      "type": "Button",
      "label": "Reset Tree",
      "function": "resetTree",
      "description": "Clears the existing tree and redraws a new one with the current parameters."
    },
    {
      "type": "Button",
      "label": "Toggle Color",
      "function": "toggleColor",
      "description": "Switches between a single color tree and a gradient color tree based on depth."
    },
    {
     "type": "Checkbox",
     "label": "Randomize Angle Each Branch",
     "parameter": "randomizeAngle",
     "default": false,
     "description": "If checked, adds a random element to the branching angle, creating a more natural-looking tree."
    },
    {
     "type": "Slider",
     "label": "Angle Variance",
     "parameter": "angleVariance",
     "min": 0,
     "max": 20,
     "default": 5,
     "step": 1,
     "description": "The degree to which the angle can deviate when randomizeAngle is true."
    }
  ],
  "VISUALS": {
    "tree": "The fractal tree is composed of lines. Each line represents a branch. The tree starts from the bottom center of the canvas and grows upwards. The initial trunk color is either a constant brown color (139, 69, 19) or changes to a gradient if 'Toggle Color' is activated. When color is toggled on, each branch will have a color determined by how many iterations (depth) from the root of the tree it is. Darker colors are used for branches closer to the root, and lighter (potentially green) colors for branches closer to the tips.",
    "background": "The background should be a light gray color (220, 220, 220).",
    "branchStyling": {
      "strokeCap": "ROUND",
      "strokeWeight": "branchThickness"
    },
    "gradientColor": {
      "startColor": [139, 69, 19],  // Brown (for trunk)
      "endColor": [0, 128, 0]   // Green (for leaves/tips)
    }
  },
  "PHYSICS": {
    "fractalAlgorithm": "The core of the simulation is a recursive function that draws the branches.  The function should:",
    "recursionStep1": "Draw a line (representing a branch) of length 'length' starting from the current position (x, y) and pointing at an angle of 90 degrees (straight up).",
    "recursionStep2": "Move the drawing cursor to the end of the line drawn in Step 1.",
    "recursionStep3": "If the current depth is greater than 0:",
    "recursionStep4_a": "Calculate the angle for the left sub-branch by subtracting 'branchAngle' from the current angle (plus a random value from -angleVariance to +angleVariance if randomizeAngle is true).",
    "recursionStep4_b": "Calculate the angle for the right sub-branch by adding 'branchAngle' to the current angle (plus a random value from -angleVariance to +angleVariance if randomizeAngle is true).",
    "recursionStep5": "Recursively call the function twice:",
    "recursionStep5_a": "Once for the left sub-branch, with the updated angle (calculated in Step 4a), a reduced length ('length' * 'branchLengthRatio'), and a reduced depth ('depth' - 1).",
    "recursionStep5_b": "Once for the right sub-branch, with the updated angle (calculated in Step 4b), a reduced length ('length' * 'branchLengthRatio'), and a reduced depth ('depth' - 1)."
  },
  "USER_INTERACTIONS": {
    "mouseClick": "No specific mouse click interactions are needed. The UI controls handle all parameter adjustments.",
    "keyboard": "No specific keyboard interactions are needed."
  },
  "ADDITIONAL_NOTES": {
    "performance": "Be mindful of performance. High recursion depths can significantly slow down the simulation. Consider adding a warning if the recursion depth exceeds a certain value (e.g., 8).",
    "resetFunction": "The 'resetTree' function should redraw the tree from scratch using the current slider values. This involves clearing the canvas and calling the recursive drawing function with the initial parameters.",
    "colorToggleFunction": "The 'toggleColor' function should toggle a boolean variable that determines whether to use a single color or a gradient color for the branches.  Update the tree on each toggle.",
    "gradientColorCalculation": "If gradient color is enabled, the color of each branch should be determined by its depth in the tree.  The color can be interpolated between the 'startColor' and 'endColor' based on the ratio of the current depth to the maximum recursion depth."
  }
}
```

Requirements:
- Include both setup() and draw() functions
- Use createCanvas(400, 400) to set canvas size
- Implement ALL specified controls (sliders, buttons) using p5.js GUI libraries or simple implementations
- Add all visual elements as described
- Implement the physics/logic accurately
- Include all specified user interactions
- Add clear comments explaining the code
- Make it educational and visually appealing
- Ensure smooth animations and responsive controls

IMPORTANT: Only output the JavaScript code, no explanations or markdown formatting. The code should be self-contained and runnable in the p5.js editor with all interactive controls working.