Is your feature request related to a problem? Please describe.
When a circuit is rendered with scope grouping, every operation/function call on the trace becomes its own labeled, nested box in the widget. Thin "wrapper" callables (ones that exist only to set up and delegate to something else) therefore add layers of nesting and visual clutter without conveying any information about the quantum operations themselves.
Concrete example (screenshot below): a StatePreparation call is wrapped by a MakeStatePreparationCircuit call, so the actual gates ( X , S† , H , Rz , S , and the CNOT ladder) are buried two dashed boxes deep. Neither wrapper box tells the reader anything the inner gates don't already say; they just cost horizontal/vertical space and make the diagram noisier. In deeper call stacks this compounds quickly.
There is currently no way for an author to say "render my gates, but don't draw a box for this function." The grouping is all-or-nothing per the group_by_scope setting.
Describe the solution you'd like
An optional attribute that marks a callable as "invisible" to the circuit renderer, e.g.:
@InvisibleInCircuit()
operation MakeStatePreparationCircuit(...) : Unit is Adj + Ctl { ... }
Semantics: during circuit generation, a callable carrying this attribute does not emit its own scope-group box. Its child operations are spliced directly into the parent's grid, so the gates still render exactly as before, just without the wrapper label/border. It is purely a rendering/tracing hint with no effect on simulation, QIR codegen, or program semantics (analogous to how existing rendering-only metadata is inert outside circuit generation).
This looks like a small, natural extension of existing machinery:
• The circuit builder already represents each traced call as a scope group: a Unitary component with a populated children grid and a metadata.scope_location, emitted when group_by_scope is enabled ( source/compiler/qsc_circuit/src/circuit.rs , source/compiler/qsc_circuit/src/builder.rs ). Those scope groups are precisely the dashed boxes in the screenshot.
• The builder already has a pass, collapse_unnecessary_scopes / collapse_if_unnecessary ( source/compiler/qsc_circuit/src/builder.rs ), that removes trivial scopes (e.g. a single-iteration loop or a single-operation lambda) and splices their children up into the parent. The requested behavior is the same splice-children-and-drop-the-box operation, just opted into explicitly per callable rather than inferred.
• Q# already has a compiler-level attribute system ( Attr enum in source/compiler/qsc_hir/src/hir.rs , surfaced as @SimulatableIntrinsic() , @Measurement() , @Reset() , etc.), so adding one more attribute that the circuit builder consults is a low-surface-area change.
Describe alternatives you've considered
Describe alternatives you've considered
• Interactive collapse/expand in the widget. Useful, but doesn't help static or exported renders (docs, papers, notebook snapshots), and a default-expanded view is still cluttered by wrappers the author already knows are noise. An author-side annotation makes the intent travel with the code.
• Post-processing the circuit JSON to strip specific groups. Fragile, has to be redone every run, and depends on internal structure.
• Restructuring the Q# to inline the wrappers. Defeats the purpose: the wrappers exist for good software-engineering reasons; only their visualization is unwanted.
Additional context

Is your feature request related to a problem? Please describe.
When a circuit is rendered with scope grouping, every operation/function call on the trace becomes its own labeled, nested box in the widget. Thin "wrapper" callables (ones that exist only to set up and delegate to something else) therefore add layers of nesting and visual clutter without conveying any information about the quantum operations themselves.
Concrete example (screenshot below): a
StatePreparationcall is wrapped by aMakeStatePreparationCircuitcall, so the actual gates (X,S†,H,Rz,S, and theCNOTladder) are buried two dashed boxes deep. Neither wrapper box tells the reader anything the inner gates don't already say; they just cost horizontal/vertical space and make the diagram noisier. In deeper call stacks this compounds quickly.There is currently no way for an author to say "render my gates, but don't draw a box for this function." The grouping is all-or-nothing per the
group_by_scopesetting.Describe the solution you'd like
An optional attribute that marks a callable as "invisible" to the circuit renderer, e.g.:
Semantics: during circuit generation, a callable carrying this attribute does not emit its own scope-group box. Its child operations are spliced directly into the parent's grid, so the gates still render exactly as before, just without the wrapper label/border. It is purely a rendering/tracing hint with no effect on simulation, QIR codegen, or program semantics (analogous to how existing rendering-only metadata is inert outside circuit generation).
This looks like a small, natural extension of existing machinery:
• The circuit builder already represents each traced call as a scope group: a
Unitarycomponent with a populatedchildrengrid and ametadata.scope_location, emitted whengroup_by_scopeis enabled (source/compiler/qsc_circuit/src/circuit.rs,source/compiler/qsc_circuit/src/builder.rs). Those scope groups are precisely the dashed boxes in the screenshot.• The builder already has a pass,
collapse_unnecessary_scopes/collapse_if_unnecessary(source/compiler/qsc_circuit/src/builder.rs), that removes trivial scopes (e.g. a single-iteration loop or a single-operation lambda) and splices their children up into the parent. The requested behavior is the same splice-children-and-drop-the-box operation, just opted into explicitly per callable rather than inferred.• Q# already has a compiler-level attribute system (
Attrenum insource/compiler/qsc_hir/src/hir.rs, surfaced as@SimulatableIntrinsic(),@Measurement(),@Reset(), etc.), so adding one more attribute that the circuit builder consults is a low-surface-area change.Describe alternatives you've considered
Describe alternatives you've considered
• Interactive collapse/expand in the widget. Useful, but doesn't help static or exported renders (docs, papers, notebook snapshots), and a default-expanded view is still cluttered by wrappers the author already knows are noise. An author-side annotation makes the intent travel with the code.
• Post-processing the circuit JSON to strip specific groups. Fragile, has to be redone every run, and depends on internal structure.
• Restructuring the Q# to inline the wrappers. Defeats the purpose: the wrappers exist for good software-engineering reasons; only their visualization is unwanted.
Additional context